@processmaker/modeler 1.43.12 → 1.43.13

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 (31) hide show
  1. package/cypress.config.js +1 -0
  2. package/dist/img/pan-icon.4a4b74b7.svg +3 -0
  3. package/dist/modeler.common.js +2667 -1922
  4. package/dist/modeler.common.js.map +1 -1
  5. package/dist/modeler.umd.js +2671 -1926
  6. package/dist/modeler.umd.js.map +1 -1
  7. package/dist/modeler.umd.min.js +4 -4
  8. package/dist/modeler.umd.min.js.map +1 -1
  9. package/package.json +2 -2
  10. package/src/ModelerApp.vue +5 -1
  11. package/src/assets/railBottom/pan-icon.svg +3 -0
  12. package/src/components/crown/crownConfig/crownConfig.vue +1 -6
  13. package/src/components/hotkeys/main.js +41 -16
  14. package/src/components/hotkeys/undoRedo.js +24 -0
  15. package/src/components/modeler/Modeler.vue +216 -186
  16. package/src/components/modeler/modeler.scss +17 -5
  17. package/src/components/railBottom/PanControl.vue +38 -0
  18. package/src/components/railBottom/RailBottom.vue +8 -0
  19. package/src/components/railBottom/{miniPaperControl/miniPaperControl.scss → bottomLeftControl.scss} +5 -1
  20. package/src/components/railBottom/controls/Controls.vue +18 -6
  21. package/src/components/railBottom/controls/SubmenuPopper/SubmenuPopper.vue +2 -7
  22. package/src/components/railBottom/miniPaperControl/MiniPaperControl.vue +1 -1
  23. package/src/components/railBottom/undoRedoControl/UndoRedoControl.vue +4 -0
  24. package/src/components/rails/explorer-rail/nodeTypesLoop/nodeTypesLoop.vue +10 -3
  25. package/src/components/rails/explorer-rail/pmBlocksLoop/pmBlocksLoop.vue +6 -3
  26. package/src/components/topRail/TopRail.vue +5 -0
  27. package/src/mixins/clickAndDrop.js +20 -0
  28. package/src/mixins/linkEditing.js +393 -0
  29. package/src/mixins/transparentDragging.js +45 -0
  30. package/src/setup/initialLoad.js +2 -1
  31. package/src/undoRedoStore.js +11 -0
@@ -44,7 +44,7 @@
44
44
  <b-col
45
45
  class="paper-container h-100 pr-4"
46
46
  ref="paper-container"
47
- :class="[cursor, { 'grabbing-cursor' : isGrabbing }]"
47
+ :class="[cursor, { 'grabbing-cursor' : panMode && panning, 'grab-cursor' : panMode && !panning }]"
48
48
  :style="{ width: parentWidth, height: parentHeight }"
49
49
  @mouseup="onMouseUp"
50
50
  @mousemove="[onMouseMove($event), setInspectorButtonPosition($event)]"
@@ -136,7 +136,7 @@
136
136
  :plane-elements="planeElements"
137
137
  :moddle="moddle"
138
138
  :nodeRegistry="nodeRegistry"
139
- :root-elements="definitions.get('rootElements')"
139
+ :root-elements="definitions?.get('rootElements')"
140
140
  :isRendering="isRendering"
141
141
  :paperManager="paperManager"
142
142
  :auto-validate="autoValidate"
@@ -174,10 +174,12 @@
174
174
  :paper-manager="paperManager"
175
175
  :graph="graph"
176
176
  :is-rendering="isRendering"
177
+ :pan-mode="panMode"
177
178
  @load-xml="loadXML"
178
179
  @clearSelection="clearSelection"
179
180
  @set-cursor="cursor = $event"
180
181
  @onCreateElement="onCreateElementHandler"
182
+ @set-pan-mode="panMode = $event"
181
183
  />
182
184
 
183
185
  <selection
@@ -266,6 +268,8 @@ import { getInvalidNodes } from '@/components/modeler/modelerUtils';
266
268
  import { NodeMigrator } from '@/components/modeler/NodeMigrator';
267
269
  import addLoopCharacteristics from '@/setup/addLoopCharacteristics';
268
270
  import cloneSelection from '../../mixins/cloneSelection';
