@processmaker/modeler 1.39.5 → 1.39.7

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@processmaker/modeler",
3
- "version": "1.39.5",
3
+ "version": "1.39.7",
4
4
  "scripts": {
5
5
  "serve": "vue-cli-service serve",
6
6
  "test:unit": "vue-cli-service test:unit",
Binary file
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <crown-button
3
+ v-if="node.isBpmnType(...validPreviewElements)"
4
+ :title="$t('Preview')"
5
+ role="menuitem"
6
+ id="preview-button"
7
+ aria-label="Preview"
8
+ @click="preview()"
9
+ v-b-tooltip.hover.viewport.d50="{ customClass: 'no-pointer-events' }"
10
+ >
11
+ <i class="fas fa-eye cog-container--button"/>
12
+ </crown-button>
13
+ </template>
14
+
15
+ <script>
16
+ import trashIcon from '@/assets/trash-alt-solid.svg';
17
+ import CrownButton from '@/components/crown/crownButtons/crownButton';
18
+ import validPreviewElements from '@/components/crown/crownButtons/validPreviewElements';
19
+
20
+ export default {
21
+ components: { CrownButton },
22
+ props: { graph: Object, shape: Object, node: Object },
23
+ data() {
24
+ return {
25
+ trashIcon,
26
+ validPreviewElements,
27
+ };
28
+ },
29
+ computed: {
30
+ isPoolLane() {
31
+ return this.node.type === 'processmaker-modeler-lane';
32
+ },
33
+ },
34
+ methods: {
35
+ preview() {
36
+ this.$emit('previewNode', this.node);
37
+ },
38
+ },
39
+ };
40
+ </script>
@@ -0,0 +1,11 @@
1
+ const validPreviewElements = [
2
+ 'bpmn:Task',
3
+ 'bpmn:UserTask',
4
+ 'bpmn:GlobalTask',
5
+ 'bpmn:CallActivity',
6
+ 'bpmn:ManualTask',
7
+ 'bpmn:ScriptTask',
8
+ 'bpmn:ServiceTask',
9
+ ];
10
+
11
+ export default validPreviewElements;
@@ -62,6 +62,13 @@
62
62
  v-on="$listeners"
63
63
  />
64
64
 
65
+ <preview-button
66
+ :graph="graph"
67
+ :shape="shape"
68
+ :node="node"
69
+ v-on="$listeners"
70
+ />
71
+
65
72
  <b-modal
66
73
  :no-fade="runningInCypressTest"
67
74
  id="modal-prevent-closing"
@@ -79,6 +86,7 @@
79
86
  </template>
80
87
 
81
88
  <script>
89
+ import PreviewButton from '@/components/crown/crownButtons/previewButton';
82
90
  import DeleteButton from '@/components/crown/crownButtons/deleteButton';
83
91
  import GenericFlowButton from '@/components/crown/crownButtons/genericFlowButton';
84
92
  import AssociationFlowButton from '@/components/crown/crownButtons/associationFlowButton';
@@ -97,6 +105,7 @@ import runningInCypressTest from '@/runningInCypressTest';
97
105
  export default {
98
106
  components: {
99
107
  CrownDropdowns,
108
+ PreviewButton,
100
109
  DeleteButton,
101
110
  GenericFlowButton,
102
111
  AssociationFlowButton,
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <div class="no-preview">
3
+ <img :src="noPreviewImg" alt="no preview">
4
+ <h1>No Screen Asigned</h1>
5
+ <h2>This is a placeholder screen. Please, assign a screen to this task.</h2>
6
+ </div>
7
+ </template>
8
+
9
+ <script>
10
+
11
+ export default {
12
+ data() {
13
+ return {
14
+ noPreviewImg: require('@/assets/noPreviewImage.png'),
15
+ };
16
+ },
17
+ };
18
+ </script>
19
+
20
+ <style scoped>
21
+ .no-preview {
22
+ display: flex;
23
+ flex-direction: column;
24
+ justify-content: center;
25
+ align-items: center;
26
+ color: #44494E;
27
+ padding: 5px;
28
+ }
29
+
30
+ .no-preview img {
31
+ max-width: 50%;
32
+ width: auto;
33
+ padding-bottom: 150px;
34
+ }
35
+
36
+ .no-preview h1 {
37
+ text-align: center;
38
+ font-weight: bold;
39
+ font-size: xx-large;
40
+ margin-bottom: 50px;
41
+ }
42
+
43
+ .no-preview h2 {
44
+ text-align: center;
45
+ font-size: x-large;
46
+ }
47
+ </style>
@@ -0,0 +1,148 @@
1
+ <template>
2
+ <b-col
3
+ v-show="visible"
4
+ id="preview_panel"
5
+ class="pl-0 h-100 overflow-hidden preview-column"
6
+ :style="{ maxWidth: width + 'px' }"
7
+ @mousedown="onMouseDown"
8
+ @mouseup="onMouseUp"
9
+ @mousemove="onMouseMove"
10
+ data-test="preview-column"
11
+ >
12
+ <b-row class="control-bar">
13
+ <b-col cols="9">
14
+ <div>
15
+ <i v-show = "selectedPreview == 1" class="fas fa-file-alt"/>
16
+ <b v-show = "selectedPreview == 2"> {} </b>
17
+ <b-dropdown
18
+ variant="ellipsis"
19
+ no-caret
20
+ no-flip
21
+ lazy
22
+ class="dropdown-right"
23
+ style="margin-top:-10px"
24
+ v-model="selectedPreview"
25
+ >
26
+ <template #button-content>
27
+ <i class="fas fa-sort-down" />
28
+ </template>
29
+
30
+ <b-dropdown-item key="1" class="ellipsis-dropdown-item mx-auto" @click="onSelectedPreview(1)">
31
+ <div class="ellipsis-dropdown-content">
32
+ <b class="pr-1 fa-fw fas fa-file-alt" />
33
+ <span>{{ $t('Document') }}</span>
34
+ </div>
35
+ </b-dropdown-item>
36
+
37
+ <b-dropdown-item key="2" class="ellipsis-dropdown-item mx-auto" @click="onSelectedPreview(2)">
38
+ <div class="ellipsis-dropdown-content">
39
+ <b class="pr-1 fa-fw">{ }</b>
40
+ <span>{{ $t('Object') }}</span>
41
+ </div>
42
+ </b-dropdown-item>
43
+ </b-dropdown>
44
+ <span>{{ $t('Preview') }} - {{ taskTitle }}</span>
45
+ </div>
46
+ </b-col>
47
+ <b-col class="actions">
48
+ <div>
49
+ <i class="fas fa-external-link-alt"/>
50
+ <i class="fas fa-times" @click="onClose()" />
51
+ </div>
52
+ </b-col>
53
+ </b-row>
54
+
55
+ <b-row>
56
+ <div style="background-color: #0074D9; height: 20px; width: 100%">&nbsp;</div>
57
+ </b-row>
58
+
59
+ <b-row>
60
+ <div class="item-title"> {{ screenTitle }} </div>
61
+ <div class="task-title"> {{ taskTitle }} </div>
62
+ </b-row>
63
+
64
+ <no-preview-available/>
65
+ </b-col>
66
+
67
+ </template>
68
+
69
+ <script>
70
+ import store from '@/store';
71
+ import NoPreviewAvailable from '@/components/inspectors/NoPreviewAvailable';
72
+
73
+ export default {
74
+ props: ['nodeRegistry', 'visible'],
75
+ components: {NoPreviewAvailable},
76
+ data() {
77
+ return {
78
+ data: {},
79
+ selectedPreview: '1',
80
+ taskTitle: '',
81
+ screenTitle: '',
82
+ width: 400,
83
+ isDragging: false,
84
+ currentPos: 400,
85
+ };
86
+ },
87
+ watch: {
88
+ highlightedNode() {
89
+ document.activeElement.blur();
90
+ this.prepareData();
91
+ },
92
+ 'highlightedNode.definition'(current, previous) { this.handleAssignmentChanges(current, previous); },
93
+ 'highlightedNode.definition.assignmentLock'(current, previous) { this.handleAssignmentChanges(current, previous); },
94
+ 'highlightedNode.definition.allowReassignment'(current, previous) { this.handleAssignmentChanges(current, previous); },
95
+ 'highlightedNode.definition.assignedUsers'(current, previous) { this.handleAssignmentChanges(current, previous); },
96
+ 'highlightedNode.definition.assignedGroups'(current, previous) { this.handleAssignmentChanges(current, previous); },
97
+ 'highlightedNode.definition.assignmentRules'(current, previous) { this.handleAssignmentChanges(current, previous); },
98
+ },
99
+ computed: {
100
+ highlightedNode() {
101
+ return store.getters.highlightedNodes[0];
102
+ },
103
+ },
104
+ methods: {
105
+ prepareData() {
106
+ if (!this.highlightedNode) {
107
+ return {};
108
+ }
109
+
110
+ this.taskTitle = this?.highlightedNode?.definition?.name;
111
+ },
112
+
113
+ handleAssignmentChanges(currentValue, previousValue) {
114
+ if (currentValue === previousValue) {
115
+ return;
116
+ }
117
+ this.prepareData();
118
+ },
119
+
120
+ onSelectedPreview(item) {
121
+ this.selectedPreview = item;
122
+ },
123
+ previewNode(node) {
124
+ this.taskTitle = node?.name;
125
+ this.showPanel = true;
126
+ },
127
+ onClose() {
128
+ this.$emit('togglePreview', false);
129
+ },
130
+ onMouseDown(event) {
131
+ this.isDragging = true;
132
+ this.currentPos = event.x;
133
+ },
134
+ onMouseUp() {
135
+ this.isDragging = false;
136
+ },
137
+ onMouseMove(event) {
138
+ if (this.isDragging) {
139
+ const dx = this.currentPos - event.x;
140
+ this.currentPos = event.x;
141
+ this.width = parseInt(this.width) + dx;
142
+ this.$emit('previewResize', this.width);
143
+ }
144
+ },
145
+ },
146
+ };
147
+ </script>
148
+ <style lang="scss" src="./preview_panel.scss" scoped />
@@ -0,0 +1,63 @@
1
+ $inspector-column-max-width: 400px;
2
+ $inspector-column-min-width: 400px;
3
+
4
+ #preview_panel::after {
5
+ display: flex;
6
+ content: '';
7
+ left: 0;
8
+ width: 5px;
9
+ height: 100%;
10
+ cursor: ew-resize;
11
+ }
12
+
13
+ .preview-column {
14
+ max-width: $inspector-column-max-width;
15
+ resize: both;
16
+ overflow:auto;
17
+ background-color: #F5F5F5;
18
+ border-left: 8px solid #EBEEF2;
19
+ }
20
+
21
+ .paneiframe {
22
+ display:block;
23
+ width:100%;
24
+ }
25
+
26
+ .preview-column .control-bar {
27
+ background-color: white;
28
+ padding: 0 5px 0 5px;
29
+ color: #7f7f7f;
30
+ }
31
+
32
+ .preview-column .control-bar .actions {
33
+ text-align: right;
34
+ }
35
+
36
+ .preview-column .control-bar .actions div {
37
+ width: 100%;
38
+ text-align: right;
39
+ }
40
+
41
+ .preview-column .control-bar .actions div i {
42
+ width: 20px;
43
+ cursor: pointer;
44
+ }
45
+
46
+ .item-title {
47
+ margin-top: 15px;
48
+ width: 100%;
49
+ height: 30px;
50
+ font-size: larger;
51
+ text-align: center;
52
+ align-items: center;
53
+ color: #7f7f7f;
54
+ }
55
+
56
+ .task-title {
57
+ width: 100%;
58
+ height: 60px;
59
+ font-size: xx-large;
60
+ font-weight: bold;
61
+ text-align: center;
62
+ color: #6c757d;
63
+ }
@@ -23,6 +23,7 @@
23
23
  @close="close"
24
24
  @save-state="pushToUndoStack"
25
25
  @clearSelection="clearSelection"
26
+ :players="players"
26
27
  @action="handleToolbarAction"
27
28
  />
28
29
  <b-row class="modeler h-100">
@@ -50,9 +51,18 @@
50
51
  </b-col>
51
52
 
52
53
  <InspectorButton
53
- v-if="showComponent"
54
+ ref="inspector-button"
55
+ v-if="showComponent && showInspectorButton"
54
56
  :showInspector="isOpenInspector"
55
- @toggleInspector="handleToggleInspector"
57
+ @toggleInspector="[handleToggleInspector($event), setInspectorButtonPosition($event)]"
58
+ :style="{ right: inspectorButtonRight + 'px' }"
59
+ />
60
+
61
+ <PreviewPanel ref="preview-panel"
62
+ @togglePreview="[handleTogglePreview($event), setInspectorButtonPosition($event)]"
63
+ @previewResize="setInspectorButtonPosition"
64
+ :visible="isOpenPreview"
65
+ :nodeRegistry="nodeRegistry"
56
66
  />
57
67
 
58
68
  <InspectorPanel
@@ -101,6 +111,7 @@
101
111
  :is-idle="requestIdleNodes.includes(node.definition.id)"
102
112
  @add-node="addNode"
103
113
  @remove-node="removeNode"
114
+ @previewNode="[handlePreview($event), setInspectorButtonPosition($event)]"
104
115
  @set-cursor="cursor = $event"
105
116
  @set-pool-target="poolTarget = $event"
106
117
  @unset-pools="unsetPools"
@@ -143,6 +154,15 @@
143
154
  @save-state="pushToUndoStack"
144
155
  />
145
156
  </b-row>
157
+
158
+ <RemoteCursor
159
+ v-for="player in players"
160
+ :cursor-color="player.color"
161
+ :username="player.name"
162
+ :key="player.id"
163
+ :top="player.top"
164
+ :left="player.left"
165
+ />
146
166
  </span>
147
167
  </template>
148
168
 
@@ -159,6 +179,7 @@ import store from '@/store';
159
179
  import nodeTypesStore from '@/nodeTypesStore';
160
180
  import InspectorButton from '@/components/inspectors/inspectorButton/InspectorButton.vue';
161
181
  import InspectorPanel from '@/components/inspectors/InspectorPanel';
182
+ import PreviewPanel from '@/components/inspectors/PreviewPanel';
162
183
  import undoRedoStore from '@/undoRedoStore';
163
184
  import { Linter } from 'bpmnlint';
164
185
  import linterConfig from '../../../.bpmnlintrc';
@@ -202,10 +223,11 @@ import RailBottom from '@/components/railBottom/RailBottom.vue';
202
223
  import ProcessmakerModelerGenericFlow from '@/components/nodes/genericFlow/genericFlow';
203
224
 
204
225
  import Selection from './Selection';
205
-
226
+ import RemoteCursor from '@/components/multiplayer/remoteCursor/RemoteCursor.vue';
206
227
 
207
228
  export default {
208
229
  components: {
230
+ PreviewPanel,
209
231
  ToolBar,
210
232
  ExplorerRail,
211
233
  InspectorButton,
@@ -213,6 +235,7 @@ export default {
213
235
  ProcessmakerModelerGenericFlow,
214
236
  Selection,
215
237
  RailBottom,
238
+ RemoteCursor,
216
239
  },
217
240
  props: {
218
241
  owner: Object,
@@ -282,6 +305,7 @@ export default {
282
305
  miniMapOpen: false,
283
306
  panelsCompressed: false,
284
307
  isOpenInspector: false,
308
+ isOpenPreview: false,
285
309
  isGrabbing: false,
286
310
  isRendering: false,
287
311
  allWarnings: [],
@@ -300,6 +324,9 @@ export default {
300
324
  isSelecting: false,
301
325
  isIntoTheSelection: false,
302
326
  dragStart: null,
327
+ players: [],
328
+ showInspectorButton: true,
329
+ inspectorButtonRight: 65,
303
330
  };
304
331
  },
305
332
  watch: {
@@ -364,8 +391,30 @@ export default {
364
391
  }
365
392
  },
366
393
  handleToggleInspector(value) {
394
+ this.showInspectorButton = !(value ?? true);
367
395
  this.isOpenInspector = value;
368
396
  },
397
+ handlePreview(node) {
398
+ this.$refs['preview-panel'].previewNode(node);
399
+ this.handleTogglePreview(true) ;
400
+ },
401
+ handleTogglePreview(value) {
402
+ this.isOpenPreview = value;
403
+ },
404
+ setInspectorButtonPosition() {
405
+ const previewWidth = this.$refs['preview-panel'].width;
406
+ if (this.isOpenInspector) {
407
+ return;
408
+ }
409
+
410
+ if (this.isOpenPreview && !this.isOpenInspector) {
411
+ this.inspectorButtonRight = 65 + previewWidth;
412
+ }
413
+
414
+ if (!this.isOpenPreview && !this.isOpenInspector) {
415
+ this.inspectorButtonRight = 65;
416
+ }
417
+ },
369
418
  isAppleOS() {
370
419
  return typeof navigator !== 'undefined' && /Mac|iPad|iPhone/.test(navigator.platform);
371
420
  },
@@ -870,7 +919,7 @@ export default {
870
919
 
871
920
  const config = definition.config ? JSON.parse(definition.config) : {};
872
921
  const type = config?.processKey || parser(definition, this.moddle);
873
-
922
+
874
923
  const unnamedElements = ['bpmn:TextAnnotation', 'bpmn:Association', 'bpmn:DataOutputAssociation', 'bpmn:DataInputAssociation'];
875
924
  const requireName = unnamedElements.indexOf(bpmnType) === -1;
876
925
  if (requireName && !definition.get('name')) {
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <div class="remote-cursor" :style="{ left: left + 'px', top: top + 'px' }">
3
+ <inline-svg :src="cursorIcon" :fill="cursorColor" />
4
+
5
+ <div class="remote-username">
6
+ {{ username }}
7
+ </div>
8
+ </div>
9
+ </template>
10
+
11
+ <script>
12
+ import InlineSvg from 'vue-inline-svg';
13
+
14
+ export default {
15
+ components: {
16
+ InlineSvg,
17
+ },
18
+ props: {
19
+ cursorColor: {
20
+ type: String,
21
+ default: '#000000',
22
+ },
23
+ username: {
24
+ type: String,
25
+ },
26
+ top: {
27
+ type: Number,
28
+ },
29
+ left: {
30
+ type: Number,
31
+ },
32
+ },
33
+ data() {
34
+ return {
35
+ cursorIcon: require('@/components/multiplayer/remoteCursor/cursor.svg'),
36
+ };
37
+ },
38
+ };
39
+ </script>
40
+
41
+ <style scoped lang="scss">
42
+ .remote {
43
+ &-cursor {
44
+ position: absolute;
45
+ display: flex;
46
+ width: auto;
47
+ height: 34px;
48
+ }
49
+
50
+ &-username {
51
+ display: flex;
52
+ justify-content: center;
53
+ align-items: center;
54
+ margin-top: 12px;
55
+ padding: 4px 10px;
56
+ gap: 10px;
57
+ border-radius: 4px;
58
+ background-color: #212529;
59
+
60
+ color: #FFFFFF;
61
+ font-size: 12px;
62
+ font-style: normal;
63
+ font-weight: 400;
64
+ line-height: normal;
65
+ }
66
+ }
67
+ </style>
@@ -0,0 +1,3 @@
1
+ <svg width="23" height="19" viewBox="0 0 23 19" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M11.5 17.5L2 1L20.5 7L13 9L11.5 17.5Z" stroke="#212529" />
3
+ </svg>
@@ -8,6 +8,7 @@
8
8
  <TopRail
9
9
  :validation-errors="validationErrors"
10
10
  :warnings="warnings"
11
+ :players="players"
11
12
  >
12
13
  <component
13
14
  :is="component.button"
@@ -129,6 +130,7 @@ export default {
129
130
  'warnings',
130
131
  'xmlManager',
131
132
  'validationBar',
133
+ 'players',
132
134
  'extraActions',
133
135
  ],
134
136
  watch: {
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <div class="top-rail-container">
3
+ <MultiplayerViewUsers :players="players"/>
3
4
  <ValidateIssue
4
5
  v-show="isOpenIssue"
5
6
  :number-of-errors="numberOfErrors"
@@ -20,12 +21,13 @@
20
21
  <script>
21
22
  import store from '@/store';
22
23
  import { ValidateButton, ValidateIssue, ValidatePanel } from '@/components/topRail/validateControl';
23
-
24
+ import MultiplayerViewUsers from '@/components/topRail/multiplayerViewUsers/MultiplayerViewUsers';
24
25
  export default {
25
26
  components: {
26
27
  ValidateButton,
27
28
  ValidateIssue,
28
29
  ValidatePanel,
30
+ MultiplayerViewUsers,
29
31
  },
30
32
  props: {
31
33
  validationErrors: {
@@ -36,6 +38,10 @@ export default {
36
38
  type: Array,
37
39
  required: true,
38
40
  },
41
+ players: {
42
+ type: Array,
43
+ required: false,
44
+ },
39
45
  },
40
46
  data() {
41
47
  return {
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <b-avatar-group class="container">
3
+ <template v-for="item in players" >
4
+ <Avatar :badgeBackgroundColor="item.color" :imgSrc= "item.imgSrc" :userName="item.name" :key="item.key"/>
5
+ </template>
6
+ </b-avatar-group>
7
+ </template>
8
+
9
+ <script>
10
+ import Avatar from '@/components/topRail/multiplayerViewUsers/avatar/Avatar';
11
+ export default {
12
+ components:{
13
+ Avatar,
14
+ },
15
+ props: {
16
+ players: {
17
+ type: Array,
18
+ required: true,
19
+ },
20
+ },
21
+ };
22
+ </script>