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.
Files changed (113) hide show
  1. package/assets/{abnfDiagram-VCTEODGH-CpSXY7qH.js → abnfDiagram-VCTEODGH-BhZn7BLv.js} +1 -1
  2. package/assets/{add-DQWffo5j.js → add-DDfJt70P.js} +1 -1
  3. package/assets/{add-group-OdAd30ej.js → add-group-Cs3S9VVn.js} +1 -1
  4. package/assets/{add-user-C6cqZSzp.js → add-user-DxI_sJLw.js} +1 -1
  5. package/assets/ai-assistant/agent.es.js +14201 -11686
  6. package/assets/app-DM8KzeFz.css +1 -0
  7. package/assets/app-DOMFUTFw.js +138 -0
  8. package/assets/{arc-6oG0N2EU.js → arc-BRY7wCfa.js} +1 -1
  9. package/assets/{architectureDiagram-5GKGNRK7-BO5E3Osk.js → architectureDiagram-5GKGNRK7-DfBT7jAW.js} +1 -1
  10. package/assets/{blockDiagram-I7D4REHJ-DpKAEeRQ.js → blockDiagram-I7D4REHJ-CW2mcR7Z.js} +1 -1
  11. package/assets/{c4Diagram-7LVT6UL2-K4ilHoqv.js → c4Diagram-7LVT6UL2-BGsyO-4Y.js} +1 -1
  12. package/assets/{catalog-BaSowP5U.js → catalog-cyCZOCXs.js} +3 -3
  13. package/assets/channel-Bd-bsjgh.js +1 -0
  14. package/assets/{chunk-2Q5K7J3B-CFvbnPgN.js → chunk-2Q5K7J3B-4EnjsYhG.js} +1 -1
  15. package/assets/{chunk-5VM5RSS4-Cxb3_K7a.js → chunk-5VM5RSS4-BVzmz0IS.js} +1 -1
  16. package/assets/{chunk-F27PBJKO-Bp-e-RqW.js → chunk-F27PBJKO-Bkf9Z4lt.js} +1 -1
  17. package/assets/{chunk-IMKFNOWR-D03Bbv3p.js → chunk-IMKFNOWR-Dg6Y3xGC.js} +1 -1
  18. package/assets/{chunk-JWPE2WC7-BQzIFXbt.js → chunk-JWPE2WC7-BdVNpqE2.js} +1 -1
  19. package/assets/{chunk-POPQ4Y6H-DGPhwQEk.js → chunk-POPQ4Y6H-0R-etdBM.js} +1 -1
  20. package/assets/{chunk-SVP7TREG-CFG2uzdK.js → chunk-SVP7TREG-CdABJwLU.js} +1 -1
  21. package/assets/{chunk-TICWLB2K-BRoATx6O.js → chunk-TICWLB2K-Da-oSw37.js} +1 -1
  22. package/assets/{chunk-XXDRQBXY-MTSPV1jX.js → chunk-XXDRQBXY-Ba8BsH2Z.js} +1 -1
  23. package/assets/classDiagram-ZZMXUADV-BftNBmvr.js +1 -0
  24. package/assets/classDiagram-v2-VYDZK3BY-BftNBmvr.js +1 -0
  25. package/assets/controls/ckeditor.es.js +10659 -10551
  26. package/assets/controls/handsontable.es.js +9053 -8479
  27. package/assets/controls/jsoneditor.es.js +479 -449
  28. package/assets/controls/leaflet.es.js +672 -663
  29. package/assets/controls/toast-ui.es.js +13696 -13676
  30. package/assets/{cose-bilkent-JH36ORCC-Cd04LiHO.js → cose-bilkent-JH36ORCC-BYrWDdVx.js} +1 -1
  31. package/assets/{cynefin-OW5HDTMX-Cvk-t4EK.js → cynefin-OW5HDTMX-CwHzXvDB.js} +1 -1
  32. package/assets/{cynefinDiagram-5FMLGOSQ-CHBsEINZ.js → cynefinDiagram-5FMLGOSQ-V6tH6arn.js} +1 -1
  33. package/assets/{dagre-GXQ25YYZ-Dq-0d5Tl.js → dagre-GXQ25YYZ-CaBvafdG.js} +1 -1
  34. package/assets/{dashboard-BZo6F7y9.js → dashboard-C27hB1GI.js} +1 -1
  35. package/assets/{diagram-S7CK7UJ4-BKDTPndI.js → diagram-S7CK7UJ4-85jkE9hd.js} +1 -1
  36. package/assets/{diagram-UQ7AKVKN-DZYq9mm9.js → diagram-UQ7AKVKN-DHJRq1TM.js} +1 -1
  37. package/assets/{diagram-VSXAHHWV-CVOsZwCq.js → diagram-VSXAHHWV-C74VLfSc.js} +1 -1
  38. package/assets/{diagram-VX7I27RA-BCBXgENw.js → diagram-VX7I27RA-CVJcG5hn.js} +1 -1
  39. package/assets/{diagram-Z3DM3KII-ByNHDStX.js → diagram-Z3DM3KII-B8ybg5RA.js} +1 -1
  40. package/assets/{docs-CDmOUM3P.js → docs-CK6W0Jko.js} +1 -1
  41. package/assets/{ebnfDiagram-PWID7BFC-WrVgmCqC.js → ebnfDiagram-PWID7BFC-D_gz_iz6.js} +1 -1
  42. package/assets/{erDiagram-RLTQ6QDP-1QXTF1US.js → erDiagram-RLTQ6QDP-D3W95aGH.js} +1 -1
  43. package/assets/{flowDiagram-HODETNUW-DWcydZT-.js → flowDiagram-HODETNUW-D2PTWIEg.js} +1 -1
  44. package/assets/{ganttDiagram-EL5Y4UJY-BDrQ3uCR.js → ganttDiagram-EL5Y4UJY-TFBUh0C6.js} +1 -1
  45. package/assets/{gitGraphDiagram-WWUBYQGX-oD2bpMWh.js → gitGraphDiagram-WWUBYQGX-BfFJzeqx.js} +1 -1
  46. package/assets/{history-CTbCqtJA.js → history-DX6CEQqv.js} +1 -1
  47. package/assets/{infoDiagram-27XIBGKW-C8opSvmW.js → infoDiagram-27XIBGKW-esGmrWiw.js} +1 -1
  48. package/assets/{init-user-DDmp5FmX.js → init-user-D1G_dbcZ.js} +1 -1
  49. package/assets/{ishikawaDiagram-5VMMS53U-CqOCcw38.js → ishikawaDiagram-5VMMS53U--aGHPnva.js} +1 -1
  50. package/assets/{journeyDiagram-3NMN7TZE-B1OlZWx5.js → journeyDiagram-3NMN7TZE-03BXeE8O.js} +1 -1
  51. package/assets/{kanban-definition-UXKFOSKX-DIEdmOZD.js → kanban-definition-UXKFOSKX-JdDv2WHg.js} +1 -1
  52. package/assets/{layout-Cznoi1Xi.js → layout-Bz6WKClu.js} +1 -1
  53. package/assets/{linear-DbhwLrTs.js → linear-Chzx_9mb.js} +1 -1
  54. package/assets/{list-X8LYs75t.js → list-BuSdZ2Ic.js} +1 -1
  55. package/assets/{login-D0flIAhA.js → login-DFWfnrmE.js} +1 -1
  56. package/assets/manifest.json +277 -277
  57. package/assets/media-manager-CT4LZgo_.js +7 -0
  58. package/assets/mermaid.core-Dp-0i8FJ.js +310 -0
  59. package/assets/{mindmap-definition-YA3MSWOX-G8OJl_uT.js → mindmap-definition-YA3MSWOX-BJSEYobY.js} +1 -1
  60. package/assets/{module-D347sEFr.js → module-Cgn-q5gZ.js} +1 -1
  61. package/assets/{notification-C7usJcF-.js → notification-BrfoqVVT.js} +1 -1
  62. package/assets/{pegDiagram-XKGWAZYB-CqOymfUM.js → pegDiagram-XKGWAZYB-ccVsKwl1.js} +1 -1
  63. package/assets/{pieDiagram-E7YTZNPT-C_nbNUey.js → pieDiagram-E7YTZNPT-B1XZVgNq.js} +1 -1
  64. package/assets/{quadrantDiagram-AXDQQJYC-RDCWL_jp.js → quadrantDiagram-AXDQQJYC-CdABEYmF.js} +1 -1
  65. package/assets/{railroadDiagram-O6MQD6OU-Bi_j7Fb_.js → railroadDiagram-O6MQD6OU-OX83MXuO.js} +1 -1
  66. package/assets/{register-DhdaEsna.js → register-Cxf3Pow-.js} +1 -1
  67. package/assets/{requirementDiagram-BXWQKSXE-Cg6IzoFA.js → requirementDiagram-BXWQKSXE-CD7swf9u.js} +1 -1
  68. package/assets/{ru-DMAUOdKr.js → ru-DxiFV21N.js} +1 -1
  69. package/assets/{sankeyDiagram-P5KCCOFB-BNN3S4hm.js → sankeyDiagram-P5KCCOFB-Cgwq2DVJ.js} +1 -1
  70. package/assets/{sequenceDiagram-WJ2MYXX4-C9UEgNLg.js → sequenceDiagram-WJ2MYXX4-BgjP07Zh.js} +1 -1
  71. package/assets/{sizeCapture-INFHLROL-DH9gM8J8.js → sizeCapture-INFHLROL-B-jQ1aKT.js} +1 -1
  72. package/assets/{stateDiagram-D77RDMKH-CzuNaJnp.js → stateDiagram-D77RDMKH-Drot14NK.js} +1 -1
  73. package/assets/stateDiagram-v2-MP3YSRHH-C5VLF0H1.js +1 -0
  74. package/assets/{swimlanes-42K2YHIH-DlfHkCIp.js → swimlanes-42K2YHIH-lCqHhK1l.js} +1 -1
  75. package/assets/swimlanesDiagram-VR7AAH4N-4yyX1ZbA.js +8 -0
  76. package/assets/{timeline-definition-24CTP7MA-B45WKY9z.js → timeline-definition-24CTP7MA-B-QLcvwc.js} +1 -1
  77. package/assets/{use-appearance-DPeAg6kc.js → use-appearance-B0ck1CR_.js} +1 -1
  78. package/assets/{user-filters-list-B-txVF_a.js → user-filters-list-ce2cmS5Z.js} +1 -1
  79. package/assets/{vennDiagram-4TSXK5OY-BARlq8EX.js → vennDiagram-4TSXK5OY-2DN2uspP.js} +1 -1
  80. package/assets/{wardleyDiagram-VM6X3IG4-DSGKYXrr.js → wardleyDiagram-VM6X3IG4-C_GODc0p.js} +1 -1
  81. package/assets/{welcome-Cdhwf3y4.js → welcome-DaAj6jOI.js} +1 -1
  82. package/assets/with-app-layout-CwAECGwY.js +34 -0
  83. package/assets/{xychartDiagram-S5SC5T6Z-DPA8cj4H.js → xychartDiagram-S5SC5T6Z-Cq8htGoW.js} +1 -1
  84. package/controllers/initUser.js +1 -1
  85. package/helpers/inertiaAddHelper.js +10 -1
  86. package/helpers/inertiaMenuHelper.d.ts +3 -2
  87. package/helpers/inertiaMenuHelper.js +9 -4
  88. package/helpers/navigationAccessHelper.d.ts +5 -0
  89. package/helpers/navigationAccessHelper.js +13 -0
  90. package/index.d.ts +1 -0
  91. package/index.js +1 -0
  92. package/interfaces/adminpanelConfig.d.ts +7 -0
  93. package/lib/Adminizer.d.ts +2 -0
  94. package/lib/Adminizer.js +3 -0
  95. package/lib/admin-links/AdminLinkHandler.js +5 -1
  96. package/lib/app-manager/AdminizerApp.d.ts +34 -0
  97. package/lib/app-manager/AppManager.js +35 -0
  98. package/lib/app-manager/ContextHandler.d.ts +240 -0
  99. package/lib/app-manager/ContextHandler.js +446 -0
  100. package/lib/app-manager/ControllerHandler.d.ts +2 -0
  101. package/lib/app-manager/ControllerHandler.js +7 -0
  102. package/package.json +3 -2
  103. package/system/bindInertia.js +34 -9
  104. package/assets/app-DMN-4aCp.js +0 -138
  105. package/assets/app-TCCHARSx.css +0 -1
  106. package/assets/channel-Dh5UPZKs.js +0 -1
  107. package/assets/classDiagram-ZZMXUADV-a_pfQoRf.js +0 -1
  108. package/assets/classDiagram-v2-VYDZK3BY-a_pfQoRf.js +0 -1
  109. package/assets/media-manager-cyrZjDu3.js +0 -6
  110. package/assets/mermaid.core-DtG9mjld.js +0 -310
  111. package/assets/stateDiagram-v2-MP3YSRHH-Cm0oV4uL.js +0 -1
  112. package/assets/swimlanesDiagram-VR7AAH4N-Cc5GTkO2.js +0 -8
  113. 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-DtG9mjld.js";import{i as Di}from"./init-Gi6I4Gst.js";import{o as Pi}from"./ordinal-Cboi1Yqb.js";import{l as Nt}from"./linear-DbhwLrTs.js";import"./app-DMN-4aCp.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]&&lt[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)+`:
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]&&lt[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()+`
@@ -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.resolveModelName(rawRelatedModel)
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
- return (await listAccessibleMenuItems(this.adminizer, req.user))
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 = this.adminizer.menuHelper.getSections();
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
  * */
@@ -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
+ }