@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
@@ -4,6 +4,7 @@ import { faTimes } from '@fortawesome/free-solid-svg-icons';
4
4
  import nodeTypesStore from '@/nodeTypesStore';
5
5
  import FilterNodeTypes from '@/components/rails/explorer-rail/filterNodeTypes/filterNodeTypes.vue';
6
6
  import NodeTypesLoop from '@/components/rails/explorer-rail/nodeTypesLoop/nodeTypesLoop.vue';
7
+ import PmBlocksLoop from '@/components/rails/explorer-rail/pmBlocksLoop/pmBlocksLoop.vue';
7
8
 
8
9
  export default {
9
10
  name: 'ExplorerRail',
@@ -14,11 +15,15 @@ export default {
14
15
  nodeTypes: {
15
16
  type: Array,
16
17
  },
18
+ pmBlockNodes: {
19
+ type: Array,
20
+ },
17
21
  },
18
22
  components: {
19
23
  FontAwesomeIcon,
20
24
  FilterNodeTypes,
21
25
  NodeTypesLoop,
26
+ PmBlocksLoop,
22
27
  },
23
28
  data() {
24
29
  return {
@@ -59,6 +64,7 @@ export default {
59
64
  },
60
65
  clearFilteredObjects() {
61
66
  nodeTypesStore.commit('clearFilteredNodes');
67
+ nodeTypesStore.commit('clearFilteredPmBlockNodes');
62
68
  },
63
69
  },
64
70
  };
@@ -79,13 +85,16 @@ export default {
79
85
  </div>
80
86
  </div>
81
87
  <div class="node-types__container" v-if="tabIndex === 0">
82
- <filter-node-types />
88
+ <filter-node-types :type="'object'"/>
83
89
  <node-types-loop
84
90
  v-on="$listeners"
85
91
  />
86
92
  </div>
87
- <div class="pm-blocks__container">
88
- <!-- Here goes the PM Blocks -->
93
+ <div class="pm-blocks__container" v-if="tabIndex === 1">
94
+ <filter-node-types :type="'pmBlock'"/>
95
+ <pm-blocks-loop
96
+ v-on="$listeners"
97
+ />
89
98
  </div>
90
99
  </div>
91
100
  </template>
@@ -2,16 +2,21 @@
2
2
  import nodeTypesStore from '@/nodeTypesStore';
3
3
  export default {
4
4
  name: 'FilterNodeTypes',
5
+ props: ['type'],
5
6
  data() {
6
7
  return {
7
8
  searchTerm: '',
8
- placeholder: this.$t('Seach Objects'),
9
9
  };
10
10
  },
11
11
  watch: {
12
12
  searchTerm(value) {
13
- if (value.length === 0) nodeTypesStore.commit('clearFilteredNodes');
14
- if (value.length > 0) nodeTypesStore.commit('setFilteredNodeTypes', value);
13
+ if (this.type === 'pmBlock') {
14
+ if (value.length === 0) nodeTypesStore.commit('clearFilteredPmBlockNodes');
15
+ if (value.length > 0) nodeTypesStore.commit('setFilteredPmBlockNodeTypes', value);
16
+ } else {
17
+ if (value.length === 0) nodeTypesStore.commit('clearFilteredNodes');
18
+ if (value.length > 0) nodeTypesStore.commit('setFilteredNodeTypes', value);
19
+ }
15
20
  },
16
21
  },
17
22
  computed: {
@@ -20,6 +25,13 @@ export default {
20
25
  const nodeTypes = nodeTypesStore.getters.getNodeTypes;
21
26
  return [...pinnedNodeTypes, ...nodeTypes];
22
27
  },
28
+ pmBlockNodes() {
29
+ const pmBlockNodeTypes = nodeTypesStore.getters.getPmBlockNodeTypes;
30
+ return [...pmBlockNodeTypes];
31
+ },
32
+ placeholder() {
33
+ return this.type === 'pmBlock' ? this.$t('Search PM Blocks') : this.$t('Search Objects');
34
+ },
23
35
  },
24
36
  };
25
37
  </script>
@@ -2,29 +2,16 @@
2
2
  import pinIcon from '@/assets/pin-angle.svg';
3
3
  import pinFillIcon from '@/assets/pin-angle-fill.svg';
4
4
  import nodeTypesStore from '@/nodeTypesStore';
5
+ import clickAndDrop from '@/mixins/clickAndDrop';
5
6
 
6
7
  export default {
7
8
  name: 'NodeTypesLoop',
9
+ mixins: [clickAndDrop],
8
10
  data() {
9
11
  return {
10
12
  pinIcon,
11
13
  pinFillIcon,
12
14
  showPin: false,
13
- wasClicked: false,
14
- element: null,
15
- selectedItem: null,
16
- xOffset: 0,
17
- yOffset: 0,
18
- movedElement: null,
19
- helperStyles: {
20
- backgroundColor:'#ffffff',
21
- position: 'absolute',
22
- height: '40px',
23
- width: '40px',
24
- zIndex: '10',
25
- opacity: '0.5',
26
- pointerEvents: 'none',
27
- },
28
15
  };
29
16
  },
30
17
  created() {
@@ -35,68 +22,13 @@ export default {
35
22
  return !!this.pinnedObjects.find(obj => obj.type === type);
36
23
  },
37
24
  unPin(object) {
25
+ this.deselect();
38
26
  return nodeTypesStore.dispatch('removeUserPinnedObject', object);
39
27
  },
40
28
  addPin(object) {
29
+ this.deselect();
41
30
  return nodeTypesStore.dispatch('addUserPinnedObject', object);
42
31
  },
43
- onClickHandler(event, control) {
44
- this.createDraggingHelper(event, control);
45
- document.addEventListener('mousemove', this.setDraggingPosition);
46
- this.setDraggingPosition(event);
47
- // Deselect control on click if same control is already selected
48
- if (this.selectedItem === control.type) {
49
- document.removeEventListener('mousemove', this.setDraggingPosition);
50
- document.body.removeChild(this.movedElement);
51
- this.$emit('onSetCursor', 'none');
52
- this.selectedItem = null;
53
- this.movedElement = null;
54
- this.wasClicked = false;
55
- return;
56
- }
57
- this.wasClicked = true;
58
- this.element = control;
59
- this.$emit('onSetCursor', 'crosshair');
60
- this.selectedItem = control.type;
61
- window.ProcessMaker.EventBus.$on('custom-pointerclick', message => {
62
- window.ProcessMaker.EventBus.$off('custom-pointerclick');
63
- document.removeEventListener('mousemove', this.setDraggingPosition);
64
- if (this.movedElement) {
65
- document.body.removeChild(this.movedElement);
66
- }
67
- this.selectedItem = null;
68
- this.movedElement = null;
69
- this.onCreateElement(message);
70
- });
71
- },
72
- createDraggingHelper(event, control) {
73
- if (this.movedElement) {
74
- document.removeEventListener('mousemove', this.setDraggingPosition);
75
- document.body.removeChild(this.movedElement);
76
- this.movedElement = null;
77
- }
78
- const sourceElement = event.target;
79
- this.movedElement = document.createElement('img');
80
- Object.keys(this.helperStyles).forEach((property) => {
81
- this.movedElement.style[property] = this.helperStyles[property];
82
- });
83
- this.movedElement.src = control.icon;
84
- document.body.appendChild(this.movedElement);
85
- this.xOffset = event.clientX - sourceElement.getBoundingClientRect().left;
86
- this.yOffset = event.clientY - sourceElement.getBoundingClientRect().top;
87
- },
88
- setDraggingPosition({ pageX, pageY }) {
89
- this.movedElement.style.left = pageX + 'px';
90
- this.movedElement.style.top = pageY + 'px';
91
- },
92
- onCreateElement(event){
93
- if (this.wasClicked && this.element) {
94
- this.$emit('onCreateElement', { event, control: this.element });
95
- this.$emit('onSetCursor', 'none');
96
- event.preventDefault();
97
- this.wasClicked = false;
98
- }
99
- },
100
32
  },
101
33
  computed: {
102
34
  pinnedObjects() {
@@ -125,10 +57,11 @@ export default {
125
57
  <template v-for="object in filteredNodes">
126
58
  <div
127
59
  class="node-types__item"
60
+ :data-test="object.type"
128
61
  :key="object.id"
129
62
  @mouseover="showPin = true"
130
63
  @mouseleave="showPin = false"
131
- @click.stop="onClickHandler($event, object)"
64
+ @click.self="onClickHandler($event, object)"
132
65
  >
133
66
  <img class="node-types__item__icon" :src="object.icon" :alt="$t(object.label)">
134
67
  <span>{{ $t(object.label) }}</span>
@@ -155,6 +88,7 @@ export default {
155
88
  <template v-for="pinnedObject in pinnedObjects">
156
89
  <div
157
90
  class="node-types__item"
91
+ :data-test="pinnedObject.type"
158
92
  :key="pinnedObject.id"
159
93
  @mouseover="showPin = true"
160
94
  @mouseleave="showPin = false"
@@ -176,6 +110,7 @@ export default {
176
110
  <template v-for="nodeType in unpinnedObjects">
177
111
  <div
178
112
  class="node-types__item"
113
+ :data-test="nodeType.type"
179
114
  :key="nodeType.id"
180
115
  @mouseover="showPin = true"
181
116
  @mouseleave="showPin = false"
@@ -0,0 +1,76 @@
1
+ <script>
2
+ import nodeTypesStore from '@/nodeTypesStore';
3
+ import clickAndDrop from '@/mixins/clickAndDrop';
4
+
5
+ export default {
6
+ name: 'PmBlocksLoop',
7
+ mixins: [clickAndDrop],
8
+ computed: {
9
+ pmBlockNodeTypes() {
10
+ return nodeTypesStore.getters.getPmBlockNodeTypes;
11
+ },
12
+ filteredPmBlockNodes() {
13
+ return nodeTypesStore.getters.getFilteredPmBlockNodeTypes;
14
+ },
15
+ searchTerm() {
16
+ return nodeTypesStore.getters.getSearchTerm;
17
+ },
18
+ },
19
+ };
20
+ </script>
21
+
22
+ <template>
23
+ <div id="pmBlockNodeTypesList">
24
+ <div id="filteredPmBlockNodes-container" v-if="filteredPmBlockNodes.length > 0">
25
+ <template v-for="object in filteredPmBlockNodes">
26
+ <div
27
+ class="node-types__item"
28
+ :key="object.id"
29
+ @click.stop="onClickHandler($event, object)"
30
+ >
31
+ <img class="node-types__item__icon" :src="object.icon" :alt="$t(object.label)">
32
+ <span>{{ $t(object.label) }}</span>
33
+ </div>
34
+ </template>
35
+ </div>
36
+ <template v-if="filteredPmBlockNodes.length === 0 && !searchTerm">
37
+ <div class="pmBlocksContainer p-2">
38
+ <template v-for="nodeType in pmBlockNodeTypes">
39
+ <div
40
+ class="pm-block-node-types__item p-2 d-block"
41
+ :key="nodeType.id"
42
+ @click.stop="onClickHandler($event, nodeType)"
43
+ >
44
+ <label>{{ $t(nodeType.label) }}</label>
45
+ <span class="d-block">{{ nodeType.description }}</span>
46
+ </div>
47
+ </template>
48
+ </div>
49
+ </template>
50
+ </div>
51
+ </template>
52
+
53
+ <style lang="scss">
54
+ .pm-block-node-types {
55
+ &__item {
56
+ display: block;
57
+ border-radius: 4px;
58
+ user-select: none;
59
+ margin-bottom: 8px;
60
+ border: 1px solid #b6bfc6;
61
+ &:hover {
62
+ background-color: #EBEEF2;
63
+ }
64
+ label {
65
+ font-size: 14px;
66
+ line-height: 8px;
67
+ font-weight: 600;
68
+ color: #104A75;
69
+ }
70
+ span {
71
+ font-size: 12px;
72
+ color:#6C757D;
73
+ }
74
+ }
75
+ }
76
+ </style>
@@ -26,7 +26,7 @@ function isNotLane(shape) {
26
26
  function bringPoolToFront(poolShape) {
27
27
  bringShapeToFront(poolShape);
28
28
 
29
- const hasLanes = poolShape.component.node.definition.processRef.laneSets[0];
29
+ const hasLanes = poolShape.component.node.definition.processRef && poolShape.component.node.definition.processRef.laneSets[0];
30
30
  if (!hasLanes) {
31
31
  return;
32
32
  }
@@ -4,49 +4,53 @@
4
4
  aria-label="Toolbar" :class="{ 'ignore-pointer': canvasDragPosition }"
5
5
  >
6
6
  <breadcrumb :breadcrumb-data="breadcrumbData" />
7
- <div class="mr-3">
8
- <align-buttons @save-state="$emit('save-state')" />
7
+ <div class="d-flex mr-3">
8
+ <TopRail
9
+ :validation-errors="validationErrors"
10
+ :warnings="warnings"
11
+ >
12
+ <component
13
+ :is="component.button"
14
+ v-for="(component, index) in validationBar"
15
+ :key="`validation-status-${index}`"
16
+ />
17
+ </TopRail>
9
18
 
10
-
11
- <div class="btn-group btn-group-sm mr-2" role="group" aria-label="Additional controls">
12
- <b-button
13
- class="btn btn-sm btn-secondary ml-auto"
14
- data-test="panels-btn"
15
- @click="$emit('toggle-panels-compressed')"
16
- v-b-tooltip.hover
17
- :title="panelsCompressed ? $t('Show Menus') : $t('Hide Menus')"
18
- >
19
- <font-awesome-icon :icon="panelsCompressed ? expandIcon : compressIcon" />
20
- </b-button>
21
- </div>
22
- <div class="btn-group btn-group-sm" role="group" aria-label="Publish controls">
19
+ <div
20
+ class="d-flex align-items-center btn-group btn-group-sm"
21
+ role="group"
22
+ aria-label="Publish controls"
23
+ data-cy="publish-control"
24
+ >
23
25
  <template v-if="isVersionsInstalled">
24
- <div class="d-flex justify-content-center align-items-center text-black text-capitalize" :style="{ width: '65px' }">
25
- <span class="toolbar-item mr-1" :style="{ fontWeight: 600 }">
26
- {{ versionStatus }}
27
- </span>
26
+ <div
27
+ class="toolbar-item toolbar-version-status"
28
+ data-cy="publish-version-status"
29
+ >
30
+ {{ versionStatus }}
28
31
  </div>
29
- <div class="d-flex justify-content-center align-items-center text-black text-capitalize mx-2" :style="{ width: '60px' }">
30
- <span class="toolbar-item mr-1" :style="{ fontWeight: 400 }">
31
- {{ loadingStatus }}
32
- </span>
32
+ <div
33
+ class="toolbar-item toolbar-loading-status"
34
+ data-cy="publish-loading-status"
35
+ >
33
36
  <span>
34
- <font-awesome-icon class="text-success" :icon="loadingIcon" :spin="isLoading" />
37
+ {{ loadingStatus }}
35
38
  </span>
39
+ <font-awesome-icon class="text-success" :icon="loadingIcon" :spin="isLoading" />
36
40
  </div>
37
41
  <a
38
- class="btn btn-sm btn-primary btn-autosave text-uppercase mx-2"
39
- data-test="publish-btn"
40
42
  :title="$t('Publish')"
41
43
  @click="$emit('saveBpmn')"
44
+ class="toolbar-item toolbar-publish"
45
+ data-cy="publish-btn"
42
46
  >
43
47
  {{ $t('Publish') }}
44
48
  </a>
45
49
  <a
46
- class="btn btn-sm btn-link toolbar-item btn-autosave text-black text-uppercase"
47
- data-test="close-btn"
48
50
  :title="$t('Close')"
49
51
  @click="$emit('close')"
52
+ class="toolbar-item toolbar-close"
53
+ data-cy="close-btn"
50
54
  >
51
55
  {{ $t('Close') }}
52
56
  </a>
@@ -56,18 +60,9 @@
56
60
  @navigate="onNavigate"
57
61
  @show="onShow"
58
62
  @hide="onHide"
63
+ data-cy="ellipsis-menu"
59
64
  />
60
65
  </template>
61
- <b-button
62
- v-else
63
- class="btn btn-sm btn-secondary mini-map-btn mx-1"
64
- data-test="mini-map-btn"
65
- v-b-tooltip.hover
66
- :title="$t('Save')"
67
- @click="$emit('saveBpmn')"
68
- >
69
- <font-awesome-icon :icon="saveIcon" />
70
- </b-button>
71
66
  </div>
72
67
  </div>
73
68
  </div>
@@ -78,23 +73,27 @@ import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
78
73
  import { faCompress, faExpand, faMapMarked, faMinus, faPlus, faRedo, faUndo, faSave, faCheckCircle, faSpinner } from '@fortawesome/free-solid-svg-icons';
79
74
  import undoRedoStore from '@/undoRedoStore';
80
75
  import Breadcrumb from '@/components/toolbar/breadcrumb/Breadcrumb';
81
- import AlignButtons from '@/components/toolbar/alignButtons/AlignButtons';
76
+ import TopRail from '@/components/topRail/TopRail.vue';
82
77
 
83
78
  export default {
84
79
  name: 'tool-bar',
85
- components: { Breadcrumb, FontAwesomeIcon, AlignButtons },
86
- props: {
87
- canvasDragPosition: {},
88
- cursor: {},
89
- paperManager: {},
90
- isRendering: {
91
- type: Boolean,
92
- },
93
- breadcrumbData: {
94
- type: Array,
95
- },
96
- panelsCompressed: Boolean,
80
+ components: {
81
+ Breadcrumb,
82
+ TopRail,
83
+ FontAwesomeIcon,
97
84
  },
85
+ props: [
86
+ 'canvasDragPosition',
87
+ 'cursor',
88
+ 'paperManager',
89
+ 'isRendering',
90
+ 'breadcrumbData',
91
+ 'panelsCompressed',
92
+ 'validationErrors',
93
+ 'warnings',
94
+ 'xmlManager',
95
+ 'validationBar',
96
+ ],
98
97
  watch: {
99
98
  miniMapOpen(isOpen) {
100
99
  this.$emit('toggle-mini-map-open', isOpen);
@@ -154,13 +153,18 @@ export default {
154
153
  spinner: faSpinner,
155
154
  ellipsisMenuActions: [
156
155
  {
157
- value: 'discard-draft',
158
- content: this.$t('Discard Draft'),
156
+ value: 'save-template',
157
+ content: this.$t('Save as Template'),
159
158
  icon: '',
160
159
  },
161
160
  {
162
- value: 'save-template',
163
- content: this.$t('Save as Template'),
161
+ value: 'save-pm-block',
162
+ content: this.$t('Save as PM Block'),
163
+ icon: '',
164
+ },
165
+ {
166
+ value: 'discard-draft',
167
+ content: this.$t('Discard Draft'),
164
168
  icon: '',
165
169
  },
166
170
  ],
@@ -193,6 +197,9 @@ export default {
193
197
  case 'save-template':
194
198
  this.$emit('publishTemplate');
195
199
  break;
200
+ case 'save-pm-block':
201
+ this.$emit('publishPmBlock');
202
+ break;
196
203
  default:
197
204
  break;
198
205
  }
@@ -1,7 +1,7 @@
1
1
  $toolbar-background-color: #fff;
2
2
 
3
3
  .toolbar {
4
- z-index: 2;
4
+ z-index: 3;
5
5
  height: $toolbar-height;
6
6
  cursor: auto;
7
7
  width: 100%;
@@ -10,14 +10,61 @@ $toolbar-background-color: #fff;
10
10
  > button {
11
11
  cursor: pointer;
12
12
  }
13
- }
14
13
 
15
- .toolbar-item {
16
- font-family: "Open Sans";
17
- font-style: normal;
18
- font-size: 14px;
19
- letter-spacing: -0.02em;
20
- line-height: 21px;
14
+ &-item {
15
+ display: flex;
16
+ justify-content: center;
17
+ align-items: center;
18
+ font-family: "Open Sans";
19
+ font-size: 14px;
20
+ font-style: normal;
21
+ font-weight: 400;
22
+ color: #000000;
23
+ text-transform: capitalize;
24
+ }
25
+
26
+ &-version-status {
27
+ margin: 0 12px;
28
+ padding-left: 12px;
29
+ border-left: 1px solid #ADB3B8;
30
+ font-weight: 600;
31
+ color: #6C757D;
32
+ }
33
+
34
+ &-loading-status {
35
+ margin-right: 21px;
36
+
37
+ > svg {
38
+ margin-left: 5px;
39
+ }
40
+ }
41
+
42
+ &-publish {
43
+ width: 72px;
44
+ height: 30px;
45
+ margin-right: 21px;
46
+ background-color: #1572C2;
47
+ border-radius: 4px;
48
+ color: #FFFFFF !important;
49
+ text-transform: uppercase;
50
+ text-decoration: none !important;
51
+ cursor: pointer;
52
+ outline: none;
53
+
54
+ &:hover {
55
+ background-color: #065c9d;
56
+ }
57
+ }
58
+
59
+ &-close {
60
+ width: 42px;
61
+ height: 22px;
62
+ margin-right: 21px;
63
+ color: #000000 !important;
64
+ cursor: pointer;
65
+ text-transform: uppercase;
66
+ text-decoration: none !important;
67
+ }
21
68
  }
22
69
 
23
70
  .text-black {
@@ -28,13 +75,6 @@ $toolbar-background-color: #fff;
28
75
  cursor: default !important;
29
76
  }
30
77
 
31
- .btn-autosave {
32
- display: flex;
33
- justify-content: center;
34
- align-items: center;
35
- border-radius: 4px !important;
36
- }
37
-
38
78
  .btn-ellipsis {
39
79
  border-top-left-radius: 4px !important;
40
80
  border-bottom-left-radius: 4px !important;
@@ -0,0 +1,92 @@
1
+ <template>
2
+ <div class="top-rail-container">
3
+ <ValidateIssue
4
+ v-show="isOpenIssue"
5
+ :number-of-errors="numberOfErrors"
6
+ @openPanel="handleOpenPanel"
7
+ />
8
+
9
+ <ValidateButton @openIssue="handleOpenIssue" />
10
+
11
+ <ValidatePanel
12
+ v-show="isOpenIssue && isOpenPanel"
13
+ :error-list="errorList"
14
+ :warnings="warnings"
15
+ />
16
+ <slot />
17
+ </div>
18
+ </template>
19
+
20
+ <script>
21
+ import store from '@/store';
22
+ import { ValidateButton, ValidateIssue, ValidatePanel } from '@/components/topRail/validateControl';
23
+
24
+ export default {
25
+ components: {
26
+ ValidateButton,
27
+ ValidateIssue,
28
+ ValidatePanel,
29
+ },
30
+ props: {
31
+ validationErrors: {
32
+ type: Object,
33
+ required: true,
34
+ },
35
+ warnings: {
36
+ type: Array,
37
+ required: true,
38
+ },
39
+ },
40
+ data() {
41
+ return {
42
+ isOpenIssue: false,
43
+ isOpenPanel: false,
44
+ };
45
+ },
46
+ computed: {
47
+ errorList() {
48
+ // Get a formatted error list to show in the issue panel
49
+ return Object.entries(this.validationErrors)
50
+ .flatMap(([errorKey, errors]) => (
51
+ errors.flatMap(error => ({
52
+ ...error,
53
+ errorKey,
54
+ ...{ 'errorId': `${error.id}_${error.message.split(' ').join('_')}` },
55
+ }))
56
+ ));
57
+ },
58
+ numberOfErrors() {
59
+ // Get the number of errors
60
+ return this.errorList.length + this.warnings.length;
61
+ },
62
+ },
63
+ watch: {
64
+ numberOfErrors(newValue) {
65
+ // Checks the number of errors, if it is "0" hides the panel errors
66
+ if (newValue === 0) {
67
+ this.isOpenPanel = false;
68
+ }
69
+ },
70
+ },
71
+ methods: {
72
+ /**
73
+ * Show/hide the issue button
74
+ * @param {boolean} value
75
+ */
76
+ handleOpenIssue(value) {
77
+ this.isOpenIssue = value;
78
+ // Set the auto-validate value store
79
+ store.commit('setAutoValidate', this.isOpenIssue);
80
+ },
81
+ /**
82
+ * Show/hide the issue panel
83
+ * @param {boolean} value
84
+ */
85
+ handleOpenPanel(value) {
86
+ this.isOpenPanel = value;
87
+ },
88
+ },
89
+ };
90
+ </script>
91
+
92
+ <style scoped lang="scss" src="./topRail.scss"></style>
@@ -0,0 +1,6 @@
1
+ .top-rail-container {
2
+ position: relative;
3
+ display: flex;
4
+ align-items: center;
5
+ padding: 0px 8px;
6
+ }
@@ -0,0 +1,3 @@
1
+ export { default as ValidateButton } from './validateButton/ValidateButton.vue';
2
+ export { default as ValidateIssue } from './validateIssue/ValidateIssue.vue';
3
+ export { default as ValidatePanel } from './validatePanel/ValidatePanel.vue';