adminizer 5.1.0-build.26 → 5.1.0-build.28

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-BPk_d6eP.js → abnfDiagram-VCTEODGH-uWOVpoSR.js} +1 -1
  2. package/assets/add-A_fIlNKI.js +1 -0
  3. package/assets/{add-group-Dgnx2vMh.js → add-group-C2x6K3tV.js} +1 -1
  4. package/assets/{add-user-BfR1nhGQ.js → add-user-u61kYlEm.js} +1 -1
  5. package/assets/ai-assistant/agent.es.js +7894 -6950
  6. package/assets/app-CRa5Kokq.js +138 -0
  7. package/assets/app-TCCHARSx.css +1 -0
  8. package/assets/{arc-uDJSz8bh.js → arc--ZX64bmY.js} +1 -1
  9. package/assets/{architectureDiagram-5GKGNRK7-OIR43cRx.js → architectureDiagram-5GKGNRK7-W9AzLZvl.js} +1 -1
  10. package/assets/{blockDiagram-I7D4REHJ-h6ySQ0QE.js → blockDiagram-I7D4REHJ-BpK_yEa7.js} +1 -1
  11. package/assets/{c4Diagram-7LVT6UL2-DOT80T2g.js → c4Diagram-7LVT6UL2-DiQzU1s0.js} +1 -1
  12. package/assets/{catalog-B6ZGmhng.js → catalog-dSCv3Szm.js} +3 -3
  13. package/assets/channel-DRO88SVn.js +1 -0
  14. package/assets/{chunk-2Q5K7J3B-BoyYAiVR.js → chunk-2Q5K7J3B-GPHETbCq.js} +1 -1
  15. package/assets/{chunk-5VM5RSS4-B-ZfcfTz.js → chunk-5VM5RSS4-bLovkogd.js} +1 -1
  16. package/assets/{chunk-F27PBJKO-GsDMG_ue.js → chunk-F27PBJKO-DbkTY41z.js} +1 -1
  17. package/assets/{chunk-IMKFNOWR-zvoLOzaf.js → chunk-IMKFNOWR-CL0VAxX7.js} +1 -1
  18. package/assets/{chunk-JWPE2WC7-DYtJ3ly7.js → chunk-JWPE2WC7-d1Grk14b.js} +1 -1
  19. package/assets/{chunk-POPQ4Y6H-ChVoBm_0.js → chunk-POPQ4Y6H-CAUhiiNt.js} +1 -1
  20. package/assets/{chunk-SVP7TREG-BV0LTCGr.js → chunk-SVP7TREG-C8ADZUEr.js} +1 -1
  21. package/assets/{chunk-TICWLB2K-Dmp4mCPP.js → chunk-TICWLB2K-oRqFZabo.js} +1 -1
  22. package/assets/{chunk-XXDRQBXY-d7y3nWm0.js → chunk-XXDRQBXY-C3zo4c2P.js} +1 -1
  23. package/assets/classDiagram-ZZMXUADV-Cb-leHEm.js +1 -0
  24. package/assets/classDiagram-v2-VYDZK3BY-Cb-leHEm.js +1 -0
  25. package/assets/controls/ckeditor.es.js +265 -259
  26. package/assets/controls/jsoneditor.es.js +5921 -5896
  27. package/assets/controls/leaflet.es.js +29 -26
  28. package/assets/{cose-bilkent-JH36ORCC-DfL41_IE.js → cose-bilkent-JH36ORCC-ZPvVaI6n.js} +1 -1
  29. package/assets/{cynefin-OW5HDTMX-CdMB9V74.js → cynefin-OW5HDTMX-EEL4eqU7.js} +1 -1
  30. package/assets/{cynefinDiagram-5FMLGOSQ-B65Z6Wy5.js → cynefinDiagram-5FMLGOSQ-DpDFbbrn.js} +1 -1
  31. package/assets/{dagre-GXQ25YYZ-vs7dR1k0.js → dagre-GXQ25YYZ-Dtjy1xN1.js} +1 -1
  32. package/assets/{dashboard-gVK2jkxM.js → dashboard-DXs-vdJG.js} +2 -2
  33. package/assets/{diagram-S7CK7UJ4-BP2KlMF7.js → diagram-S7CK7UJ4-BhWisCOy.js} +1 -1
  34. package/assets/{diagram-UQ7AKVKN-DtBR3nL4.js → diagram-UQ7AKVKN-BBH2Mm33.js} +1 -1
  35. package/assets/{diagram-VSXAHHWV-DNqepAMp.js → diagram-VSXAHHWV-B1Xc2cPz.js} +1 -1
  36. package/assets/{diagram-VX7I27RA-B_qeXnMo.js → diagram-VX7I27RA-CTTYzy1s.js} +1 -1
  37. package/assets/{diagram-Z3DM3KII-Deat3YWi.js → diagram-Z3DM3KII-DdH0yWH0.js} +1 -1
  38. package/assets/{docs-CV8mkNUq.js → docs-BZYlfOON.js} +1 -1
  39. package/assets/{ebnfDiagram-PWID7BFC-C0qShrVz.js → ebnfDiagram-PWID7BFC-R9cSqf0y.js} +1 -1
  40. package/assets/{erDiagram-RLTQ6QDP-ByGzKaF4.js → erDiagram-RLTQ6QDP-Bpu-Pm95.js} +1 -1
  41. package/assets/{flowDiagram-HODETNUW-DP7cFly4.js → flowDiagram-HODETNUW-NdXf-fRN.js} +1 -1
  42. package/assets/{ganttDiagram-EL5Y4UJY-CxsNBze0.js → ganttDiagram-EL5Y4UJY-itQHv_dH.js} +1 -1
  43. package/assets/{gitGraphDiagram-WWUBYQGX-DAjOquZ3.js → gitGraphDiagram-WWUBYQGX-DorHK4Wx.js} +1 -1
  44. package/assets/{history-BjZubBIS.js → history-DB48MCa8.js} +1 -1
  45. package/assets/{infoDiagram-27XIBGKW-DAHcs_EB.js → infoDiagram-27XIBGKW-FgFATKk4.js} +1 -1
  46. package/assets/{init-user-Y2cS_Umn.js → init-user-DAXb55S_.js} +1 -1
  47. package/assets/{ishikawaDiagram-5VMMS53U-DG-NixrB.js → ishikawaDiagram-5VMMS53U-Bjl1a496.js} +1 -1
  48. package/assets/{journeyDiagram-3NMN7TZE-B3QkLsRE.js → journeyDiagram-3NMN7TZE-DU1TmnbI.js} +1 -1
  49. package/assets/{kanban-definition-UXKFOSKX-Co9SxVeD.js → kanban-definition-UXKFOSKX-BsrlKdcU.js} +1 -1
  50. package/assets/{layout-CcAsMdrw.js → layout-C68duuC7.js} +1 -1
  51. package/assets/{linear-p2QT3a1B.js → linear-DdadsTLS.js} +1 -1
  52. package/assets/{list-Bu_Q0EVP.js → list-D3R3q3Ti.js} +2 -2
  53. package/assets/{login-n9fNk99k.js → login-DwxC2WD6.js} +1 -1
  54. package/assets/manifest.json +277 -277
  55. package/assets/{media-manager-ChlwzfP8.js → media-manager-mt4Ykki7.js} +1 -1
  56. package/assets/{mermaid.core-CUYdfyhY.js → mermaid.core-DxLHD4PF.js} +5 -5
  57. package/assets/{mindmap-definition-YA3MSWOX-9_Osk887.js → mindmap-definition-YA3MSWOX-BfdP8hOy.js} +1 -1
  58. package/assets/module-DKdDlng0.js +1 -0
  59. package/assets/{notification-DTOo0s9p.js → notification-DDWbaooT.js} +1 -1
  60. package/assets/{pegDiagram-XKGWAZYB-xGo27v2q.js → pegDiagram-XKGWAZYB-BO9cFGCI.js} +1 -1
  61. package/assets/{pieDiagram-E7YTZNPT-BlxVq7jD.js → pieDiagram-E7YTZNPT-B4KrTpto.js} +1 -1
  62. package/assets/{quadrantDiagram-AXDQQJYC-DSIsRL3O.js → quadrantDiagram-AXDQQJYC-BumScZvv.js} +1 -1
  63. package/assets/{railroadDiagram-O6MQD6OU-CcXubifR.js → railroadDiagram-O6MQD6OU-DUDQQC-p.js} +1 -1
  64. package/assets/{register-sc1NPrUn.js → register-5rs1OSaq.js} +1 -1
  65. package/assets/{requirementDiagram-BXWQKSXE-CQ0HxjT5.js → requirementDiagram-BXWQKSXE-BtNsxNt1.js} +1 -1
  66. package/assets/{ru-BcGQTZye.js → ru-Cf1WWSt0.js} +1 -1
  67. package/assets/{sankeyDiagram-P5KCCOFB-BfeizISp.js → sankeyDiagram-P5KCCOFB-xjPcSTcN.js} +1 -1
  68. package/assets/{sequenceDiagram-WJ2MYXX4-U6sVYSC5.js → sequenceDiagram-WJ2MYXX4-BVOgA3-B.js} +1 -1
  69. package/assets/{sizeCapture-INFHLROL-sy73XuOR.js → sizeCapture-INFHLROL-BDI5FsKO.js} +1 -1
  70. package/assets/{stateDiagram-D77RDMKH-BBQ4V6V5.js → stateDiagram-D77RDMKH-DreIJby8.js} +1 -1
  71. package/assets/stateDiagram-v2-MP3YSRHH-BNzSJJYe.js +1 -0
  72. package/assets/{swimlanes-42K2YHIH-DgNoaSy5.js → swimlanes-42K2YHIH-J_CNnPZv.js} +1 -1
  73. package/assets/swimlanesDiagram-VR7AAH4N-DN5N1rG7.js +8 -0
  74. package/assets/{timeline-definition-24CTP7MA-DCZ7_pVf.js → timeline-definition-24CTP7MA-BXGN0YmT.js} +1 -1
  75. package/assets/{use-appearance-B1Ulba0z.js → use-appearance-B2YFalXG.js} +1 -1
  76. package/assets/{user-filters-list-Jd8ADfF3.js → user-filters-list-D8WohjvX.js} +1 -1
  77. package/assets/{vennDiagram-4TSXK5OY-BH1b3-en.js → vennDiagram-4TSXK5OY-Mu0lMKUo.js} +1 -1
  78. package/assets/{wardleyDiagram-VM6X3IG4-4tU49eCf.js → wardleyDiagram-VM6X3IG4-CXFMI74r.js} +1 -1
  79. package/assets/{welcome-CoEo_2b6.js → welcome-DHQx7R11.js} +1 -1
  80. package/assets/with-app-layout-Cvg36gxr.js +31 -0
  81. package/assets/{xychartDiagram-S5SC5T6Z-C-jB1QUO.js → xychartDiagram-S5SC5T6Z-DCr7j1YG.js} +1 -1
  82. package/controllers/adminLinks.d.ts +7 -0
  83. package/controllers/adminLinks.js +10 -0
  84. package/helpers/menuHelper.d.ts +11 -1
  85. package/helpers/menuHelper.js +16 -6
  86. package/helpers/navigationAccessHelper.d.ts +10 -3
  87. package/helpers/navigationAccessHelper.js +21 -2
  88. package/helpers/pathPattern.d.ts +5 -0
  89. package/helpers/pathPattern.js +10 -0
  90. package/interfaces/adminpanelConfig.d.ts +23 -0
  91. package/lib/admin-links/AdminLinkHandler.d.ts +41 -0
  92. package/lib/admin-links/AdminLinkHandler.js +94 -1
  93. package/lib/ai-assistant/AiAssistantUiMethodHandler.d.ts +4 -22
  94. package/lib/ai-assistant/AiAssistantUiMethodHandler.js +3 -47
  95. package/lib/docs/AbstractDocumentation.js +2 -4
  96. package/package.json +1 -2
  97. package/system/Router.js +7 -0
  98. package/system/bindInertia.js +16 -0
  99. package/ui/components/VanillaJSONEditor.js +50 -11
  100. package/ui/components/ui/badge.d.ts +1 -1
  101. package/ui/components/ui/badge.js +1 -0
  102. package/ui/components/ui/command.d.ts +3 -1
  103. package/ui/components/ui/command.js +2 -2
  104. package/assets/add-BJKSs5TK.js +0 -1
  105. package/assets/app-BKQr0JOg.js +0 -138
  106. package/assets/app-DPmI-MvN.css +0 -1
  107. package/assets/channel-e6rquzsE.js +0 -1
  108. package/assets/classDiagram-ZZMXUADV-DIbGlLDx.js +0 -1
  109. package/assets/classDiagram-v2-VYDZK3BY-DIbGlLDx.js +0 -1
  110. package/assets/module-jjWCUszz.js +0 -1
  111. package/assets/stateDiagram-v2-MP3YSRHH-BrVvb-bz.js +0 -1
  112. package/assets/swimlanesDiagram-VR7AAH4N-CkLcfj4e.js +0 -8
  113. package/assets/with-app-layout-R5blfHwR.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-CUYdfyhY.js";import{i as Di}from"./init-Gi6I4Gst.js";import{o as Pi}from"./ordinal-Cboi1Yqb.js";import{l as Nt}from"./linear-p2QT3a1B.js";import"./app-BKQr0JOg.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-DxLHD4PF.js";import{i as Di}from"./init-Gi6I4Gst.js";import{o as Pi}from"./ordinal-Cboi1Yqb.js";import{l as Nt}from"./linear-DdadsTLS.js";import"./app-CRa5Kokq.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()+`
@@ -0,0 +1,7 @@
1
+ /**
2
+ * JSON proxy of the navigation registry (`AdminLinkHandler`): the very search
3
+ * the assistant's `search-admin-links` skill performs, for the panel's global
4
+ * search palette and for hosts. Policies checked the auth; the registry drops
5
+ * every page this user may not open.
6
+ */
7
+ export declare function searchAdminLinks(req: ReqType, res: ResType): Promise<ResType>;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * JSON proxy of the navigation registry (`AdminLinkHandler`): the very search
3
+ * the assistant's `search-admin-links` skill performs, for the panel's global
4
+ * search palette and for hosts. Policies checked the auth; the registry drops
5
+ * every page this user may not open.
6
+ */
7
+ export async function searchAdminLinks(req, res) {
8
+ const query = typeof req.query.q === 'string' ? req.query.q : '';
9
+ return res.json({ results: await req.adminizer.adminLinkHandler.search(req.user, query) });
10
+ }
@@ -4,7 +4,7 @@
4
4
  * @constructor
5
5
  */
6
6
  import { User } from "../models/User.js";
7
- import { ActionType, AdminpanelConfig, HrefConfig, ModelConfig, NavbarSectionConfig } from "../interfaces/adminpanelConfig.js";
7
+ import { ActionType, AdminpanelConfig, HrefConfig, MenuBadge, ModelConfig, NavbarSectionConfig } from "../interfaces/adminpanelConfig.js";
8
8
  export type MenuItem = {
9
9
  link: string;
10
10
  title: string;
@@ -15,7 +15,17 @@ export type MenuItem = {
15
15
  accessRightsToken: string | null;
16
16
  modelResourceName?: string;
17
17
  section?: string;
18
+ /** Raw value from the config; `listAccessibleMenuItems` resolves it per user. */
19
+ badge?: MenuBadge;
18
20
  };
21
+ /**
22
+ * True when a model's item must not be in this user's navbar: `navbar.visible`
23
+ * is `false`, or `navbar.groupsAccessRights` names groups the user is not in.
24
+ * The navigation registry (`AdminLinkHandler`) applies the same rule to the
25
+ * model's record templates, so a model hidden from the menu is hidden from
26
+ * search, the assistant and breadcrumbs as well.
27
+ */
28
+ export declare function isModelHiddenInNavbar(user: User, config: ModelConfig): boolean;
19
29
  export declare class MenuHelper {
20
30
  private config;
21
31
  constructor(config: AdminpanelConfig);
@@ -1,4 +1,18 @@
1
1
  import { GroupsAccessRightsHelper } from "./accessRightsHelper.js";
2
+ /**
3
+ * True when a model's item must not be in this user's navbar: `navbar.visible`
4
+ * is `false`, or `navbar.groupsAccessRights` names groups the user is not in.
5
+ * The navigation registry (`AdminLinkHandler`) applies the same rule to the
6
+ * model's record templates, so a model hidden from the menu is hidden from
7
+ * search, the assistant and breadcrumbs as well.
8
+ */
9
+ export function isModelHiddenInNavbar(user, config) {
10
+ if (typeof config.navbar?.visible === 'boolean')
11
+ return !config.navbar.visible;
12
+ if (config.navbar?.groupsAccessRights)
13
+ return !GroupsAccessRightsHelper.hasAccess(user, config.navbar.groupsAccessRights);
14
+ return false;
15
+ }
2
16
  export class MenuHelper {
3
17
  config;
4
18
  constructor(config) {
@@ -179,17 +193,13 @@ export class MenuHelper {
179
193
  icon: resolvedLink.icon || null,
180
194
  accessRightsToken: resolvedLink.accessRightsToken || null,
181
195
  section: resolvedLink.section || 'Platform',
196
+ badge: resolvedLink.badge,
182
197
  });
183
198
  });
184
199
  if (this.config.models) {
185
200
  const _this = this;
186
201
  Object.entries(this.config.models).forEach(function ([key, val]) {
187
- const hide = typeof val.navbar?.visible === 'boolean'
188
- ? !val.navbar.visible
189
- : val.navbar?.groupsAccessRights
190
- ? !GroupsAccessRightsHelper.hasAccess(user, val.navbar.groupsAccessRights)
191
- : false;
192
- if (!hide) {
202
+ if (!isModelHiddenInNavbar(user, val)) {
193
203
  if (val.tools && val.tools.length > 0 && val.tools[0].id !== "overview") {
194
204
  val.tools.unshift({
195
205
  id: "overview",
@@ -1,13 +1,20 @@
1
- import type { HrefConfig } from '../interfaces/adminpanelConfig.js';
2
- import type { Adminizer } from '../lib/Adminizer.js';
1
+ import type { HrefConfig, MenuBadge } from '../interfaces/adminpanelConfig.js';
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
5
  /** Drops the sub-items this user may not open, recursively. */
6
6
  export declare function filterAccessibleHrefItems(adminizer: Adminizer, user: User, items: HrefConfig[]): Promise<HrefConfig[]>;
7
+ /**
8
+ * The badge of a menu item for this user: a plain value as is, a resolver
9
+ * called with the user. A failing resolver must not take the page down — it
10
+ * is logged and the item renders without a badge.
11
+ */
12
+ export declare function resolveMenuBadge(user: User, badge: MenuBadge | undefined, itemId: string): Promise<number | string | undefined>;
7
13
  /**
8
14
  * The navigation menu a user may actually open: configured models, additional
9
15
  * links and app-contributed pages, filtered with the very same rules the
10
16
  * sidebar uses. Titles are left untranslated, so callers that need i18n (the
11
- * Inertia page props) translate on top of this.
17
+ * Inertia page props) translate on top of this. Badge resolvers are evaluated
18
+ * here, after the permission check, so they never run for a hidden page.
12
19
  */
13
20
  export declare function listAccessibleMenuItems(adminizer: Adminizer, user: User): Promise<MenuItem[]>;
@@ -1,3 +1,4 @@
1
+ import { Adminizer } from '../lib/Adminizer.js';
1
2
  /** Drops the sub-items this user may not open, recursively. */
2
3
  export async function filterAccessibleHrefItems(adminizer, user, items) {
3
4
  const accessible = [];
@@ -12,11 +13,28 @@ export async function filterAccessibleHrefItems(adminizer, user, items) {
12
13
  }
13
14
  return accessible;
14
15
  }
16
+ /**
17
+ * The badge of a menu item for this user: a plain value as is, a resolver
18
+ * called with the user. A failing resolver must not take the page down — it
19
+ * is logged and the item renders without a badge.
20
+ */
21
+ export async function resolveMenuBadge(user, badge, itemId) {
22
+ if (typeof badge !== 'function')
23
+ return badge;
24
+ try {
25
+ return await badge(user);
26
+ }
27
+ catch (error) {
28
+ Adminizer.log.error(`navigation > badge of "${itemId}" failed: ${error}`);
29
+ return undefined;
30
+ }
31
+ }
15
32
  /**
16
33
  * The navigation menu a user may actually open: configured models, additional
17
34
  * links and app-contributed pages, filtered with the very same rules the
18
35
  * sidebar uses. Titles are left untranslated, so callers that need i18n (the
19
- * Inertia page props) translate on top of this.
36
+ * Inertia page props) translate on top of this. Badge resolvers are evaluated
37
+ * here, after the permission check, so they never run for a hidden page.
20
38
  */
21
39
  export async function listAccessibleMenuItems(adminizer, user) {
22
40
  const menu = [];
@@ -26,7 +44,7 @@ export async function listAccessibleMenuItems(adminizer, user) {
26
44
  if (menuItem.accessRightsToken)
27
45
  tokens.push(menuItem.accessRightsToken);
28
46
  if (await adminizer.accessRightsHelper.checkAnyPermission(tokens, user)) {
29
- menu.push({ ...menuItem, actions });
47
+ menu.push({ ...menuItem, actions, badge: await resolveMenuBadge(user, menuItem.badge, menuItem.id) });
30
48
  }
31
49
  }
32
50
  for (const link of await adminizer.adminLinkHandler.list(user)) {
@@ -39,6 +57,7 @@ export async function listAccessibleMenuItems(adminizer, user) {
39
57
  icon: null,
40
58
  accessRightsToken: link.accessRightsToken ?? null,
41
59
  section: link.section || 'Platform',
60
+ badge: await resolveMenuBadge(user, link.badge, link.id),
42
61
  });
43
62
  }
44
63
  return menu;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Matches an Express-style pattern (`/model/:name`) against a concrete path.
3
+ * Query, hash and trailing slashes are ignored on both sides.
4
+ */
5
+ export declare function matchesPathPattern(pattern: string, url: string): boolean;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Matches an Express-style pattern (`/model/:name`) against a concrete path.
3
+ * Query, hash and trailing slashes are ignored on both sides.
4
+ */
5
+ export function matchesPathPattern(pattern, url) {
6
+ const path = url.replace(/[?#].*$/, '').replace(/\/+$/, '') || '/';
7
+ const source = pattern.replace(/\/+$/, '') || '/';
8
+ const regex = new RegExp(`^${source.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/:[A-Za-z0-9_]+/g, '[^/]+')}$`);
9
+ return regex.test(path);
10
+ }
@@ -135,6 +135,13 @@ export interface AdminpanelConfig {
135
135
  sections?: {
136
136
  [section: string]: NavbarSectionConfig;
137
137
  };
138
+ /**
139
+ * Breadcrumbs of pages that send none of their own (`breadcrumbs` prop).
140
+ * `'auto'` resolves them from the navigation registry: menu items, app
141
+ * links and link templates whose URL is a prefix of the current one.
142
+ * `'manual'` (default) shows only what a page sends.
143
+ */
144
+ breadcrumbs?: 'manual' | 'auto';
138
145
  };
139
146
  /**
140
147
  * Policies that will be executed before going to every page
@@ -703,6 +710,14 @@ export interface CreateUpdateConfig {
703
710
  * */
704
711
  controller?: string | ControllerFunction;
705
712
  }
713
+ /**
714
+ * Badge of a sidebar item: a value, or a resolver computing it for the user
715
+ * the menu is built for. A resolver runs on every request and only for items
716
+ * that user may open, so it must be cheap — return a cached count, never run a
717
+ * query per call. A resolver that throws is logged and renders no badge.
718
+ * `0`, `''` and `undefined` render nothing.
719
+ */
720
+ export type MenuBadge = number | string | ((user: User) => number | string | undefined | Promise<number | string | undefined>);
706
721
  export interface HrefConfig {
707
722
  id: string;
708
723
  title: string;
@@ -724,6 +739,14 @@ export interface HrefConfig {
724
739
  * Optional section grouping for navbar items (side navigation)
725
740
  */
726
741
  section?: string;
742
+ /**
743
+ * Count shown next to the item in the expanded sidebar (rendered as
744
+ * `SidebarMenuBadge`). `0`, `''` and `undefined` render nothing. Not drawn
745
+ * in the collapsed icon rail, where a number without a label means nothing.
746
+ * Either a value or a resolver computing it per request for the user the
747
+ * menu is built for — see `MenuBadge`.
748
+ */
749
+ badge?: MenuBadge;
727
750
  }
728
751
  /**
729
752
  * Presentation of a single navbar section header.
@@ -1,3 +1,5 @@
1
+ import { type MenuItem } from '../../helpers/menuHelper.js';
2
+ import type { MenuBadge } from '../../interfaces/adminpanelConfig.js';
1
3
  import type { User } from '../../models/User.js';
2
4
  import type { Adminizer } from '../Adminizer.js';
3
5
  export interface AdminLink {
@@ -8,6 +10,8 @@ export interface AdminLink {
8
10
  title?: string;
9
11
  section?: string;
10
12
  accessRightsToken?: string;
13
+ /** Count shown next to the item in the sidebar: a value or a per-user resolver, see `MenuBadge`. */
14
+ badge?: MenuBadge;
11
15
  }
12
16
  export interface ResolvedAdminLink extends AdminLink {
13
17
  owner: string;
@@ -38,6 +42,24 @@ export interface ResolvedAdminLinkTemplate extends AdminLinkTemplate {
38
42
  owner: string;
39
43
  params: AdminLinkTemplateParam[];
40
44
  }
45
+ /** A hit of `AdminLinkHandler.search`: a concrete page or a template plus its placeholders. */
46
+ export interface AdminLinkSearchResult {
47
+ id: string;
48
+ title: string;
49
+ /** Concrete page, ready to open. Absent for templates. */
50
+ link?: string;
51
+ /** Parametrized page: fill `params` and resolve through `resolveTemplate`. */
52
+ template?: string;
53
+ /** Placeholders that must be filled to open a template. */
54
+ params?: AdminLinkTemplateParam[];
55
+ description?: string;
56
+ section?: string;
57
+ }
58
+ /** One crumb of `AdminLinkHandler.locate`; the page itself carries no `href`. */
59
+ export interface AdminBreadcrumb {
60
+ title: string;
61
+ href?: string;
62
+ }
41
63
  /** Server-side registry of standalone admin pages contributed by applications. */
42
64
  export declare class AdminLinkHandler {
43
65
  private readonly adminizer;
@@ -61,6 +83,25 @@ export declare class AdminLinkHandler {
61
83
  * admin URL, rejecting templates this user may not open.
62
84
  */
63
85
  resolveTemplate(user: User, id: string, params?: Record<string, unknown>): Promise<string>;
86
+ /**
87
+ * Search exactly the navigation a user can open: the menu the sidebar
88
+ * renders (sub-items included) plus every link template. Permission-safe by
89
+ * construction, so the result may be handed to an agent or to the browser.
90
+ * Parametrized pages are returned as templates, so a record page is
91
+ * reachable even though its URL only exists once the id is known.
92
+ */
93
+ search(user: User, query?: string): Promise<AdminLinkSearchResult[]>;
94
+ /**
95
+ * Breadcrumb chain of an admin url: every page of the registry — menu items
96
+ * and their actions, app links, link templates — whose path is a prefix of
97
+ * it, shortest first. The last crumb has no `href` when it is the page
98
+ * itself. Pages this user may not open never appear.
99
+ *
100
+ * `menu` lets a caller that already holds the user's menu (bindInertia
101
+ * computes a translated one per request) skip a second computation.
102
+ */
103
+ locate(user: User, url: string, menu?: MenuItem[]): Promise<AdminBreadcrumb[]>;
104
+ private normalizePath;
64
105
  /** Fills the placeholders of a template with url-encoded values. */
65
106
  buildHref(template: ResolvedAdminLinkTemplate, params?: Record<string, unknown>): string;
66
107
  /** True for paths that change data and therefore must never be navigated to. */
@@ -1,3 +1,6 @@
1
+ import { listAccessibleMenuItems } from '../../helpers/navigationAccessHelper.js';
2
+ import { matchesPathPattern } from '../../helpers/pathPattern.js';
3
+ import { isModelHiddenInNavbar } from '../../helpers/menuHelper.js';
1
4
  /** Segments no template may point at: opening one mutates data. */
2
5
  const DESTRUCTIVE_PATH = /\/model\/[^/]+\/remove(\/|$)/i;
3
6
  /** Server-side registry of standalone admin pages contributed by applications. */
@@ -108,6 +111,92 @@ export class AdminLinkHandler {
108
111
  throw new Error(`Admin link template "${id}" is not available`);
109
112
  return this.buildHref(template, params);
110
113
  }
114
+ /**
115
+ * Search exactly the navigation a user can open: the menu the sidebar
116
+ * renders (sub-items included) plus every link template. Permission-safe by
117
+ * construction, so the result may be handed to an agent or to the browser.
118
+ * Parametrized pages are returned as templates, so a record page is
119
+ * reachable even though its URL only exists once the id is known.
120
+ */
121
+ async search(user, query = '') {
122
+ const needle = this.slug(query);
123
+ const result = [];
124
+ const matches = (...values) => !needle || this.slug(values.filter(Boolean).join(' ')).includes(needle);
125
+ const add = (item, section) => {
126
+ if (!item?.link || !item?.title)
127
+ return;
128
+ const link = {
129
+ id: String(item.id || item.title), title: String(item.title), link: String(item.link),
130
+ section: item.section || section,
131
+ };
132
+ // A link with placeholders is surfaced as a template instead.
133
+ if (!/:[A-Za-z0-9_]+/.test(link.link) && matches(link.title, link.id, link.section))
134
+ result.push(link);
135
+ for (const child of item.actions ?? item.subItems ?? [])
136
+ add(child, link.section);
137
+ };
138
+ for (const item of await listAccessibleMenuItems(this.adminizer, user))
139
+ add(item, item.section);
140
+ for (const template of await this.listTemplates(user)) {
141
+ if (!matches(template.title, template.id, template.section, template.description, template.template))
142
+ continue;
143
+ result.push({
144
+ id: template.id,
145
+ title: template.title,
146
+ template: template.template,
147
+ params: template.params,
148
+ description: template.description,
149
+ section: template.section,
150
+ // A template without placeholders is already a usable link.
151
+ link: template.params.length ? undefined : template.template,
152
+ });
153
+ }
154
+ return result;
155
+ }
156
+ /**
157
+ * Breadcrumb chain of an admin url: every page of the registry — menu items
158
+ * and their actions, app links, link templates — whose path is a prefix of
159
+ * it, shortest first. The last crumb has no `href` when it is the page
160
+ * itself. Pages this user may not open never appear.
161
+ *
162
+ * `menu` lets a caller that already holds the user's menu (bindInertia
163
+ * computes a translated one per request) skip a second computation.
164
+ */
165
+ async locate(user, url, menu) {
166
+ const prefix = (this.adminizer.config.routePrefix || '').replace(/\/+$/, '');
167
+ const path = this.normalizePath(url);
168
+ if (path !== prefix && !path.startsWith(`${prefix}/`))
169
+ return [];
170
+ // Concrete pages: exact path -> title.
171
+ const pages = new Map();
172
+ const collect = (item) => {
173
+ const link = typeof item?.link === 'string' ? item.link : '';
174
+ if (link.startsWith('/') && item?.title && !/:[A-Za-z0-9_]+/.test(link)) {
175
+ pages.set(this.normalizePath(link), String(item.title));
176
+ }
177
+ for (const child of item?.actions ?? item?.subItems ?? [])
178
+ collect(child);
179
+ };
180
+ for (const item of menu ?? await listAccessibleMenuItems(this.adminizer, user))
181
+ collect(item);
182
+ const templates = await this.listTemplates(user);
183
+ const crumbs = [];
184
+ const segments = path.slice(prefix.length).split('/').filter(Boolean);
185
+ for (let depth = 1; depth <= segments.length; depth++) {
186
+ const candidate = `${prefix}/${segments.slice(0, depth).join('/')}`;
187
+ const title = pages.get(candidate)
188
+ ?? templates.find((template) => matchesPathPattern(template.template, candidate))?.title;
189
+ if (title)
190
+ crumbs.push({ title, href: candidate });
191
+ }
192
+ const last = crumbs[crumbs.length - 1];
193
+ if (last?.href === path)
194
+ delete last.href;
195
+ return crumbs;
196
+ }
197
+ normalizePath(url) {
198
+ return url.replace(/[?#].*$/, '').replace(/\/+$/, '') || '/';
199
+ }
111
200
  /** Fills the placeholders of a template with url-encoded values. */
112
201
  buildHref(template, params = {}) {
113
202
  return template.template.replace(/:([A-Za-z0-9_]+)/g, (_match, name) => {
@@ -136,6 +225,10 @@ export class AdminLinkHandler {
136
225
  { name: 'id', description: 'Identifier of the record, as returned when reading its data.' },
137
226
  ];
138
227
  for (const [model, config] of Object.entries(this.adminizer.config.models ?? {})) {
228
+ // A model kept out of this user's navbar (`navbar.visible: false`,
229
+ // `navbar.groupsAccessRights`) is kept out of the registry as well.
230
+ if (typeof config === 'object' && config && isModelHiddenInNavbar(user, config))
231
+ continue;
139
232
  const title = typeof config === 'object' && config?.title ? config.title : model;
140
233
  const section = typeof config === 'object' ? config?.navbar?.section : undefined;
141
234
  builtin(`model-${model}-edit`, `${title}: open record`, `${prefix}/model/${model}/edit/:id`, `update-${model}-model`, `Open the edit page of a single ${title} record by its id.`, section, recordId);
@@ -178,6 +271,6 @@ export class AdminLinkHandler {
178
271
  }));
179
272
  }
180
273
  slug(value) {
181
- return String(value).trim().toLowerCase().replace(/[\s_-]+/g, '-');
274
+ return String(value ?? '').trim().toLowerCase().replace(/[\s_-]+/g, '-');
182
275
  }
183
276
  }
@@ -1,18 +1,8 @@
1
1
  import type { User } from '../../models/User.js';
2
2
  import type { Adminizer } from '../Adminizer.js';
3
- import type { AdminLinkTemplateParam } from '../admin-links/AdminLinkHandler.js';
4
- export interface AiAssistantAdminLink {
5
- id: string;
6
- title: string;
7
- /** Concrete page, ready for `navigate`. Absent for templates. */
8
- link?: string;
9
- /** Parametrized page: pass `template` plus `params` to `navigate`. */
10
- template?: string;
11
- /** Placeholders that must be filled to open a template. */
12
- params?: AdminLinkTemplateParam[];
13
- description?: string;
14
- section?: string;
15
- }
3
+ import type { AdminLinkSearchResult } from '../admin-links/AdminLinkHandler.js';
4
+ /** @deprecated Use `AdminLinkSearchResult`; kept as an alias for compatibility. */
5
+ export type AiAssistantAdminLink = AdminLinkSearchResult;
16
6
  /**
17
7
  * A browser capability an AI service may expose as a tool. The agent emits
18
8
  * `ui.method` with this id; the assistant panel performs the browser action.
@@ -41,14 +31,7 @@ export declare class AiAssistantUiMethodHandler {
41
31
  register(method: AiAssistantUiMethod, owner?: string): void;
42
32
  unregister(id: string, owner?: string): void;
43
33
  getAvailable(user: User): Promise<AiAssistantUiMethod[]>;
44
- /**
45
- * Search exactly the navigation a user can open. This intentionally uses
46
- * MenuHelper rather than client-side markup, therefore a tool result is
47
- * permission-safe and works when the assistant panel is not visible.
48
- *
49
- * Parametrized pages are returned as templates, so a record page is
50
- * reachable even though its URL only exists once the id is known.
51
- */
34
+ /** The registry search (`AdminLinkHandler.search`), kept here for model services. */
52
35
  searchAdminLinks(user: User, query?: string): Promise<AiAssistantAdminLink[]>;
53
36
  /**
54
37
  * Validates what an agent asked to open and returns the concrete admin URL.
@@ -56,5 +39,4 @@ export declare class AiAssistantUiMethodHandler {
56
39
  * can only reach pages that user could reach by clicking.
57
40
  */
58
41
  resolveNavigation(user: User, target: AiAssistantNavigationTarget): Promise<string>;
59
- private slug;
60
42
  }
@@ -1,4 +1,3 @@
1
- import { listAccessibleMenuItems } from '../../helpers/navigationAccessHelper.js';
2
1
  export class AiAssistantUiMethodHandler {
3
2
  adminizer;
4
3
  methods = new Map();
@@ -69,49 +68,9 @@ export class AiAssistantUiMethodHandler {
69
68
  }
70
69
  return available;
71
70
  }
72
- /**
73
- * Search exactly the navigation a user can open. This intentionally uses
74
- * MenuHelper rather than client-side markup, therefore a tool result is
75
- * permission-safe and works when the assistant panel is not visible.
76
- *
77
- * Parametrized pages are returned as templates, so a record page is
78
- * reachable even though its URL only exists once the id is known.
79
- */
80
- async searchAdminLinks(user, query = '') {
81
- const needle = this.slug(query);
82
- const result = [];
83
- const matches = (...values) => !needle || this.slug(values.filter(Boolean).join(' ')).includes(needle);
84
- const add = (item, section) => {
85
- if (!item?.link || !item?.title)
86
- return;
87
- const link = {
88
- id: String(item.id || item.title), title: String(item.title), link: String(item.link),
89
- section: item.section || section,
90
- };
91
- // A link with placeholders is surfaced as a template instead.
92
- if (!/:[A-Za-z0-9_]+/.test(link.link) && matches(link.title, link.id, link.section))
93
- result.push(link);
94
- for (const child of item.actions ?? item.subItems ?? [])
95
- add(child, link.section);
96
- };
97
- // Exactly the menu the sidebar renders for this user, sub-items included.
98
- for (const item of await listAccessibleMenuItems(this.adminizer, user))
99
- add(item, item.section);
100
- for (const template of await this.adminizer.adminLinkHandler.listTemplates(user)) {
101
- if (!matches(template.title, template.id, template.section, template.description, template.template))
102
- continue;
103
- result.push({
104
- id: template.id,
105
- title: template.title,
106
- template: template.template,
107
- params: template.params,
108
- description: template.description,
109
- section: template.section,
110
- // A template without placeholders is already a usable link.
111
- link: template.params.length ? undefined : template.template,
112
- });
113
- }
114
- return result;
71
+ /** The registry search (`AdminLinkHandler.search`), kept here for model services. */
72
+ searchAdminLinks(user, query = '') {
73
+ return this.adminizer.adminLinkHandler.search(user, query);
115
74
  }
116
75
  /**
117
76
  * Validates what an agent asked to open and returns the concrete admin URL.
@@ -138,7 +97,4 @@ export class AiAssistantUiMethodHandler {
138
97
  }
139
98
  return href;
140
99
  }
141
- slug(value) {
142
- return String(value ?? '').trim().toLowerCase().replace(/[\s_-]+/g, '-');
143
- }
144
100
  }
@@ -1,3 +1,4 @@
1
+ import { matchesPathPattern } from '../../helpers/pathPattern.js';
1
2
  const SNIPPET_LIMIT = 3;
2
3
  const SNIPPET_CONTEXT = 120;
3
4
  /**
@@ -85,10 +86,7 @@ export class AbstractDocumentation {
85
86
  }
86
87
  /** Matches an Express-style pattern (`/model/:name`) against a concrete path. */
87
88
  matchesUrl(pattern, url) {
88
- const path = url.replace(/[?#].*$/, '').replace(/\/+$/, '') || '/';
89
- const source = pattern.replace(/\/+$/, '') || '/';
90
- const regex = new RegExp(`^${source.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/:[A-Za-z0-9_]+/g, '[^/]+')}$`);
91
- return regex.test(path);
89
+ return matchesPathPattern(pattern, url);
92
90
  }
93
91
  /** Lines containing the query, trimmed to a little context around the match. */
94
92
  extractSnippets(markdown, query) {
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "adminizer",
3
3
  "type": "module",
4
- "version": "5.1.0-build.26",
4
+ "version": "5.1.0-build.28",
5
5
  "main": "index.js",
6
6
  "exports": {
7
7
  ".": "./index.js",
8
8
  "./lib/DataAccessor": "./dist/lib/DataAccessor.js",
9
- "./ui/*": "./dist/ui/components/ui/*.js",
10
9
  "./adminizer-module": "./adminizer-module.d.ts"
11
10
  },
12
11
  "scripts": {
package/system/Router.js CHANGED
@@ -33,6 +33,7 @@ import { HistoryController } from "../controllers/history-actions/HistoryControl
33
33
  import { AiAssistantController } from "../controllers/ai/AiAssistantController.js";
34
34
  import { AiAgentController } from "../controllers/ai/AiAgentController.js";
35
35
  import listUserFilters from "../controllers/listUserFilters.js";
36
+ import { searchAdminLinks } from "../controllers/adminLinks.js";
36
37
  import { requireAnyPermission, requireAuthAPI, requireAuthEnabled, requireAuthUI, requirePermission } from "../policies/authPolicies.js";
37
38
  import { aiModelToken, catalogToken, groupFilterVisibilityToken, historyToken, mediaManagerToken, modelCreateToken, modelDeleteToken, modelReadToken, modelUpdateToken, widgetToken, widgetsToken } from "../policies/permissionResolvers.js";
38
39
  import { bindWithMiddlewares } from "./routePolicies.js";
@@ -222,6 +223,12 @@ export default class Router {
222
223
  */
223
224
  adminizer.app.get(`${adminizer.config.routePrefix}/api/user-key`, withPolicies(getUserApiKey, requireAuthEnabled(), requireAuthAPI()));
224
225
  adminizer.app.post(`${adminizer.config.routePrefix}/api/user-key/regenerate`, withPolicies(regenerateUserApiKey, requireAuthEnabled(), requireAuthAPI()));
226
+ /**
227
+ * Navigation registry search — consumed by the global search palette
228
+ * (src/assets/js/components/global-search.tsx). Results are filtered by
229
+ * the user's permissions inside the registry.
230
+ */
231
+ adminizer.app.get(`${adminizer.config.routePrefix}/api/links/search`, withPolicies(searchAdminLinks, requireAuthAPI()));
225
232
  /**
226
233
  * AI assistant — consumed by src/assets/js/contexts/AiAssistantContext.tsx
227
234
  */