Commit 8127666c authored by Jérome Perrin's avatar Jérome Perrin

Update Graph Editor

* Fixes https://erp5js.nexedi.net/#/bug_module/20160609-11B02E6 and https://erp5js.nexedi.net/#/bug_module/20210517-F12266
* Support ERP5JS
* Improve test coverage
* Small CSS changes
* Fix bug editing business process when erp5_graph_editor was installed 

See merge request !1461
parents f359f267 3272990a
...@@ -75,26 +75,20 @@ ...@@ -75,26 +75,20 @@
<key> <string>bottom</string> </key> <key> <string>bottom</string> </key>
<value> <value>
<list> <list>
<string>listbox</string> <string>my_jsplumb_graph</string>
</list> </list>
</value> </value>
</item> </item>
<item> <item>
<key> <string>center</string> </key> <key> <string>center</string> </key>
<value> <value>
<list> <list/>
<string>my_jsplumb_graph</string>
</list>
</value> </value>
</item> </item>
<item> <item>
<key> <string>hidden</string> </key> <key> <string>hidden</string> </key>
<value> <value>
<list> <list/>
<string>listbox_int_index</string>
<string>listbox_order_builder_title_list</string>
<string>listbox_delivery_builder_title_list</string>
</list>
</value> </value>
</item> </item>
<item> <item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>columns</string>
<string>editable_columns</string>
<string>enabled</string>
<string>portal_types</string>
<string>sort</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>columns</string> </key>
<value>
<list>
<tuple>
<string>int_index</string>
<string>Index</string>
</tuple>
<tuple>
<string>title</string>
<string>Title</string>
</tuple>
<tuple>
<string>predecessor_title</string>
<string>Predecessor</string>
</tuple>
<tuple>
<string>successor_title</string>
<string>Successor</string>
</tuple>
<tuple>
<string>order_builder_title_list</string>
<string>Order Builders</string>
</tuple>
<tuple>
<string>delivery_builder_title_list</string>
<string>Delivery Builders</string>
</tuple>
<tuple>
<string>trade_phase_title</string>
<string>Trade Phase</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>editable_columns</string> </key>
<value>
<list>
<tuple>
<string>int_index</string>
<string>int_index</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewTradeFieldLibrary</string> </value>
</item>
<item>
<key> <string>portal_types</string> </key>
<value>
<list>
<tuple>
<string>Business Link</string>
<string>Business Link</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>sort</string> </key>
<value>
<list>
<tuple>
<string>int_index</string>
<string>ascending</string>
</tuple>
</list>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Business Links</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_delivery_builder_title_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox_delivery_builder_title_list</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewTradeFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_int_index</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox_int_index</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewTradeFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>listbox_order_builder_title_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_view_mode_listbox_order_builder_title_list</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewTradeFieldLibrary</string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -227,7 +227,7 @@ ...@@ -227,7 +227,7 @@
</item> </item>
<item> <item>
<key> <string>gadget_url</string> </key> <key> <string>gadget_url</string> </key>
<value> <string>dream_graph_editor/jsplumb/index.html</string> </value> <value> <string>gadget_graph_editor.html</string> </value>
</item> </item>
<item> <item>
<key> <string>hidden</string> </key> <key> <string>hidden</string> </key>
...@@ -235,7 +235,7 @@ ...@@ -235,7 +235,7 @@
</item> </item>
<item> <item>
<key> <string>js_sandbox</string> </key> <key> <string>js_sandbox</string> </key>
<value> <string></string> </value> <value> <string>iframe</string> </value>
</item> </item>
<item> <item>
<key> <string>renderjs_extra</string> </key> <key> <string>renderjs_extra</string> </key>
...@@ -253,11 +253,11 @@ ...@@ -253,11 +253,11 @@
</item> </item>
<item> <item>
<key> <string>validator_field_id</string> </key> <key> <string>validator_field_id</string> </key>
<value> <string></string> </value> <value> <string>my_core_mode_text_content_validator</string> </value>
</item> </item>
<item> <item>
<key> <string>validator_form_id</string> </key> <key> <string>validator_form_id</string> </key>
<value> <string></string> </value> <value> <string>Base_viewFieldLibrary</string> </value>
</item> </item>
</dictionary> </dictionary>
</value> </value>
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
<item> <item>
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list/> <list>
<string>editable</string>
</list>
</value> </value>
</item> </item>
<item> <item>
...@@ -69,6 +71,10 @@ ...@@ -69,6 +71,10 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_view_mode_reference</string> </value> <value> <string>my_view_mode_reference</string> </value>
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
<item> <item>
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list/> <list>
<string>editable</string>
</list>
</value> </value>
</item> </item>
<item> <item>
...@@ -69,6 +71,10 @@ ...@@ -69,6 +71,10 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>editable</string> </key>
<value> <int>0</int> </value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_view_mode_title</string> </value> <value> <string>my_view_mode_title</string> </value>
......
...@@ -3,7 +3,6 @@ from Products.Formulator.Errors import FormValidationError ...@@ -3,7 +3,6 @@ from Products.Formulator.Errors import FormValidationError
request = container.REQUEST request = container.REQUEST
form = getattr(context, form_id) form = getattr(context, form_id)
edit_order = form.edit_order
try: try:
# Validate # Validate
form.validate_all_to_request(request, key_prefix='my_') form.validate_all_to_request(request, key_prefix='my_')
...@@ -16,7 +15,7 @@ except FormValidationError, validation_errors: ...@@ -16,7 +15,7 @@ except FormValidationError, validation_errors:
result['field_errors'][key] = value.error_text result['field_errors'][key] = value.error_text
return form() return form()
(kw, encapsulated_editor_list), action = context.Base_edit(form_id, silent_mode=1) (kw, encapsulated_editor_list), _ = context.Base_edit(form_id, silent_mode=1)
assert not encapsulated_editor_list assert not encapsulated_editor_list
context.setProperties( context.setProperties(
......
from Products.ERP5Type.Message import translateString
import json import json
portal = context.getPortalObject()
# if a graph has been saved, we use this info for node coordinates. # if a graph has been saved, we use this info for node coordinates.
position_graph = context.getProperty('jsplumb_graph') position_graph = context.getProperty('jsplumb_graph')
......
from Products.ERP5Type.Message import translateString
import json import json
portal = context.getPortalObject()
# if a graph has been saved, we use this info for node coordinates. # if a graph has been saved, we use this info for node coordinates.
position_graph = context.getProperty('jsplumb_graph') position_graph = context.getProperty('jsplumb_graph')
...@@ -37,11 +35,8 @@ def getWorkflowGraph(workflow): ...@@ -37,11 +35,8 @@ def getWorkflowGraph(workflow):
'transition_id': transition.getId(), # used for edition. 'transition_id': transition.getId(), # used for edition.
'path': transition.getPath() 'path': transition.getPath()
}) })
else:
# user action
transition_list.append(transition)
if transition_list != []: if transition_list:
graph['edge']['transition_to_%s' % (state.getId())] = { graph['edge']['transition_to_%s' % (state.getId())] = {
'_class':'workflow.transition', '_class':'workflow.transition',
'source':state.getId(), 'source':state.getId(),
......
...@@ -4,53 +4,25 @@ ...@@ -4,53 +4,25 @@
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="stylesheet" href="../lib/jquery-ui.css"> <link rel="stylesheet" href="../lib/jquery-ui.css">
<link rel="stylesheet" href="jsplumb.css"> <link rel="stylesheet" href="jsplumb.css">
<title>JSPlumb gadget</title> <title>JSPlumb public gadget (for qunit tests)</title>
<!-- <!--
FIXME: renderjs fails if we include renderjs.js twice (this one has a different URL from ERP5's one) The gadget for test is used with "public" sandbox, so we should not include javascripts again.
The following scripts must have been included by the parent page:
<script src="renderjs.js" type="text/javascript"></script> <script src="renderjs.js" type="text/javascript"></script>
<script src="rsvp.js" type="text/javascript"></script> <script src="rsvp.js" type="text/javascript"></script>
-->
<!--
FIXME: Including jQuery twice cause the jsplumb to be loaded twice.
For now we assume that it has already been loaded at this point.
<script src="../lib/jquery.js" type="text/javascript"></script> <script src="../lib/jquery.js" type="text/javascript"></script>
--> -->
<script src="../lib/jquery-ui.js" type="text/javascript"></script> <script src="../lib/jquery-ui.js" type="text/javascript"></script>
<script src="../lib/jquery.jsplumb.js" type="text/javascript"></script> <script src="../lib/jquery.jsplumb.js" type="text/javascript"></script>
<script src="../lib/handlebars.min.js" type="text/javascript"></script> <script src="../lib/handlebars.min.js" type="text/javascript"></script>
<script src="seedrandom.js" type="text/javascript"></script>
<script src="../lib/springy.js" type="text/javascript"></script> <script src="../lib/springy.js" type="text/javascript"></script>
<script src="../dream/mixin_promise.js" type="text/javascript"></script> <script src="../dream/mixin_promise.js" type="text/javascript"></script>
<script src="jsplumb.js" type="text/javascript"></script> <script src="jsplumb.js" type="text/javascript"></script>
<script id="node-template" type="text/x-handlebars-template">
<div class="window {{class}}"
id="{{element_id}}"
title="{{title}}">
<a href="{{name_href}}">{{name}}</a>
<div class="ep"></div>
</div>
</script>
<script id="popup-edit-template" type="text/x-handlebars-template">
<div id="edit-popup" data-position-to="origin">
<div data-role="header" data-theme="a">
<h1 class="node_class">Edit properties</h1>
<!-- XXX add this for jquery mobile version.
<a href="#" data-rel="back" class="ui-btn ui-corner-all ui-shadow ui-btn-a ui-icon-delete ui-btn-icon-notext ui-btn-right">Close</a>
-->
</div>
<br/>
<form class="ui-content">
<fieldset></fieldset>
<input type="button" value="Delete" class="graph_editor_delete_button">
<input type="submit" value="Validate" class="graph_editor_validate_button">
</form>
</div>
</script>
</head> </head>
<body> <body>
<div class="graph_container"></div> <div class="graph_container"></div>
<div class="dummy_window"></div> <div class="dummy_window"></div>
</body> </body>
</html> </html>
\ No newline at end of file
body {
margin: 0px;
}
.graph_container { .graph_container {
position: relative; position: relative;
font-size: 80%; font-size: 0.8em;
border: 1px solid #999; width: 100vw;
height: 100vh;
min-width: 400px;
min-height: 1200px;
overflow: hidden; overflow: hidden;
background-color: #eaedef; background-color: #eaedef;
text-align: center; text-align: center;
} font-family: helvetica;
.selected {
color: #bd0b0b!important
} }
.window, .window,
...@@ -26,6 +25,7 @@ ...@@ -26,6 +25,7 @@
-webkit-box-shadow: 2px 2px 19px #aaa; -webkit-box-shadow: 2px 2px 19px #aaa;
-moz-box-shadow: 2px 2px 19px #aaa -moz-box-shadow: 2px 2px 19px #aaa
} }
path, path,
._jsPlumb_endpoint { ._jsPlumb_endpoint {
cursor: pointer cursor: pointer
...@@ -46,6 +46,11 @@ path, ...@@ -46,6 +46,11 @@ path,
._jsPlumb_overlay { ._jsPlumb_overlay {
z-index: 23 z-index: 23
} }
._jsPlumb_overlay._jsPlumb_hover {
z-index: 25!important;
font-size: 1.2em;
font-weight: bold;
}
._jsPlumb_connector._jsPlumb_hover { ._jsPlumb_connector._jsPlumb_hover {
z-index: 21!important z-index: 21!important
} }
...@@ -58,8 +63,7 @@ path, ...@@ -58,8 +63,7 @@ path,
filter: alpha(opacity=80); filter: alpha(opacity=80);
background-color: #fff; background-color: #fff;
color: #000; color: #000;
font-family: helvetica; padding: .5em;
padding: .5em
} }
.window, .window,
.dummy_window { .dummy_window {
...@@ -69,12 +73,9 @@ path, ...@@ -69,12 +73,9 @@ path,
box-sizing: border-box; box-sizing: border-box;
position: absolute; position: absolute;
color: #000; color: #000;
font-family: serif;
font-style: italic;
padding-top: .9em; padding-top: .9em;
font-size: .9em; font-size: .9em;
cursor: move; cursor: move;
font-size: 11px;
-webkit-transition: background-color .1s ease-in; -webkit-transition: background-color .1s ease-in;
-moz-transition: background-color .1s ease-in; -moz-transition: background-color .1s ease-in;
transition: background-color .1s ease-in; transition: background-color .1s ease-in;
...@@ -83,13 +84,15 @@ path, ...@@ -83,13 +84,15 @@ path,
.window:hover { .window:hover {
background-color: #5c96bc; background-color: #5c96bc;
background-image: none; background-image: none;
color: #fff color: #fff;
font-weight: bold;
} }
.dummy_window { .dummy_window {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
visibility: hidden visibility: hidden;
z-index: -1;
} }
.ep { .ep {
position: absolute; position: absolute;
...@@ -109,8 +112,10 @@ path, ...@@ -109,8 +112,10 @@ path,
.dragHover { .dragHover {
background-color: #1e8151; background-color: #1e8151;
background-image: none; background-image: none;
color: #fff color: #fff;
font-weight: bold;
} }
path { path {
cursor: pointer cursor: pointer
} }
\ No newline at end of file
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
(function (RSVP, rJS, $, jsPlumb, Handlebars, loopEventListener, promiseEventListener, DOMParser, Springy) { (function (RSVP, rJS, $, jsPlumb, Handlebars, loopEventListener, promiseEventListener, DOMParser, Springy) {
"use strict"; "use strict";
/* TODO: /* TODO:
* less dependancies ( promise event listener ? ) * less dependencies ( promise event listener ? )
* no more handlebars * no more handlebars
* id should not always be modifiable * id should not always be modifiable
* drop zoom level * drop zoom level
...@@ -31,9 +31,30 @@ ...@@ -31,9 +31,30 @@
*/ */
var gadget_klass = rJS(window); var gadget_klass = rJS(window);
var domParser = new DOMParser(); var domParser = new DOMParser();
var node_template_source = gadget_klass.__template_element.getElementById("node-template").innerHTML; var node_template = Handlebars.compile(
var node_template = Handlebars.compile(node_template_source); ' <div class="window {{class}}"'
var popup_edit_template = gadget_klass.__template_element.getElementById("popup-edit-template").innerHTML; + ' id="{{element_id}}"'
+ ' title="{{title}}">'
+ ' {{name}}'
+ ' <div class="ep"></div>'
+ '</div>'
);
var popup_edit_template = (
' <div id="edit-popup" data-position-to="origin">'
+ ' <div data-role="header" data-theme="a">'
+ ' <h1 class="node_class">Edit properties</h1>'
+ ' <!-- XXX add this for jquery mobile version.'
+ ' <a href="#" data-rel="back" class="ui-btn ui-corner-all ui-shadow ui-btn-a ui-icon-delete ui-btn-icon-notext ui-btn-right">Close</a>'
+ ' -->'
+ ' </div>'
+ ' <br/>'
+ ' <form class="ui-content">'
+ ' <fieldset></fieldset>'
+ ' <input type="button" value="Delete" class="graph_editor_delete_button">'
+ ' <input type="submit" value="Validate" class="graph_editor_validate_button">'
+ ' </form>'
+ '</div>'
);
function layoutGraph(graph_data) { function layoutGraph(graph_data) {
// Promise returning the graph once springy calculated the layout. // Promise returning the graph once springy calculated the layout.
...@@ -204,8 +225,8 @@ ...@@ -204,8 +225,8 @@
function updateConnectionData(gadget, connection, remove) { function updateConnectionData(gadget, connection, remove) {
if (connection.ignoreEvent) { if (connection.ignoreEvent) {
// this hack is for edge edition. Maybe there I missed one thing and // this hack is for edge edition and when the graph is re-rendered.
// there is a better way. // Maybe there I missed one thing and there is a better way.
return; return;
} }
if (remove) { if (remove) {
...@@ -353,25 +374,11 @@ ...@@ -353,25 +374,11 @@
function addEdge(gadget, edge_id, edge_data) { function addEdge(gadget, edge_id, edge_data) {
var overlays = []; var overlays = [];
var connection; var connection;
var label = '';
if (edge_data.name) { if (edge_data.name) {
label = edge_data.name;
if (edge_data.path) {
label = label.link(edge_data.path);
}
}
if (edge_data.name_path_dict) {
var linked_name_list = [];
for (var name in edge_data.name_path_dict) {
linked_name_list.push(name.link(edge_data.name_path_dict[name]));
}
label = linked_name_list.join(', ');
}
if (label) {
overlays = [ overlays = [
["Label", { ["Label", {
cssClass: "l1 component label", cssClass: "l1 component label",
label: label label: edge_data.name
}] }]
]; ];
} }
...@@ -491,6 +498,82 @@ ...@@ -491,6 +498,82 @@
return clone(expanded_class_definition); return clone(expanded_class_definition);
} }
function openEdgeEditionDialog(gadget, connection) {
var edge_id = connection.id;
var edge_data = gadget.props.data.graph.edge[edge_id];
var edit_popup = $(gadget.props.element).find("#popup-edit-template");
var schema;
var fieldset_element;
var delete_promise;
var class_definition = gadget.props.data.class_definition[edge_data._class];
if (class_definition === undefined) {
return;
}
schema = expandSchema(class_definition, gadget.props.data);
// We do not edit source & destination on edge this way.
delete schema.properties.source;
delete schema.properties.destination;
gadget.props.element.insertAdjacentHTML("beforeend", popup_edit_template);
edit_popup = $(gadget.props.element).find("#edit-popup");
edit_popup.find(".node_class").text(connection.name || connection._class);
fieldset_element = edit_popup.find("fieldset")[0];
edit_popup.dialog();
edit_popup.show();
function save_promise(fieldset_gadget) {
return new RSVP.Queue().push(function () {
return promiseEventListener(edit_popup.find(".graph_editor_validate_button")[0], "click", false);
}).push(function (evt) {
var data = {
id: $(evt.target[1]).val(),
data: {}
};
return fieldset_gadget.getContent().then(function (r) {
$.extend(data.data, gadget.props.data.graph.edge[connection.id]);
$.extend(data.data, r);
// to redraw, we remove the edge and add again.
// but we want to disable events on connection, since event
// handling promise are executed asynchronously in undefined order,
// we cannot just remove and /then/ add, because the new edge is
// added before the old is removed.
connection.ignoreEvent = true;
gadget.props.jsplumb_instance.detach(connection);
addEdge(gadget, r.id, data.data);
});
});
}
delete_promise = new RSVP.Queue().push(function () {
return promiseEventListener(edit_popup.find(".graph_editor_delete_button")[0], "click", false);
}).push(function () {
// connectionDetached event will remove the edge from data
gadget.props.jsplumb_instance.detach(connection);
});
return gadget.declareGadget("dream_graph_editor/fieldset/index.html", {
element: fieldset_element,
scope: "fieldset"
}).push(function (fieldset_gadget) {
return RSVP.all([fieldset_gadget, fieldset_gadget.render({
value: edge_data,
property_definition: schema
}, edge_id)]);
}).push(function (fieldset_gadget) {
edit_popup.dialog("open");
return fieldset_gadget[0];
}).push(function (fieldset_gadget) {
fieldset_gadget.startService(); // XXX
return fieldset_gadget;
}).push(function (fieldset_gadget) {
// Expose the dialog handling promise so that we can wait for it in
// test.
gadget.props.dialog_promise = RSVP.any([save_promise(fieldset_gadget, edge_id), delete_promise]);
return gadget.props.dialog_promise;
}).push(function () {
edit_popup.dialog("close");
edit_popup.remove();
delete gadget.props.dialog_promise;
});
}
function openNodeEditionDialog(gadget, element) { function openNodeEditionDialog(gadget, element) {
var node_id = getNodeId(gadget, element.id); var node_id = getNodeId(gadget, element.id);
var node_data = gadget.props.data.graph.node[node_id]; var node_data = gadget.props.data.graph.node[node_id];
...@@ -544,7 +627,7 @@ ...@@ -544,7 +627,7 @@
}).push(function () { }).push(function () {
return removeElement(gadget, node_id); return removeElement(gadget, node_id);
}); });
return gadget.declareGadget("../fieldset/index.html", { return gadget.declareGadget("dream_graph_editor/fieldset/index.html", {
element: fieldset_element, element: fieldset_element,
scope: "fieldset" scope: "fieldset"
}).push(function (fieldset_gadget) { }).push(function (fieldset_gadget) {
...@@ -588,6 +671,12 @@ ...@@ -588,6 +671,12 @@
}); });
} }
function waitForConnectionClick(gadget) {
return loopJsplumbBind(gadget, "click", function (connection) {
return openEdgeEditionDialog(gadget, connection);
});
}
function addNode(gadget, node_id, node_data) { function addNode(gadget, node_id, node_data) {
var render_element = $(gadget.props.main); var render_element = $(gadget.props.main);
var class_definition = gadget.props.data.class_definition[node_data._class]; var class_definition = gadget.props.data.class_definition[node_data._class];
...@@ -612,8 +701,7 @@ ...@@ -612,8 +701,7 @@
"class": node_data._class.replace(".", "-"), "class": node_data._class.replace(".", "-"),
element_id: dom_element_id, element_id: dom_element_id,
title: node_data.name || node_data.id, title: node_data.name || node_data.id,
name: node_data.name || node_data.id, name: node_data.name || node_data.id
name_href: node_data.path
}), "text/html").querySelector(".window"); }), "text/html").querySelector(".window");
render_element.append(domElement); render_element.append(domElement);
box = $(gadget.props.element).find("#" + dom_element_id); box = $(gadget.props.element).find("#" + dom_element_id);
...@@ -623,10 +711,6 @@ ...@@ -623,10 +711,6 @@
} }
box.css("top", absolute_position[1]); box.css("top", absolute_position[1]);
box.css("left", absolute_position[0]); box.css("left", absolute_position[0]);
if (node_data.is_initial_state) {
box.css("border", "double #000000");
box.css("font-weight", "bold");
}
updateNodeStyle(gadget, dom_element_id); updateNodeStyle(gadget, dom_element_id);
draggable(gadget); draggable(gadget);
// XXX make only this element draggable. // XXX make only this element draggable.
...@@ -731,6 +815,20 @@ ...@@ -731,6 +815,20 @@
} }
}); });
*/ */
// reset previous graph, if any.
if ($(".window", this.props.element).length) {
$.each(
// disable the "delete" event, otherwise after render load the
// graph, loopJsplumbBind events will process the connection deleted
// events
this.props.jsplumb_instance.getAllConnections(),
function (i, connection) {
connection.ignoreEvent = true;
});
this.props.jsplumb_instance.reset();
$(".window", this.props.element).remove();
}
if (data) { if (data) {
this.props.data = JSON.parse(data); this.props.data = JSON.parse(data);
...@@ -803,7 +901,8 @@ ...@@ -803,7 +901,8 @@
return RSVP.all([ return RSVP.all([
waitForDrop(gadget), waitForDrop(gadget),
waitForConnection(gadget), waitForConnection(gadget),
waitForConnectionDetached(gadget) waitForConnectionDetached(gadget),
waitForConnectionClick(gadget)
]); ]);
}); });
......
...@@ -296,7 +296,7 @@ ...@@ -296,7 +296,7 @@
jsplumb_gadget.render(sample_data_graph); jsplumb_gadget.render(sample_data_graph);
}).then(runTest).fail(error_handler).always(start); }).then(runTest).fail(error_handler).always(start);
}); });
test("Node can be connected", function () { test("Nodes can be connected", function () {
var jsplumb_gadget; var jsplumb_gadget;
stop(); stop();
function runTest() { function runTest() {
...@@ -308,6 +308,9 @@ ...@@ -308,6 +308,9 @@
source: node1.id, source: node1.id,
target: node2.id target: node2.id
}); });
// .connect insternal API is asynchronous, but there's no way to wait for the event to be processed.
// for now we just wait for a short delay
return RSVP.delay(1e3);
}).then(function () { }).then(function () {
return jsplumb_gadget.getContent(); return jsplumb_gadget.getContent();
}).then(function (content) { }).then(function (content) {
...@@ -588,5 +591,24 @@ ...@@ -588,5 +591,24 @@
}); });
}).fail(error_handler).always(start); }).fail(error_handler).always(start);
}); });
test("Gadget can be rendered multiple times", function () {
var jsplumb_gadget;
stop();
g.declareGadget("./index.html", {
element: document.querySelector("#test-element")
}).then(function (new_gadget) {
jsplumb_gadget = new_gadget;
return jsplumb_gadget.render(sample_data_graph);
}).then(function () {
return jsplumb_gadget.getContent();
}).then(function () {
return jsplumb_gadget.render(sample_data_graph);
}).then(function () {
return jsplumb_gadget.getContent();
}).then(function (content) {
equal(sample_data_graph, content);
equal($(".window", document.querySelector("#test-element")).length, 2, "Graph is rendered only once");
}).fail(error_handler).always(start);
});
}); });
}(rJS, JSON, QUnit, RSVP, jQuery)); }(rJS, JSON, QUnit, RSVP, jQuery));
\ No newline at end of file
...@@ -24,13 +24,6 @@ ...@@ -24,13 +24,6 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
// Nexedi patch: use seedrandom instead of Math.random to always get the same
// graph representation this will in order to be able to use seed and thus
// get the same set of random number, used to set the place of the graph nodes
var seeded_random = new Math.seedrandom('Using seedrandom for getting same set'
+ 'of pseudorandom numbers.');
(function (root, factory) { (function (root, factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module. // AMD. Register as an anonymous module.
...@@ -584,7 +577,7 @@ var seeded_random = new Math.seedrandom('Using seedrandom for getting same set' ...@@ -584,7 +577,7 @@ var seeded_random = new Math.seedrandom('Using seedrandom for getting same set'
}; };
Vector.random = function() { Vector.random = function() {
return new Vector(10.0 * (seeded_random() - 0.5), 10.0 * (seeded_random() - 0.5)); return new Vector(10.0 * (Math.random() - 0.5), 10.0 * (Math.random() - 0.5));
}; };
Vector.prototype.add = function(v2) { Vector.prototype.add = function(v2) {
......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="dream_graph_editor/lib/jquery-ui.css">
<link rel="stylesheet" href="dream_graph_editor/jsplumb/jsplumb.css">
<title>Graph Editor</title>
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<script src="dream_graph_editor/lib/jquery.js" type="text/javascript"></script>
<script src="dream_graph_editor/lib/jquery-ui.js" type="text/javascript"></script>
<script src="dream_graph_editor/lib/jquery.jsplumb.js" type="text/javascript"></script>
<script src="dream_graph_editor/lib/handlebars.min.js" type="text/javascript"></script>
<script src="dream_graph_editor/lib/springy.js" type="text/javascript"></script>
<script src="dream_graph_editor/dream/mixin_promise.js" type="text/javascript"></script>
<script src="dream_graph_editor/jsplumb/jsplumb.js" type="text/javascript"></script>
<body>
<div class="graph_container"></div>
<div class="dummy_window"></div>
</body>
</html>
...@@ -6,17 +6,13 @@ ...@@ -6,17 +6,13 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_Cacheable__manager_id</string> </key>
<value> <string>http_cache</string> </value>
</item>
<item> <item>
<key> <string>__name__</string> </key> <key> <string>__name__</string> </key>
<value> <string>seedrandom.js</string> </value> <value> <string>gadget_graph_editor.html</string> </value>
</item> </item>
<item> <item>
<key> <string>content_type</string> </key> <key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value> <value> <string>text/html</string> </value>
</item> </item>
<item> <item>
<key> <string>precondition</string> </key> <key> <string>precondition</string> </key>
......
...@@ -2,8 +2,6 @@ import json ...@@ -2,8 +2,6 @@ import json
business_process = sci['object'] business_process = sci['object']
graph = business_process.getProperty('jsplumb_graph') graph = business_process.getProperty('jsplumb_graph')
assert graph
if graph: if graph:
portal = business_process.getPortalObject() portal = business_process.getPortalObject()
trade_state_dict = dict(start=None, end=None) trade_state_dict = dict(start=None, end=None)
......
...@@ -13,7 +13,11 @@ Run existing qunit test in zelenium framework, to easily integrate it in current ...@@ -13,7 +13,11 @@ Run existing qunit test in zelenium framework, to easily integrate it in current
<td tal:content="string:${context/portal_url}/dream_graph_editor/jsplumb/test.html"></td> <td tal:content="string:${context/portal_url}/dream_graph_editor/jsplumb/test.html"></td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>waitForTextPresent</td>
<td>Running</td>
<td></td>
</tr>
<tr> <tr>
<td>waitForTextPresent</td> <td>waitForTextPresent</td>
<td>Tests completed in </td> <td>Tests completed in </td>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Image" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>testWorkflowGraph-reference-snapshot-1.png</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>image/png</string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>284</int> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>1127</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testWorkflowGraph</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode>Workflow Graph</unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html>
<head><title tal:content="template/title"></title></head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="4" tal:content="template/title">
</td></tr>
</thead><tbody>
<tr>
<td>open</td>
<td tal:content="string:${context/portal_url}/portal_workflow/validation_workflow/Workflow_viewGraph"></td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@data-gadget-editable="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>//div[@data-gadget-editable="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@class, "workflow-state")][4]</td>
<td></td>
</tr>
<tr>
<td>pause</td>
<td>1000</td>
<td></td>
</tr>
<tr><td colspan="3"><b>Verify the rendering of the graph matches our reference snapshot</b></td></tr>
<tr>
<td>verifyImageMatchSnapshot</td>
<td>//body</td>
<td>1</td>
</tr>
<tr>
<td>selectFrame</td>
<td>relative=top</td>
<td></td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td>assertPortalStatusMessage</td>
<td>Data updated.</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
...@@ -233,7 +233,7 @@ ...@@ -233,7 +233,7 @@
</item> </item>
<item> <item>
<key> <string>gadget_url</string> </key> <key> <string>gadget_url</string> </key>
<value> <string>dream_graph_editor/jsplumb/index.html</string> </value> <value> <string>gadget_graph_editor.html</string> </value>
</item> </item>
<item> <item>
<key> <string>hidden</string> </key> <key> <string>hidden</string> </key>
...@@ -241,7 +241,7 @@ ...@@ -241,7 +241,7 @@
</item> </item>
<item> <item>
<key> <string>js_sandbox</string> </key> <key> <string>js_sandbox</string> </key>
<value> <string></string> </value> <value> <string>iframe</string> </value>
</item> </item>
<item> <item>
<key> <string>renderjs_extra</string> </key> <key> <string>renderjs_extra</string> </key>
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <unicode></unicode> </value> <value> <unicode>Test Item View Tracking List</unicode> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
xmlns:metal="http://xml.zope.org/namespaces/metal"> xmlns:metal="http://xml.zope.org/namespaces/metal">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Item View Tracking List</title> <title tal:content="template/title"></title>
</head> </head>
<body> <body>
<table cellpadding="1" cellspacing="1" border="1"> <table cellpadding="1" cellspacing="1" border="1">
<thead> <thead>
<tr><td rowspan="1" colspan="3">TTest Item View Tracking List/td></tr> <tr><td rowspan="1" colspan="3" tal:content="template/title"></td></tr>
</thead><tbody> </thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForItemRenderjsUi/macros/init" /> <tal:block metal:use-macro="here/Zuite_viewCommonTemplateForItemRenderjsUi/macros/init" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForItemRenderjsUi/macros/prepare_data" /> <tal:block metal:use-macro="here/Zuite_viewCommonTemplateForItemRenderjsUi/macros/prepare_data" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForItemRenderjsUi/macros/view_item_tracking_list" /> <tal:block metal:use-macro="here/Zuite_viewCommonTemplateForItemRenderjsUi/macros/view_item_tracking_list" />
</tbody></table> </tbody></table>
</body> </body>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ERP5Site_createItemRJSZuiteItemAndPackingList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>ItemRJSZuite_deleteData</string> </value> <value> <string>ERP5Site_deleteItemRJSZuiteData</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>Zuite_CommonTemplateForItemRenderjsUi</string> </value> <value> <string>Zuite_viewCommonTemplateForItemRenderjsUi</string> </value>
</item> </item>
<item> <item>
<key> <string>output_encoding</string> </key> <key> <string>output_encoding</string> </key>
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
</tr> </tr>
<tr> <tr>
<td>open</td> <td>open</td>
<td>${base_url}/ItemRJSZuite_deleteData</td> <td>${base_url}/ERP5Site_deleteItemRJSZuiteData</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
...@@ -35,13 +35,13 @@ ...@@ -35,13 +35,13 @@
</tal:block> </tal:block>
<tal:block metal:define-macro="prepare_data"> <tal:block metal:define-macro="prepare_data">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForItemRenderjsUi/macros/delete_data" /> <tal:block metal:use-macro="here/Zuite_viewCommonTemplateForItemRenderjsUi/macros/delete_data" />
<tr> <tr>
<td colspan="3"><b>Create Item Test Data</b></td> <td colspan="3"><b>Create Item Test Data</b></td>
</tr> </tr>
<tr> <tr>
<td>open</td> <td>open</td>
<td>${base_url}/ItemRJSZuite_createItemAndPackingList</td> <td>${base_url}/ERP5Site_createItemRJSZuiteItemAndPackingList</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
...@@ -86,6 +86,29 @@ ...@@ -86,6 +86,29 @@
<td>Purchase Packing List Line</td> <td>Purchase Packing List Line</td>
<td></td> <td></td>
</tr> </tr>
<!-- Graph editor to visualize tracking -->
<tr>
<td>waitForElementPresent</td>
<td>//div[@data-gadget-scope="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>//div[@data-gadget-scope="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@class, "node")][2]</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>relative=top</td>
<td></td>
</tr>
<tal:block tal:define="click_configuration python: {'text': 'Sale Packing List Line'}"> <tal:block tal:define="click_configuration python: {'text': 'Sale Packing List Line'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_page_link" /> <tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_page_link" />
</tal:block> </tal:block>
......
erp5_item erp5_item
erp5_web_renderjs_ui_test erp5_web_renderjs_ui_test
\ No newline at end of file erp5_graph_editor
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testBusinessProcess</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode>Test Business Process</unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html>
<head><title tal:content="template/title"></title></head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="4" tal:content="template/title"></td></tr>
</thead>
<tbody tal:define="init_method string:Zuite_createBusinessProcessForTradeZuite;">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForTradeZuite/macros/init" />
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/business_process_module/test_trade_ui_test_business_process?editable=true</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/save" />
</tbody></table>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testBusinessProcessGraph</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode>Test Business Process Graph</unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html>
<head><title tal:content="template/title"></title></head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="4" tal:content="template/title"></td></tr>
</thead>
<tbody tal:define="init_method string:Zuite_createBusinessProcessForTradeZuite;">
<!-- Setup {{{ -->
<tal:block metal:use-macro="here/Zuite_CommonTemplateForTradeZuite/macros/init" />
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/business_process_module/test_trade_ui_test_business_process?editable=true</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<!-- }}} -->
<tal:block tal:define="click_configuration python: {'text': 'Views'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Graph Editor'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_page_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>waitForElementPresent</td>
<td>//div[@data-gadget-scope="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>//div[@data-gadget-scope="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@class, "erp5-business_process")][5]</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>relative=top</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/save" />
<tr>
<td>waitForElementPresent</td>
<td>//div[@data-gadget-scope="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>//div[@data-gadget-scope="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@class, "erp5-business_process")][5]</td>
<td></td>
</tr>
<tr>
<td>assertElementNotPresent</td>
<td>//div[contains(@class, "erp5-business_process")][6]</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>relative=top</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testBusinessProcess</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode>Test Business Process</unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html>
<head><title tal:content="template/title"></title></head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="4" tal:content="template/title"></td></tr>
</thead>
<tbody tal:define="init_method string:Zuite_createBusinessProcessForTradeZuite;">
<!-- Setup {{{ -->
<tal:block metal:use-macro="here/Zuite_CommonTemplateForTradeZuite/macros/init" />
<!-- }}} -->
<tr>
<td>open</td>
<td>${base_url}/business_process_module/test_trade_ui_test_business_process/</td>
<td></td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td>assertPortalStatusMessage</td>
<td>Data updated.</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testBusinessProcessGraph</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode>Test Business Process Graph</unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html>
<head><title tal:content="template/title"></title></head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="4" tal:content="template/title"></td></tr>
</thead>
<tbody tal:define="init_method string:Zuite_createBusinessProcessForTradeZuite;">
<!-- Setup {{{ -->
<tal:block metal:use-macro="here/Zuite_CommonTemplateForTradeZuite/macros/init" />
<!-- }}} -->
<tr>
<td>open</td>
<td>${base_url}/business_process_module/test_trade_ui_test_business_process/BusinessProcess_viewGraphEditor</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@data-gadget-editable="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>//div[@data-gadget-editable="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@class, "erp5-business_process")][5]</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>relative=top</td>
<td></td>
</tr>
<tr>
<td>clickAndWait</td>
<td>Base_edit:method</td>
<td></td>
</tr>
<tr>
<td>assertPortalStatusMessage</td>
<td>Data updated.</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@data-gadget-editable="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>//div[@data-gadget-editable="field_my_jsplumb_graph"]//iframe</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@class, "erp5-business_process")][5]</td>
<td></td>
</tr>
<tr>
<td>selectFrame</td>
<td>relative=top</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
portal = context.getPortalObject()
# Create trade states
if getattr(portal.portal_categories.trade_state, 'erp5_trade_ui_test_ts', None) is None:
portal.portal_categories.trade_state.newContent(
id='erp5_trade_ui_test_ts'
)
portal.portal_categories.trade_state.erp5_trade_ui_test_ts.newContent(
id='delivered',
title='Delivered'
)
portal.portal_categories.trade_state.erp5_trade_ui_test_ts.newContent(
id='invoiced',
title='Invoiced'
)
# Create trade phases
if getattr(portal.portal_categories.trade_phase, 'erp5_trade_ui_test_tp', None) is None:
portal.portal_categories.trade_phase.newContent(
id='erp5_trade_ui_test_tp'
)
portal.portal_categories.trade_phase.erp5_trade_ui_test_tp.newContent(
id='delivery',
title='Delivery'
)
portal.portal_categories.trade_phase.erp5_trade_ui_test_tp.newContent(
id='invoicing',
title='Invoicing'
)
# Create business process
test_trade_ui_test_client = portal.business_process_module.newContent(
id='test_trade_ui_test_business_process')
test_trade_ui_test_client.newContent(
portal_type='Business Link',
completed_state_list=('delivered', 'stopped'),
frozen_state_list=('delivered', 'stopped'),
predecessor_value=None,
successor_value=portal.portal_categories.trade_state.erp5_trade_ui_test_ts.delivered,
trade_phase_value=portal.portal_categories.trade_phase.erp5_trade_ui_test_tp.delivery,
title='Deliver'
)
test_trade_ui_test_client.newContent(
portal_type='Business Link',
completed_state_list=('delivered', 'stopped'),
frozen_state_list=('delivered', 'stopped'),
predecessor_value=portal.portal_categories.trade_state.erp5_trade_ui_test_ts.delivered,
successor_value=portal.portal_categories.trade_state.erp5_trade_ui_test_ts.invoiced,
trade_phase_value=portal.portal_categories.trade_phase.erp5_trade_ui_test_tp.invoicing,
title='Invoice'
)
# XXX not sure we need such links
test_trade_ui_test_client.newContent(
portal_type='Business Link',
completed_state_list=('delivered', 'stopped'),
frozen_state_list=('delivered', 'stopped'),
predecessor_value=portal.portal_categories.trade_state.erp5_trade_ui_test_ts.invoiced,
successor_value=None,
trade_phase_value=portal.portal_categories.trade_phase.erp5_trade_ui_test_tp.invoicing,
title='Finish'
)
return "Data Created."
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>ItemRJSZuite_createItemAndPackingList</string> </value> <value> <string>Zuite_createBusinessProcessForTradeZuite</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -8,6 +8,7 @@ object_value_list = [ ...@@ -8,6 +8,7 @@ object_value_list = [
getattr(portal.organisation_module, 'test_trade_ui_test_client', None), getattr(portal.organisation_module, 'test_trade_ui_test_client', None),
getattr(portal.person_module, 'test_trade_ui_test_supplier', None), getattr(portal.person_module, 'test_trade_ui_test_supplier', None),
getattr(portal.person_module, 'test_trade_ui_test_client', None), getattr(portal.person_module, 'test_trade_ui_test_client', None),
getattr(portal.business_process_module, 'test_trade_ui_test_business_process', None),
] + [ ] + [
getattr(portal.getDefaultModule(portal_type), "erp5_trade_ui_test_trade_condition" + suffix, None) getattr(portal.getDefaultModule(portal_type), "erp5_trade_ui_test_trade_condition" + suffix, None)
for portal_type in ("Internal Trade Condition", "Purchase Trade Condition", "Sale Trade Condition") for portal_type in ("Internal Trade Condition", "Purchase Trade Condition", "Sale Trade Condition")
......
erp5_pdm_ui_test erp5_pdm_ui_test
erp5_graph_editor
erp5_trade erp5_trade
erp5_ui_test erp5_ui_test
\ No newline at end of file
...@@ -72,7 +72,9 @@ ...@@ -72,7 +72,9 @@
<item> <item>
<key> <string>center</string> </key> <key> <string>center</string> </key>
<value> <value>
<list/> <list>
<string>my_title</string>
</list>
</value> </value>
</item> </item>
<item> <item>
...@@ -84,9 +86,7 @@ ...@@ -84,9 +86,7 @@
<item> <item>
<key> <string>left</string> </key> <key> <string>left</string> </key>
<value> <value>
<list> <list/>
<string>my_title</string>
</list>
</value> </value>
</item> </item>
<item> <item>
......
...@@ -144,9 +144,7 @@ ...@@ -144,9 +144,7 @@
</item> </item>
<item> <item>
<key> <string>gadget_url</string> </key> <key> <string>gadget_url</string> </key>
<value> <value> <string></string> </value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item> </item>
<item> <item>
<key> <string>hidden</string> </key> <key> <string>hidden</string> </key>
...@@ -160,6 +158,10 @@ ...@@ -160,6 +158,10 @@
<key> <string>js_sandbox</string> </key> <key> <string>js_sandbox</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>renderjs_extra</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>required</string> </key> <key> <string>required</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -168,6 +170,14 @@ ...@@ -168,6 +170,14 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
</item> </item>
<item>
<key> <string>validator_field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>validator_form_id</string> </key>
<value> <string></string> </value>
</item>
</dictionary> </dictionary>
</value> </value>
</item> </item>
...@@ -221,7 +231,7 @@ ...@@ -221,7 +231,7 @@
</item> </item>
<item> <item>
<key> <string>gadget_url</string> </key> <key> <string>gadget_url</string> </key>
<value> <string></string> </value> <value> <string>gadget_graph_editor.html</string> </value>
</item> </item>
<item> <item>
<key> <string>hidden</string> </key> <key> <string>hidden</string> </key>
...@@ -233,7 +243,13 @@ ...@@ -233,7 +243,13 @@
</item> </item>
<item> <item>
<key> <string>js_sandbox</string> </key> <key> <string>js_sandbox</string> </key>
<value> <string></string> </value> <value> <string>iframe</string> </value>
</item>
<item>
<key> <string>renderjs_extra</string> </key>
<value>
<list/>
</value>
</item> </item>
<item> <item>
<key> <string>required</string> </key> <key> <string>required</string> </key>
...@@ -243,6 +259,14 @@ ...@@ -243,6 +259,14 @@
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string>Graph</string> </value> <value> <string>Graph</string> </value>
</item> </item>
<item>
<key> <string>validator_field_id</string> </key>
<value> <string>my_core_mode_text_content_validator</string> </value>
</item>
<item>
<key> <string>validator_form_id</string> </key>
<value> <string>erp5_core/Base_viewFieldLibrary</string> </value>
</item>
</dictionary> </dictionary>
</value> </value>
</item> </item>
...@@ -262,17 +286,4 @@ ...@@ -262,17 +286,4 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: context.getPortalObject().restrictedTraverse(\'dream_graph_editor/jsplumb/index.html\').absolute_url()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData> </ZopeData>
...@@ -12,6 +12,23 @@ ...@@ -12,6 +12,23 @@
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value> </value>
</item> </item>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>jsplumb_graph</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item> <item>
<key> <string>_mt_index</string> </key> <key> <string>_mt_index</string> </key>
<value> <value>
...@@ -44,6 +61,10 @@ ...@@ -44,6 +61,10 @@
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>validation_workflow</string> </value> <value> <string>validation_workflow</string> </value>
</item> </item>
<item>
<key> <string>jsplumb_graph</string> </key>
<value> <string>{"class_definition":{},"graph":{"node":{"state_deleted":{"coordinate":{"top":0.949081048508587,"left":0.9496606334841629},"path":"/erp5/portal_workflow/validation_workflow/state_deleted","_class":"workflow.state","name":"Deleted","is_initial_state":false},"state_invalidated":{"coordinate":{"top":0.949081048508587,"left":0.5264423076923077},"path":"/erp5/portal_workflow/validation_workflow/state_invalidated","_class":"workflow.state","name":"Invalidated","is_initial_state":false},"state_validated":{"coordinate":{"top":0.1385959626393492,"left":0.3545673076923077},"path":"/erp5/portal_workflow/validation_workflow/state_validated","_class":"workflow.state","name":"Validated","is_initial_state":false},"state_draft":{"coordinate":{"top":0.41578788791804766,"left":0.025240384615384616},"path":"/erp5/portal_workflow/validation_workflow/state_draft","_class":"workflow.state","name":"Draft","is_initial_state":true}},"edge":{"transition_to_state_invalidated":{"source":"state_invalidated","destination":"state_invalidated","_class":"workflow.transition","name_path_dict":{"Delete Action":"/erp5/portal_workflow/validation_workflow/transition_delete_action","Validate Action":"/erp5/portal_workflow/validation_workflow/transition_validate_action"}},"state_draft_transition_validate":{"name":"Validate","description":"Validates a document in ERP5","destination":"state_validated","source":"state_draft","path":"/erp5/portal_workflow/validation_workflow/transition_validate","_class":"workflow.transition","transition_id":"transition_validate","actbox_url":null},"state_draft_transition_invalidate":{"name":"Invalidate","description":"This action invalidates a document in ERP5","destination":"state_invalidated","source":"state_draft","path":"/erp5/portal_workflow/validation_workflow/transition_invalidate","_class":"workflow.transition","transition_id":"transition_invalidate","actbox_url":null},"state_validated_transition_invalidate":{"name":"Invalidate","description":"This action invalidates a document in ERP5","destination":"state_invalidated","source":"state_validated","path":"/erp5/portal_workflow/validation_workflow/transition_invalidate","_class":"workflow.transition","transition_id":"transition_invalidate","actbox_url":null},"state_invalidated_transition_delete":{"name":"Delete","description":"Delete a document in ERP5","destination":"state_deleted","source":"state_invalidated","path":"/erp5/portal_workflow/validation_workflow/transition_delete","_class":"workflow.transition","transition_id":"transition_delete","actbox_url":null},"state_invalidated_transition_validate":{"name":"Validate","description":"Validates a document in ERP5","destination":"state_validated","source":"state_invalidated","path":"/erp5/portal_workflow/validation_workflow/transition_validate","_class":"workflow.transition","transition_id":"transition_validate","actbox_url":null},"transition_to_state_validated":{"source":"state_validated","destination":"state_validated","_class":"workflow.transition","name_path_dict":{"Invalidate Action":"/erp5/portal_workflow/validation_workflow/transition_invalidate_action"}},"state_draft_transition_delete":{"name":"Delete","description":"Delete a document in ERP5","destination":"state_deleted","source":"state_draft","path":"/erp5/portal_workflow/validation_workflow/transition_delete","_class":"workflow.transition","transition_id":"transition_delete","actbox_url":null},"transition_to_state_draft":{"source":"state_draft","destination":"state_draft","_class":"workflow.transition","name_path_dict":{"Invalidate Action":"/erp5/portal_workflow/validation_workflow/transition_invalidate_action","Delete Action":"/erp5/portal_workflow/validation_workflow/transition_delete_action","Validate Action":"/erp5/portal_workflow/validation_workflow/transition_validate_action"}}}}}</string> </value>
</item>
<item> <item>
<key> <string>manager_bypass</string> </key> <key> <string>manager_bypass</string> </key>
<value> <int>0</int> </value> <value> <int>0</int> </value>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment