adminizer 5.1.0-build.29 → 5.2.0-build.30
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/assets/{abnfDiagram-VCTEODGH-CpSXY7qH.js → abnfDiagram-VCTEODGH-BhZn7BLv.js} +1 -1
- package/assets/{add-DQWffo5j.js → add-DDfJt70P.js} +1 -1
- package/assets/{add-group-OdAd30ej.js → add-group-Cs3S9VVn.js} +1 -1
- package/assets/{add-user-C6cqZSzp.js → add-user-DxI_sJLw.js} +1 -1
- package/assets/ai-assistant/agent.es.js +14201 -11686
- package/assets/app-DM8KzeFz.css +1 -0
- package/assets/app-DOMFUTFw.js +138 -0
- package/assets/{arc-6oG0N2EU.js → arc-BRY7wCfa.js} +1 -1
- package/assets/{architectureDiagram-5GKGNRK7-BO5E3Osk.js → architectureDiagram-5GKGNRK7-DfBT7jAW.js} +1 -1
- package/assets/{blockDiagram-I7D4REHJ-DpKAEeRQ.js → blockDiagram-I7D4REHJ-CW2mcR7Z.js} +1 -1
- package/assets/{c4Diagram-7LVT6UL2-K4ilHoqv.js → c4Diagram-7LVT6UL2-BGsyO-4Y.js} +1 -1
- package/assets/{catalog-BaSowP5U.js → catalog-cyCZOCXs.js} +3 -3
- package/assets/channel-Bd-bsjgh.js +1 -0
- package/assets/{chunk-2Q5K7J3B-CFvbnPgN.js → chunk-2Q5K7J3B-4EnjsYhG.js} +1 -1
- package/assets/{chunk-5VM5RSS4-Cxb3_K7a.js → chunk-5VM5RSS4-BVzmz0IS.js} +1 -1
- package/assets/{chunk-F27PBJKO-Bp-e-RqW.js → chunk-F27PBJKO-Bkf9Z4lt.js} +1 -1
- package/assets/{chunk-IMKFNOWR-D03Bbv3p.js → chunk-IMKFNOWR-Dg6Y3xGC.js} +1 -1
- package/assets/{chunk-JWPE2WC7-BQzIFXbt.js → chunk-JWPE2WC7-BdVNpqE2.js} +1 -1
- package/assets/{chunk-POPQ4Y6H-DGPhwQEk.js → chunk-POPQ4Y6H-0R-etdBM.js} +1 -1
- package/assets/{chunk-SVP7TREG-CFG2uzdK.js → chunk-SVP7TREG-CdABJwLU.js} +1 -1
- package/assets/{chunk-TICWLB2K-BRoATx6O.js → chunk-TICWLB2K-Da-oSw37.js} +1 -1
- package/assets/{chunk-XXDRQBXY-MTSPV1jX.js → chunk-XXDRQBXY-Ba8BsH2Z.js} +1 -1
- package/assets/classDiagram-ZZMXUADV-BftNBmvr.js +1 -0
- package/assets/classDiagram-v2-VYDZK3BY-BftNBmvr.js +1 -0
- package/assets/controls/ckeditor.es.js +10659 -10551
- package/assets/controls/handsontable.es.js +9053 -8479
- package/assets/controls/jsoneditor.es.js +479 -449
- package/assets/controls/leaflet.es.js +672 -663
- package/assets/controls/toast-ui.es.js +13696 -13676
- package/assets/{cose-bilkent-JH36ORCC-Cd04LiHO.js → cose-bilkent-JH36ORCC-BYrWDdVx.js} +1 -1
- package/assets/{cynefin-OW5HDTMX-Cvk-t4EK.js → cynefin-OW5HDTMX-CwHzXvDB.js} +1 -1
- package/assets/{cynefinDiagram-5FMLGOSQ-CHBsEINZ.js → cynefinDiagram-5FMLGOSQ-V6tH6arn.js} +1 -1
- package/assets/{dagre-GXQ25YYZ-Dq-0d5Tl.js → dagre-GXQ25YYZ-CaBvafdG.js} +1 -1
- package/assets/{dashboard-BZo6F7y9.js → dashboard-C27hB1GI.js} +1 -1
- package/assets/{diagram-S7CK7UJ4-BKDTPndI.js → diagram-S7CK7UJ4-85jkE9hd.js} +1 -1
- package/assets/{diagram-UQ7AKVKN-DZYq9mm9.js → diagram-UQ7AKVKN-DHJRq1TM.js} +1 -1
- package/assets/{diagram-VSXAHHWV-CVOsZwCq.js → diagram-VSXAHHWV-C74VLfSc.js} +1 -1
- package/assets/{diagram-VX7I27RA-BCBXgENw.js → diagram-VX7I27RA-CVJcG5hn.js} +1 -1
- package/assets/{diagram-Z3DM3KII-ByNHDStX.js → diagram-Z3DM3KII-B8ybg5RA.js} +1 -1
- package/assets/{docs-CDmOUM3P.js → docs-CK6W0Jko.js} +1 -1
- package/assets/{ebnfDiagram-PWID7BFC-WrVgmCqC.js → ebnfDiagram-PWID7BFC-D_gz_iz6.js} +1 -1
- package/assets/{erDiagram-RLTQ6QDP-1QXTF1US.js → erDiagram-RLTQ6QDP-D3W95aGH.js} +1 -1
- package/assets/{flowDiagram-HODETNUW-DWcydZT-.js → flowDiagram-HODETNUW-D2PTWIEg.js} +1 -1
- package/assets/{ganttDiagram-EL5Y4UJY-BDrQ3uCR.js → ganttDiagram-EL5Y4UJY-TFBUh0C6.js} +1 -1
- package/assets/{gitGraphDiagram-WWUBYQGX-oD2bpMWh.js → gitGraphDiagram-WWUBYQGX-BfFJzeqx.js} +1 -1
- package/assets/{history-CTbCqtJA.js → history-DX6CEQqv.js} +1 -1
- package/assets/{infoDiagram-27XIBGKW-C8opSvmW.js → infoDiagram-27XIBGKW-esGmrWiw.js} +1 -1
- package/assets/{init-user-DDmp5FmX.js → init-user-D1G_dbcZ.js} +1 -1
- package/assets/{ishikawaDiagram-5VMMS53U-CqOCcw38.js → ishikawaDiagram-5VMMS53U--aGHPnva.js} +1 -1
- package/assets/{journeyDiagram-3NMN7TZE-B1OlZWx5.js → journeyDiagram-3NMN7TZE-03BXeE8O.js} +1 -1
- package/assets/{kanban-definition-UXKFOSKX-DIEdmOZD.js → kanban-definition-UXKFOSKX-JdDv2WHg.js} +1 -1
- package/assets/{layout-Cznoi1Xi.js → layout-Bz6WKClu.js} +1 -1
- package/assets/{linear-DbhwLrTs.js → linear-Chzx_9mb.js} +1 -1
- package/assets/{list-X8LYs75t.js → list-BuSdZ2Ic.js} +1 -1
- package/assets/{login-D0flIAhA.js → login-DFWfnrmE.js} +1 -1
- package/assets/manifest.json +277 -277
- package/assets/media-manager-CT4LZgo_.js +7 -0
- package/assets/mermaid.core-Dp-0i8FJ.js +310 -0
- package/assets/{mindmap-definition-YA3MSWOX-G8OJl_uT.js → mindmap-definition-YA3MSWOX-BJSEYobY.js} +1 -1
- package/assets/{module-D347sEFr.js → module-Cgn-q5gZ.js} +1 -1
- package/assets/{notification-C7usJcF-.js → notification-BrfoqVVT.js} +1 -1
- package/assets/{pegDiagram-XKGWAZYB-CqOymfUM.js → pegDiagram-XKGWAZYB-ccVsKwl1.js} +1 -1
- package/assets/{pieDiagram-E7YTZNPT-C_nbNUey.js → pieDiagram-E7YTZNPT-B1XZVgNq.js} +1 -1
- package/assets/{quadrantDiagram-AXDQQJYC-RDCWL_jp.js → quadrantDiagram-AXDQQJYC-CdABEYmF.js} +1 -1
- package/assets/{railroadDiagram-O6MQD6OU-Bi_j7Fb_.js → railroadDiagram-O6MQD6OU-OX83MXuO.js} +1 -1
- package/assets/{register-DhdaEsna.js → register-Cxf3Pow-.js} +1 -1
- package/assets/{requirementDiagram-BXWQKSXE-Cg6IzoFA.js → requirementDiagram-BXWQKSXE-CD7swf9u.js} +1 -1
- package/assets/{ru-DMAUOdKr.js → ru-DxiFV21N.js} +1 -1
- package/assets/{sankeyDiagram-P5KCCOFB-BNN3S4hm.js → sankeyDiagram-P5KCCOFB-Cgwq2DVJ.js} +1 -1
- package/assets/{sequenceDiagram-WJ2MYXX4-C9UEgNLg.js → sequenceDiagram-WJ2MYXX4-BgjP07Zh.js} +1 -1
- package/assets/{sizeCapture-INFHLROL-DH9gM8J8.js → sizeCapture-INFHLROL-B-jQ1aKT.js} +1 -1
- package/assets/{stateDiagram-D77RDMKH-CzuNaJnp.js → stateDiagram-D77RDMKH-Drot14NK.js} +1 -1
- package/assets/stateDiagram-v2-MP3YSRHH-C5VLF0H1.js +1 -0
- package/assets/{swimlanes-42K2YHIH-DlfHkCIp.js → swimlanes-42K2YHIH-lCqHhK1l.js} +1 -1
- package/assets/swimlanesDiagram-VR7AAH4N-4yyX1ZbA.js +8 -0
- package/assets/{timeline-definition-24CTP7MA-B45WKY9z.js → timeline-definition-24CTP7MA-B-QLcvwc.js} +1 -1
- package/assets/{use-appearance-DPeAg6kc.js → use-appearance-B0ck1CR_.js} +1 -1
- package/assets/{user-filters-list-B-txVF_a.js → user-filters-list-ce2cmS5Z.js} +1 -1
- package/assets/{vennDiagram-4TSXK5OY-BARlq8EX.js → vennDiagram-4TSXK5OY-2DN2uspP.js} +1 -1
- package/assets/{wardleyDiagram-VM6X3IG4-DSGKYXrr.js → wardleyDiagram-VM6X3IG4-C_GODc0p.js} +1 -1
- package/assets/{welcome-Cdhwf3y4.js → welcome-DaAj6jOI.js} +1 -1
- package/assets/with-app-layout-CwAECGwY.js +34 -0
- package/assets/{xychartDiagram-S5SC5T6Z-DPA8cj4H.js → xychartDiagram-S5SC5T6Z-Cq8htGoW.js} +1 -1
- package/controllers/initUser.js +1 -1
- package/helpers/inertiaAddHelper.js +10 -1
- package/helpers/inertiaMenuHelper.d.ts +3 -2
- package/helpers/inertiaMenuHelper.js +9 -4
- package/helpers/navigationAccessHelper.d.ts +5 -0
- package/helpers/navigationAccessHelper.js +13 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/interfaces/adminpanelConfig.d.ts +7 -0
- package/lib/Adminizer.d.ts +2 -0
- package/lib/Adminizer.js +3 -0
- package/lib/admin-links/AdminLinkHandler.js +5 -1
- package/lib/app-manager/AdminizerApp.d.ts +34 -0
- package/lib/app-manager/AppManager.js +35 -0
- package/lib/app-manager/ContextHandler.d.ts +240 -0
- package/lib/app-manager/ContextHandler.js +446 -0
- package/lib/app-manager/ControllerHandler.d.ts +2 -0
- package/lib/app-manager/ControllerHandler.js +7 -0
- package/package.json +3 -2
- package/system/bindInertia.js +34 -9
- package/assets/app-DMN-4aCp.js +0 -138
- package/assets/app-TCCHARSx.css +0 -1
- package/assets/channel-Dh5UPZKs.js +0 -1
- package/assets/classDiagram-ZZMXUADV-a_pfQoRf.js +0 -1
- package/assets/classDiagram-v2-VYDZK3BY-a_pfQoRf.js +0 -1
- package/assets/media-manager-cyrZjDu3.js +0 -6
- package/assets/mermaid.core-DtG9mjld.js +0 -310
- package/assets/stateDiagram-v2-MP3YSRHH-Cm0oV4uL.js +0 -1
- package/assets/swimlanesDiagram-VR7AAH4N-Cc5GTkO2.js +0 -8
- package/assets/with-app-layout-CcoboJFc.js +0 -31
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{s as pi,g as mi,o as $t,n as yi,a as bi,b as wi,_ as a,l as Ut,D as Ai,d as Ci,p as Si,y as Dt,i as Ri,A as Gt,B as _i,E as ki,aC as Ti,a9 as Xt}from"./mermaid.core-
|
|
1
|
+
import{s as pi,g as mi,o as $t,n as yi,a as bi,b as wi,_ as a,l as Ut,D as Ai,d as Ci,p as Si,y as Dt,i as Ri,A as Gt,B as _i,E as ki,aC as Ti,a9 as Xt}from"./mermaid.core-Dp-0i8FJ.js";import{i as Di}from"./init-Gi6I4Gst.js";import{o as Pi}from"./ordinal-Cboi1Yqb.js";import{l as Nt}from"./linear-Chzx_9mb.js";import"./app-DOMFUTFw.js";import"./isObject-DL-BuaBl.js";import"./defaultLocale-DX6XiGOO.js";function vi(e,t,i){e=+e,t=+t,i=(n=arguments.length)<2?(t=e,e=0,1):n<3?1:+i;for(var s=-1,n=Math.max(0,Math.ceil((t-e)/i))|0,o=new Array(n);++s<n;)o[s]=e+s*i;return o}function St(){var e=Pi().unknown(void 0),t=e.domain,i=e.range,s=0,n=1,o,h,p=!1,u=0,f=0,R=.5;delete e.unknown;function C(){var y=t().length,E=n<s,v=E?n:s,L=E?s:n;o=(L-v)/Math.max(1,y-u+f*2),p&&(o=Math.floor(o)),v+=(L-v-o*(y-u))*R,h=o*(1-u),p&&(v=Math.round(v),h=Math.round(h));var M=vi(y).map(function(b){return v+o*b});return i(E?M.reverse():M)}return e.domain=function(y){return arguments.length?(t(y),C()):t()},e.range=function(y){return arguments.length?([s,n]=y,s=+s,n=+n,C()):[s,n]},e.rangeRound=function(y){return[s,n]=y,s=+s,n=+n,p=!0,C()},e.bandwidth=function(){return h},e.step=function(){return o},e.round=function(y){return arguments.length?(p=!!y,C()):p},e.padding=function(y){return arguments.length?(u=Math.min(1,f=+y),C()):u},e.paddingInner=function(y){return arguments.length?(u=Math.min(1,y),C()):u},e.paddingOuter=function(y){return arguments.length?(f=+y,C()):f},e.align=function(y){return arguments.length?(R=Math.max(0,Math.min(1,y)),C()):R},e.copy=function(){return St(t(),[s,n]).round(p).paddingInner(u).paddingOuter(f).align(R)},Di.apply(C(),arguments)}var Rt=(function(){var e=a(function(W,l,g,d){for(g=g||{},d=W.length;d--;g[W[d]]=l);return g},"o"),t=[1,10,12,14,16,18,19,21,23],i=[2,6],s=[1,3],n=[1,5],o=[1,6],h=[1,7],p=[1,5,10,12,14,16,18,19,21,23,36,37,38],u=[1,25],f=[1,26],R=[1,28],C=[1,29],y=[1,30],E=[1,31],v=[1,32],L=[1,33],M=[1,34],b=[1,35],D=[1,36],c=[1,37],z=[1,43],F=[1,42],X=[1,47],N=[1,50],k=[1,10,12,14,16,18,19,21,23,36,37,38],H=[1,10,12,14,16,18,19,21,23,24,26,28,29,36,37,38],A=[1,10,12,14,16,18,19,21,23,24,26,28,29,36,37,38,42,43,44,45,46,47,48,49,50,51],S=[1,65],O=[26,28],T={trace:a(function(){},"trace"),yy:{},symbols_:{error:2,start:3,eol:4,XYCHART:5,chartConfig:6,document:7,CHART_ORIENTATION:8,statement:9,title:10,text:11,X_AXIS:12,parseXAxis:13,Y_AXIS:14,parseYAxis:15,LINE:16,plotData:17,BAR:18,acc_title:19,acc_title_value:20,acc_descr:21,acc_descr_value:22,acc_descr_multiline_value:23,SQUARE_BRACES_START:24,dataPoints:25,SQUARE_BRACES_END:26,dataPoint:27,COMMA:28,NUMBER_WITH_DECIMAL:29,STR:30,xAxisData:31,bandData:32,ARROW_DELIMITER:33,commaSeparatedTexts:34,yAxisData:35,NEWLINE:36,SEMI:37,EOF:38,alphaNum:39,MD_STR:40,alphaNumToken:41,AMP:42,NUM:43,ALPHA:44,PLUS:45,EQUALS:46,MULT:47,DOT:48,BRKT:49,MINUS:50,UNDERSCORE:51,$accept:0,$end:1},terminals_:{2:"error",5:"XYCHART",8:"CHART_ORIENTATION",10:"title",12:"X_AXIS",14:"Y_AXIS",16:"LINE",18:"BAR",19:"acc_title",20:"acc_title_value",21:"acc_descr",22:"acc_descr_value",23:"acc_descr_multiline_value",24:"SQUARE_BRACES_START",26:"SQUARE_BRACES_END",28:"COMMA",29:"NUMBER_WITH_DECIMAL",30:"STR",33:"ARROW_DELIMITER",36:"NEWLINE",37:"SEMI",38:"EOF",40:"MD_STR",42:"AMP",43:"NUM",44:"ALPHA",45:"PLUS",46:"EQUALS",47:"MULT",48:"DOT",49:"BRKT",50:"MINUS",51:"UNDERSCORE"},productions_:[0,[3,2],[3,3],[3,2],[3,1],[6,1],[7,0],[7,2],[9,2],[9,2],[9,2],[9,2],[9,2],[9,3],[9,2],[9,3],[9,2],[9,2],[9,1],[17,3],[25,3],[25,1],[27,2],[27,1],[13,1],[13,2],[13,1],[31,1],[31,3],[32,3],[34,3],[34,1],[15,1],[15,2],[15,1],[35,3],[4,1],[4,1],[4,1],[11,1],[11,1],[11,1],[39,1],[39,2],[41,1],[41,1],[41,1],[41,1],[41,1],[41,1],[41,1],[41,1],[41,1],[41,1]],performAction:a(function(l,g,d,x,_,r,lt){var m=r.length-1;switch(_){case 5:x.setOrientation(r[m]);break;case 9:x.setDiagramTitle(r[m].text.trim());break;case 12:x.setLineData({text:"",type:"text"},r[m]);break;case 13:x.setLineData(r[m-1],r[m]);break;case 14:x.setBarData({text:"",type:"text"},r[m]);break;case 15:x.setBarData(r[m-1],r[m]);break;case 16:this.$=r[m].trim(),x.setAccTitle(this.$);break;case 17:case 18:this.$=r[m].trim(),x.setAccDescription(this.$);break;case 19:this.$=r[m-1];break;case 20:case 30:this.$=[r[m-2],...r[m]];break;case 21:case 31:this.$=[r[m]];break;case 22:this.$={value:Number(r[m-1]),label:r[m]};break;case 23:this.$={value:Number(r[m]),label:""};break;case 24:x.setXAxisTitle(r[m]);break;case 25:x.setXAxisTitle(r[m-1]);break;case 26:x.setXAxisTitle({type:"text",text:""});break;case 27:x.setXAxisBand(r[m]);break;case 28:x.setXAxisRangeData(Number(r[m-2]),Number(r[m]));break;case 29:this.$=r[m-1];break;case 32:x.setYAxisTitle(r[m]);break;case 33:x.setYAxisTitle(r[m-1]);break;case 34:x.setYAxisTitle({type:"text",text:""});break;case 35:x.setYAxisRangeData(Number(r[m-2]),Number(r[m]));break;case 39:this.$={text:r[m],type:"text"};break;case 40:this.$={text:r[m],type:"text"};break;case 41:this.$={text:r[m],type:"markdown"};break;case 42:this.$=r[m];break;case 43:this.$=r[m-1]+""+r[m];break}},"anonymous"),table:[e(t,i,{3:1,4:2,7:4,5:s,36:n,37:o,38:h}),{1:[3]},e(t,i,{4:2,7:4,3:8,5:s,36:n,37:o,38:h}),e(t,i,{4:2,7:4,6:9,3:10,5:s,8:[1,11],36:n,37:o,38:h}),{1:[2,4],9:12,10:[1,13],12:[1,14],14:[1,15],16:[1,16],18:[1,17],19:[1,18],21:[1,19],23:[1,20]},e(p,[2,36]),e(p,[2,37]),e(p,[2,38]),{1:[2,1]},e(t,i,{4:2,7:4,3:21,5:s,36:n,37:o,38:h}),{1:[2,3]},e(p,[2,5]),e(t,[2,7],{4:22,36:n,37:o,38:h}),{11:23,30:u,39:24,40:f,41:27,42:R,43:C,44:y,45:E,46:v,47:L,48:M,49:b,50:D,51:c},{11:39,13:38,24:z,29:F,30:u,31:40,32:41,39:24,40:f,41:27,42:R,43:C,44:y,45:E,46:v,47:L,48:M,49:b,50:D,51:c},{11:45,15:44,29:X,30:u,35:46,39:24,40:f,41:27,42:R,43:C,44:y,45:E,46:v,47:L,48:M,49:b,50:D,51:c},{11:49,17:48,24:N,30:u,39:24,40:f,41:27,42:R,43:C,44:y,45:E,46:v,47:L,48:M,49:b,50:D,51:c},{11:52,17:51,24:N,30:u,39:24,40:f,41:27,42:R,43:C,44:y,45:E,46:v,47:L,48:M,49:b,50:D,51:c},{20:[1,53]},{22:[1,54]},e(k,[2,18]),{1:[2,2]},e(k,[2,8]),e(k,[2,9]),e(H,[2,39],{41:55,42:R,43:C,44:y,45:E,46:v,47:L,48:M,49:b,50:D,51:c}),e(H,[2,40]),e(H,[2,41]),e(A,[2,42]),e(A,[2,44]),e(A,[2,45]),e(A,[2,46]),e(A,[2,47]),e(A,[2,48]),e(A,[2,49]),e(A,[2,50]),e(A,[2,51]),e(A,[2,52]),e(A,[2,53]),e(k,[2,10]),e(k,[2,24],{32:41,31:56,24:z,29:F}),e(k,[2,26]),e(k,[2,27]),{33:[1,57]},{11:59,30:u,34:58,39:24,40:f,41:27,42:R,43:C,44:y,45:E,46:v,47:L,48:M,49:b,50:D,51:c},e(k,[2,11]),e(k,[2,32],{35:60,29:X}),e(k,[2,34]),{33:[1,61]},e(k,[2,12]),{17:62,24:N},{25:63,27:64,29:S},e(k,[2,14]),{17:66,24:N},e(k,[2,16]),e(k,[2,17]),e(A,[2,43]),e(k,[2,25]),{29:[1,67]},{26:[1,68]},{26:[2,31],28:[1,69]},e(k,[2,33]),{29:[1,70]},e(k,[2,13]),{26:[1,71]},{26:[2,21],28:[1,72]},e(O,[2,23],{30:[1,73]}),e(k,[2,15]),e(k,[2,28]),e(k,[2,29]),{11:59,30:u,34:74,39:24,40:f,41:27,42:R,43:C,44:y,45:E,46:v,47:L,48:M,49:b,50:D,51:c},e(k,[2,35]),e(k,[2,19]),{25:75,27:64,29:S},e(O,[2,22]),{26:[2,30]},{26:[2,20]}],defaultActions:{8:[2,1],10:[2,3],21:[2,2],74:[2,30],75:[2,20]},parseError:a(function(l,g){if(g.recoverable)this.trace(l);else{var d=new Error(l);throw d.hash=g,d}},"parseError"),parse:a(function(l){var g=this,d=[0],x=[],_=[null],r=[],lt=this.table,m="",dt=0,Ot=0,ui=2,Vt=1,di=r.slice.call(arguments,1),P=Object.create(this.lexer),$={yy:{}};for(var bt in this.yy)Object.prototype.hasOwnProperty.call(this.yy,bt)&&($.yy[bt]=this.yy[bt]);P.setInput(l,$.yy),$.yy.lexer=P,$.yy.parser=this,typeof P.yylloc>"u"&&(P.yylloc={});var wt=P.yylloc;r.push(wt);var xi=P.options&&P.options.ranges;typeof $.yy.parseError=="function"?this.parseError=$.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function fi(B){d.length=d.length-2*B,_.length=_.length-B,r.length=r.length-B}a(fi,"popStack");function Ft(){var B;return B=x.pop()||P.lex()||Vt,typeof B!="number"&&(B instanceof Array&&(x=B,B=x.pop()),B=g.symbols_[B]||B),B}a(Ft,"lex");for(var I,U,V,At,j={},xt,Y,Wt,ft;;){if(U=d[d.length-1],this.defaultActions[U]?V=this.defaultActions[U]:((I===null||typeof I>"u")&&(I=Ft()),V=lt[U]&<[U][I]),typeof V>"u"||!V.length||!V[0]){var Ct="";ft=[];for(xt in lt[U])this.terminals_[xt]&&xt>ui&&ft.push("'"+this.terminals_[xt]+"'");P.showPosition?Ct="Parse error on line "+(dt+1)+`:
|
|
2
2
|
`+P.showPosition()+`
|
|
3
3
|
Expecting `+ft.join(", ")+", got '"+(this.terminals_[I]||I)+"'":Ct="Parse error on line "+(dt+1)+": Unexpected "+(I==Vt?"end of input":"'"+(this.terminals_[I]||I)+"'"),this.parseError(Ct,{text:P.match,token:this.terminals_[I]||I,line:P.yylineno,loc:wt,expected:ft})}if(V[0]instanceof Array&&V.length>1)throw new Error("Parse Error: multiple actions possible at state: "+U+", token: "+I);switch(V[0]){case 1:d.push(I),_.push(P.yytext),r.push(P.yylloc),d.push(V[1]),I=null,Ot=P.yyleng,m=P.yytext,dt=P.yylineno,wt=P.yylloc;break;case 2:if(Y=this.productions_[V[1]][1],j.$=_[_.length-Y],j._$={first_line:r[r.length-(Y||1)].first_line,last_line:r[r.length-1].last_line,first_column:r[r.length-(Y||1)].first_column,last_column:r[r.length-1].last_column},xi&&(j._$.range=[r[r.length-(Y||1)].range[0],r[r.length-1].range[1]]),At=this.performAction.apply(j,[m,Ot,dt,$.yy,V[1],_,r].concat(di)),typeof At<"u")return At;Y&&(d=d.slice(0,-1*Y*2),_=_.slice(0,-1*Y),r=r.slice(0,-1*Y)),d.push(this.productions_[V[1]][0]),_.push(j.$),r.push(j._$),Wt=lt[d[d.length-2]][d[d.length-1]],d.push(Wt);break;case 3:return!0}}return!0},"parse")},ht=(function(){var W={EOF:1,parseError:a(function(g,d){if(this.yy.parser)this.yy.parser.parseError(g,d);else throw new Error(g)},"parseError"),setInput:a(function(l,g){return this.yy=g||this.yy||{},this._input=l,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:a(function(){var l=this._input[0];this.yytext+=l,this.yyleng++,this.offset++,this.match+=l,this.matched+=l;var g=l.match(/(?:\r\n?|\n).*/g);return g?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),l},"input"),unput:a(function(l){var g=l.length,d=l.split(/(?:\r\n?|\n)/g);this._input=l+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-g),this.offset-=g;var x=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),d.length-1&&(this.yylineno-=d.length-1);var _=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:d?(d.length===x.length?this.yylloc.first_column:0)+x[x.length-d.length].length-d[0].length:this.yylloc.first_column-g},this.options.ranges&&(this.yylloc.range=[_[0],_[0]+this.yyleng-g]),this.yyleng=this.yytext.length,this},"unput"),more:a(function(){return this._more=!0,this},"more"),reject:a(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
|
|
4
4
|
`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:a(function(l){this.unput(this.match.slice(l))},"less"),pastInput:a(function(){var l=this.matched.substr(0,this.matched.length-this.match.length);return(l.length>20?"...":"")+l.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:a(function(){var l=this.match;return l.length<20&&(l+=this._input.substr(0,20-l.length)),(l.substr(0,20)+(l.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:a(function(){var l=this.pastInput(),g=new Array(l.length+1).join("-");return l+this.upcomingInput()+`
|
package/controllers/initUser.js
CHANGED
|
@@ -9,7 +9,7 @@ export default async function initUser(req, res) {
|
|
|
9
9
|
const userModel = req.adminizer.modelHandler.internal("auth").get("User");
|
|
10
10
|
let admins = await userModel.find({ where: { isAdministrator: true } });
|
|
11
11
|
if (admins.length) {
|
|
12
|
-
res.redirect(`${req.adminizer.config.routePrefix}/model/User/login`);
|
|
12
|
+
return res.redirect(`${req.adminizer.config.routePrefix}/model/User/login`);
|
|
13
13
|
}
|
|
14
14
|
if (req.method.toUpperCase() === "POST") {
|
|
15
15
|
let login = req.body.login;
|
|
@@ -2,6 +2,7 @@ import inertiaActionsHelper from "./inertiaActionsHelper.js";
|
|
|
2
2
|
import { isObject } from "./JsUtils.js";
|
|
3
3
|
import { withAssetVersion } from "./assetVersionHelper.js";
|
|
4
4
|
import { Adminizer } from "../lib/Adminizer.js";
|
|
5
|
+
import { isBlockedLink } from "./navigationAccessHelper.js";
|
|
5
6
|
const missingControlWarnings = new Set();
|
|
6
7
|
/**
|
|
7
8
|
* Get ISO week number from date
|
|
@@ -123,8 +124,11 @@ export default async function inertiaAddHelper(req, modelResource, fields, recor
|
|
|
123
124
|
options = initOptions;
|
|
124
125
|
value = initValue;
|
|
125
126
|
const rawRelatedModel = (field.model?.model || field.model?.collection);
|
|
127
|
+
// `model`/`collection` is the host ORM model name, not an Adminizer resource name:
|
|
128
|
+
// resolve it the same way FieldsHelper.loadAssoc does, otherwise a host model that
|
|
129
|
+
// shares its name with a system resource (group -> Group, user -> User) opens the wrong form
|
|
126
130
|
relatedModel = rawRelatedModel
|
|
127
|
-
? req.adminizer.modelHandler.
|
|
131
|
+
? req.adminizer.modelHandler.resolveAssociationResource(rawRelatedModel, field.model?.resourceName)
|
|
128
132
|
: undefined;
|
|
129
133
|
if (relatedModel && req.user) {
|
|
130
134
|
canCreateRelated = await req.adminizer.accessRightsHelper.checkPermission(`create-${relatedModel}-model`, req.user);
|
|
@@ -132,6 +136,11 @@ export default async function inertiaAddHelper(req, modelResource, fields, recor
|
|
|
132
136
|
else if (relatedModel && !req.adminizer.config.auth?.enable) {
|
|
133
137
|
canCreateRelated = true;
|
|
134
138
|
}
|
|
139
|
+
// The create form of a model declared to belong to a layout context
|
|
140
|
+
// the user may not enter answers 403
|
|
141
|
+
if (canCreateRelated && relatedModel && await isBlockedLink(req.adminizer, req.user, `${req.adminizer.config.routePrefix}/model/${relatedModel}/add`)) {
|
|
142
|
+
canCreateRelated = false;
|
|
143
|
+
}
|
|
135
144
|
}
|
|
136
145
|
if (type === 'select-many') {
|
|
137
146
|
fieldType = 'select-many';
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { Adminizer } from "../lib/Adminizer.js";
|
|
2
2
|
import { NavbarSectionConfig } from "../interfaces/adminpanelConfig.js";
|
|
3
3
|
import { MenuItem } from "./menuHelper.js";
|
|
4
|
+
import type { AdminContext } from "../lib/app-manager/ContextHandler.js";
|
|
4
5
|
export declare class InertiaMenuHelper {
|
|
5
6
|
private adminizer;
|
|
6
7
|
constructor(adminizer: Adminizer);
|
|
7
|
-
getMenuItems(req: ReqType): Promise<MenuItem[]>;
|
|
8
|
+
getMenuItems(req: ReqType, context?: AdminContext): Promise<MenuItem[]>;
|
|
8
9
|
private translateMenuItem;
|
|
9
10
|
private translateHrefItem;
|
|
10
11
|
/**
|
|
11
12
|
* Navbar section metadata keyed by the *translated* section name, so the UI
|
|
12
13
|
* can look it up with the already-translated `section` of a menu item.
|
|
13
14
|
*/
|
|
14
|
-
getSections(req: ReqType): Record<string, NavbarSectionConfig>;
|
|
15
|
+
getSections(req: ReqType, context?: AdminContext): Record<string, NavbarSectionConfig>;
|
|
15
16
|
getBrandTitle(): string;
|
|
16
17
|
getLogoutUrl(): string;
|
|
17
18
|
}
|
|
@@ -4,8 +4,11 @@ export class InertiaMenuHelper {
|
|
|
4
4
|
constructor(adminizer) {
|
|
5
5
|
this.adminizer = adminizer;
|
|
6
6
|
}
|
|
7
|
-
async getMenuItems(req) {
|
|
8
|
-
|
|
7
|
+
async getMenuItems(req, context) {
|
|
8
|
+
const items = context
|
|
9
|
+
? await this.adminizer.contextHandler.listMenuItems(context, req.user)
|
|
10
|
+
: await listAccessibleMenuItems(this.adminizer, req.user);
|
|
11
|
+
return items
|
|
9
12
|
.map((menuItem) => this.translateMenuItem(req, menuItem));
|
|
10
13
|
}
|
|
11
14
|
translateMenuItem(req, menuItem) {
|
|
@@ -28,8 +31,10 @@ export class InertiaMenuHelper {
|
|
|
28
31
|
* Navbar section metadata keyed by the *translated* section name, so the UI
|
|
29
32
|
* can look it up with the already-translated `section` of a menu item.
|
|
30
33
|
*/
|
|
31
|
-
getSections(req) {
|
|
32
|
-
const sections =
|
|
34
|
+
getSections(req, context) {
|
|
35
|
+
const sections = context
|
|
36
|
+
? this.adminizer.contextHandler.getSections(context)
|
|
37
|
+
: this.adminizer.menuHelper.getSections();
|
|
33
38
|
return Object.fromEntries(Object.entries(sections).map(([name, section]) => [req.i18n.__(name), section]));
|
|
34
39
|
}
|
|
35
40
|
getBrandTitle() {
|
|
@@ -2,6 +2,11 @@ import type { HrefConfig, MenuBadge } from '../interfaces/adminpanelConfig.js';
|
|
|
2
2
|
import { Adminizer } from '../lib/Adminizer.js';
|
|
3
3
|
import type { User } from '../models/User.js';
|
|
4
4
|
import type { MenuItem } from './menuHelper.js';
|
|
5
|
+
/**
|
|
6
|
+
* True for a link to a page of a layout context this user may not enter
|
|
7
|
+
* (`context` of a model or a route): the page would answer 403.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isBlockedLink(adminizer: Adminizer, user: User | undefined, link: unknown): Promise<boolean>;
|
|
5
10
|
/** Drops the sub-items this user may not open, recursively. */
|
|
6
11
|
export declare function filterAccessibleHrefItems(adminizer: Adminizer, user: User, items: HrefConfig[]): Promise<HrefConfig[]>;
|
|
7
12
|
/**
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { Adminizer } from '../lib/Adminizer.js';
|
|
2
|
+
/**
|
|
3
|
+
* True for a link to a page of a layout context this user may not enter
|
|
4
|
+
* (`context` of a model or a route): the page would answer 403.
|
|
5
|
+
*/
|
|
6
|
+
export async function isBlockedLink(adminizer, user, link) {
|
|
7
|
+
// Partial Adminizer stand-ins (tests) may come without contexts.
|
|
8
|
+
return typeof link === 'string' && !!adminizer.contextHandler && await adminizer.contextHandler.isBlocked(link, user);
|
|
9
|
+
}
|
|
2
10
|
/** Drops the sub-items this user may not open, recursively. */
|
|
3
11
|
export async function filterAccessibleHrefItems(adminizer, user, items) {
|
|
4
12
|
const accessible = [];
|
|
@@ -6,6 +14,9 @@ export async function filterAccessibleHrefItems(adminizer, user, items) {
|
|
|
6
14
|
if (item.accessRightsToken && !await adminizer.accessRightsHelper.checkPermission(item.accessRightsToken, user)) {
|
|
7
15
|
continue;
|
|
8
16
|
}
|
|
17
|
+
if (await isBlockedLink(adminizer, user, item.link)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
9
20
|
accessible.push({
|
|
10
21
|
...item,
|
|
11
22
|
subItems: item.subItems ? await filterAccessibleHrefItems(adminizer, user, item.subItems) : item.subItems,
|
|
@@ -39,6 +50,8 @@ export async function resolveMenuBadge(user, badge, itemId) {
|
|
|
39
50
|
export async function listAccessibleMenuItems(adminizer, user) {
|
|
40
51
|
const menu = [];
|
|
41
52
|
for (const menuItem of adminizer.menuHelper.getMenuItems(user)) {
|
|
53
|
+
if (await isBlockedLink(adminizer, user, menuItem.link))
|
|
54
|
+
continue;
|
|
42
55
|
const actions = await filterAccessibleHrefItems(adminizer, user, menuItem.actions ?? []);
|
|
43
56
|
const tokens = actions.map((item) => item.accessRightsToken).filter(Boolean);
|
|
44
57
|
if (menuItem.accessRightsToken)
|
package/index.d.ts
CHANGED
|
@@ -64,6 +64,7 @@ export * from "./lib/app-manager/AdminizerApp.js";
|
|
|
64
64
|
export * from "./lib/app-manager/AppManager.js";
|
|
65
65
|
export * from "./lib/app-manager/ControllerHandler.js";
|
|
66
66
|
export * from "./lib/app-manager/AssetHandler.js";
|
|
67
|
+
export * from "./lib/app-manager/ContextHandler.js";
|
|
67
68
|
export * from "./lib/app-manager/ConfigLayerHandler.js";
|
|
68
69
|
export * from "./lib/access-rights/AccessRightsHandler.js";
|
|
69
70
|
export * from "./lib/media-manager/helpers/MediaManagerHelper.js";
|
package/index.js
CHANGED
|
@@ -64,6 +64,7 @@ export * from "./lib/app-manager/AdminizerApp.js";
|
|
|
64
64
|
export * from "./lib/app-manager/AppManager.js";
|
|
65
65
|
export * from "./lib/app-manager/ControllerHandler.js";
|
|
66
66
|
export * from "./lib/app-manager/AssetHandler.js";
|
|
67
|
+
export * from "./lib/app-manager/ContextHandler.js";
|
|
67
68
|
export * from "./lib/app-manager/ConfigLayerHandler.js";
|
|
68
69
|
export * from "./lib/access-rights/AccessRightsHandler.js";
|
|
69
70
|
export * from "./lib/media-manager/helpers/MediaManagerHelper.js";
|
|
@@ -372,6 +372,13 @@ export interface ModelConfig {
|
|
|
372
372
|
*/
|
|
373
373
|
section?: string;
|
|
374
374
|
};
|
|
375
|
+
/**
|
|
376
|
+
* Id of the layout context the model's pages (`/model/<name>/...`) belong
|
|
377
|
+
* to: they render in that context, and users who may not enter it get 403
|
|
378
|
+
* on every one of them, related-record dialogs included (404 when no such
|
|
379
|
+
* context is registered). Left out, the pages behave as before.
|
|
380
|
+
*/
|
|
381
|
+
context?: string;
|
|
375
382
|
/**
|
|
376
383
|
* Model resource fields configuration
|
|
377
384
|
* */
|
package/lib/Adminizer.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { FeedbackHandler } from "./feedback/FeedbackHandler.js";
|
|
|
25
25
|
import { AppManager } from "./app-manager/AppManager.js";
|
|
26
26
|
import { ControllerHandler } from "./app-manager/ControllerHandler.js";
|
|
27
27
|
import { AssetHandler } from "./app-manager/AssetHandler.js";
|
|
28
|
+
import { ContextHandler } from "./app-manager/ContextHandler.js";
|
|
28
29
|
import { ConfigLayerHandler } from "./app-manager/ConfigLayerHandler.js";
|
|
29
30
|
import { AccessRightsHandler } from "./access-rights/AccessRightsHandler.js";
|
|
30
31
|
import { AiAssistantUiMethodHandler } from './ai-assistant/AiAssistantUiMethodHandler.js';
|
|
@@ -74,6 +75,7 @@ export declare class Adminizer {
|
|
|
74
75
|
appManager: AppManager;
|
|
75
76
|
controllerHandler: ControllerHandler;
|
|
76
77
|
assetHandler: AssetHandler;
|
|
78
|
+
contextHandler: ContextHandler;
|
|
77
79
|
configLayerHandler: ConfigLayerHandler;
|
|
78
80
|
accessRightsHandler: AccessRightsHandler;
|
|
79
81
|
jwtSecret: string;
|
package/lib/Adminizer.js
CHANGED
|
@@ -42,6 +42,7 @@ import { validateAccessGraph } from "./access-graph/AccessGraphResolver.js";
|
|
|
42
42
|
import { AppManager } from "./app-manager/AppManager.js";
|
|
43
43
|
import { ControllerHandler } from "./app-manager/ControllerHandler.js";
|
|
44
44
|
import { AssetHandler } from "./app-manager/AssetHandler.js";
|
|
45
|
+
import { ContextHandler } from "./app-manager/ContextHandler.js";
|
|
45
46
|
import { ConfigLayerHandler } from "./app-manager/ConfigLayerHandler.js";
|
|
46
47
|
import { AccessRightsHandler } from "./access-rights/AccessRightsHandler.js";
|
|
47
48
|
import { AiAssistantUiMethodHandler } from './ai-assistant/AiAssistantUiMethodHandler.js';
|
|
@@ -131,6 +132,7 @@ export class Adminizer {
|
|
|
131
132
|
appManager;
|
|
132
133
|
controllerHandler;
|
|
133
134
|
assetHandler;
|
|
135
|
+
contextHandler;
|
|
134
136
|
configLayerHandler;
|
|
135
137
|
accessRightsHandler;
|
|
136
138
|
// Constants
|
|
@@ -157,6 +159,7 @@ export class Adminizer {
|
|
|
157
159
|
this.documentationHandler = new DocumentationHandler(this, () => bindDocs(this));
|
|
158
160
|
this.controllerHandler = new ControllerHandler(this);
|
|
159
161
|
this.assetHandler = new AssetHandler(this);
|
|
162
|
+
this.contextHandler = new ContextHandler(this);
|
|
160
163
|
this.configLayerHandler = new ConfigLayerHandler(this);
|
|
161
164
|
this.appManager = new AppManager(this);
|
|
162
165
|
// Registering or unregistering a model changes what the record-access resolvers may
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { listAccessibleMenuItems } from '../../helpers/navigationAccessHelper.js';
|
|
1
|
+
import { isBlockedLink, listAccessibleMenuItems } from '../../helpers/navigationAccessHelper.js';
|
|
2
2
|
import { matchesPathPattern } from '../../helpers/pathPattern.js';
|
|
3
3
|
import { isModelHiddenInNavbar } from '../../helpers/menuHelper.js';
|
|
4
4
|
/** Segments no template may point at: opening one mutates data. */
|
|
@@ -43,6 +43,8 @@ export class AdminLinkHandler {
|
|
|
43
43
|
continue;
|
|
44
44
|
if (link.accessRightsToken && !await this.adminizer.accessRightsHelper.checkPermission(link.accessRightsToken, user))
|
|
45
45
|
continue;
|
|
46
|
+
if (await isBlockedLink(this.adminizer, user, link.link))
|
|
47
|
+
continue;
|
|
46
48
|
accessible.push(link);
|
|
47
49
|
}
|
|
48
50
|
return accessible;
|
|
@@ -88,6 +90,8 @@ export class AdminLinkHandler {
|
|
|
88
90
|
return;
|
|
89
91
|
if (template.accessRightsToken && !await this.adminizer.accessRightsHelper.checkPermission(template.accessRightsToken, user))
|
|
90
92
|
return;
|
|
93
|
+
if (await isBlockedLink(this.adminizer, user, template.template))
|
|
94
|
+
return;
|
|
91
95
|
if (templates.some((existing) => existing.template === template.template || existing.id === template.id))
|
|
92
96
|
return;
|
|
93
97
|
templates.push(template);
|
|
@@ -11,6 +11,7 @@ import type { AbstractAiModelService } from "../ai-assistant/AbstractAiModelServ
|
|
|
11
11
|
import type { AiAssistantUiMethod } from '../ai-assistant/AiAssistantUiMethodHandler.js';
|
|
12
12
|
import type { AdminLink, AdminLinkTemplate } from '../admin-links/AdminLinkHandler.js';
|
|
13
13
|
import type { AiAssistantAgentSkill } from '../ai-assistant/AiAssistantAgentSkillHandler.js';
|
|
14
|
+
import type { AdminContext, AdminContextScope } from './ContextHandler.js';
|
|
14
15
|
export type AppDisposer = () => void | Promise<void>;
|
|
15
16
|
export type AppEventName = string | symbol;
|
|
16
17
|
export type AppEventHandler<TPayload = any> = (payload: TPayload, runtime: AppRuntime) => void | Promise<void>;
|
|
@@ -49,6 +50,12 @@ export interface AppController {
|
|
|
49
50
|
method: AppControllerMethod;
|
|
50
51
|
middleware: MiddlewareType;
|
|
51
52
|
policies?: AppControllerPolicy[];
|
|
53
|
+
/**
|
|
54
|
+
* Id of the layout context the route belongs to: it renders in that
|
|
55
|
+
* context, and users who may not enter it get 403 (404 when no such
|
|
56
|
+
* context is registered). Left out, the route behaves as before.
|
|
57
|
+
*/
|
|
58
|
+
context?: string;
|
|
52
59
|
}
|
|
53
60
|
export interface AppAsset {
|
|
54
61
|
id: string;
|
|
@@ -209,6 +216,28 @@ export interface AppSkills {
|
|
|
209
216
|
}
|
|
210
217
|
export interface AppAdminLinkResource extends AdminLink {
|
|
211
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* A layout context owned by an app. Unlike {@link AdminContext}, layout
|
|
221
|
+
* modules are given as app assets; they are served and disposed with the app.
|
|
222
|
+
*/
|
|
223
|
+
export interface AppContextResource extends Omit<AdminContext, "layout"> {
|
|
224
|
+
layout?: "inherit" | "stock" | "none" | "default" | "bare" | {
|
|
225
|
+
module: AppAsset;
|
|
226
|
+
stylesheet?: AppAsset;
|
|
227
|
+
base?: "inherit" | "stock";
|
|
228
|
+
} | {
|
|
229
|
+
overrides: AppAsset;
|
|
230
|
+
stylesheet?: AppAsset;
|
|
231
|
+
} | {
|
|
232
|
+
component: AppAsset;
|
|
233
|
+
stylesheet?: AppAsset;
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* A context registered by an app. Pages may give their component as an app
|
|
238
|
+
* asset; pages and routes are removed together with the app.
|
|
239
|
+
*/
|
|
240
|
+
export type AppContextScope = AdminContextScope<AppAsset | string>;
|
|
212
241
|
export interface AppAdminLinkTemplateResource extends AdminLinkTemplate {
|
|
213
242
|
}
|
|
214
243
|
/**
|
|
@@ -236,6 +265,11 @@ export interface AppSetupContext {
|
|
|
236
265
|
adminLink(link: AppAdminLinkResource): void;
|
|
237
266
|
/** Register a parametrized page (e.g. `/admin/orders/:id/invoice`) the assistant may open. */
|
|
238
267
|
adminLinkTemplate(template: AppAdminLinkTemplateResource): void;
|
|
268
|
+
/**
|
|
269
|
+
* Register a layout context: own URL prefix, navbar and, optionally,
|
|
270
|
+
* layout. The returned scope adds pages to it.
|
|
271
|
+
*/
|
|
272
|
+
context(context: AppContextResource): AppContextScope;
|
|
239
273
|
listener(event: AppEventName, handler: AppEventHandler): void;
|
|
240
274
|
}
|
|
241
275
|
/**
|
|
@@ -14,6 +14,8 @@ class RuntimeAppSetupContext {
|
|
|
14
14
|
pendingCatalogRegistrations = [];
|
|
15
15
|
configLayerIndex = 0;
|
|
16
16
|
modelAccessIndex = 0;
|
|
17
|
+
/** Asset URLs of context page components, by asset id. */
|
|
18
|
+
pageComponents = new Map();
|
|
17
19
|
constructor(adminizer, appName) {
|
|
18
20
|
this.adminizer = adminizer;
|
|
19
21
|
this.appName = appName;
|
|
@@ -148,6 +150,39 @@ class RuntimeAppSetupContext {
|
|
|
148
150
|
this.adminizer.adminLinkHandler.removeTemplate(resourceId, this.appName);
|
|
149
151
|
});
|
|
150
152
|
}
|
|
153
|
+
context(resource) {
|
|
154
|
+
const source = resource.layout;
|
|
155
|
+
let layout;
|
|
156
|
+
if (typeof source !== "object") {
|
|
157
|
+
layout = source;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
const stylesheet = source.stylesheet ? this.asset(source.stylesheet) : undefined;
|
|
161
|
+
if ("component" in source)
|
|
162
|
+
layout = { component: this.asset(source.component), stylesheet };
|
|
163
|
+
else if ("overrides" in source)
|
|
164
|
+
layout = { overrides: this.asset(source.overrides), stylesheet };
|
|
165
|
+
else
|
|
166
|
+
layout = { module: this.asset(source.module), stylesheet, base: source.base };
|
|
167
|
+
}
|
|
168
|
+
const { id } = this.adminizer.contextHandler.register({ ...resource, layout }, this.appName);
|
|
169
|
+
this.disposers.push(() => this.adminizer.contextHandler.unregister(id, this.appName));
|
|
170
|
+
// Pages go through this context: their routes and assets are the app's.
|
|
171
|
+
return this.adminizer.contextHandler.scope(id, {
|
|
172
|
+
controller: (controller) => this.controller(controller),
|
|
173
|
+
component: (component) => {
|
|
174
|
+
if (typeof component === "string")
|
|
175
|
+
return component;
|
|
176
|
+
// One asset however many pages, of however many contexts, render it.
|
|
177
|
+
let url = this.pageComponents.get(component.id);
|
|
178
|
+
if (!url) {
|
|
179
|
+
url = this.asset(component);
|
|
180
|
+
this.pageComponents.set(component.id, url);
|
|
181
|
+
}
|
|
182
|
+
return url;
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
}
|
|
151
186
|
listener(event, handler) {
|
|
152
187
|
const resourceId = `${this.appName}:${event.toString()}:${this.disposers.length + 1}`;
|
|
153
188
|
const listener = (payload) => handler(payload, this.adminizer.appManager.createRuntime(this.appName));
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { Adminizer } from "../Adminizer.js";
|
|
2
|
+
import type { HrefConfig, NavbarSectionConfig } from "../../interfaces/adminpanelConfig.js";
|
|
3
|
+
import type { User } from "../../models/User.js";
|
|
4
|
+
import type { MenuItem } from "../../helpers/menuHelper.js";
|
|
5
|
+
import type { AppController, AppControllerMethod, AppControllerPolicy } from "./AdminizerApp.js";
|
|
6
|
+
export declare const DEFAULT_ADMIN_CONTEXT_ID = "default";
|
|
7
|
+
/**
|
|
8
|
+
* Shell of a context.
|
|
9
|
+
* - `inherit` — the layout of the default context (the stock one for the
|
|
10
|
+
* default context itself);
|
|
11
|
+
* - `stock` — the stock sidebar + header, without any override;
|
|
12
|
+
* - `none` — no shell at all, the page fills the window;
|
|
13
|
+
* - `{module}` — URL of an ES module whose named exports ({@link ShellSlotName})
|
|
14
|
+
* replace parts of the inherited layout; each receives the replaced part as
|
|
15
|
+
* `Default`. The `Layout` export replaces the whole layout. `base: "stock"`
|
|
16
|
+
* applies the module over the stock layout instead of the inherited one.
|
|
17
|
+
*
|
|
18
|
+
* Kept for compatibility: `default` is `stock`, `bare` is `none`,
|
|
19
|
+
* `{overrides}` is `{module}`, and `{component}` is a module whose default
|
|
20
|
+
* export is the whole layout, applied over the stock layout.
|
|
21
|
+
*/
|
|
22
|
+
export type AdminContextLayout = "inherit" | "stock" | "none" | {
|
|
23
|
+
module: string;
|
|
24
|
+
stylesheet?: string;
|
|
25
|
+
base?: "inherit" | "stock";
|
|
26
|
+
} | "default" | "bare" | {
|
|
27
|
+
overrides: string;
|
|
28
|
+
stylesheet?: string;
|
|
29
|
+
} | {
|
|
30
|
+
component: string;
|
|
31
|
+
stylesheet?: string;
|
|
32
|
+
};
|
|
33
|
+
/** Parts of the stock layout a context may override; `Layout` is the whole of it. */
|
|
34
|
+
export type ShellSlotName = "Layout" | "Sidebar" | "SidebarHeader" | "SidebarContent" | "SidebarFooter" | "Header" | "HeaderStart" | "HeaderActions";
|
|
35
|
+
export interface AdminContextNavbar {
|
|
36
|
+
/** Items of the context's own menu; `page()` and `menuItem()` append to them. */
|
|
37
|
+
items?: HrefConfig[];
|
|
38
|
+
sections?: Record<string, NavbarSectionConfig>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A layout context: a part of the panel living under its own URL prefix
|
|
42
|
+
* with its own navbar and, optionally, its own layout.
|
|
43
|
+
*/
|
|
44
|
+
export interface AdminContext {
|
|
45
|
+
id: string;
|
|
46
|
+
title: string;
|
|
47
|
+
icon?: string;
|
|
48
|
+
/** Path below `routePrefix`, e.g. `/support`. Every URL under it belongs to the context. */
|
|
49
|
+
prefix: string;
|
|
50
|
+
/** Where the switcher leads; defaults to the prefix itself. A path below `routePrefix`. */
|
|
51
|
+
home?: string;
|
|
52
|
+
/** @default "inherit" */
|
|
53
|
+
layout?: AdminContextLayout;
|
|
54
|
+
/**
|
|
55
|
+
* `inherit` shows the menu of the default context. Left out, the menu is
|
|
56
|
+
* inherited as well until `page()` or `menuItem()` adds an item to it.
|
|
57
|
+
*/
|
|
58
|
+
navbar?: "inherit" | AdminContextNavbar;
|
|
59
|
+
/**
|
|
60
|
+
* Users lacking the token neither see the context in the switcher nor get
|
|
61
|
+
* its shell, and may not open the pages declared to belong to it.
|
|
62
|
+
*/
|
|
63
|
+
accessRightsToken?: string;
|
|
64
|
+
/** Show in the context switcher. @default true */
|
|
65
|
+
switcher?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/** What may be changed about the built-in context mounted at `routePrefix`. */
|
|
68
|
+
export type DefaultAdminContextOptions = Partial<Pick<AdminContext, "title" | "icon" | "layout" | "navbar" | "switcher" | "home">>;
|
|
69
|
+
/** A page of a context: a route under its prefix, a menu item and breadcrumbs in one call. */
|
|
70
|
+
export interface AdminContextPage<Component = string> {
|
|
71
|
+
/** Unique within the context; also the id of the menu item. */
|
|
72
|
+
id: string;
|
|
73
|
+
/** Path below the context prefix; `""` is the prefix itself. */
|
|
74
|
+
path: string;
|
|
75
|
+
title: string;
|
|
76
|
+
icon?: string;
|
|
77
|
+
/** ES module whose default export renders the page; it receives `props`. */
|
|
78
|
+
component?: Component;
|
|
79
|
+
/** Props of `component`: values, or a function computing them per request. */
|
|
80
|
+
props?: Record<string, unknown> | ((req: ReqType) => Record<string, unknown> | Promise<Record<string, unknown>>);
|
|
81
|
+
/** A handler of its own instead of `component`. */
|
|
82
|
+
middleware?: MiddlewareType;
|
|
83
|
+
/** @default "get" */
|
|
84
|
+
method?: AppControllerMethod;
|
|
85
|
+
/** @default `auth`. The context token is checked for every page of the context anyway. */
|
|
86
|
+
policies?: AppControllerPolicy[];
|
|
87
|
+
/** Add a menu item. @default true, false when the context's navbar is `"inherit"` */
|
|
88
|
+
menu?: boolean;
|
|
89
|
+
section?: string;
|
|
90
|
+
badge?: HrefConfig["badge"];
|
|
91
|
+
accessRightsToken?: string;
|
|
92
|
+
}
|
|
93
|
+
/** A route under the context prefix without a menu item, e.g. an API of the context. */
|
|
94
|
+
export interface AdminContextController extends Omit<AppController, "route" | "policies" | "context"> {
|
|
95
|
+
/** Path below the context prefix. */
|
|
96
|
+
path: string;
|
|
97
|
+
/** @default `auth`. The context token is checked anyway. */
|
|
98
|
+
policies?: AppControllerPolicy[];
|
|
99
|
+
}
|
|
100
|
+
/** A registered context: adds pages, routes and menu items to it. */
|
|
101
|
+
export interface AdminContextScope<Component = string> {
|
|
102
|
+
readonly id: string;
|
|
103
|
+
/** Registers a page under the context prefix and returns its menu item. */
|
|
104
|
+
page(page: AdminContextPage<Component>): HrefConfig;
|
|
105
|
+
/** Registers a route under the context prefix and returns its full path. */
|
|
106
|
+
controller(controller: AdminContextController): string;
|
|
107
|
+
/** Appends an item to the context's own menu. */
|
|
108
|
+
menuItem(item: HrefConfig): void;
|
|
109
|
+
}
|
|
110
|
+
/** How a scope registers what its pages need: the host's handlers or an app's setup context. */
|
|
111
|
+
export interface AdminContextRegistrar<Component = string> {
|
|
112
|
+
controller(controller: AppController): string;
|
|
113
|
+
/** Turns a page component into the URL of its module. */
|
|
114
|
+
component(component: Component): string;
|
|
115
|
+
}
|
|
116
|
+
/** Context description as the browser receives it. */
|
|
117
|
+
export interface AdminContextProps {
|
|
118
|
+
id: string;
|
|
119
|
+
title: string;
|
|
120
|
+
icon: string | null;
|
|
121
|
+
/** Full URL prefix of the context, `routePrefix` included. */
|
|
122
|
+
prefix: string;
|
|
123
|
+
link: string;
|
|
124
|
+
layout: AdminContextLayoutProps;
|
|
125
|
+
}
|
|
126
|
+
/** A module of the layout chain. */
|
|
127
|
+
export interface AdminContextLayerProps {
|
|
128
|
+
/** URL of the ES module; its named exports are slot overrides. */
|
|
129
|
+
module: string;
|
|
130
|
+
/** `Layout`: the default export is the whole layout (`{component}`). */
|
|
131
|
+
default?: "Layout";
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Resolved layout: the layers applied in order over the root, the default
|
|
135
|
+
* context's ones first.
|
|
136
|
+
*/
|
|
137
|
+
export interface AdminContextLayoutProps {
|
|
138
|
+
/** What the layers are applied over: the stock shell or nothing at all. */
|
|
139
|
+
root: "stock" | "none";
|
|
140
|
+
layers: AdminContextLayerProps[];
|
|
141
|
+
stylesheets: string[];
|
|
142
|
+
}
|
|
143
|
+
/** Registry of layout contexts contributed by the host and by apps. */
|
|
144
|
+
export declare class ContextHandler {
|
|
145
|
+
private readonly adminizer;
|
|
146
|
+
private readonly contexts;
|
|
147
|
+
private readonly assignments;
|
|
148
|
+
private readonly reportedMissing;
|
|
149
|
+
private defaultOptions;
|
|
150
|
+
constructor(adminizer: Adminizer);
|
|
151
|
+
/**
|
|
152
|
+
* Registers a context. The returned scope adds pages to it; they are
|
|
153
|
+
* registered as `owner`'s controllers.
|
|
154
|
+
*/
|
|
155
|
+
register(context: AdminContext, owner?: string): AdminContextScope;
|
|
156
|
+
unregister(id: string, owner?: string): void;
|
|
157
|
+
/** A scope adding pages to a registered context through the given registrar. */
|
|
158
|
+
scope<Component>(id: string, registrar: AdminContextRegistrar<Component>): AdminContextScope<Component>;
|
|
159
|
+
/** Overrides title, icon, layout or navbar of the built-in context. */
|
|
160
|
+
configureDefault(options: DefaultAdminContextOptions): void;
|
|
161
|
+
getDefault(): AdminContext;
|
|
162
|
+
get(id: string): AdminContext | undefined;
|
|
163
|
+
list(): AdminContext[];
|
|
164
|
+
/** Contexts this user may enter, the default one first. */
|
|
165
|
+
listAccessible(user: User): Promise<AdminContext[]>;
|
|
166
|
+
/**
|
|
167
|
+
* Declares that the pages at `path` (below `routePrefix`, `:params`
|
|
168
|
+
* allowed) belong to a context: they render in it wherever the user came
|
|
169
|
+
* from, and only users who may enter the context may open them. Covers
|
|
170
|
+
* everything below `path` too unless `exact`. Returns a function removing
|
|
171
|
+
* the declaration.
|
|
172
|
+
*/
|
|
173
|
+
assign(path: string, contextId: string, options?: {
|
|
174
|
+
owner?: string;
|
|
175
|
+
exact?: boolean;
|
|
176
|
+
}): () => void;
|
|
177
|
+
/**
|
|
178
|
+
* The context the page at `url` is declared to belong to: by `assign()`,
|
|
179
|
+
* a controller's `context` or a model's `context`. The most specific
|
|
180
|
+
* declaration wins. Login, logout, registration and the first-user setup
|
|
181
|
+
* never belong to a context.
|
|
182
|
+
*/
|
|
183
|
+
declaredFor(url: string): string | undefined;
|
|
184
|
+
/** True when the page at `url` belongs to a context this user may not enter. */
|
|
185
|
+
isBlocked(url: string, user: User | undefined): Promise<boolean>;
|
|
186
|
+
/**
|
|
187
|
+
* Blocks the pages declared to belong to a context the user may not
|
|
188
|
+
* enter, before any handler and for every method: not logged in — the
|
|
189
|
+
* login page (401 for API calls), no context token — 403, a context that
|
|
190
|
+
* is not registered (a typo, a disabled app) — 404. Pages without a
|
|
191
|
+
* declaration pass untouched.
|
|
192
|
+
*/
|
|
193
|
+
guard(): MiddlewareType;
|
|
194
|
+
/**
|
|
195
|
+
* The context a request belongs to.
|
|
196
|
+
*
|
|
197
|
+
* A page declared to belong to a context renders in it. A URL under a
|
|
198
|
+
* context prefix belongs to that context. Any other URL (the built-in
|
|
199
|
+
* `/model/...` pages, for one) stays in the context the user came from —
|
|
200
|
+
* remembered in a cookie — as long as that context's navbar links to it;
|
|
201
|
+
* otherwise it falls back to the default context.
|
|
202
|
+
*/
|
|
203
|
+
resolve(req: ReqType): Promise<AdminContext>;
|
|
204
|
+
/** Remembers the context of a page visit; see {@link resolve}. */
|
|
205
|
+
remember(req: ReqType, res: ResType, context: AdminContext): void;
|
|
206
|
+
/** The untranslated menu of a context for this user. */
|
|
207
|
+
listMenuItems(context: AdminContext, user: User): Promise<MenuItem[]>;
|
|
208
|
+
getSections(context: AdminContext): Record<string, NavbarSectionConfig>;
|
|
209
|
+
/**
|
|
210
|
+
* The layout of a context with inheritance from the default context
|
|
211
|
+
* applied. Layers always add up along the chain: a module over a parent
|
|
212
|
+
* keeps the parent's layers, whatever they replace.
|
|
213
|
+
*/
|
|
214
|
+
resolveLayout(context: AdminContext): AdminContextLayoutProps;
|
|
215
|
+
toProps(context: AdminContext): AdminContextProps;
|
|
216
|
+
private addPage;
|
|
217
|
+
private addController;
|
|
218
|
+
private addMenuItem;
|
|
219
|
+
/** Renders a `component` page: the module page with context breadcrumbs. */
|
|
220
|
+
private renderPage;
|
|
221
|
+
private require;
|
|
222
|
+
private isAccessible;
|
|
223
|
+
private claims;
|
|
224
|
+
/** A model page `/model/<name>/...` of a model whose config declares a context. */
|
|
225
|
+
private modelDeclaration;
|
|
226
|
+
/** Model config by resource name, matched the way the model routes match it. */
|
|
227
|
+
private findModelConfig;
|
|
228
|
+
private isAuthPath;
|
|
229
|
+
/** A route pattern as a regexp: `:param`, `*splat` and `{optional}` parts of Express routes. */
|
|
230
|
+
private compilePattern;
|
|
231
|
+
/** Static segments weigh more than parameters. */
|
|
232
|
+
private specificity;
|
|
233
|
+
private isPageRequest;
|
|
234
|
+
private root;
|
|
235
|
+
private fullPrefix;
|
|
236
|
+
private normalizePrefix;
|
|
237
|
+
private normalizePath;
|
|
238
|
+
private requestPath;
|
|
239
|
+
private readCookie;
|
|
240
|
+
}
|