@processmaker/modeler 1.31.0 → 1.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +7 -0
  2. package/babel.config.js +1 -2
  3. package/dist/img/inclusive-gateway.0f0afffd.svg +4 -0
  4. package/dist/img/inspector.42e5d40d.svg +5 -0
  5. package/dist/img/issue-close.5d1630e6.svg +3 -0
  6. package/dist/img/issue-item.3187f291.svg +3 -0
  7. package/dist/img/issue-open.707390b4.svg +4 -0
  8. package/dist/img/validate-close.09ace97a.svg +4 -0
  9. package/dist/img/validate-open.b0ecf74e.svg +4 -0
  10. package/dist/modeler.common.js +3354 -2489
  11. package/dist/modeler.common.js.map +1 -1
  12. package/dist/modeler.umd.js +3354 -2489
  13. package/dist/modeler.umd.js.map +1 -1
  14. package/dist/modeler.umd.min.js +4 -4
  15. package/dist/modeler.umd.min.js.map +1 -1
  16. package/package.json +2 -2
  17. package/src/.DS_Store +0 -0
  18. package/src/ModelerApp.vue +0 -9
  19. package/src/NodeIdGenerator.js +16 -1
  20. package/src/assets/inspector.svg +5 -0
  21. package/src/assets/toolpanel/inclusive-gateway.svg +2 -2
  22. package/src/assets/topRail/issue-close.svg +3 -0
  23. package/src/assets/topRail/issue-item.svg +3 -0
  24. package/src/assets/topRail/issue-open.svg +4 -0
  25. package/src/assets/topRail/validate-close.svg +4 -0
  26. package/src/assets/topRail/validate-open.svg +4 -0
  27. package/src/components/controls/controls.vue +2 -11
  28. package/src/components/crown/crownButtons/addLaneAboveButton.vue +3 -1
  29. package/src/components/crown/crownButtons/addLaneBelowButton.vue +3 -1
  30. package/src/components/crown/crownButtons/crownBoundaryEventDropdown.vue +2 -1
  31. package/src/components/crown/crownButtons/genericFlowButton.vue +2 -1
  32. package/src/components/crown/crownButtons/icons/faAlignLeft.js +1 -1
  33. package/src/components/crown/crownMultiselect/crownAlign.vue +3 -0
  34. package/src/components/crown/crownMultiselect/crownMultiselect.vue +4 -2
  35. package/src/components/hotkeys/escKey.js +20 -0
  36. package/src/components/hotkeys/main.js +4 -2
  37. package/src/components/inspectors/InspectorPanel.vue +26 -3
  38. package/src/components/inspectors/inspector.scss +11 -0
  39. package/src/components/inspectors/inspectorButton/InspectorButton.vue +38 -0
  40. package/src/components/inspectors/inspectorButton/inspectorButton.scss +19 -0
  41. package/src/components/inspectors/process.js +1 -1
  42. package/src/components/modeler/Modeler.vue +62 -5
  43. package/src/components/modeler/ModelerReadonly.vue +52 -6
  44. package/src/components/modeler/Selection.vue +9 -1
  45. package/src/components/nodes/association/index.js +1 -1
  46. package/src/components/nodes/baseStartEvent/index.js +1 -1
  47. package/src/components/nodes/boundaryEvent/index.js +1 -1
  48. package/src/components/nodes/dataInputAssociation/index.js +1 -1
  49. package/src/components/nodes/dataObject/index.js +1 -1
  50. package/src/components/nodes/dataOutputAssociation/index.js +1 -1
  51. package/src/components/nodes/dataStore/index.js +1 -1
  52. package/src/components/nodes/endEvent/index.js +1 -1
  53. package/src/components/nodes/eventBasedGateway/index.js +1 -1
  54. package/src/components/nodes/exclusiveGateway/index.js +1 -1
  55. package/src/components/nodes/gateway/index.js +1 -1
  56. package/src/components/nodes/inclusiveGateway/index.js +1 -1
  57. package/src/components/nodes/intermediateEvent/index.js +1 -1
  58. package/src/components/nodes/intermediateMessageEvent/index.js +1 -1
  59. package/src/components/nodes/intermediateTimerEvent/index.js +1 -1
  60. package/src/components/nodes/manualTask/index.js +1 -1
  61. package/src/components/nodes/messageFlow/index.js +1 -1
  62. package/src/components/nodes/parallelGateway/index.js +1 -1
  63. package/src/components/nodes/pool/index.js +1 -1
  64. package/src/components/nodes/pool/pool.vue +10 -4
  65. package/src/components/nodes/poolLane/index.js +1 -1
  66. package/src/components/nodes/scriptTask/index.js +1 -1
  67. package/src/components/nodes/sequenceFlow/index.js +1 -1
  68. package/src/components/nodes/serviceTask/index.js +1 -1
  69. package/src/components/nodes/subProcess/index.js +1 -1
  70. package/src/components/nodes/task/index.js +1 -1
  71. package/src/components/nodes/textAnnotation/index.js +1 -1
  72. package/src/components/railBottom/controls/Controls.vue +15 -75
  73. package/src/components/railBottom/controls/SubmenuPopper/SubmenuPopper.vue +5 -5
  74. package/src/components/rails/explorer-rail/explorer-rail.scss +11 -0
  75. package/src/components/rails/explorer-rail/explorer.vue +12 -3
  76. package/src/components/rails/explorer-rail/filterNodeTypes/filterNodeTypes.vue +15 -3
  77. package/src/components/rails/explorer-rail/nodeTypesLoop/nodeTypesLoop.vue +8 -73
  78. package/src/components/rails/explorer-rail/pmBlocksLoop/pmBlocksLoop.vue +76 -0
  79. package/src/components/shapeStackUtils.js +1 -1
  80. package/src/components/toolbar/ToolBar.vue +62 -55
  81. package/src/components/toolbar/toolbar.scss +55 -15
  82. package/src/components/topRail/TopRail.vue +92 -0
  83. package/src/components/topRail/topRail.scss +6 -0
  84. package/src/components/topRail/validateControl/index.js +3 -0
  85. package/src/components/topRail/validateControl/validateButton/ValidateButton.vue +39 -0
  86. package/src/components/topRail/validateControl/validateButton/validateButton.scss +25 -0
  87. package/src/components/topRail/validateControl/validateIssue/ValidateIssue.vue +60 -0
  88. package/src/components/topRail/validateControl/validateIssue/validateIssue.scss +54 -0
  89. package/src/components/topRail/validateControl/validatePanel/ValidatePanel.vue +54 -0
  90. package/src/components/topRail/validateControl/validatePanel/validatePanel.scss +67 -0
  91. package/src/mixins/clickAndDrop.js +107 -0
  92. package/src/mixins/highlightConfig.js +78 -10
  93. package/src/mixins/linkConfig.js +32 -8
  94. package/src/nodeTypesStore.js +48 -0
  95. package/src/setup/registerPmBlock.js +0 -0
  96. package/vue.config.js +1 -0
  97. package/dist/img/distribute-horizontally-icon.5c513cf4.svg +0 -3
  98. package/dist/img/distribute-vertically-icon.a35fb699.svg +0 -3
  99. package/dist/img/inclusive-gateway.754cb36f.svg +0 -4
  100. package/src/components/controls/rankConstants.js +0 -1
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <button
3
+ type="button"
4
+ @click.prevent="handleOpen"
5
+ :class="['validate-button', { 'validate-button-active': isOpen }]"
6
+ data-cy="validate-button"
7
+ >
8
+ <inline-svg :src="isOpen ? validateOpenIcon : validateCloseIcon" />
9
+ </button>
10
+ </template>
11
+
12
+ <script>
13
+ import InlineSvg from 'vue-inline-svg';
14
+
15
+ export default {
16
+ components: {
17
+ InlineSvg,
18
+ },
19
+ data() {
20
+ return {
21
+ isOpen: false,
22
+ validateCloseIcon: require('@/assets/topRail/validate-close.svg'),
23
+ validateOpenIcon: require('@/assets/topRail/validate-open.svg'),
24
+ };
25
+ },
26
+ methods: {
27
+ /**
28
+ * Show/hide issue button
29
+ */
30
+ handleOpen() {
31
+ this.isOpen = !this.isOpen;
32
+
33
+ this.$emit('openIssue', this.isOpen);
34
+ },
35
+ },
36
+ };
37
+ </script>
38
+
39
+ <style scoped lang="scss" src="./validateButton.scss"></style>
@@ -0,0 +1,25 @@
1
+ .validate-button {
2
+ display: flex;
3
+ justify-content: center;
4
+ align-items: center;
5
+ width: 32px;
6
+ height: 32px;
7
+ background-color: #EBEEF2;
8
+ border: 0 none;
9
+ border-radius: 4px;
10
+ transition: background-color 0.3s ease;
11
+
12
+ & > svg {
13
+ width: 18px;
14
+ fill: #212529;
15
+ }
16
+
17
+ &:active,
18
+ &-active {
19
+ background-color: #104A75;
20
+
21
+ & > svg {
22
+ fill: #ffffff;
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <button
3
+ type="button"
4
+ :disabled="numberOfErrors === 0"
5
+ @click.prevent="handleOpen"
6
+ class="issue-box"
7
+ data-cy="validate-issue-button"
8
+ >
9
+ <span class="issue-title">Issues</span>
10
+
11
+ <span class="issue-badge">{{ numberOfErrors }}</span>
12
+
13
+ <span class="issue-icon">
14
+ <inline-svg :src="isOpen ? issueOpenIcon : issueCloseIcon" />
15
+ </span>
16
+ </button>
17
+ </template>
18
+
19
+ <script>
20
+ import InlineSvg from 'vue-inline-svg';
21
+
22
+ export default {
23
+ components: {
24
+ InlineSvg,
25
+ },
26
+ props: {
27
+ numberOfErrors: {
28
+ type: Number,
29
+ required: true,
30
+ },
31
+ },
32
+ data() {
33
+ return {
34
+ isOpen: false,
35
+ issueCloseIcon: require('@/assets/topRail/issue-close.svg'),
36
+ issueOpenIcon: require('@/assets/topRail/issue-open.svg'),
37
+ };
38
+ },
39
+ watch: {
40
+ numberOfErrors(newValue) {
41
+ // Checks the number of errors if it is "0" reset the issue icon
42
+ if (newValue === 0) {
43
+ this.isOpen = false;
44
+ }
45
+ },
46
+ },
47
+ methods: {
48
+ /**
49
+ * Show/hide the issue panel
50
+ */
51
+ handleOpen() {
52
+ this.isOpen = !this.isOpen;
53
+
54
+ this.$emit('openPanel', this.isOpen);
55
+ },
56
+ },
57
+ };
58
+ </script>
59
+
60
+ <style scoped lang="scss" src="./validateIssue.scss"></style>
@@ -0,0 +1,54 @@
1
+ .issue {
2
+ &-box {
3
+ display: flex;
4
+ align-items: center;
5
+ background-color: #EBEEF2;
6
+ margin-right: 12px;
7
+ padding: 4px 8px;
8
+ border: 0 none;
9
+ border-radius: 4px;
10
+ font-family: 'Open Sans';
11
+ }
12
+
13
+ &-title {
14
+ font-weight: 400;
15
+ font-size: 14px;
16
+ line-height: 21px;
17
+ letter-spacing: -0.02em;
18
+ color: #212529;
19
+ }
20
+
21
+ &-badge {
22
+ display: flex;
23
+ justify-content: center;
24
+ align-items: center;
25
+ min-width: 16px;
26
+ height: 20px;
27
+ margin: {
28
+ left: 7px;
29
+ right: 15px;
30
+ };
31
+ padding: {
32
+ left: 3px;
33
+ right: 3px;
34
+ };
35
+ background: #FFAB00;
36
+ border-radius: 8px;
37
+ font-size: 12.8px;
38
+ font-weight: 400;
39
+ color: #FFFFFF;
40
+ }
41
+
42
+ &-icon {
43
+ display: flex;
44
+ justify-content: center;
45
+ align-items: center;
46
+ width: 14px;
47
+ height: 14px;
48
+ padding: 0px;
49
+
50
+ & > svg {
51
+ fill: #212529;
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,54 @@
1
+ <template>
2
+ <div
3
+ class="validate-container"
4
+ data-cy="validate-panel"
5
+ >
6
+ <div v-for="(error, index) in errorList" :key="`${error.errorId}_${index}`" class="validate-item-box">
7
+ <vue-inline-svg :src="issueIcon" />
8
+
9
+ <div class="validate-item-info">
10
+ <div class="validate-item-title">{{ error.errorKey }}</div>
11
+ <div class="validate-item-description">{{ error.message }}.</div>
12
+ <div class="validate-item-node" v-if="error.id">
13
+ <span class="validate-item-node-title">{{ $t('Node ID') }}:</span> {{ error.id }}
14
+ </div>
15
+ </div>
16
+ </div>
17
+
18
+ <div v-for="(warning, index) in warnings" :key="warning.title + index" class="validate-item-box">
19
+ <vue-inline-svg :src="issueIcon" />
20
+
21
+ <div class="validate-item-info">
22
+ <div class="validate-item-title">{{ warning.title }}</div>
23
+ <div class="validate-item-description">{{ warning.text }}.</div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <script>
30
+ import VueInlineSvg from 'vue-inline-svg';
31
+
32
+ export default {
33
+ components: {
34
+ VueInlineSvg,
35
+ },
36
+ props: {
37
+ errorList: {
38
+ type: Array,
39
+ required: true,
40
+ },
41
+ warnings: {
42
+ type: Array,
43
+ required: true,
44
+ },
45
+ },
46
+ data() {
47
+ return {
48
+ issueIcon: require('@/assets/topRail/issue-item.svg'),
49
+ };
50
+ },
51
+ };
52
+ </script>
53
+
54
+ <style scoped lang="scss" src="./validatePanel.scss"></style>
@@ -0,0 +1,67 @@
1
+ .validate {
2
+ &-container {
3
+ position: absolute;
4
+ top: 48px;
5
+ right: 8px;
6
+ display: flex;
7
+ flex-direction: column;
8
+ width: 386px;
9
+ height: 273px;
10
+ padding: 12px;
11
+ background: #F7F7F7;
12
+ border: 1px solid #C4C8CC;
13
+ border-radius: 4px;
14
+ overflow-y: auto;
15
+ z-index: 3;
16
+ }
17
+
18
+ &-item {
19
+ &-box {
20
+ display: flex;
21
+ justify-content: flex-start;
22
+ margin-bottom: 10px;
23
+ color: #000000;
24
+
25
+ & > svg {
26
+ width: 16px;
27
+ margin: {
28
+ top: 4px;
29
+ right: 10px;
30
+ };
31
+ fill: #D11401;
32
+ }
33
+
34
+ &:last-child {
35
+ margin-bottom: 0;
36
+ }
37
+ }
38
+
39
+ &-info {
40
+ flex: 1 1 0;
41
+ display: flex;
42
+ flex-direction: column;
43
+ font-family: 'Open Sans';
44
+ font-style: normal;
45
+ font-size: 14px;
46
+ }
47
+
48
+ &-title {
49
+ font-weight: 600;
50
+ text-transform: capitalize;
51
+ }
52
+
53
+ &-description {
54
+ font-style: italic;
55
+ font-weight: 400;
56
+ color: #6C757D;
57
+ }
58
+
59
+ &-node {
60
+ &-title {
61
+ font-weight: 600;
62
+ }
63
+
64
+ font-weight: 400;
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,107 @@
1
+ import nodeTypesStore from '@/nodeTypesStore';
2
+
3
+ export default {
4
+ data() {
5
+ return {
6
+ wasClicked: false,
7
+ selectedSubmenuItem: null,
8
+ xOffset: 0,
9
+ yOffset: 0,
10
+ helperStyles: {
11
+ backgroundColor:'#ffffff',
12
+ position: 'absolute',
13
+ height: '40px',
14
+ width: '40px',
15
+ zIndex: '10',
16
+ opacity: '0.5',
17
+ pointerEvents: 'none',
18
+ },
19
+ popperType: null,
20
+ };
21
+ },
22
+ methods: {
23
+ onClickHandler(event, control) {
24
+ this.createDraggingHelper(event, control);
25
+ document.addEventListener('mousemove', this.setDraggingPosition);
26
+ this.setDraggingPosition(event);
27
+ // Deselect control on click if same control is already selected
28
+ if (this.selectedItem && (this.selectedItem.type === control.type)) {
29
+ this.deselect();
30
+ return;
31
+ }
32
+ this.wasClicked = true;
33
+ nodeTypesStore.commit('setSelectedNode', control);
34
+ this.$emit('onSetCursor', 'crosshair');
35
+ if (!this.parent) {
36
+ this.popperType = control.type;
37
+ }
38
+ window.ProcessMaker.EventBus.$on('custom-pointerclick', message => {
39
+ window.ProcessMaker.EventBus.$off('custom-pointerclick');
40
+ document.removeEventListener('mousemove', this.setDraggingPosition);
41
+ if (this.movedElement) {
42
+ document.body.removeChild(this.movedElement);
43
+ }
44
+ this.popperType = null;
45
+ this.selectedSubmenuItem = null;
46
+ this.onCreateElement(message);
47
+ nodeTypesStore.commit('clearSelectedNode');
48
+ nodeTypesStore.commit('setGhostNode', null);
49
+ this.$emit('onSetCursor', 'none');
50
+ });
51
+ },
52
+ onCreateElement(event){
53
+ if (this.wasClicked && this.selectedItem) {
54
+ if (this.parent) {
55
+ this.parent = null;
56
+ }
57
+ this.$emit('onCreateElement', { event, control: this.selectedItem });
58
+ this.wasClicked = false;
59
+ event.preventDefault();
60
+ }
61
+ },
62
+ setDraggingPosition({ pageX, pageY }) {
63
+ let tempGhost = this.movedElement;
64
+ if (tempGhost) {
65
+ tempGhost.style.left = `${pageX}px`;
66
+ tempGhost.style.top = `${pageY}px`;
67
+ }
68
+ nodeTypesStore.commit('setGhostNode', tempGhost);
69
+ },
70
+ createDraggingHelper(event, control) {
71
+ if (this.movedElement) {
72
+ document.removeEventListener('mousemove', this.setDraggingPosition);
73
+ document.body.removeChild(this.movedElement);
74
+ nodeTypesStore.commit('setGhostNode', null);
75
+ }
76
+ const sourceElement = event.target;
77
+ nodeTypesStore.commit('setGhostNode', document.createElement('img'));
78
+ let tempGhost = this.movedElement;
79
+ Object.keys(this.helperStyles).forEach((property) => {
80
+ tempGhost.style[property] = this.helperStyles[property];
81
+ });
82
+ tempGhost.src = control.icon;
83
+ nodeTypesStore.commit('setGhostNode', tempGhost);
84
+ document.body.appendChild(this.movedElement);
85
+ this.xOffset = event.clientX - sourceElement.getBoundingClientRect().left;
86
+ this.yOffset = event.clientY - sourceElement.getBoundingClientRect().top;
87
+ },
88
+ deselect() {
89
+ document.removeEventListener('mousemove', this.setDraggingPosition);
90
+ if (this.movedElement) {
91
+ document.body.removeChild(this.movedElement);
92
+ }
93
+ this.$emit('onSetCursor', 'none');
94
+ this.wasClicked = false;
95
+ nodeTypesStore.commit('clearSelectedNode');
96
+ nodeTypesStore.commit('setGhostNode', null);
97
+ },
98
+ },
99
+ computed: {
100
+ selectedItem() {
101
+ return nodeTypesStore.getters.getSelectedNode;
102
+ },
103
+ movedElement() {
104
+ return nodeTypesStore.getters.getGhostNode;
105
+ },
106
+ },
107
+ };
@@ -1,4 +1,12 @@
1
1
  import cloneDeep from 'lodash/cloneDeep';
2
+ import store from '@/store';
3
+
4
+ const COLOR_DEFAULT = '#5096db';
5
+ const COLOR_ERROR = '##FF0000';
6
+ const COLOR_IN_PROGRESS = '#1572C2';
7
+ const COLOR_IDLE = '#ced4da';
8
+ const COLOR_COMPLETED = '#00875A';
9
+ const COLOR_COMPLETED_FILL = '#edfffc';
2
10
 
3
11
  const errorHighlighter = {
4
12
  highlighter: {
@@ -6,7 +14,7 @@ const errorHighlighter = {
6
14
  options: {
7
15
  padding: 10,
8
16
  attrs: {
9
- stroke: 'red',
17
+ stroke: COLOR_ERROR,
10
18
  'stroke-width': 10,
11
19
  opacity: 0.3,
12
20
  },
@@ -19,7 +27,7 @@ const defaultHighlighter = {
19
27
  name: 'stroke',
20
28
  options: {
21
29
  attrs: {
22
- stroke: '#5096db',
30
+ stroke: COLOR_DEFAULT,
23
31
  'stroke-width': 3,
24
32
  'data-cy': 'selected',
25
33
  },
@@ -27,6 +35,43 @@ const defaultHighlighter = {
27
35
  },
28
36
  };
29
37
 
38
+ const completedHighlighter = {
39
+ highlighter: {
40
+ name: 'stroke',
41
+ options: {
42
+ attrs: {
43
+ stroke: COLOR_COMPLETED,
44
+ 'stroke-width': 3,
45
+ },
46
+ },
47
+ },
48
+ };
49
+
50
+ const inProgressHighlighter = {
51
+ highlighter: {
52
+ name: 'stroke',
53
+ options: {
54
+ attrs: {
55
+ stroke: COLOR_IN_PROGRESS,
56
+ 'stroke-width': 3,
57
+ 'stroke-dasharray': '4 4',
58
+ },
59
+ },
60
+ },
61
+ };
62
+
63
+ const idleHighlighter = {
64
+ highlighter: {
65
+ name: 'stroke',
66
+ options: {
67
+ attrs: {
68
+ stroke: COLOR_IDLE,
69
+ 'stroke-width': 3,
70
+ },
71
+ },
72
+ },
73
+ };
74
+
30
75
  export default {
31
76
  props: [
32
77
  'highlighted',
@@ -34,6 +79,9 @@ export default {
34
79
  'hasError',
35
80
  'autoValidate',
36
81
  'borderOutline',
82
+ 'isCompleted',
83
+ 'isInProgress',
84
+ 'isIdle',
37
85
  ],
38
86
  data() {
39
87
  return {
@@ -68,6 +116,23 @@ export default {
68
116
  },
69
117
  methods: {
70
118
  setShapeHighlight() {
119
+ if (store.getters.isReadOnly) {
120
+ this.shapeView.unhighlight(this.shapeBody, completedHighlighter);
121
+ if (this.isCompleted) {
122
+ this.shape.attr('body/fill', COLOR_COMPLETED_FILL);
123
+ this.shapeView.highlight(this.shapeBody, completedHighlighter);
124
+ }
125
+ this.shapeView.unhighlight(this.shapeBody, inProgressHighlighter);
126
+ if (this.isInProgress) {
127
+ this.shapeView.highlight(this.shapeBody, inProgressHighlighter);
128
+ }
129
+ if (this.isIdle) {
130
+ this.shape.attr('body/fill', COLOR_IDLE);
131
+ this.shapeView.highlight(this.shapeBody, idleHighlighter);
132
+ }
133
+ return;
134
+ }
135
+
71
136
  if (!this.shapeView) {
72
137
  return;
73
138
  }
@@ -84,7 +149,9 @@ export default {
84
149
  if (this.currentBorderOutline) {
85
150
  this.shapeView.unhighlight(this.shapeBody, this.currentBorderOutline);
86
151
  }
87
- this.currentBorderOutline = borderOutline ? cloneDeep(borderOutline) : null;
152
+ this.currentBorderOutline = borderOutline
153
+ ? cloneDeep(borderOutline)
154
+ : null;
88
155
  if (this.currentBorderOutline) {
89
156
  this.shapeView.highlight(this.shapeBody, this.currentBorderOutline);
90
157
  }
@@ -92,14 +159,15 @@ export default {
92
159
  },
93
160
  mounted() {
94
161
  this.$nextTick(() => {
95
- this.paperManager.awaitScheduledUpdates()
96
- .then(() => {
97
- this.setShapeHighlight();
98
- this.shape.on('change:size', () => {
99
- this.paperManager.awaitScheduledUpdates().then(this.setShapeHighlight);
100
- this.$emit('shape-resize', this.shape);
101
- });
162
+ this.paperManager.awaitScheduledUpdates().then(() => {
163
+ this.setShapeHighlight();
164
+ this.shape.on('change:size', () => {
165
+ this.paperManager
166
+ .awaitScheduledUpdates()
167
+ .then(this.setShapeHighlight);
168
+ this.$emit('shape-resize', this.shape);
102
169
  });
170
+ });
103
171
  });
104
172
  },
105
173
  };
@@ -15,8 +15,11 @@ function isPoint(item) {
15
15
  return item.x && item.y;
16
16
  }
17
17
 
18
+ const COLOR_IDLE = '#ced4da';
19
+ const COLOR_COMPLETED = '#00875A';
20
+
18
21
  export default {
19
- props: ['highlighted', 'paper'],
22
+ props: ['highlighted', 'paper', 'paperManager', 'isCompleted'],
20
23
  data() {
21
24
  return {
22
25
  sourceShape: null,
@@ -40,6 +43,9 @@ export default {
40
43
  }
41
44
  },
42
45
  highlighted(highlighted) {
46
+ if (store.getters.isReadOnly) {
47
+ return;
48
+ }
43
49
  if (highlighted) {
44
50
  this.shape.attr({
45
51
  line: { stroke: '#5096db' },
@@ -73,6 +79,12 @@ export default {
73
79
  },
74
80
  },
75
81
  methods: {
82
+ setShapeHighlight() {
83
+ const COLOR = this.isCompleted ? COLOR_COMPLETED : COLOR_IDLE;
84
+ this.shape.attr({
85
+ line: { stroke: COLOR },
86
+ });
87
+ },
76
88
  findSourceShape() {
77
89
  return this.graph.getElements().find(element => {
78
90
  return element.component && element.component.node.definition === this.node.definition.get('sourceRef');
@@ -120,6 +132,8 @@ export default {
120
132
  resetShapeColor(targetShape);
121
133
 
122
134
  this.shape.on('change:vertices', this.onChangeVertices);
135
+ this.shape.listenTo(this.sourceShape, 'change:position', this.updateWaypoints);
136
+ this.shape.listenTo(targetShape, 'change:position', this.updateWaypoints);
123
137
 
124
138
  const sourceShape = this.shape.getSourceElement();
125
139
  sourceShape.embed(this.shape);
@@ -127,13 +141,15 @@ export default {
127
141
  },
128
142
  /**
129
143
  * On Change vertices handler
130
- * @param {Object} link
131
- * @param {Array} vertices
132
- * @param {Object} options
144
+ * @param {Object} link
145
+ * @param {Array} vertices
146
+ * @param {Object} options
133
147
  */
134
- onChangeVertices(link, vertices, options){
148
+ async onChangeVertices(link, vertices, options){
135
149
  if (options && options.ui) {
136
150
  this.updateWaypoints();
151
+ await this.$nextTick();
152
+ this.$emit('save-state');
137
153
  }
138
154
  },
139
155
  updateWaypoints() {
@@ -234,7 +250,6 @@ export default {
234
250
  emitSave() {
235
251
  if (this.highlighted) {
236
252
  this.updateWaypoints.flush();
237
- this.$emit('save-state');
238
253
  document.removeEventListener('mouseup', this.emitSave);
239
254
  this.listeningToMouseup = false;
240
255
  }
@@ -255,9 +270,10 @@ export default {
255
270
 
256
271
  this.$once('click', () => {
257
272
  this.$nextTick(() => {
258
- if (store.getters.isReadOnly === false) {
259
- this.setupLinkTools();
273
+ if (store.getters.isReadOnly) {
274
+ return;
260
275
  }
276
+ this.setupLinkTools();
261
277
  });
262
278
  });
263
279
 
@@ -319,6 +335,14 @@ export default {
319
335
  this.shape.on('change:vertices', function() {
320
336
  this.component.$emit('shape-resize');
321
337
  });
338
+
339
+ if (store.getters.isReadOnly) {
340
+ this.$nextTick(() => {
341
+ this.paperManager.awaitScheduledUpdates().then(() => {
342
+ this.setShapeHighlight();
343
+ });
344
+ });
345
+ }
322
346
  },
323
347
  beforeDestroy() {
324
348
  document.removeEventListener('mouseup', this.emitSave);