aboutsummaryrefslogtreecommitdiffstats
path: root/dox-sequence-diagram-ui/src/main/webapp
diff options
context:
space:
mode:
authorMichael Lando <ml636r@att.com>2017-02-19 12:57:33 +0200
committerMichael Lando <ml636r@att.com>2017-02-19 13:47:13 +0200
commitefa037d34be7b1570efdc767c79fad8d4005f10e (patch)
treecf1036ba2728dea8a61492b678fa91954e629403 /dox-sequence-diagram-ui/src/main/webapp
parentf5f13c4f6b6fe3b4d98e349dfd7db59339803436 (diff)
Add new code new version
Change-Id: Ic02a76313503b526f17c3df29eb387a29fe6a42a Signed-off-by: Michael Lando <ml636r@att.com>
Diffstat (limited to 'dox-sequence-diagram-ui/src/main/webapp')
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/WEB-INF/web.xml14
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/favicon.icobin0 -> 894 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/index.html13
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/Sequencer.jsx199
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Common.js356
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Logger.js137
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Options.js136
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/application/Application.jsx268
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/Diagram.jsx896
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/components/popup/Popup.jsx94
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/diagram.html56
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/fragment.html18
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/lifeline.html19
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/message.html29
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/occurrence.html7
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/title.html3
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/dialog/Dialog.jsx222
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/Editor.jsx171
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/Designer.jsx403
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/actions/Actions.jsx471
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifeline.jsx264
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/LifelineNew.jsx112
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifelines.jsx136
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Message.jsx587
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/MessageNew.jsx106
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Messages.jsx143
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/metadata/Metadata.jsx34
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/source/Source.jsx86
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/toolbar/Toolbar.jsx275
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/export/Export.jsx31
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/icons/Icon.jsx41
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/overlay/Overlay.jsx61
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodel.js94
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodels.js87
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Model.js512
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/Scenarios.js110
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/BLANK.json16
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/DIMENSIONS.json16
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/ECOMP.json62
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/BLANK.json37
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/DIMENSIONS.json91
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/ECOMP.json514
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc-sequencer-meta-schema.xsd166
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc-sequencer-schema.xsd274
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc_sequencer_meta_schema.json332
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc_sequencer_schema.json582
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/templates/default.metamodel.json17
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/templates/default.model.json11
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/lib/main.jsx35
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/_typography.scss25
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/_variables.scss44
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-bold-italic.otfbin0 -> 138100 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-bold.otfbin0 -> 153056 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-italic.otfbin0 -> 138748 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-light-Italic.otfbin0 -> 139760 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-light.otfbin0 -> 145516 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-medium-italic.otfbin0 -> 141340 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-medium.otfbin0 -> 131984 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-regular.otfbin0 -> 144548 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-actions.scss120
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-common.scss112
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-controls.scss72
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-designer.scss256
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-development.scss29
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-diagram-svg.scss189
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-diagram.scss206
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-dialog.scss159
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-editor.scss125
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-standalone.scss2
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites-raster.scss30
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.css.svg1
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.defs.svg1
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.pngbin0 -> 2251 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/amdocs.pngbin0 -> 2069 bytes
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/request-async.svg59
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/request-sync.svg26
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/response.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/blank.svg60
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/close.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/collapsed.svg28
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/delete.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/download.svg29
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/edit.svg28
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/exclaim.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/expanded.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-default.svg22
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-start.svg26
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-stop.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/handle.svg26
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/info.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/notes.svg28
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-default.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-start.svg26
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-stop.svg26
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/open.svg29
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/plus.svg28
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/question.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/save.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/settings.svg29
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/upload.svg28
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/validate.svg27
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/sdc-sequencer.scss87
-rw-r--r--dox-sequence-diagram-ui/src/main/webapp/res/thirdparty/react-select/react-select.min.css1
103 files changed, 10598 insertions, 0 deletions
diff --git a/dox-sequence-diagram-ui/src/main/webapp/WEB-INF/web.xml b/dox-sequence-diagram-ui/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..a2f51b5271
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app id="Ecomp_ES6_Blueprint" version="3.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
+
+ <display-name>Ecomp ES6 Blueprint</display-name>
+
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ </welcome-file-list>
+
+</web-app>
+
diff --git a/dox-sequence-diagram-ui/src/main/webapp/favicon.ico b/dox-sequence-diagram-ui/src/main/webapp/favicon.ico
new file mode 100644
index 0000000000..a9ee1b6351
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/favicon.ico
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/index.html b/dox-sequence-diagram-ui/src/main/webapp/index.html
new file mode 100644
index 0000000000..b4a3a73dda
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/index.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>SDC Sequencer - DEMO</title>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
+ <meta http-equiv="content-type" content="text/html; charset=UTF8">
+ <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
+ <script type="text/javascript" src="index.js"></script>
+ </head>
+ <body>
+ <div id="asdcsApplication"></div>
+ </body>
+</html>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/Sequencer.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/Sequencer.jsx
new file mode 100644
index 0000000000..ff8e9a22ca
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/Sequencer.jsx
@@ -0,0 +1,199 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+import Application from './components/application/Application';
+import Common from './common/Common';
+import Options from './common/Options';
+import Model from './model/Model';
+import Metamodel from './model/Metamodel';
+import Metamodels from './model/Metamodels';
+import Scenarios from './model/demo/scenarios/Scenarios';
+import '../../../../res/sdc-sequencer.scss';
+/**
+ * ASDC Sequencer entry point.
+ */
+export default class Sequencer extends React.Component {
+
+ // //////////////////////////////////////////////////////////////////////////////////////////////
+
+ constructor(props, context) {
+ super(props, context);
+
+
+ this.setMetamodel.bind(this);
+ this.setModel.bind(this);
+ this.getModel.bind(this);
+ this.getMetamodel.bind(this);
+ this.getSVG.bind(this);
+ this.getDemoScenarios.bind(this);
+ this.newModel.bind(this);
+
+ // Parse options.
+
+ this.options = new Options(props.options);
+
+ // Default scenarios.
+
+ const scenarios = this.getDemoScenarios();
+ this.setMetamodel(scenarios.getMetamodels());
+
+ // this.setModel(scenarios.getBlank());
+ this.setModel(scenarios.getDimensions());
+ // this.setModel(scenarios.getECOMP());
+
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Optionally save known metamodels so that subsequent loading and unloading
+ * of models needn't include the corresponding metamodel.
+ * @param metamodels array of conformant metamodel JSON definitions.
+ * @return this.
+ */
+ setMetamodel(metamodels) {
+ Common.assertType(metamodels, 'Array');
+ this.metamodels = new Metamodels(metamodels);
+ return this;
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set current diagram.
+ * @param modelJSON JSON diagram spec.
+ * @param metamodelIdOrDefinition optional metamodel definition or reference. Defaults to
+ * the model's metadata @ref, or the default (permissive) metamodel.
+ * @return this.
+ */
+ setModel(modelJSON, metamodelIdOrDefinition) {
+ Common.assertType(modelJSON, 'Object');
+ const ref = (modelJSON.metadata) ? modelJSON.metadata.ref : undefined;
+ const metamodel = this.getMetamodel(metamodelIdOrDefinition || ref);
+ Common.assertInstanceOf(metamodel, Metamodel);
+ this.model = new Model(modelJSON, metamodel);
+ if (this.application) {
+ this.application.setModel(this.model);
+ }
+ return this;
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get current diagram state. At any given instant the diagram might not make *sense*
+ * but it should always be syntactically valid.
+ * @return current Model.
+ */
+ getModel() {
+
+ if (this.application) {
+ const model = this.application.getModel();
+ if (model) {
+ return model.unwrap();
+ }
+ }
+
+ return this.model;
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Extract SVG element.
+ * @return stringified SVG element.
+ */
+ getSVG() {
+ return this.application.getSVG();
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get demo scenarios, allowing initialization in demo mode from the outside.
+ * @returns {Scenarios}
+ */
+ getDemoScenarios() {
+ return new Scenarios();
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Create new model.
+ * @param metamodelIdOrDefinition
+ * @return newly-created model.
+ */
+ newModel(metamodelIdOrDefinition) {
+ const metamodel = this.getMetamodel(metamodelIdOrDefinition);
+ Common.assertInstanceOf(metamodel, Metamodel);
+ const model = new Model({}, metamodel);
+ if (this.application) {
+ this.application.setModel(model);
+ }
+ return model;
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get Metamodel instance corresponding to an ID or JSON definition.
+ * @param metamodelIdOrDefinition String ID or JSON definition.
+ * @returns Metamodel instance.
+ * @private
+ */
+ getMetamodel(metamodelIdOrDefinition) {
+ const metamodelType = Common.getType(metamodelIdOrDefinition);
+ if (metamodelType === 'Object') {
+ return new Metamodel(metamodelIdOrDefinition);
+ }
+ return this.metamodels.getMetamodelOrDefault(metamodelIdOrDefinition);
+ }
+
+ // //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render current diagram state.
+ */
+ render() {
+
+ if (this.props.model) {
+
+ // If a model was specified as a property, apply it. Otherwise
+ // fall back to the demo model.
+
+ const scenarios = this.getDemoScenarios();
+ const metamodel = [scenarios.getBlankMetamodel(), scenarios.getECOMPMetamodel()];
+ if (this.props.metamodel) {
+ metamodel.push(this.props.metamodel);
+ }
+ this.setMetamodel(metamodel);
+ this.setModel(this.props.model);
+ }
+
+ return (
+ <Application options={this.options} sequencer={this} ref={(a) => { this.application = a; }} />
+ );
+ }
+
+}
+
+Sequencer.propTypes = {
+ options: React.PropTypes.object.isRequired,
+ model: React.PropTypes.object,
+ metamodel: React.PropTypes.object,
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Common.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Common.js
new file mode 100644
index 0000000000..7337367dca
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Common.js
@@ -0,0 +1,356 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+/**
+ * Common operations.
+ */
+export default class Common {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Retrieve and start a simple timer. Retrieve elapsed time by calling #ms().
+ * @returns {*}
+ */
+ static timer() {
+ const start = new Date().getTime();
+ return {
+ ms() {
+ return (new Date().getTime() - start);
+ },
+ };
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get datatype, stripping '[object Boolean]' to just 'Boolean'.
+ * @param o JS object.
+ * @return String like String, Number, Date, Null, Undefined, stuff like that.
+ */
+ static getType(o) {
+ const str = Object.prototype.toString.call(o);
+ const prefix = '[object ';
+ if (str.substr(str, prefix.length) === prefix) {
+ return str.substr(prefix.length, str.length - (prefix.length + 1));
+ }
+ return str;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Assert that an argument was provided.
+ * @param value to be checked.
+ * @param message message on assertion failure.
+ * @return value.
+ */
+ static assertNotNull(value, message = 'Unexpected null value') {
+ if (!value) {
+ throw new Error(message);
+ }
+ return value;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Assert argument type.
+ * @param value to be checked.
+ * @param expected expected type string, e,g. Number from [object Number].
+ * @return value.
+ */
+ static assertType(value, expected) {
+ const type = this.getType(value);
+ if (type !== expected) {
+ throw new Error(`Expected type ${expected}, got ${type}`);
+ }
+ return value;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Assert argument type.
+ * @param value to be checked.
+ * @param unexpected unexpected type string, e,g. Number from [object Number].
+ * @return value.
+ */
+ static assertNotType(value, unexpected) {
+ const type = this.getType(value);
+ if (type === unexpected) {
+ throw new Error(`Forbidden type "${unexpected}"`);
+ }
+ return value;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Assert argument is a simple JSON object, and specifically not (something like an) ES6 class.
+ * @param value to be checked.
+ * @return value.
+ */
+ static assertPlainObject(value) {
+ Common.assertType(value, 'Object');
+ // TODO
+ /*
+ if (!($.isPlainObject(value))) {
+ throw new Error(`Expected plain object: ${value}`);
+ }
+ */
+ return value;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Assert argument type.
+ * @param value to be checked.
+ * @param c expected class.
+ * @return value.
+ */
+ static assertInstanceOf(value, c) {
+ Common.assertNotNull(value);
+ if (!(value instanceof c)) {
+ throw new Error(`Expected instanceof ${c}: ${value}`);
+ }
+ return value;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Assert that a string matches a regex.
+ * @param value value to be tested.
+ * @param re pattern to be applied.
+ * @return value.
+ */
+ static assertMatches(value, re) {
+ this.assertType(value, 'String');
+ this.assertType(re, 'RegExp');
+ if (!re.test(value)) {
+ throw new Error(`Value ${value} doesn't match pattern ${re}`);
+ }
+ return value;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Assert the value of a boolean.
+ *
+ * @param bool to be checked.
+ * @param message optional message on assertion failure.
+ * @return value.
+ */
+ static assertThat(bool, message) {
+ if (!bool) {
+ throw new Error(message || `Unexpected: ${bool}`);
+ }
+ return bool;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Verify that a value, generally a function arg, is a DOM element.
+ * @param value to be checked.
+ * @return value.
+ */
+ static assertHTMLElement(value) {
+ if (!Common.isHTMLElement(value)) {
+ throw new Error(`Expected HTMLElement: ${value}`);
+ }
+ return value;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Check whether a value, generally a function arg, is an HTML DOM element.
+ * @param o to be checked.
+ * @return true if DOM element.
+ */
+ static isHTMLElement(o) {
+ if (typeof HTMLElement === 'object') {
+ return o instanceof HTMLElement;
+ }
+ return o && typeof o === 'object' && o !== null
+ && o.nodeType === 1 && typeof o.nodeName === 'string';
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Check if a string is non-empty.
+ * @param s string to be checked.
+ * @returns false if non-blank string, true otherwise.
+ */
+ static isBlank(s) {
+ if (Common.getType(s) === 'String') {
+ return (s.trim().length === 0);
+ }
+ return true;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Detect dates that are numbers, milli/seconds since epoch..
+ *
+ * @param n candidate number.
+ * @returns {boolean}
+ */
+ static isNumber(n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Parse the text output from a template to a DOM element.
+ * @param txt input text.
+ * @returns {Element}
+ */
+ static txt2dom(txt) {
+ return new DOMParser().parseFromString(txt, 'image/svg+xml').documentElement;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Recursively convert a DOM element to an SVG (namespaced) element. Otherwise
+ * you get HTML elements that *happen* to have SVG names, but which aren't actually SVG.
+ *
+ * @param node DOM node to be converted.
+ * @param svg to be updated.
+ * @returns {*} for chaining.
+ */
+ static dom2svg(node, svg) {
+
+ Common.assertNotType(node, 'String');
+
+ if (node.childNodes && node.childNodes.length > 0) {
+
+ for (const c of node.childNodes) {
+ switch (c.nodeType) {
+ case document.TEXT_NODE:
+ svg.text(c.nodeValue);
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (const c of node.childNodes) {
+ switch (c.nodeType) {
+ case document.ELEMENT_NODE:
+ Common.dom2svg(c, svg.append(`svg:${c.nodeName.toLowerCase()}`));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (node.hasAttributes()) {
+ for (let i = 0; i < node.attributes.length; i++) {
+ const a = node.attributes.item(i);
+ svg.attr(a.name, a.value);
+ }
+ }
+
+ return svg;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get the lines to be shown in the label.
+ *
+ * @param labelText original label text.
+ * @param wordWrapAt chars at which to break words.
+ * @param lineWrapAt chars at which to wrap.
+ * @param maximumLines lines at which to truncate.
+ * @returns {Array}
+ */
+ static tokenize(labelText = '', wordWrapAt, lineWrapAt, maximumLines) {
+
+ let l = labelText;
+
+ // Hyphenate and break long words.
+
+ const regex = new RegExp(`(\\w{${wordWrapAt - 1}})(?=\\w)`, 'g');
+ l = l.replace(regex, '$1- ');
+
+ const labelTokens = l.split(/\s+/);
+ const lines = [];
+ let label = '';
+ for (const labelToken of labelTokens) {
+ if (label.length > 0) {
+ const length = label.length + labelToken.length + 1;
+ if (length > lineWrapAt) {
+ lines.push(label.trim());
+ label = labelToken;
+ continue;
+ }
+ }
+ label = `${label} ${labelToken}`;
+ }
+
+ if (label) {
+ lines.push(label.trim());
+ }
+
+ const truncated = lines.slice(0, maximumLines);
+ if (truncated.length < lines.length) {
+ let finalLine = truncated[maximumLines - 1];
+ if (finalLine.length > (lineWrapAt - 4)) {
+ finalLine = finalLine.substring(0, lineWrapAt - 4);
+ }
+ finalLine = `${finalLine} ...`;
+ truncated[maximumLines - 1] = finalLine;
+ }
+
+ return truncated;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Brutally sanitize an input string. We have no syntax rules, and hence no specific
+ * rules to apply, but we have very few unconstrained fields, so we can implement a
+ * crude default and devolve the rest to options.
+ * @param value value to be sanitized.
+ * @param options control options including validation rules.
+ * @param type validation type.
+ * @returns {*} sanitized string.
+ * @private
+ */
+ static sanitizeText(value, options, type) {
+ const rules = Common.assertNotNull(options.validation[type]);
+ let v = value || rules.defaultValue || '';
+ if (rules.replace) {
+ v = v.replace(rules.replace, '');
+ }
+ if (v.length > rules.maxLength) {
+ v = `${v.substring(0, rules.maxLength)}...`;
+ }
+ return v;
+ }
+
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Logger.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Logger.js
new file mode 100644
index 0000000000..187f49bb08
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Logger.js
@@ -0,0 +1,137 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+/* eslint-disable no-console */
+
+import Common from './Common';
+
+/**
+ * Logger, to allow calls to console.log during development, but
+ * disable them for production.
+ */
+export default class Logger {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * No-op call so that we can leave imports in place,
+ * even when there's no debugging.
+ */
+ static noop() {
+ // Nothing.
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set debug level.
+ * @param level threshold.
+ */
+ static setLevel(level) {
+ this.level = Logger.OFF;
+ if (Common.getType(level) === 'Number') {
+ this.level = level;
+ } else {
+ this.level = Logger[level];
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get debug level.
+ * @returns {number|*}
+ */
+ static getLevel() {
+ return this.level;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Write DEBUG-level log.
+ * @param msg message or tokens.
+ */
+ static debug(...msg) {
+ if (this.level >= Logger.DEBUG) {
+ const out = this.serialize(msg);
+ console.info(`ASDCS [DEBUG] ${out}`);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Write INFO-level log.
+ * @param msg message or tokens.
+ */
+ static info(...msg) {
+ if (this.level >= Logger.INFO) {
+ const out = this.serialize(msg);
+ console.info(`ASDCS [INFO] ${out}`);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Write debug.
+ * @param msg message or tokens.
+ */
+ static warn(msg) {
+ if (this.level >= Logger.WARN) {
+ const out = this.serialize(msg);
+ console.warn(`ASDCS [WARN] ${out}`);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Write error.
+ * @param msg message or tokens.
+ */
+ static error(...msg) {
+ if (this.level >= Logger.ERROR) {
+ const out = this.serialize(msg);
+ console.error(`ASDCS [ERROR] ${out}`);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Serialize msg.
+ * @param msg message or tokens.
+ * @returns {string}
+ */
+ static serialize(...msg) {
+ let out = '';
+ msg.forEach((token) => {
+ out = `${out}${token}`;
+ });
+ return out;
+ }
+}
+
+// /////////////////////////////////////////////////////////////////////////////////////////////////
+
+Logger.OFF = 0;
+Logger.ERROR = 1;
+Logger.WARN = 2;
+Logger.INFO = 3;
+Logger.DEBUG = 4;
+Logger.level = Logger.OFF;
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Options.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Options.js
new file mode 100644
index 0000000000..15897d7ee3
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Options.js
@@ -0,0 +1,136 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import _merge from 'lodash/merge';
+
+import Logger from './Logger';
+
+/**
+ * A wrapper for an options object. User-supplied options are merged with defaults,
+ * and the result -- runtime options -- are available by calling #getOptions().
+ */
+export default class Options {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct options, applying defaults.
+ * @param options optional override options.
+ */
+ constructor(options = {}) {
+ this.options = _merge({}, Options.DEFAULTS, options);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Unwrap options.
+ * @returns {*}
+ */
+ unwrap() {
+ return this.options;
+ }
+}
+
+// /////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Default options, overridden by anything of the same name.
+ */
+Options.DEFAULTS = {
+ log: {
+ level: Logger.WARN,
+ },
+ demo: false,
+ useHtmlSelect: true,
+ diagram: {
+ svg: {
+ x: 0,
+ y: 0,
+ width: 1600,
+ height: 1200,
+ margin: 50,
+ floodColor: '#009fdb',
+ scale: {
+ height: true,
+ width: true,
+ minimum: 0.25,
+ },
+ },
+ title: {
+ height: 0,
+ },
+ metadata: false,
+ lifelines: {
+ header: {
+ height: 225,
+ width: 350,
+ wrapWords: 14,
+ wrapLines: 18,
+ maxLines: 5,
+ },
+ occurrences: {
+ marginTop: 50,
+ marginBottom: 75,
+ foreshortening: 5,
+ width: 50,
+ },
+ spacing: {
+ horizontal: 400,
+ vertical: 400,
+ },
+ },
+ messages: {
+ label: {
+ wrapWords: 14,
+ wrapLines: 18,
+ maxLines: 4,
+ },
+ },
+ fragments: {
+ leftMargin: 150,
+ topMargin: 200,
+ widthMargin: 300,
+ heightMargin: 350,
+ label: {
+ wrapWords: 50,
+ wrapLines: 50,
+ maxLines: 2,
+ },
+ },
+ },
+ validation: {
+ lifeline: {
+ maxLength: 100,
+ defaultValue: '',
+ replace: /[^\-\.\+ &%#@\?\(\)\[\]<>\w\d]/g,
+ },
+ message: {
+ maxLength: 100,
+ defaultValue: '',
+ replace: /[^\-\.\+ &%#@\?\(\)\[\]<>\w\d]/g,
+ },
+ notes: {
+ maxLength: 255,
+ defaultValue: '',
+ },
+ guard: {
+ maxLength: 80,
+ defaultValue: '',
+ replace: /[^\-\.\+ &%#@\?\(\)\[\]<>\w\d]/g,
+ },
+ },
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/application/Application.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/application/Application.jsx
new file mode 100644
index 0000000000..20b06922c8
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/application/Application.jsx
@@ -0,0 +1,268 @@
+
+import React from 'react';
+
+import Common from '../../common/Common';
+import Logger from '../../common/Logger';
+import Diagram from '../diagram/Diagram';
+import Dialog from '../dialog/Dialog';
+import Editor from '../editor/Editor';
+import Export from '../export/Export';
+import Overlay from '../overlay/Overlay';
+
+/**
+ * Application controller, also a view.
+ */
+export default class Application extends React.Component {
+
+ /**
+ * Construct application view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+
+ this.sequencer = Common.assertNotNull(props.sequencer);
+ this.model = this.sequencer.getModel();
+ this.metamodel = this.sequencer.getMetamodel();
+ this.options = props.options;
+ Logger.setLevel(this.options.unwrap().log.level);
+
+ // Bindings.
+
+ this.showInfoDialog = this.showInfoDialog.bind(this);
+ this.showEditDialog = this.showEditDialog.bind(this);
+ this.showConfirmDialog = this.showConfirmDialog.bind(this);
+ this.hideOverlay = this.hideOverlay.bind(this);
+ this.onMouseMove = this.onMouseMove.bind(this);
+ this.onMouseUp = this.onMouseUp.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get application options.
+ * @returns JSON options, see Options.js.
+ */
+ getOptions() {
+ return this.options.unwrap();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set diagram name.
+ * @param n diagram (human-readable) name.
+ */
+ setName(n) {
+ this.diagram.setName(n);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set diagram model.
+ * @param model diagram instance.
+ */
+ setModel(model) {
+
+ Common.assertNotNull(model);
+
+ this.model = model;
+
+ if (this.editor) {
+ this.editor.render();
+ }
+
+ if (this.diagram) {
+ this.diagram.render();
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get Model wrapper.
+ * @returns Model.
+ */
+ getModel() {
+ return this.model;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get SVG element.
+ * @returns {*}
+ */
+ getSVG() {
+ return this.diagram.getSVG();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get top-level widget. Provides the demo toolbar with access to the public API.
+ * @returns {*}
+ */
+ getSequencer() {
+ return this.sequencer;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Present info dialog.
+ * @param msg info message.
+ */
+ showInfoDialog(msg) {
+ this.dialog.showInfoDialog(msg);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Present error dialog.
+ * @param msg error message.
+ */
+ showErrorDialog(msg) {
+ this.dialog.showErrorDialog(msg);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Present confirmation dialog.
+ * @param msg info message.
+ * @param cb callback function to be invoked on OK.
+ */
+ showConfirmDialog(msg, cb) {
+ Common.assertType(cb, 'Function');
+ this.dialog.showConfirmDialog(msg, cb);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Present edit (textarea) dialog.
+ * @param msg prompt.
+ * @param text current edit text.
+ * @param cb callback function to be invoked on OK, taking the updated text
+ * as an argument.
+ */
+ showEditDialog(msg, text, cb) {
+ this.dialog.showEditDialog(msg, text, cb);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Select lifeline by ID.
+ * @param id lifeline ID.
+ */
+ selectLifeline(id) {
+ if (this.editor) {
+ this.editor.selectLifeline(id);
+ }
+ if (this.diagram) {
+ this.diagram.selectLifeline(id);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Select message by ID.
+ * @param id message ID.
+ */
+ selectMessage(id) {
+ if (this.editor) {
+ this.editor.selectMessage(id);
+ }
+ if (this.diagram) {
+ this.diagram.selectMessage(id);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * (Re)render just the diagram.
+ */
+ renderDiagram() {
+ this.diagram.redraw();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show overlay between application and modal dialog.
+ */
+ showOverlay() {
+ if (this.overlay) {
+ this.overlay.setVisible(true);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Hide overlay between application and modal dialog.
+ */
+ hideOverlay() {
+ if (this.overlay) {
+ this.overlay.setVisible(false);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Capture mouse move events, for resize.
+ * @param event move event.
+ */
+ onMouseMove(event) {
+ if (this.editor) {
+ this.editor.onMouseMove(event);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Propagate mouse event to the editor that manages the resize.
+ */
+ onMouseUp() {
+ if (this.editor) {
+ this.editor.onMouseUp();
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render current model state.
+ */
+ render() {
+
+ return (
+
+ <div className="asdcs-control" onMouseMove={this.onMouseMove} onMouseUp={this.onMouseUp}>
+
+ <Editor application={this} ref={(r) => { this.editor = r; }} />
+ <Diagram application={this} ref={(r) => { this.diagram = r; }} />
+ <Dialog application={this} ref={(r) => { this.dialog = r; }} />
+ <Export />
+ <Overlay application={this} ref={(r) => { this.overlay = r; }} />
+
+ </div>
+ );
+ }
+
+}
+
+/** React properties. */
+Application.propTypes = {
+ options: React.PropTypes.object.isRequired,
+ sequencer: React.PropTypes.object.isRequired,
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/Diagram.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/Diagram.jsx
new file mode 100644
index 0000000000..f2da7a5a1b
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/Diagram.jsx
@@ -0,0 +1,896 @@
+
+import React from 'react';
+import _template from 'lodash/template';
+import _merge from 'lodash/merge';
+import d3 from 'd3';
+
+import Common from '../../common/Common';
+import Logger from '../../common/Logger';
+import Popup from './components/popup/Popup';
+
+/**
+ * SVG diagram view.
+ */
+export default class Diagram extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct React view.
+ * @param props properties.
+ * @param context context.
+ */
+ constructor(props, context) {
+ super(props, context);
+
+ this.application = Common.assertNotNull(props.application);
+ this.options = this.application.getOptions().diagram;
+
+ this.events = {};
+ this.state = {
+ height: 0,
+ width: 0,
+ };
+
+ this.templates = {
+ diagram: _template(require('./templates/diagram.html')),
+ lifeline: _template(require('./templates/lifeline.html')),
+ message: _template(require('./templates/message.html')),
+ occurrence: _template(require('./templates/occurrence.html')),
+ fragment: _template(require('./templates/fragment.html')),
+ title: _template(require('./templates/title.html')),
+ };
+
+ this.handleResize = this.handleResize.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set diagram name.
+ * @param n name.
+ */
+ setName(n) {
+ this.svg.select('').text(n);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get SVG from diagram.
+ * @returns {*|string}
+ */
+ getSVG() {
+ const svg = this.svg.node().outerHTML;
+ return svg.replace('<svg ', '<svg xmlns="http://www.w3.org/2000/svg" ');
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Select message by ID.
+ * @param id message ID.
+ */
+ selectMessage(id) {
+ const sel = this.svg.selectAll('g.asdcs-diagram-message-container');
+ sel.classed('asdcs-active', false);
+ sel.selectAll('rect.asdcs-diagram-message-bg').attr('filter', null);
+ if (id) {
+ const parent = this.svg.select(`g.asdcs-diagram-message-container[data-id="${id}"]`);
+ parent.classed('asdcs-active', true);
+ parent.selectAll('rect.asdcs-diagram-message-bg').attr('filter', 'url(#asdcsSvgHighlight)');
+ }
+ this._showNotesPopup(id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Select lifeline by ID.
+ * @param id lifeline ID.
+ */
+ selectLifeline(id) {
+ const sel = this.svg.selectAll('g.asdcs-diagram-lifeline-container');
+ sel.classed('asdcs-active', false);
+ sel.selectAll('rect').attr('filter', null);
+ if (id) {
+ const parent = this.svg.select(`g.asdcs-diagram-lifeline-container[data-id="${id}"]`);
+ parent.selectAll('rect').attr('filter', 'url(#asdcsSvgHighlight)');
+ parent.classed('asdcs-active', true);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle resize, including initial sizing.
+ */
+ handleResize() {
+ if (this.wrapper) {
+ const height = this.wrapper.offsetHeight;
+ const width = this.wrapper.offsetWidth;
+ if (this.state.height !== height || this.state.width !== width) {
+ this.setState({ height, width });
+ }
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * (Re)render diagram.
+ */
+ render() {
+
+ const model = this.application.getModel();
+ const modelJSON = model.unwrap();
+ const name = modelJSON.diagram.metadata.name;
+ const options = this.application.getOptions();
+ const titleHeight = options.diagram.title.height;
+ const titleClass = (titleHeight && titleHeight > 0) ? `height:${titleHeight}` : 'asdcs-hidden';
+
+ return (
+ <div className="asdcs-diagram">
+ <div className={`asdcs-diagram-name ${titleClass}`}>{name}</div>
+ <div className="asdcs-diagram-svg" ref={(r) => { this.wrapper = r; }}></div>
+ <Popup visible={false} ref={(r) => { this.popup = r; }} />
+ </div>
+ );
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ redraw() {
+ this.updateSVG();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Initial render.
+ */
+ componentDidMount() {
+ window.addEventListener('resize', this.handleResize);
+ this.updateSVG();
+
+ // Insurance:
+
+ setTimeout(() => {
+ this.handleResize();
+ }, 500);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.handleResize);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render on update.
+ */
+ componentDidUpdate() {
+ this.updateSVG();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Redraw SVG diagram. So far it's fast enough that it doesn't seem to matter whether
+ * it's completely redrawn.
+ */
+ updateSVG() {
+
+ if (!this.svg) {
+ const svgparams = _merge({}, this.options.svg);
+ this.wrapper.innerHTML = this.templates.diagram(svgparams);
+ this.svg = d3.select(this.wrapper).select('svg');
+ }
+
+ if (this.state.height === 0) {
+
+ // We'll get a resize event, and the height will be non-zero when it's actually time.
+
+ return;
+ }
+
+ if (this.state.height && this.state.width) {
+ const margin = this.options.svg.margin;
+ const x = -margin;
+ const y = -margin;
+ const height = this.state.height + (margin * 2);
+ const width = this.state.width + (margin * 2);
+ const viewBox = `${x} ${y} ${width} ${height}`;
+ this.svg.attr('viewBox', viewBox);
+ }
+
+
+ // If we've already rendered, then save the current scale/translate so that we
+ // can reapply it after rendering.
+
+ const gContentSelection = this.svg.selectAll('g.asdcs-diagram-content');
+ if (gContentSelection.size() === 1) {
+ const transform = gContentSelection.attr('transform');
+ if (transform) {
+ this.savedTransform = transform;
+ }
+ }
+
+ // Empty the document. We're starting again.
+
+ this.svg.selectAll('.asdcs-diagram-content').remove();
+
+ // Extract the model.
+
+ const model = this.application.getModel();
+ if (!model) {
+ return;
+ }
+ const modelJSON = model.unwrap();
+
+ // Extract dimension options.
+
+ const header = this.options.lifelines.header;
+ const spacing = this.options.lifelines.spacing;
+
+ // Make separate container elements so that we can control Z order.
+
+ const gContent = this.svg.append('g').attr('class', 'asdcs-diagram-content');
+ const gLifelines = gContent.append('g').attr('class', 'asdcs-diagram-lifelines');
+ const gCanvas = gContent.append('g').attr('class', 'asdcs-diagram-canvas');
+ gCanvas.append('g').attr('class', 'asdcs-diagram-occurrences');
+ gCanvas.append('g').attr('class', 'asdcs-diagram-fragments');
+ gCanvas.append('g').attr('class', 'asdcs-diagram-messages');
+
+ // Lifelines -----------------------------------------------------------------------------------
+
+ const actorsById = {};
+ const positionsByMessageId = {};
+ const lifelines = [];
+ for (const actor of modelJSON.diagram.lifelines) {
+ const x = (header.width / 2) + (lifelines.length * spacing.horizontal);
+ Diagram._processLifeline(actor, x);
+ lifelines.push({ x, actor });
+ actorsById[actor.id] = actor;
+ }
+
+ // Messages ------------------------------------------------------------------------------------
+
+ // Analyze occurrence information.
+
+ const occurrences = model.analyzeOccurrences();
+ const fragments = model.analyzeFragments();
+ let y = this.options.lifelines.header.height + spacing.vertical;
+ let messageIndex = 0;
+ for (const step of modelJSON.diagram.steps) {
+ if (step.message) {
+ positionsByMessageId[step.message.id] = positionsByMessageId[step.message.id] || {};
+ positionsByMessageId[step.message.id].y = y;
+ this._drawMessage(gCanvas, step.message, y, actorsById,
+ positionsByMessageId, ++messageIndex, occurrences, fragments);
+ }
+ y += spacing.vertical;
+ }
+
+ // ---------------------------------------------------------------------------------------------
+
+ // Draw the actual (dashed) lifelines in a background <g>.
+
+ this._drawLifelines(gLifelines, lifelines, y);
+
+ // Initialize mouse event handlers.
+
+ this._initMouseEvents(gLifelines, gCanvas);
+
+ // Scale to fit.
+
+ const bb = gContent.node().getBBox();
+ this._initZoom(gContent, bb.width, bb.height);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Draw message into SVG canvas.
+ * @param gCanvas container.
+ * @param message message to be rendered.
+ * @param y current y position.
+ * @param actorsById actor lookup.
+ * @param positionsByMessageId x- and y-position of each message.
+ * @param messageIndex where we are in the set of messages to be rendered.
+ * @param oData occurrences info.
+ * @param fData fragments info.
+ * @private
+ */
+ _drawMessage(gCanvas, message, y, actorsById, positionsByMessageId,
+ messageIndex, oData, fData) {
+
+ Common.assertNotNull(oData);
+
+ const request = message.type === 'request';
+ const fromActor = request ? actorsById[message.from] : actorsById[message.to];
+ const toActor = request ? actorsById[message.to] : actorsById[message.from];
+
+ if (!fromActor) {
+ Logger.warn(`Cannot draw message ${JSON.stringify(message)}: 'from' not found.`);
+ return;
+ }
+
+ if (!toActor) {
+ Logger.warn(`Cannot draw message ${JSON.stringify(message)}: 'to' not found.`);
+ return;
+ }
+
+ // Occurrences. --------------------------------------------------------------------------------
+
+ if (message.occurrence) {
+ Logger.debug(`Found occurrence for ${message.name}: ${JSON.stringify(message.occurrence)}`);
+ }
+ const activeTo = Diagram._calcActive(oData, toActor.id);
+ this._drawOccurrence(gCanvas, oData, positionsByMessageId, fromActor, message.id);
+ this._drawOccurrence(gCanvas, oData, positionsByMessageId, toActor, message.id);
+ const activeFrom = Diagram._calcActive(oData, fromActor.id);
+
+ // Messages. -----------------------------------------------------------------------------------
+
+ const gMessages = gCanvas.select('g.asdcs-diagram-messages');
+
+ // Save positions for later.
+
+ const positions = positionsByMessageId[message.id];
+ positions.x0 = fromActor.x;
+ positions.x1 = toActor.x;
+
+ // Calculate.
+
+ const leftToRight = fromActor.x < toActor.x;
+ const loopback = (message.to === message.from);
+ const x1 = this._calcMessageX(activeTo, toActor.x, true, leftToRight);
+ const x0 = loopback ? x1 : this._calcMessageX(activeFrom, fromActor.x, false, leftToRight);
+
+ let messagePath;
+ if (loopback) {
+
+ // To self.
+
+ messagePath = `M${x1},${y}`;
+ messagePath = `${messagePath} L${x1 + 200},${y}`;
+ messagePath = `${messagePath} L${x1 + 200},${y + 50}`;
+ messagePath = `${messagePath} L${x1},${y + 50}`;
+ } else {
+
+ // Between lifelines.
+
+ messagePath = `M${x0},${y}`;
+ messagePath = `${messagePath} L${x1},${y}`;
+ }
+
+ const styles = Diagram._getMessageStyles(message);
+
+ // Split message over lines.
+
+ const messageWithPrefix = `${messageIndex}. ${message.name}`;
+ const maxLines = this.options.messages.label.maxLines;
+ const wrapWords = this.options.messages.label.wrapWords;
+ const wrapLines = this.options.messages.label.wrapLines;
+ const messageLines = Common.tokenize(messageWithPrefix, wrapWords, wrapLines, maxLines);
+
+ const messageTxt = this.templates.message({
+ id: message.id,
+ classes: styles.css,
+ marker: styles.marker,
+ dasharray: styles.dasharray,
+ labels: messageLines,
+ lines: maxLines,
+ path: messagePath,
+ index: messageIndex,
+ x0, x1, y,
+ });
+
+ const messageEl = Common.txt2dom(messageTxt);
+ const gMessage = gMessages.append('g');
+ Common.dom2svg(messageEl, gMessage);
+
+ // Set the background's bounding box to that of the text,
+ // so that they fit snugly.
+
+ const labelBB = gMessage.select('.asdcs-diagram-message-label').node().getBBox();
+ gMessage.select('.asdcs-diagram-message-label-bg')
+ .attr('x', labelBB.x)
+ .attr('y', labelBB.y)
+ .attr('height', labelBB.height)
+ .attr('width', labelBB.width);
+
+ // Fragments. ----------------------------------------------------------------------------------
+
+ const fragment = fData[message.id];
+ if (fragment) {
+
+ // It ends on this message.
+
+ this._drawFragment(gCanvas, fragment, positionsByMessageId);
+
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Draw a single occurrence.
+ * @param gCanvas container.
+ * @param oData occurrence data.
+ * @param positionsByMessageId map of y positions by message ID.
+ * @param actor wrapper containing lifeline ID (.id), position (.x) and name (.name).
+ * @param messageId message identifier.
+ * @private
+ */
+ _drawOccurrence(gCanvas, oData, positionsByMessageId, actor, messageId) {
+
+ Common.assertType(oData, 'Object');
+ Common.assertType(positionsByMessageId, 'Object');
+ Common.assertType(actor, 'Object');
+ Common.assertType(messageId, 'String');
+
+ const gOccurrences = gCanvas.select('g.asdcs-diagram-occurrences');
+
+ const oOptions = this.options.lifelines.occurrences;
+ const oWidth = oOptions.width;
+ const oHalfWidth = oWidth / 2;
+ const oForeshortening = oOptions.foreshortening;
+ const oMarginTop = oOptions.marginTop;
+ const oMarginBottom = oOptions.marginBottom;
+ const o = oData[actor.id];
+
+ const active = Diagram._calcActive(oData, actor.id);
+
+ const x = (actor.x - oHalfWidth) + (active * oWidth);
+ const positions = positionsByMessageId[messageId];
+ const y = positions.y;
+
+ let draw = true;
+ if (o) {
+
+ if (o.start[messageId]) {
+
+ // Starting, but drawing nothing until we find the end.
+
+ o.active.push(messageId);
+ draw = false;
+
+ } else if (active > 0) {
+
+ const startMessageId = o.stop[messageId];
+ if (startMessageId) {
+
+ // OK, it ends here. Draw the occurrence box.
+
+ o.active.pop();
+ const foreshorteningY = active * oForeshortening;
+ const startY = positionsByMessageId[startMessageId].y;
+ const height = ((oMarginTop + oMarginBottom) + (y - startY)) - (foreshorteningY * 2);
+ const oProps = {
+ x: (actor.x - oHalfWidth) + ((active - 1) * oWidth),
+ y: ((startY - oMarginTop) + foreshorteningY),
+ height,
+ width: oWidth,
+ };
+
+ const occurrenceTxt = this.templates.occurrence(oProps);
+ const occurrenceEl = Common.txt2dom(occurrenceTxt);
+ Common.dom2svg(occurrenceEl, gOccurrences.append('g'));
+
+ }
+ draw = false;
+ }
+ }
+
+ if (draw) {
+
+ // Seems this is a singleton occurrence. We just draw a wee box around it.
+
+ const height = (oMarginTop + oMarginBottom);
+ const occurrenceProperties = { x, y: y - oMarginTop, height, width: oWidth };
+ const defaultTxt = this.templates.occurrence(occurrenceProperties);
+ const defaultEl = Common.txt2dom(defaultTxt);
+ Common.dom2svg(defaultEl, gOccurrences.append('g'));
+ }
+
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Draw box(es) around fragment(s).
+ * @param gCanvas container.
+ * @param fragment fragment definition, corresponding to its final (stop) message.
+ * @param positionsByMessageId message dimensions.
+ * @private
+ */
+ _drawFragment(gCanvas, fragment, positionsByMessageId) {
+
+ const optFragments = this.options.fragments;
+ const gFragments = gCanvas.select('g.asdcs-diagram-fragments');
+ const p1 = positionsByMessageId[fragment.stop];
+ if (p1 && fragment.start && fragment.start.length > 0) {
+
+ for (const start of fragment.start) {
+
+ const message = this.application.getModel().getMessageById(start);
+ const bounds = this._calcFragmentBounds(message, fragment, positionsByMessageId);
+ if (bounds) {
+
+ const maxLines = this.options.fragments.label.maxLines;
+ const wrapWords = this.options.fragments.label.wrapWords;
+ const wrapLines = this.options.fragments.label.wrapLines;
+ const lines = Common.tokenize(message.fragment.guard, wrapWords, wrapLines, maxLines);
+
+ const params = {
+ id: start,
+ x: bounds.x0 - optFragments.leftMargin,
+ y: bounds.y0 - optFragments.topMargin,
+ height: (bounds.y1 - bounds.y0) + optFragments.heightMargin,
+ width: (bounds.x1 - bounds.x0) + optFragments.widthMargin,
+ operator: (message.fragment.operator || 'alt'),
+ lines,
+ };
+
+ const fragmentTxt = this.templates.fragment(params);
+ const fragmentEl = Common.txt2dom(fragmentTxt);
+ const gFragment = gFragments.append('g');
+ Common.dom2svg(fragmentEl, gFragment);
+
+ const labelBB = gFragment.select('.asdcs-diagram-fragment-guard').node().getBBox();
+ gFragment.select('.asdcs-diagram-fragment-guard-bg')
+ .attr('x', labelBB.x)
+ .attr('y', labelBB.y)
+ .attr('height', labelBB.height)
+ .attr('width', labelBB.width);
+
+ } else {
+ Logger.warn(`Bad fragment: ${JSON.stringify(fragment)}`);
+ }
+ }
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ _calcFragmentBounds(startMessage, fragment, positionsByMessageId) {
+ if (startMessage) {
+ const steps = this.application.getModel().unwrap().diagram.steps;
+ const bounds = { x0: 99999, x1: 0, y0: 99999, y1: 0 };
+ let foundStart = false;
+ let foundStop = false;
+ for (const step of steps) {
+ const message = step.message;
+ if (message) {
+ if (message.id === startMessage.id) {
+ foundStart = true;
+ }
+ if (foundStart && !foundStop) {
+ const positions = positionsByMessageId[message.id];
+ if (positions) {
+ bounds.x0 = Math.min(bounds.x0, Math.min(positions.x0, positions.x1));
+ bounds.y0 = Math.min(bounds.y0, positions.y);
+ bounds.x1 = Math.max(bounds.x1, Math.max(positions.x0, positions.x1));
+ bounds.y1 = Math.max(bounds.y1, positions.y);
+ } else {
+ // This probably means it hasn't been recorded yet, which is fine, because
+ // we draw fragments from where they END.
+ foundStop = true;
+ }
+ }
+
+ if (message.id === fragment.stop) {
+ foundStop = true;
+ }
+ }
+ }
+ return bounds;
+ }
+ return undefined;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Draw all lifelines.
+ * @param gLifelines lifelines container.
+ * @param lifelines lifelines definitions.
+ * @param y height.
+ * @private
+ */
+ _drawLifelines(gLifelines, lifelines, y) {
+
+ const maxLines = this.options.lifelines.header.maxLines;
+ const wrapWords = this.options.lifelines.header.wrapWords;
+ const wrapLines = this.options.lifelines.header.wrapLines;
+
+ for (const lifeline of lifelines) {
+ const lines = Common.tokenize(lifeline.actor.name, wrapWords, wrapLines, maxLines);
+ const lifelineTxt = this.templates.lifeline({
+ x: lifeline.x,
+ y0: 0,
+ y1: y,
+ lines,
+ rows: maxLines,
+ headerHeight: this.options.lifelines.header.height,
+ headerWidth: this.options.lifelines.header.width,
+ id: lifeline.actor.id,
+ });
+
+ const lifelineEl = Common.txt2dom(lifelineTxt);
+ Common.dom2svg(lifelineEl, gLifelines.append('g'));
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Initialize all mouse events.
+ * @param gLifelines lifelines container.
+ * @param gCanvas top-level canvas container.
+ * @private
+ */
+ _initMouseEvents(gLifelines, gCanvas) {
+
+ const self = this;
+ const source = 'asdcs';
+ const origin = `${window.location.protocol}//${window.location.host}`;
+
+ let timer;
+ gLifelines.selectAll('.asdcs-diagram-lifeline-selectable')
+ .on('mouseenter', function f() {
+ timer = setTimeout(() => {
+ self.application.selectLifeline(d3.select(this.parentNode).attr('data-id'));
+ }, 150);
+ })
+ .on('mouseleave', () => {
+ clearTimeout(timer);
+ self.application.selectLifeline();
+ })
+ .on('click', function f() {
+ const id = d3.select(this.parentNode).attr('data-id');
+ window.postMessage({ source, id, type: 'lifeline' }, origin);
+ });
+
+ gLifelines.selectAll('.asdcs-diagram-lifeline-heading-box')
+ .on('mouseenter', function f() {
+ timer = setTimeout(() => {
+ self.application.selectLifeline(d3.select(this.parentNode).attr('data-id'));
+ }, 150);
+ })
+ .on('mouseleave', () => {
+ clearTimeout(timer);
+ self.application.selectLifeline();
+ })
+ .on('click', function f() {
+ const id = d3.select(this.parentNode).attr('data-id');
+ window.postMessage({ source, id, type: 'lifelineHeader' }, origin);
+ });
+
+ gCanvas.selectAll('.asdcs-diagram-message-selectable')
+ .on('mouseenter', function f() {
+ self.events.message = { x: d3.event.pageX, y: d3.event.pageY };
+ timer = setTimeout(() => {
+ self.application.selectMessage(d3.select(this.parentNode).attr('data-id'));
+ }, 200);
+ })
+ .on('mouseleave', () => {
+ delete self.events.message;
+ clearTimeout(timer);
+ self.application.selectMessage();
+ })
+ .on('click', function f() {
+ const id = d3.select(this.parentNode).attr('data-id');
+ window.postMessage({ source, id, type: 'message' }, origin);
+ });
+
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get CSS classes to be applied to a message, according to whether request/response
+ * or synchronous/asynchronous.
+ * @param message message being rendered.
+ * @returns CSS class name(s).
+ * @private
+ */
+ static _getMessageStyles(message) {
+
+ let marker = 'asdcsDiagramArrowSolid';
+ let dasharray = '';
+ let css = 'asdcs-diagram-message';
+ if (message.type === 'request') {
+ css = `${css} asdcs-diagram-message-request`;
+ } else {
+ css = `${css} asdcs-diagram-message-response`;
+ marker = 'asdcsDiagramArrowOpen';
+ dasharray = '30, 10';
+ }
+
+ if (message.asynchronous) {
+ css = `${css} asdcs-diagram-message-asynchronous`;
+ marker = 'asdcsDiagramArrowOpen';
+ } else {
+ css = `${css} asdcs-diagram-message-synchronous`;
+ }
+
+ return { css, marker, dasharray };
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Initialize or reinitialize zoom. This sets the initial zoom in the case of
+ * a re-rendering, and initializes the eventhandling in all cases.
+ *
+ * It does some fairly risky parsing of the 'transform' attribute, assuming that it
+ * can contain scale() and translate(). But only the zoom handler and us are writing
+ * the transform values, so that's probably OK.
+ *
+ * @param gContent container.
+ * @param width diagram width.
+ * @param height diagram height.
+ * @private
+ */
+ _initZoom(gContent, width, height) {
+
+ const zoomed = function zoomed() {
+ gContent.attr('transform',
+ `translate(${d3.event.translate})scale(${d3.event.scale})`);
+ };
+
+ const viewWidth = this.state.width || this.options.svg.width;
+ const viewHeight = this.state.height || this.options.svg.height;
+ const scaleMinimum = this.options.svg.scale.minimum;
+ const scaleWidth = viewWidth / width;
+ const scaleHeight = viewHeight / height;
+
+ let scale = scaleMinimum;
+ if (this.options.svg.scale.width) {
+ scale = Math.max(scale, scaleWidth);
+ }
+ if (this.options.svg.scale.height) {
+ scale = Math.min(scale, scaleHeight);
+ }
+
+ scale = Math.max(scale, scaleMinimum);
+
+ let translate = [0, 0];
+ if (this.savedTransform) {
+ const s = this.savedTransform;
+ const scaleStart = s.indexOf('scale(');
+ if (scaleStart !== -1) {
+ scale = parseFloat(s.substring(scaleStart + 6, s.length - 1));
+ }
+ const translateStart = s.indexOf('translate(');
+ if (translateStart !== -1) {
+ const spec = s.substring(translateStart + 10, s.indexOf(')', translateStart));
+ const tokens = spec.split(',');
+ translate = [parseFloat(tokens[0]), parseFloat(tokens[1])];
+ }
+
+ gContent.attr('transform', this.savedTransform);
+ } else {
+ gContent.attr('transform', `scale(${scale})`);
+ }
+
+ const zoom = d3.behavior.zoom()
+ .scale(scale)
+ .scaleExtent([scaleMinimum, 10])
+ .translate(translate)
+ .on('zoom', zoomed);
+ this.svg.call(zoom);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Hide from the linter the fact that we're modifying the lifeline.
+ * @param lifeline to be updated with X position.
+ * @param x X position.
+ * @private
+ */
+ static _processLifeline(lifeline, x) {
+ const actor = lifeline;
+ actor.id = actor.id || actor.name;
+ actor.x = x;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Derive active occurrences for lifeline.
+ * @param oData occurrences data.
+ * @param lifelineId lifeline to be analyzed.
+ * @returns {number}
+ * @private
+ */
+ static _calcActive(oData, lifelineId) {
+ const o = oData[lifelineId];
+ let active = 0;
+ if (o && o.active) {
+ active = o.active.length;
+ }
+ return active;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Derive the X position of an occurrence on a lifeline, taking into account how
+ * many occurrences are active.
+ * @param active active count.
+ * @param x lifeline X position; basis for offset.
+ * @param arrow whether this is the arrow (to) end.
+ * @param leftToRight whether this message goes left-to-right.
+ * @returns {*} calculated X position for occurrence left-hand side.
+ * @private
+ */
+ _calcMessageX(active, x, arrow, leftToRight) {
+ const width = this.options.lifelines.occurrences.width;
+ const halfWidth = width / 2;
+ const active0 = Math.max(0, active - 1);
+ let calculated = x + (active0 * width);
+ if (arrow) {
+ // End (ARROW).
+ if (leftToRight) {
+ calculated -= halfWidth;
+ } else {
+ calculated += halfWidth;
+ }
+ } else {
+ // Start (NOT ARROW).
+ if (leftToRight) {
+ calculated += halfWidth;
+ } else {
+ calculated -= halfWidth;
+ }
+ }
+
+ return calculated;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show popup upon hovering over a messages that has associated notes.
+ * @param id
+ * @private
+ */
+ _showNotesPopup(id) {
+ if (this.popup) {
+ if (id) {
+ const message = this.application.getModel().getMessageById(id);
+ if (message && message.notes && message.notes.length > 0 && this.events.message) {
+ this.popup.setState({
+ visible: true,
+ left: this.events.message.x - 50,
+ top: this.events.message.y + 20,
+ notes: message.notes[0],
+ });
+ }
+ } else {
+ this.popup.setState({ visible: false, notes: '' });
+ }
+ }
+ }
+}
+
+
+Diagram.propTypes = {
+ application: React.PropTypes.object.isRequired,
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/components/popup/Popup.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/components/popup/Popup.jsx
new file mode 100644
index 0000000000..08c6da1e76
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/components/popup/Popup.jsx
@@ -0,0 +1,94 @@
+
+
+import React from 'react';
+
+import Icon from '../../../icons/Icon';
+import iconEdit from '../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/edit.svg';
+
+/**
+ * A hover-over popup. It shows notes, but perhaps will be put to other uses.
+ * @param props React properties.
+ * @returns {XML}
+ * @constructor
+ */
+export default class Popup extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct react view.
+ * @param props element properties (of which there are none).
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ top: 0,
+ left: 0,
+ visible: false,
+ notes: '',
+ };
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render view.
+ * @returns {XML}
+ */
+ render() {
+
+ // Build CSS + styles to position and configure popup.
+
+ let top = this.state.top;
+ let left = this.state.left;
+
+ const popupHeight = 200;
+ const popupWidth = 320;
+
+ let auxCssVertical = 'top';
+ let auxCssHorizontal = 'left';
+
+ if (this.state.top > (window.innerHeight - popupHeight)) {
+ top -= (popupHeight + 50);
+ auxCssVertical = 'bottom';
+ }
+
+ if (this.state.left > (window.innerWidth - popupWidth)) {
+ left -= (popupWidth - 80);
+ auxCssHorizontal = 'right';
+ }
+
+ const auxCss = `asdcs-diagram-popup-${auxCssVertical}${auxCssHorizontal}`;
+ const styles = {
+ top,
+ left,
+ display: (this.state.visible ? 'block' : 'none'),
+ };
+
+ // Render element.
+
+ let notes = this.state.notes || '';
+ if (notes.length > 255) {
+ notes = notes.substring(0, 255);
+ notes = `${notes} ...`;
+ }
+
+ return (
+ <div className={`asdcs-diagram-popup ${auxCss}`} style={styles}>
+ <div className="asdcs-diagram-popup-header">Notes</div>
+ <div className="asdcs-diagram-popup-body">
+ <div className="asdcs-icon-popup">
+ <Icon glyph={iconEdit} />
+ </div>
+ <div className="asdcs-diagram-notes">
+ <div className="asdcs-diagram-note">
+ {notes}
+ </div>
+ </div>
+ </div>
+ <div className="asdcs-diagram-popup-footer"></div>
+ </div>
+ );
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/diagram.html b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/diagram.html
new file mode 100644
index 0000000000..22893ce864
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/diagram.html
@@ -0,0 +1,56 @@
+<svg height="100%" width="100%" viewBox="<%-(x-25)%> <%-(y-25)%> <%-(width+50)%> <%-(height+50)%>" preserveAspectRatio="xMinYMin">
+ <defs>
+
+ <filter id="asdcsSvgHighlight" height="50" width="50" x="-25" y="-25">
+ <morphology in="SourceAlpha" operator="dilate" radius="25"></morphology>
+ <feGaussianBlur result="blur" stdDeviation="20"></feGaussianBlur>
+ <feComposite in2="SourceAlpha" k2="1" k3="-1" operator="arithmetic" result="hlDiff"></feComposite>
+ <feFlood flood-color="<%-floodColor%>" flood-opacity="1"></feFlood>
+ <feComposite in2="hlDiff" operator="in"></feComposite>
+ <feComposite in2="SourceGraphic" operator="over" result="withGlow"></feComposite>
+ </filter>
+
+ <marker id="asdcsDiagramArrowOpen"
+ viewBox="0 0 15 15"
+ refX="12"
+ refY="4"
+ markerWidth="15"
+ markerHeight="20"
+ orient="auto">
+ <path d="M0,0 L12,4 L0,8" class="asdcs-diagram-arrow asdcs-diagram-arrow-open" />
+ </marker>
+
+ <marker id="asdcsDiagramArrowClosed"
+ viewBox="0 0 15 15"
+ refX="12"
+ refY="4"
+ markerWidth="15"
+ markerHeight="20"
+ orient="auto">
+ <path d="M0,0 L12,4 L0,8 Z" class="asdcs-diagram-arrow asdcs-diagram-arrow-open" />
+ </marker>
+
+ <marker id="asdcsDiagramArrowSolid"
+ viewBox="0 0 15 15"
+ refX="12"
+ refY="4"
+ markerWidth="15"
+ markerHeight="20"
+ orient="auto">
+ <path d="M0,0 L12,4 L0,8 Z" class="asdcs-diagram-arrow asdcs-diagram-arrow-solid" />
+ </marker>
+
+ <!--
+ <marker id="asdcsDiagramArrowSolid"
+ viewBox="0 0 20 20"
+ refX="20"
+ refY="6"
+ markerWidth="20"
+ markerHeight="20"
+ orient="auto">
+ <path d="M0,0 L18,6 L0,12 Z" class="asdcs-diagram-arrow asdcs-diagram-arrow-solid" />
+ </marker>
+ -->
+
+ </defs>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/fragment.html b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/fragment.html
new file mode 100644
index 0000000000..812f5fcfb8
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/fragment.html
@@ -0,0 +1,18 @@
+<g class="asdcs-diagram-fragment" data-id="<%-id%>" data-type="fragment">
+
+ <rect x="<%-x%>" y="<%-y%>" height="<%-height%>" width="<%-width%>"></rect>
+
+ <path d="M<%-x%>,<%-(y+80)%> L<%-(x+100)%>,<%-(y+80)%> L<%-(x+120)%>,<%-(y+60)%> L<%-(x+120)%>,<%-y%>"/>
+
+ <text x="<%-(x+20)%>" y="<%-(y+50)%>" class="asdcs-diagram-fragment-operation"><%-operator%></text>
+
+ <rect class="asdcs-diagram-fragment-guard-bg"
+ x="0" y="0" height="0" width="0"
+ rx="5" ry="5" ></rect>
+
+ <text class="asdcs-diagram-fragment-guard" x="<%-(x+160)%>" y="<%-(y+10)%>"><%
+ for (var lineIndex = 0; lineIndex < lines.length ; lineIndex++) {
+ %><tspan x="<%-(x+160)%>" dy="40px"><%- lines[lineIndex] %></tspan><%
+ }%></text>
+
+</g>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/lifeline.html b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/lifeline.html
new file mode 100644
index 0000000000..cd01d42c5a
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/lifeline.html
@@ -0,0 +1,19 @@
+<g class="asdcs-diagram-lifeline-container" data-id="<%-id%>" data-type="lifeline">
+
+ <rect x="<%-(x-(headerWidth/2))%>" y="<%-(y0)%>" width="<%-headerWidth%>" height="<%-headerHeight%>" class="asdcs-diagram-lifeline-heading-box"></rect>
+
+ <text x="<%-x%>" y="<%-(headerHeight * ((rows-lines.length)/10))%>" class="asdcs-diagram-lifeline-heading-label"><%
+ for (var linesIndex = 0; linesIndex < lines.length && linesIndex < rows ; linesIndex++) {
+ %><tspan x="<%-x%>" dy="<%-(headerHeight/rows)-5%>px"><%- lines[linesIndex] %></tspan><%
+ }
+ %></text>
+
+ <rect x="<%-(x-5)%>" y="<%-(y0+headerHeight)%>" width="10" height="<%-(y1-(y0+headerHeight))%>" class="asdcs-diagram-lifeline-bg"></rect>
+
+ <path d="M<%-x%>,<%-(y0+headerHeight)%> L<%-x%>,<%-y1%>"
+ class="asdcs-diagram-lifeline-selectable"></path>
+
+ <path d="M<%-x%>,<%-(y0+headerHeight)%> L<%-x%>,<%-y1%>"
+ class="asdcs-diagram-lifeline"></path>
+
+</g>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/message.html b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/message.html
new file mode 100644
index 0000000000..bd4c33a016
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/message.html
@@ -0,0 +1,29 @@
+<g class="asdcs-diagram-message-container" data-id="<%-id%>" data-type="lifeline">
+
+ <%
+ var delta = 40;
+ var x = (x0 + x1) / 2;
+ var y0 = y - ((labels.length + 1) * delta);
+ %>
+
+ <rect class="asdcs-diagram-message-label-bg"
+ x="<%-x%>"
+ y="<%-y0%>"
+ height="10"
+ width="10"
+ rx="10" ry="10" ></rect>
+
+ <text class="asdcs-diagram-message-label" x="<%-x%>" y="<%-y0%>"><%
+ for (var labelIndex = 0; labelIndex < labels.length && labelIndex < lines ; labelIndex++) {
+ %><tspan x="<%-x%>" dy="<%-delta%>px"><%- labels[labelIndex] %></tspan><%
+ }%></text>
+
+
+ <rect x="<%-Math.min(x0,x1)%>" y="<%-(y-5)%>" width="<%-Math.abs(x1-x0)%>" height="10" class="asdcs-diagram-message-bg"></rect>
+
+ <path class="asdcs-diagram-message-selectable" d="<%-path%>"></path>
+
+ <path class="<%-classes%>" marker-end="url(#<%-marker%>)" stroke-dasharray="<%-dasharray%>"
+ data-id="<%-id%>" data-type="message" d="<%-path%>"></path>
+
+</g>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/occurrence.html b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/occurrence.html
new file mode 100644
index 0000000000..0af9ff3d68
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/occurrence.html
@@ -0,0 +1,7 @@
+<g>
+ <rect class="asdcs-diagram-occurrence"
+ x="<%-x%>"
+ y="<%-y%>"
+ width="<%-width%>"
+ height="<%-height%>" />
+</g>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/title.html b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/title.html
new file mode 100644
index 0000000000..b7a5d68a6d
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/templates/title.html
@@ -0,0 +1,3 @@
+<g class="asdcs-diagram-title">
+ <text x="<%-x%>" y="<%-y%>"><%-title%></text>
+</g>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/dialog/Dialog.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/dialog/Dialog.jsx
new file mode 100644
index 0000000000..4429d80bc6
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/dialog/Dialog.jsx
@@ -0,0 +1,222 @@
+
+
+import React from 'react';
+
+import Icon from '../icons/Icon';
+import iconQuestion from '../../../../../../res/ecomp/asdc/sequencer/sprites/icon/question.svg';
+import iconExclaim from '../../../../../../res/ecomp/asdc/sequencer/sprites/icon/exclaim.svg';
+import iconInfo from '../../../../../../res/ecomp/asdc/sequencer/sprites/icon/info.svg';
+import iconEdit from '../../../../../../res/ecomp/asdc/sequencer/sprites/icon/edit.svg';
+import iconClose from '../../../../../../res/ecomp/asdc/sequencer/sprites/icon/close.svg';
+
+/**
+ * Multi-purpose dialog. Rendered into the page on initialization, and then
+ * configured, shown and hidden as required.
+ */
+export default class Dialog extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct view.
+ */
+ constructor(props, context) {
+
+ super(props, context);
+
+ this.MODE = {
+ INFO: {
+ icon: 'asdcs-icon-info',
+ heading: 'Information',
+ },
+ ERROR: {
+ icon: 'asdcs-icon-exclaim',
+ heading: 'Error',
+ },
+ EDIT: {
+ icon: 'asdcs-icon-edit',
+ heading: 'Edit',
+ edit: true,
+ confirm: true,
+ },
+ CONFIRM: {
+ icon: 'asdcs-icon-question',
+ heading: 'Confirm',
+ confirm: true,
+ },
+ };
+
+ this.state = {
+ mode: this.MODE.INFO,
+ message: '',
+ text: '',
+ visible: false,
+ };
+
+ // Bindings.
+
+ this.onClickOK = this.onClickOK.bind(this);
+ this.onClickCancel = this.onClickCancel.bind(this);
+ this.onChangeText = this.onChangeText.bind(this);
+ this.showConfirmDialog = this.showConfirmDialog.bind(this);
+ this.showInfoDialog = this.showInfoDialog.bind(this);
+ this.showEditDialog = this.showEditDialog.bind(this);
+ this.showErrorDialog = this.showErrorDialog.bind(this);
+ this.showDialog = this.showDialog.bind(this);
+
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show info dialog.
+ * @param message info message.
+ */
+ showInfoDialog(message) {
+ this.showDialog(this.MODE.INFO, { message });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show error dialog.
+ * @param message error message.
+ */
+ showErrorDialog(message) {
+ this.showDialog(this.MODE.ERROR, { message });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show edit dialog.
+ * @param message dialog message.
+ * @param text current edit text.
+ * @param callback callback function to be invoked on OK.
+ */
+ showEditDialog(message, text, callback) {
+ this.showDialog(this.MODE.EDIT, { message, text, callback });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show confirmation dialog.
+ * @param message dialog message.
+ * @param callback callback function to be invoked on OK.
+ */
+ showConfirmDialog(message, callback) {
+ this.showDialog(this.MODE.CONFIRM, { message, callback });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle buttonclick.
+ */
+ onClickOK() {
+ this.props.application.hideOverlay();
+ this.setState({ visible: false });
+ if (this.callback) {
+
+ // So far the only thing we can return is edit text, but send it back
+ // as properties to allow for future return values.
+
+ this.callback({ text: this.state.text });
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle buttonclick.
+ */
+ onClickCancel() {
+ this.props.application.hideOverlay();
+ this.setState({ visible: false });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle text changes.
+ * @param event update event.
+ */
+ onChangeText(event) {
+ this.setState({ text: event.target.value });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show dialog in specified configuration.
+ * @param mode dialog mode.
+ * @param args dialog parameters, varying slightly by dialog type.
+ * @private
+ */
+ showDialog(mode, args) {
+ this.props.application.showOverlay();
+ this.callback = args.callback;
+ this.setState({
+ mode,
+ visible: true,
+ message: args.message || '',
+ text: args.text || '',
+ });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render dialog into the page, initially hidden.
+ */
+ render() {
+
+ const dialogClass = (this.state.visible) ? '' : 'asdcs-hidden';
+ const cancelClass = (this.callback) ? '' : 'asdcs-hidden';
+ const textClass = (this.state.mode === this.MODE.EDIT) ? '' : 'asdcs-hidden';
+
+ return (
+ <div className={`asdcs-dialog ${dialogClass}`}>
+ <div className="asdcs-dialog-header">{this.state.mode.heading}</div>
+ <div className="asdcs-dialog-close" onClick={this.onClickCancel} >
+ <Icon glyph={iconClose} className={this.MODE.CONFIRM.icon} />
+ </div>
+ <div className={`asdcs-dialog-icon ${this.state.mode.icon}`}>
+ <Icon glyph={iconQuestion} className={this.MODE.CONFIRM.icon} />
+ <Icon glyph={iconExclaim} className={this.MODE.ERROR.icon} />
+ <Icon glyph={iconInfo} className={this.MODE.INFO.icon} />
+ <Icon glyph={iconEdit} className={this.MODE.EDIT.icon} />
+ </div>
+ <div className="asdcs-dialog-message">
+ {this.state.message}
+ </div>
+ <div className={`asdcs-dialog-text ${textClass}`}>
+ <textarea
+ maxLength="255"
+ value={this.state.text}
+ onChange={this.onChangeText}
+ />
+ </div>
+ <div className="asdcs-dialog-buttonbar">
+ <button
+ className={`asdcs-dialog-button-cancel ${cancelClass}`}
+ onClick={this.onClickCancel}
+ >
+ Cancel
+ </button>
+ <button
+ className="asdcs-dialog-button-ok"
+ onClick={this.onClickOK}
+ >
+ OK
+ </button>
+ </div>
+ </div>
+ );
+ }
+}
+
+Dialog.propTypes = {
+ application: React.PropTypes.object.isRequired,
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/Editor.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/Editor.jsx
new file mode 100644
index 0000000000..09703b84bf
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/Editor.jsx
@@ -0,0 +1,171 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+import Logger from '../../common/Logger';
+import Common from '../../common/Common';
+import Designer from './components/designer/Designer';
+import Toolbar from './components/toolbar/Toolbar';
+import Source from './components/source/Source';
+
+/**
+ * Editor view, aggregating the designer, the code editor, the toolbar.
+ */
+export default class Editor extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct React view.
+ * @param props properties.
+ * @param context context.
+ */
+ constructor(props, context) {
+ super(props, context);
+
+ this.application = Common.assertNotNull(props.application);
+ this.demo = this.application.getOptions().demo;
+
+ // Bindings.
+
+ this.selectMessage = this.selectMessage.bind(this);
+ this.selectLifeline = this.selectLifeline.bind(this);
+
+ this.onMouseDown = this.onMouseDown.bind(this);
+ this.onMouseUp = this.onMouseUp.bind(this);
+ this.onMouseMove = this.onMouseMove.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Select message by ID.
+ * @param id message ID.
+ */
+ selectMessage(id) {
+ if (this.designer) {
+ this.designer.selectMessage(id);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Select lifeline by ID.
+ * @param id lifeline ID.
+ */
+ selectLifeline(id) {
+ if (this.designer) {
+ this.designer.selectLifeline(id);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Record that we're dragging.
+ */
+ onMouseDown() {
+ if (this.editor) {
+ this.resize = {
+ initialWidth: this.editor.offsetWidth,
+ initialPageX: undefined,
+ };
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Record that we're not dragging.
+ */
+ onMouseUp() {
+ this.resize = undefined;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Record mouse movement.
+ */
+ onMouseMove(event) {
+ if (this.resize) {
+ if (this.editor) {
+ if (this.resize.initialPageX) {
+ const deltaX = event.pageX - this.resize.initialPageX;
+ const newWidth = this.resize.initialWidth + deltaX;
+ const newWidthBounded = Math.min(800, Math.max(400, newWidth));
+ this.editor.style.width = `${newWidthBounded}px`;
+ } else {
+ this.resize.initialPageX = event.pageX;
+ }
+ }
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render editor.
+ */
+ render() {
+
+ Logger.info('Editor.jsx - render()');
+
+ return (
+
+ <div
+ className="asdcs-editor"
+ ref={(r) => { this.editor = r; }}
+ >
+
+ <Toolbar application={this.props.application} editor={this} />
+
+ <div className="asdcs-editor-content">
+ <Source application={this.props.application} />
+ <Designer
+ application={this.props.application}
+ ref={(r) => {
+ if (r) {
+ this.designer = r.getDecoratedComponentInstance();
+ } else {
+ this.designer = null;
+ }
+ }}
+ />
+ </div>
+
+ <div className="asdcs-editor-statusbar">
+ <div className="asdcs-editor-status"></div>
+ <div className="asdcs-editor-validation"></div>
+ </div>
+
+ <div
+ className="asdcs-editor-resize-handle"
+ onMouseDown={this.onMouseDown}
+ onMouseUp={this.onMouseUp}
+ >
+ </div>
+ </div>
+ );
+ }
+}
+
+/** Element properties. */
+Editor.propTypes = {
+ application: React.PropTypes.object.isRequired,
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/Designer.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/Designer.jsx
new file mode 100644
index 0000000000..69cdd17ed5
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/Designer.jsx
@@ -0,0 +1,403 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+import HTML5Backend from 'react-dnd-html5-backend';
+import { DragDropContext } from 'react-dnd';
+
+import Common from '../../../../common/Common';
+import Logger from '../../../../common/Logger';
+
+import Actions from './components/actions/Actions';
+import Lifelines from './components/lifeline/Lifelines';
+import Messages from './components/message/Messages';
+import Metadata from './components/metadata/Metadata';
+
+import Icon from '../../../icons/Icon';
+import iconExpanded from '../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/expanded.svg';
+import iconCollapsed from '../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/collapsed.svg';
+
+/**
+ * LHS design wid` view.
+ */
+class Designer extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+
+ Logger.noop();
+
+ this.application = Common.assertNotNull(props.application);
+
+ this.state = {
+ lifelinesExpanded: false,
+ messagesExpanded: true,
+ activeLifelineId: undefined,
+ activeMessageId: undefined,
+ };
+
+ // Bind this.
+
+ this.onToggle = this.onToggle.bind(this);
+ this.onMouseEnterLifeline = this.onMouseEnterLifeline.bind(this);
+ this.onMouseLeaveLifeline = this.onMouseLeaveLifeline.bind(this);
+ this.onMouseEnterMessage = this.onMouseEnterMessage.bind(this);
+ this.onMouseLeaveMessage = this.onMouseLeaveMessage.bind(this);
+
+ this.addMessage = this.addMessage.bind(this);
+ this.updateMessage = this.updateMessage.bind(this);
+ this.deleteMessage = this.deleteMessage.bind(this);
+ this.addLifeline = this.addLifeline.bind(this);
+ this.updateLifeline = this.updateLifeline.bind(this);
+ this.deleteLifeline = this.deleteLifeline.bind(this);
+
+ this.selectMessage = this.selectMessage.bind(this);
+ this.selectLifeline = this.selectLifeline.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Select message by ID.
+ * @param id message ID.
+ */
+ selectMessage(id) {
+
+ // TODO: scroll into view.
+
+ this.setState({ activeMessageId: id });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Select lifeline by ID.
+ * @param id lifeline ID.
+ */
+ selectLifeline(id) {
+
+ // TODO: scroll into view.
+
+ this.setState({ activeLifelineId: id });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show/hide lifelines section.
+ */
+ onToggle() {
+ const lifelinesExpanded = !this.state.lifelinesExpanded;
+ const messagesExpanded = !lifelinesExpanded;
+ this.setState({ lifelinesExpanded, messagesExpanded });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle mouse event.
+ * @param id lifeline identifier.
+ */
+ onMouseEnterLifeline(id) {
+ this.application.selectLifeline(id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle mouse event.
+ */
+ onMouseLeaveLifeline() {
+ this.application.selectLifeline();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle mouse event.
+ * @param id message identifier.
+ */
+ onMouseEnterMessage(id) {
+ this.application.selectMessage(id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle mouse event.
+ */
+ onMouseLeaveMessage() {
+ // Only on next selection.
+ // this.application.selectMessage();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Add new message.
+ */
+ addMessage() {
+
+ if (this.application.getModel().unwrap().diagram.lifelines.length < 2) {
+ self.application.showErrorDialog('You need at least two lifelines.');
+ return;
+ }
+
+ this.application.getModel().addMessage();
+ this.forceUpdate();
+ this.application.renderDiagram();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Apply property changes to the message identified by props.id.
+ * @param props properties to be updated (excluding 'id').
+ */
+ updateMessage(props) {
+ Common.assertPlainObject(props);
+ const model = this.application.getModel();
+ const message = model.getMessageById(props.id);
+ if (message) {
+ for (const k of Object.keys(props)) {
+ if (k !== 'id') {
+ message[k] = props[k];
+ }
+ }
+ }
+ this.forceUpdate();
+ this.application.renderDiagram();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Delete message after confirmation.
+ * @param id ID of message to be deleted.
+ */
+ deleteMessage(id) {
+
+ const self = this;
+ const model = this.application.getModel();
+
+ const confirmComplete = function f() {
+ model.deleteMessageById(id);
+ self.render();
+ self.application.renderDiagram();
+ };
+
+ this.application.showConfirmDialog('Delete this message?',
+ confirmComplete);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Add new lifeline.
+ */
+ addLifeline() {
+ this.application.getModel().addLifeline();
+ this.forceUpdate();
+ this.application.renderDiagram();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Apply property changes to the lifeline identified by props.id.
+ * @param props properties to be updated (excluding 'id').
+ */
+ updateLifeline(props) {
+ Common.assertPlainObject(props);
+ const model = this.application.getModel();
+ const lifeline = model.getLifelineById(props.id);
+ if (lifeline) {
+ for (const k of Object.keys(props)) {
+ if (k !== 'id') {
+ lifeline[k] = props[k];
+ }
+ }
+ }
+ this.forceUpdate();
+ this.application.renderDiagram();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Delete lifeline after confirmation.
+ * @param id candidate for deletion.
+ */
+ deleteLifeline(id) {
+
+ const self = this;
+ const model = this.application.getModel();
+
+ const confirmComplete = function f() {
+ model.deleteLifelineById(id);
+ self.forceUpdate();
+ self.application.renderDiagram();
+ };
+ this.application.showConfirmDialog('Delete this lifeline and all its steps?',
+ confirmComplete);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render designer.
+ */
+ render() {
+
+ const application = this.props.application;
+ const model = application.getModel();
+ const diagram = model.unwrap().diagram;
+ const metadata = diagram.metadata;
+
+ const lifelinesIcon = this.state.lifelinesExpanded ? iconExpanded : iconCollapsed;
+ const lifelinesClass = this.state.lifelinesExpanded ? '' : 'asdcs-hidden';
+ const messagesIcon = this.state.messagesExpanded ? iconExpanded : iconCollapsed;
+ const messagesClass = this.state.messagesExpanded ? '' : 'asdcs-hidden';
+
+ return (
+
+ <div className="asdcs-editor-designer">
+ <div className="asdcs-designer-accordion">
+
+ <div className="asdcs-designer-metadata-container">
+ <Metadata metadata={metadata} />
+ </div>
+
+ <h3 onClick={this.onToggle}>Lifelines
+ <div className="asdcs-designer-icon" onClick={this.onToggle}>
+ <Icon glyph={lifelinesIcon} />
+ </div>
+ </h3>
+
+ <div className={`asdcs-designer-lifelines-container ${lifelinesClass}`}>
+ <Lifelines
+ application={this.application}
+ designer={this}
+ activeLifelineId={this.state.activeLifelineId}
+ />
+ </div>
+
+ <h3 onClick={this.onToggle}>Steps
+ <div className="asdcs-designer-icon" onClick={this.onToggle}>
+ <Icon glyph={messagesIcon} />
+ </div>
+ </h3>
+
+ <div className={`asdcs-designer-steps-container ${messagesClass}`} >
+ <Messages
+ application={this.application}
+ designer={this}
+ activeMessageId={this.state.activeMessageId}
+ />
+ </div>
+
+ </div>
+
+ <Actions
+ application={this.props.application}
+ model={model}
+ ref={(r) => { this.actions = r; }}
+ />
+
+ </div>
+ );
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Scroll accordion pane to make
+ * @param $element focused element.
+ * @private
+ */
+ static _scrollIntoView($element) {
+ const $pane = $element.closest('.ui-accordion-content');
+ const paneScrollTop = $pane.scrollTop();
+ const paneHeight = $pane.height();
+ const paneBottom = paneScrollTop + paneHeight;
+ const elementTop = $element[0].offsetTop - $pane[0].offsetTop;
+ const elementHeight = $element.height();
+ const elementBottom = elementTop + elementHeight;
+ if (elementBottom > paneBottom) {
+ $pane.scrollTop(elementTop);
+ } else if (elementTop < paneScrollTop) {
+ $pane.scrollTop(elementTop);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show actions menu.
+ * @param id selected message ID.
+ * @param position page coordinates.
+ */
+ showActions(id, position) {
+ if (this.actions) {
+ this.actions.show(id, position);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show notes popup.
+ * @param id selected message identifier.
+ */
+ showNotes(id) {
+ const model = this.application.getModel();
+ const options = this.application.getOptions();
+ const message = model.getMessageById(id);
+ const notes = (message.notes && (message.notes.length > 0)) ? message.notes[0] : '';
+ const editComplete = function f(p) {
+ message.notes = [];
+ if (p && p.text) {
+ const sanitized = Common.sanitizeText(p.text, options, 'notes');
+ message.notes.push(sanitized);
+ }
+ };
+ this.application.showEditDialog('Notes:', notes, editComplete);
+ }
+}
+
+/** Element properties. */
+Designer.propTypes = {
+ application: React.PropTypes.object.isRequired,
+};
+
+export default DragDropContext(HTML5Backend)(Designer);
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/actions/Actions.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/actions/Actions.jsx
new file mode 100644
index 0000000000..851da78870
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/actions/Actions.jsx
@@ -0,0 +1,471 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+import Select from 'react-select';
+
+import Common from '../../../../../../common/Common';
+import Logger from '../../../../../../common/Logger';
+
+import Icon from '../../../../../icons/Icon';
+import iconSettings from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/settings.svg';
+import iconExpanded from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/expanded.svg';
+import iconCollapsed from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/collapsed.svg';
+import iconOccurrenceDefault from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/occurrence-default.svg';
+import iconOccurrenceStart from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/occurrence-start.svg';
+import iconOccurrenceStop from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/occurrence-stop.svg';
+import iconFragmentDefault from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/fragment-default.svg';
+import iconFragmentStart from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/fragment-start.svg';
+import iconFragmentStop from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/fragment-stop.svg';
+
+/**
+ * Action menu view.
+ */
+export default class Actions extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+
+ Logger.noop();
+
+ this.state = {
+ id: undefined,
+ visible: false,
+ };
+
+ // Bindings.
+
+ this.show = this.show.bind(this);
+
+ this.onClickOccurrenceToggle = this.onClickOccurrenceToggle.bind(this);
+ this.onClickOccurrenceFrom = this.onClickOccurrenceFrom.bind(this);
+ this.onClickOccurrenceTo = this.onClickOccurrenceTo.bind(this);
+
+ this.onClickFragmentToggle = this.onClickFragmentToggle.bind(this);
+ this.onChangeFragmentGuard = this.onChangeFragmentGuard.bind(this);
+ this.onChangeFragmentOperator = this.onChangeFragmentOperator.bind(this);
+
+ this.onMouseOut = this.onMouseOut.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Show for message.
+ * @param id message ID.
+ * @param position xy coordinates.
+ */
+ show(id, position) {
+ const message = this.props.model.getMessageById(id);
+
+ let occurrencesToggle = false;
+ let fragmentToggle = false;
+ if (message) {
+
+ message.occurrences = message.occurrences || { start: [], stop: [] };
+ message.occurrences.start = message.occurrences.start || [];
+ message.occurrences.stop = message.occurrences.stop || [];
+ message.fragment = message.fragment || {};
+ message.fragment.start = message.fragment.start || false;
+ message.fragment.stop = message.fragment.stop || false;
+ message.fragment.guard = message.fragment.guard || '';
+ message.fragment.operator = message.fragment.operator || '';
+
+ const mo = message.occurrences;
+ occurrencesToggle = (mo.start.length > 0 || mo.stop.length > 0);
+
+ const mf = message.fragment;
+ fragmentToggle = (mf.start || mf.stop);
+ }
+
+ this.setState({
+ id,
+ message,
+ occurrencesToggle,
+ fragmentToggle,
+ visible: true,
+ x: position.x,
+ y: position.y,
+ });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Toggle occurrence state.
+ */
+ onClickOccurrenceToggle() {
+ const message = this.state.message;
+ if (message) {
+ const oFromState = Actions.getOccurrenceState(message.occurrences, message.from);
+ const oToState = Actions.getOccurrenceState(message.occurrences, message.to);
+ const oExpanded = oFromState > 0 || oToState > 0;
+ if (oExpanded) {
+ this.setState({ occurrencesExpanded: true });
+ } else {
+ const occurrencesExpanded = !this.state.occurrencesExpanded;
+ this.setState({ occurrencesExpanded });
+ }
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle menu click.
+ */
+ onClickOccurrenceFrom() {
+ const message = this.state.message;
+ if (message) {
+ Actions._toggleOccurrence(message.occurrences, message.from);
+ }
+ this.setState({ message });
+ this.props.application.renderDiagram();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle menu click.
+ */
+ onClickOccurrenceTo() {
+ const message = this.state.message;
+ if (message) {
+ Actions._toggleOccurrence(message.occurrences, message.to);
+ }
+ this.setState({ message });
+ this.props.application.renderDiagram();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Toggle fragment.
+ */
+ onClickFragmentToggle() {
+ const message = this.state.message;
+ if (message) {
+ Actions._toggleFragment(message.fragment);
+ }
+ this.setState({ message });
+ this.props.application.renderDiagram();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle menu click.
+ * @param event update event.
+ */
+ onChangeFragmentGuard(event) {
+ const message = this.state.message;
+ if (message) {
+ const options = this.props.application.getOptions();
+ message.fragment.guard = Common.sanitizeText(event.target.value, options, 'guard');
+ }
+ this.setState({ message });
+ this.props.application.renderDiagram();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle menu click.
+ * @param value updated value.
+ */
+ onChangeFragmentOperator(value) {
+ const message = this.state.message;
+ if (message) {
+ message.fragment.operator = value.value;
+ }
+ this.setState({ message });
+ this.props.application.renderDiagram();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle mouse movement.
+ */
+ onMouseOut() {
+ this.setState({ id: -1, visible: false, x: 0, y: 0 });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render view.
+ * @returns {XML}
+ */
+ render() {
+
+ const actionsStyles = { };
+ const message = this.state.message;
+ if (!message || !this.state.visible) {
+
+ // Invisible.
+
+ return (<div className="asdcs-actions" ></div>);
+ }
+
+ // Position and display.
+
+ actionsStyles.display = 'block';
+ actionsStyles.left = this.state.x - 10;
+ actionsStyles.top = this.state.y - 10;
+
+ const oFromState = Actions.getOccurrenceState(message.occurrences, message.from);
+ const oToState = Actions.getOccurrenceState(message.occurrences, message.to);
+ const fState = Actions.getFragmentState(message.fragment);
+
+ const oExpanded = this.state.occurrencesExpanded || (oFromState > 0) || (oToState > 0);
+ const oAuxClassName = oExpanded ? '' : 'asdcs-hidden';
+
+ const fExpanded = fState !== 0;
+ const fAuxClassName = fExpanded ? '' : 'asdcs-hidden';
+
+ const fragmentOperatorOptions = [{
+ value: 'alt',
+ label: 'Alternate',
+ }, {
+ value: 'opt',
+ label: 'Optional',
+ }, {
+ value: 'loop',
+ label: 'Loop',
+ }];
+
+ const operator = message.fragment.operator || 'alt';
+
+ return (
+ <div
+ className="asdcs-actions"
+ style={actionsStyles}
+ onMouseLeave={this.onMouseOut}
+ >
+ <div className="asdcs-actions-header">
+ <div className="asdcs-actions-icon">
+ <Icon glyph={iconSettings} />
+ </div>
+ </div>
+
+ <div className="asdcs-actions-options">
+
+ <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-occurrence">
+ <div
+ className="asdcs-actions-option asdcs-actions-option-occurrence-toggle"
+ onClick={this.onClickOccurrenceToggle}
+ >
+ <span className="asdcs-label">Occurrence</span>
+ <div className="asdcs-actions-state">
+ <Icon glyph={iconCollapsed} className={oExpanded ? 'asdcs-hidden' : ''} />
+ <Icon glyph={iconExpanded} className={oExpanded ? '' : 'asdcs-hidden'} />
+ </div>
+ </div>
+ </div>
+
+ <div
+ className={`asdcs-actions-option asdcs-actions-option-occurrence-from ${oAuxClassName}`}
+ onClick={this.onClickOccurrenceFrom}
+ >
+ <span className="asdcs-label">From</span>
+ <div className="asdcs-actions-state">
+ <span className="asdcs-annotation"></span>
+ <Icon glyph={iconOccurrenceDefault} className={oFromState === 0 ? '' : 'asdcs-hidden'} />
+ <Icon glyph={iconOccurrenceStart} className={oFromState === 1 ? '' : 'asdcs-hidden'} />
+ <Icon glyph={iconOccurrenceStop} className={oFromState === 2 ? '' : 'asdcs-hidden'} />
+ </div>
+ </div>
+
+ <div
+ className={`asdcs-actions-option asdcs-actions-option-occurrence-to ${oAuxClassName}`}
+ onClick={this.onClickOccurrenceTo}
+ >
+ <span className="asdcs-label">To</span>
+ <div className="asdcs-actions-state">
+ <span className="asdcs-annotation"></span>
+ <Icon glyph={iconOccurrenceDefault} className={oToState === 0 ? '' : 'asdcs-hidden'} />
+ <Icon glyph={iconOccurrenceStart} className={oToState === 1 ? '' : 'asdcs-hidden'} />
+ <Icon glyph={iconOccurrenceStop} className={oToState === 2 ? '' : 'asdcs-hidden'} />
+ </div>
+ </div>
+
+ <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-fragment">
+ <div
+ className="asdcs-actions-option asdcs-actions-fragment-toggle"
+ onClick={this.onClickFragmentToggle}
+ >
+ <span className="asdcs-label">Fragment</span>
+ <div className="asdcs-actions-state">
+ <span className="asdcs-annotation"></span>
+ <Icon glyph={iconFragmentDefault} className={fState === 0 ? '' : 'asdcs-hidden'} />
+ <Icon glyph={iconFragmentStart} className={fState === 1 ? '' : 'asdcs-hidden'} />
+ <Icon glyph={iconFragmentStop} className={fState === 2 ? '' : 'asdcs-hidden'} />
+ </div>
+ </div>
+ </div>
+
+ <div className={`asdcs-actions-option asdcs-actions-fragment-operator ${fAuxClassName}`}>
+ <div className="asdcs-label">Operator</div>
+ <div className="asdcs-value">
+ <Select
+ className="asdcs-editable-select"
+ openOnFocus
+ clearable={false}
+ searchable={false}
+ value={operator}
+ onChange={this.onChangeFragmentOperator}
+ options={fragmentOperatorOptions}
+ />
+ </div>
+ </div>
+
+ <div className={`asdcs-actions-option asdcs-actions-fragment-guard ${fAuxClassName}`}>
+ <div className="asdcs-label">Guard</div>
+ <div className="asdcs-value">
+ <input
+ className="asdcs-editable"
+ type="text"
+ size="20"
+ maxLength="80"
+ value={message.fragment.guard}
+ placeholder="Condition"
+ onChange={this.onChangeFragmentGuard}
+ />
+ </div>
+ </div>
+
+ </div>
+
+ <div className="asdcs-actions-footer"></div>
+
+ </div>
+
+ );
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Toggle through three occurrence states on click.
+ * @param occurrence occurrences state, updated as side-effect.
+ * @param lifelineId message end that's being toggled.
+ * @private
+ */
+ static _toggleOccurrence(occurrence, lifelineId) {
+ const o = occurrence;
+
+ const rm = function rm(array, value) {
+ const index = array.indexOf(value);
+ if (index !== -1) {
+ array.splice(index, 1);
+ }
+ };
+
+ const add = function add(array, value) {
+ if (array.indexOf(value) === -1) {
+ array.push(value);
+ }
+ };
+
+ if (o.start && o.start.indexOf(lifelineId) !== -1) {
+ // Start -> stop.
+ rm(o.start, lifelineId);
+ add(o.stop, lifelineId);
+ } else if (o.stop && o.stop.indexOf(lifelineId) !== -1) {
+ // Stop -> default.
+ rm(o.start, lifelineId);
+ rm(o.stop, lifelineId);
+ } else {
+ // Default -> start.
+ add(o.start, lifelineId);
+ rm(o.stop, lifelineId);
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Toggle fragment setting on click.
+ * @param fragment
+ * @private
+ **/
+ static _toggleFragment(fragment) {
+ const f = fragment;
+ if (f.start === true) {
+ f.start = false;
+ f.stop = true;
+ } else if (f.stop === true) {
+ f.stop = false;
+ f.start = false;
+ } else {
+ f.start = true;
+ f.stop = false;
+ }
+ f.guard = '';
+ f.operator = '';
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get ternary occurrences state.
+ * @param o occurrences.
+ * @param lifelineId from/to lifeline ID.
+ * @returns {number}
+ * @private
+ */
+ static getOccurrenceState(o, lifelineId) {
+ if (o.start.indexOf(lifelineId) !== -1) {
+ return 1;
+ }
+ if (o.stop.indexOf(lifelineId) !== -1) {
+ return 2;
+ }
+ return 0;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get ternary fragment state.
+ * @param f fragment.
+ * @returns {number}
+ * @private
+ */
+ static getFragmentState(f) {
+ if (f.start) {
+ return 1;
+ }
+ if (f.stop) {
+ return 2;
+ }
+ return 0;
+ }
+}
+
+/** Element properties. */
+Actions.propTypes = {
+ application: React.PropTypes.object.isRequired,
+ model: React.PropTypes.object.isRequired,
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifeline.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifeline.jsx
new file mode 100644
index 0000000000..e8d8cffb7a
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifeline.jsx
@@ -0,0 +1,264 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+import { DragSource, DropTarget } from 'react-dnd';
+
+import Common from '../../../../../../common/Common';
+
+import Icon from '../../../../../icons/Icon';
+import iconHandle from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/handle.svg';
+import iconDelete from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/delete.svg';
+
+/**
+ * LHS lifeline row view.
+ */
+class Lifeline extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct editor view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+
+ this.state = {
+ active: false,
+ name: props.lifeline.name,
+ };
+
+ const metamodel = Common.assertNotNull(this.props.metamodel).unwrap();
+ this.canReorder = metamodel.diagram.lifelines.constraints.reorder;
+ this.canDelete = metamodel.diagram.lifelines.constraints.delete;
+
+ // Bindings.
+
+ this.onChangeName = this.onChangeName.bind(this);
+ this.onBlurName = this.onBlurName.bind(this);
+ this.onClickDelete = this.onClickDelete.bind(this);
+ this.onMouseEnter = this.onMouseEnter.bind(this);
+ this.onMouseLeave = this.onMouseLeave.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle name change.
+ * @param event change event.
+ */
+ onChangeName(event) {
+ this.setState({ name: event.target.value });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle name change.
+ * @param event change event.
+ */
+ onBlurName(event) {
+ const options = this.props.application.getOptions();
+ const sanitized = Common.sanitizeText(event.target.value, options, 'lifeline');
+ const props = {
+ id: this.props.lifeline.id,
+ name: sanitized,
+ };
+ this.props.designer.updateLifeline(props);
+ this.setState({ name: sanitized });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle lifeline delete.
+ */
+ onClickDelete() {
+ this.props.designer.deleteLifeline(this.props.lifeline.id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle mouseover event.
+ */
+ onMouseEnter() {
+ this.setState({ active: true });
+ this.props.designer.onMouseEnterLifeline(this.props.lifeline.id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle mouseleave event.
+ */
+ onMouseLeave() {
+ this.setState({ active: false });
+ this.props.designer.onMouseLeaveLifeline(this.props.lifeline.id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get whether metadata permits reorder.
+ * @returns true if reorderable.
+ */
+ isCanReorder() {
+ return this.canReorder;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get whether metadata permits delete.
+ * @returns true if lifeline can be deleted.
+ */
+ isCanDelete() {
+ return this.canDelete;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * React render.
+ * @returns {*}
+ */
+ render() {
+
+ const id = this.props.lifeline.id;
+ const activeClass = (this.props.active === true) ? 'asdcs-active' : '';
+ const { connectDragSource, connectDropTarget } = this.props;
+ return connectDragSource(connectDropTarget(
+
+ <div
+ className={`asdcs-designer-lifeline ${activeClass}`}
+ data-id={id}
+ onMouseEnter={this.onMouseEnter}
+ onMouseLeave={this.onMouseLeave}
+ >
+ <table className="asdcs-designer-layout asdcs-designer-lifeline-row1">
+ <tbody>
+ <tr>
+ <td>
+ <div className="asdcs-designer-sort asdcs-designer-icon">
+ <Icon glyph={iconHandle} />
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-lifeline-index">{this.props.lifeline.index}.</div>
+ </td>
+ <td>
+ <div className="asdcs-designer-lifeline-name">
+ <input
+ type="text"
+ className="asdcs-editable"
+ placeholder="Unnamed"
+ value={this.state.name}
+ onChange={this.onChangeName}
+ onBlur={this.onBlurName}
+ />
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-delete asdcs-designer-icon" onClick={this.onClickDelete}>
+ <Icon glyph={iconDelete} />
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ ));
+ }
+}
+
+/**
+ * Declare properties.
+ */
+Lifeline.propTypes = {
+ application: React.PropTypes.object.isRequired,
+ designer: React.PropTypes.object.isRequired,
+ lifeline: React.PropTypes.object.isRequired,
+ active: React.PropTypes.bool.isRequired,
+ metamodel: React.PropTypes.object.isRequired,
+ id: React.PropTypes.any.isRequired,
+ index: React.PropTypes.number.isRequired,
+ lifelines: React.PropTypes.object.isRequired,
+ isDragging: React.PropTypes.bool.isRequired,
+ connectDragSource: React.PropTypes.func.isRequired,
+ connectDropTarget: React.PropTypes.func.isRequired,
+};
+
+/** DND. */
+const source = {
+ beginDrag(props) {
+ return {
+ id: props.id,
+ index: props.index,
+ };
+ },
+};
+
+/** DND. */
+const sourceCollect = function collection(connect, monitor) {
+ return {
+ connectDragSource: connect.dragSource(),
+ isDragging: monitor.isDragging(),
+ };
+};
+
+/** DND. */
+const target = {
+ drop(props, monitor, component) {
+ Common.assertNotNull(props);
+ Common.assertNotNull(monitor);
+ const decorated = component.getDecoratedComponentInstance();
+ if (decorated) {
+ const lifelines = decorated.props.lifelines;
+ if (lifelines) {
+ const dragIndex = monitor.getItem().index;
+ const hoverIndex = lifelines.getHoverIndex();
+ lifelines.onDrop(dragIndex, hoverIndex);
+ }
+ }
+ },
+ hover(props, monitor, component) {
+ Common.assertNotNull(props);
+ Common.assertNotNull(monitor);
+ if (component) {
+ const decorated = component.getDecoratedComponentInstance();
+ if (decorated) {
+ const lifelines = decorated.props.lifelines;
+ if (lifelines) {
+ lifelines.setHoverIndex(decorated.props.index);
+ }
+ }
+ }
+ },
+};
+
+/** DND. */
+function targetCollect(connect, monitor) {
+ return {
+ connectDropTarget: connect.dropTarget(),
+ isOver: monitor.isOver(),
+ };
+}
+
+const wrapper1 = DragSource('lifeline', source, sourceCollect)(Lifeline);
+export default DropTarget(['lifeline', 'lifeline-new'], target, targetCollect)(wrapper1);
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/LifelineNew.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/LifelineNew.jsx
new file mode 100644
index 0000000000..a6e9a70703
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/LifelineNew.jsx
@@ -0,0 +1,112 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+import { DragSource } from 'react-dnd';
+
+import Icon from '../../../../../icons/Icon';
+import iconPlus from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/plus.svg';
+import iconHandle from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/handle.svg';
+
+/**
+ * LHS lifeline row view.
+ */
+class LifelineNew extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+
+ // Bindings.
+
+ this.onClickAdd = this.onClickAdd.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle click event.
+ */
+ onClickAdd() {
+ this.props.designer.addLifeline();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render view.
+ * @returns {*}
+ */
+ render() {
+ const { connectDragSource } = this.props;
+ return connectDragSource(
+ <div className="asdcs-designer-lifeline asdcs-designer-lifeline-new">
+ <table className="asdcs-designer-layout asdcs-designer-lifeline-new">
+ <tbody>
+ <tr>
+ <td>
+ <div className="asdcs-designer-sort asdcs-designer-icon">
+ <Icon glyph={iconHandle} />
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-label" onClick={this.onClickAdd}>
+ Add Lifeline
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-icon" onClick={this.onClickAdd}>
+ <Icon glyph={iconPlus} />
+ </div>
+ </td>
+ <td>&nbsp;</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ );
+ }
+}
+
+/** Element properties. */
+LifelineNew.propTypes = {
+ designer: React.PropTypes.object.isRequired,
+ lifelines: React.PropTypes.object.isRequired,
+ connectDragSource: React.PropTypes.func.isRequired,
+};
+
+/** DND. */
+const source = {
+ beginDrag(props) {
+ return { id: props.id };
+ },
+};
+
+/** DND. */
+const collect = function collection(connect, monitor) {
+ return {
+ connectDragSource: connect.dragSource(),
+ isDragging: monitor.isDragging(),
+ };
+};
+
+export default DragSource('lifeline-new', source, collect)(LifelineNew);
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifelines.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifelines.jsx
new file mode 100644
index 0000000000..2e2f2ee7fd
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifelines.jsx
@@ -0,0 +1,136 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+import Common from '../../../../../../common/Common';
+
+import Lifeline from './Lifeline';
+import LifelineNew from './LifelineNew';
+
+/**
+ * Lifeline container, facilitating DND.
+ * @param props lifeline element properties.
+ * @returns {*}
+ * @constructor
+ */
+export default class Lifelines extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+ this.setHoverIndex = this.setHoverIndex.bind(this);
+ this.getHoverIndex = this.getHoverIndex.bind(this);
+ this.onDrop = this.onDrop.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Record last hover index as non-state.
+ * @param index index.
+ */
+ setHoverIndex(index) {
+ this.hoverIndex = index;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get last recorded hover index.
+ * @returns {*}
+ */
+ getHoverIndex() {
+ return this.hoverIndex;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle drop.
+ * @param dragIndex dragged item index; undefined if new.
+ * @param hoverIndex drop index.
+ */
+ onDrop(dragIndex, hoverIndex) {
+ if (hoverIndex >= 0) {
+ const application = this.props.application;
+ const model = application.getModel();
+ if (Common.isNumber(dragIndex)) {
+ if (dragIndex !== hoverIndex) {
+ model.reorderLifelines(dragIndex, hoverIndex);
+ }
+ } else {
+ model.addLifeline(hoverIndex);
+ }
+ this.forceUpdate();
+ application.renderDiagram();
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render view.
+ * @returns {XML}
+ */
+ render() {
+ const model = this.props.application.getModel();
+ const metamodel = model.getMetamodel();
+ const diagram = model.unwrap().diagram;
+
+ const lifelines = [];
+ for (const lifeline of diagram.lifelines) {
+ lifelines.push(<Lifeline
+ key={`l${lifeline.id}`}
+ application={this.props.application}
+ designer={this.props.designer}
+ lifeline={lifeline}
+ active={this.props.activeLifelineId === lifeline.id}
+ id={lifeline.id}
+ metamodel={metamodel}
+ lifelines={this}
+ index={lifelines.length}
+ />);
+ }
+
+ lifelines.push(<LifelineNew
+ key="_l"
+ designer={this.props.designer}
+ lifelines={this}
+ />);
+
+ return (
+ <div className="asdcs-designer-lifelines">
+ {lifelines}
+ </div>
+ );
+ }
+}
+
+/**
+ * Declare properties.
+ */
+Lifelines.propTypes = {
+ application: React.PropTypes.object.isRequired,
+ designer: React.PropTypes.object.isRequired,
+ activeLifelineId: React.PropTypes.string,
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Message.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Message.jsx
new file mode 100644
index 0000000000..95bff702da
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Message.jsx
@@ -0,0 +1,587 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+import Select from 'react-select';
+import { DragSource, DropTarget } from 'react-dnd';
+
+import Common from '../../../../../../common/Common';
+
+import Icon from '../../../../../icons/Icon';
+import iconDelete from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/delete.svg';
+import iconHandle from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/handle.svg';
+import iconNotes from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/notes.svg';
+import iconSettings from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/settings.svg';
+import iconRequestSync from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/arrow/request-sync.svg';
+import iconRequestAsync from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/arrow/request-async.svg';
+import iconResponse from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/arrow/response.svg';
+
+/**
+ * LHS message row view.
+ */
+class Message extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+
+ this.state = {
+ active: false,
+ name: props.message.name || '',
+ };
+
+ this.combinedOptions = [{
+ value: 'REQUEST_SYNC',
+ }, {
+ value: 'REQUEST_ASYNC',
+ }, {
+ value: 'RESPONSE',
+ }];
+
+ // Bindings.
+
+ this.onChangeName = this.onChangeName.bind(this);
+ this.onBlurName = this.onBlurName.bind(this);
+ this.onChangeType = this.onChangeType.bind(this);
+ this.onChangeFrom = this.onChangeFrom.bind(this);
+ this.onChangeTo = this.onChangeTo.bind(this);
+ this.onClickDelete = this.onClickDelete.bind(this);
+ this.onClickActions = this.onClickActions.bind(this);
+ this.onClickNotes = this.onClickNotes.bind(this);
+ this.onMouseEnter = this.onMouseEnter.bind(this);
+ this.onMouseLeave = this.onMouseLeave.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle name change.
+ * @param event change event.
+ */
+ onChangeName(event) {
+ this.setState({ name: event.target.value });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle name change.
+ * @param event change event.
+ */
+ onBlurName(event) {
+ const options = this.props.application.getOptions();
+ const sanitized = Common.sanitizeText(event.target.value, options, 'message');
+ const props = {
+ id: this.props.message.id,
+ name: sanitized,
+ };
+ this.props.designer.updateMessage(props);
+ this.setState({ name: sanitized });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle delete.
+ */
+ onClickDelete() {
+ this.props.designer.deleteMessage(this.props.message.id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle menu click.
+ */
+ onClickActions(event) {
+ this.props.designer.showActions(this.props.message.id, { x: event.pageX, y: event.pageY });
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle menu click.
+ */
+ onClickNotes() {
+ this.props.designer.showNotes(this.props.message.id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle selection.
+ * @param value selection.
+ */
+ onChangeFrom(value) {
+ if (value.target) {
+ this.updateMessage({ from: value.target.value });
+ } else {
+ this.updateMessage({ from: value.value });
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle selection.
+ * @param value selection.
+ */
+ onChangeTo(value) {
+ if (value.target) {
+ this.updateMessage({ to: value.target.value });
+ } else {
+ this.updateMessage({ to: value.value });
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle selection.
+ * @param selected selection.
+ */
+ onChangeType(selected) {
+
+ const value = selected.target ? selected.target.value : selected.value;
+ const props = {};
+ if (value.indexOf('RESPONSE') !== -1) {
+ props.type = 'response';
+ props.asynchronous = false;
+ } else {
+ props.type = 'request';
+ props.asynchronous = (value.indexOf('ASYNC') !== -1);
+ }
+
+ this.updateMessage(props);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle mouse event.
+ */
+ onMouseEnter() {
+ this.setState({ active: true });
+ this.props.designer.onMouseEnterMessage(this.props.message.id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle mouse event.
+ */
+ onMouseLeave() {
+ this.setState({ active: false });
+ this.props.designer.onMouseLeaveMessage(this.props.message.id);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Update message properties.
+ * @param props properties updates.
+ */
+ updateMessage(props) {
+ const update = {
+ id: this.props.message.id,
+ };
+ for (const k of Object.keys(props)) {
+ update[k] = props[k];
+ }
+ this.props.designer.updateMessage(update);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render icon.
+ * @param option selection.
+ * @returns {XML}
+ */
+ renderOption(option) {
+ if (option.value === 'RESPONSE') {
+ return <Icon glyph={iconResponse} />;
+ }
+ if (option.value === 'REQUEST_ASYNC') {
+ return <Icon glyph={iconRequestAsync} />;
+ }
+ return <Icon glyph={iconRequestSync} />;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get request/response and asynchronous combined constant.
+ * @param message message whose properties define spec.
+ * @returns {*}
+ */
+ getMessageSpec(message) {
+ if (message.type === 'response') {
+ return 'RESPONSE';
+ }
+ if (message.asynchronous) {
+ return 'REQUEST_ASYNC';
+ }
+ return 'REQUEST_SYNC';
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @returns {*}
+ * @private
+ */
+ renderHTMLSelect() {
+
+ const message = this.props.message;
+ const from = this.props.from;
+ const to = Common.assertNotNull(this.props.to);
+ const messageNotesActiveClass = message.notes && message.notes.length > 0 ? 'asdcs-active' : '';
+ const combinedValue = this.getMessageSpec(message);
+
+ const lifelineOptions = [];
+ for (const lifeline of this.props.model.unwrap().diagram.lifelines) {
+ lifelineOptions.push(<option
+ key={lifeline.id}
+ value={lifeline.id}
+ >
+ {lifeline.name}
+ </option>);
+ }
+
+ const activeClass = (this.state.active || this.props.active) ? 'asdcs-active' : '';
+ const { connectDragSource, connectDropTarget } = this.props;
+ return connectDragSource(connectDropTarget(
+ <div
+ className={`asdcs-designer-message ${activeClass}`}
+ data-id={message.id}
+ onMouseEnter={this.onMouseEnter}
+ onMouseLeave={this.onMouseLeave}
+ >
+
+ <table className="asdcs-designer-layout asdcs-designer-message-row1">
+ <tbody>
+ <tr>
+ <td>
+ <div className="asdcs-designer-sort asdcs-designer-icon">
+ <Icon glyph={iconHandle} />
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-message-index">{message.index}.</div>
+ </td>
+ <td>
+ <div className="asdcs-designer-message-name">
+ <input
+ type="text"
+ className="asdcs-editable"
+ value={this.state.name}
+ placeholder="Unnamed"
+ onBlur={this.onBlurName}
+ onChange={this.onChangeName}
+ />
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-actions">
+ <div
+ className="asdcs-designer-settings asdcs-designer-icon"
+ onClick={this.onClickActions}
+ >
+ <Icon glyph={iconSettings} />
+ </div>
+ <div
+ className={`asdcs-designer-notes asdcs-designer-icon ${messageNotesActiveClass}`}
+ onClick={this.onClickNotes}
+ >
+ <Icon glyph={iconNotes} />
+ </div>
+ <div
+ className="asdcs-designer-delete asdcs-designer-icon"
+ onClick={this.onClickDelete}
+ >
+ <Icon glyph={iconDelete} />
+ </div>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <table className="asdcs-designer-layout asdcs-designer-message-row2">
+ <tbody>
+ <tr>
+ <td>
+ <select
+ onChange={this.onChangeFrom}
+ className="asdcs-designer-select-message-from"
+ value={from.id}
+ onChange={this.onChangeFrom}
+ >
+ options={lifelineOptions}
+ </select>
+ </td>
+ <td>
+ <select
+ onChange={this.onChangeFrom}
+ className="asdcs-designer-select-message-type"
+ value={combinedValue}
+ onChange={this.onChangeType}
+ >
+ <option value="REQUEST_SYNC">⇾</option>
+ <option value="REQUEST_ASYNC">→</option>
+ <option value="RESPONSE">⇠</option>
+ </select>
+ </td>
+ <td>
+ <select
+ onChange={this.onChangeFrom}
+ className="asdcs-designer-select-message-to"
+ value={to.id}
+ onChange={this.onChangeTo}
+ >
+ options={lifelineOptions}
+ </select>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+ ));
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render view.
+ * @returns {*}
+ * @private
+ */
+ renderReactSelect() {
+
+ const message = this.props.message;
+ const from = this.props.from;
+ const to = Common.assertNotNull(this.props.to);
+ const messageNotesActiveClass = message.notes && message.notes.length > 0 ? 'asdcs-active' : '';
+ const combinedValue = this.getMessageSpec(message);
+
+ const lifelineOptions = [];
+ for (const lifeline of this.props.model.unwrap().diagram.lifelines) {
+ lifelineOptions.push({
+ value: lifeline.id,
+ label: lifeline.name,
+ });
+ }
+
+ const activeClass = (this.state.active || this.props.active) ? 'asdcs-active' : '';
+ const { connectDragSource, connectDropTarget } = this.props;
+ return connectDragSource(connectDropTarget(
+
+ <div
+ className={`asdcs-designer-message ${activeClass}`}
+ data-id={message.id}
+ onMouseEnter={this.onMouseEnter}
+ onMouseLeave={this.onMouseLeave}
+ >
+
+ <table className="asdcs-designer-layout asdcs-designer-message-row1">
+ <tbody>
+ <tr>
+ <td>
+ <div className="asdcs-designer-sort asdcs-designer-icon">
+ <Icon glyph={iconHandle} />
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-message-index">{message.index}.</div>
+ </td>
+ <td>
+ <div className="asdcs-designer-message-name">
+ <input
+ type="text"
+ className="asdcs-editable"
+ value={this.state.name}
+ placeholder="Unnamed"
+ onBlur={this.onBlurName}
+ onChange={this.onChangeName}
+ />
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-actions">
+ <div
+ className="asdcs-designer-settings asdcs-designer-icon"
+ onClick={this.onClickActions}
+ >
+ <Icon glyph={iconSettings} />
+ </div>
+ <div
+ className={`asdcs-designer-notes asdcs-designer-icon ${messageNotesActiveClass}`}
+ onClick={this.onClickNotes}
+ >
+ <Icon glyph={iconNotes} />
+ </div>
+ <div
+ className="asdcs-designer-delete asdcs-designer-icon"
+ onClick={this.onClickDelete}
+ >
+ <Icon glyph={iconDelete} />
+ </div>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <table className="asdcs-designer-layout asdcs-designer-message-row2">
+ <tbody>
+ <tr>
+ <td>
+ <Select
+ className="asdcs-editable-select asdcs-designer-editable-message-from"
+ openOnFocus
+ clearable={false}
+ searchable={false}
+ value={from.id}
+ onChange={this.onChangeFrom}
+ options={lifelineOptions}
+ />
+ </td>
+ <td>
+ <Select
+ className="asdcs-editable-select asdcs-designer-editable-message-type"
+ openOnFocus
+ clearable={false}
+ searchable={false}
+ value={combinedValue}
+ onChange={this.onChangeType}
+ options={this.combinedOptions}
+ optionRenderer={this.renderOption}
+ valueRenderer={this.renderOption}
+ />
+ </td>
+ <td>
+ <Select
+ className="asdcs-editable-select asdcs-designer-editable-message-to"
+ openOnFocus
+ clearable={false}
+ searchable={false}
+ value={to.id}
+ onChange={this.onChangeTo}
+ options={lifelineOptions}
+ />
+ </td>
+
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+ ));
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ render() {
+ const options = this.props.application.getOptions();
+ if (options.useHtmlSelect) {
+ return this.renderHTMLSelect();
+ }
+ return this.renderReactSelect();
+ }
+}
+
+/**
+ * Declare properties.
+ * @type {{designer: *, message: *, from: *, to: *, model: *, connectDragSource: *}}
+ */
+Message.propTypes = {
+ application: React.PropTypes.object.isRequired,
+ designer: React.PropTypes.object.isRequired,
+ message: React.PropTypes.object.isRequired,
+ active: React.PropTypes.bool.isRequired,
+ from: React.PropTypes.object.isRequired,
+ to: React.PropTypes.object.isRequired,
+ model: React.PropTypes.object.isRequired,
+ index: React.PropTypes.number.isRequired,
+ messages: React.PropTypes.object.isRequired,
+ connectDragSource: React.PropTypes.func.isRequired,
+ connectDropTarget: React.PropTypes.func.isRequired,
+};
+
+/** DND. */
+const source = {
+ beginDrag(props) {
+ return {
+ id: props.id,
+ index: props.index,
+ };
+ },
+};
+
+/** DND. */
+const sourceCollect = function collection(connect, monitor) {
+ return {
+ connectDragSource: connect.dragSource(),
+ isDragging: monitor.isDragging(),
+ };
+};
+
+
+/** DND. */
+const target = {
+ drop(props, monitor, component) {
+ Common.assertNotNull(props);
+ Common.assertNotNull(monitor);
+ const decorated = component.getDecoratedComponentInstance();
+ if (decorated) {
+ const messages = decorated.props.messages;
+ if (messages) {
+ const dragIndex = monitor.getItem().index;
+ const hoverIndex = messages.getHoverIndex();
+ messages.onDrop(dragIndex, hoverIndex);
+ }
+ }
+ },
+ hover(props, monitor, component) {
+ Common.assertNotNull(props);
+ Common.assertNotNull(monitor);
+ if (component) {
+ const decorated = component.getDecoratedComponentInstance();
+ if (decorated) {
+ decorated.props.messages.setHoverIndex(decorated.props.index);
+ }
+ }
+ },
+};
+
+/** DND. */
+function targetCollect(connect, monitor) {
+ return {
+ connectDropTarget: connect.dropTarget(),
+ isOver: monitor.isOver(),
+ };
+}
+
+const wrapper = DragSource('message', source, sourceCollect)(Message);
+export default DropTarget(['message', 'message-new'], target, targetCollect)(wrapper);
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/MessageNew.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/MessageNew.jsx
new file mode 100644
index 0000000000..230cb9fa60
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/MessageNew.jsx
@@ -0,0 +1,106 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+import { DragSource } from 'react-dnd';
+
+import Icon from '../../../../../icons/Icon';
+import iconPlus from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/plus.svg';
+import iconHandle from '../../../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/handle.svg';
+
+/**
+ * LHS lifeline row view.
+ */
+class MessageNew extends React.Component {
+
+ /**
+ * Construct view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+ this.onClickAdd = this.onClickAdd.bind(this);
+ }
+
+ /**
+ * Handle add.
+ */
+ onClickAdd() {
+ this.props.designer.addMessage();
+ }
+
+ /**
+ * Render view.
+ * @returns {*}
+ */
+ render() {
+ const { connectDragSource } = this.props;
+ return connectDragSource(
+ <div className="asdcs-designer-message asdcs-designer-message-new">
+ <table className="asdcs-designer-layout asdcs-designer-message-new">
+ <tbody>
+ <tr>
+ <td>
+ <div className="asdcs-designer-sort asdcs-designer-icon">
+ <Icon glyph={iconHandle} />
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-label" onClick={this.onClickAdd}>
+ Add Message
+ </div>
+ </td>
+ <td>
+ <div className="asdcs-designer-icon" onClick={this.onClickAdd}>
+ <Icon glyph={iconPlus} />
+ </div>
+ </td>
+ <td>
+ &nbsp;
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ );
+ }
+}
+
+/** Element properties. */
+MessageNew.propTypes = {
+ designer: React.PropTypes.object.isRequired,
+ messages: React.PropTypes.object.isRequired,
+ connectDragSource: React.PropTypes.func.isRequired,
+};
+
+/** DND. */
+const source = {
+ beginDrag(props) {
+ return { id: props.id };
+ },
+};
+
+/** DND. */
+const collect = function collection(connect, monitor) {
+ return {
+ connectDragSource: connect.dragSource(),
+ isDragging: monitor.isDragging(),
+ };
+};
+
+export default DragSource('message-new', source, collect)(MessageNew);
+
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Messages.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Messages.jsx
new file mode 100644
index 0000000000..a305a6bd86
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Messages.jsx
@@ -0,0 +1,143 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+import Common from '../../../../../../common/Common';
+
+import Message from './Message';
+import MessageNew from './MessageNew';
+
+/**
+ * Messages container, facilitating DND.
+ * @param props lifeline element properties.
+ * @returns {*}
+ * @constructor
+ */
+export default class Messages extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ };
+ this.setHoverIndex = this.setHoverIndex.bind(this);
+ this.getHoverIndex = this.getHoverIndex.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Record last hover index as non-state.
+ * @param index index.
+ */
+ setHoverIndex(index) {
+ this.hoverIndex = index;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get last recorded hover index.
+ * @returns {*}
+ */
+ getHoverIndex() {
+ return this.hoverIndex;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle drop.
+ * @param dragIndex dragged item index; undefined if new.
+ * @param hoverIndex drop index.
+ */
+ onDrop(dragIndex, hoverIndex) {
+ if (hoverIndex >= 0) {
+ const application = this.props.application;
+ const model = application.getModel();
+ if (Common.isNumber(dragIndex)) {
+ if (dragIndex !== hoverIndex) {
+ model.reorderMessages(dragIndex, hoverIndex);
+ }
+ } else {
+ model.addMessage(hoverIndex);
+ }
+ this.forceUpdate();
+ application.renderDiagram();
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render view.
+ * @returns {*}
+ */
+ render() {
+
+ const model = this.props.application.getModel();
+ const diagram = model.unwrap().diagram;
+
+ // Render existing messages.
+
+ const messages = [];
+ for (const step of diagram.steps) {
+ const message = step.message;
+ const from = model.getLifelineById(message.from);
+ const to = model.getLifelineById(message.to);
+ messages.push(<Message
+ key={`m${message.id}`}
+ application={this.props.application}
+ designer={this.props.designer}
+ message={message}
+ active={this.props.activeMessageId === message.id}
+ from={from}
+ to={to}
+ model={model}
+ index={messages.length}
+ messages={this}
+ />);
+ }
+
+ // Render add.
+
+ messages.push(<MessageNew
+ key="_m"
+ designer={this.props.designer}
+ messages={this}
+ />);
+
+ return (
+ <div className="asdcs-designer-steps">
+ {messages}
+ </div>
+ );
+ }
+}
+
+/** Element properties. */
+Messages.propTypes = {
+ application: React.PropTypes.object.isRequired,
+ designer: React.PropTypes.object.isRequired,
+ activeMessageId: React.PropTypes.string,
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/metadata/Metadata.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/metadata/Metadata.jsx
new file mode 100644
index 0000000000..a17a197ca0
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/metadata/Metadata.jsx
@@ -0,0 +1,34 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+/**
+ * Metadata view.
+ */
+const Metadata = function Metadata(props) {
+ return (
+ <div className="asdcs-designer-metadata">
+ {props.metadata.name}
+ </div>
+ );
+};
+
+Metadata.propTypes = {
+ metadata: React.PropTypes.object.isRequired,
+};
+
+export default Metadata;
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/source/Source.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/source/Source.jsx
new file mode 100644
index 0000000000..3d13d830da
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/source/Source.jsx
@@ -0,0 +1,86 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+/**
+ * Editor view, aggregating the designer, the code editor, the toolbar.
+ */
+export default class Source extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct view.
+ */
+ constructor(props, context) {
+ super(props, context);
+ this.demo = this.props.application.getOptions().demo;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set JSON mode.
+ * @param json JSON (stringified) code.
+ */
+ setJSON(json = '') {
+ if (this.textarea) {
+ this.textarea.value = json;
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set YAML mode.
+ * @param yaml YAML code.
+ */
+ setYAML(yaml = '') {
+ if (this.textarea) {
+ this.textarea.value = yaml;
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ componentDidMount() {
+ /*
+ this.cm = CodeMirror.fromTextArea(this.textarea, {
+ lineNumbers: true,
+ readOnly: true,
+ });
+ */
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render to DOM.
+ */
+ render() {
+ return (
+ <div className="asdcs-editor-code">
+ <textarea ref={(r) => { this.textarea = r; }}></textarea>
+ </div>
+ );
+ }
+}
+
+Source.propTypes = {
+ application: React.PropTypes.object.isRequired,
+};
+
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/toolbar/Toolbar.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/toolbar/Toolbar.jsx
new file mode 100644
index 0000000000..dd75180b2a
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/toolbar/Toolbar.jsx
@@ -0,0 +1,275 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+import Common from '../../../../common/Common';
+
+import iconPlus from '../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/plus.svg';
+import iconOpen from '../../../../../../../../res/ecomp/asdc/sequencer/sprites/icon/open.svg';
+
+/**
+ * Toolbar view. Buttons offered in the toolbar depend on the mode. Unless in demo mode,
+ * all you get are the buttons for toggling between JSON/YAML/Designer.
+ */
+export default class Toolbar extends React.Component {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct view.
+ */
+ constructor(props, context) {
+ super(props, context);
+ this.application = Common.assertType(this.props.application, 'Object');
+ this.editor = Common.assertType(this.props.editor, 'Object');
+ this.mode = 'design';
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set editor mode, one of {design, json, yaml}.
+ * @param mode
+ */
+ setMode(mode = 'design') {
+ this.mode = mode;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Render into the DOM.
+ */
+ render() {
+
+ const demo = this.application.getOptions().demo;
+ const demoCss = demo ? '' : 'asdc-hide';
+
+ return (
+ <div className={`asdcs-editor-toolbar ${demoCss}`}>
+ <div className="asdcs-editor-toolbar-demo">
+ <button className="asdcs-button-new" data-title="New sequence">
+ <svg>
+ <use xlinkHref={iconPlus} className="asdcs-icon" />
+ </svg>
+ </button>
+ <button className="asdcs-button-open" data-title="Open sequence">
+ <svg>
+ <use xlinkHref={iconOpen} className="asdcs-icon" />
+ </svg>
+ </button>
+ <button className="asdcs-button-save" data-title="Save checkpoint">
+ <svg>
+ <use xlinkHref="#icon--save" className="asdcs-icon" />
+ </svg>
+ </button>
+ <button className="asdcs-button-validate" data-title="Validate">
+ <svg>
+ <use xlinkHref="#icon--validate" className="asdcs-icon" />
+ </svg>
+ </button>
+ <button className="asdcs-button-download" data-title="Download">
+ <svg>
+ <use xlinkHref="#icon--download" className="asdcs-icon" />
+ </svg>
+ </button>
+ <button className="asdcs-button-upload" data-title="Upload">
+ <svg>
+ <use xlinkHref="#icon--upload" className="asdcs-icon" />
+ </svg>
+ </button>
+ </div>
+ <div className="asdcs-editor-toolbar-toggle">
+ <button className="asdcs-button-design asdcs-button-mode asdcs-button-toggle-left">
+ Design
+ </button>
+ <button className="asdcs-button-json asdcs-button-mode asdcs-button-toggle-center">
+ JSON
+ </button>
+ <button className="asdcs-button-yaml asdcs-button-mode asdcs-button-toggle-right">
+ YAML
+ </button>
+ </div>
+ </div>
+ );
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Initialize eventhandlers.
+ * @private
+ *
+ _initEvents() {
+
+ $('button.asdcs-button-open', this.$el).click(() => {
+ this._doDemoOpen();
+ });
+
+ $('button.asdcs-button-new', this.$el).click(() => {
+ this._doDemoNew();
+ });
+
+ $('button.asdcs-button-save', this.$el).click(() => {
+ this._doDemoSave();
+ });
+
+ $('button.asdcs-button-upload', this.$el).click(() => {
+ this._doDemoUpload();
+ });
+
+ $('button.asdcs-button-download', this.$el).click(() => {
+ this._doDemoDownload();
+ });
+
+ $('button.asdcs-button-validate', this.$el).click(() => {
+ this._doDemoValidate();
+ });
+
+ $('button.asdcs-button-json', this.$el).click((e) => {
+ if ($(e.target).hasClass('asdcs-active')) {
+ return;
+ }
+ this.editor.toggleToJSON();
+ });
+
+ $('button.asdcs-button-yaml', this.$el).click((e) => {
+ if ($(e.target).hasClass('asdcs-active')) {
+ return;
+ }
+ this.editor.toggleToYAML();
+ });
+
+ $('button.asdcs-button-design', this.$el).click((e) => {
+ if ($(e.target).hasClass('asdcs-active')) {
+ return;
+ }
+ this.editor.toggleToDesign();
+ });
+ }
+ */
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Demo action.
+ *
+ _doDemoOpen() {
+ const complete = function complete() {
+ const sequencer = this.application.getSequencer();
+ const scenarios = sequencer.getDemoScenarios();
+ sequencer.setModel(scenarios.getECOMP());
+ };
+ this.application.showConfirmDialog('[DEMO MODE] Open a canned DEMO sequence ' +
+ 'via the public #setModel() API?', complete);
+
+ }
+ */
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Demo action.
+ *
+ _doDemoNew() {
+ const complete = function complete() {
+ const sequencer = this.application.getSequencer();
+ sequencer.newModel();
+ };
+ this.application.showConfirmDialog('[DEMO MODE] Create an empty sequence via the ' +
+ 'public #newModel() API?', complete);
+ }
+ */
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Demo action.
+ *
+ _doDemoSave() {
+ const sequencer = this.application.getSequencer();
+ Logger.info(`[DEMO MODE] model:\n${JSON.stringify(sequencer.getModel(), null, 4)}`);
+ this.application.showInfoDialog('[DEMO MODE] Retrieved model via the public #getModel ' +
+ 'API and logged its JSON to the console.');
+ }
+ */
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Demo action.
+ *
+ _doDemoUpload() {
+ const sequencer = this.application.getSequencer();
+ const svg = sequencer.getSVG();
+ // console.log(`[DEMO MODE] SVG:\n${svg}`);
+ const $control = this.$el.closest('.asdcs-control');
+ Logger.info(`parent: ${$control.length}`);
+ const $form = $('form.asdcs-export', $control);
+ Logger.info(`form: ${$form.length}`);
+ $('input[name=svg]', $form).val(svg);
+ try {
+ $form.submit();
+ } catch (e) {
+ Logger.error(e);
+ this.application.showErrorDialog('[DEMO MODE] Export service not available. Retrieved ' +
+ 'SVG via the public #getSVG API and dumped it to the console.');
+ }
+ }
+ */
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Demo action.
+ *
+ _doDemoDownload() {
+ const json = JSON.stringify(this.application.getSequencer().getModel());
+ const $control = this.$el.closest('.asdcs-control');
+ const $a = $('<a download="model.json" style="display:none">').appendTo($control);
+ $a.attr('href', `data:application/json;charset=utf-8,${encodeURIComponent(json)}`);
+ $a[0].click();
+ $a.remove();
+ }
+ */
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Demo action.
+ *
+ _doDemoValidate() {
+ this.application.showInfoDialog('[DEMO MODE] Dumping validation result to the console.');
+ const errors = this.application.getModel().validate();
+ Logger.info(`[DEMO MODE] Validation: ${JSON.stringify(errors, null, 4)}`);
+ }
+ */
+}
+
+Toolbar.propTypes = {
+ application: React.PropTypes.object.isRequired,
+ editor: React.PropTypes.object.isRequired,
+};
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/export/Export.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/export/Export.jsx
new file mode 100644
index 0000000000..529ae92ded
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/export/Export.jsx
@@ -0,0 +1,31 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+const Export = function Export() {
+ return (
+ <form className="asdcs-export" action="/ossui-svg/services/ossui/svg/export" method="post">
+ <input name="svg" type="hidden" value="" />
+ <input name="css" type="hidden" value="sdc/sequencer/default" />
+ <input name="type" type="hidden" value="PDF" />
+ <input name="height" type="hidden" value="1920" />
+ <input name="width" type="hidden" value="1080" />
+ </form>
+ );
+};
+
+export default Export;
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/icons/Icon.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/icons/Icon.jsx
new file mode 100644
index 0000000000..6bc04f997f
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/icons/Icon.jsx
@@ -0,0 +1,41 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+/**
+ * Simple icon view.
+ * @param glyph glyph definition, from import.
+ * @param className optional classname, for svg element.
+ * @returns {XML}
+ * @constructor
+ */
+const Icon = function Icon({ glyph, className }) {
+ return (
+ <svg viewBox="0 0 1000 1000" className={className} >
+ <use xlinkHref={glyph} className="asdcs-icon" />
+ </svg>
+ );
+};
+
+/** Declare properties. */
+Icon.propTypes = {
+ className: React.PropTypes.string,
+ glyph: React.PropTypes.string.isRequired,
+};
+
+export default Icon;
+
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/overlay/Overlay.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/overlay/Overlay.jsx
new file mode 100644
index 0000000000..817f4f1697
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/overlay/Overlay.jsx
@@ -0,0 +1,61 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+
+/**
+ * Overlay view.
+ */
+export default class Overlay extends React.Component {
+
+ /**
+ * Construct view.
+ * @param props element properties.
+ * @param context react context.
+ */
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ visible: false,
+ };
+ this.setVisible = this.setVisible.bind(this);
+ }
+
+ /**
+ * Set visibility.
+ * @param visible true if visible.
+ */
+ setVisible(visible) {
+ this.setState({
+ visible,
+ });
+ }
+
+ /**
+ * Render view.
+ * @returns {XML}
+ */
+ render() {
+ const display = this.state.visible ? 'block' : 'none';
+ return (
+ <div
+ className="asdcs-overlay"
+ style={{ display }}
+ >
+ </div>
+ );
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodel.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodel.js
new file mode 100644
index 0000000000..82e8ada588
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodel.js
@@ -0,0 +1,94 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import _merge from 'lodash/merge';
+
+import Common from '../common/Common';
+
+/**
+ * Rules governing what a definition can contain.
+ */
+export default class Metamodel {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct from JSON definition.
+ * @param json schema definition.
+ */
+ constructor(json) {
+ Common.assertType(json, 'Object');
+ const dfault = require('./templates/default.metamodel.json');
+ this.json = _merge({}, dfault, json);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get schema identifier.
+ * @returns ID.
+ */
+ getId() {
+ return this.json.diagram.metadata.id;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get lifeline constraints.
+ * @returns {*}
+ */
+ getConstraints() {
+ return this.json.diagram.lifelines.constraints;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get lifeline metadata by lifeline ID.
+ * @param id sought lifeline.
+ * @returns lifeline if found.
+ */
+ getLifelineById(id) {
+ for (const lifeline of this.json.diagram.lifelines.lifelines) {
+ if (lifeline.id === id) {
+ return lifeline;
+ }
+ }
+ return undefined;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get original JSON.
+ * @returns JSON.
+ */
+ unwrap() {
+ return this.json;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get default schema.
+ * @returns Metamodel default (permissive) Metamodel.
+ */
+ static getDefault() {
+ return new Metamodel({});
+ }
+
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodels.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodels.js
new file mode 100644
index 0000000000..4ecfc0b5f7
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodels.js
@@ -0,0 +1,87 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import Common from '../common/Common';
+import Metamodel from './Metamodel';
+
+/**
+ * A simple lookup for schemas by ID.
+ */
+export default class Metamodels {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct metamodels from provided JSON definitions.
+ * @param metamodels JSON metamodel definitions.
+ */
+ constructor(metamodels) {
+
+ Common.assertType(metamodels, 'Array');
+
+ this.lookup = {};
+
+ // Save each metamodel. It's up to the Metamodel class to make sense of
+ // potentially nonsense metamodel definitions.
+
+ for (const json of metamodels) {
+ const metamodel = new Metamodel(json);
+ this.lookup[metamodel.getId()] = metamodel;
+ }
+
+ // Set (or override) the default metamodel with the inlined one.
+
+ this.lookup.$ = Metamodel.getDefault();
+ Common.assertInstanceOf(this.lookup.$, Metamodel);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get Metamodel by its @id.
+ * @param id identifier.
+ * @returns Metamodel, or undefined if no matching metamodel found.
+ */
+ getMetamodel(id) {
+ return this.lookup[id];
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get the default (permissive) metamodel.
+ * @returns default Metamodel.
+ */
+ getDefault() {
+ return this.lookup.$;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get metamodel by its @id, falling back to the default.
+ * @param id identifier.
+ * @returns matching metamodel, or default.
+ */
+ getMetamodelOrDefault(id) {
+ const metamodel = this.getMetamodel(id);
+ if (metamodel) {
+ return metamodel;
+ }
+ return this.getDefault();
+ }
+
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Model.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Model.js
new file mode 100644
index 0000000000..1e68cd6034
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Model.js
@@ -0,0 +1,512 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import _merge from 'lodash/merge';
+// import jsonschema from 'jsonschema';
+
+import Common from '../common/Common';
+import Metamodel from './Metamodel';
+
+/**
+ * A wrapper for a model instance.
+ */
+export default class Model {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct model from model JSON. JSON is assumed to be in more or less
+ * the correct structure, but it's OK if it's missing IDs.
+ *
+ * @param json initial JSON; will be updated in situ.
+ * @param metamodel Metaobject definition.
+ */
+ constructor(json, metamodel) {
+
+ if (metamodel) {
+ Common.assertInstanceOf(metamodel, Metamodel);
+ }
+
+ this.metamodel = metamodel || Metamodel.getDefault();
+ Common.assertInstanceOf(this.metamodel, Metamodel);
+
+ this.jsonschema = require('./schema/asdc_sequencer_schema.json');
+ this.templates = {
+ defaultModel: require('./templates/default.model.json'),
+ defaultMetamodel: require('./templates/default.metamodel.json'),
+ };
+
+ this.model = this._preprocess(Common.assertType(json, 'Object'));
+ Common.assertPlainObject(this.model);
+
+ this.renumber();
+
+ this.addLifeline = this.addLifeline.bind(this);
+ this.addMessage = this.addMessage.bind(this);
+ this.renumber = this.renumber.bind(this);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Unwrap to get model object.
+ * @returns {*}
+ */
+ unwrap() {
+ return Common.assertPlainObject(this.model);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get the metamodel which defines valid states for this model.
+ * @returns Metamodel definition.
+ */
+ getMetamodel() {
+ return Common.assertInstanceOf(this.metamodel, Metamodel);
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Find lifeline by its ID.
+ * @param id lifeline ID.
+ * @returns lifeline object, if found.
+ */
+ getLifelineById(id) {
+ for (const lifeline of this.model.diagram.lifelines) {
+ if (lifeline.id === id) {
+ return lifeline;
+ }
+ }
+ return undefined;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get message by ID.
+ * @param id message ID.
+ * @returns message if matched.
+ */
+ getMessageById(id) {
+ Common.assertNotNull(id);
+ const step = this.getStepByMessageId(id);
+ if (step) {
+ return step.message;
+ }
+ return undefined;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get step by message ID.
+ * @param id step ID.
+ * @returns step if matched.
+ */
+ getStepByMessageId(id) {
+ Common.assertNotNull(id);
+ for (const step of this.model.diagram.steps) {
+ if (step.message && step.message.id === id) {
+ return step;
+ }
+ }
+ return undefined;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Add message to steps.
+ * @returns {{}}
+ */
+ addMessage(index) {
+ const d = this.model.diagram;
+ const step = {};
+ step.message = {};
+ step.message.id = Model._guid();
+ step.message.name = '[Unnamed Message]';
+ step.message.type = 'request';
+ step.message.from = d.lifelines.length > 0 ? d.lifelines[0].id : -1;
+ step.message.to = d.lifelines.length > 1 ? d.lifelines[1].id : -1;
+ if (index >= 0) {
+ d.steps.splice(index, 0, step);
+ } else {
+ d.steps.push(step);
+ }
+ this.renumber();
+ return step;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Delete message with ID.
+ * @param id to be deleted.
+ */
+ deleteMessageById(id) {
+ Common.assertNotNull(id);
+ const step = this.getStepByMessageId(id);
+ if (step) {
+ const index = this.model.diagram.steps.indexOf(step);
+ if (index !== -1) {
+ this.model.diagram.steps.splice(index, 1);
+ }
+ }
+ this.renumber();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Add lifeline to lifelines.
+ * @param index optional index.
+ * @returns {{}}
+ */
+ addLifeline(index) {
+ const lifeline = {};
+ lifeline.id = Model._guid();
+ lifeline.name = '[Unnamed Lifeline]';
+ if (index >= 0) {
+ this.model.diagram.lifelines.splice(index, 0, lifeline);
+ } else {
+ this.model.diagram.lifelines.push(lifeline);
+ }
+ this.renumber();
+ return lifeline;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Delete lifeline with ID.
+ * @param id to be deleted.
+ */
+ deleteLifelineById(id) {
+ Common.assertNotNull(id);
+ this.deleteStepsByLifelineId(id);
+ const lifeline = this.getLifelineById(id);
+ if (lifeline) {
+ const index = this.model.diagram.lifelines.indexOf(lifeline);
+ if (index !== -1) {
+ this.model.diagram.lifelines.splice(index, 1);
+ }
+ }
+ this.renumber();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Delete all steps corresponding to lifeline.
+ * @param id lifeline ID.
+ */
+ deleteStepsByLifelineId(id) {
+ Common.assertNotNull(id);
+ const steps = this.getStepsByLifelineId(id);
+ for (const step of steps) {
+ this.deleteMessageById(step.message.id);
+ }
+ this.renumber();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get all steps corresponding to lifeline.
+ * @param id lifeline ID.
+ * @return steps from/to lifeline.
+ */
+ getStepsByLifelineId(id) {
+ Common.assertNotNull(id);
+ const steps = [];
+ for (const step of this.model.diagram.steps) {
+ if (step.message) {
+ if (step.message.from === id || step.message.to === id) {
+ steps.push(step);
+ }
+ }
+ }
+ return steps;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Validate model. Disabled, because we removed the jsonschema dependency.
+ * @returns {Array} of validation errors, if any.
+ */
+ validate() {
+ const errors = [];
+ return errors;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Reorder messages.
+ * @param index message index.
+ * @param afterIndex new (after) index.
+ */
+ reorderMessages(index, afterIndex) {
+ Common.assertType(index, 'Number');
+ Common.assertType(afterIndex, 'Number');
+ const steps = this.model.diagram.steps;
+ const element = steps[index];
+ steps.splice(index, 1);
+ steps.splice(afterIndex, 0, element);
+ this.renumber();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Reorder lifelines.
+ * @param index lifeline index.
+ * @param afterIndex new (after) index.
+ */
+ reorderLifelines(index, afterIndex) {
+ Common.assertType(index, 'Number');
+ Common.assertType(afterIndex, 'Number');
+ const lifelines = this.model.diagram.lifelines;
+ const element = lifelines[index];
+ lifelines.splice(index, 1);
+ lifelines.splice(afterIndex, 0, element);
+ this.renumber();
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Renumber lifelines and messages.
+ */
+ renumber() {
+ const modelJSON = this.unwrap();
+ let stepIndex = 1;
+ let lifelineIndex = 1;
+ for (const step of modelJSON.diagram.steps) {
+ if (step.message) {
+ step.message.index = stepIndex++;
+ }
+ }
+ for (const lifeline of modelJSON.diagram.lifelines) {
+ lifeline.index = lifelineIndex++;
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Build a simple, navigable dataset describing fragments.
+ * @returns {{}}, indexed by (stop) message ID, describing fragments.
+ */
+ analyzeFragments() {
+
+ const fData = {};
+
+ let depth = 0;
+ const modelJSON = this.unwrap();
+ const open = [];
+
+ const getData = function g(stop, fragment) {
+ let data = fData[stop];
+ if (!data) {
+ data = { stop, start: [], fragment };
+ fData[stop] = data;
+ }
+ return data;
+ };
+
+ const fragmentsByStart = {};
+ for (const step of modelJSON.diagram.steps) {
+ if (step.message && step.message.fragment) {
+ const message = step.message;
+ const fragment = message.fragment;
+ if (fragment.start) {
+ fragmentsByStart[fragment.start] = fragment;
+ open.push(message.id);
+ depth++;
+ }
+ if (fragment.stop) {
+ if (open.length > 0) {
+ getData(message.id).start.push(open.pop());
+ }
+ depth = Math.max(depth - 1, 0);
+ }
+ }
+ }
+
+ if (open.length > 0) {
+ for (const o of open) {
+ getData(o, fragmentsByStart[o]).start.push(o);
+ }
+ }
+
+ return fData;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Build a simple, navigable dataset describing occurrences.
+ * @returns a map, indexed by lifeline ID, of objects containing {start:[],stop:[],active[]}.
+ * @private
+ */
+ analyzeOccurrences() {
+
+ const oData = {};
+
+ // A few inline functions. They make this method kinda lengthy, but they
+ // reduce clutter in the class and keep it coherent, so it's OK.
+
+ const getDataByLifelineId = function get(lifelineId) {
+ if (!oData[lifelineId]) {
+ oData[lifelineId] = { active: [], start: {}, stop: {} };
+ }
+ return oData[lifelineId];
+ };
+
+ const contains = function contains(array, value) {
+ return (array && (array.indexOf(value) !== -1));
+ };
+
+ const process = function process(message, lifelineId) {
+ const oRule = message.occurrences;
+ if (oRule) {
+
+ const oDataLifeline = getDataByLifelineId(lifelineId);
+ if (oDataLifeline) {
+
+ // Record all starts.
+
+ if (contains(oRule.start, lifelineId)) {
+ oDataLifeline.active.push(message.id);
+ oDataLifeline.start[message.id] = undefined;
+ }
+
+ // Reconcile with stops.
+
+ if (contains(oRule.stop, lifelineId)) {
+ const startMessageId = oDataLifeline.active.pop();
+ oDataLifeline.stop[message.id] = startMessageId;
+ if (startMessageId) {
+ oDataLifeline.start[startMessageId] = message.id;
+ }
+ }
+ }
+ }
+ };
+
+ // Analyze start and end.
+
+ const modelJSON = this.unwrap();
+ for (const step of modelJSON.diagram.steps) {
+ if (step.message) {
+ const message = step.message;
+ if (message.occurrences) {
+ process(message, message.from);
+ process(message, message.to);
+ }
+ }
+ }
+
+ // Reset active. (We used it, but it's not actually for us; it's for keeping
+ // track of active occurrences when rendering the diagram.)
+
+ for (const lifelineId of Object.keys(oData)) {
+ oData[lifelineId].active = [];
+ }
+
+ // Reconcile the start and end (message ID) maps for each lifeline,
+ // finding a "stop" for every start. Default to starting and stopping
+ // on the same message, which is the same as no occurrence.
+
+ for (const lifelineId of Object.keys(oData)) {
+ const lifelineData = oData[lifelineId];
+ for (const startId of Object.keys(lifelineData.start)) {
+ const stopId = lifelineData.start[startId];
+ if (!stopId) {
+ lifelineData.start[startId] = startId;
+ lifelineData.stop[startId] = startId;
+ }
+ }
+ }
+
+ return oData;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Preprocess model, adding IDs and whatnot.
+ * @param original to be preprocessed.
+ * @returns preprocessed JSON.
+ * @private
+ */
+ _preprocess(original) {
+
+ const json = _merge({}, this.templates.defaultModel, original);
+ const metamodel = this.metamodel.unwrap();
+ if (!json.diagram.metadata.ref) {
+ if (metamodel.diagram.metadata.id) {
+ json.diagram.metadata.ref = metamodel.diagram.metadata.id;
+ } else {
+ json.diagram.metadata.ref = '$';
+ }
+ }
+
+ for (const lifeline of json.diagram.lifelines) {
+ lifeline.id = lifeline.id || lifeline.name;
+ }
+
+ for (const step of json.diagram.steps) {
+ if (step.message) {
+ step.message.id = step.message.id || Model._guid();
+ const occurrences = step.message.occurrences;
+ if (occurrences) {
+ occurrences.start = occurrences.start || [];
+ occurrences.stop = occurrences.stop || [];
+ }
+ }
+ }
+
+ if (!json.diagram.metadata.id || json.diagram.metadata.id === '$') {
+ json.diagram.metadata.id = Model._guid();
+ }
+
+ return json;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Create pseudo-UUID.
+ * @returns {string}
+ * @private
+ */
+ static _guid() {
+ function s4() {
+ return Math.floor((1 + Math.random()) * 0x10000)
+ .toString(16)
+ .substring(1);
+ }
+ return `${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}`;
+ }
+
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/Scenarios.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/Scenarios.js
new file mode 100644
index 0000000000..4130ec7ec3
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/Scenarios.js
@@ -0,0 +1,110 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+/**
+ * Example scenarios, for development, testing and demos.
+ */
+export default class Scenarios {
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct scenarios; read model and metamodel templates.
+ */
+ constructor() {
+ this.templates = {
+ model: {
+ ecomp: require('./model/ECOMP.json'),
+ blank: require('./model/BLANK.json'),
+ dimensions: require('./model/DIMENSIONS.json'),
+ },
+ metamodel: {
+ ecomp: require('./metamodel/ECOMP.json'),
+ blank: require('./metamodel/BLANK.json'),
+ },
+ };
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get ECOMP scenario.
+ * @return ECOMP scenario JSON.
+ */
+ getECOMP() {
+ return JSON.parse(JSON.stringify(this.templates.model.ecomp));
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get ECOMP scenario metamodel.
+ * @return scenario metamodel JSON.
+ */
+ getECOMPMetamodel() {
+ return JSON.parse(JSON.stringify(this.templates.metamodel.ecomp));
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get blank scenario.
+ * @return blank scenario JSON.
+ */
+ getBlank() {
+ return JSON.parse(JSON.stringify(this.templates.model.blank));
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get empty scenario metamodel.
+ * @return empty metamodel JSON.
+ */
+ getBlankMetamodel() {
+ return JSON.parse(JSON.stringify(this.templates.metamodel.blank));
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get scenario.
+ * @return scenario JSON.
+ */
+ getDimensions() {
+ return JSON.parse(JSON.stringify(this.templates.model.dimensions));
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get scenario metamodel.
+ * @return metamodel JSON.
+ */
+ getDimensionsMetamodel() {
+ return JSON.parse(JSON.stringify(this.templates.metamodel.blank));
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Get demo metamodels.
+ * @returns {*[]}
+ */
+ getMetamodels() {
+ return [this.getBlankMetamodel(), this.getDimensionsMetamodel(), this.getECOMPMetamodel()];
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/BLANK.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/BLANK.json
new file mode 100644
index 0000000000..2853405883
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/BLANK.json
@@ -0,0 +1,16 @@
+{
+ "diagram": {
+ "metadata": {
+ "id": "BLANK",
+ "name": "Blank"
+ },
+ "lifelines": {
+ "lifelines": [],
+ "constraints": {
+ "create": true,
+ "delete": true,
+ "reorder": true
+ }
+ }
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/DIMENSIONS.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/DIMENSIONS.json
new file mode 100644
index 0000000000..f02111d0f3
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/DIMENSIONS.json
@@ -0,0 +1,16 @@
+{
+ "diagram": {
+ "metadata": {
+ "id": "DIMENSIONS",
+ "name": "Dimensions"
+ },
+ "lifelines": {
+ "lifelines": [],
+ "constraints": {
+ "create": true,
+ "delete": true,
+ "reorder": true
+ }
+ }
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/ECOMP.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/ECOMP.json
new file mode 100644
index 0000000000..939c1398b5
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/metamodel/ECOMP.json
@@ -0,0 +1,62 @@
+{
+ "diagram": {
+ "metadata": {
+ "id": "ECOMP",
+ "name": "ECOMP"
+
+ },
+ "lifelines": {
+ "lifelines": [{
+ "id": "1",
+ "name": "Customer"
+ }, {
+ "id": "2",
+ "name": "MSO"
+ }, {
+ "id": "3",
+ "name": "SDN"
+ }, {
+ "id": "4",
+ "name": "A&AI"
+ }, {
+ "id": "5",
+ "name": "IPE TOR"
+ }, {
+ "id": "6",
+ "name": "ORM"
+ }, {
+ "id": "7",
+ "name": "ORD"
+ }, {
+ "id": "8",
+ "name": "Heat"
+ }, {
+ "id": "9",
+ "name": "NovaAPI"
+ }, {
+ "id": "10",
+ "name": "Ntrn Contrl"
+ }, {
+ "id": "11",
+ "name": "RO"
+ }, {
+ "id": "12",
+ "name": "Nova Agent"
+ }, {
+ "id": "13",
+ "name": "VF Agent"
+ }, {
+ "id": "14",
+ "name": "Hypervisor"
+ }, {
+ "id": "15",
+ "name": "VF"
+ }],
+ "constraints": {
+ "create": true,
+ "delete": true,
+ "reorder": true
+ }
+ }
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/BLANK.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/BLANK.json
new file mode 100644
index 0000000000..784a80e820
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/BLANK.json
@@ -0,0 +1,37 @@
+{
+ "diagram": {
+ "metadata": {
+ "id": "$",
+ "ref": "BLANK",
+ "name": "New Sequence"
+ },
+ "lifelines": [
+ {
+ "id": "Alice",
+ "name": "Alice"
+ },
+ {
+ "id": "Bob",
+ "name": "Bob"
+ }
+ ],
+ "steps": [
+ {
+ "message": {
+ "from": "Alice",
+ "to": "Bob",
+ "label": "Sup Bob",
+ "type": "request"
+ }
+ },
+ {
+ "message": {
+ "from": "Bob",
+ "to": "Alice",
+ "label": "Yo Alice",
+ "type": "response"
+ }
+ }
+ ]
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/DIMENSIONS.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/DIMENSIONS.json
new file mode 100644
index 0000000000..642e34a785
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/DIMENSIONS.json
@@ -0,0 +1,91 @@
+{
+ "diagram": {
+ "metadata": {
+ "id": "DIMENSIONS1",
+ "name": "Dimensions Test",
+ "ref": "DIMENSIONS"
+ },
+ "lifelines": [
+ {
+ "id": "L01",
+ "name": "Lorum Ipsum"
+ },
+ {
+ "id": "L02",
+ "name": "Donec nisi urna, porttitor efficitur felis vel, efficitur consequat nunc"
+ },
+ {
+ "id": "L03",
+ "name": "Mauris dignissim SphymomanometerSphymomanometer enim non sapien tristique lacinia"
+ }
+ ],
+ "steps": [
+ {
+ "message": {
+ "id": "M01",
+ "from": "L01",
+ "to": "L02",
+ "name": "Morbi",
+ "type": "request",
+ "notes": [
+ "Proin non libero malesuada."
+ ],
+ "fragment": {
+ "operator": "alt",
+ "start": true,
+ "guard": "Curabitur sollicitudin nulla elit, et ultrices tortor faucibus quis"
+ },
+ "occurrences": {
+ "start": ["L01", "L02"],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M02",
+ "from": "L02",
+ "to": "L03",
+ "name": "Quisque pretium tellus sit amet congue dictum. Mauris ac rutrum arcu, et fringilla orci",
+ "type": "request",
+ "notes": [
+ "Nam quis felis hendrerit, lacinia ipsum vitae, faucibus elit. Morbi sit amet nunc eget massa vehicula rhoncus sit amet vel tellus. Aliquam accumsan eros elit, et sollicitudin lacus vehicula eu. Aenean rhoncus justo ut felis tincidunt, sit amet vulputate metus aliquet. Phasellus tellus est, consequat nec ex mollis, lacinia vestibulum justo. Nam quis felis hendrerit, lacinia ipsum vitae, faucibus elit. Morbi sit amet nunc eget massa vehicula rhoncus sit amet vel tellus. Aliquam accumsan eros elit, et sollicitudin lacus vehicula eu. Aenean rhoncus justo ut felis tincidunt, sit amet vulputate metus aliquet. Phasellus tellus est, consequat nec ex mollis, lacinia vestibulum justo."
+ ],
+ "occurrences": {
+ "start": [],
+ "stop": ["L02"]
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M03",
+ "from": "L01",
+ "to": "L03",
+ "name": "Nullam",
+ "type": "response",
+ "fragment": {
+ "stop": true
+ },
+ "occurrences": {
+ "start": [],
+ "stop": ["L01"]
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M04",
+ "from": "L01",
+ "to": "L03",
+ "name": "Etiam convallis augue est. ",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/ECOMP.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/ECOMP.json
new file mode 100644
index 0000000000..dd9bfc5eb0
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/model/ECOMP.json
@@ -0,0 +1,514 @@
+{
+ "diagram": {
+ "metadata": {
+ "id": "ECOMP1",
+ "name": "Detailed flow in Ecomp1",
+ "ref": "ECOMP"
+ },
+ "lifelines": [
+ {
+ "id": "L01",
+ "name": "Customer"
+ },
+ {
+ "id": "L02",
+ "name": "MSO"
+ },
+ {
+ "id": "L03",
+ "name": "SDN"
+ },
+ {
+ "id": "L04",
+ "name": "A&AI"
+ },
+ {
+ "id": "L05",
+ "name": "IPE TOR"
+ },
+ {
+ "id": "L06",
+ "name": "ORM"
+ },
+ {
+ "id": "L07",
+ "name": "ORD"
+ },
+ {
+ "id": "L08",
+ "name": "Heat"
+ },
+ {
+ "id": "L09",
+ "name": "NovaAPI"
+ },
+ {
+ "id": "L10",
+ "name": "Ntrn Contrl"
+ },
+ {
+ "id": "L11",
+ "name": "RO"
+ },
+ {
+ "id": "L12",
+ "name": "Nova Agent"
+ },
+ {
+ "id": "L13",
+ "name": "VF Agent"
+ },
+ {
+ "id": "L14",
+ "name": "Hypervisor"
+ },
+ {
+ "id": "L15",
+ "name": "VF"
+ }
+ ],
+ "steps": [
+ {
+ "message": {
+ "id": "M01",
+ "from": "L01",
+ "to": "L02",
+ "name": "Create",
+ "type": "request",
+ "notes": [
+ "This note is short."
+ ],
+ "occurrences": {
+ "start": ["L01", "L02"],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M02",
+ "from": "L02",
+ "to": "L04",
+ "name": "Check Tenant",
+ "type": "request",
+ "occurrences": {
+ "start": ["L02"],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M03",
+ "from": "L02",
+ "to": "L06",
+ "name": "Create Tenant",
+ "type": "request",
+ "fragment": {
+ "operator": "alt",
+ "start": true,
+ "guard": "Does not exist"
+ },
+ "occurrences": {
+ "start": ["L06"],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M04",
+ "from": "L06",
+ "to": "L07",
+ "name": "Distribute",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M05",
+ "from": "L06",
+ "to": "L02",
+ "name": "Async Response",
+ "type": "response",
+ "asynchronous": true,
+ "fragment": {
+ "stop": true
+ },
+ "occurrences": {
+ "start": [],
+ "stop": ["L02", "L06"]
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M06",
+ "from": "L07",
+ "to": "L08",
+ "name": "Push",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M07",
+ "from": "L08",
+ "to": "L02",
+ "name": "Tenant Complete",
+ "type": "response",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M08",
+ "from": "L02",
+ "to": "L03",
+ "name": "Service Topology",
+ "type": "request",
+ "occurrences": {
+ "start": ["L03"],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M09",
+ "from": "L03",
+ "to": "L05",
+ "name": "Pre-configs",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M10",
+ "from": "L03",
+ "to": "L04",
+ "name": "Retrieve and populate",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": ["L03"]
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M11",
+ "from": "L02",
+ "to": "L08",
+ "name": "VNF PreRequisite Heat Template",
+ "type": "request",
+ "notes": [
+ "I got up and made coffee and read my emails and answered them until I got frustrated and made a mental note to answer the others later and then looked out of the window for a while and then made more coffee."
+ ],
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M12",
+ "from": "L08",
+ "to": "L10",
+ "name": "Provider and OAM nw",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M13",
+ "from": "L02",
+ "to": "L08",
+ "name": "Get Stack Status",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M14",
+ "from": "L08",
+ "to": "L02",
+ "name": "Status complete",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M15",
+ "from": "L11",
+ "to": "L04",
+ "name": "Provider and OAM Inventory",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M16",
+ "from": "L02",
+ "to": "L08",
+ "name": "VNF Server Heat Template",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M17",
+ "from": "L08",
+ "to": "L10",
+ "name": "Show Port",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M18",
+ "from": "L11",
+ "to": "L02",
+ "name": "Async Response with Stack ID",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M19",
+ "from": "L10",
+ "to": "L08",
+ "name": "Response",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M20",
+ "from": "L08",
+ "to": "L09",
+ "name": "Nova VM",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M21",
+ "from": "L09",
+ "to": "L12",
+ "name": "Scheduler Picks Nova Agent",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M22",
+ "from": "L12",
+ "to": "L14",
+ "name": "Picks VF",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M23",
+ "from": "L12",
+ "to": "L10",
+ "name": "Retrieves Port Info",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M24",
+ "from": "L12",
+ "to": "L13",
+ "name": "Calls CF Agent",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M25",
+ "from": "L13",
+ "to": "L15",
+ "name": "Configure VF",
+ "type": "response",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M26",
+ "from": "L15",
+ "to": "L13",
+ "name": "Response",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M27",
+ "from": "L13",
+ "to": "L12",
+ "name": "Complete",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M28",
+ "from": "L12",
+ "to": "L08",
+ "name": "Response Complete",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M29",
+ "from": "L11",
+ "to": "L04",
+ "name": "VServer and Show Port Inventory",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M30",
+ "from": "L02",
+ "to": "L08",
+ "name": "Get Stack Status",
+ "type": "request",
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M31",
+ "from": "L08",
+ "to": "L02",
+ "name": "Stack Status Complete",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": []
+ }
+ }
+ },
+ {
+ "message": {
+ "id": "M32",
+ "from": "L02",
+ "to": "L01",
+ "name": "Done",
+ "type": "response",
+ "asynchronous": true,
+ "occurrences": {
+ "start": [],
+ "stop": ["L01", "L02"]
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc-sequencer-meta-schema.xsd b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc-sequencer-meta-schema.xsd
new file mode 100644
index 0000000000..f75063bed5
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc-sequencer-meta-schema.xsd
@@ -0,0 +1,166 @@
+<xs:schema
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://ns.ecomp.com/asdc/sequencer"
+ xmlns:s="http://ns.ecomp.com/asdc/sequencer"
+ attributeFormDefault="unqualified"
+ elementFormDefault="unqualified">
+
+ <!--
+
+ https://github.com/highsource/jsonix-schema-compiler/wiki/JSON-Schema-Generation
+
+ npm install -x-save-dev json-schema-generation
+
+ java -jar node_modules/jsonix-schema-compiler/lib/jsonix-schema-compiler-full.jar \
+ -generateJsonSchema \
+ -d ./src/main/webapp/lib/ecomp/asdc/sequencer/schema/ \
+ -p asdc_sequencer_schema \
+ ./src/main/webapp/lib/ecomp/asdc/sequencer/schema/asdc-sequencer-meta-schema.xsd
+
+ -->
+
+ <xs:element name="diagram">
+ <xs:annotation>
+ <xs:documentation>
+
+ Diagram meta-schema, defining what diagram documents may look like.
+
+ The main difference between the metaschema (this) and the schema, is that
+ the metaschema describes what's *allowed* rather than what *is*.
+
+ Specific differences:
+
+ 1. The metaschema exists primarily to constrain lifelines; to declare any
+ that are predefined, to prescribe cardinality, order and whether or not
+ ad hoc lifelines may be created by the user.
+ 2. The metaschema doesn't constrain messages at all. This may come along later,
+ but for now they're freetext, and can be defined between any legal pair
+ of lifelines.
+ 3. The metaschema doesn't have @ref attributes; its @id attributes are the
+ target of @ref attributes in the instance schema.m
+
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="metadata" type="s:metadataType"/>
+ <xs:element name="lifelines" type="s:lifelinesType"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="entityType" abstract="true">
+ <xs:annotation>
+ <xs:documentation>
+ Common attributes, most importantly @id, which every entity must have.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="notes" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="note" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="id" use="required" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ Schema definition identifier.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" use="required" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ Human-readable name.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="metadataType">
+ <xs:annotation>
+ <xs:documentation>
+ Diagram metadata, including:
+ - Unique ID, referenced by @ref attributes in instance documents.
+ - Human-readable description, displayed on-screen.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="s:entityType"/>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="lifelineType">
+ <xs:annotation>
+ <xs:documentation>
+ Metadata concerning a single lifeline.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="s:entityType">
+ <xs:attribute name="mandatory" type="xs:boolean" use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>
+ Whether an instance may omit this lifeline. Only takes effect
+ where the lifelines setting is @delete=true.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="lifelinesType">
+ <xs:annotation>
+ <xs:documentation>
+ Metadata concerning allowed lifelines. Somewhat more strict that
+ instance data.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="s:entityType">
+ <xs:sequence>
+ <xs:element name="lifeline" type="s:lifelineType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="constraints">
+ <xs:complexType>
+ <xs:attribute name="create" type="xs:boolean" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ Whether the user may create their own lifelines.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="delete" type="xs:boolean" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ Whether declared lifelines may be deleted.
+ See also @mandatory on lifeline.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="reorder" type="xs:boolean" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ Whether lifelines may be reordered.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+</xs:schema>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc-sequencer-schema.xsd b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc-sequencer-schema.xsd
new file mode 100644
index 0000000000..71a7d07cb1
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc-sequencer-schema.xsd
@@ -0,0 +1,274 @@
+<xs:schema
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://ns.ecomp.com/asdc/sequencer"
+ xmlns:s="http://ns.ecomp.com/asdc/sequencer"
+ attributeFormDefault="unqualified"
+ elementFormDefault="unqualified">
+
+ <!--
+
+ https://github.com/highsource/jsonix-schema-compiler/wiki/JSON-Schema-Generation
+
+ npm install -x-save-dev json-schema-generation
+
+ java -jar node_modules/jsonix-schema-compiler/lib/jsonix-schema-compiler-full.jar \
+ -generateJsonSchema \
+ -d ./src/main/webapp/lib/ecomp/asdc/sequencer/schema/ \
+ -p asdc_sequencer_schema \
+ ./src/main/webapp/lib/ecomp/asdc/sequencer/schema/asdc-sequencer-schema.xsd
+
+ -->
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:element name="diagram">
+ <xs:annotation>
+ <xs:documentation>
+ Diagram state.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="metadata" type="s:metadataType"/>
+ <xs:element name="lifelines" type="s:lifelinesType"/>
+ <xs:element name="steps" type="s:stepsType"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="entityType" abstract="true">
+ <xs:annotation>
+ <xs:documentation>
+ Stuff common to all entities; an identifier, a name, an optional
+ schema reference, and some optional notes.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="notes" minOccurs="0">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="note" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="annotation" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>
+ Optional annotations; non-structural information attached to any entity.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="id" use="required" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ Entity identifier.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="ref" use="optional" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ Optional reference to schema definition, where this entity
+ corresponds to (and is constrained by) a schema entity.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="name" use="required" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ Human-readable name.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="externalId" use="optional" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ ID of entity in originating system. For external use; not
+ used by the sequencer widget.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="metadataType">
+ <xs:annotation>
+ <xs:documentation>
+ Diagram metadata, including name, identifier and schema reference.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="s:entityType"/>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="lifelineType">
+ <xs:annotation>
+ <xs:documentation>
+ Definition of a single lifeline.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="s:entityType"/>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="lifelinesType">
+ <xs:annotation>
+ <xs:documentation>
+ A set of lifelines. May be top-level or in a fragment.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="s:entityType">
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="lifeline" type="s:lifelineType"/>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="occurrencesType">
+ <xs:annotation>
+ <xs:documentation>
+ An occurrence at one or other end of a message.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="start" use="optional">
+ <xs:simpleType>
+ <xs:list itemType="xs:token"/>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="stop" use="optional">
+ <xs:simpleType>
+ <xs:list itemType="xs:token"/>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="fragmentType">
+ <xs:annotation>
+ <xs:documentation>
+ A fragment directive.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="start" type="xs:boolean" use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>
+ Whether fragment starts; fragment activated when @start=true.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="stop" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Indication of the last message in this fragment.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="operation" use="optional" default="alt">
+ <xs:annotation>
+ <xs:documentation>
+ Fragment operation. Start with the three everybody knows, but
+ there are others.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="alt"/>
+ <xs:enumeration value="opt"/>
+ <xs:enumeration value="loop"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="guard" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Guard condition.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="messageType">
+ <xs:annotation>
+ <xs:documentation>
+ A message between lifelines.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="s:entityType">
+ <xs:sequence>
+ <xs:element name="occurrences" type="s:occurrencesType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="fragment" type="s:fragmentType" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute name="to" type="xs:string" use="required"/>
+ <xs:attribute name="from" type="xs:string" use="required"/>
+ <xs:attribute name="type">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="request"/>
+ <xs:enumeration value="response"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="asynchronous" type="xs:boolean" default="false"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="guardType">
+ <xs:annotation>
+ <xs:documentation>
+ Guard condition within a fragment. Some fragments have more than
+ one section, each with their own guard condition.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="guard" type="xs:string"/>
+ <xs:element name="steps" type="s:stepsType"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <!-- /////////////////////////////////////////////////////////////////////////////////////// -->
+
+ <xs:complexType name="stepsType">
+ <xs:annotation>
+ <xs:documentation>
+ An ordered set of messages and subsequences.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="s:entityType">
+ <xs:sequence maxOccurs="unbounded">
+ <xs:choice>
+ <xs:element name="message" type="s:messageType"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+</xs:schema>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc_sequencer_meta_schema.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc_sequencer_meta_schema.json
new file mode 100644
index 0000000000..cf4174ed35
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc_sequencer_meta_schema.json
@@ -0,0 +1,332 @@
+
+{
+ "id":"#",
+ "definitions":{
+ "LifelinesType.Constraints":{
+ "type":"object",
+ "title":"LifelinesType.Constraints",
+ "required":[
+ "create",
+ "delete",
+ "reorder"
+ ],
+ "properties":{
+ "create":{
+ "title":"create",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/boolean"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"create",
+ "namespaceURI":""
+ }
+ },
+ "delete":{
+ "title":"delete",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/boolean"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"delete",
+ "namespaceURI":""
+ }
+ },
+ "reorder":{
+ "title":"reorder",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/boolean"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"reorder",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "propertiesOrder":[
+ "create",
+ "delete",
+ "reorder"
+ ]
+ },
+ "LifelinesType":{
+ "required":[
+ "constraints"
+ ],
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType"
+ },
+ {
+ "type":"object",
+ "title":"LifelinesType",
+ "properties":{
+ "lifeline":{
+ "title":"lifeline",
+ "allOf":[
+ {
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/LifelineType"
+ },
+ "minItems":0
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"lifeline",
+ "namespaceURI":""
+ }
+ },
+ "constraints":{
+ "title":"constraints",
+ "allOf":[
+ {
+ "$ref":"#/definitions/LifelinesType.Constraints"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"constraints",
+ "namespaceURI":""
+ }
+ }
+ }
+ }
+ ],
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"lifelinesType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "lifeline",
+ "constraints"
+ ]
+ },
+ "EntityType.Notes":{
+ "type":"object",
+ "title":"EntityType.Notes",
+ "properties":{
+ "note":{
+ "title":"note",
+ "allOf":[
+ {
+ "type":"array",
+ "items":{
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ },
+ "minItems":0
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"note",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "propertiesOrder":[
+ "note"
+ ]
+ },
+ "MetadataType":{
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType"
+ },
+ {
+ "type":"object",
+ "title":"MetadataType",
+ "properties":{
+ }
+ }
+ ],
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"metadataType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ }
+ },
+ "EntityType":{
+ "type":"object",
+ "title":"EntityType",
+ "required":[
+ "id",
+ "name"
+ ],
+ "properties":{
+ "notes":{
+ "title":"notes",
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType.Notes"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"notes",
+ "namespaceURI":""
+ }
+ },
+ "id":{
+ "title":"id",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"id",
+ "namespaceURI":""
+ }
+ },
+ "name":{
+ "title":"name",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"name",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"entityType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "notes",
+ "id",
+ "name"
+ ]
+ },
+ "Diagram":{
+ "type":"object",
+ "title":"Diagram",
+ "required":[
+ "metadata",
+ "lifelines"
+ ],
+ "properties":{
+ "metadata":{
+ "title":"metadata",
+ "allOf":[
+ {
+ "$ref":"#/definitions/MetadataType"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"metadata",
+ "namespaceURI":""
+ }
+ },
+ "lifelines":{
+ "title":"lifelines",
+ "allOf":[
+ {
+ "$ref":"#/definitions/LifelinesType"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"lifelines",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "propertiesOrder":[
+ "metadata",
+ "lifelines"
+ ]
+ },
+ "LifelineType":{
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType"
+ },
+ {
+ "type":"object",
+ "title":"LifelineType",
+ "properties":{
+ "mandatory":{
+ "title":"mandatory",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/boolean"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"mandatory",
+ "namespaceURI":""
+ }
+ }
+ }
+ }
+ ],
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"lifelineType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "mandatory"
+ ]
+ }
+ },
+ "anyOf":[
+ {
+ "type":"object",
+ "properties":{
+ "name":{
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/QName"
+ },
+ {
+ "type":"object",
+ "properties":{
+ "localPart":{
+ "enum":[
+ "diagram"
+ ]
+ },
+ "namespaceURI":{
+ "enum":[
+ "http://ns.ecomp.com/asdc/sequencer"
+ ]
+ }
+ }
+ }
+ ]
+ },
+ "value":{
+ "$ref":"#/definitions/Diagram"
+ }
+ },
+ "elementName":{
+ "localPart":"diagram",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc_sequencer_schema.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc_sequencer_schema.json
new file mode 100644
index 0000000000..d655826290
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/schema/asdc_sequencer_schema.json
@@ -0,0 +1,582 @@
+
+{
+ "id":"#",
+ "definitions":{
+ "EntityType.Notes":{
+ "type":"object",
+ "title":"EntityType.Notes",
+ "properties":{
+ "note":{
+ "title":"note",
+ "allOf":[
+ {
+ "type":"array",
+ "items":{
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ },
+ "minItems":0
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"note",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "propertiesOrder":[
+ "note"
+ ]
+ },
+ "GuardType":{
+ "type":"object",
+ "title":"GuardType",
+ "required":[
+ "guard",
+ "steps"
+ ],
+ "properties":{
+ "guard":{
+ "title":"guard",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"guard",
+ "namespaceURI":""
+ }
+ },
+ "steps":{
+ "title":"steps",
+ "allOf":[
+ {
+ "$ref":"#/definitions/StepsType"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"steps",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"guardType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "guard",
+ "steps"
+ ]
+ },
+ "MetadataType":{
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType"
+ },
+ {
+ "type":"object",
+ "title":"MetadataType",
+ "properties":{
+ }
+ }
+ ],
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"metadataType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ }
+ },
+ "OccurrencesType":{
+ "type":"object",
+ "title":"OccurrencesType",
+ "properties":{
+ "start":{
+ "title":"start",
+ "allOf":[
+ {
+ "type":"array",
+ "items":{
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"start",
+ "namespaceURI":""
+ }
+ },
+ "stop":{
+ "title":"stop",
+ "allOf":[
+ {
+ "type":"array",
+ "items":{
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"stop",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"occurrencesType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "start",
+ "stop"
+ ]
+ },
+ "Diagram":{
+ "type":"object",
+ "title":"Diagram",
+ "required":[
+ "metadata",
+ "lifelines",
+ "steps"
+ ],
+ "properties":{
+ "metadata":{
+ "title":"metadata",
+ "allOf":[
+ {
+ "$ref":"#/definitions/MetadataType"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"metadata",
+ "namespaceURI":""
+ }
+ },
+ "lifelines":{
+ "title":"lifelines",
+ "allOf":[
+ {
+ "$ref":"#/definitions/LifelinesType"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"lifelines",
+ "namespaceURI":""
+ }
+ },
+ "steps":{
+ "title":"steps",
+ "allOf":[
+ {
+ "$ref":"#/definitions/StepsType"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"steps",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "propertiesOrder":[
+ "metadata",
+ "lifelines",
+ "steps"
+ ]
+ },
+ "LifelineType":{
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType"
+ },
+ {
+ "type":"object",
+ "title":"LifelineType",
+ "properties":{
+ }
+ }
+ ],
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"lifelineType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ }
+ },
+ "LifelinesType":{
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType"
+ },
+ {
+ "type":"object",
+ "title":"LifelinesType",
+ "properties":{
+ "lifeline":{
+ "title":"lifeline",
+ "allOf":[
+ {
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/LifelineType"
+ },
+ "minItems":0
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"lifeline",
+ "namespaceURI":""
+ }
+ }
+ }
+ }
+ ],
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"lifelinesType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "lifeline"
+ ]
+ },
+ "FragmentType":{
+ "type":"object",
+ "title":"FragmentType",
+ "properties":{
+ "start":{
+ "title":"start",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/boolean"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"start",
+ "namespaceURI":""
+ }
+ },
+ "stop":{
+ "title":"stop",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"stop",
+ "namespaceURI":""
+ }
+ },
+ "operation":{
+ "title":"operation",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"operation",
+ "namespaceURI":""
+ }
+ },
+ "guard":{
+ "title":"guard",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"guard",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"fragmentType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "start",
+ "stop",
+ "operation",
+ "guard"
+ ]
+ },
+ "StepsType":{
+ "required":[
+ "message"
+ ],
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType"
+ },
+ {
+ "type":"object",
+ "title":"StepsType",
+ "properties":{
+ "message":{
+ "title":"message",
+ "allOf":[
+ {
+ "type":"array",
+ "items":{
+ "$ref":"#/definitions/MessageType"
+ },
+ "minItems":1
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"message",
+ "namespaceURI":""
+ }
+ }
+ }
+ }
+ ],
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"stepsType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "message"
+ ]
+ },
+ "EntityType":{
+ "type":"object",
+ "title":"EntityType",
+ "required":[
+ "id",
+ "name"
+ ],
+ "properties":{
+ "notes":{
+ "title":"notes",
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType.Notes"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"notes",
+ "namespaceURI":""
+ }
+ },
+ "id":{
+ "title":"id",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"id",
+ "namespaceURI":""
+ }
+ },
+ "ref":{
+ "title":"ref",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"ref",
+ "namespaceURI":""
+ }
+ },
+ "name":{
+ "title":"name",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"name",
+ "namespaceURI":""
+ }
+ }
+ },
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"entityType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "notes",
+ "id",
+ "ref",
+ "name"
+ ]
+ },
+ "MessageType":{
+ "required":[
+ "to",
+ "from"
+ ],
+ "allOf":[
+ {
+ "$ref":"#/definitions/EntityType"
+ },
+ {
+ "type":"object",
+ "title":"MessageType",
+ "properties":{
+ "occurrences":{
+ "title":"occurrences",
+ "allOf":[
+ {
+ "$ref":"#/definitions/OccurrencesType"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"occurrences",
+ "namespaceURI":""
+ }
+ },
+ "fragment":{
+ "title":"fragment",
+ "allOf":[
+ {
+ "$ref":"#/definitions/FragmentType"
+ }
+ ],
+ "propertyType":"element",
+ "elementName":{
+ "localPart":"fragment",
+ "namespaceURI":""
+ }
+ },
+ "to":{
+ "title":"to",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"to",
+ "namespaceURI":""
+ }
+ },
+ "from":{
+ "title":"from",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"from",
+ "namespaceURI":""
+ }
+ },
+ "type":{
+ "title":"type",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/string"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"type",
+ "namespaceURI":""
+ }
+ },
+ "asynchronous":{
+ "title":"asynchronous",
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/boolean"
+ }
+ ],
+ "propertyType":"attribute",
+ "attributeName":{
+ "localPart":"asynchronous",
+ "namespaceURI":""
+ }
+ }
+ }
+ }
+ ],
+ "typeType":"classInfo",
+ "typeName":{
+ "localPart":"messageType",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ },
+ "propertiesOrder":[
+ "occurrences",
+ "fragment",
+ "to",
+ "from",
+ "type",
+ "asynchronous"
+ ]
+ }
+ },
+ "anyOf":[
+ {
+ "type":"object",
+ "properties":{
+ "name":{
+ "allOf":[
+ {
+ "$ref":"http://www.jsonix.org/jsonschemas/w3c/2001/XMLSchema.jsonschema#/definitions/QName"
+ },
+ {
+ "type":"object",
+ "properties":{
+ "localPart":{
+ "enum":[
+ "diagram"
+ ]
+ },
+ "namespaceURI":{
+ "enum":[
+ "http://ns.ecomp.com/asdc/sequencer"
+ ]
+ }
+ }
+ }
+ ]
+ },
+ "value":{
+ "$ref":"#/definitions/Diagram"
+ }
+ },
+ "elementName":{
+ "localPart":"diagram",
+ "namespaceURI":"http://ns.ecomp.com/asdc/sequencer"
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/templates/default.metamodel.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/templates/default.metamodel.json
new file mode 100644
index 0000000000..f6a28a8723
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/templates/default.metamodel.json
@@ -0,0 +1,17 @@
+{
+ "diagram": {
+ "metadata": {
+ "id": "$",
+ "name": "Blank Sequence"
+
+ },
+ "lifelines": {
+ "lifelines": [],
+ "constraints": {
+ "create": true,
+ "delete": true,
+ "reorder": true
+ }
+ }
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/templates/default.model.json b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/templates/default.model.json
new file mode 100644
index 0000000000..42edc5516b
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/templates/default.model.json
@@ -0,0 +1,11 @@
+{
+ "diagram": {
+ "metadata": {
+ "id": "$",
+ "name": "New Sequence"
+
+ },
+ "lifelines": [],
+ "steps": []
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/main.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/main.jsx
new file mode 100644
index 0000000000..33a62f7228
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/lib/main.jsx
@@ -0,0 +1,35 @@
+/*!
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+import React from 'react';
+import { render } from 'react-dom';
+import Sequencer from './ecomp/asdc/sequencer/Sequencer';
+import '../res/ecomp/asdc/sequencer/sequencer-development.scss';
+import '../res/thirdparty/react-select/react-select.min.css';
+
+function renderApplication() {
+ const shell = document.createElement('div');
+ shell.setAttribute('style', 'height:100%;width:100%;margin:0;padding:0');
+ document.body.appendChild(shell);
+ const options = { demo: true };
+ render(<Sequencer options={options} />, shell);
+}
+
+if (window.addEventListener) {
+ window.addEventListener('DOMContentLoaded', renderApplication);
+} else {
+ window.attachEvent('onload', renderApplication);
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/_typography.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/_typography.scss
new file mode 100644
index 0000000000..5d23eff34f
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/_typography.scss
@@ -0,0 +1,25 @@
+/* Fonts */
+@font-face {
+ font-family: Omnes-Light;
+ src: url('ecomp/asdc/common/fonts/omnes-att-light.otf');
+}
+
+@font-face {
+ font-family: Omnes-Regular;
+ src: url('ecomp/asdc/common/fonts/omnes-att-regular.otf');
+}
+
+@font-face {
+ font-family: Omnes-Medium;
+ src: url('ecomp/asdc/common/fonts/omnes-att-medium.otf');
+}
+
+@font-face {
+ font-family: Omnes-Bold;
+ src: url('ecomp/asdc/common/fonts/omnes-att-bold.otf');
+}
+
+$base-font-regular: omnes-regular, "Omnes-Regular";
+$base-font-light: omnes-light, "Omnes-Light";
+$base-font-medium: omnes-medium, "Omnes-Medium";
+$base-font-bold: omnes-bold, "Omnes-Bold";
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/_variables.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/_variables.scss
new file mode 100644
index 0000000000..1880ac3047
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/_variables.scss
@@ -0,0 +1,44 @@
+
+// primary colors
+$blue: #009fdb;
+$dark-blue: #0568ae;
+$light-blue: #71c5e8;
+$green: #4ca90c;
+$dark-green: #007a3e;
+$light-green: #b5bd00;
+$orange: #ea7400;
+$yellow: #ffb81c;
+$dark-purple: #702f8a;
+$purple: #9063cd;
+$light-purple: #caa2dd;
+$black: #000000;
+$dark-gray: #5a5a5a;
+$gray: #959595;
+$light-gray: #d2d2d2;
+$white: #ffffff;
+
+// Secondary Colors
+$red: #cf2a2a;
+$background-gray: #f2f2f2;
+$text-black: #191919;
+$link-blue: #056bae;
+$functional-green: #007a3e;
+$functional-yellow: #ffb81c;
+$tlv-gray: #f8f8f8;
+$tlv-light-gray: #eaeaea;
+$tlv-hover: #e6f6fb;
+
+
+$scroll-bar-color: $dark-gray;
+
+//responsive @media params
+$tablet-max-width: 1024px;
+$laptop-min-width: 1224px;
+$desktop-min-width: 1824px;
+
+/* Textures */
+$images-folder-name: "../images";
+$plus-circle-icon: $images-folder-name + "/plus-circle-icon.svg";
+$interface-icon: $images-folder-name + "/interface.svg";
+$sdc-logo: $images-folder-name + "/logo.svg";
+$warning-icon: $images-folder-name + "/warning.svg";
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-bold-italic.otf b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-bold-italic.otf
new file mode 100644
index 0000000000..77f0dbc15f
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-bold-italic.otf
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-bold.otf b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-bold.otf
new file mode 100644
index 0000000000..136afca84c
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-bold.otf
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-italic.otf b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-italic.otf
new file mode 100644
index 0000000000..5dc1da79d4
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-italic.otf
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-light-Italic.otf b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-light-Italic.otf
new file mode 100644
index 0000000000..b13ae4fede
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-light-Italic.otf
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-light.otf b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-light.otf
new file mode 100644
index 0000000000..587d871e6f
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-light.otf
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-medium-italic.otf b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-medium-italic.otf
new file mode 100644
index 0000000000..f824bc23e7
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-medium-italic.otf
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-medium.otf b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-medium.otf
new file mode 100644
index 0000000000..3085c1fa39
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-medium.otf
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-regular.otf b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-regular.otf
new file mode 100644
index 0000000000..a1a78eb7ca
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/common/fonts/omnes-att-regular.otf
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-actions.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-actions.scss
new file mode 100644
index 0000000000..bc5b151c16
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-actions.scss
@@ -0,0 +1,120 @@
+.asdcs-control {
+
+ .asdcs-actions {
+
+ @include drop-shadow();
+
+ * {
+ @include noselect();
+ }
+
+ $asdcsActionMenuWidth: 275px;
+ $asdcsActionMenuSpanIndent: 20px;
+
+ position: fixed;
+ display: none;
+ top: 0;
+ left: 0;
+
+ background: $asdcsColorOneLight;
+ border: 1px solid $asdcsColorWhitish;
+ border-radius: $asdcsPopupBorderRadius;
+ width: $asdcsActionMenuWidth;
+ z-index: 10000;
+
+ .asdcs-actions-header {
+ padding: 5px;
+ height: 20px;
+ pointer-events: none;
+ .asdcs-actions-icon {
+ height: $asdcsSmallIconSize;
+ width: $asdcsSmallIconSize;
+ fill: $asdcsColorTwo;
+ }
+ }
+
+ .asdcs-actions-footer {
+ height: 10px;
+ }
+
+ div.asdcs-actions-options {
+
+ div.asdcs-actions-state {
+ float: right;
+ height: $asdcsSmallIconSize;
+ width: $asdcsSmallIconSize;
+ .asdcs-actions-icon {
+ fill: $asdcsColorOneDark;
+ }
+ }
+
+ .asdcs-icon-action {
+ display: none;
+ fill: $asdcsColorOneDark;
+ height: 20px;
+ width: 20px;
+ }
+
+ span.asdcs-annotation {
+ color: $asdcsColorOneDark;
+ }
+
+ .asdcs-actions-option {
+ padding: 8px;
+ border-top: 1px solid $asdcsColorOne;
+ border-collapse: collapse;
+ cursor: pointer;
+ &:hover {
+ background-color: lighten($asdcsColorOneLight, 5%);
+ @include transition(background-color $asdcsTransitionTime ease);
+ }
+ }
+
+ .asdcs-icon {
+ fill: $asdcsColorOneDark;
+ &:hover {
+ fill: $asdcsColorEmphasisHover;
+ @include transition(fill $asdcsTransitionTime ease);
+ }
+ }
+
+ .asdcs-actions-optiongroup-occurrence {
+ .asdcs-actions-option-occurrence-from,
+ .asdcs-actions-option-occurrence-to {
+ span.asdcs-label {
+ padding-left: $asdcsActionMenuSpanIndent;
+ }
+ }
+ .asdcs-actions-option-occurrence-toggle {
+ background-color: $asdcsColorOneLight;
+ }
+ }
+
+ .asdcs-actions-optiongroup-fragment {
+ .asdcs-actions-fragment-toggle {
+ background-color: $asdcsColorOneLight;
+ }
+ }
+
+ .asdcs-actions-fragment-operator,
+ .asdcs-actions-fragment-guard {
+ div.asdcs-label {
+ display: table-cell;
+ width: 100px;
+ }
+ div.asdcs-value {
+ display: table-cell;
+ width: 150px;
+ input {
+ width: 90%;
+ border-color: $asdcsColorOne;
+ }
+ .asdcs-editable-select {
+ border: 1px solid $asdcsColorOne;
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-common.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-common.scss
new file mode 100644
index 0000000000..e90a435a98
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-common.scss
@@ -0,0 +1,112 @@
+@import '../common/_variables.scss';
+
+$asdcsApplicationMinHeight: 400px;
+$asdcsEditorWidth: 500px;
+
+$asdcsFontSize: 13px;
+$asdcsTransitionTime: 250ms;
+$asdcsTextColor: $text-black;
+
+$asdcsColorWhite: $white;
+$asdcsColorWhitish: lighten($asdcsColorWhite, 5%);
+$asdcsColorBlack: $black;
+
+$asdcsColorOne: $tlv-light-gray;
+$asdcsColorOneLight: lighten($asdcsColorOne, 5%);
+$asdcsColorOneDark: $dark-gray;
+
+$asdcsColorTwo: $blue;
+$asdcsColorTwoLight: lighten($asdcsColorTwo, 10%);
+
+$asdcsColorThree: $light-purple;
+
+$asdcsColorGrey: $gray;
+$asdcsColorDarkGrey: $dark-gray;
+$asdcsColorLightGrey: $light-gray;
+
+$asdcsColorEmphasis: lighten($asdcsColorTwo, 10%);
+$asdcsColorEmphasisHover: $asdcsColorTwo;
+
+$asdcsSmallIconSize: 20px;
+
+// Buttons.
+
+$asdcsColorButtonBG: $asdcsColorOneDark;
+$asdcsColorButtonBGHover: $asdcsColorOne;
+$asdcsColorButtonFG: $asdcsColorWhitish;
+$asdcsColorButtonFGHover: $asdcsColorWhite;
+
+// Input fields.
+
+$asdcsInputSelectBorderColor: #d8d8d8;
+$asdcsInputSelectBorderRadius: 2px;
+$asdcsInputSelectFontSize: 14px;
+$asdcsInputSelectHeight: 30px;
+$asdcsInputSelectArrowColor: $asdcsColorOneDark;
+
+$asdcsInputTextColor: $asdcsTextColor;
+$asdcsInputTextBorderColor: $asdcsColorWhite;
+$asdcsInputTextBorderFocusColor: #d8d8d8;
+$asdcsInputTextBorderRadius: 2px;
+$asdcsInputTextFontSize: $asdcsFontSize;
+$asdcsInputTextHeight: 22px;
+
+$asdcsPopupBorderRadius: 3px;
+
+// SVG-specific.
+
+$asdcsSVGSelectableColor: $asdcsColorOne;
+$asdcsSVGSelectableOpacity: 0.01;
+$asdcsSVGSelectableWidth: 100;
+
+$asdcsSVGStrokeColor: $gray;
+$asdcsSVGStrokeColorLifeline: $asdcsSVGStrokeColor;
+$asdcsSVGStrokeColorMessage: #d8d8d8;
+$asdcsSVGTextColorMessage: $asdcsColorOneDark;
+$asdcsSVGStrokeColorFragment: $asdcsColorOneDark;
+$asdcsSVGStrokeWidth: 4;
+$asdcsSVGStrokeActiveColor: $asdcsColorBlack;
+$asdcsSVGStrokeActiveWidth: $asdcsSVGStrokeWidth + 4;
+
+// -------------------------------------------------------------------------------------------------
+
+@mixin drop-shadow($x: 0px, $y: 0px, $blur: 2px, $spread: 2px, $alpha: 0.25) {
+ -webkit-box-shadow: $x $y $blur $spread rgba(0, 0, 0, $alpha);
+ -moz-box-shadow: $x $y $blur $spread rgba(0, 0, 0, $alpha);
+ box-shadow: $x $y $blur $spread rgba(0, 0, 0, $alpha);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+@mixin transition($transition) {
+ -webkit-transition: $transition;
+ -moz-transition: $transition;
+ -ms-transition: $transition;
+ -o-transition: $transition;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+@mixin gradient($startColor: #eee, $endColor: white) {
+ background-color: $startColor;
+ background: -webkit-gradient(linear, left top, left bottom, from($startColor), to($endColor));
+ background: -webkit-linear-gradient(top, $startColor, $endColor);
+ background: -moz-linear-gradient(top, $startColor, $endColor);
+ background: -ms-linear-gradient(top, $startColor, $endColor);
+ background: -o-linear-gradient(top, $startColor, $endColor);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+@mixin noselect() {
+ -webkit-touch-callout: none; /* iOS Safari */
+ -webkit-user-select: none; /* Chrome/Safari/Opera */
+ -khtml-user-select: none; /* Konqueror */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* IE/Edge */
+ user-select: none; /* non-prefixed version, currently not supported by any browser */
+}
+
+.asdcs-hidden {
+ display: none;
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-controls.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-controls.scss
new file mode 100644
index 0000000000..68256b9c3e
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-controls.scss
@@ -0,0 +1,72 @@
+.asdcs-control {
+
+ // Input /////////////////////////////////////////////////////////////////////////////////////////
+
+ input.asdcs-editable {
+ border: 1px solid $asdcsInputTextBorderColor;
+ border-radius: $asdcsInputTextBorderRadius;
+ padding: 3px 5px;
+ height: $asdcsInputTextHeight;
+ width: calc(100% - 10px);
+ color: $asdcsInputTextColor;
+ background-color: $asdcsColorWhite;
+ &:focus {
+ border: 1px solid $asdcsInputTextBorderFocusColor;
+ background-color: $asdcsColorWhitish;
+ }
+ }
+
+ // Select ////////////////////////////////////////////////////////////////////////////////////////
+
+ .asdcs-editable-select {
+ outline: none;
+ border-radius: $asdcsInputSelectBorderRadius;
+ border: 1px solid $asdcsInputSelectBorderColor;
+ height: $asdcsInputSelectHeight;
+ div {
+ border-radius: $asdcsInputSelectBorderRadius;
+ }
+ * {
+ line-height: initial;
+ text-align: initial;
+ font-size: $asdcsInputSelectFontSize;
+ }
+ .Select-menu-outer {
+ .Select-option {
+ padding: 4px;
+ .is-selected {
+ background-color: $asdcsColorOneLight;
+ }
+ }
+ }
+ .Select-value {
+ height: $asdcsInputSelectHeight - 4px;
+ padding-left: 5px;
+ }
+ .Select-input {
+ border: none;
+ height: 1px;
+ line-height: 1px;
+ }
+ .Select-control {
+ box-shadow: none;
+ border: none;
+ }
+ .Select-control, .Select-placeholder {
+ border: none;
+ height: $asdcsInputSelectHeight - 4px;
+ }
+ .Select-placeholder {
+ padding-left: 4px;
+ }
+ .Select-arrow-zone {
+ text-align: center;
+ overflow: hidden;
+ padding-top: 4px;
+ }
+ &.is-focused {
+ .Select-control {
+ }
+ }
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-designer.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-designer.scss
new file mode 100644
index 0000000000..9caeee5c57
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-designer.scss
@@ -0,0 +1,256 @@
+.asdcs-control {
+
+ .asdcs-editor-designer {
+
+ overflow: hidden;
+ table {
+ border-spacing: 2px;
+ }
+
+ $asdcsActiveBorderWidth: 1px;
+ $asdcsActiveBorderColor: $asdcsColorEmphasis;
+ .asdcs-designer-accordion {
+ display: flex;
+ flex-direction: column;
+ }
+
+ .asdcs-designer-metadata {
+ height: 70px;
+ display: table-cell;
+ padding: 0 15px;
+ text-align: left;
+ vertical-align: middle;
+ font-size: 16px;
+ color: $asdcsTextColor;
+ @include noselect();
+ }
+
+ .asdcs-designer-lifelines-container,
+ .asdcs-designer-steps-container {
+ flex: 1;
+ div,span {
+ @include noselect();
+ }
+ // overflow: hidden;
+ overflow: auto;
+ }
+
+ .asdcs-designer-lifelines-container {
+ padding: 0;
+ margin: 0;
+ .asdcs-designer-lifelines {
+ padding: 0;
+ .asdcs-designer-lifeline {
+ background-color: $asdcsColorWhite;
+ border: $asdcsActiveBorderWidth solid transparent; //$asdcsColorWhite;
+ border-bottom: $asdcsActiveBorderWidth solid $asdcsColorOne;
+ .asdcs-designer-lifeline-new {
+ background-color: $asdcsColorOneLight;
+ }
+ &.asdcs-active {
+ border: $asdcsActiveBorderWidth solid $asdcsColorEmphasis;
+ }
+ }
+ }
+ }
+
+ .asdcs-designer-steps-container {
+ padding: 0;
+ margin: 0;
+ .asdcs-designer-steps {
+ padding: 0;
+ .asdcs-designer-message {
+ border: $asdcsActiveBorderWidth solid $asdcsColorWhite;
+ border-bottom: $asdcsActiveBorderWidth solid $asdcsColorOne;
+ background-color: $asdcsColorWhite;
+ .asdcs-designer-message-new {
+ background-color: $asdcsColorOneLight;
+ }
+ &.asdcs-active {
+ border: $asdcsActiveBorderWidth solid $asdcsColorEmphasis;
+ }
+ select {
+ height: 30px;
+ width: 100%;
+ background-color: $asdcsColorWhite;
+ border-radius: $asdcsInputSelectBorderRadius;
+ border: 1px solid $asdcsInputSelectBorderColor;
+ -moz-appearance: none; // Just FF.
+ option {
+ padding: 10px 0;
+ font-size: $asdcsFontSize + 2;
+ }
+ &.asdcs-designer-select-message-type {
+ option {
+ font-size: $asdcsFontSize + 5;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .asdcs-designer-lifelines-container,
+ .asdcs-designer-steps-container {
+ table.asdcs-designer-layout {
+ width: 100%;
+ padding: 8px;
+ tbody, tr {
+ width: 100%;
+ }
+ td {
+ text-align: center;
+ vertical-align: middle;
+ }
+ &.asdcs-designer-message-row1 {
+ padding-bottom: 4px;
+ td:nth-child(3) {
+ width: 99%;
+ }
+ }
+ &.asdcs-designer-message-row2 {
+ padding-top: 0;
+ tr {
+ td:nth-child(1), td:nth-child(3) {
+ width: 45%;
+ }
+ td:nth-child(2) {
+ min-width: 70px;
+ width: 70px;
+ }
+ svg {
+ fill: $asdcsColorOneDark;
+ }
+ }
+ }
+ &.asdcs-designer-message-new {
+ tr {
+ td:nth-child(2) div {
+ white-space: nowrap;
+ color: $asdcsColorEmphasis;
+ cursor: pointer;
+ &:hover {
+ color: $asdcsColorEmphasisHover;
+ }
+ }
+ td:nth-child(3) div {
+ fill: $asdcsColorEmphasis;
+ cursor: pointer;
+ &:hover {
+ fill: $asdcsColorEmphasisHover;
+ }
+ }
+ td:nth-child(4) {
+ width: 99%;
+ }
+ }
+ }
+ &.asdcs-designer-lifeline-row1 {
+ tr {
+ td:nth-child(3) {
+ width: 99%;
+ }
+ }
+ }
+ &.asdcs-designer-lifeline-new {
+ tr {
+ td:nth-child(2) div {
+ white-space: nowrap;
+ color: $asdcsColorEmphasis;
+ cursor: pointer;
+ &:hover {
+ color: $asdcsColorEmphasisHover;
+ }
+ }
+ td:nth-child(3) div {
+ fill: $asdcsColorEmphasis;
+ &:hover {
+ fill: $asdcsColorEmphasisHover;
+ }
+ }
+ td:nth-child(4) {
+ width: 99%;
+ }
+ }
+ }
+ }
+ }
+
+ .asdcs-designer-placeholder {
+ padding: 8px;
+ background-color: $asdcsColorOneLight;
+ }
+
+ .asdcs-designer-icon {
+ display: table-cell;
+ text-align: right;
+ vertical-align: middle;
+ cursor: pointer;
+ fill: $asdcsColorDarkGrey;
+ min-width: $asdcsSmallIconSize;
+ width: $asdcsSmallIconSize;
+ height: $asdcsSmallIconSize;
+ &.asdcs-active {
+ fill: $asdcsColorEmphasis;
+ }
+ &:hover {
+ fill: $asdcsColorEmphasisHover;
+ @include transition(fill $asdcsTransitionTime ease);
+ }
+ svg {
+ pointer-events: none;
+ width: $asdcsSmallIconSize;
+ height: $asdcsSmallIconSize;
+ }
+ }
+
+ .asdcs-designer-sort {
+ text-align: center;
+ cursor: move;
+ display: table-cell;
+ }
+
+ .asdcs-designer-lifeline-index,
+ .asdcs-designer-message-index{
+ color: $asdcsTextColor;
+ }
+
+ button.asdcs-designer-new {
+ padding: 0 4px;
+ svg {
+ width: $asdcsSmallIconSize;
+ height: $asdcsSmallIconSize;
+ }
+ fill: $asdcsColorWhitish;
+ &:hover {
+ background-color: $asdcsColorEmphasis;
+ @include transition(background-color $asdcsTransitionTime ease);
+ }
+ }
+
+ h3 {
+ margin: 0;
+ font-size: 14px;
+ line-height: 40px;
+ vertical-align: middle;
+ height: 40px;
+ padding: 0 10px 0 15px;
+ background-color: $asdcsColorOne;
+ border-bottom: 1px solid $asdcsColorOneLight;
+ color: $asdcsColorOneDark;
+ text-transform: uppercase;
+ cursor: pointer;
+ div.asdcs-designer-icon {
+ padding-top: 7px;
+ display: inline;
+ float: right;
+ fill: $asdcsColorDarkGrey;
+ &:hover {
+ fill: $asdcsColorGrey;
+ @include transition(fill $asdcsTransitionTime ease);
+ }
+ }
+ @include noselect();
+ }
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-development.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-development.scss
new file mode 100644
index 0000000000..0d9eef54d2
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-development.scss
@@ -0,0 +1,29 @@
+html,body {
+ margin: 0px;
+ padding: 0px;
+ height: 100%;
+ width: 100%;
+}
+@font-face {
+ font-family: Omnes-Light;
+ src: url('../common/fonts/omnes-att-light.otf');
+}
+
+@font-face {
+ font-family: Omnes-Regular;
+ src: url('../common/fonts/omnes-att-regular.otf');
+}
+
+@font-face {
+ font-family: Omnes-Medium;
+ src: url('../common/fonts/omnes-att-medium.otf');
+}
+
+@font-face {
+ font-family: Omnes-Bold;
+ src: url('../common/fonts/omnes-att-bold.otf');
+}
+
+* {
+ font-family: "Omnes-Regular", "Helvetiva Neue", Helvetica, Arial, SansSerif;
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-diagram-svg.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-diagram-svg.scss
new file mode 100644
index 0000000000..310c4d0c40
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-diagram-svg.scss
@@ -0,0 +1,189 @@
+// Separate to allow for SVG-only styles, for application by Batik
+// to exported SVG on the service-side.
+
+svg {
+
+ text {
+ text-anchor: middle;
+ color: $asdcsTextColor;
+ stroke: none;
+ }
+
+ g.asdcs-diagram-title {
+ text {
+ font-size: 40pt;
+ }
+ }
+
+ rect.asdcs-diagram-occurrence {
+ stroke: $asdcsSVGStrokeColor;
+ stroke-width: $asdcsSVGStrokeWidth;
+ fill: $asdcsColorWhite;
+ }
+
+ g.asdcs-diagram-message-container {
+
+ text.asdcs-diagram-message-label {
+ fill: $asdcsSVGTextColorMessage;
+ pointer-events: none;
+ font-size: 28pt;
+ }
+
+ rect.asdcs-diagram-message-label-bg {
+ pointer-events: none;
+ stroke: none;
+ fill: $asdcsColorWhite;
+ fill-opacity: 0.75;
+ }
+
+ path.asdcs-diagram-message-selectable {
+ stroke: $asdcsSVGSelectableColor;
+ stroke-width: $asdcsSVGSelectableWidth;
+ fill: none;
+ opacity: $asdcsSVGSelectableOpacity;
+ cursor: pointer;
+ }
+
+ path.asdcs-diagram-message {
+ pointer-events: none;
+ stroke: $asdcsSVGStrokeColorMessage;
+ stroke-width: $asdcsSVGStrokeWidth;
+ fill: none;
+ &.asdcs-diagram-message-response {
+ stroke-dasharray: 30, 10;
+ }
+ }
+
+ rect.asdcs-diagram-message-bg {
+ stroke: none;
+ fill: $asdcsColorWhite;
+ }
+
+ &.asdcs-active {
+ path.asdcs-diagram-message {
+ stroke: $asdcsSVGStrokeActiveColor;
+ stroke-width: $asdcsSVGStrokeActiveWidth;
+ }
+ rect.asdcs-diagram-message-bg {
+ // Not FF:
+ // filter: url(#asdcsSvgHighlight);
+ }
+ rect.asdcs-diagram-message-label-bg {
+ fill: #fafafa;
+ }
+ }
+
+ .asdcs-diagram-notes-container {
+ display: none;
+ path {
+ fill:none;
+ stroke: $asdcsSVGStrokeColor;
+ stroke-width: 6px;
+ }
+ text {
+ font-weight: bold;
+ font-size: 40px;
+ text-anchor: start;
+ }
+ }
+
+ &.asdcs-active {
+ .asdcs-diagram-notes-container {
+ display: block;
+ }
+ }
+
+ }
+
+ g.asdcs-diagram-lifeline-container {
+
+ rect.asdcs-diagram-lifeline-heading-box {
+ stroke: $asdcsColorThree;
+ stroke-width: $asdcsSVGStrokeWidth;
+ fill: $asdcsColorWhite;
+ cursor: pointer;
+ }
+
+ text.asdcs-diagram-lifeline-heading-label {
+ font-size: 36px;
+ pointer-events: none;
+ }
+
+ path.asdcs-diagram-lifeline-selectable {
+ stroke: $asdcsSVGSelectableColor;
+ stroke-width: $asdcsSVGSelectableWidth;
+ opacity: $asdcsSVGSelectableOpacity;
+ cursor: pointer;
+ }
+
+ path.asdcs-diagram-lifeline {
+ pointer-events: none;
+ fill: $asdcsSVGStrokeColor;
+ stroke: $asdcsSVGStrokeColorLifeline;
+ stroke-width: $asdcsSVGStrokeWidth;
+ stroke-dasharray: 40, 10;
+ }
+
+ rect.asdcs-diagram-lifeline-bg {
+ stroke: none;
+ fill:white;
+ }
+
+ &.asdcs-active {
+ rect.asdcs-diagram-lifeline-heading-box, path.asdcs-diagram-lifeline {
+ stroke: $asdcsSVGStrokeActiveColor;
+ stroke-width: $asdcsSVGStrokeActiveWidth;
+ }
+ rect {
+ // Not supported by FF:
+ // filter:url(#asdcsSvgHighlight);
+ }
+ }
+ }
+
+ .asdcs-diagram-fragment {
+
+ rect {
+ stroke: $asdcsSVGStrokeColorFragment;
+ stroke-width: $asdcsSVGStrokeWidth;
+ fill: none;
+ }
+
+ rect.asdcs-diagram-fragment-guard-bg {
+ pointer-events: none;
+ stroke: none;
+ fill: $asdcsColorWhite;
+ fill-opacity: 0.75;
+ }
+
+ text {
+ font-size: 28pt;
+ text-anchor: start;
+ &.asdcs-diagram-fragment-guard {
+ fill: #888;
+ }
+ }
+
+ path {
+ stroke: $asdcsSVGStrokeColor;
+ stroke-width: $asdcsSVGStrokeWidth;
+ fill: none;
+ }
+ }
+
+ #asdcsDiagramArrowOpen, #asdcsDiagramArrowClosed, #asdcsDiagramArrowSolid {
+ stroke: $asdcsSVGStrokeColor;
+ }
+
+ #asdcsDiagramArrowOpen {
+ fill:none;
+ }
+
+ #asdcsDiagramArrowClosed {
+ fill:white;
+ }
+
+ #asdcsDiagramArrowSolid {
+ fill:$asdcsSVGStrokeColor;
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-diagram.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-diagram.scss
new file mode 100644
index 0000000000..fe67c9059e
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-diagram.scss
@@ -0,0 +1,206 @@
+.asdcs-control {
+
+ div.asdcs-diagram {
+
+ width: auto;
+ height: 100%;
+ overflow: hidden;
+
+ @include noselect();
+
+ div.asdcs-diagram-name {
+ height: 40px;
+ line-height: 40px;
+ font-size: 24px;
+ text-align: center;
+ background-color: $asdcsColorOneLight;
+ @include noselect();
+ }
+
+ div.asdcs-diagram-svg {
+ height: 100%;
+ }
+
+ div.asdcs-diagram-popup {
+
+ @include drop-shadow();
+
+ $asdcsDiagramPopupIconPaneSize: 80px;
+ $asdcsDiagramPopupHeaderHeight: 40px;
+ $asdcsDiagramPopupFooterHeight: $asdcsDiagramPopupHeaderHeight;
+ $asdcsDiagramPopupHeight: 200px;
+ $asdcsDiagramPopupWidth: 320px;
+ $asdcsDiagramPopupBodyHeight: $asdcsDiagramPopupHeight - ($asdcsDiagramPopupHeaderHeight + $asdcsDiagramPopupFooterHeight);
+ $asdcsDiagramPopupNotesIconSize: 64px;
+
+ position: absolute;
+ height: $asdcsDiagramPopupHeight;
+ width: $asdcsDiagramPopupWidth;
+ text-overflow: ellipsis;
+ background: $asdcsColorOneLight;
+ border: 1px solid $asdcsColorWhitish;
+ border-radius: $asdcsPopupBorderRadius;
+
+ .asdcs-diagram-popup-header {
+ font-weight: bold;
+ font-size: 120%;
+ padding: 4px 10px;
+ height: $asdcsDiagramPopupHeaderHeight;
+ line-height: $asdcsDiagramPopupHeaderHeight;
+ }
+
+ .asdcs-diagram-popup-body {
+
+ height: $asdcsDiagramPopupBodyHeight;
+ overflow: hidden;
+
+ .asdcs-icon-popup {
+ display: table-cell;
+ text-align: center;
+ vertical-align: middle;
+ height: $asdcsDiagramPopupBodyHeight;
+ width: $asdcsDiagramPopupIconPaneSize;
+ min-width: $asdcsDiagramPopupIconPaneSize;
+ svg {
+ height: $asdcsDiagramPopupNotesIconSize;
+ width: $asdcsDiagramPopupNotesIconSize;
+ .asdcs-icon {
+ fill: $asdcsColorOneDark;
+ }
+ }
+ }
+
+ .asdcs-diagram-notes {
+ display: table-cell;
+ width: 100%;
+ vertical-align: middle;
+ overflow: hidden;
+ text-align: left;
+ padding: 0 15px 5px 0;
+ margin-right: 10px;
+ }
+ }
+
+ .asdcs-diagram-popup-footer {
+ height: 0;
+ }
+
+ $asdcsPopupBorderColor1: rgba(242, 242, 242, 0);
+ $asdcsPopupBorderColor2: rgba(211, 211, 211, 0);
+
+ &.asdcs-diagram-popup-topleft {
+
+ &:after, &:before {
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+ pointer-events: none;
+ bottom: 100%;
+ left: 50px;
+ }
+
+ &:after {
+ border-color: $asdcsPopupBorderColor1;
+ border-width: 6px;
+ border-bottom-color: $asdcsColorOneLight;
+ margin-left: -6px;
+ }
+
+ &:before {
+ border-color: $asdcsPopupBorderColor2;
+ border-width: 7px;
+ border-bottom-color: $asdcsColorOneLight;
+ margin-left: -7px;
+ }
+ }
+
+ &.asdcs-diagram-popup-topright {
+
+ &:after, &:before {
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+ pointer-events: none;
+ bottom: 100%;
+ right: 50px;
+ }
+
+ &:after {
+ border-color: $asdcsPopupBorderColor1;
+ border-width: 6px;
+ border-bottom-color: $asdcsColorOneLight;
+ margin-left: -6px;
+ }
+
+ &:before {
+ border-color: $asdcsPopupBorderColor2;
+ border-width: 7px;
+ border-bottom-color: $asdcsColorOneLight;
+ margin-left: -7px;
+ }
+ }
+
+ &.asdcs-diagram-popup-bottomleft {
+
+ &:after, &:before {
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+ pointer-events: none;
+ top: 100%;
+ left: 50px;
+ }
+
+ &:after {
+ border-color: $asdcsPopupBorderColor1;
+ border-width: 6px;
+ border-top-color: $asdcsColorOneLight;
+ margin-left: -6px;
+ }
+
+ &:before {
+ border-color: $asdcsPopupBorderColor2;
+ border-width: 7px;
+ border-top-color: $asdcsColorOneLight;
+ margin-left: -7px;
+ }
+ }
+
+ &.asdcs-diagram-popup-bottomright {
+
+ &:after, &:before {
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+ pointer-events: none;
+ top: 100%;
+ right: 50px;
+ }
+
+ &:after {
+ border-color: rgba(242, 242, 242, 0);
+ border-width: 6px;
+ border-top-color: $asdcsColorOneLight;
+ margin-left: -6px;
+ }
+
+ &:before {
+ border-color: rgba(211, 211, 211, 0);
+ border-width: 7px;
+ border-top-color: $asdcsColorOneLight;
+ margin-left: -7px;
+ }
+ }
+ }
+
+ @import 'sequencer-diagram-svg.scss';
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-dialog.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-dialog.scss
new file mode 100644
index 0000000000..89a6412dd0
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-dialog.scss
@@ -0,0 +1,159 @@
+/*
+<div class="asdcs-dialog">
+<div class="asdcs-dialog-overlay"></div>
+<div class="asdcs-dialog-header"></div>
+<div class="asdcs-dialog-body"></div>
+<div class="asdcs-dialog-buttonbar">
+<button class="asdcs-dialog-button-cancel">Cancel</button>
+<button class="asdcs-dialog-button-ok">OK</button>
+</div>
+</div>
+*/
+
+.asdcs-control {
+
+ $asdcsDialogIconSize: 70px;
+ $asdcsDialogWidth: 400px;
+
+ .asdcs-overlay {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ z-index: 5;
+ background-color: white;
+ opacity: 0.25;
+ pointer-events: all;
+ }
+
+ .asdcs-dialog {
+
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ width: $asdcsDialogWidth;
+ margin-left: -($asdcsDialogWidth/2);
+ height: 300px;
+ margin-top: -150px;
+ background: $asdcsColorOneLight;
+ border: 1px solid $asdcsColorWhitish;
+ border-radius: $asdcsPopupBorderRadius;
+ z-index: 10;
+
+ @include drop-shadow();
+
+ .asdcs-dialog-header {
+ position: absolute;
+ height: 60px;
+ line-height: 40px;
+ width: 100%;
+ box-sizing: border-box;
+ font-size: 14px;
+ font-weight: bold;
+ padding: 10px 15px;
+ }
+
+ .asdcs-dialog-close {
+ position: absolute;
+ top: 15px;
+ right: 15px;
+ height: $asdcsSmallIconSize;
+ width: $asdcsSmallIconSize;
+ fill: $asdcsColorGrey;
+ cursor: pointer;
+ &:hover {
+ fill: $asdcsColorEmphasis;
+ }
+ }
+
+ .asdcs-dialog-buttonbar {
+
+ position: absolute;
+ height: 50px;
+ width: 100%;
+ bottom: 0;
+ //background-color: $asdcsColorOne;
+ text-align: right;
+
+ button {
+ width: 75px;
+ border-radius: 4px;
+ border: none;
+ background-color: $asdcsColorTwo;
+ color: $asdcsColorWhite;
+ padding: 7px 10px;
+ margin: 10px 10px 10px 0px;
+ &:hover {
+ background-color: $asdcsColorTwoLight;
+ }
+ }
+ }
+
+ .asdcs-dialog-icon {
+ position: absolute;
+ top: 80px;
+ left: 20px;
+ height: $asdcsDialogIconSize;
+ width: $asdcsDialogIconSize;
+ pointer-events: none;
+ fill: $asdcsColorOneDark;
+
+ svg {
+ display: none;
+ }
+
+ &.asdcs-icon-question {
+ svg.asdcs-icon-question {
+ display: block;
+ }
+ }
+
+ &.asdcs-icon-exclaim {
+ svg.asdcs-icon-exclaim {
+ display: block;
+ }
+ }
+
+ &.asdcs-icon-info {
+ svg.asdcs-icon-info {
+ display: block;
+ }
+ }
+
+ &.asdcs-icon-edit {
+ svg.asdcs-icon-edit {
+ display: block;
+ }
+ }
+ }
+
+ .asdcs-dialog-message {
+ position: absolute;
+ padding: 10px;
+ top: 90px;
+ height: 100px;
+ left: 100px;
+ width: $asdcsDialogWidth - 120px;
+ display: table-cell;
+ vertical-align: middle;
+ word-wrap: break-word;
+ text-overflow: ellipsis;
+ }
+
+ .asdcs-dialog-text {
+ position:absolute;
+ padding: 10px;
+ top:60px;
+ height: 150px;
+ left:100px;
+ width: $asdcsDialogWidth - 130px;
+ textarea {
+ height:100%;
+ width:100%;
+ resize: none;
+ }
+ }
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-editor.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-editor.scss
new file mode 100644
index 0000000000..da35ba9182
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-editor.scss
@@ -0,0 +1,125 @@
+.asdcs-control {
+
+ div.asdcs-editor {
+
+ $asdcsEditorResizeWidth: 6px;
+ $asdcsEditorToolbarPadding: 4px;
+
+ box-sizing: border-box;
+ float: left;
+ height: 100%;
+ width: $asdcsEditorWidth;
+ overflow-x: hidden;
+ overflow-y: auto;
+ position: relative;
+ padding-right: $asdcsEditorResizeWidth;
+
+ div.asdcs-editor-toolbar {
+
+ display: none;
+
+ height: 40px;
+ width: 100%;
+
+ background-color: $asdcsColorOneDark;
+ text-align: center;
+
+ .asdcs-editor-toolbar-demo {
+ padding: $asdcsEditorToolbarPadding;
+ display: inline;
+ float: left;
+ }
+
+ .asdcs-editor-toolbar-toggle {
+ padding: $asdcsEditorToolbarPadding;
+ display: inline;
+ float: right;
+ }
+
+ button {
+
+ &.asdcs-button-mode {
+
+ padding-left: 8px;
+ padding-right: 8px;
+
+ &.asdcs-button-toggle-left {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ margin-right: -4px;
+ }
+
+ &.asdcs-button-toggle-right {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ margin-left: -4px;
+ }
+
+ &.asdcs-button-toggle-center {
+ border-radius: 0;
+ border-right: 1px solid lighten($asdcsColorOneDark, 3%);
+ border-left: 1px solid lighten($asdcsColorOneDark, 3%);
+ }
+
+ &.asdcs-active {
+ background-color: $asdcsColorButtonBGHover;
+ }
+
+ &:hover {
+ border-color: transparent;
+ @include transition(border-color $asdcsTransitionTime ease);
+ }
+ }
+
+ svg {
+ height: $asdcsSmallIconSize;
+ width: $asdcsSmallIconSize;
+ fill: $asdcsColorWhitish;
+ }
+ }
+ }
+
+ div.asdcs-editor-content {
+
+ height: 100%;
+ width: 100%;
+ overflow-x: hidden;
+ overflow-y: auto;
+
+ div.asdcs-editor-code {
+ display:none;
+ height: 100%;
+ width: 100%;
+ background-color: $asdcsColorWhitish;
+ textarea {
+ height: 100%;
+ }
+ .CodeMirror {
+ height: 100%;
+ }
+ }
+
+ div.asdcs-editor-designer {
+ height: 100%;
+ width: 100%;
+
+ .asdcs-designer-accordion {
+ height: 100%;
+ }
+ }
+
+ }
+
+ div.asdcs-editor-resize-handle {
+ background-color: $asdcsColorOne;
+ position: absolute;
+ top: 0;
+ right: 0;
+ height: 100%;
+ width: $asdcsEditorResizeWidth;
+ cursor: e-resize;
+ @include drop-shadow();
+
+ }
+ }
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-standalone.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-standalone.scss
new file mode 100644
index 0000000000..bd13af16e0
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sequencer-standalone.scss
@@ -0,0 +1,2 @@
+@import 'sequencer-common.scss';
+@import 'sequencer-diagram-svg.scss';
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites-raster.scss b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites-raster.scss
new file mode 100644
index 0000000000..f23295399b
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites-raster.scss
@@ -0,0 +1,30 @@
+
+@mixin sprite-width($sprite) {
+ width: nth($sprite, 3);
+}
+@mixin sprite-height($sprite) {
+ height: nth($sprite, 4);
+}
+@function sprite-width($sprite) {
+ @return nth($sprite, 3);
+}
+@function sprite-height($sprite) {
+ @return nth($sprite, 4);
+}
+@mixin sprite-position($sprite) {
+ $sprite-offset-x: nth($sprite, 1);
+ $sprite-offset-y: nth($sprite, 2);
+ background-position: $sprite-offset-x $sprite-offset-y;
+}
+@mixin sprite($sprite, $display: block) {
+ @include sprite-position($sprite);
+ background-repeat: no-repeat;
+ overflow: hidden;
+ display: $display;
+ @include sprite-width($sprite);
+ @include sprite-height($sprite);
+}
+
+.icon {
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFQAAAAmCAYAAABagbwLAAAIkklEQVRoBe2ZCVAUVxrH/yDnMAOOHFFYd1eQ04HgGsEIjjEql3jEAo9UUopuorgeAUUUZY1urMRdSzdeSarcrJLVqKuwJhpNxHAKi6igEUE8QPAWhDkYbtmvH844gyAdHavWqn5V3f3e9773ve5ff+97X8+YdHR0QCjGI2BqPFOCJY6AANTIfiAANTJQs672/APeFIJqVyjPaBefzjfR7xY8VJ+GEeoCUCNA1DchANWnYYS6ANQIEPVNCED1aRih/soAtbKyMsLjvnwTrwTQ37u64S9r12LRvDkvn8gLzvBUHvqC9l7KcJHIBt7eXjBt07wU+8Y0+kp4KPfAjx49Qgcd/+/lV3mot7cPvDw9YC+VoqFBjfLycpwtPq97RheXgXBy6Iei8+chk/nB30+GPvQdUUzt8xdLmJ589Gi4uw6CUlGPX0hWVn5FN15bCQwYAW8vD7S3teDChV8AczP09KOYn+/r8JX5wNrSEpU3KpCekaU189Q1IjwcLgP6Q0FzXyq9jIuXLhnomJmZYfzYcXBx7g+NRoMrV66g8FyRgU5vDd5AFy/+CDHvTUcTTaRQqSEWiyG2EWH/vm/x6aYtbJ7Zc+cjasJo/PRzJkYMD0BzcxPs+kphSUC+3rUbnt4y+Ms8oW7QwNHRCY9am5D88TocS89g453phSQmJGD0yOGor69Ha1sb+tr1RVHxOVhbWUD/m9jRqT+WxsUhbKwcSqUCzS2tcHRwwN3bt7Bx89+RnpWre/aJE6dgefwSSKwtcK+mhu5dAhuRNf59YB/Wb/yc6Y15ezySVyyDnViE2ocPYWktgp1EjBMnjiFh1Tqdrd4qvIC+GTwGcwhmdmYG9h5Mg0rdAKnUHjExszEhPJS8IhuFRcUMoIlJH3iSB26ih7paUYkBzi5ITlqJObNnIYvGr1i9BnX1CoLrg8Sl8ZgQMk4HNHbBQgbzW3pJ6Zk5aGlpg4enJ+bMeh9O9v3IS58gjZ0fy2Ae2L8fJ7NzoWlqhqenN+bNjcG6NatR/UEsLl+rQEDgSCQui0PNnRv49OtvcOPWbYhEYsyYPh3R02ag4vp17E39HjGzZqG1UYU1mzehsuomRDZihIWFY2pkON7JK0Da0R97Y8n6eQGVSGyQk5ONvQcOouhiKUxMTNBBN+vq4YlhPu/DwsLi8WS0vh+1ITU1FYeP/sBkJbSswiMmYoTfYBw4lIpTBWeY/GJJCSIjJqBfv76s/ZrzQEwcL8fpgnzsStmDhqYWNk9FZSVMTM2wOmHJ4zlAkIfQg4YgJysDu/bsg4o8nivXrl2HNW1g8Qs/RPTkCHyyaTuCgoIgJs9cve0LZObm62xwHi0WWcLN1ZXJHBzs0dxQi3RaXU3NzUzGLfnamvu4+6BGN663Ci+gPx07Au7gimyIL9wGu8LHywuTIiPQ2NRkMEcDhYTK6psGMrVGBYVSBaWqwUDeSF5lZdH5Y43/0GGsr7S0FAq1BpYUE7nCbUbcg925X8sAc7LfDeqEkH+6EEpaLX369OHE4AJtQeEZPKiJQmBgAAm2w4eyg6rrV2m1VDEV7enC+XOYt+CctomsnFzMnBqJk8e+R86pPBSeOYvDR37A9h07dDp8KryAcoaWJ6zAlMhQWFA85N6gWq0C5z1uA527mefJ0uyms1uRhJYYVxQqFYicTodbDZrGRjqaoJXaSiSsv4FkBoV0lSolWltbodXhrvUq8rJ7dw1UuzY2fLaevLEGkyNCEBwcjJCQECSvSqIVk4fN275C6eXyrkO6bfMCmpi0BjOnhNFSPoQjx0/g1u07qK2rx+SpUUj+aH63hn+t8CHtvFyxs5VQevTkhXBx09ramuKeSLcpKWgT4oqY5HrsWYy1k9jBnEKQUvmA6XAryI42UFuJLR7W1TGZ9iSXy4H2VmSf6gwFO3d+Be7woljM5b2jgoPwtjwIi1uaEbs0STvsmVfTZ/Y+7hw7ehSqblTin7tTUFJWznZpC3Nz+A6RoY12Ym5ZvmjJSj/OTPjJZJDaiXV229rb4e7ujgGOUt2mdLPqBrgZR40MpAzCHO2kw91Dc0sLAoe/QRuYFPn5/2X2Sul+B7l5wsdjsMEtvhEYRJvXnxE9KYzJv0lJwcyod1i97HIp0v6Thvhly2jPKKOw4W0w9lkNXkAVSiWcnJwwhnJIW0olXFxcsHjRYkwJG0Ne08Fkz5qET197exv2HDqCocMCELcwFr/9jTPzyojwCPzpw7mdJh47blnpRRz67jhGBMmRGL+I6XJp3LToaZQRvEu7tRpbd6awMfn5eWikbGHVyuUY9xZ5JJVhNEfsH2PQlzbbvQfSmMxGbIsF8z5A9JRJrM2dplEW4OXhjivXrulkvVV4LfmtO77Elg1rER8fjzjK/bi41qhpwL/27sd7707Hhs/W4ccAOYtxXF/Xwkm6lZOuvvrfNqzHACcHhFK6EhLa6Tm00+AqPVB7mz1MTZ/YXv/JWvYRMT4kDOPGh7IpuTkUdbVYkvQxS+04YXbWz9j25UD2O8DGv25gXq69l+3btiD/bDEb+/nWbViXvBKrKMVLWrlCZ+/+vdvYsXM3a/M5mejndtyAnv5Tcvfwwhh5MCQ2Nrh1sxr7KAXiyowZMyG1scAX/9gNGX21vOYgxcmMTNanPfn7/4GSZBHbSbUy7hoQEAgzkw7kFZzWF0Mufwv+vkMIdgdK6GsqPTOL4tkoaNRKgy8zbtDIkcEY+rov2yyrq6twMO2wgS1tw4k+BMJDQ+DQTwqVSoHcvHxcKrus7dZdo6Oi6EtpADoojFRUXsd3RztDkU6hS6Xrf0q8gXaxIzQfE+gKlFcMFejxJyAA5c+Kl6YAlBcm/koCUP6seGkKQHlh4q8kAOXPipemAJQXJv5KAlD+rHhpPpXY8xolKPVIQPDQHtE8X4cA9Pm49ThKANojmufr+B95nv72O1nccAAAAABJRU5ErkJggg==');
+}
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.css.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.css.svg
new file mode 100644
index 0000000000..ce02a1a41e
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.css.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="1000" height="23000" viewBox="0 0 1000 23000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="blank"/><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--collapsed" y="1000"><path d="M200.102 100L800 500.26 200 900z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--delete" y="2000"><path d="M500 98.344C278.768 98.344 98.344 278.768 98.344 500S278.768 901.656 500 901.656 901.656 721.232 901.656 500 721.232 98.344 500 98.344zm0 100c167.188 0 301.656 134.468 301.656 301.656 0 167.188-134.468 301.656-301.656 301.656-167.188 0-301.656-134.468-301.656-301.656 0-167.188 134.468-301.656 301.656-301.656zm-154.438 97.25a50.005 50.005 0 0 0-34.843 85.844L429.28 500 310.72 618.563a50.006 50.006 0 1 0 70.719 70.718L500 570.72 618.563 689.28a50.006 50.006 0 1 0 70.718-70.718L570.72 500 689.28 381.437a50.006 50.006 0 1 0-70.718-70.718L500 429.28 381.437 310.72a50.005 50.005 0 0 0-35.875-15.125z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--download" y="3000"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm-26.357 243.536h45.714a11.404 11.404 0 0 1 11.429 11.428V472.25h91.428l-63.25 92.571-63.214 92.572-63.25-92.572-63.25-92.571h92.964V354.964a11.404 11.404 0 0 1 11.429-11.428z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--edit" y="4000"><path d="M644.351 150l-87.07 105.56 155.65 132.863L800 282.863 644.351 150zM528.258 290.747l-261.21 316.68 155.65 132.863 261.209-316.68-155.649-132.863zm-134.584 484.73L237.862 642.812 200 850l193.674-74.523z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--exclaim" y="5000"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm-54.469 217.719h108.844l-12 271.75H457.5l-11.969-271.75zm1.813 314.062H552.53v67.688H447.344V631.78z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--expanded" y="6000"><path d="M900 250.102L499.74 850 100 250z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--fragment-default" y="7000"/><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--fragment-start" y="8000"><path d="M100 100v800h150V700h450V250h200V100H100zm150 150h300v300H250V250z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--fragment-stop" y="9000"><path d="M900 900V100H700v600H100v200h800z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--handle" y="10000"><path d="M177.397 100.008a76.318 80.006 0 1 0 0 159.997h645.206a76.318 80.006 0 1 0 0-159.997H177.397zm0 319.994a76.318 80.006 0 1 0 0 159.996h645.206a76.318 80.006 0 1 0 0-159.996H177.397zm0 319.993a76.318 80.006 0 1 0 0 159.997h645.206a76.318 80.006 0 1 0 0-159.997H177.397z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--info" y="11000"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm-49.469 200.531h98.938v70H450.53v-70zm2.594 111h93.75V699.47h-93.75V411.53z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--notes" y="12000"><path d="M200 100v800h600V442.857H500V100H200zm350 1.821v283.893h248.375L550 101.821z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--occurrence-default" y="13000"><path d="M300 100h400v800H300z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--occurrence-start" y="14000"><path d="M100 100v800h375V100H100zm425 400v400h375V500H525z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--occurrence-stop" y="15000"><path d="M100 100v800h375V100H100zm425 0v400h375V100H525z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--open" y="16000"><path d="M100 200v459.155h26.898L244.957 299.57h484.86V200H100zm170.182 140.845L119.452 800H749.27L900 340.845H270.182z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--plus" y="17000"><path d="M443.75 200v243.75H200v112.5h243.75V800h112.5V556.25H800v-112.5H556.25V200h-112.5z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--question" y="18000"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm-9.375 200.531c44.104 0 79.108 9.542 105 28.625 25.891 19.084 38.843 44.03 38.844 74.844 0 17.683-2.706 33.375-8.063 47.031-5.178 13.481-12.576 25.209-22.218 35.188-9.643 9.98-21.243 18.903-34.813 26.781-13.392 7.879-28.568 15.054-45.531 21.531v59.875h-94.282v-88.5c12.678-3.326 24.104-6.748 34.282-10.25 10.356-3.501 21.156-9.184 32.406-17.062 10.535-7.003 18.764-15.127 24.656-24.406 6.071-9.28 9.094-19.801 9.094-31.532 0-17.507-5.8-29.927-17.406-37.281-11.428-7.528-27.609-11.312-48.5-11.313-12.857 0-27.408 2.73-43.656 8.157-16.071 5.427-30.796 12.421-44.188 21h-10.719v-80.094c11.428-4.727 29.033-9.641 52.781-14.719 23.75-5.252 47.85-7.874 72.313-7.875zm-67.5 329.594h108.219v69.344H423.125v-69.344z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--save" y="19000"><path d="M100 100v800h800V236.844c-20.581-.151-37.219-16.883-37.219-37.5s16.638-37.349 37.219-37.5V100H100zm400 300c55.228 0 100 44.772 100 100s-44.772 100-100 100-100-44.772-100-100 44.772-100 100-100zm0 250c22.16 0 40 17.84 40 40v120c0 22.16-17.84 40-40 40s-40-17.84-40-40V690c0-22.16 17.84-40 40-40z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--settings" y="20000"><path style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Sans" d="M442.857 100a28.509 28.509 0 0 0-28.571 28.571v78.036a304.473 304.473 0 0 0-61.036 25.429l-55.286-55.286a28.493 28.493 0 0 0-40.393 0l-80.821 80.821a28.493 28.493 0 0 0 0 40.393l55.179 55.179a304.13 304.13 0 0 0-25.643 61.143H128.57A28.509 28.509 0 0 0 100 442.857v114.286a28.509 28.509 0 0 0 28.571 28.571h77.715a303.927 303.927 0 0 0 25.643 61.143l-55.179 55.179a28.493 28.493 0 0 0 0 40.393l80.821 80.821a28.493 28.493 0 0 0 40.393 0l55.286-55.286a304.544 304.544 0 0 0 61.036 25.465v78A28.509 28.509 0 0 0 442.857 900h114.286a28.509 28.509 0 0 0 28.571-28.571v-78.036a304.537 304.537 0 0 0 61-25.464l55.322 55.321a28.493 28.493 0 0 0 40.393 0l80.821-80.821a28.493 28.493 0 0 0 0-40.393l-55.179-55.179a303.863 303.863 0 0 0 25.643-61.143h77.715A28.509 28.509 0 0 0 900 557.143V442.857a28.509 28.509 0 0 0-28.571-28.571h-77.715a304.067 304.067 0 0 0-25.643-61.143l55.179-55.179a28.493 28.493 0 0 0 0-40.393l-80.821-80.821a28.493 28.493 0 0 0-40.393 0l-55.322 55.321a304.488 304.488 0 0 0-61-25.464v-78.036A28.509 28.509 0 0 0 557.143 100H442.857zM500 365.286c74.994 0 134.321 59.107 134.321 134.714S574.994 634.679 500 634.679 365.679 575.607 365.679 500 425.006 365.286 500 365.286z" font-weight="400" color="#000" overflow="visible" font-family="Sans"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--upload" y="21000"><path d="M500 900c-220.914 0-400-179.086-400-400s179.086-400 400-400 400 179.086 400 400-179.086 400-400 400zm-26.357-243.536h45.714a11.404 11.404 0 0 0 11.429-11.428V527.75h91.428l-63.25-92.571-63.214-92.572-63.25 92.572-63.25 92.571h92.964v117.286a11.404 11.404 0 0 0 11.429 11.428z"/></svg><svg width="1000" height="1000" viewBox="0 0 1000 1000" id="icon--validate" y="22000"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm179.719 200c8.054 0 13.379.7 15.968 2.094 2.877 1.395 4.313 3.206 4.313 5.437 0 3.627-4.158 10.332-12.5 20.094-97.232 113.25-187.277 232.92-270.125 359C411.622 695.551 399.835 700 382 700c-18.123 0-28.923-.826-32.375-2.5-8.63-3.626-18.712-22.31-30.219-56.063C306.461 604.06 300 580.61 300 571.125c0-10.042 8.765-19.797 26.313-29.281 10.643-6.137 20.157-9.219 28.5-9.219 9.78 0 17.259 7.817 22.437 23.438 10.068 29.567 17.247 44.343 21.563 44.343 3.451 0 6.891-2.51 10.343-7.531 70.478-109.902 135.934-198.717 196.344-266.5C621.034 308.802 645.774 300 679.719 300z"/></svg></svg> \ No newline at end of file
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.defs.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.defs.svg
new file mode 100644
index 0000000000..81d66d69d0
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.defs.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><svg viewBox="0 0 1000 1000" id="blank"/><svg viewBox="0 0 1000 1000" id="icon--collapsed"><path d="M200.102 100L800 500.26 200 900z"/></svg><svg viewBox="0 0 1000 1000" id="icon--delete"><path d="M500 98.344C278.768 98.344 98.344 278.768 98.344 500S278.768 901.656 500 901.656 901.656 721.232 901.656 500 721.232 98.344 500 98.344zm0 100c167.188 0 301.656 134.468 301.656 301.656 0 167.188-134.468 301.656-301.656 301.656-167.188 0-301.656-134.468-301.656-301.656 0-167.188 134.468-301.656 301.656-301.656zm-154.438 97.25a50.005 50.005 0 0 0-34.843 85.844L429.28 500 310.72 618.563a50.006 50.006 0 1 0 70.719 70.718L500 570.72 618.563 689.28a50.006 50.006 0 1 0 70.718-70.718L570.72 500 689.28 381.437a50.006 50.006 0 1 0-70.718-70.718L500 429.28 381.437 310.72a50.005 50.005 0 0 0-35.875-15.125z"/></svg><svg viewBox="0 0 1000 1000" id="icon--download"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm-26.357 243.536h45.714a11.404 11.404 0 0 1 11.429 11.428V472.25h91.428l-63.25 92.571-63.214 92.572-63.25-92.572-63.25-92.571h92.964V354.964a11.404 11.404 0 0 1 11.429-11.428z"/></svg><svg viewBox="0 0 1000 1000" id="icon--edit"><path d="M644.351 150l-87.07 105.56 155.65 132.863L800 282.863 644.351 150zM528.258 290.747l-261.21 316.68 155.65 132.863 261.209-316.68-155.649-132.863zm-134.584 484.73L237.862 642.812 200 850l193.674-74.523z"/></svg><svg viewBox="0 0 1000 1000" id="icon--exclaim"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm-54.469 217.719h108.844l-12 271.75H457.5l-11.969-271.75zm1.813 314.062H552.53v67.688H447.344V631.78z"/></svg><svg viewBox="0 0 1000 1000" id="icon--expanded"><path d="M900 250.102L499.74 850 100 250z"/></svg><svg viewBox="0 0 1000 1000" id="icon--fragment-default"/><svg viewBox="0 0 1000 1000" id="icon--fragment-start"><path d="M100 100v800h150V700h450V250h200V100H100zm150 150h300v300H250V250z"/></svg><svg viewBox="0 0 1000 1000" id="icon--fragment-stop"><path d="M900 900V100H700v600H100v200h800z"/></svg><svg viewBox="0 0 1000 1000" id="icon--handle"><path d="M177.397 100.008a76.318 80.006 0 1 0 0 159.997h645.206a76.318 80.006 0 1 0 0-159.997H177.397zm0 319.994a76.318 80.006 0 1 0 0 159.996h645.206a76.318 80.006 0 1 0 0-159.996H177.397zm0 319.993a76.318 80.006 0 1 0 0 159.997h645.206a76.318 80.006 0 1 0 0-159.997H177.397z"/></svg><svg viewBox="0 0 1000 1000" id="icon--info"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm-49.469 200.531h98.938v70H450.53v-70zm2.594 111h93.75V699.47h-93.75V411.53z"/></svg><svg viewBox="0 0 1000 1000" id="icon--notes"><path d="M200 100v800h600V442.857H500V100H200zm350 1.821v283.893h248.375L550 101.821z"/></svg><svg viewBox="0 0 1000 1000" id="icon--occurrence-default"><path d="M300 100h400v800H300z"/></svg><svg viewBox="0 0 1000 1000" id="icon--occurrence-start"><path d="M100 100v800h375V100H100zm425 400v400h375V500H525z"/></svg><svg viewBox="0 0 1000 1000" id="icon--occurrence-stop"><path d="M100 100v800h375V100H100zm425 0v400h375V100H525z"/></svg><svg viewBox="0 0 1000 1000" id="icon--open"><path d="M100 200v459.155h26.898L244.957 299.57h484.86V200H100zm170.182 140.845L119.452 800H749.27L900 340.845H270.182z"/></svg><svg viewBox="0 0 1000 1000" id="icon--plus"><path d="M443.75 200v243.75H200v112.5h243.75V800h112.5V556.25H800v-112.5H556.25V200h-112.5z"/></svg><svg viewBox="0 0 1000 1000" id="icon--question"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm-9.375 200.531c44.104 0 79.108 9.542 105 28.625 25.891 19.084 38.843 44.03 38.844 74.844 0 17.683-2.706 33.375-8.063 47.031-5.178 13.481-12.576 25.209-22.218 35.188-9.643 9.98-21.243 18.903-34.813 26.781-13.392 7.879-28.568 15.054-45.531 21.531v59.875h-94.282v-88.5c12.678-3.326 24.104-6.748 34.282-10.25 10.356-3.501 21.156-9.184 32.406-17.062 10.535-7.003 18.764-15.127 24.656-24.406 6.071-9.28 9.094-19.801 9.094-31.532 0-17.507-5.8-29.927-17.406-37.281-11.428-7.528-27.609-11.312-48.5-11.313-12.857 0-27.408 2.73-43.656 8.157-16.071 5.427-30.796 12.421-44.188 21h-10.719v-80.094c11.428-4.727 29.033-9.641 52.781-14.719 23.75-5.252 47.85-7.874 72.313-7.875zm-67.5 329.594h108.219v69.344H423.125v-69.344z"/></svg><svg viewBox="0 0 1000 1000" id="icon--save"><path d="M100 100v800h800V236.844c-20.581-.151-37.219-16.883-37.219-37.5s16.638-37.349 37.219-37.5V100H100zm400 300c55.228 0 100 44.772 100 100s-44.772 100-100 100-100-44.772-100-100 44.772-100 100-100zm0 250c22.16 0 40 17.84 40 40v120c0 22.16-17.84 40-40 40s-40-17.84-40-40V690c0-22.16 17.84-40 40-40z"/></svg><svg viewBox="0 0 1000 1000" id="icon--settings"><path style="text-indent:0;text-align:start;line-height:normal;text-transform:none;block-progression:tb;marker:none;-inkscape-font-specification:Sans" d="M442.857 100a28.509 28.509 0 0 0-28.571 28.571v78.036a304.473 304.473 0 0 0-61.036 25.429l-55.286-55.286a28.493 28.493 0 0 0-40.393 0l-80.821 80.821a28.493 28.493 0 0 0 0 40.393l55.179 55.179a304.13 304.13 0 0 0-25.643 61.143H128.57A28.509 28.509 0 0 0 100 442.857v114.286a28.509 28.509 0 0 0 28.571 28.571h77.715a303.927 303.927 0 0 0 25.643 61.143l-55.179 55.179a28.493 28.493 0 0 0 0 40.393l80.821 80.821a28.493 28.493 0 0 0 40.393 0l55.286-55.286a304.544 304.544 0 0 0 61.036 25.465v78A28.509 28.509 0 0 0 442.857 900h114.286a28.509 28.509 0 0 0 28.571-28.571v-78.036a304.537 304.537 0 0 0 61-25.464l55.322 55.321a28.493 28.493 0 0 0 40.393 0l80.821-80.821a28.493 28.493 0 0 0 0-40.393l-55.179-55.179a303.863 303.863 0 0 0 25.643-61.143h77.715A28.509 28.509 0 0 0 900 557.143V442.857a28.509 28.509 0 0 0-28.571-28.571h-77.715a304.067 304.067 0 0 0-25.643-61.143l55.179-55.179a28.493 28.493 0 0 0 0-40.393l-80.821-80.821a28.493 28.493 0 0 0-40.393 0l-55.322 55.321a304.488 304.488 0 0 0-61-25.464v-78.036A28.509 28.509 0 0 0 557.143 100H442.857zM500 365.286c74.994 0 134.321 59.107 134.321 134.714S574.994 634.679 500 634.679 365.679 575.607 365.679 500 425.006 365.286 500 365.286z" font-weight="400" color="#000" overflow="visible" font-family="Sans"/></svg><svg viewBox="0 0 1000 1000" id="icon--upload"><path d="M500 900c-220.914 0-400-179.086-400-400s179.086-400 400-400 400 179.086 400 400-179.086 400-400 400zm-26.357-243.536h45.714a11.404 11.404 0 0 0 11.429-11.428V527.75h91.428l-63.25-92.571-63.214-92.572-63.25 92.572-63.25 92.571h92.964v117.286a11.404 11.404 0 0 0 11.429 11.428z"/></svg><svg viewBox="0 0 1000 1000" id="icon--validate"><path d="M500 100c-220.914 0-400 179.086-400 400s179.086 400 400 400 400-179.086 400-400-179.086-400-400-400zm179.719 200c8.054 0 13.379.7 15.968 2.094 2.877 1.395 4.313 3.206 4.313 5.437 0 3.627-4.158 10.332-12.5 20.094-97.232 113.25-187.277 232.92-270.125 359C411.622 695.551 399.835 700 382 700c-18.123 0-28.923-.826-32.375-2.5-8.63-3.626-18.712-22.31-30.219-56.063C306.461 604.06 300 580.61 300 571.125c0-10.042 8.765-19.797 26.313-29.281 10.643-6.137 20.157-9.219 28.5-9.219 9.78 0 17.259 7.817 22.437 23.438 10.068 29.567 17.247 44.343 21.563 44.343 3.451 0 6.891-2.51 10.343-7.531 70.478-109.902 135.934-198.717 196.344-266.5C621.034 308.802 645.774 300 679.719 300z"/></svg></defs></svg> \ No newline at end of file
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.png b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.png
new file mode 100644
index 0000000000..546a71c681
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites.png
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/amdocs.png b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/amdocs.png
new file mode 100644
index 0000000000..f560f5be17
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/amdocs.png
Binary files differ
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/request-async.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/request-async.svg
new file mode 100644
index 0000000000..11c5086198
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/request-async.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="request-async.svg">
+ <metadata
+ id="metadata9">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs7" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="1029"
+ id="namedview5"
+ showgrid="false"
+ inkscape:zoom="0.944"
+ inkscape:cx="297.24147"
+ inkscape:cy="436.65307"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1" />
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 480.40625 246.34375 L 480.40625 366.90625 L 480.40625 372.8125 L 532.90625 403.96875 L 610.59375 450 L 130.9375 450 L 100 450 L 100 480.9375 L 100 519.0625 L 100 550 L 130.9375 550 L 609.0625 550 L 532.90625 595.15625 L 480.40625 626.3125 L 480.40625 632.21875 L 480.40625 752.84375 L 583.0625 689.5625 L 798.40625 556.84375 L 891.4375 499.5 L 798.375 442.1875 L 583.0625 309.5625 L 480.40625 246.34375 z "
+ id="path3762" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/request-sync.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/request-sync.svg
new file mode 100644
index 0000000000..d7410035a4
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/request-sync.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="request-sync.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ id="rect2996"
+ d="m 100,450 0,43.5 0,13 0,43.5 43.5,0 513,0 43.5,0 0,-43.5 0,-13 0,-43.5 -43.5,0 -513,0 -43.5,0 z m 402.17474,-203.12882 0,120.47069 0,265.32548 0,120.49969 L 599.92483,692.9172 815.24655,560.23996 913.05094,499.93213 815.2194,439.68228 599.89767,307.06303 502.17474,246.87118 z m 130.33345,240.94139 19.74009,12.14855 -19.74009,12.17755 0,-24.3261 z" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/response.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/response.svg
new file mode 100644
index 0000000000..3429077f21
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/arrow/response.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="response.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ id="rect3773-40"
+ d="m 908.375,450 0,35.71875 0,28.5625 0,35.71875 -35.71875,0 -28.5625,0 -35.71875,0 0,-35.71875 0,-28.5625 0,-35.71875 35.71875,0 28.5625,0 35.71875,0 z m -350,0 0,35.71875 0,28.5625 0,35.71875 -35.71875,0 -28.5625,0 -35.71875,0 0,-35.71875 0,-28.5625 0,-35.71875 35.71875,0 28.5625,0 35.71875,0 z m 175,0 0,35.71875 0,28.5625 0,35.71875 -35.71875,0 -28.5625,0 -35.71875,0 0,-35.71875 0,-28.5625 0,-35.71875 35.71875,0 28.5625,0 35.71875,0 z m -222.34375,-203.1875 0,120.5625 0,5.90625 -52.5,31.15625 L 350.625,468.375 297.21875,500 l 53.375,31.625 107.9375,64 52.5,31.15625 0,5.90625 0,120.625 L 408.375,690.03125 193.03125,557.3125 100,499.96875 193.0625,442.65625 408.375,310.03125 511.03125,246.8125 z m -70.3125,252.46875 0,1.4375 -1.1875,-0.71875 1.1875,-0.71875 z"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/blank.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/blank.svg
new file mode 100644
index 0000000000..9ecbff0eca
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/blank.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg3043"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="New document 4">
+ <defs
+ id="defs5498" />
+ <sodipodi:namedview
+ inkscape:window-height="821"
+ inkscape:window-width="936"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:zoom="0.454"
+ inkscape:cx="500"
+ inkscape:cy="500"
+ inkscape:window-x="917"
+ inkscape:window-y="218"
+ inkscape:current-layer="layer1"
+ inkscape:window-maximized="0">
+ <sodipodi:guide
+ orientation="horizontal"
+ position="200"
+ id="guide5596" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata5594">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1" />
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/close.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/close.svg
new file mode 100644
index 0000000000..2fd91dea94
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/close.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="delete.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 500,98.34375 C 278.76784,98.34375 98.34375,278.76784 98.34375,500 98.34375,721.23216 278.76784,901.65625 500,901.65625 721.23214,901.65625 901.65625,721.23216 901.65625,500 901.65625,278.76783 721.23215,98.34375 500,98.34375 z m 0,100 c 167.18813,0 301.65625,134.4681 301.65625,301.65625 C 801.65625,667.18814 667.18814,801.65625 500,801.65625 332.81184,801.65625 198.34375,667.18814 198.34375,500 198.34375,332.81184 332.81184,198.34375 500,198.34375 z m -154.4375,97.25 A 50.005,50.005 0 0 0 310.71875,381.4375 L 429.28125,500 310.71875,618.5625 a 50.005708,50.005708 0 1 0 70.71875,70.71875 L 500,570.71875 618.5625,689.28125 A 50.005708,50.005708 0 1 0 689.28125,618.5625 L 570.71875,500 689.28125,381.4375 A 50.005708,50.005708 0 1 0 618.5625,310.71875 L 500,429.28125 381.4375,310.71875 a 50.005,50.005 0 0 0 -35.875,-15.125 z"
+ id="path3789-6"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/collapsed.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/collapsed.svg
new file mode 100644
index 0000000000..2865518a49
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/collapsed.svg
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="collapsed.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="m 500.5625,299.375 a 74.185358,74.185358 0 0 0 -2.65625,0.1875 A 74.185358,74.185358 0 0 0 451.25,315.875 L 128.59375,567.3125 a 74.185358,74.185358 0 1 0 91.1875,117.03125 L 500.125,465.84375 780.21875,684.125 a 74.185358,74.185358 0 1 0 91.1875,-117 L 548.75,315.65625 A 74.185358,74.185358 0 0 0 500.5625,299.375 z"
+ id="path2991-0"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/delete.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/delete.svg
new file mode 100644
index 0000000000..2fd91dea94
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/delete.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="delete.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 500,98.34375 C 278.76784,98.34375 98.34375,278.76784 98.34375,500 98.34375,721.23216 278.76784,901.65625 500,901.65625 721.23214,901.65625 901.65625,721.23216 901.65625,500 901.65625,278.76783 721.23215,98.34375 500,98.34375 z m 0,100 c 167.18813,0 301.65625,134.4681 301.65625,301.65625 C 801.65625,667.18814 667.18814,801.65625 500,801.65625 332.81184,801.65625 198.34375,667.18814 198.34375,500 198.34375,332.81184 332.81184,198.34375 500,198.34375 z m -154.4375,97.25 A 50.005,50.005 0 0 0 310.71875,381.4375 L 429.28125,500 310.71875,618.5625 a 50.005708,50.005708 0 1 0 70.71875,70.71875 L 500,570.71875 618.5625,689.28125 A 50.005708,50.005708 0 1 0 689.28125,618.5625 L 570.71875,500 689.28125,381.4375 A 50.005708,50.005708 0 1 0 618.5625,310.71875 L 500,429.28125 381.4375,310.71875 a 50.005,50.005 0 0 0 -35.875,-15.125 z"
+ id="path3789-6"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/download.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/download.svg
new file mode 100644
index 0000000000..1cc851b518
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/download.svg
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="download.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:#000000;fill-opacity:1;stroke:none"
+ d="M 500,100 C 279.0861,100 100,279.0861 100,500 100,720.91389 279.0861,900 500,900 720.9139,900 900,720.91389 900,500 900,279.0861 720.9139,100 500,100 z m -26.35714,243.53571 45.71428,0 c 6.33143,0 11.42857,5.09715 11.42857,11.42858 l 0,117.28571 91.42858,0 -63.25,92.57143 L 495.75,657.39286 432.5,564.82143 369.25,472.25 l 92.96429,0 0,-117.28571 c 0,-6.33143 5.09714,-11.42858 11.42857,-11.42858 z"
+ id="path2987"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/edit.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/edit.svg
new file mode 100644
index 0000000000..f374e7c8d5
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/edit.svg
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="edit.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 644.35135,150 557.28154,255.56013 712.93019,388.42333 800,282.8632 644.35135,150 z M 528.25827,290.74684 267.04882,607.42725 422.69747,740.29045 683.90691,423.61005 528.25827,290.74684 z M 393.6742,775.47716 237.8623,642.81188 200,850 393.6742,775.47716 z"
+ id="rect2986"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/exclaim.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/exclaim.svg
new file mode 100644
index 0000000000..8194d819b1
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/exclaim.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="exclaim.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 500 100 C 279.0861 100 100 279.08611 100 500 C 100 720.91389 279.0861 900 500 900 C 720.9139 900 900 720.91389 900 500 C 900 279.08611 720.9139 100 500 100 z M 445.53125 317.71875 L 554.375 317.71875 L 542.375 589.46875 L 457.5 589.46875 L 445.53125 317.71875 z M 447.34375 631.78125 L 552.53125 631.78125 L 552.53125 699.46875 L 447.34375 699.46875 L 447.34375 631.78125 z "
+ id="path2991" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/expanded.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/expanded.svg
new file mode 100644
index 0000000000..0de9bffb93
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/expanded.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="expanded.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="m 500.5625,700.74658 a 74.185358,74.185358 0 0 1 -2.65625,-0.1875 A 74.185358,74.185358 0 0 1 451.25,684.24658 L 128.59375,432.80908 a 74.185358,74.185358 0 1 1 91.1875,-117.03125 l 280.34375,218.5 280.09375,-218.28125 a 74.185358,74.185358 0 1 1 91.1875,117 L 548.75,684.46533 a 74.185358,74.185358 0 0 1 -48.1875,16.28125 z"
+ id="path2991-0"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-default.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-default.svg
new file mode 100644
index 0000000000..5c7af09ea3
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-default.svg
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="fragment-default.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1" />
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-start.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-start.svg
new file mode 100644
index 0000000000..6ea25b8c70
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-start.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="fragment-start.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 100 100 L 100 250 L 100 550 L 100 700 L 100 900 L 250 900 L 250 700 L 700 700 L 700 550 L 700 250 L 900 250 L 900 100 L 250 100 L 100 100 z M 250 250 L 550 250 L 550 550 L 250 550 L 250 250 z "
+ id="rect2984" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-stop.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-stop.svg
new file mode 100644
index 0000000000..47f055c873
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/fragment-stop.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="fragment-stop.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="m 900,900 0,-200 0,-600 -200,0 0,600 -600,0 0,200 600,0 200,0 z"
+ id="rect2984"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/handle.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/handle.svg
new file mode 100644
index 0000000000..c21a7dddb7
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/handle.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg3809"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="handle.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 224.4375 150 A 74.815327 74.815327 0 1 0 224.4375 299.625 L 775.5625 299.625 A 74.815327 74.815327 0 1 0 775.5625 150 L 224.4375 150 z M 225.25 425.375 A 74.596181 74.815327 0 1 0 225.25 575 L 774.75 575 A 74.596181 74.815327 0 1 0 774.75 425.375 L 225.25 425.375 z M 225.25 700.375 A 74.596181 74.815327 0 1 0 225.25 850 L 774.75 850 A 74.596181 74.815327 0 1 0 774.75 700.375 L 225.25 700.375 z "
+ id="path2988" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/info.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/info.svg
new file mode 100644
index 0000000000..04a8b2f205
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/info.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="info.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 500 100 C 279.0861 100 100 279.08611 100 500 C 100 720.91389 279.0861 900 500 900 C 720.9139 900 900 720.91389 900 500 C 900 279.08611 720.9139 100 500 100 z M 450.53125 300.53125 L 549.46875 300.53125 L 549.46875 370.53125 L 450.53125 370.53125 L 450.53125 300.53125 z M 453.125 411.53125 L 546.875 411.53125 L 546.875 699.46875 L 453.125 699.46875 L 453.125 411.53125 z "
+ id="path2991" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/notes.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/notes.svg
new file mode 100644
index 0000000000..29a663f602
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/notes.svg
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="notes.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="m 200,100 0,800 600,0 0,-457.14286 -300,0 L 500,100 200,100 z m 350,1.82143 0,283.89286 248.375,0 L 550,101.82143 z"
+ id="rect4951"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-default.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-default.svg
new file mode 100644
index 0000000000..a943b4acbc
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-default.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="occurrence-default.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+
+ d="m 300,100 400,0 0,800 -400,0 z"
+ id="rect2984" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-start.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-start.svg
new file mode 100644
index 0000000000..df0e78377d
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-start.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="occurrence-start.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 100 100 L 100 900 L 475 900 L 475 100 L 100 100 z M 525 500 L 525 900 L 900 900 L 900 500 L 525 500 z "
+ id="rect2984" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-stop.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-stop.svg
new file mode 100644
index 0000000000..9b7aecc04e
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/occurrence-stop.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="occurrence-end.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 100 100 L 100 900 L 475 900 L 475 100 L 100 100 z M 525 100 L 525 500 L 900 500 L 900 100 L 525 100 z "
+ id="rect2984" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/open.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/open.svg
new file mode 100644
index 0000000000..779c20e471
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/open.svg
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="open.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:#000000;fill-opacity:1;stroke:none"
+ d="m 100,200 0,459.1551 26.89847,0 118.05807,-359.58543 484.8614,0 0,-99.56967 L 100,200 z M 270.18206,340.8449 119.45219,800 749.27013,800 900,340.8449 l -629.81794,0 z"
+ id="rect2986"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/plus.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/plus.svg
new file mode 100644
index 0000000000..7854624a97
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/plus.svg
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="plus.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="m 443.75,200 0,243.75 -243.75,0 0,112.5 243.75,0 0,243.75 112.5,0 0,-243.75 243.75,0 0,-112.5 -243.75,0 0,-243.75 -112.5,0 z"
+ id="rect2986"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/question.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/question.svg
new file mode 100644
index 0000000000..9cd19eda9a
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/question.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="question.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 500 100 C 279.0861 100 100 279.08611 100 500 C 100 720.91389 279.0861 900 500 900 C 720.9139 900 900 720.91389 900 500 C 900 279.08611 720.9139 100 500 100 z M 490.625 300.53125 C 534.72949 300.53165 569.73333 310.07321 595.625 329.15625 C 621.51612 348.24003 634.46844 373.18672 634.46875 404 C 634.46844 421.68309 631.76279 437.37548 626.40625 451.03125 C 621.22767 464.51244 613.82953 476.23956 604.1875 486.21875 C 594.54491 496.19836 582.94543 505.12171 569.375 513 C 555.98266 520.87866 540.80688 528.05356 523.84375 534.53125 L 523.84375 594.40625 L 429.5625 594.40625 L 429.5625 505.90625 C 442.24025 502.57999 453.66561 499.15799 463.84375 495.65625 C 474.20016 492.1549 485.00046 486.47244 496.25 478.59375 C 506.78495 471.59089 515.01354 463.46683 520.90625 454.1875 C 526.97714 444.90866 529.9998 434.38669 530 422.65625 C 529.9998 405.14881 524.20006 392.72855 512.59375 385.375 C 501.16564 377.847 484.98529 374.06283 464.09375 374.0625 C 451.23719 374.06283 436.68648 376.79168 420.4375 382.21875 C 404.36687 387.64646 389.64205 394.64027 376.25 403.21875 L 365.53125 403.21875 L 365.53125 323.125 C 376.95914 318.39829 394.56375 313.48389 418.3125 308.40625 C 442.06106 303.15434 466.16192 300.53165 490.625 300.53125 z M 423.125 630.125 L 531.34375 630.125 L 531.34375 699.46875 L 423.125 699.46875 L 423.125 630.125 z "
+ id="path2991" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/save.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/save.svg
new file mode 100644
index 0000000000..e71a3a3cae
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/save.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="save.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 100 100 L 100 900 L 900 900 L 900 236.84375 C 879.41881 236.69254 862.78125 219.96058 862.78125 199.34375 C 862.78125 178.72692 879.41881 161.99496 900 161.84375 L 900 100 L 100 100 z M 500 400 C 555.22847 400 600 444.77152 600 500 C 600 555.22847 555.22847 600 500 600 C 444.77153 600 400 555.22847 400 500 C 400 444.77152 444.77153 400 500 400 z M 500 650 C 522.16 650 540 667.84 540 690 L 540 810 C 540 832.16 522.16 850 500 850 C 477.84 850 460 832.16 460 810 L 460 690 C 460 667.84 477.84 650 500 650 z "
+ id="rect2987" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/settings.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/settings.svg
new file mode 100644
index 0000000000..255980690a
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/settings.svg
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="settings.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+d="m 442.85714,100 c -15.82857,-1.1e-5 -28.57144,12.74286 -28.57143,28.57143 l 0,78.03571 c -21.39083,6.29739 -41.83274,14.84225 -61.03571,25.42857 L 297.96429,176.75 c -11.1925,-11.19249 -29.20038,-11.19249 -40.39286,0 L 176.75,257.57143 c -11.19249,11.19248 -11.19249,29.20038 0,40.39286 l 55.17857,55.17857 c -10.65924,19.2368 -19.30642,39.7185 -25.64286,61.14285 l -77.71428,0 C 112.74286,414.2857 99.999989,427.02857 100,442.85714 l 0,114.28572 c -1.1e-5,15.82857 12.74286,28.57144 28.57143,28.57143 l 77.71428,0 c 6.33867,21.43243 14.97845,41.89934 25.64286,61.14285 L 176.75,702.03571 c -11.19249,11.19248 -11.19249,29.20038 0,40.39286 L 257.57143,823.25 c 11.19248,11.19249 29.20036,11.19249 40.39286,0 L 353.25,767.96429 c 19.20386,10.58763 39.64379,19.16626 61.03571,25.46428 l 0,78 c -10e-6,15.82857 12.74286,28.57144 28.57143,28.57143 l 114.28572,0 c 15.82857,10e-6 28.57144,-12.74286 28.57143,-28.57143 l 0,-78.03571 c 21.3803,-6.29801 41.80587,-14.88105 61,-25.46429 L 702.03571,823.25 c 11.19248,11.19249 29.20038,11.19249 40.39286,0 L 823.25,742.42857 c 11.19249,-11.19248 11.19249,-29.20038 0,-40.39286 l -55.17857,-55.17857 c 10.6655,-19.24547 19.30402,-39.70804 25.64286,-61.14285 l 77.71428,0 c 15.82857,10e-6 28.57144,-12.74286 28.57143,-28.57143 l 0,-114.28572 c 10e-6,-15.82857 -12.74286,-28.57144 -28.57143,-28.57143 l -77.71428,0 c -6.33662,-21.42673 -14.98253,-41.90409 -25.64286,-61.14285 L 823.25,297.96429 c 11.19249,-11.1925 11.19249,-29.20038 0,-40.39286 L 742.42857,176.75 c -11.19248,-11.19249 -29.20038,-11.19249 -40.39286,0 l -55.32142,55.32143 c -19.19616,-10.58354 -39.61723,-19.16664 -61,-25.46429 l 0,-78.03571 C 585.7143,112.74286 572.97143,99.999989 557.14286,100 l -114.28572,0 z M 500,365.28571 c 74.99435,0 134.32143,59.10773 134.32143,134.71429 0,75.60656 -59.32708,134.67857 -134.32143,134.67857 -74.99437,0 -134.32143,-59.07201 -134.32143,-134.67857 0,-75.60656 59.32708,-134.71429 134.32143,-134.71429 z"
+ id="path3783"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g3951" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/upload.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/upload.svg
new file mode 100644
index 0000000000..453f8418b9
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/upload.svg
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="upload.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 500,900 C 279.0861,900 100,720.9139 100,500 100,279.08611 279.0861,100 500,100 c 220.9139,0 400,179.08611 400,400 0,220.9139 -179.0861,400 -400,400 z m -26.35714,-243.53571 45.71428,0 c 6.33143,0 11.42857,-5.09715 11.42857,-11.42858 l 0,-117.28571 91.42858,0 -63.25,-92.57143 L 495.75,342.60714 432.5,435.17857 369.25,527.75 l 92.96429,0 0,117.28571 c 0,6.33143 5.09714,11.42858 11.42857,11.42858 z"
+ id="path2987"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/validate.svg b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/validate.svg
new file mode 100644
index 0000000000..35cc9fa418
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/ecomp/asdc/sequencer/sprites/icon/validate.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1000"
+ height="1000"
+ id="svg4406"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="validate.svg">
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="M 500 100 C 279.08608 100 100 279.08609 100 500 C 100 720.91389 279.08608 900 500 900 C 720.91389 900 900 720.91389 900 500 C 900 279.08609 720.91389 100 500 100 z M 679.71875 300 C 687.77296 300.00048 693.09804 300.69955 695.6875 302.09375 C 698.56369 303.48895 699.99953 305.30021 700 307.53125 C 699.99953 311.15798 695.84187 317.86261 687.5 327.625 C 590.26844 440.87501 500.22263 560.54434 417.375 686.625 C 411.6215 695.55114 399.83514 700.00006 382 700 C 363.87689 700.00006 353.07688 699.17376 349.625 697.5 C 340.99491 693.87387 330.9128 675.18934 319.40625 641.4375 C 306.46119 604.05972 299.99993 580.60914 300 571.125 C 299.99993 561.08339 308.76478 551.32795 326.3125 541.84375 C 336.95605 535.70737 346.47007 532.62524 354.8125 532.625 C 364.59303 532.62524 372.07186 540.44209 377.25 556.0625 C 387.31816 585.63032 394.49734 600.40643 398.8125 600.40625 C 402.26433 600.40643 405.70408 597.8961 409.15625 592.875 C 479.63425 482.97293 545.08977 394.15781 605.5 326.375 C 621.03359 308.80222 645.77372 300.00048 679.71875 300 z "
+ id="path2991" />
+ </g>
+</svg>
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/sdc-sequencer.scss b/dox-sequence-diagram-ui/src/main/webapp/res/sdc-sequencer.scss
new file mode 100644
index 0000000000..bcb01d2253
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/sdc-sequencer.scss
@@ -0,0 +1,87 @@
+@import 'ecomp/asdc/sequencer/sequencer-common.scss';
+
+.asdcs-control {
+
+ width: 100%;
+ height: 100%;
+ min-height: $asdcsApplicationMinHeight;
+
+ * {
+ outline: none;
+ line-height: initial;
+ text-align: initial;
+ }
+
+ p, div, span, td, input, select, option {
+ font-size: $asdcsFontSize;
+ color: $asdcsColorOneDark;
+ padding: 0;
+ margin: 0;
+ }
+
+ table {
+ border-collapse: initial;
+ border-spacing: initial;
+ }
+
+ // SVG always fills its container.
+
+ svg {
+ height:100%;
+ width: 100%;
+ }
+
+ button {
+
+ border-radius: 4px;
+ background-color: $asdcsColorButtonBG;
+ padding: 4px;
+ border: none;
+ color: $asdcsColorWhitish;
+ min-width: 30px;
+ min-height: 30px;
+ text-align: center;
+ vertical-align: middle;
+
+ &:hover {
+ cursor: pointer;
+ background-color: $asdcsColorEmphasisHover;
+ color: $asdcsColorWhite;
+ @include transition(background-color 250ms ease);
+ }
+
+ &:disabled {
+ cursor: default;
+ background-color:gray;
+ color:darkGray;
+ }
+
+ }
+
+ form {
+ display: none;
+ }
+
+ ::-webkit-scrollbar {
+ width: 10px;
+ }
+
+ ::-webkit-scrollbar-track {
+ border-radius: 0;
+ background-color: $asdcsColorOneLight;
+ }
+
+ ::-webkit-scrollbar-thumb {
+ border-radius: 6px;
+ margin:1px;
+ background-color: $asdcsColorOne;
+ }
+}
+
+@import 'ecomp/asdc/sequencer/sequencer-controls.scss';
+@import 'ecomp/asdc/sequencer/sequencer-diagram.scss';
+@import 'ecomp/asdc/sequencer/sequencer-editor.scss';
+@import 'ecomp/asdc/sequencer/sequencer-dialog.scss';
+@import 'ecomp/asdc/sequencer/sequencer-designer.scss';
+@import 'ecomp/asdc/sequencer/sequencer-actions.scss';
+
diff --git a/dox-sequence-diagram-ui/src/main/webapp/res/thirdparty/react-select/react-select.min.css b/dox-sequence-diagram-ui/src/main/webapp/res/thirdparty/react-select/react-select.min.css
new file mode 100644
index 0000000000..f1fa71dec4
--- /dev/null
+++ b/dox-sequence-diagram-ui/src/main/webapp/res/thirdparty/react-select/react-select.min.css
@@ -0,0 +1 @@
+.Select,.Select-control{position:relative}.Select-arrow-zone,.Select-clear-zone,.Select-loading-zone{text-align:center;cursor:pointer}.Select,.Select div,.Select input,.Select span{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.Select.is-disabled>.Select-control{background-color:#f9f9f9}.Select.is-disabled>.Select-control:hover{box-shadow:none}.Select.is-disabled .Select-arrow-zone{cursor:default;pointer-events:none}.Select-control{background-color:#fff;border-radius:4px;border:1px solid #ccc;color:#333;cursor:default;display:table;height:36px;outline:0;overflow:hidden;width:100%}.is-searchable.is-focused:not(.is-open)>.Select-control,.is-searchable.is-open>.Select-control{cursor:text}.Select-control:hover{box-shadow:0 1px 0 rgba(0,0,0,.06)}.is-open>.Select-control{border-bottom-right-radius:0;border-bottom-left-radius:0;background:#fff;border-color:#b3b3b3 #ccc #d9d9d9}.is-open>.Select-control>.Select-arrow{border-color:transparent transparent #999;border-width:0 5px 5px}.is-focused:not(.is-open)>.Select-control{border-color:#007eff;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 0 3px rgba(0,126,255,.1)}.Select--single>.Select-control .Select-value,.Select-placeholder{bottom:0;color:#aaa;left:0;line-height:34px;padding-left:10px;padding-right:10px;position:absolute;right:0;top:0;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.has-value.Select--single>.Select-control>.Select-value .Select-value-label,.has-value.is-pseudo-focused.Select--single>.Select-control>.Select-value .Select-value-label{color:#333}.has-value.Select--single>.Select-control>.Select-value a.Select-value-label,.has-value.is-pseudo-focused.Select--single>.Select-control>.Select-value a.Select-value-label{cursor:pointer;text-decoration:none}.has-value.Select--single>.Select-control>.Select-value a.Select-value-label:focus,.has-value.Select--single>.Select-control>.Select-value a.Select-value-label:hover,.has-value.is-pseudo-focused.Select--single>.Select-control>.Select-value a.Select-value-label:focus,.has-value.is-pseudo-focused.Select--single>.Select-control>.Select-value a.Select-value-label:hover{color:#007eff;outline:0;text-decoration:underline}.Select-input{height:34px;padding-left:10px;padding-right:10px;vertical-align:middle}.Select-input>input{width:100%;background:none;border:0;box-shadow:none;cursor:default;display:inline-block;font-family:inherit;font-size:inherit;margin:0;outline:0;line-height:14px;padding:8px 0 12px;-webkit-appearance:none}.Select-loading,.Select-loading-zone{width:16px;position:relative;vertical-align:middle}.is-focused .Select-input>input{cursor:text}.has-value.is-pseudo-focused .Select-input{opacity:0}.Select-control:not(.is-searchable)>.Select-input{outline:0}.Select-loading-zone{display:table-cell}.Select-loading{-webkit-animation:Select-animation-spin .4s infinite linear;-o-animation:Select-animation-spin .4s infinite linear;animation:Select-animation-spin .4s infinite linear;height:16px;box-sizing:border-box;border-radius:50%;border:2px solid #ccc;border-right-color:#333;display:inline-block}.Select-clear-zone{-webkit-animation:Select-animation-fadeIn .2s;-o-animation:Select-animation-fadeIn .2s;animation:Select-animation-fadeIn .2s;color:#999;display:table-cell;position:relative;vertical-align:middle;width:17px}.Select-clear-zone:hover{color:#D0021B}.Select-clear{display:inline-block;font-size:18px;line-height:1}.Select--multi .Select-clear-zone{width:17px}.Select-arrow-zone{display:table-cell;position:relative;vertical-align:middle;width:25px;padding-right:5px}.Select-arrow{border-color:#999 transparent transparent;border-style:solid;border-width:5px 5px 2.5px;display:inline-block;height:0;width:0}.Select-noresults,.Select-option{box-sizing:border-box;display:block;padding:8px 10px}.Select-arrow-zone:hover>.Select-arrow,.is-open .Select-arrow{border-top-color:#666}@-webkit-keyframes Select-animation-fadeIn{from{opacity:0}to{opacity:1}}@keyframes Select-animation-fadeIn{from{opacity:0}to{opacity:1}}.Select-menu-outer{border-bottom-right-radius:4px;border-bottom-left-radius:4px;background-color:#fff;border:1px solid #ccc;border-top-color:#e6e6e6;box-shadow:0 1px 0 rgba(0,0,0,.06);box-sizing:border-box;margin-top:-1px;max-height:200px;position:absolute;top:100%;width:100%;z-index:1;-webkit-overflow-scrolling:touch}.Select-menu{max-height:198px;overflow-y:auto}.Select-option{background-color:#fff;color:#666;cursor:pointer}.Select-option:last-child{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.Select-option.is-selected{background-color:#f5faff;background-color:rgba(0,126,255,.04);color:#333}.Select-option.is-focused{background-color:#ebf5ff;background-color:rgba(0,126,255,.08);color:#333}.Select-option.is-disabled{color:#ccc;cursor:default}.Select-noresults{color:#999;cursor:default}.Select--multi .Select-input{vertical-align:middle;margin-left:10px;padding:0}.Select--multi.has-value .Select-input{margin-left:5px}.Select--multi .Select-value{background-color:#ebf5ff;background-color:rgba(0,126,255,.08);border-radius:2px;border:1px solid rgba(0,126,255,.24);color:#007eff;display:inline-block;font-size:.9em;line-height:1.4;margin-left:5px;margin-top:5px;vertical-align:top}.Select--multi .Select-value-icon,.Select--multi .Select-value-label{display:inline-block;vertical-align:middle}.Select--multi .Select-value-label{border-bottom-right-radius:2px;border-top-right-radius:2px;cursor:default;padding:2px 5px}.Select--multi a.Select-value-label{color:#007eff;cursor:pointer;text-decoration:none}.Select--multi a.Select-value-label:hover{text-decoration:underline}.Select--multi .Select-value-icon{cursor:pointer;border-bottom-left-radius:2px;border-top-left-radius:2px;border-right:1px solid #c2e0ff;border-right:1px solid rgba(0,126,255,.24);padding:1px 5px 3px}.Select--multi .Select-value-icon:focus,.Select--multi .Select-value-icon:hover{background-color:#d8eafd;background-color:rgba(0,113,230,.08);color:#0071e6}.Select--multi .Select-value-icon:active{background-color:#c2e0ff;background-color:rgba(0,126,255,.24)}.Select--multi.is-disabled .Select-value{background-color:#fcfcfc;border:1px solid #e3e3e3;color:#333}.Select--multi.is-disabled .Select-value-icon{cursor:not-allowed;border-right:1px solid #e3e3e3}.Select--multi.is-disabled .Select-value-icon:active,.Select--multi.is-disabled .Select-value-icon:focus,.Select--multi.is-disabled .Select-value-icon:hover{background-color:#fcfcfc}@keyframes Select-animation-spin{to{transform:rotate(1turn)}}@-webkit-keyframes Select-animation-spin{to{-webkit-transform:rotate(1turn)}}