@processmaker/modeler 1.31.0 → 1.32.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 (40) hide show
  1. package/dist/.DS_Store +0 -0
  2. package/dist/img/issue-close.5d1630e6.svg +3 -0
  3. package/dist/img/issue-item.3187f291.svg +3 -0
  4. package/dist/img/issue-open.707390b4.svg +4 -0
  5. package/dist/img/validate-close.09ace97a.svg +4 -0
  6. package/dist/img/validate-open.b0ecf74e.svg +4 -0
  7. package/dist/modeler.common.js +1074 -398
  8. package/dist/modeler.common.js.map +1 -1
  9. package/dist/modeler.umd.js +1074 -398
  10. package/dist/modeler.umd.js.map +1 -1
  11. package/dist/modeler.umd.min.js +4 -4
  12. package/dist/modeler.umd.min.js.map +1 -1
  13. package/package.json +2 -2
  14. package/src/.DS_Store +0 -0
  15. package/src/ModelerApp.vue +0 -9
  16. package/src/assets/topRail/issue-close.svg +3 -0
  17. package/src/assets/topRail/issue-item.svg +3 -0
  18. package/src/assets/topRail/issue-open.svg +4 -0
  19. package/src/assets/topRail/validate-close.svg +4 -0
  20. package/src/assets/topRail/validate-open.svg +4 -0
  21. package/src/components/hotkeys/escKey.js +20 -0
  22. package/src/components/hotkeys/main.js +4 -2
  23. package/src/components/modeler/Modeler.vue +3 -0
  24. package/src/components/modeler/ModelerReadonly.vue +21 -6
  25. package/src/components/railBottom/controls/Controls.vue +7 -75
  26. package/src/components/rails/explorer-rail/nodeTypesLoop/nodeTypesLoop.vue +2 -72
  27. package/src/components/toolbar/ToolBar.vue +23 -14
  28. package/src/components/topRail/TopRail.vue +91 -0
  29. package/src/components/topRail/topRail.scss +6 -0
  30. package/src/components/topRail/validateControl/index.js +3 -0
  31. package/src/components/topRail/validateControl/validateButton/ValidateButton.vue +38 -0
  32. package/src/components/topRail/validateControl/validateButton/validateButton.scss +25 -0
  33. package/src/components/topRail/validateControl/validateIssue/ValidateIssue.vue +59 -0
  34. package/src/components/topRail/validateControl/validateIssue/validateIssue.scss +54 -0
  35. package/src/components/topRail/validateControl/validatePanel/ValidatePanel.vue +51 -0
  36. package/src/components/topRail/validateControl/validatePanel/validatePanel.scss +67 -0
  37. package/src/mixins/clickAndDrop.js +100 -0
  38. package/src/mixins/highlightConfig.js +52 -8
  39. package/src/mixins/linkConfig.js +6 -2
  40. package/src/nodeTypesStore.js +15 -0
