summaryrefslogtreecommitdiff
path: root/addons/web_process
diff options
context:
space:
mode:
authorJiten (OpenERP) <jra@tinyerp.com>2011-11-22 10:48:03 +0530
committerJiten (OpenERP) <jra@tinyerp.com>2011-11-22 10:48:03 +0530
commit990ece97a5dfd2b22be25d73193452c034424cdb (patch)
treed0ebc692ed7d608d0cf4a79a5506e48e85ee4c9b /addons/web_process
parentaad7d22763beb1774218bd7f041a918a56237964 (diff)
parent8ca42daf0a1b0ef3505a0505328a9d785ecb564c (diff)
[MERGE] Merge from openerp-web.
bzr revid: jra@tinyerp.com-20111122051803-1ttx64ilabhxo4p1
Diffstat (limited to 'addons/web_process')
-rw-r--r--addons/web_process/__init__.py0
-rw-r--r--addons/web_process/__openerp__.py15
-rw-r--r--addons/web_process/static/src/css/process.css62
-rw-r--r--addons/web_process/static/src/img/ToolOval.jpgbin0 -> 650 bytes
-rw-r--r--addons/web_process/static/src/img/ToolShowGrid.jpgbin0 -> 635 bytes
-rw-r--r--addons/web_process/static/src/img/ToolShowGrid.pngbin0 -> 810 bytes
-rw-r--r--addons/web_process/static/src/img/button-a-a.pngbin0 -> 6595 bytes
-rw-r--r--addons/web_process/static/src/img/cta-a.gifbin0 -> 108 bytes
-rw-r--r--addons/web_process/static/src/img/grid_10.jpgbin0 -> 4530 bytes
-rw-r--r--addons/web_process/static/src/img/iconset-a-help.gifbin0 -> 379 bytes
-rw-r--r--addons/web_process/static/src/img/node-current.pngbin0 -> 3143 bytes
-rw-r--r--addons/web_process/static/src/img/node-gray.pngbin0 -> 3128 bytes
-rw-r--r--addons/web_process/static/src/img/node-subflow-gray.pngbin0 -> 6837 bytes
-rw-r--r--addons/web_process/static/src/img/node-subflow.pngbin0 -> 6851 bytes
-rw-r--r--addons/web_process/static/src/img/node.pngbin0 -> 3205 bytes
-rw-r--r--addons/web_process/static/src/img/port.gifbin0 -> 166 bytes
-rw-r--r--addons/web_process/static/src/img/sep-a.gifbin0 -> 43 bytes
-rw-r--r--addons/web_process/static/src/img/window_bg.pngbin0 -> 128 bytes
-rw-r--r--addons/web_process/static/src/img/window_toolbar.pngbin0 -> 200 bytes
-rw-r--r--addons/web_process/static/src/js/process.js309
-rw-r--r--addons/web_process/static/src/xml/web_process.xml143
21 files changed, 529 insertions, 0 deletions
diff --git a/addons/web_process/__init__.py b/addons/web_process/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/addons/web_process/__init__.py
diff --git a/addons/web_process/__openerp__.py b/addons/web_process/__openerp__.py
new file mode 100644
index 00000000000..1ef47573d55
--- /dev/null
+++ b/addons/web_process/__openerp__.py
@@ -0,0 +1,15 @@
+{
+ "name" : "Process",
+ "version" : "2.0",
+ "depends" : ["web"],
+ "js": [
+ "static/src/js/process.js"
+ ],
+ "css": [
+ "static/src/css/process.css"
+ ],
+ 'qweb': [
+ "static/src/xml/web_process.css"
+ ],
+ 'active': True
+}
diff --git a/addons/web_process/static/src/css/process.css b/addons/web_process/static/src/css/process.css
new file mode 100644
index 00000000000..364c3788b11
--- /dev/null
+++ b/addons/web_process/static/src/css/process.css
@@ -0,0 +1,62 @@
+
+a.cta-a {
+ float: left;
+ padding: 5px 10px;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ background: #eeeded url(/web_process/static/src/img/cta-a.gif) repeat-x;
+ box-shadow: 0 1px 0 #fff;
+ -moz-box-shadow: 0 1px 0 #fff;
+ -webkit-box-shadow: 0 1px 0 #fff;
+ color: #8c8c8c;
+ font-size: 0.9em;
+ text-transform: uppercase;
+ font-weight: bold;
+ text-shadow: #fff 0 1px 0;
+ margin: 2px;
+}
+
+a.cta-a span {
+ float: left;
+ padding: 7px 0 5px 5px;
+ background-position: 0 50%;
+ background-repeat: no-repeat;
+ cursor: pointer;
+}
+
+a.cta-a strong {
+ display: block;
+ color: #393939;
+}
+
+.process_h1 {
+ background:url("/web_process/static/src/img/sep-a.gif") repeat-x scroll 0 90% transparent;
+ font-size:2em;
+ font-weight:normal;
+ padding:0 0 5px 5px;
+ line-height: 1.2;
+}
+
+.process-links {
+ padding: 5px 10px;
+ text-align: center;
+ display: table;
+ margin: auto;
+}
+
+.process-links a.cta-a {
+ display: table-cell;
+}
+
+.process-help-text {
+ float: left;
+ padding:5px 10px;
+ min-height:56px;
+ font-size: 120%;
+}
+
+td.process_fields,button.toggle_fields span:last-child {
+ display: none;
+} \ No newline at end of file
diff --git a/addons/web_process/static/src/img/ToolOval.jpg b/addons/web_process/static/src/img/ToolOval.jpg
new file mode 100644
index 00000000000..c30f15a07d2
--- /dev/null
+++ b/addons/web_process/static/src/img/ToolOval.jpg
Binary files differ
diff --git a/addons/web_process/static/src/img/ToolShowGrid.jpg b/addons/web_process/static/src/img/ToolShowGrid.jpg
new file mode 100644
index 00000000000..8285acc8aac
--- /dev/null
+++ b/addons/web_process/static/src/img/ToolShowGrid.jpg
Binary files differ
diff --git a/addons/web_process/static/src/img/ToolShowGrid.png b/addons/web_process/static/src/img/ToolShowGrid.png
new file mode 100644
index 00000000000..ea530671b97
--- /dev/null
+++ b/addons/web_process/static/src/img/ToolShowGrid.png
Binary files differ
diff --git a/addons/web_process/static/src/img/button-a-a.png b/addons/web_process/static/src/img/button-a-a.png
new file mode 100644
index 00000000000..bd046bbbef7
--- /dev/null
+++ b/addons/web_process/static/src/img/button-a-a.png
Binary files differ
diff --git a/addons/web_process/static/src/img/cta-a.gif b/addons/web_process/static/src/img/cta-a.gif
new file mode 100644
index 00000000000..daa561e29f5
--- /dev/null
+++ b/addons/web_process/static/src/img/cta-a.gif
Binary files differ
diff --git a/addons/web_process/static/src/img/grid_10.jpg b/addons/web_process/static/src/img/grid_10.jpg
new file mode 100644
index 00000000000..5254207b964
--- /dev/null
+++ b/addons/web_process/static/src/img/grid_10.jpg
Binary files differ
diff --git a/addons/web_process/static/src/img/iconset-a-help.gif b/addons/web_process/static/src/img/iconset-a-help.gif
new file mode 100644
index 00000000000..5400acec57b
--- /dev/null
+++ b/addons/web_process/static/src/img/iconset-a-help.gif
Binary files differ
diff --git a/addons/web_process/static/src/img/node-current.png b/addons/web_process/static/src/img/node-current.png
new file mode 100644
index 00000000000..51f86b04c78
--- /dev/null
+++ b/addons/web_process/static/src/img/node-current.png
Binary files differ
diff --git a/addons/web_process/static/src/img/node-gray.png b/addons/web_process/static/src/img/node-gray.png
new file mode 100644
index 00000000000..972013540cf
--- /dev/null
+++ b/addons/web_process/static/src/img/node-gray.png
Binary files differ
diff --git a/addons/web_process/static/src/img/node-subflow-gray.png b/addons/web_process/static/src/img/node-subflow-gray.png
new file mode 100644
index 00000000000..ffafe1bd681
--- /dev/null
+++ b/addons/web_process/static/src/img/node-subflow-gray.png
Binary files differ
diff --git a/addons/web_process/static/src/img/node-subflow.png b/addons/web_process/static/src/img/node-subflow.png
new file mode 100644
index 00000000000..fd2a480204d
--- /dev/null
+++ b/addons/web_process/static/src/img/node-subflow.png
Binary files differ
diff --git a/addons/web_process/static/src/img/node.png b/addons/web_process/static/src/img/node.png
new file mode 100644
index 00000000000..853ac85cd56
--- /dev/null
+++ b/addons/web_process/static/src/img/node.png
Binary files differ
diff --git a/addons/web_process/static/src/img/port.gif b/addons/web_process/static/src/img/port.gif
new file mode 100644
index 00000000000..1a3f97815e7
--- /dev/null
+++ b/addons/web_process/static/src/img/port.gif
Binary files differ
diff --git a/addons/web_process/static/src/img/sep-a.gif b/addons/web_process/static/src/img/sep-a.gif
new file mode 100644
index 00000000000..5a064f21e89
--- /dev/null
+++ b/addons/web_process/static/src/img/sep-a.gif
Binary files differ
diff --git a/addons/web_process/static/src/img/window_bg.png b/addons/web_process/static/src/img/window_bg.png
new file mode 100644
index 00000000000..864aed8a40b
--- /dev/null
+++ b/addons/web_process/static/src/img/window_bg.png
Binary files differ
diff --git a/addons/web_process/static/src/img/window_toolbar.png b/addons/web_process/static/src/img/window_toolbar.png
new file mode 100644
index 00000000000..77c30b79d82
--- /dev/null
+++ b/addons/web_process/static/src/img/window_toolbar.png
Binary files differ
diff --git a/addons/web_process/static/src/js/process.js b/addons/web_process/static/src/js/process.js
new file mode 100644
index 00000000000..f7497773645
--- /dev/null
+++ b/addons/web_process/static/src/js/process.js
@@ -0,0 +1,309 @@
+openerp.web_process = function (openerp) {
+ var QWeb = openerp.web.qweb;
+ openerp.web.ViewManager.include({
+ start: function() {
+ this._super();
+ var self = this;
+ this.process_check();
+ this.process_help = this.action ? this.action.help : 'Help: Not Defined';
+ this.model = this.dataset.model;
+ if(this.action) this.process_model = this.action.res_model;
+ else this.process_model = this.model;
+ },
+ process_check: function() {
+ var self = this,
+ grandparent = this.widget_parent && this.widget_parent.widget_parent,
+ view = this.views[this.views_src[0].view_type],
+ $process_view = this.$element.find('.oe-process-view');
+ if (!(grandparent instanceof openerp.web.WebClient) ||
+ !(view.view_type === this.views_src[0].view_type
+ && view.view_id === this.views_src[0].view_id)) {
+ $process_view.hide();
+ return;
+ }
+ $process_view.click(function() {
+ self.initialize_process_view();
+ });
+ },
+ initialize_process_view: function() {
+ var self = this;
+ $.when(this.fields_get(), this.help(), this.get_process_object()).pipe(function(fields, help, process) {
+ self.process_fields = fields;
+ self.process_help = help;
+ if(process && process.length) {
+ if(process.length > 1) {
+ self.process_selection = process;
+ } else {
+ self.process_id = process[0][0],
+ self.process_title = process[0][1];
+ }
+ }
+ return $.Deferred().resolve();
+ }).pipe(function() {
+ var def = $.Deferred();
+ if(self.process_id) {
+ self.graph_get().done(function(res) {
+ self.process_notes = res.notes;
+ self.process_subflows = _.filter(res.nodes, function(x) {
+ return x.subflow != false;
+ });
+ self.process_related = res.related;
+ def.resolve(res);
+ });
+ } else def.resolve();
+ return def.promise();
+ }).done(function(res) {
+ $.when(self.render_process_view()).done(function() {
+ if(res) self.draw_process_graph(res);
+ });
+ });
+ },
+ graph_get: function() {
+ var self = this;
+ var def = $.Deferred();
+ this.process_id = parseInt(this.process_id, 10);
+
+ this.process_dataset
+ .call("graph_get",[this.process_id, this.model || this.dataset.model, false, [80,80,150,100]])
+ .done(function(res) {
+ self.process_dataset
+ .call("search_by_model",[self.model || self.dataset.model,self.session.context])
+ .done(
+ function(r) {
+ res['related'] = r;
+ def.resolve(res);
+ });
+ });
+ return def.promise();
+ },
+ fields_get : function() {
+ var self = this,
+ def = $.Deferred(),
+ dataset = new openerp.web.DataSetStatic(this, this.model || this.dataset.model, this.session.context);
+ dataset
+ .call('fields_get',[])
+ .done(function(fields) {
+ def.resolve(fields);
+ }).fail(def.reject);
+ return def.promise();
+ },
+ help : function() {
+ var self = this,
+ def = $.Deferred();
+ if(!this.subflow_model) {
+ def.resolve(this.action ? (this.action.help!=false ? this.action.help : 'Help: Not Defined') : 'Help: Not Defined');
+ } else {
+ var dataset = new openerp.web.DataSetSearch(this, "ir.actions.act_window", this.session.context, []);
+ dataset
+ .read_slice(['help'],
+ {
+ domain: [
+ ['res_model', '=', this.subflow_model],
+ ['name', 'ilike', this.subflow_name]
+ ]
+ }
+ ).done(function(res) {
+ def.resolve(res.help || 'Help: Not Defined');
+ });
+ }
+ return def.promise();
+ },
+ get_process_object : function() {
+ var self = this,
+ def = $.Deferred();
+ if(this.process_id)
+ return def.resolve().promise();
+
+ this.process_dataset = new openerp.web.DataSetStatic(this, "process.process", this.session.context);
+ this.process_dataset
+ .call("search_by_model", [self.process_model,self.session.context])
+ .done(function(res) {
+ if (!res.length) {
+ self.process_model = false;
+ self.get_process_object().done(def.resolve);
+ }
+ else {
+ def.resolve(res);
+ }
+ })
+ .fail(def.reject);
+ return def.promise();
+ },
+ render_process_view : function() {
+ this.$element.html(QWeb.render("ProcessView", this));
+ var self = this;
+ this.$element.find('#edit_process').click(function() {
+ self.edit_process_view();
+ });
+ var $parent = this.widget_parent.$element;
+ $parent.find('#change_process').click(function() {
+ self.process_selection = false,
+ self.process_id = $parent.find('#select_process').val(),
+ self.process_title = $.trim($parent.find('#select_process option:selected').text());
+ self.initialize_process_view();
+ });
+
+ this.$element.find(".toggle_fields").click(function() {
+ $(this).children().toggle();
+ self.$element.find('.process_fields').toggle();
+ });
+
+ this.$element.find(".process_subflow").click(function() {
+ self.process_id = this.id;
+ self.initialize_process_view();
+ });
+ },
+ draw_process_graph : function(res) {
+ var self = this,
+ process_graph = new Graph();
+ var process_renderer = function(r, n) {
+ var process_node,
+ process_node_text,
+ process_node_desc,
+ process_set;
+
+ var node_button,
+ node_menu,
+ img_src;
+
+ var bg = "node",
+ clip_rect = "".concat(n.node.x,",",n.node.y,",150,100");
+
+ //Image part
+ bg = n.node.kind == "subflow" ? "node-subflow" : "node";
+ bg = n.node.gray ? bg + "-gray" : bg;
+ img_src = '/web_process/static/src/img/'+ bg + '.png';
+
+ r['image'](img_src, n.node.x, n.node.y,150, 100)
+ .attr({"clip-rect": clip_rect})
+ .mousedown(function() {
+ return false;
+ });
+ //Node
+ process_node = r['rect'](n.node.x, n.node.y, 150, 100).attr({stroke: "none"});
+ // Node text
+ process_node_text = r.text(n.node.x, n.node.y, (n.node.name))
+ .attr({"fill": "#fff", "font-weight": "bold", "cursor": "pointer"});
+ process_node_text.translate((process_node.getBBox().width/ 2) + 5, 10)
+ if(n.node.subflow) {
+ process_node_text.click(function() {
+ self.process_id = n.node.subflow[0];
+ self.subflow_model = n.node.model;
+ self.subflow_name = n.node.name;
+ self.initialize_process_view();
+ });
+ }
+ //Node Description
+ new_notes = n.node.notes;
+ if(n.node.notes.length > 25) {
+ var new_notes= temp_str = '';
+ var from = to = 0;
+ while (1) {
+ from = 25;
+ temp_str = n.node.notes.substr(to ,25);
+ if (temp_str.lastIndexOf(" ") < 25 && temp_str.length >= 25) {
+ from = temp_str.lastIndexOf(" ");
+ }
+ new_notes += "\n" + n.node.notes.substr(to , from);
+ if(new_notes.length > n.node.notes.length) break;
+ to += from;
+ }
+ }
+ process_node_desc = r.text(n.node.x+85, n.node.y+50, (new_notes));
+ r['image']('/web/static/src/img/icons/gtk-info.png', n.node.x+20, n.node.y+70, 16, 16)
+ .attr({"cursor": "pointer", "title": "Help"})
+ .click(function() {
+ window.open(n.node.url || "http://doc.openerp.com/v6.0/index.php?model=" + n.node.model);
+ });
+
+ if(n.node.menu) {
+ r['image']('/web/static/src/img/icons/gtk-jump-to.png', n.node.x+115, n.node.y+70, 16, 16)
+ .attr({"cursor": "pointer", "title": n.node.menu.name})
+ .click(function() {
+ self.jump_to_view(n.node.res_model, n.node.menu.id);
+ });
+ }
+
+ process_set = r.set().push(process_node);
+ process_set.mousedown(function() {
+ return false;
+ });
+ return process_set;
+ };
+
+ _.each(res['nodes'],function(node, node_id) {
+ node['res_model'] = self.model,
+ node['res_id'] = false,
+ node['id'] = node_id;
+ process_graph.addNode(node['name'], {node: node,render: process_renderer});
+ });
+
+ _.each(res['transitions'], function(transitions) {
+ var src = res['nodes'][transitions['source']];
+ var dst = res['nodes'][transitions['target']];
+ // make active
+ transitions['active'] = src.active && !dst.gray;
+ process_graph.addEdge(src['name'], dst['name'], {directed : true});
+ });
+
+ var layouter = new Graph.Layout.Ordered(process_graph);
+ var render_process_graph = new Graph.Renderer.Raphael('process_canvas', process_graph, $('#process_canvas').width(), $('#process_canvas').height());
+ },
+ jump_to_view: function(model, id) {
+ var self = this;
+ var dataset = new openerp.web.DataSetStatic(this, 'ir.values', this.session.context);
+ dataset.call('get',
+ ['action', 'tree_but_open',[['ir.ui.menu', id]], dataset.context],
+ function(res) {
+ self.$element.empty();
+ var action = res[0][res[0].length - 1];
+ self.rpc("/web/action/load", {
+ action_id: action.id,
+ context: dataset.context
+ }, function(result) {
+ var action_manager = new openerp.web.ActionManager(self);
+ action_manager.appendTo(self.widget_parent.$element);
+ action_manager.do_action(result.result);
+ });
+ });
+ },
+ edit_process_view: function() {
+ var self = this;
+ var action_manager = new openerp.web.ActionManager(this);
+ var dialog = new openerp.web.Dialog(this, {
+ width: 800,
+ height: 600,
+ buttons : {
+ Cancel : function() {
+ $(this).dialog('destroy');
+ },
+ Save : function() {
+ var form_view = action_manager.inner_viewmanager.views.form.controller;
+
+ form_view.do_save(function() {
+ self.initialize_process_view();
+ });
+ $(this).dialog('destroy');
+ }
+ }
+ }).start().open();
+
+ action_manager.appendTo(dialog.$element);
+ action_manager.do_action({
+ res_model : 'process.process',
+ res_id: self.process_id,
+ views : [[false, 'form']],
+ type : 'ir.actions.act_window',
+ auto_search : false,
+ flags : {
+ search_view: false,
+ sidebar : false,
+ views_switcher : false,
+ action_buttons : false,
+ pager: false
+ }
+ });
+ },
+ });
+};
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web_process/static/src/xml/web_process.xml b/addons/web_process/static/src/xml/web_process.xml
new file mode 100644
index 00000000000..63e207a4f96
--- /dev/null
+++ b/addons/web_process/static/src/xml/web_process.xml
@@ -0,0 +1,143 @@
+<template>
+ <t t-extend="ViewManager" t-name="ViewManagerAction">
+ <t t-jquery=".oe-view-manager-header" t-operation="append">
+ <img class="oe-process-view" src="/web/static/src/img/icons/gtk-help.png" title="ProcessView"/>
+ </t>
+ </t>
+ <t t-name="ProcessView">
+ <table class="view" border="0" width="100%" height="100%" cellpadding="0" cellspacing="0">
+ <tr>
+ <td width="75%" valign="top" class="fields collapsed" style="padding-top:10px;">
+ <h1 class="process_h1">
+ <t t-esc="action.name"/> (<t t-esc="model"/>)
+ </h1>
+ <p class="process-links">
+ <a class="cta-a" target="_blank" href="#">
+ <span>
+ <strong>Documentation</strong>
+ Read Documentation Online
+ </span>
+ </a>
+ <a class="cta-a" target="_blank" href="http://www.openerp.com/forum/">
+ <span>
+ <strong>Forum</strong>
+ Community Discussion
+ </span>
+ </a>
+ <a class="cta-a" target="_blank" href="http://www.openerp.com/services/books">
+ <span>
+ <strong>Books</strong>
+ Get the book on Amazon
+ </span>
+ </a>
+ <a class="cta-a" target="_blank" href="http://www.openerp.com/services/subscribe-onsite">
+ <span>
+ <strong>Support / Publisher Warranty</strong>
+ Get the OpenERP Warranty
+ </span>
+ </a>
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p><t t-esc="process_help"/></p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <h2>
+ <t t-esc="process_title"/> Process
+ </h2>
+ <t t-if="process_notes">
+ <p>
+ <strong>Notes:</strong> <t t-esc="process_notes"/>
+ </p>
+ <p>
+ <strong>Last modified by:</strong> N/A
+ </p>
+ <t t-if="process_subflows.length">
+ <strong>Subflows:</strong>
+
+ <t t-foreach="process_subflows" t-as="subflow">
+ <t t-if="subflow.subflow[0] != process_id">
+ <p>
+ <a class="process_subflow" t-att-id="subflow.subflow[0]" href="javascript: void(0)">
+ <t t-esc="subflow.subflow[1]"/>
+ </a>
+ </p>
+ </t>
+ </t>
+ </t>
+ <t t-if="process_related.length and process_related[0][0] != process_id">
+ <strong>Related:</strong>
+ <p>
+ <a class="process_subflow" t-att-id="process_related[0][0]" href="javascript: void(0)">
+ <t t-esc="process_related[0][1]"/>
+ </a>
+ </p>
+ </t>
+ </t>
+ </td>
+ </tr>
+ <tr t-if="process_selection">
+ <td>
+ <fieldset>
+ <legend>
+ Select Process
+ </legend>
+ <select id="select_process">
+ <t t-foreach="process_selection" t-as="prc">
+ <option t-att-value="prc[0]">
+ <t t-esc="prc[1]"/>
+ </option>
+ </t>
+ </select>
+ <button id="change_process">Select</button>
+ </fieldset>
+ </td>
+ </tr>
+ <tr t-if="process_id">
+ <td>
+ <div id="process_canvas" style="overflow: auto;"></div>
+ </td>
+ </tr>
+ <tr t-if="process_id">
+ <td>
+ <button id="edit_process">Edit Process</button>
+ <button class="toggle_fields">
+ <span>Show Fields</span>
+ <span>Hide Fields</span>
+ </button>
+ </td>
+ </tr>
+ <tr t-if="process_id">
+ <td class="process_fields">
+ <table>
+ <t t-foreach="process_fields" t-as="field">
+ <tr>
+ <td>
+ <t t-esc="field"/>
+ </td>
+ <td>
+ <table>
+ <t t-foreach="field_value" t-as="fld">
+ <tr>
+ <td>
+ <t t-esc="fld"/>:
+ </td>
+ <td>
+ <t t-esc="fld_value"/>
+ </td>
+ </tr>
+ </t>
+ </table>
+ </td>
+ </tr>
+ </t>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </t>
+</template> \ No newline at end of file