1515 :edges =" styledEdges"
1616 :node-types =" nodeTypes"
1717 :edge-types =" edgeTypes"
18- :nodes-connectable =" true "
18+ :nodes-connectable =" workflow?.canCreate "
1919 :elements-selectable =" true"
2020 :snap-to-grid =" true"
2121 :snap-grid =" [40, 40]"
3030 />
3131
3232 <button
33+ id =" toggle-minimap"
3334 class =" toolbar-button custom-controls-button position-absolute"
35+ tabindex =" 0"
3436 style =" z-index : 1003 "
3537 :style =" showMiniMap ? 'bottom: 130px; left: 180px;' : 'bottom: 10px; left: 10px;'"
36- tabindex =" 0"
37- @click =" showMiniMap = !showMiniMap"
3838 :aria-label =" showMiniMap ? translate('COM_WORKFLOW_GRAPH_MINIMAP_HIDE') : translate('COM_WORKFLOW_GRAPH_MINIMAP_SHOW')"
3939 :title =" showMiniMap ? translate('COM_WORKFLOW_GRAPH_MINIMAP_HIDE') : translate('COM_WORKFLOW_GRAPH_MINIMAP_SHOW')"
40- id = " toggle-minimap "
40+ @click = " showMiniMap = !showMiniMap "
4141 >
42- <span v-if =" showMiniMap" class =" fa fa-close" ></span >
43- <span v-else class =" icon icon-expand-2" ></span >
42+ <span
43+ v-if =" showMiniMap"
44+ class =" fa fa-close"
45+ />
46+ <span
47+ v-else
48+ class =" icon icon-expand-2"
49+ />
4450 </button >
4551 <MiniMap
4652 v-if =" showMiniMap"
5359 />
5460 <CustomControls aria-label =" Graph controls" />
5561 <ControlsPanel
62+ v-if =" workflow?.canCreate"
5663 class =" canvas-controls-panel"
5764 :is-transition-mode =" isTransitionMode"
5865 @add-stage =" addStage"
7178
7279<script >
7380import {
74- ref , computed , onMounted , onUnmounted , watch , nextTick ,
81+ ref , computed , onMounted , onUnmounted , watch ,
7582} from ' vue' ;
7683import { useStore } from ' vuex' ;
7784// eslint-disable-next-line import/no-unresolved
@@ -113,7 +120,7 @@ export default {
113120 setup () {
114121 const store = useStore ();
115122 const {
116- fitView , zoomIn , zoomOut , viewport , zoomTo , setViewport , onViewportChange , getViewport ,
123+ fitView , zoomIn , zoomOut , viewport , setViewport , onViewportChange ,
117124 } = useVueFlow ();
118125
119126 const isTransitionMode = ref (true );
@@ -125,6 +132,7 @@ export default {
125132 const previouslyFocusedElement = ref (null );
126133
127134 const showMiniMap = ref (true );
135+ const workflow = computed (() => store .getters .workflow || {});
128136 const stages = computed (() => store .getters .stages || []);
129137 const transitions = computed (() => store .getters .transitions || []);
130138 const loading = computed (() => store .getters .loading );
@@ -134,11 +142,18 @@ export default {
134142 return Joomla .Text ._ (key);
135143 }
136144
137- function openModal (type , id = null ) {
145+ function openModal (type , id = null , params = {} ) {
138146 previouslyFocusedElement .value = document .activeElement ;
139147 const extension = Joomla .getOptions (' com_workflow' , {})? .extension || ' ' ;
140148 const baseUrl = ` index.php?option=com_workflow&view=${ type} &workflow_id=${ workflowId .value } &extension=${ extension} &layout=modal&tmpl=component` ;
141- const src = id ? ` ${ baseUrl} &id=${ id} ` : baseUrl;
149+ const baseUrlwithId = id ? ` ${ baseUrl} &id=${ id} ` : baseUrl;
150+ const extraQuery = Object .entries (params)
151+ .map (([key , val ]) => ` ${ encodeURIComponent (key)} =${ encodeURIComponent (val)} ` )
152+ .join (' &' );
153+ const src = extraQuery
154+ ? ` ${ baseUrlwithId} &${ extraQuery} `
155+ : baseUrlwithId;
156+
142157 const textHeader = id
143158 ? translate (` COM_WORKFLOW_GRAPH_EDIT_${ type .toUpperCase ()} ` )
144159 : translate (` COM_WORKFLOW_GRAPH_ADD_${ type .toUpperCase ()} ` );
@@ -152,6 +167,30 @@ export default {
152167 setupDialogFocusHandlers (previouslyFocusedElement, store);
153168 }
154169
170+ function canEdit (id , type = ' stage' ) {
171+ if (type === ' stage' ) {
172+ const stage = stages .value .find ((s ) => s .id === parseInt (id, 10 ));
173+ return stage? .permissions ? .edit ;
174+ }
175+ if (type === ' transition' ) {
176+ const transition = transitions .value .find ((t ) => t .id === parseInt (id, 10 ));
177+ return transition? .permissions ? .edit ;
178+ }
179+ return false ;
180+ }
181+
182+ function canDelete (id , type = ' stage' ) {
183+ if (type === ' stage' ) {
184+ const stage = stages .value .find ((s ) => s .id === parseInt (id, 10 ));
185+ return stage? .permissions ? .delete ;
186+ }
187+ if (type === ' transition' ) {
188+ const transition = transitions .value .find ((t ) => t .id === parseInt (id, 10 ));
189+ return transition? .permissions ? .delete ;
190+ }
191+ return false ;
192+ }
193+
155194 function selectStage (id ) {
156195 selectedStage .value = parseInt (id, 10 );
157196 selectedTransition .value = null ;
@@ -163,10 +202,16 @@ export default {
163202 }
164203
165204 function editStage (id ) {
205+ if (! canEdit (id, ' stage' )) {
206+ return ;
207+ }
166208 openModal (' stage' , id);
167209 }
168210
169211 function editTransition (id ) {
212+ if (! canEdit (id, ' transition' )) {
213+ return ;
214+ }
170215 openModal (' transition' , id);
171216 }
172217
@@ -176,11 +221,17 @@ export default {
176221 }
177222
178223 function deleteStage (id ) {
224+ if (! canDelete (id, ' stage' )) {
225+ return ;
226+ }
179227 store .dispatch (' deleteStage' , { id, workflowId: workflowId .value });
180228 selectedStage .value = null ;
181229 }
182230
183231 function deleteTransition (id ) {
232+ if (! canDelete (id, ' transition' )) {
233+ return ;
234+ }
184235 store .dispatch (' deleteTransition' , { id, workflowId: workflowId .value });
185236 selectedTransition .value = null ;
186237 }
@@ -191,6 +242,9 @@ export default {
191242 }
192243
193244 function showDeleteModal (type , id ) {
245+ if ((! canDelete (id, ' stage' ) && type === ' stage' ) || (! canDelete (id, ' transition' ) && type === ' transition' )) {
246+ return ;
247+ }
194248 const title = translate (type === ' stage'
195249 ? ' COM_WORKFLOW_GRAPH_DELETE_STAGE_TITLE'
196250 : ' COM_WORKFLOW_GRAPH_DELETE_TRANSITION_TITLE' );
@@ -207,11 +261,17 @@ export default {
207261 }
208262
209263 function addStage () {
264+ if (! workflow? .value ? .canCreate ) {
265+ return ;
266+ }
210267 openModal (' stage' );
211268 announce (liveRegion .value , translate (' COM_WORKFLOW_GRAPH_ADD_STAGE_DIALOG_OPENED' ));
212269 }
213270
214271 function addTransition () {
272+ if (! workflow? .value ? .canCreate ) {
273+ return ;
274+ }
215275 openModal (' transition' );
216276 announce (liveRegion .value , translate (' COM_WORKFLOW_GRAPH_ADD_TRANSITION_DIALOG_OPENED' ));
217277 }
@@ -226,8 +286,13 @@ export default {
226286 );
227287 }
228288
229- function handleConnect () {
230- if (isTransitionMode .value ) openModal (' transition' );
289+ function handleConnect ({ source, target }) {
290+ if (! workflow? .value ? .canCreate ) {
291+ return ;
292+ }
293+ if (isTransitionMode .value && source && target) {
294+ openModal (' transition' , null , { from_stage_id: source, to_stage_id: target });
295+ }
231296 }
232297
233298 function selectEdge ({ edge }) {
@@ -385,18 +450,16 @@ export default {
385450 const { panX , panY , zoom } = store .getters .canvas ?? {};
386451
387452 if (
388- typeof panX === ' number' && ! Number .isNaN (panX) &&
389- typeof panY === ' number' && ! Number .isNaN (panY) &&
390- typeof zoom === ' number' && ! Number .isNaN (zoom)
453+ typeof panX === ' number' && ! Number .isNaN (panX)
454+ && typeof panY === ' number' && ! Number .isNaN (panY)
455+ && typeof zoom === ' number' && ! Number .isNaN (zoom)
391456 ) {
392-
393457 isRestoringViewport = true ;
394458 Promise .resolve ()
395459 .then (() => setViewport ({ x: panX, y: panY, zoom }))
396460 .finally (() => {
397461 isRestoringViewport = false ;
398462 });
399-
400463 } else {
401464 fitView ({ padding: 0.5 , duration: 300 });
402465 }
@@ -408,19 +471,17 @@ export default {
408471 return ;
409472 }
410473
411- if ([x, y, zoom].some (v => typeof v !== ' number' || Number .isNaN (v))) {
474+ if ([x, y, zoom].some (( v ) => typeof v !== ' number' || Number .isNaN (v))) {
412475 return ;
413476 }
414477 store .dispatch (' updateCanvasViewport' , { panX: x, panY: y, zoom });
415478 });
416479
417-
418-
419-
420480 return {
421481 loading,
422482 error,
423483 showMiniMap,
484+ workflow,
424485 positionedNodes,
425486 styledEdges,
426487 liveRegion,
0 commit comments