@@ -0,0 +1,59 @@
1
+ <template>
2
+ <button
3
+ type="button"
4
+ :disabled="numberOfErrors === 0"
5
+ @click.prevent="handleOpen"
6
+ class="issue-box"
7
+ >
8
+ <span class="issue-title">Issues</span>
9
+
10
+ <span class="issue-badge">{{ numberOfErrors }}</span>
11
+
12
+ <span class="issue-icon">
13
+ <inline-svg :src="isOpen ? issueOpenIcon : issueCloseIcon" />
14
+ </span>
15
+ </button>
16
+ </template>
17
+
18
+ <script>
19
+ import InlineSvg from 'vue-inline-svg';
20
+
21
+ export default {
22
+ components: {
23
+ InlineSvg,
24
+ },
25
+ props: {
26
+ numberOfErrors: {
27
+ type: Number,
28
+ required: true,
29
+ },
30
+ },
31
+ data() {
32
+ return {
33
+ isOpen: false,
34
+ issueCloseIcon: require('@/assets/topRail/issue-close.svg'),
35
+ issueOpenIcon: require('@/assets/topRail/issue-open.svg'),
36
+ };
37
+ },
38
+ watch: {
39
+ numberOfErrors(newValue) {
40
+ // Checks the number of errors if it is "0" reset the issue icon
41
+ if (newValue === 0) {
42
+ this.isOpen = false;
43
+ }
44
+ },
45
+ },
46
+ methods: {
47
+ /**
48
+ * Show/hide the issue panel
49
+ */
50
+ handleOpen() {
51
+ this.isOpen = !this.isOpen;
52
+
53
+ this.$emit('openPanel', this.isOpen);
54
+ },
55
+ },
56
+ };
57
+ </script>
58
+
59
+ <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,51 @@
1
+ <template>
2
+ <div class="validate-container">
3
+ <div v-for="(error, index) in errorList" :key="`${error.errorId}_${index}`" class="validate-item-box">
4
+ <vue-inline-svg :src="issueIcon" />
5
+
6
+ <div class="validate-item-info">
7
+ <div class="validate-item-title">{{ error.errorKey }}</div>
8
+ <div class="validate-item-description">{{ error.message }}.</div>
9
+ <div class="validate-item-node" v-if="error.id">
10
+ <span class="validate-item-node-title">{{ $t('Node ID') }}:</span> {{ error.id }}
11
+ </div>
12
+ </div>
13
+ </div>
14
+
15
+ <div v-for="(warning, index) in warnings" :key="warning.title + index" class="validate-item-box">
16
+ <vue-inline-svg :src="issueIcon" />
17
+
18
+ <div class="validate-item-info">
19
+ <div class="validate-item-title">{{ warning.title }}</div>
20
+ <div class="validate-item-description">{{ warning.text }}.</div>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ </template>
25
+
26
+ <script>
27
+ import VueInlineSvg from 'vue-inline-svg';
28
+
29
+ export default {
30
+ components: {
31
+ VueInlineSvg,
32
+ },
33
+ props: {
34
+ errorList: {
35
+ type: Array,
36
+ required: true,
37
+ },
38
+ warnings: {
39
+ type: Array,
40
+ required: true,
41
+ },
42
+ },
43
+ data() {
44
+ return {
45
+ issueIcon: require('@/assets/topRail/issue-item.svg'),
46
+ };
47
+ },
48
+ };
49
+ </script>
50
+
51
+ <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: 1;
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,100 @@
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
+ document.removeEventListener('mousemove', this.setDraggingPosition);
30
+ document.body.removeChild(this.movedElement);
31
+ this.$emit('onSetCursor', 'none');
32
+ nodeTypesStore.commit('clearSelectedNode');
33
+ nodeTypesStore.commit('setGhostNode', null);
34
+ this.wasClicked = false;
35
+ return;
36
+ }
37
+ this.wasClicked = true;
38
+ nodeTypesStore.commit('setSelectedNode', control);
39
+ this.$emit('onSetCursor', 'crosshair');
40
+ if (!this.parent) {
41
+ this.popperType = control.type;
42
+ }
43
+ window.ProcessMaker.EventBus.$on('custom-pointerclick', message => {
44
+ window.ProcessMaker.EventBus.$off('custom-pointerclick');
45
+ document.removeEventListener('mousemove', this.setDraggingPosition);
46
+ if (this.movedElement) {
47
+ document.body.removeChild(this.movedElement);
48
+ }
49
+ this.popperType = null;
50
+ this.selectedSubmenuItem = null;
51
+ this.onCreateElement(message);
52
+ nodeTypesStore.commit('clearSelectedNode');
53
+ nodeTypesStore.commit('setGhostNode', null);
54
+ });
55
+ },
56
+ onCreateElement(event){
57
+ if (this.wasClicked && this.selectedItem) {
58
+ if (this.parent) {
59
+ this.parent = null;
60
+ }
61
+ this.$emit('onCreateElement', { event, control: this.selectedItem });
62
+ this.$emit('onSetCursor', 'none');
63
+ event.preventDefault();
64
+ this.wasClicked = false;
65
+ }
66
+ },
67
+ setDraggingPosition({ pageX, pageY }) {
68
+ let tempGhost = this.movedElement;
69
+ tempGhost.style.left = `${pageX}px`;
70
+ tempGhost.style.top = `${pageY}px`;
71
+ nodeTypesStore.commit('setGhostNode', tempGhost);
72
+ },
73
+ createDraggingHelper(event, control) {
74
+ if (this.movedElement) {
75
+ document.removeEventListener('mousemove', this.setDraggingPosition);
76
+ document.body.removeChild(this.movedElement);
77
+ nodeTypesStore.commit('setGhostNode', null);
78
+ }
79
+ const sourceElement = event.target;
80
+ nodeTypesStore.commit('setGhostNode', document.createElement('img'));
81
+ let tempGhost = this.movedElement;
82
+ Object.keys(this.helperStyles).forEach((property) => {
83
+ tempGhost.style[property] = this.helperStyles[property];
84
+ });
85
+ tempGhost.src = control.icon;
86
+ nodeTypesStore.commit('setGhostNode', tempGhost);
87
+ document.body.appendChild(this.movedElement);
88
+ this.xOffset = event.clientX - sourceElement.getBoundingClientRect().left;
89
+ this.yOffset = event.clientY - sourceElement.getBoundingClientRect().top;
90
+ },
91
+ },
92
+ computed: {
93
+ selectedItem() {
94
+ return nodeTypesStore.getters.getSelectedNode;
95
+ },
96
+ movedElement() {
97
+ return nodeTypesStore.getters.getGhostNode;
98
+ },
99
+ },
100
+ };
@@ -1,4 +1,6 @@
1
+ /* eslint-disable no-unused-vars */
1
2
  import cloneDeep from 'lodash/cloneDeep';
