@cesarechazu/directus-extension-run-flow-refresh 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 cesar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # Run Flow + Refresh
2
+
3
+ Run a Directus manual flow for the current item and optionally refresh the current form, reload the page, or navigate back when the flow finishes.
4
+
5
+ This interface is designed for alias fields and works well in collection item views where a user needs a single action button to launch a manual flow and then refresh the UI.
6
+
7
+ ## Interface
8
+
9
+ <img src="https://raw.githubusercontent.com/cesarechazu/directus-extension-run-flow-refresh/main/img/interface.png" alt="Run Flow + Refresh interface" width="720">
10
+
11
+ ## Features
12
+
13
+ - Runs a manual Directus flow for the current item
14
+ - Passes the current collection and primary key to the flow trigger
15
+ - Optional confirmation dialog before execution
16
+ - Optional result dialog after completion
17
+ - Configurable refresh delay
18
+ - Supports form refresh, page reload, back navigation, or no reload after execution
19
+ - Works as an `alias` field, so it does not create a database column
20
+
21
+ ## Usage
22
+
23
+ Use this interface on an `alias` field inside an item form when you want to expose a manual action button to the user.
24
+
25
+ Typical flow:
26
+
27
+ - The user opens an existing item.
28
+ - The user clicks the button to trigger a Directus manual flow for that record.
29
+ - The flow receives the current collection and primary key.
30
+ - When the flow finishes, the interface can refresh the current form, reload the page, go back, or do nothing.
31
+
32
+ ## Options
33
+
34
+ - `flowId`: manual flow UUID to execute
35
+ - `buttonLabel`: visible button text
36
+ - `buttonIcon`: Directus icon for the action button
37
+ - `refreshType`: controls what happens after the flow finishes
38
+ - `form`: refresh the current item form
39
+ - `full`: reload the page
40
+ - `back`: return to the previous page, with page reload fallback when there is no useful history entry
41
+ - `none`: keep the current page unchanged
42
+ - `refreshDelay`: delay in milliseconds before applying the selected refresh behavior
43
+ - `confirmTitle`: confirmation dialog title
44
+ - `confirmMessage`: confirmation dialog message
45
+ - `confirmCancelLabel`: cancel button label
46
+ - `confirmContinueLabel`: continue button label
47
+ - `resultDialogEnabled`: show a result dialog after success
48
+ - `resultTitle`: result dialog title
49
+ - `resultMessage`: result dialog message
50
+ - `resultCloseLabel`: result dialog close button label
51
+
52
+ ## Notes
53
+
54
+ - The selected flow must use the Directus `manual` trigger type.
55
+ - New items must be saved before the flow can run.
56
+ - If no flow completion event is detected, the interface falls back to a delayed completion handling path.
57
+ - `Reload Form` uses the same refresh pattern as the native Directus flow sidebar. If the form refresh context is not available, it falls back to a page reload.
58
+
59
+ ## License
60
+
61
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{useApi as e,defineInterface as t}from"@directus/extensions-sdk";import{inject as n,ref as a,computed as i,onBeforeUnmount as l,resolveComponent as o,openBlock as r,createElementBlock as s,createElementVNode as c,createVNode as f,withCtx as u,createBlock as d,createCommentVNode as p,toDisplayString as m,createTextVNode as g,withModifiers as w}from"vue";var h=[],y=[];!function(e,t){if(e&&"undefined"!=typeof document){var n,a=!0===t.prepend?"prepend":"append",i=!0===t.singleTag,l="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(i){var o=h.indexOf(l);-1===o&&(o=h.push(l)-1,y[o]={}),n=y[o]&&y[o][a]?y[o][a]:y[o][a]=r()}else n=r();65279===e.charCodeAt(0)&&(e=e.substring(1)),n.styleSheet?n.styleSheet.cssText+=e:n.appendChild(document.createTextNode(e))}function r(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),t.attributes)for(var n=Object.keys(t.attributes),i=0;i<n.length;i++)e.setAttribute(n[i],t.attributes[n[i]]);var o="prepend"===a?"afterbegin":"beforeend";return l.insertAdjacentElement(o,e),e}}("\n.manual-flow-trigger-interface[data-v-99cf9e51] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.flow-executor[data-v-99cf9e51] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.action-button[data-v-99cf9e51] {\n align-self: flex-start;\n display: inline-flex;\n width: fit-content !important;\n min-width: max-content !important;\n max-width: none !important;\n --v-button-width: auto;\n --v-button-min-width: max-content;\n white-space: nowrap;\n overflow: visible;\n}\n.action-button[data-v-99cf9e51] .v-button__content {\n width: auto !important;\n max-width: none !important;\n overflow: visible;\n white-space: nowrap;\n}\n.button-content[data-v-99cf9e51] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n white-space: nowrap;\n}\n.button-icon[data-v-99cf9e51] {\n flex: 0 0 auto;\n}\n.notice-spacing[data-v-99cf9e51] {\n margin-top: 8px;\n}\n.confirm-backdrop[data-v-99cf9e51] {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.45);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 999;\n padding: 16px;\n}\n.confirm-panel[data-v-99cf9e51] {\n width: min(520px, 100%);\n background: var(--theme--background, #ffffff);\n color: var(--theme--foreground, #1b1b1b);\n border-radius: 8px;\n padding: 20px;\n box-shadow: 0 16px 48px rgba(0, 0, 0, 0.2);\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.confirm-title[data-v-99cf9e51] {\n font-size: 16px;\n font-weight: 600;\n}\n.confirm-message[data-v-99cf9e51] {\n opacity: 0.9;\n}\n.confirm-actions[data-v-99cf9e51] {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-top: 4px;\n}\n",{});var v=(e,t)=>{const n=e.__vccOpts||e;for(const[e,a]of t)n[e]=a;return n};const x={emits:["refresh"],props:{value:{type:String,default:null},flowId:{type:String,default:null},buttonLabel:{type:String,default:"Run Flow"},buttonIcon:{type:String,default:"play_arrow"},refreshType:{type:String,default:"full",validator:e=>["form","full","back","none"].includes(e)},refreshDelay:{type:Number,default:1e3},confirmTitle:{type:String,default:"Confirm Action"},confirmMessage:{type:String,default:"Do you want to run this flow?"},confirmCancelLabel:{type:String,default:"Cancel"},confirmContinueLabel:{type:String,default:"Run Flow"},resultDialogEnabled:{type:Boolean,default:!1},resultTitle:{type:String,default:"Done"},resultMessage:{type:String,default:"The flow finished successfully."},resultCloseLabel:{type:String,default:"Close"},collection:{type:String,required:!0},primaryKey:{type:[String,Number],default:"+"}},setup(t,{emit:o,attrs:r}){const s=e(),c=n("notify",null),f=n("refresh",null),u=n("values",null),d=a(!1),p=a(null),m=a(null),g=a(!1),w=a(!1),h=i(()=>Boolean(t.flowId)),y=i(()=>{const e=Number(t.refreshDelay);return!Number.isFinite(e)||e<0?0:Math.round(e)});function v(e){"function"==typeof c&&c(e)}async function x(){const e=t.flowId;if(e)if("+"!==t.primaryKey){d.value=!0,p.value=null;try{const n=(await s.get(`/flows/${e}`)).data.data;if(!n)throw new Error("Flow not found");if("manual"!==n.trigger)throw new Error("Flow is not a manual trigger type");const a={collection:t.collection,keys:[t.primaryKey]};await s.post(`/flows/trigger/${e}`,a),function(){const e=e=>{const n=t.flowId;e.detail?.flow!==n&&e.detail?.flow||(C(),a())};window.addEventListener("directus:flow:complete",e),window.addEventListener("flow:complete",e),m.value=e;const n=setTimeout(()=>{C(),a()},5e3);function a(){window.removeEventListener("directus:flow:complete",e),window.removeEventListener("flow:complete",e),clearTimeout(n),m.value=null}}()}catch(e){console.error("Error executing flow:",e),p.value=e.response?.data?.errors?.[0]?.message||e.message||"Error executing flow",v({title:"Error",text:p.value,type:"error"}),d.value=!1,g.value=!1}}else v({title:"Save Item First",text:"Please save this item before executing the flow",type:"warning"});else p.value="Flow is not configured"}async function b(){if("none"!==t.refreshType){if("form"===t.refreshType){const e=await async function(){if(!t.collection||"+"===t.primaryKey)return!1;const e="function"==typeof r.onSetFieldValue?r.onSetFieldValue:null;try{const n=await s.get(`/items/${t.collection}/${t.primaryKey}`),a=n?.data?.data;if(!a||"object"!=typeof a)return!1;let i=!1;for(const[t,n]of Object.entries(a))e?(e(t,n),i=!0):u&&"object"==typeof u&&(u[t]=n,i=!0);return i}catch(e){return console.warn("Form reload request failed, falling back to page reload.",e),!1}}();if(!e&&"function"==typeof f)try{return void f()}catch(e){console.warn("Injected form refresh failed, falling back to page reload.",e)}try{o("refresh")}catch{}if(e)return}"back"===t.refreshType&&window.history.length>1?window.history.back():window.location.reload()}}function C(){d.value=!1,g.value=!1,setTimeout(async()=>{t.resultDialogEnabled?w.value=!0:"none"!==t.refreshType?await b():v({title:"Success",text:"Flow executed successfully",type:"success"})},y.value)}return l(()=>{m.value&&(window.removeEventListener("directus:flow:complete",m.value),window.removeEventListener("flow:complete",m.value))}),{loading:d,errorMessage:p,executeFlow:x,canExecute:h,confirmOpen:g,resultOpen:w,openConfirm:function(){h.value&&(g.value=!0)},closeConfirm:function(){d.value||(g.value=!1)},confirmAndExecute:async function(){d.value||await x()},closeResult:async function(){w.value=!1,await b()}}}},b={class:"manual-flow-trigger-interface"},C={class:"flow-executor"},k={class:"button-content"},_={class:"confirm-panel"},L={class:"confirm-title"},T={key:0,class:"confirm-message"},S={class:"confirm-actions"},E={class:"confirm-panel"},D={class:"confirm-title"},F={key:0,class:"confirm-message"},R={class:"confirm-actions"};var M=t({id:"run-flow-refresh",name:"Run Flow + Refresh",icon:"play_arrow",description:"Run a manual flow for the current item and optionally refresh the current form or page when it finishes",component:v(x,[["render",function(e,t,n,a,i,l){const h=o("v-icon"),y=o("v-button"),v=o("v-notice");return r(),s("div",b,[c("div",C,[f(y,{loading:a.loading,disabled:a.loading||!a.canExecute,onClick:a.openConfirm,class:"action-button"},{default:u(()=>[c("span",k,[n.buttonIcon?(r(),d(h,{key:0,name:n.buttonIcon,class:"button-icon"},null,8,["name"])):p("v-if",!0),c("span",null,m(n.buttonLabel),1)])]),_:1},8,["loading","disabled","onClick"]),a.errorMessage?(r(),d(v,{key:0,type:"danger",onClose:t[0]||(t[0]=e=>a.errorMessage=null),class:"notice-spacing"},{default:u(()=>[g(m(a.errorMessage),1)]),_:1})):p("v-if",!0)]),a.confirmOpen?(r(),s("div",{key:0,class:"confirm-backdrop",role:"dialog","aria-modal":"true",onClick:t[1]||(t[1]=w((...e)=>a.closeConfirm&&a.closeConfirm(...e),["self"]))},[c("div",_,[c("div",L,m(n.confirmTitle),1),n.confirmMessage?(r(),s("div",T,m(n.confirmMessage),1)):p("v-if",!0),c("div",S,[f(y,{secondary:"",disabled:a.loading,onClick:a.closeConfirm},{default:u(()=>[g(m(n.confirmCancelLabel),1)]),_:1},8,["disabled","onClick"]),f(y,{loading:a.loading,disabled:a.loading,onClick:a.confirmAndExecute},{default:u(()=>[g(m(n.confirmContinueLabel),1)]),_:1},8,["loading","disabled","onClick"])])])])):p("v-if",!0),a.resultOpen?(r(),s("div",{key:1,class:"confirm-backdrop",role:"dialog","aria-modal":"true",onClick:t[2]||(t[2]=w((...e)=>a.closeResult&&a.closeResult(...e),["self"]))},[c("div",E,[c("div",D,m(n.resultTitle),1),n.resultMessage?(r(),s("div",F,m(n.resultMessage),1)):p("v-if",!0),c("div",R,[f(y,{onClick:a.closeResult},{default:u(()=>[g(m(n.resultCloseLabel),1)]),_:1},8,["onClick"])])])])):p("v-if",!0)])}],["__scopeId","data-v-99cf9e51"],["__file","interface.vue"]]),hideLabel:!0,options:[{field:"flowId",name:"Flow",type:"string",meta:{interface:"input",width:"full",required:!0,note:"Enter the manual Flow ID (UUID). You can find it in the URL when editing the flow in Settings > Flows.",options:{placeholder:"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}}},{field:"buttonLabel",name:"Button Label",type:"string",meta:{interface:"input",width:"half"},schema:{default_value:"Run Flow"}},{field:"buttonIcon",name:"Button Icon",type:"string",meta:{interface:"select-icon",width:"half"},schema:{default_value:"play_arrow"}},{field:"refreshType",name:"Refresh Mode",type:"string",meta:{interface:"select-dropdown",options:{choices:[{text:"Reload Form",value:"form"},{text:"Reload Page",value:"full"},{text:"Go Back",value:"back"},{text:"No Reload",value:"none"}]},width:"half"},schema:{default_value:"full"}},{field:"refreshDelay",name:"Refresh Delay (ms)",type:"integer",meta:{interface:"input",width:"half",note:"Delay in milliseconds before applying the selected refresh behavior."},schema:{default_value:1e3}},{field:"confirmDivider",name:"Confirmation",type:"alias",meta:{interface:"presentation-divider",options:{title:"Confirmation",icon:"help"},width:"full"}},{field:"confirmTitle",name:"Title",type:"string",meta:{interface:"input",width:"half"},schema:{default_value:"Confirm Action"}},{field:"confirmMessage",name:"Message",type:"string",meta:{interface:"input",width:"half"},schema:{default_value:"Do you want to run this flow?"}},{field:"confirmCancelLabel",name:"Cancel Button Label",type:"string",meta:{interface:"input",width:"half"},schema:{default_value:"Cancel"}},{field:"confirmContinueLabel",name:"Continue Button Label",type:"string",meta:{interface:"input",width:"half"},schema:{default_value:"Run Flow"}},{field:"resultDivider",name:"Result Dialog",type:"alias",meta:{interface:"presentation-divider",options:{title:"Result Dialog",icon:"check"},width:"full"}},{field:"resultDialogEnabled",name:"Show Dialog",type:"boolean",meta:{interface:"boolean",width:"half"},schema:{default_value:!1}},{field:"resultCloseLabel",name:"Close Button Label",type:"string",meta:{interface:"input",width:"half"},schema:{default_value:"Close"}},{field:"resultTitle",name:"Title",type:"string",meta:{interface:"input",width:"half"},schema:{default_value:"Done"}},{field:"resultMessage",name:"Message",type:"string",meta:{interface:"input",width:"half"},schema:{default_value:"The flow finished successfully."}}],types:["alias"],localTypes:["presentation"],group:"presentation"});export{M as default};
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@cesarechazu/directus-extension-run-flow-refresh",
3
+ "version": "1.0.0",
4
+ "description": "Interface to run a manual flow for the current item and optionally refresh the current form, reload the page, or navigate back after completion",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "cesar",
9
+ "email": "cesarechazu@gmail.com"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/cesarechazu/directus-extension-run-flow-refresh.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/cesarechazu/directus-extension-run-flow-refresh/issues"
17
+ },
18
+ "homepage": "https://github.com/cesarechazu/directus-extension-run-flow-refresh#readme",
19
+ "keywords": [
20
+ "directus",
21
+ "directus-extension",
22
+ "directus-extension-interface",
23
+ "flow",
24
+ "manual-flow",
25
+ "refresh"
26
+ ],
27
+ "files": [
28
+ "dist",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "directus:extension": {
33
+ "type": "interface",
34
+ "path": "dist/index.js",
35
+ "source": "src/index.js",
36
+ "host": "^11.0.0"
37
+ },
38
+ "scripts": {
39
+ "build": "directus-extension build",
40
+ "dev": "directus-extension build --watch",
41
+ "validate": "directus-extension validate"
42
+ },
43
+ "devDependencies": {
44
+ "@directus/extensions-sdk": "^11.0.0",
45
+ "vue": "^3.3.0"
46
+ }
47
+ }