271
+ import linkEditing from '../../mixins/linkEditing';
272
+ import transparentDragging from '@/mixins/transparentDragging';
269
273
  import RailBottom from '@/components/railBottom/RailBottom.vue';
270
274
 
271
275
  import ProcessmakerModelerGenericFlow from '@/components/nodes/genericFlow/genericFlow';
@@ -320,7 +324,7 @@ export default {
320
324
  default: () => [],
321
325
  },
322
326
  },
323
- mixins: [hotkeys, cloneSelection],
327
+ mixins: [hotkeys, cloneSelection, linkEditing, transparentDragging],
324
328
  data() {
325
329
  return {
326
330
  extraActions: [],
@@ -361,7 +365,8 @@ export default {
361
365
  panelsCompressed: false,
362
366
  isOpenInspector: false,
363
367
  isOpenPreview: false,
364
- isGrabbing: false,
368
+ panMode: false,
369
+ panning: false,
365
370
  isRendering: false,
366
371
  isLoaded: false,
367
372
  allWarnings: [],
@@ -411,6 +416,14 @@ export default {
411
416
  };
412
417
  },
413
418
  watch: {
419
+ isReadOnly() {
420
+ this.panMode = this.isReadOnly;
421
+ },
422
+ panning() {
423
+ if (!this.panning) {
424
+ this.canvasDragPosition = null;
425
+ }
426
+ },
414
427
  isRendering() {
415
428
  const loadingMessage = 'Loading process, please be patient.';
416
429
  if (this.isRendering) {
@@ -445,8 +458,19 @@ export default {
445
458
  window.ProcessMaker.EventBus.$emit('modeler:highlightedNodes', this.highlightedNodes);
446
459
  }
447
460
  },
461
+ creatingNewNode() {
462
+ if (this.creatingNewNode) {
463
+ this.clearSelection();
464
+ }
465
+ },
448
466
  },
449
467
  computed: {
468
+ isReadOnly() {
469
+ return store.getters.isReadOnly;
470
+ },
471
+ creatingNewNode() {
472
+ return nodeTypesStore.getters.getSelectedNode;
473
+ },
450
474
  filteredPlayers() {
451
475
  const allPlayers = _.uniqBy(this.players, 'name');
452
476
  return allPlayers.filter(player => {
@@ -454,7 +478,7 @@ export default {
454
478
  });
455
479
  },
456
480
  showWelcomeMessage() {
457
- return !this.selectedNode && !this.nodes.length && !store.getters.isReadOnly && this.isLoaded;
481
+ return !this.selectedNode && !this.nodes.length && !this.isReadOnly && this.isLoaded && !undoRedoStore.getters.isRunning;
458
482
  },
459
483
  noElementsSelected() {
460
484
  return this.highlightedNodes.filter(node => !node.isType('processmaker-modeler-process')).length === 0;
@@ -479,8 +503,167 @@ export default {
479
503
  },
480
504
  showComponent: () => store.getters.showComponent,
481
505
  isMultiplayer: () => store.getters.isMultiplayer,
506
+ isPackageAiInstalled() {
507
+ return window.ProcessMaker?.modeler?.isPackageAiInstalled;
508
+ },
482
509
  },
483
510
  methods: {
511
+ mountedInit() {
512
+ store.commit('setReadOnly', this.readOnly);
513
+ this.graph = new dia.Graph();
514
+ store.commit('setGraph', this.graph);
515
+ this.graph.set('interactiveFunc', cellView => {
516
+ const isPoolEdge = cellView.model.get('type') === 'standard.EmbeddedImage';
517
+ return {
518
+ elementMove: isPoolEdge,
519
+ labelMove: false,
520
+ };
521
+ });
522
+
523
+ this.paperManager = PaperManager.factory(this.$refs.paper, this.graph.get('interactiveFunc'), this.graph);
524
+ this.paper = this.paperManager.paper;
525
+ },
526
+ addEventHandlers() {
527
+ this.paperManager.addEventHandler('cell:pointerdblclick', focusNameInputAndHighlightLabel);
528
+
529
+ this.handleResize();
530
+ window.addEventListener('resize', this.handleResize);
531
+
532
+ store.commit('setPaper', this.paperManager.paper);
533
+
534
+ this.paperManager.addEventHandler('element:pointerclick', this.blurFocusedScreenBuilderElement, this);
535
+
536
+ this.paperManager.addEventHandler('blank:pointerdown', (event) => {
537
+ if (this.panMode) {
538
+ this.startPanning();
539
+ return;
540
+ }
541
+ this.pointerDownHandler(event);
542
+ }, this);
543
+
544
+ this.paperManager.addEventHandler('blank:pointerup', (event) => {
545
+ if (this.panMode) {
546
+ this.stopPanning();
547
+ }
548
+ this.activeNode = null;
549
+ this.pointerUpHandler(event);
550
+ }, this);
551
+ this.paperManager.addEventHandler('cell:pointerup', (cellView, event) => {
552
+ if (this.panMode) {
553
+ this.stopPanning();
554
+ return;
555
+ }
556
+ this.activeNode = null;
557
+ this.pointerUpHandler(event, cellView);
558
+ }, this);
559
+
560
+ this.$refs['paper-container'].addEventListener('mouseenter', () => {
561
+ store.commit('setClientLeftPaper', false);
562
+ });
563
+
564
+ this.$el.addEventListener('mousemove', event => {
565
+ this.pointerMoveHandler(event);
566
+ });
567
+
568
+ this.$refs['paper-container'].addEventListener('mouseleave', () => {
569
+ this.paperManager.removeEventHandler('blank:pointermove');
570
+ store.commit('setClientLeftPaper', true);
571
+ });
572
+
573
+ this.paperManager.addEventHandler('cell:pointerclick', (cellView, evt, x, y) => {
574
+ const clickHandler = cellView.model.get('onClick');
575
+ if (clickHandler) {
576
+ clickHandler(cellView, evt, x, y);
577
+ }
578
+ });
579
+
580
+ this.paperManager.addEventHandler('cell:pointerclick', ({ model: shape }, event) => {
581
+ if (!this.isBpmnNode(shape)) {
582
+ return;
583
+ }
584
+
585
+ // ignore click event if the user is Grabbing the paper
586
+ if (this.panMode) {
587
+ return;
588
+ }
589
+
590
+ shape.component.$emit('click', event);
591
+ this.$emit('click', {
592
+ event,
593
+ node: this.highlightedNode.definition,
594
+ });
595
+ });
596
+
597
+ this.paperManager.addEventHandler('cell:pointerdown', ({ model: shape }, event) => {
598
+ if (!this.isBpmnNode(shape)) {
599
+ return;
600
+ }
601
+ // If the user is panning
602
+ if (this.panMode) {
603
+ this.startPanning();
604
+ return;
605
+ }
606
+ this.setShapeStacking(shape);
607
+ this.activeNode = shape.component.node;
608
+ this.pointerDowInShape(event, shape);
609
+ });
610
+
611
+ this.$root.$on('replace-ai-node', (data) => {
612
+ this.replaceAiNode(data);
613
+ });
614
+
615
+ window.ProcessMaker.EventBus.$on('save-changes', (redirectUrl, nodeId, generatingAssets) => {
616
+ if (redirectUrl) {
617
+ this.redirect(redirectUrl);
618
+ }
619
+ if (generatingAssets) {
620
+ this.generateAssets();
621
+ }
622
+ });
623
+
624
+ },
625
+ registerCustomNodes()
626
+ {
627
+ /* Register custom nodes */
628
+ window.ProcessMaker.EventBus.$emit('modeler-start', {
629
+ $t: this.$t,
630
+ modeler: this,
631
+ registerMenuAction: this.registerMenuAction,
632
+ loadXML: async(xml) => {
633
+ await this.loadXML(xml);
634
+ await undoRedoStore.dispatch('pushState', xml);
635
+
636
+ try {
637
+ const multiplayer = new Multiplayer(this);
638
+ multiplayer.init();
639
+ this.multiplayer = multiplayer;
640
+ } catch (error) {
641
+ console.warn('Could not initialize multiplayer', error);
642
+ }
643
+ },
644
+ addWarnings: warnings => this.$emit('warnings', warnings),
645
+ addBreadcrumbs: breadcrumbs => this.breadcrumbData.push(breadcrumbs),
646
+ });
647
+ },
648
+ initAI() {
649
+ // AI Setup
650
+ if (this.isPackageAiInstalled) {
651
+ this.currentNonce = localStorage.currentNonce;
652
+ if (!localStorage.getItem('promptSessions') || localStorage.getItem('promptSessions') === 'null') {
653
+ localStorage.setItem('promptSessions', JSON.stringify([]));
654
+ }
655
+ if (!localStorage.getItem('cancelledJobs') || localStorage.getItem('cancelledJobs') === 'null') {
656
+ this.cancelledJobs = [];
657
+ } else {
658
+ this.cancelledJobs = JSON.parse(localStorage.getItem('cancelledJobs'));
659
+ }
660
+ this.promptSessionId = this.getPromptSessionForUser();
661
+ this.fetchHistory();
662
+ this.subscribeToProgress();
663
+ this.subscribeToGenerationCompleted();
664
+ this.subscribeToErrors();
665
+ }
666
+ },
484
667
  onNodeDefinitionChanged() {
485
668
  // re-render the preview just if the preview pane is open
486
669
  if (this.isOpenPreview) {
@@ -491,7 +674,11 @@ export default {
491
674
  this.isResizingPreview = true;
492
675
  this.currentCursorPosition = event.x;
493
676
  },
494
- onMouseUp() {
677
+ onMouseUp(event) {
678
+ if (window.ProcessMaker.mouseDownDrag) {
679
+ window.ProcessMaker.EventBus.$emit('custom-pointerclick', event);
680
+ window.ProcessMaker.mouseDownDrag = false;
681
+ }
495
682
  this.isResizingPreview = false;
496
683
  },
497
684
  onMouseMove(event) {
@@ -1219,6 +1406,9 @@ export default {
1219
1406
  this.highlightNode(newNode);
1220
1407
 
1221
1408
  await this.addNode(newNode);
1409
+
1410
+ this.$emit('node-added', newNode);
1411
+
1222
1412
  if (!nodeThatWillBeReplaced) {
1223
1413
  return;
1224
1414
  }
@@ -1677,17 +1867,11 @@ export default {
1677
1867
  });
1678
1868
  }, 3000000, { leading: true, trailing: true });
1679
1869
  updateMousePosition();
1680
-
1681
- if (store.getters.isReadOnly) {
1682
- if (this.canvasDragPosition && !this.clientLeftPaper) {
1683
- this.paperManager.translate(
1684
- event.offsetX - this.canvasDragPosition.x,
1685
- event.offsetY - this.canvasDragPosition.y,
1686
- );
1687
- }
1870
+
1871
+ if (this.panMode) {
1688
1872
  return;
1689
1873
  }
1690
- if (this.isGrabbing) return;
1874
+
1691
1875
  if (this.dragStart && (Math.abs(x - this.dragStart.x) > 5 || Math.abs(y - this.dragStart.y) > 5)) {
1692
1876
  this.isDragging = true;
1693
1877
  this.dragStart = null;
@@ -1897,12 +2081,17 @@ export default {
1897
2081
  this.setPromptSessions((response.data.promptSessionId));
1898
2082
  this.promptSessionId = (response.data.promptSessionId);
1899
2083
  localStorage.promptSessionId = (response.data.promptSessionId);
1900
- }).catch((error) => {
1901
- const errorMsg = error.message;
1902
- if (error === 404) {
2084
+ })
2085
+ .catch((error) => {
2086
+
2087
+ const errorMsg = error.response?.data?.message || error.message;
2088
+
2089
+ this.loading = false;
2090
+ if (error.response.status === 404) {
1903
2091
  this.removePromptSessionForUser();
1904
2092
  localStorage.promptSessionId = '';
1905
2093
  this.promptSessionId = '';
2094
+ this.fetchHistory();
1906
2095
  } else {
1907
2096
  window.ProcessMaker.alert(errorMsg, 'danger');
1908
2097
  }
@@ -1974,6 +2163,9 @@ export default {
1974
2163
  subscribeToProgress() {
1975
2164
  const channel = `ProcessMaker.Models.User.${window.ProcessMaker?.modeler?.process?.user_id}`;
1976
2165
  const streamProgressEvent = '.ProcessMaker\\Package\\PackageAi\\Events\\GenerateArtifactsProgressEvent';
2166
+ if (!window.Echo) {
2167
+ return;
2168
+ }
1977
2169
  window.Echo.private(channel).listen(
1978
2170
  streamProgressEvent,
1979
2171
  (response) => {
@@ -2083,174 +2275,12 @@ export default {
2083
2275
  this.$emit('set-xml-manager', this.xmlManager);
2084
2276
  },
2085
2277
  mounted() {
2086
- store.commit('setReadOnly', this.readOnly);
2087
- this.graph = new dia.Graph();
2088
- store.commit('setGraph', this.graph);
2089
- this.graph.set('interactiveFunc', cellView => {
2090
- const isPoolEdge = cellView.model.get('type') === 'standard.EmbeddedImage';
2091
- return {
2092
- elementMove: isPoolEdge,
2093
- labelMove: false,
2094
- };
2095
- });
2096
-
2097
- this.paperManager = PaperManager.factory(this.$refs.paper, this.graph.get('interactiveFunc'), this.graph);
2098
- this.paper = this.paperManager.paper;
2099
-
2100
- this.paperManager.addEventHandler('cell:pointerdblclick', focusNameInputAndHighlightLabel);
2101
-
2102
- this.handleResize();
2103
- window.addEventListener('resize', this.handleResize);
2104
-
2105
- store.commit('setPaper', this.paperManager.paper);
2106
-
2107
- this.paperManager.addEventHandler('element:pointerclick', this.blurFocusedScreenBuilderElement, this);
2108
-
2109
- this.paperManager.addEventHandler('blank:pointerdown', (event, x, y) => {
2110
- if (this.isGrabbing) return;
2111
- if (store.getters.isReadOnly) {
2112
- this.isGrabbing = true;
2113
- }
2114
- const scale = this.paperManager.scale;
2115
- this.canvasDragPosition = { x: x * scale.sx, y: y * scale.sy };
2116
- this.isOverShape = false;
2117
- this.pointerDownHandler(event);
2118
- }, this);
2119
-
2120
- this.paperManager.addEventHandler('cell:mouseover element:mouseover', ({ model: shape }) => {
2121
- if (this.isBpmnNode(shape) && shape.attr('body/cursor') !== 'default' && !this.isGrabbing) {
2122
- shape.attr('body/cursor', 'move');
2123
- }
2124
- // If the user is panning the Paper while hovering an element, ignore the default move cursor
2125
- if (this.isGrabbing && this.isBpmnNode(shape)) {
2126
- shape.attr('body/cursor', 'grabbing');
2127
- }
2128
- });
2129
- this.paperManager.addEventHandler('blank:pointerup', (event) => {
2130
- this.isGrabbing = false;
2131
- this.canvasDragPosition = null;
2132
- this.activeNode = null;
2133
- this.pointerUpHandler(event);
2134
- }, this);
2135
- this.paperManager.addEventHandler('cell:pointerup', (cellView, event) => {
2136
- this.canvasDragPosition = null;
2137
- this.activeNode = null;
2138
- this.pointerUpHandler(event, cellView);
2139
- }, this);
2140
-
2141
- this.$refs['paper-container'].addEventListener('mouseenter', () => {
2142
- store.commit('setClientLeftPaper', false);
2143
- });
2144
-
2145
- this.$el.addEventListener('mousemove', event => {
2146
- this.pointerMoveHandler(event);
2147
- });
2148
-
2149
- this.$refs['paper-container'].addEventListener('mouseleave', () => {
2150
- this.paperManager.removeEventHandler('blank:pointermove');
2151
- store.commit('setClientLeftPaper', true);
2152
- });
2153
-
2154
- this.paperManager.addEventHandler('cell:pointerclick', (cellView, evt, x, y) => {
2155
- const clickHandler = cellView.model.get('onClick');
2156
- if (clickHandler) {
2157
- clickHandler(cellView, evt, x, y);
2158
- }
2159
- });
2160
-
2161
- this.paperManager.addEventHandler('cell:pointerclick', ({ model: shape }, event) => {
2162
- if (!this.isBpmnNode(shape)) {
2163
- return;
2164
- }
2165
-
2166
- // ignore click event if the user is Grabbing the paper
2167
- if (this.isGrabbing) return;
2168
-
2169
- shape.component.$emit('click', event);
2170
- this.$emit('click', {
2171
- event,
2172
- node: this.highlightedNode.definition,
2173
- });
2174
- });
2175
-
2176
- this.paperManager.addEventHandler('cell:pointerdown', ({ model: shape }, event) => {
2177
- if (!this.isBpmnNode(shape)) {
2178
- return;
2179
- }
2180
- // If the user is pressing Space (grabbing) and clicking on a Cell, return
2181
- if (this.isGrabbing) {
2182
- return;
2183
- }
2184
- this.setShapeStacking(shape);
2185
- this.activeNode = shape.component.node;
2186
- this.isOverShape = true;
2187
- this.pointerDowInShape(event, shape);
2188
- });
2189
- // If the user is grabbing the paper while he clicked in a cell, move the paper and not the cell
2190
- this.paperManager.addEventHandler('cell:pointermove', (_, event, x, y) => {
2191
- if (this.isGrabbing) {
2192
- if (!this.canvasDragPosition) {
2193
- const scale = this.paperManager.scale;
2194
- this.canvasDragPosition = { x: x * scale.sx, y: y * scale.sy };
2195
- }
2196
- if (this.canvasDragPosition && !this.clientLeftPaper) {
2197
- this.paperManager.translate(
2198
- event.offsetX - this.canvasDragPosition.x,
2199
- event.offsetY - this.canvasDragPosition.y,
2200
- );
2201
- }
2202
- }
2203
- });
2204
-
2205
- /* Register custom nodes */
2206
- window.ProcessMaker.EventBus.$emit('modeler-start', {
2207
- $t: this.$t,
2208
- modeler: this,
2209
- registerMenuAction: this.registerMenuAction,
2210
- loadXML: async(xml) => {
2211
- await this.loadXML(xml);
2212
- await undoRedoStore.dispatch('pushState', xml);
2213
-
2214
- try {
2215
- const multiplayer = new Multiplayer(this);
2216
- multiplayer.init();
2217
- this.multiplayer = multiplayer;
2218
- } catch (error) {
2219
- console.warn('Could not initialize multiplayer', error);
2220
- }
2221
- },
2222
- addWarnings: warnings => this.$emit('warnings', warnings),
2223
- addBreadcrumbs: breadcrumbs => this.breadcrumbData.push(breadcrumbs),
2224
- });
2225
-
2226
- this.$root.$on('replace-ai-node', (data) => {
2227
- this.replaceAiNode(data);
2228
- });
2229
-
2230
- window.ProcessMaker.EventBus.$on('save-changes', (redirectUrl, nodeId, generatingAssets) => {
2231
- if (redirectUrl) {
2232
- this.redirect(redirectUrl);
2233
- }
2234
- if (generatingAssets) {
2235
- this.generateAssets();
2236
- }
2237
- });
2238
-
2239
- // AI Setup
2240
- this.currentNonce = localStorage.currentNonce;
2241
- if (!localStorage.getItem('promptSessions') || localStorage.getItem('promptSessions') === 'null') {
2242
- localStorage.setItem('promptSessions', JSON.stringify([]));
2243
- }
2244
- if (!localStorage.getItem('cancelledJobs') || localStorage.getItem('cancelledJobs') === 'null') {
2245
- this.cancelledJobs = [];
2246
- } else {
2247
- this.cancelledJobs = JSON.parse(localStorage.getItem('cancelledJobs'));
2248
- }
2249
- this.promptSessionId = this.getPromptSessionForUser();
2250
- this.fetchHistory();
2251
- this.subscribeToProgress();
2252
- this.subscribeToGenerationCompleted();
2253
- this.subscribeToErrors();
2278
+ this.mountedInit();
2279
+ this.addEventHandlers();
2280
+ this.registerCustomNodes();
2281
+ this.initAi();
2282
+ this.linkEditingInit();
2283
+ this.initTransparentDragging();
2254
2284
  },
2255
2285
  };
2256
2286
  </script>
@@ -12,19 +12,19 @@
12
12
  top: 0;
13
13
  }
14
14
 
15
- .grabbing-cursor {
15
+ .grabbing-cursor, .grabbing-cursor .joint-element, .grabbing-cursor path {
16
16
  cursor: grabbing !important;
17
17
  }
18
+
19
+ .grab-cursor, .grab-cursor .joint-element, .grab-cursor path {
20
+ cursor: grab !important;
21
+ }
18
22
 
19
23
  .paper-container {
20
24
  position: initial !important;
21
25
  user-select: none;
22
26
  }
23
27
 
24
- .joint-element {
25
- cursor: default;
26
- }
27
-
28
28
  .joint-marker-vertex:hover {
29
29
  fill: $error-color;
30
30
  cursor: url('../../assets/delete-icon-vertex.png') 0 0, pointer;
@@ -38,3 +38,15 @@
38
38
  .no-pointer-events {
39
39
  pointer-events: none;
40
40
  }
41
+
42
+ .element-tooltip {
43
+ position: absolute;
44
+ border: 1px solid #B9CFE2;
45
+ background-color: #EDF4FF;
46
+ padding: 3px 8px;
47
+ font-size: 0.8em;
48
+ }
49
+
50
+ .transparent-cell {
51
+ opacity: 0.4;
52
+ }
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <div class="pan-tool-box">
3
+ <button type="button" class="pan-tool-button" :class="panMode ? 'pan-tool-button-active' : ''"
4
+ data-cy="pan-button" @click="$emit('set-pan-mode', !panMode)" v-b-tooltip.hover
5
+ :title="$t('Pan Tool')"
6
+ >
7
+ <inline-svg :src="icon" />
8
+ </button>
9
+ </div>
10
+ </template>
11
+
12
+ <script>
13
+ import InlineSvg from 'vue-inline-svg';
14
+ export default {
15
+ components: {
16
+ InlineSvg,
17
+ },
18
+ props: {
19
+ panMode: {
20
+ type: Boolean,
21
+ default: false,
22
+ },
23
+ },
24
+ data() {
25
+ return {
26
+ icon: require('@/assets/railBottom/pan-icon.svg'),
27
+ };
28
+ },
29
+ };
30
+ </script>
31
+ <style lang="scss" scoped src="./bottomLeftControl.scss"></style>
32
+
33
+ <style lang="scss" scoped>
34
+ .pan-tool-box {
35
+ margin-left: 1em;
36
+ overflow: hidden;
37
+ }
38
+ </style>
@@ -15,6 +15,11 @@
15
15
  :paper-manager="paperManager"
16
16
  ref="zoomBox"
17
17
  />
18
+
19
+ <PanControl
20
+ @set-pan-mode="$emit('set-pan-mode', $event)"
21
+ :pan-mode="panMode"
22
+ />
18
23
  </div>
19
24
 
20
25
  <div
@@ -46,12 +51,14 @@ import { nextTick } from 'vue';
46
51
  import MiniPaperControl from '@/components/railBottom/miniPaperControl/MiniPaperControl.vue';
47
52
  import ZoomControl from '@/components/railBottom/zoomControl/ZoomControl.vue';
48
53
  import UndoRedoControl from '@/components/railBottom/undoRedoControl/UndoRedoControl.vue';
54
+ import PanControl from './PanControl.vue';
49
55
  import Controls from '@/components/railBottom/controls/Controls.vue';
50
56
  import store from '@/store';
51
57
 
52
58
  export default {
53
59
  components: {
54
60
  MiniPaperControl,
61
+ PanControl,
55
62
  ZoomControl,
56
63
  UndoRedoControl,
57
64
  Controls,
@@ -61,6 +68,7 @@ export default {
61
68
  graph: Object,
62
69
  isRendering: Boolean,
63
70
  nodeTypes: Array,
71
+ panMode: Boolean,
64
72
  },
65
73
  data() {
66
74
  return {
@@ -1,4 +1,4 @@
1
- .mini-paper {
1
+ .mini-paper, .pan-tool {
2
2
  &-box {
3
3
  position: relative;
4
4
  display: flex;
@@ -32,6 +32,10 @@
32
32
  &:hover:not(.mini-paper-button-active) {
33
33
  background-color: #ebeef2;
34
34
  }
35
+
36
+ &:hover:not(.pan-tool-button-active) {
37
+ background-color: #ebeef2;
38
+ }
35
39
 
36
40
  &:active,
37
41
  &-active {