3
+ import store from '@/store';
2
4
 
3
5
  const errorHighlighter = {
4
6
  highlighter: {
@@ -27,6 +29,31 @@ const defaultHighlighter = {
27
29
  },
28
30
  };
29
31
 
32
+ const completedHighlighter = {
33
+ highlighter: {
34
+ name: 'stroke',
35
+ options: {
36
+ attrs: {
37
+ stroke: '#1572C2',
38
+ 'stroke-width': 3,
39
+ },
40
+ },
41
+ },
42
+ };
43
+
44
+ const inProgressHighlighter = {
45
+ highlighter: {
46
+ name: 'stroke',
47
+ options: {
48
+ attrs: {
49
+ stroke: '#00875A',
50
+ 'stroke-width': 3,
51
+ 'stroke-dasharray': '4 4',
52
+ },
53
+ },
54
+ },
55
+ };
56
+
30
57
  export default {
31
58
  props: [
32
59
  'highlighted',
@@ -34,6 +61,8 @@ export default {
34
61
  'hasError',
35
62
  'autoValidate',
36
63
  'borderOutline',
64
+ 'isCompleted',
65
+ 'isInProgress',
37
66
  ],
38
67
  data() {
39
68
  return {
@@ -68,6 +97,18 @@ export default {
68
97
  },
69
98
  methods: {
70
99
  setShapeHighlight() {
100
+ if (store.getters.isReadOnly) {
101
+ this.shapeView.unhighlight(this.shapeBody, completedHighlighter);
102
+ if (this.isCompleted) {
103
+ this.shapeView.highlight(this.shapeBody, completedHighlighter);
104
+ }
105
+ this.shapeView.unhighlight(this.shapeBody, inProgressHighlighter);
106
+ if (this.isInProgress) {
107
+ this.shapeView.highlight(this.shapeBody, inProgressHighlighter);
108
+ }
109
+ return;
110
+ }
111
+
71
112
  if (!this.shapeView) {
72
113
  return;
73
114
  }
@@ -84,7 +125,9 @@ export default {
84
125
  if (this.currentBorderOutline) {
85
126
  this.shapeView.unhighlight(this.shapeBody, this.currentBorderOutline);
86
127
  }
87
- this.currentBorderOutline = borderOutline ? cloneDeep(borderOutline) : null;
128
+ this.currentBorderOutline = borderOutline
129
+ ? cloneDeep(borderOutline)
130
+ : null;
88
131
  if (this.currentBorderOutline) {
89
132
  this.shapeView.highlight(this.shapeBody, this.currentBorderOutline);
90
133
  }
@@ -92,14 +135,15 @@ export default {
92
135
  },
93
136
  mounted() {
94
137
  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
- });
138
+ this.paperManager.awaitScheduledUpdates().then(() => {
139
+ this.setShapeHighlight();
140
+ this.shape.on('change:size', () => {
141
+ this.paperManager
142
+ .awaitScheduledUpdates()
143
+ .then(this.setShapeHighlight);
144
+ this.$emit('shape-resize', this.shape);
102
145
  });
146
+ });
103
147
  });
104
148
  },
105
149
  };
@@ -40,6 +40,9 @@ export default {
40
40
  }
41
41
  },
42
42
  highlighted(highlighted) {
43
+ if (store.getters.isReadOnly) {
44
+ return;
45
+ }
43
46
  if (highlighted) {
44
47
  this.shape.attr({
45
48
  line: { stroke: '#5096db' },
@@ -255,9 +258,10 @@ export default {
255
258
 
256
259
  this.$once('click', () => {
257
260
  this.$nextTick(() => {
258
- if (store.getters.isReadOnly === false) {
259
- this.setupLinkTools();
261
+ if (store.getters.isReadOnly) {
262
+ return;
260
263
  }
264
+ this.setupLinkTools();
261
265
  });
262
266
  });
263
267
 
@@ -12,6 +12,8 @@ export default new Vuex.Store({
12
12
  filteredNodeTypes: [],
13
13
  explorerOpen: false,
14
14
  searchTerm: '',
15
+ selectedNode: null,
16
+ ghostNode: null,
15
17
  },
16
18
  getters: {
17
19
  getNodeTypes: state => state.nodeTypes,
@@ -19,6 +21,8 @@ export default new Vuex.Store({
19
21
  getFilteredNodeTypes: state => state.filteredNodeTypes,
20
22
  getExplorerOpen: state => state.explorerOpen,
21
23
  getSearchTerm: state => state.searchTerm,
24
+ getSelectedNode: state => state.selectedNode,
25
+ getGhostNode: state => state.ghostNode,
22
26
  },
23
27
  mutations: {
24
28
  setNodeTypes(state, nodeTypes) {
@@ -37,6 +41,8 @@ export default new Vuex.Store({
37
41
  },
38
42
  setPinnedNodes(state, payload) {
39
43
  state.pinnedNodeTypes.push(payload);
44
+ // Remove duplicates
45
+ state.pinnedNodeTypes = [...new Map(state.pinnedNodeTypes.map(node => [node['type'], node])).values()];
40
46
  state.pinnedNodeTypes.sort((node1, node2) => node1.rank - node2.rank);
41
47
  },
42
48
  setUnpinNode(state, payload) {
@@ -61,6 +67,15 @@ export default new Vuex.Store({
61
67
  toggleExplorer(state) {
62
68
  state.explorerOpen = !state.explorerOpen;
63
69
  },
70
+ setSelectedNode(state, payload) {
71
+ state.selectedNode = payload;
72
+ },
73
+ clearSelectedNode(state) {
74
+ state.selectedNode = null;
75
+ },
76
+ setGhostNode(state, payload) {
77
+ state.ghostNode = payload;
78
+ },
64
79
  },
65
80
  actions: {
66
81
  getUserPinnedObjects({ commit }) {