directus-extension-dev-canvas
Version:
A module for developing Directus extensions with hot-reloading
2 lines (1 loc) • 11.7 kB
JavaScript
import{defineModule as e}from"@directus/extensions-sdk";import{computed as t,defineComponent as n,reactive as l,toRefs as o,toRef as a,ref as i,watch as u,nextTick as r,resolveComponent as s,openBlock as c,createBlock as d,resolveDynamicComponent as v,unref as p,withCtx as f,createVNode as y,normalizeProps as m,guardReactiveProps as g,createElementVNode as h,createTextVNode as _,onMounted as x,getCurrentInstance as b,onUnmounted as w,queuePostFlushCb as C,createElementBlock as S,Fragment as k,createCommentVNode as O,mergeProps as E,h as V}from"vue";import{useRouter as j,RouterView as R}from"vue-router";import{useI18n as U}from"vue-i18n";const $=["selection","layoutOptions","layoutQuery"];function T(e){const a=t((()=>function(e){return n({name:`${e.id}-wrapper`,props:{collection:{type:String,required:!0},selection:{type:Array,default:()=>[]},layoutOptions:{type:Object,default:()=>({})},layoutQuery:{type:Object,default:()=>({})},layoutProps:{type:Object,default:()=>({})},filter:{type:Object,default:null},filterUser:{type:Object,default:null},filterSystem:{type:Object,default:null},search:{type:String,default:null},showSelect:{type:String,default:"multiple"},selectMode:{type:Boolean,default:!1},readonly:{type:Boolean,default:!1},resetPreset:{type:Function,default:null},clearFilters:{type:Function,default:null}},emits:$.map((e=>`update:${e}`)),setup(t,{emit:n}){console.log("setup dynamic compoent");const a=l({...e.setup(t,{emit:n}),...o(t)});for(const e in a)a[`onUpdate:${e}`]=l=>{var o;o=e,$.includes(o)?n(`update:${e}`,l):Object.keys(t).includes(e)||(a[e]=l)};return{state:a}},render:e=>void 0!==e.$slots.default?e.$slots.default({layoutState:e.state}):null})}(e.value)));return{layoutWrapper:a}}const D={class:"layout-options"},M={class:"field"};var L=n({__name:"LayoutCanvas",props:{config:{},collection:{}},setup(e){const{t:t}=U(),n=e,{layoutWrapper:l}=T(a(n,"config")),o=i(!0),x=i(n.collection),b=i({}),w=i([]),C=i({}),S=i(!1);return u([x,b],(()=>{o.value&&!S.value&&(o.value=!1,S.value=!0,r((()=>{o.value=!0,r((()=>{S.value=!1}))})))})),(e,n)=>{const a=s("interface-system-collection"),i=s("sidebar-detail"),u=s("private-view"),r=s("v-notice");return e.config&&o.value?(c(),d(v(p(l)),{key:0,selection:w.value,"onUpdate:selection":n[1]||(n[1]=e=>w.value=e),"layout-options":b.value,"onUpdate:layoutOptions":n[2]||(n[2]=e=>b.value=e),"layout-query":C.value,"onUpdate:layoutQuery":n[3]||(n[3]=e=>C.value=e),collection:x.value},{default:f((({layoutState:l})=>[y(u,{class:"dev-canvas",title:"Development Canvas"},{actions:f((()=>[(c(),d(v(e.config.slots.actions),m(g(l)),null,16))])),sidebar:f((()=>[y(i,{icon:"layers",title:p(t)("layout_options")},{default:f((()=>[h("div",D,[h("div",M,[n[4]||(n[4]=h("div",{class:"type-label"},"Layout Collection",-1)),y(a,{modelValue:x.value,"onUpdate:modelValue":n[0]||(n[0]=e=>x.value=e),placeholder:"Select collection"},null,8,["modelValue"])]),(c(),d(v(e.config.slots.options),m(g(l)),null,16))])])),_:2},1032,["title"]),(c(),d(v(e.config.slots.sidebar),m(g(l)),null,16))])),default:f((()=>[(c(),d(v(e.config.component),m(g(l)),null,16))])),_:2},1024)])),_:1},40,["selection","layout-options","layout-query","collection"])):(c(),d(r,{key:1},{default:f((()=>n[5]||(n[5]=[_("Missing layout config")]))),_:1}))}}}),N=(e,t)=>{const n=e.__vccOpts||e;for(const[e,l]of t)n[e]=l;return n},A=N(L,[["__file","LayoutCanvas.vue"]]);let I=!1;function q(){if(I)return;I=!0;const e=new Map;window.__VUE_HMR_RUNTIME__={createRecord:B(n),rerender:B((function(e,n){const l=t.get(e);if(!l)return;l.initialDef.render=n,[...l.instances].forEach((e=>{n&&(e.render=n,F(e.type).render=n),e.renderCache=[],e.update()}))})),reload:B((function(n,l){const o=t.get(n);if(!o)return;l=F(l),P(o.initialDef,l);const a=[...o.instances];for(let t=0;t<a.length;t++){const n=a[t],i=F(n.type);let u=e.get(i);u||(i!==o.initialDef&&P(i,l),e.set(i,u=new Set)),u.add(n),n.appContext.propsCache.delete(n.type),n.appContext.emitsCache.delete(n.type),n.appContext.optionsCache.delete(n.type),n.ceReload?(u.add(n),n.ceReload(l.styles),u.delete(n)):n.parent?r((()=>{n.parent.update(),u.delete(n)})):n.appContext.reload?n.appContext.reload():"undefined"!=typeof window?window.location.reload():console.warn("[HMR] Root or manually mounted instance modified. Full reload required."),n.root.ce&&n!==n.root&&n.root.ce._removeChildStyle(i)}C((()=>{e.clear()}))}))};const t=new Map;function n(e,l){if(t.has(e)){const n=t.get(e);return n.initialDef=F(l),[...n.instances].forEach((e=>{e.render=()=>null,e.update()})),!1}const o=F(l);t.set(e,{initialDef:o,instances:new Set});const a=o.setup;return a._isPatched||(o.setup=function(e,l){return x((()=>{!function(e){const l=e.type.__hmrId;let o=t.get(l);o||(n(l,e.type),o=t.get(l)),o.instances.add(e)}(b())})),w((()=>{var e;e=b(),t.get(e.type.__hmrId).instances.delete(e)})),a.call(this,e,l)},o.setup._isPatched=!0),!0}}function F(e){return"function"==typeof e&&"__vccOpts"in e?e.__vccOpts:e}function P(e,t){Object.assign(e,t);for(const n in e)"__file"===n||n in t||delete e[n]}function B(e){return(t,n)=>{try{return e(t,n)}catch(e){console.error(e),console.warn("[HMR] Something went wrong during Vue component hot-reload. Full reload required.")}}}var H=n({__name:"module",setup(e){const n=j();let l;const o=i(!0),a=i(),m=i(),g=i(null),x=["display","interface","layout","module","bundle"],b={server:"http://localhost:5173"},w=i(b);i("");const C=i(""),V=i(!0),U=i([]),$=i({}),T=i([]),D=t((()=>{const e=T.value.map((e=>({text:`${e.type.toUpperCase()} - ${e.name}`,value:e.name})));return e.sort(((e,t)=>e.text.localeCompare(t.text))),[{name:"Vite Server",field:"server",type:"string",meta:{interface:"input",required:!0,options:{placeholder:"http://localhost:5173"},note:"The full url and port of your vite server"}},{name:"Select Extension",field:"extension",type:"string",meta:{interface:"select-dropdown",options:{items:e}}},{name:"Test Collection",field:"collection",type:"string",meta:{interface:"system-collection",options:{placeholder:"Select collection"},conditions:[{name:"Extension selected",rule:{extension:{_nnull:!0}},hidden:!1}],hidden:!0,note:"This is optional, your extension might not need it."}}]})),M=[{name:"Test Value",field:"value",type:"string",meta:{field:"value",interface:"input",options:{placeholder:"Test Value"}}}];try{const e=localStorage.getItem("dev-canvas-settings");e&&(w.value=JSON.parse(e),w.value.extension?I():w.value=b)}catch(e){w.value=b}function L(){V.value=!1,r((()=>{V.value=!0}))}async function N(){if(w.value.server.match(/^https?:\/\/.*:\d{2,5}/))try{const e=await fetch(`${w.value.server}/package.json`),t=await e.json(),n=t["directus:extension"];if(!n)return g.value="No extension found in package.json";if("bundle"===n.type)T.value=n.entries.filter((e=>x.includes(e.type)));else{if(!x.includes(n.type))return g.value=`Extension type ${n.type} is not supported`;n.name||(n.name=t.name),T.value=[n],w.value.extension=n.name}I()}catch(e){console.warn(e)}}async function I(){if(!w.value.extension)return;const e=T.value.find((e=>e.name===w.value.extension));if(!e)return void(g.value=new Error(`Extension ${w.value.extension} not found in package.json`));const{server:t,collection:i}=w.value,{source:u,type:r}=e;C.value=r;try{$.value={},a.value={field:{type:"unknown"},editing:"+",collection:i,relations:{o2m:void 0,m2o:void 0,m2a:void 0},collections:{related:void 0,junction:void 0},fields:{corresponding:void 0,junctionCurrent:void 0,junctionRelated:void 0,sort:void 0},items:{},localType:"standard",autoGenerateJunctionRelation:!1,saving:!1},g.value=null;const e=(await import(`${t}/${u}`)).default;if("module"===r){const t=e.routes.find((e=>""===e.path))||e.routes[0];if(!t)throw new Error("No root route found, ensure your module contains at least one route.");l&&(n.replace("/dev-canvas"),n.removeRoute(l)),l=n.addRoute("dev-canvas",{...t,path:e.id}),m.value=!0,n.replace(`/dev-canvas/${e.id}`)}else"layout"===r?m.value=e:(m.value=e.component,U.value=[...M,..."function"==typeof e.options?e.options(a.value):e.options]);o.value=!1}catch(e){console.warn(e),g.value=e,m.value=null}}return u(w,(e=>{localStorage.setItem("dev-canvas-settings",JSON.stringify(e))})),u((()=>w.value.server),N,{immediate:!0}),u($,L),q(),(e,t)=>{const n=s("v-card-title"),l=s("v-form"),a=s("v-error"),i=s("v-sheet"),u=s("v-button"),r=s("v-card-actions"),x=s("v-card"),b=s("v-dialog"),j=s("v-icon"),T=s("v-notice"),M=s("private-view");return c(),S(k,null,[y(b,{modelValue:o.value,"onUpdate:modelValue":t[1]||(t[1]=e=>o.value=e)},{default:f((()=>[y(x,{class:"dev-canvas-dialog"},{default:f((()=>[y(n,null,{default:f((()=>t[4]||(t[4]=[_("Load Extension")]))),_:1}),t[7]||(t[7]=h("br",null,null,-1)),y(i,null,{default:f((()=>[y(l,{fields:D.value,modelValue:w.value,"onUpdate:modelValue":t[0]||(t[0]=e=>w.value=e)},null,8,["fields","modelValue"]),g.value?(c(),d(a,{key:0,error:g.value},null,8,["error"])):O("v-if",!0)])),_:1}),y(r,null,{default:f((()=>[y(u,{onClick:N,secondary:""},{default:f((()=>t[5]||(t[5]=[_("Reload Extensions List")]))),_:1}),y(u,{onClick:I},{default:f((()=>t[6]||(t[6]=[_("Load It")]))),_:1})])),_:1})])),_:1})])),_:1},8,["modelValue"]),y(u,{icon:"",class:"dev-canvas-toggle",onClick:t[2]||(t[2]=e=>o.value=!0)},{default:f((()=>[y(j,{name:"developer_board"})])),_:1}),O(" LAYOUTS "),m.value&&"layout"===C.value?(c(),d(A,{key:0,collection:w.value.collection,config:m.value},null,8,["collection","config"])):m.value&&"module"===C.value?(c(),S(k,{key:1},[O(" MODULES "),y(p(R))],64)):(c(),S(k,{key:2},[O(" DISPLAYS & INTERFACES "),y(M,{class:"dev-canvas no-sidebar",title:"Development Canvas","split-view":!!m.value},{splitView:f((()=>[m.value&&V.value?(c(),d(i,{key:0},{default:f((()=>[(c(),d(v(m.value),E($.value,{collection:w.value.collection,field:e.extField}),null,16,["collection","field"]))])),_:1})):O("v-if",!0),t[10]||(t[10]=h("br",null,null,-1)),y(i,null,{default:f((()=>[y(u,{"x-small":"",secondary:"",onClick:L},{default:f((()=>t[9]||(t[9]=[_("Refresh")]))),_:1})])),_:1})])),default:f((()=>[m.value?(c(),d(i,{key:1},{default:f((()=>[y(l,{modelValue:$.value,"onUpdate:modelValue":t[3]||(t[3]=e=>$.value=e),fields:U.value},null,8,["modelValue","fields"])])),_:1})):(c(),d(i,{key:0},{default:f((()=>[y(T,null,{default:f((()=>t[8]||(t[8]=[_("No extension loaded")]))),_:1})])),_:1}))])),_:1},8,["split-view"])],2112))],64)}}}),J=[],Q=[];!function(e,t){if(e&&"undefined"!=typeof document){var n,l=!0===t.prepend?"prepend":"append",o=!0===t.singleTag,a="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(o){var i=J.indexOf(a);-1===i&&(i=J.push(a)-1,Q[i]={}),n=Q[i]&&Q[i][l]?Q[i][l]:Q[i][l]=u()}else n=u();65279===e.charCodeAt(0)&&(e=e.substring(1)),n.styleSheet?n.styleSheet.cssText+=e:n.appendChild(document.createTextNode(e))}function u(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),t.attributes)for(var n=Object.keys(t.attributes),o=0;o<n.length;o++)e.setAttribute(n[o],t.attributes[n[o]]);var i="prepend"===l?"afterbegin":"beforeend";return a.insertAdjacentElement(i,e),e}}("\n.dev-canvas-toggle {\n\tposition: fixed;\n\tbottom: 1rem;\n\tright: 1rem;\n\tz-index: 1000;\n}\n.dev-canvas,\n.dev-canvas-dialog.v-card {\n\t--theme--form--row-gap: 24px;\n\t--v-sheet-padding: 24px;\n}\n.dev-canvas .module-nav,\n.dev-canvas.no-sidebar #sidebar {\n\tdisplay: none !important;\n}\n.dev-canvas .field {\n\tpadding: 4px 0;\n}\n",{});var W=e({id:"dev-canvas",name:"Development Canvas",icon:"developer_board",routes:[{name:"dev-canvas",path:"",component:N(H,[["__file","module.vue"]]),children:[{path:"",component:V("div")},{path:":pathMatch(.*)*",redirect:{name:"dev-canvas"}}]}],preRegisterCheck:e=>e.admin_access});export{W as default};