@nocobase/client-v2 2.2.0-beta.1 → 2.2.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/es/index.mjs CHANGED
@@ -1240,7 +1240,7 @@ ctx.render(<JsItem />);
1240
1240
  border-top-color: transparent;
1241
1241
  background-color: transparent;
1242
1242
  }
1243
- `,children:"x"})})})]})};class vZ{render(e,t){if(!e)return null;try{return(0,s.jsx)(vK,{value:e,...t})}catch(e){return console.error("渲染失败:",e),(0,s.jsxs)("pre",{style:{color:"red"},children:["Markdown 渲染错误:",e.message]})}}edit(e){try{return(0,s.jsx)(vQ,{...e})}catch(e){return(0,s.jsxs)("pre",{style:{color:"red"},children:["Markdown 编辑器加载错误:",e.message]})}}}class v0 extends __rspack_external_liquidjs.Liquid{transformLiquidContext(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t={};for(let l of e){let e=l.replace(/^ctx\./,"").split("."),o=t;for(let t=0;t<e.length;t++){let n=e[t];t===e.length-1?o[n]=`{{${l}}}`:(o[n]=o[n]||{},o=o[n])}}return t}async render(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};try{return await this.parseAndRender(e,t)}catch(e){return console.error("[Liquid] 模板解析失败:",e),`<pre style="color:red;">Liquid 模板错误:${e.message}</pre>`}}isFieldUsed(e,t){return t.some(t=>t.replace(/^ctx\./,"").endsWith(e))}enrichArrayFieldsSelective(e,t){if(e&&"object"==typeof e)for(let l in e){let o=e[l];if(Array.isArray(o)&&o.length&&"object"==typeof o[0]){let e=o;Object.keys(e[0]).filter(o=>["string","number","boolean"].includes(typeof e[0][o])&&this.isFieldUsed(`${l}.${o}`,t)).forEach(t=>{e[t]=e.map(e=>null!=e[t]?e[t]:"").join(",")}),e.forEach(e=>this.enrichArrayFieldsSelective(e,t))}else o&&"object"==typeof o&&this.enrichArrayFieldsSelective(o,t)}}async renderWithFullContext(e,t){if(e)try{"number"==typeof e&&(e=String(e)),e=e.replace(/\{\{\s*t\s*\(\s*(['"])([\s\S]*?)\1\s*(?:,\s*\{\s*ns\s*:\s*(['"])([\s\S]*?)\3\s*\}\s*)?\)\s*\}\}/g,(e,l,o,n,i)=>{try{let e=i?t.t(o,{ns:i}):t.t(o);if(null==e)return"";return/[{][{%]/.test(e)?`{% raw %}${e}{% endraw %}`:e}catch{return e}});let l=await this.fullVariables(e),o=l.map(e=>this.transformLiquidContext([e])),n=(await Promise.all(o.map(e=>t.resolveJsonTemplate(e)))).reduce((e,t)=>(0,c.merge)(e,t),{});return this.enrichArrayFieldsSelective(n,l),await this.render(e,{ctx:n})}catch(t){return e}}constructor(e){super({extname:".liquid",cache:!0,...e}),this.registerFilter("t",e.ctx.t),this.registerFilter("log",e=>(console.log("[Liquid log]",e),e))}}let v1=()=>{let e=(0,u.useFlowEngine)({throwError:!1});if(!e)return{isMobileLayout:!1,setIsMobileLayout:()=>{}};let t=e.getModel(eX);return t?{isMobileLayout:t.isMobileLayout,setIsMobileLayout:t.setIsMobileLayout.bind(t)}:{isMobileLayout:!1,setIsMobileLayout:()=>{}}};function v2(e){let{flowEngine:t,pageUid:l,refreshDesktopRoutes:o,layoutContentRef:n}=e;return o$({flowEngine:t,pageUid:l,refreshDesktopRoutes:o,layoutContentRef:n,getLayoutModel:e=>oq(e,{required:!0})})}var v5=__webpack_require__(9652),v8=__webpack_require__(6681),v4=__webpack_require__(9784),v3=__webpack_require__(65);class v6 extends iz{async load(){this.app.addComponents({FlowRoute:oX}),this.app.flowEngine.setModelRepository(new vw(this.app));let e=Object.fromEntries(Object.entries(l).filter(e=>{let[,t]=e;return"function"==typeof t&&t.prototype instanceof u.FlowModel}));this.flowEngine.registerModels(e),this.flowEngine.registerActions(o),this.flowEngine.registerActions(t),this.flowEngine.flowSettings.registerComponents({IconPicker:ed.ar,DefaultValue:vx,FlowSettingsVariableTextArea:iU.n}),this.flowEngine.flowSettings.addToolbarItem({key:"dynamic-flows-editor",component:vA,visible:e=>e.getEvents().size>0,sort:0});let n=new vZ;this.flowEngine.context.defineProperty("markdown",{get:()=>n});let i=new v0({ctx:this.flowEngine.context});this.flowEngine.context.defineProperty("liquid",{get:()=>i}),this.flowEngine.context.defineMethod("previewRunJS",async function(e,t){let l=await Promise.resolve().then(__webpack_require__.bind(__webpack_require__,426));return await l.previewRunJS(String(e??""),this,{version:t})},{description:"Preview/diagnose a RunJS snippet (lint + sandbox execution).",detail:"(code: string, version?: string) => Promise<{ success: boolean; message: string }>",params:[{name:"code",type:"string",description:"RunJS code to preview."},{name:"version",type:"string",description:"RunJS version override (e.g. v1/v2)."}],returns:{type:"Promise<PreviewRunJSResult>",description:"Preview result."},completion:{insertText:"await ctx.previewRunJS('console.log(1)', 'v2')"}})}}let v9={"ar-EG":"ar","az-AZ":"az","bg-BG":"bg","bn-BD":"bn-bd","by-BY":"en","ca-ES":"ca","cs-CZ":"cs","da-DK":"da","de-DE":"de","el-GR":"el","en-GB":"en-gb","en-US":"en","es-ES":"es","et-EE":"et","fa-IR":"fa","fi-FI":"fi","fr-BE":"fr","fr-CA":"fr","fr-FR":"fr","ga-IE":"ga","gl-ES":"gl","he-IL":"he","hi-IN":"hi","hr-HR":"hr","hu-HU":"hu","hy-AM":"hy-am","id-ID":"id","is-IS":"is","it-IT":"it","ja-JP":"ja","ka-GE":"ka","kk-KZ":"kk","km-KH":"km","kn-IN":"kn","ko-KR":"ko","ku-IQ":"ku","lt-LT":"lt","lv-LV":"lv","mk-MK":"mk","ml-IN":"ml","mn-MN":"mn","ms-MY":"ms","nb-NO":"nb","ne-NP":"ne","nl-BE":"nl-be","nl-NL":"nl","pl-PL":"pl","pt-BR":"pt-br","pt-PT":"pt","ro-RO":"ro","ru-RU":"ru","si-LK":"si","sk-SK":"sk","sl-SI":"sl","sr-RS":"sr","sv-SE":"sv","ta-IN":"ta","th-TH":"th","tk-TK":"tk","tr-TR":"tr","uk-UA":"uk","ur-PK":"ur","vi-VN":"vi","zh-CN":"zh-cn","zh-HK":"zh-hk","zh-TW":"zh-tw"};class v7{atX0SecondsPastTheMinuteGt20(){return this.data.atX0SecondsPastTheMinuteGt20}atX0MinutesPastTheHourGt20(){return this.data.atX0MinutesPastTheHourGt20}commaMonthX0ThroughMonthX1(){return this.data.commaMonthX0ThroughMonthX1}commaYearX0ThroughYearX1(){return this.data.commaYearX0ThroughYearX1}use24HourTimeFormatByDefault(){return this.data.use24HourTimeFormatByDefault}anErrorOccuredWhenGeneratingTheExpressionD(){return this.data.anErrorOccuredWhenGeneratingTheExpressionD}everyMinute(){return this.data.everyMinute}everyHour(){return this.data.everyHour}atSpace(){return this.data.atSpace}everyMinuteBetweenX0AndX1(){return this.data.everyMinuteBetweenX0AndX1}at(){return this.data.at}spaceAnd(){return this.data.spaceAnd}everySecond(){return this.data.everySecond}everyX0Seconds(){return this.data.everyX0Seconds}secondsX0ThroughX1PastTheMinute(){return this.data.secondsX0ThroughX1PastTheMinute}atX0SecondsPastTheMinute(){return this.data.atX0SecondsPastTheMinute}everyX0Minutes(){return this.data.everyX0Minutes}minutesX0ThroughX1PastTheHour(){return this.data.minutesX0ThroughX1PastTheHour}atX0MinutesPastTheHour(){return this.data.atX0MinutesPastTheHour}everyX0Hours(){return this.data.everyX0Hours}betweenX0AndX1(){return this.data.betweenX0AndX1}atX0(){return this.data.atX0}commaEveryDay(){return this.data.commaEveryDay}commaEveryX0DaysOfTheWeek(){return this.data.commaEveryX0DaysOfTheWeek}commaX0ThroughX1(){return this.data.commaX0ThroughX1}commaAndX0ThroughX1(){return this.data.commaAndX0ThroughX1}first(){return this.data.first}second(){return this.data.second}third(){return this.data.third}fourth(){return this.data.fourth}fifth(){return this.data.fifth}commaOnThe(){return this.data.commaOnThe}spaceX0OfTheMonth(){return this.data.spaceX0OfTheMonth}lastDay(){return this.data.lastDay}commaOnTheLastX0OfTheMonth(){return this.data.commaOnTheLastX0OfTheMonth}commaOnlyOnX0(){return this.data.commaOnlyOnX0}commaAndOnX0(){return this.data.commaAndOnX0}commaEveryX0Months(){return this.data.commaEveryX0Months}commaOnlyInX0(){return this.data.commaOnlyInX0}commaOnTheLastDayOfTheMonth(){return this.data.commaOnTheLastDayOfTheMonth}commaOnTheLastWeekdayOfTheMonth(){return this.data.commaOnTheLastWeekdayOfTheMonth}commaDaysBeforeTheLastDayOfTheMonth(){return this.data.commaDaysBeforeTheLastDayOfTheMonth}firstWeekday(){return this.data.firstWeekday}weekdayNearestDayX0(){return this.data.weekdayNearestDayX0}commaOnTheX0OfTheMonth(){return this.data.commaOnTheX0OfTheMonth}commaEveryX0Days(){return this.data.commaEveryX0Days}commaBetweenDayX0AndX1OfTheMonth(){return this.data.commaBetweenDayX0AndX1OfTheMonth}commaOnDayX0OfTheMonth(){return this.data.commaOnDayX0OfTheMonth}commaEveryHour(){return this.data.commaEveryHour}commaEveryX0Years(){return this.data.commaEveryX0Years}commaStartingX0(){return this.data.commaStartingX0}daysOfTheWeek(){return this.data.daysOfTheWeek}monthsOfTheYear(){return this.data.monthsOfTheYear}constructor(e){this.data=e}}let _e=e=>{(__rspack_external_cronstrue.default.default?__rspack_external_cronstrue.default.default:__rspack_external_cronstrue.default).initialize({load(t){t[null==e?void 0:e.lang]=new v7(null==e?void 0:e.cronstrue)}})};class _t extends iz{async afterAdd(){let e=this.app.apiClient,t=e.auth.locale;try{var l;let o=await e.request({url:"app:getLang",params:{locale:t},headers:{"X-Role":"anonymous"}}),n=(null==o||null==(l=o.data)?void 0:l.data)||{};this.engine.context.defineProperty("locales",{value:n}),this.app.use(g.App,{component:!1}),n.lang&&(e.auth.setLocale(n.lang),this.app.setDocumentLanguage(n.lang),this.app.i18n.changeLanguage(n.lang)),Object.keys(n.resources||{}).forEach(e=>{this.app.i18n.addResources(n.lang,e,n.resources[e]||{})}),(0,__rspack_external__formily_validator_5f6f1884.setValidateLanguage)(n.lang),_e(n);let i=v9[n.lang]||"en";await __webpack_require__(8817)(`./${i}`),m6.default.locale(i),window.cronLocale=n.cron}catch(e){throw e}}}let _l=["/signin","/signup","/forgot-password","/reset-password"];function _o(e,t){if(!t)return e;let l=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=RegExp(`^${l.replace(/\/?$/,"")}(\\/|$)`);return e.replace(o,"/")||e}function _n(e,t){let l=_o(e,t);return _l.some(e=>l===e||l.startsWith(`${e}/`))}function _i(e,t){let l=_o(e,t);return"/admin"===l||l.startsWith("/admin/")}function _r(e,t){return(e.router.matchRoutes(t)||[]).some(e=>{var t;return(null==e||null==(t=e.route)?void 0:t.authCheck)===!0})}function _a(e,t){return _i(t,e.router.getBasename())||_r(e,t)}function _s(e,t){return _n(t,e.router.getBasename())||e.router.isSkippedAuthCheckRoute(t)?"skipped":_a(e,t)?"required":"unchecked"}let _d=(0,p.createContext)(null);function _u(){return(0,p.useContext)(_d)}function _c(){var e,t;let{allowAnonymous:l}=(0,lg.v6)(),o=(0,u.useFlowEngine)(),n=null==o||null==(t=o.context)||null==(e=t.user)?void 0:e.roles;return(0,p.useMemo)(()=>{let e=e=>{var t;return null==e?"":(null==o||null==(t=o.context)?void 0:t.t)?o.context.t(e):e},t=(n||[]).filter(e=>(null==e?void 0:e.name)!=="__union__").map(t=>({name:t.name,title:e(t.title)}));return l&&t.push({name:"anonymous",title:"Anonymous"}),t},[l,o,n])}_d.displayName="CurrentUserContext";let _p=e=>{let{children:t}=e,l=(0,f.n)(),o=(0,h.useLocation)(),[n,i]=(0,p.useState)(!0),[r,a]=(0,p.useState)(null),d=(0,p.useRef)(!1);if((0,p.useEffect)(()=>{let e=!0,t=l.router.getBasename(),n=_n(o.pathname,t)||l.router.isSkippedAuthCheckRoute(o.pathname),r=_a(l,o.pathname);if(n||!r){i(!1),a(null);return}return d.current||i(!0),a(null),(async()=>{try{await l.dataSourceManager.ensureLoaded(),d.current=!0,e&&i(!1)}catch(t){if(!e)return;i(!1),a(t instanceof Error?t:Error(String(t)))}})(),()=>{e=!1}},[l,o.pathname]),r)throw r;return n?l.renderComponent("AppSpin"):(0,s.jsx)(s.Fragment,{children:t})},_m=e=>{let{children:t}=e,l=(0,f.n)(),o=(0,h.useLocation)(),n=(0,h.useNavigate)(),[i,r]=(0,p.useState)({loading:!0}),a=(0,p.useRef)(o);a.current=o;let d=_s(l,o.pathname);return((0,p.useEffect)(()=>{let e=!0;return"required"!==d?void r({loading:!1}):(r(e=>e.loading?e:{...e,loading:!0}),(async()=>{var t,o;try{let o=await l.apiClient.request({url:"/auth:check",skipNotify:!0,skipAuth:!0});if(!e)return;let i=null==o||null==(t=o.data)?void 0:t.data;if((null==i?void 0:i.code)===302)return void r({loading:!1});if((null==i?void 0:i.id)==null)return void n(`/signin?redirect=${encodeURIComponent(eT(l,a.current))}`,{replace:!0});let s=(0,u.createCollectionContextMeta)(()=>{var e,t;return(null==(t=l.flowEngine.context.dataSourceManager)||null==(e=t.getDataSource("main"))?void 0:e.getCollection("users"))||null},l.flowEngine.translate("Current user"));s.sort=1e3,l.flowEngine.context.defineProperty("user",{value:i,resolveOnServer:!0,meta:s}),r({data:null==o?void 0:o.data,loading:!1})}catch(t){if(!e)return;if((null==t||null==(o=t.response)?void 0:o.status)===401||(null==t?void 0:t.status)===401)return void n(`/signin?redirect=${encodeURIComponent(eT(l,a.current))}`,{replace:!0});throw r({loading:!1}),t}})(),()=>{e=!1})},[l,d,n]),i.loading)?l.renderComponent("AppSpin"):(0,s.jsx)(_d.Provider,{value:i,children:t})},_h=()=>{var e,t;let l=(0,f.n)(),o=!!(null==l||null==(t=l.apiClient)||null==(e=t.auth)?void 0:e.token),n=eP(l);return o?(0,s.jsx)(h.Navigate,{replace:!0,to:"/admin"}):(0,s.jsx)(h.Navigate,{replace:!0,to:`/signin?redirect=${encodeURIComponent(n)}`})};class _f extends iz{async afterAdd(){await this.addPlugins()}async load(){this.addComponents(),this.addRoutes(),this.app.use(_p),this.app.use(_m),this.app.flowEngine.registerModels({AdminLayoutModel:oV,AdminLayoutMenuItemModel:t9,AdminSettingsLayoutModel:v8.C}),this.app.layoutManager.registerLayout({routeName:"admin",routePath:"/admin",uid:eX,layoutModelClass:"AdminLayoutModel"}),this.app.pluginSettingsManager.addMenuItem({key:"plugin-manager",title:this.app.i18n.t("Plugin manager"),icon:"ApiOutlined",aclSnippet:"pm",sort:-200}),this.app.pluginSettingsManager.addPageTabItem({menuKey:"plugin-manager",key:"index",title:this.app.i18n.t("Plugin manager"),componentLoader:()=>Promise.resolve().then(__webpack_require__.bind(__webpack_require__,9784)),aclSnippet:"pm",sort:-200}),this.app.pluginSettingsManager.addMenuItem({key:"system-settings",title:this.app.i18n.t("System settings"),icon:"SettingOutlined",aclSnippet:"pm.system-settings.system-settings",sort:-100}),this.app.pluginSettingsManager.addPageTabItem({menuKey:"system-settings",key:"index",title:this.app.i18n.t("System settings"),componentLoader:()=>Promise.resolve().then(__webpack_require__.bind(__webpack_require__,65)),aclSnippet:"pm.system-settings.system-settings",sort:-100}),this.app.pluginSettingsManager.addMenuItem({key:"security",title:this.app.i18n.t("Security"),icon:"SafetyOutlined",aclSnippet:"pm.security"})}addRoutes(){this.router.add("root",{path:"/",element:(0,s.jsx)(_h,{})}),this.router.add("not-found",{path:"*",Component:I.bM}),this.router.add("admin.settings",{path:"/admin/settings",componentLoader:()=>Promise.resolve().then(__webpack_require__.bind(__webpack_require__,9652))}),this.router.add("admin.settings.route-empty",{path:"*",Component:h.Outlet})}addComponents(){}async addPlugins(){await this.app.pm.add(v6),await this.app.pm.add(_t,{name:"builtin-locale"})}}var _g=__webpack_require__(5026);let _y={type:"boolean","x-content":'{{t("Unique")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly || primaryKeyOnly }}"},_v={type:"boolean","x-content":'{{t("Primary")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly || primaryKeyOnly }}"},__={type:"boolean",title:'{{t("Auto increment")}}',"x-content":'{{t("Auto increment")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly }}"},_b={type:"boolean",title:'{{t("Default value")}}',"x-content":'{{t("Automatically generate default values")}}',"x-decorator":"FormItem","x-component":"Checkbox",default:!0},_x={type:"string",title:'{{t("Relationship type")}}',required:!0,"x-disabled":!0,"x-decorator":"FormItem","x-component":"Select",enum:[{label:"{{t('HasOne')}}",value:"hasOne"},{label:"{{t('HasMany')}}",value:"hasMany"},{label:"{{t('BelongsTo')}}",value:"belongsTo"},{label:"{{t('BelongsToMany')}}",value:"belongsToMany"}]},_M={onDelete:{type:"string",title:'{{t("ON DELETE")}}',required:!0,default:"SET NULL","x-disabled":"{{ !createOnly }}","x-decorator":"FormItem","x-component":"Select",enum:[{label:"{{t('SET NULL')}}",value:"SET NULL"},{label:"{{t('RESTRICT')}}",value:"RESTRICT"},{label:"{{t('CASCADE')}}",value:"CASCADE"},{label:"{{t('NO ACTION')}}",value:"NO ACTION"}]}},_w={reverse:{type:"void","x-component":"div",properties:{autoCreateReverseField:{type:"boolean",default:!1,"x-decorator":"FormItem","x-component":"Checkbox","x-content":'{{t("Create inverse field in the target collection")}}'},"reverseField.type":{..._x,title:'{{t("Inverse relationship type")}}'},"reverseField.uiSchema.title":{type:"string",title:'{{t("Inverse field display name")}}',default:"{{record.title}}",required:!0,"x-decorator":"FormItem","x-component":"Input","x-disabled":"{{ !showReverseFieldConfig }}"},"reverseField.name":{type:"string",title:'{{t("Inverse field name")}}',required:!0,"x-decorator":"FormItem","x-component":"Input","x-validator":"uid","x-disabled":"{{ !showReverseFieldConfig }}",description:"{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}"}}}},_S={"uiSchema.x-component-props.picker":{type:"string",title:'{{t("Picker")}}',"x-decorator":"FormItem","x-component":"Radio.Group",default:"date",enum:[{label:'{{t("Date")}}',value:"date"},{label:'{{t("Month")}}',value:"month"},{label:'{{t("Quarter")}}',value:"quarter"},{label:'{{t("Year")}}',value:"year"}]},"uiSchema.x-component-props.dateFormat":{type:"string",title:'{{t("Date format")}}',"x-decorator":"FormItem","x-component":"ExpiresRadio","x-decorator-props":{},"x-component-props":{className:(0,S.css)`
1243
+ `,children:"x"})})})]})};class vZ{render(e,t){if(!e)return null;try{return(0,s.jsx)(vK,{value:e,...t})}catch(e){return console.error("渲染失败:",e),(0,s.jsxs)("pre",{style:{color:"red"},children:["Markdown 渲染错误:",e.message]})}}edit(e){try{return(0,s.jsx)(vQ,{...e})}catch(e){return(0,s.jsxs)("pre",{style:{color:"red"},children:["Markdown 编辑器加载错误:",e.message]})}}}class v0 extends __rspack_external_liquidjs.Liquid{transformLiquidContext(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t={};for(let l of e){let e=l.replace(/^ctx\./,"").split("."),o=t;for(let t=0;t<e.length;t++){let n=e[t];t===e.length-1?o[n]=`{{${l}}}`:(o[n]=o[n]||{},o=o[n])}}return t}async render(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};try{return await this.parseAndRender(e,t)}catch(e){return console.error("[Liquid] 模板解析失败:",e),`<pre style="color:red;">Liquid 模板错误:${e.message}</pre>`}}isFieldUsed(e,t){return t.some(t=>t.replace(/^ctx\./,"").endsWith(e))}enrichArrayFieldsSelective(e,t){if(e&&"object"==typeof e)for(let l in e){let o=e[l];if(Array.isArray(o)&&o.length&&"object"==typeof o[0]){let e=o;Object.keys(e[0]).filter(o=>["string","number","boolean"].includes(typeof e[0][o])&&this.isFieldUsed(`${l}.${o}`,t)).forEach(t=>{e[t]=e.map(e=>null!=e[t]?e[t]:"").join(",")}),e.forEach(e=>this.enrichArrayFieldsSelective(e,t))}else o&&"object"==typeof o&&this.enrichArrayFieldsSelective(o,t)}}async renderWithFullContext(e,t){if(e)try{"number"==typeof e&&(e=String(e)),e=e.replace(/\{\{\s*t\s*\(\s*(['"])([\s\S]*?)\1\s*(?:,\s*\{\s*ns\s*:\s*(['"])([\s\S]*?)\3\s*\}\s*)?\)\s*\}\}/g,(e,l,o,n,i)=>{try{let e=i?t.t(o,{ns:i}):t.t(o);if(null==e)return"";return/[{][{%]/.test(e)?`{% raw %}${e}{% endraw %}`:e}catch{return e}});let l=await this.fullVariables(e),o=l.map(e=>this.transformLiquidContext([e])),n=(await Promise.all(o.map(e=>t.resolveJsonTemplate(e)))).reduce((e,t)=>(0,c.merge)(e,t),{});return this.enrichArrayFieldsSelective(n,l),await this.render(e,{ctx:n})}catch(t){return e}}constructor(e){super({extname:".liquid",cache:!0,...e}),this.registerFilter("t",e.ctx.t),this.registerFilter("log",e=>(console.log("[Liquid log]",e),e))}}let v1=()=>{let e=(0,u.useFlowEngine)({throwError:!1});if(!e)return{isMobileLayout:!1,setIsMobileLayout:()=>{}};let t=e.getModel(eX);return t?{isMobileLayout:t.isMobileLayout,setIsMobileLayout:t.setIsMobileLayout.bind(t)}:{isMobileLayout:!1,setIsMobileLayout:()=>{}}};function v2(e){let{flowEngine:t,pageUid:l,refreshDesktopRoutes:o,layoutContentRef:n}=e;return o$({flowEngine:t,pageUid:l,refreshDesktopRoutes:o,layoutContentRef:n,getLayoutModel:e=>oq(e,{required:!0})})}var v5=__webpack_require__(9652),v8=__webpack_require__(6681),v4=__webpack_require__(9784),v3=__webpack_require__(65);class v6 extends iz{async load(){this.app.addComponents({FlowRoute:oX}),this.app.flowEngine.setModelRepository(new vw(this.app));let e=Object.fromEntries(Object.entries(l).filter(e=>{let[,t]=e;return"function"==typeof t&&t.prototype instanceof u.FlowModel}));this.flowEngine.registerModels(e),this.flowEngine.registerActions(o),this.flowEngine.registerActions(t),this.flowEngine.flowSettings.registerComponents({IconPicker:ed.ar,DefaultValue:vx,FlowSettingsVariableTextArea:iU.n}),this.flowEngine.flowSettings.addToolbarItem({key:"dynamic-flows-editor",component:vA,visible:e=>e.getEvents().size>0,sort:0});let n=new vZ;this.flowEngine.context.defineProperty("markdown",{get:()=>n});let i=new v0({ctx:this.flowEngine.context});this.flowEngine.context.defineProperty("liquid",{get:()=>i}),this.flowEngine.context.defineMethod("previewRunJS",async function(e,t){let l=await Promise.resolve().then(__webpack_require__.bind(__webpack_require__,426));return await l.previewRunJS(String(e??""),this,{version:t})},{description:"Preview/diagnose a RunJS snippet (lint + sandbox execution).",detail:"(code: string, version?: string) => Promise<{ success: boolean; message: string }>",params:[{name:"code",type:"string",description:"RunJS code to preview."},{name:"version",type:"string",description:"RunJS version override (e.g. v1/v2)."}],returns:{type:"Promise<PreviewRunJSResult>",description:"Preview result."},completion:{insertText:"await ctx.previewRunJS('console.log(1)', 'v2')"}})}}let v9={"ar-EG":"ar","az-AZ":"az","bg-BG":"bg","bn-BD":"bn-bd","by-BY":"en","ca-ES":"ca","cs-CZ":"cs","da-DK":"da","de-DE":"de","el-GR":"el","en-GB":"en-gb","en-US":"en","es-ES":"es","et-EE":"et","fa-IR":"fa","fi-FI":"fi","fr-BE":"fr","fr-CA":"fr","fr-FR":"fr","ga-IE":"ga","gl-ES":"gl","he-IL":"he","hi-IN":"hi","hr-HR":"hr","hu-HU":"hu","hy-AM":"hy-am","id-ID":"id","is-IS":"is","it-IT":"it","ja-JP":"ja","ka-GE":"ka","kk-KZ":"kk","km-KH":"km","kn-IN":"kn","ko-KR":"ko","ku-IQ":"ku","lt-LT":"lt","lv-LV":"lv","mk-MK":"mk","ml-IN":"ml","mn-MN":"mn","ms-MY":"ms","nb-NO":"nb","ne-NP":"ne","nl-BE":"nl-be","nl-NL":"nl","pl-PL":"pl","pt-BR":"pt-br","pt-PT":"pt","ro-RO":"ro","ru-RU":"ru","si-LK":"si","sk-SK":"sk","sl-SI":"sl","sr-RS":"sr","sv-SE":"sv","ta-IN":"ta","th-TH":"th","tk-TK":"tk","tr-TR":"tr","uk-UA":"uk","ur-PK":"ur","vi-VN":"vi","zh-CN":"zh-cn","zh-HK":"zh-hk","zh-TW":"zh-tw"};class v7{atX0SecondsPastTheMinuteGt20(){return this.data.atX0SecondsPastTheMinuteGt20}atX0MinutesPastTheHourGt20(){return this.data.atX0MinutesPastTheHourGt20}commaMonthX0ThroughMonthX1(){return this.data.commaMonthX0ThroughMonthX1}commaYearX0ThroughYearX1(){return this.data.commaYearX0ThroughYearX1}use24HourTimeFormatByDefault(){return this.data.use24HourTimeFormatByDefault}anErrorOccuredWhenGeneratingTheExpressionD(){return this.data.anErrorOccuredWhenGeneratingTheExpressionD}everyMinute(){return this.data.everyMinute}everyHour(){return this.data.everyHour}atSpace(){return this.data.atSpace}everyMinuteBetweenX0AndX1(){return this.data.everyMinuteBetweenX0AndX1}at(){return this.data.at}spaceAnd(){return this.data.spaceAnd}everySecond(){return this.data.everySecond}everyX0Seconds(){return this.data.everyX0Seconds}secondsX0ThroughX1PastTheMinute(){return this.data.secondsX0ThroughX1PastTheMinute}atX0SecondsPastTheMinute(){return this.data.atX0SecondsPastTheMinute}everyX0Minutes(){return this.data.everyX0Minutes}minutesX0ThroughX1PastTheHour(){return this.data.minutesX0ThroughX1PastTheHour}atX0MinutesPastTheHour(){return this.data.atX0MinutesPastTheHour}everyX0Hours(){return this.data.everyX0Hours}betweenX0AndX1(){return this.data.betweenX0AndX1}atX0(){return this.data.atX0}commaEveryDay(){return this.data.commaEveryDay}commaEveryX0DaysOfTheWeek(){return this.data.commaEveryX0DaysOfTheWeek}commaX0ThroughX1(){return this.data.commaX0ThroughX1}commaAndX0ThroughX1(){return this.data.commaAndX0ThroughX1}first(){return this.data.first}second(){return this.data.second}third(){return this.data.third}fourth(){return this.data.fourth}fifth(){return this.data.fifth}commaOnThe(){return this.data.commaOnThe}spaceX0OfTheMonth(){return this.data.spaceX0OfTheMonth}lastDay(){return this.data.lastDay}commaOnTheLastX0OfTheMonth(){return this.data.commaOnTheLastX0OfTheMonth}commaOnlyOnX0(){return this.data.commaOnlyOnX0}commaAndOnX0(){return this.data.commaAndOnX0}commaEveryX0Months(){return this.data.commaEveryX0Months}commaOnlyInX0(){return this.data.commaOnlyInX0}commaOnTheLastDayOfTheMonth(){return this.data.commaOnTheLastDayOfTheMonth}commaOnTheLastWeekdayOfTheMonth(){return this.data.commaOnTheLastWeekdayOfTheMonth}commaDaysBeforeTheLastDayOfTheMonth(){return this.data.commaDaysBeforeTheLastDayOfTheMonth}firstWeekday(){return this.data.firstWeekday}weekdayNearestDayX0(){return this.data.weekdayNearestDayX0}commaOnTheX0OfTheMonth(){return this.data.commaOnTheX0OfTheMonth}commaEveryX0Days(){return this.data.commaEveryX0Days}commaBetweenDayX0AndX1OfTheMonth(){return this.data.commaBetweenDayX0AndX1OfTheMonth}commaOnDayX0OfTheMonth(){return this.data.commaOnDayX0OfTheMonth}commaEveryHour(){return this.data.commaEveryHour}commaEveryX0Years(){return this.data.commaEveryX0Years}commaStartingX0(){return this.data.commaStartingX0}daysOfTheWeek(){return this.data.daysOfTheWeek}monthsOfTheYear(){return this.data.monthsOfTheYear}constructor(e){this.data=e}}let _e=e=>{(__rspack_external_cronstrue.default.default?__rspack_external_cronstrue.default.default:__rspack_external_cronstrue.default).initialize({load(t){t[null==e?void 0:e.lang]=new v7(null==e?void 0:e.cronstrue)}})};class _t extends iz{async afterAdd(){let e=this.app.apiClient,t=e.auth.locale;try{var l;let o=await e.request({url:"app:getLang",params:{locale:t},headers:{"X-Role":"anonymous"}}),n=(null==o||null==(l=o.data)?void 0:l.data)||{};this.engine.context.defineProperty("locales",{value:n}),this.app.use(g.App,{component:!1}),n.lang&&(e.auth.setLocale(n.lang),this.app.setDocumentLanguage(n.lang),this.app.i18n.changeLanguage(n.lang)),Object.keys(n.resources||{}).forEach(e=>{this.app.i18n.addResources(n.lang,e,n.resources[e]||{})}),(0,__rspack_external__formily_validator_5f6f1884.setValidateLanguage)(n.lang),_e(n);let i=v9[n.lang]||"en";await __webpack_require__(8817)(`./${i}`),m6.default.locale(i),window.cronLocale=n.cron}catch(e){throw e}}}let _l=["/signin","/signup","/forgot-password","/reset-password"];function _o(e,t){if(!t)return e;let l=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=RegExp(`^${l.replace(/\/?$/,"")}(\\/|$)`);return e.replace(o,"/")||e}function _n(e,t){let l=_o(e,t);return _l.some(e=>l===e||l.startsWith(`${e}/`))}function _i(e,t){let l=_o(e,t);return"/admin"===l||l.startsWith("/admin/")}function _r(e,t){return(e.router.matchRoutes(t)||[]).some(e=>{var t;return(null==e||null==(t=e.route)?void 0:t.authCheck)===!0})}function _a(e,t){return _i(t,e.router.getBasename())||_r(e,t)}function _s(e,t){return _n(t,e.router.getBasename())||e.router.isSkippedAuthCheckRoute(t)?"skipped":_a(e,t)?"required":"unchecked"}let _d=(0,p.createContext)(null);function _u(){return(0,p.useContext)(_d)}function _c(){var e,t;let{allowAnonymous:l}=(0,lg.v6)(),o=(0,u.useFlowEngine)(),n=null==o||null==(t=o.context)||null==(e=t.user)?void 0:e.roles;return(0,p.useMemo)(()=>{let e=e=>{var t;return null==e?"":(null==o||null==(t=o.context)?void 0:t.t)?o.context.t(e):e},t=(n||[]).filter(e=>(null==e?void 0:e.name)!=="__union__").map(t=>({name:t.name,title:e(t.title)}));return l&&t.push({name:"anonymous",title:"Anonymous"}),t},[l,o,n])}_d.displayName="CurrentUserContext";let _p=e=>{let{children:t}=e,l=(0,f.n)(),o=(0,h.useLocation)(),[n,i]=(0,p.useState)(!0),[r,a]=(0,p.useState)(null),d=(0,p.useRef)(!1);if((0,p.useEffect)(()=>{let e=!0,t=l.router.getBasename(),n=_n(o.pathname,t)||l.router.isSkippedAuthCheckRoute(o.pathname),r=_a(l,o.pathname);if(n||!r){i(!1),a(null);return}return d.current||i(!0),a(null),(async()=>{try{await l.dataSourceManager.ensureLoaded(),d.current=!0,e&&i(!1)}catch(t){if(!e)return;i(!1),a(t instanceof Error?t:Error(String(t)))}})(),()=>{e=!1}},[l,o.pathname]),r)throw r;return n?l.renderComponent("AppSpin"):(0,s.jsx)(s.Fragment,{children:t})},_m=e=>{let{children:t}=e,l=(0,f.n)(),o=(0,h.useLocation)(),n=(0,h.useNavigate)(),[i,r]=(0,p.useState)({loading:!0,authStatus:"unknown"}),a=(0,p.useRef)(o);a.current=o;let d=_s(l,o.pathname),c="required"===d&&"authenticated"!==i.authStatus,m=(0,p.useMemo)(()=>({data:i.data,loading:i.loading}),[i.data,i.loading]);if((0,p.useEffect)(()=>{let e=!0;return"required"!==d?void r({loading:!1,authStatus:"unauthenticated",error:null}):(r(e=>"authenticated"===e.authStatus?e:{data:e.data,loading:!0,authStatus:"unknown",error:null}),(async()=>{var t,o;try{let o=await l.apiClient.request({url:"/auth:check",skipNotify:!0,skipAuth:!0});if(!e)return;let i=null==o||null==(t=o.data)?void 0:t.data;if((null==i?void 0:i.code)===302)return void r({loading:!1,authStatus:"redirecting",error:null});if((null==i?void 0:i.id)==null){r({loading:!0,authStatus:"unauthenticated",error:null}),n(`/signin?redirect=${encodeURIComponent(eT(l,a.current))}`,{replace:!0});return}let s=(0,u.createCollectionContextMeta)(()=>{var e,t;return(null==(t=l.flowEngine.context.dataSourceManager)||null==(e=t.getDataSource("main"))?void 0:e.getCollection("users"))||null},l.flowEngine.translate("Current user"));s.sort=1e3,l.flowEngine.context.defineProperty("user",{value:i,resolveOnServer:!0,meta:s}),r({data:null==o?void 0:o.data,loading:!1,authStatus:"authenticated",error:null})}catch(i){if(!e)return;let t=i;if((null==t||null==(o=t.response)?void 0:o.status)===401||(null==t?void 0:t.status)===401){r({loading:!0,authStatus:"unauthenticated",error:null}),n(`/signin?redirect=${encodeURIComponent(eT(l,a.current))}`,{replace:!0});return}r({loading:!1,authStatus:"unknown",error:i instanceof Error?i:Error(String(i))})}})(),()=>{e=!1})},[l,d,n]),i.error)throw i.error;return i.loading||c?l.renderComponent("AppSpin"):(0,s.jsx)(_d.Provider,{value:m,children:t})},_h=()=>{var e,t;let l=(0,f.n)(),o=!!(null==l||null==(t=l.apiClient)||null==(e=t.auth)?void 0:e.token),n=eP(l);return o?(0,s.jsx)(h.Navigate,{replace:!0,to:"/admin"}):(0,s.jsx)(h.Navigate,{replace:!0,to:`/signin?redirect=${encodeURIComponent(n)}`})};class _f extends iz{async afterAdd(){await this.addPlugins()}async load(){this.addComponents(),this.addRoutes(),this.app.use(_m),this.app.use(_p),this.app.flowEngine.registerModels({AdminLayoutModel:oV,AdminLayoutMenuItemModel:t9,AdminSettingsLayoutModel:v8.C}),this.app.layoutManager.registerLayout({routeName:"admin",routePath:"/admin",uid:eX,layoutModelClass:"AdminLayoutModel"}),this.app.pluginSettingsManager.addMenuItem({key:"plugin-manager",title:this.app.i18n.t("Plugin manager"),icon:"ApiOutlined",aclSnippet:"pm",sort:-200}),this.app.pluginSettingsManager.addPageTabItem({menuKey:"plugin-manager",key:"index",title:this.app.i18n.t("Plugin manager"),componentLoader:()=>Promise.resolve().then(__webpack_require__.bind(__webpack_require__,9784)),aclSnippet:"pm",sort:-200}),this.app.pluginSettingsManager.addMenuItem({key:"system-settings",title:this.app.i18n.t("System settings"),icon:"SettingOutlined",aclSnippet:"pm.system-settings.system-settings",sort:-100}),this.app.pluginSettingsManager.addPageTabItem({menuKey:"system-settings",key:"index",title:this.app.i18n.t("System settings"),componentLoader:()=>Promise.resolve().then(__webpack_require__.bind(__webpack_require__,65)),aclSnippet:"pm.system-settings.system-settings",sort:-100}),this.app.pluginSettingsManager.addMenuItem({key:"security",title:this.app.i18n.t("Security"),icon:"SafetyOutlined",aclSnippet:"pm.security"})}addRoutes(){this.router.add("root",{path:"/",element:(0,s.jsx)(_h,{})}),this.router.add("not-found",{path:"*",Component:I.bM}),this.router.add("admin.settings",{path:"/admin/settings",componentLoader:()=>Promise.resolve().then(__webpack_require__.bind(__webpack_require__,9652))}),this.router.add("admin.settings.route-empty",{path:"*",Component:h.Outlet})}addComponents(){}async addPlugins(){await this.app.pm.add(v6),await this.app.pm.add(_t,{name:"builtin-locale"})}}var _g=__webpack_require__(5026);let _y={type:"boolean","x-content":'{{t("Unique")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly || primaryKeyOnly }}"},_v={type:"boolean","x-content":'{{t("Primary")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly || primaryKeyOnly }}"},__={type:"boolean",title:'{{t("Auto increment")}}',"x-content":'{{t("Auto increment")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly }}"},_b={type:"boolean",title:'{{t("Default value")}}',"x-content":'{{t("Automatically generate default values")}}',"x-decorator":"FormItem","x-component":"Checkbox",default:!0},_x={type:"string",title:'{{t("Relationship type")}}',required:!0,"x-disabled":!0,"x-decorator":"FormItem","x-component":"Select",enum:[{label:"{{t('HasOne')}}",value:"hasOne"},{label:"{{t('HasMany')}}",value:"hasMany"},{label:"{{t('BelongsTo')}}",value:"belongsTo"},{label:"{{t('BelongsToMany')}}",value:"belongsToMany"}]},_M={onDelete:{type:"string",title:'{{t("ON DELETE")}}',required:!0,default:"SET NULL","x-disabled":"{{ !createOnly }}","x-decorator":"FormItem","x-component":"Select",enum:[{label:"{{t('SET NULL')}}",value:"SET NULL"},{label:"{{t('RESTRICT')}}",value:"RESTRICT"},{label:"{{t('CASCADE')}}",value:"CASCADE"},{label:"{{t('NO ACTION')}}",value:"NO ACTION"}]}},_w={reverse:{type:"void","x-component":"div",properties:{autoCreateReverseField:{type:"boolean",default:!1,"x-decorator":"FormItem","x-component":"Checkbox","x-content":'{{t("Create inverse field in the target collection")}}'},"reverseField.type":{..._x,title:'{{t("Inverse relationship type")}}'},"reverseField.uiSchema.title":{type:"string",title:'{{t("Inverse field display name")}}',default:"{{record.title}}",required:!0,"x-decorator":"FormItem","x-component":"Input","x-disabled":"{{ !showReverseFieldConfig }}"},"reverseField.name":{type:"string",title:'{{t("Inverse field name")}}',required:!0,"x-decorator":"FormItem","x-component":"Input","x-validator":"uid","x-disabled":"{{ !showReverseFieldConfig }}",description:"{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}"}}}},_S={"uiSchema.x-component-props.picker":{type:"string",title:'{{t("Picker")}}',"x-decorator":"FormItem","x-component":"Radio.Group",default:"date",enum:[{label:'{{t("Date")}}',value:"date"},{label:'{{t("Month")}}',value:"month"},{label:'{{t("Quarter")}}',value:"quarter"},{label:'{{t("Year")}}',value:"year"}]},"uiSchema.x-component-props.dateFormat":{type:"string",title:'{{t("Date format")}}',"x-decorator":"FormItem","x-component":"ExpiresRadio","x-decorator-props":{},"x-component-props":{className:(0,S.css)`
1244
1244
  .ant-radio-wrapper {
1245
1245
  display: flex;
1246
1246
  margin: 5px 0px;
package/lib/index.js CHANGED
@@ -1240,7 +1240,7 @@ ctx.render(<JsItem />);
1240
1240
  border-top-color: transparent;
1241
1241
  background-color: transparent;
1242
1242
  }
1243
- `,children:"x"})})})]})};class vZ{render(e,t){if(!e)return null;try{return(0,s.jsx)(vU,{value:e,...t})}catch(e){return console.error("渲染失败:",e),(0,s.jsxs)("pre",{style:{color:"red"},children:["Markdown 渲染错误:",e.message]})}}edit(e){try{return(0,s.jsx)(vQ,{...e})}catch(e){return(0,s.jsxs)("pre",{style:{color:"red"},children:["Markdown 编辑器加载错误:",e.message]})}}}class v0 extends liquidjs__rspack_import_80.Liquid{transformLiquidContext(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t={};for(let l of e){let e=l.replace(/^ctx\./,"").split("."),o=t;for(let t=0;t<e.length;t++){let n=e[t];t===e.length-1?o[n]=`{{${l}}}`:(o[n]=o[n]||{},o=o[n])}}return t}async render(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};try{return await this.parseAndRender(e,t)}catch(e){return console.error("[Liquid] 模板解析失败:",e),`<pre style="color:red;">Liquid 模板错误:${e.message}</pre>`}}isFieldUsed(e,t){return t.some(t=>t.replace(/^ctx\./,"").endsWith(e))}enrichArrayFieldsSelective(e,t){if(e&&"object"==typeof e)for(let l in e){let o=e[l];if(Array.isArray(o)&&o.length&&"object"==typeof o[0]){let e=o;Object.keys(e[0]).filter(o=>["string","number","boolean"].includes(typeof e[0][o])&&this.isFieldUsed(`${l}.${o}`,t)).forEach(t=>{e[t]=e.map(e=>null!=e[t]?e[t]:"").join(",")}),e.forEach(e=>this.enrichArrayFieldsSelective(e,t))}else o&&"object"==typeof o&&this.enrichArrayFieldsSelective(o,t)}}async renderWithFullContext(e,t){if(e)try{"number"==typeof e&&(e=String(e)),e=e.replace(/\{\{\s*t\s*\(\s*(['"])([\s\S]*?)\1\s*(?:,\s*\{\s*ns\s*:\s*(['"])([\s\S]*?)\3\s*\}\s*)?\)\s*\}\}/g,(e,l,o,n,i)=>{try{let e=i?t.t(o,{ns:i}):t.t(o);if(null==e)return"";return/[{][{%]/.test(e)?`{% raw %}${e}{% endraw %}`:e}catch{return e}});let l=await this.fullVariables(e),o=l.map(e=>this.transformLiquidContext([e])),n=(await Promise.all(o.map(e=>t.resolveJsonTemplate(e)))).reduce((e,t)=>(0,c.merge)(e,t),{});return this.enrichArrayFieldsSelective(n,l),await this.render(e,{ctx:n})}catch(t){return e}}constructor(e){super({extname:".liquid",cache:!0,...e}),this.registerFilter("t",e.ctx.t),this.registerFilter("log",e=>(console.log("[Liquid log]",e),e))}}let v1=()=>{let e=(0,u.useFlowEngine)({throwError:!1});if(!e)return{isMobileLayout:!1,setIsMobileLayout:()=>{}};let t=e.getModel(eX);return t?{isMobileLayout:t.isMobileLayout,setIsMobileLayout:t.setIsMobileLayout.bind(t)}:{isMobileLayout:!1,setIsMobileLayout:()=>{}}};function v2(e){let{flowEngine:t,pageUid:l,refreshDesktopRoutes:o,layoutContentRef:n}=e;return o$({flowEngine:t,pageUid:l,refreshDesktopRoutes:o,layoutContentRef:n,getLayoutModel:e=>oq(e,{required:!0})})}var v5=__nested_rspack_require_1176521__(9652),v8=__nested_rspack_require_1176521__(6681),v4=__nested_rspack_require_1176521__(9784),v3=__nested_rspack_require_1176521__(65);class v6 extends iz{async load(){this.app.addComponents({FlowRoute:oX}),this.app.flowEngine.setModelRepository(new vS(this.app));let e=Object.fromEntries(Object.entries(l).filter(e=>{let[,t]=e;return"function"==typeof t&&t.prototype instanceof u.FlowModel}));this.flowEngine.registerModels(e),this.flowEngine.registerActions(o),this.flowEngine.registerActions(t),this.flowEngine.flowSettings.registerComponents({IconPicker:ed.ar,DefaultValue:vM,FlowSettingsVariableTextArea:iK.n}),this.flowEngine.flowSettings.addToolbarItem({key:"dynamic-flows-editor",component:vA,visible:e=>e.getEvents().size>0,sort:0});let n=new vZ;this.flowEngine.context.defineProperty("markdown",{get:()=>n});let i=new v0({ctx:this.flowEngine.context});this.flowEngine.context.defineProperty("liquid",{get:()=>i}),this.flowEngine.context.defineMethod("previewRunJS",async function(e,t){let l=await Promise.resolve().then(__nested_rspack_require_1176521__.bind(__nested_rspack_require_1176521__,426));return await l.previewRunJS(String(e??""),this,{version:t})},{description:"Preview/diagnose a RunJS snippet (lint + sandbox execution).",detail:"(code: string, version?: string) => Promise<{ success: boolean; message: string }>",params:[{name:"code",type:"string",description:"RunJS code to preview."},{name:"version",type:"string",description:"RunJS version override (e.g. v1/v2)."}],returns:{type:"Promise<PreviewRunJSResult>",description:"Preview result."},completion:{insertText:"await ctx.previewRunJS('console.log(1)', 'v2')"}})}}let v9={"ar-EG":"ar","az-AZ":"az","bg-BG":"bg","bn-BD":"bn-bd","by-BY":"en","ca-ES":"ca","cs-CZ":"cs","da-DK":"da","de-DE":"de","el-GR":"el","en-GB":"en-gb","en-US":"en","es-ES":"es","et-EE":"et","fa-IR":"fa","fi-FI":"fi","fr-BE":"fr","fr-CA":"fr","fr-FR":"fr","ga-IE":"ga","gl-ES":"gl","he-IL":"he","hi-IN":"hi","hr-HR":"hr","hu-HU":"hu","hy-AM":"hy-am","id-ID":"id","is-IS":"is","it-IT":"it","ja-JP":"ja","ka-GE":"ka","kk-KZ":"kk","km-KH":"km","kn-IN":"kn","ko-KR":"ko","ku-IQ":"ku","lt-LT":"lt","lv-LV":"lv","mk-MK":"mk","ml-IN":"ml","mn-MN":"mn","ms-MY":"ms","nb-NO":"nb","ne-NP":"ne","nl-BE":"nl-be","nl-NL":"nl","pl-PL":"pl","pt-BR":"pt-br","pt-PT":"pt","ro-RO":"ro","ru-RU":"ru","si-LK":"si","sk-SK":"sk","sl-SI":"sl","sr-RS":"sr","sv-SE":"sv","ta-IN":"ta","th-TH":"th","tk-TK":"tk","tr-TR":"tr","uk-UA":"uk","ur-PK":"ur","vi-VN":"vi","zh-CN":"zh-cn","zh-HK":"zh-hk","zh-TW":"zh-tw"};class v7{atX0SecondsPastTheMinuteGt20(){return this.data.atX0SecondsPastTheMinuteGt20}atX0MinutesPastTheHourGt20(){return this.data.atX0MinutesPastTheHourGt20}commaMonthX0ThroughMonthX1(){return this.data.commaMonthX0ThroughMonthX1}commaYearX0ThroughYearX1(){return this.data.commaYearX0ThroughYearX1}use24HourTimeFormatByDefault(){return this.data.use24HourTimeFormatByDefault}anErrorOccuredWhenGeneratingTheExpressionD(){return this.data.anErrorOccuredWhenGeneratingTheExpressionD}everyMinute(){return this.data.everyMinute}everyHour(){return this.data.everyHour}atSpace(){return this.data.atSpace}everyMinuteBetweenX0AndX1(){return this.data.everyMinuteBetweenX0AndX1}at(){return this.data.at}spaceAnd(){return this.data.spaceAnd}everySecond(){return this.data.everySecond}everyX0Seconds(){return this.data.everyX0Seconds}secondsX0ThroughX1PastTheMinute(){return this.data.secondsX0ThroughX1PastTheMinute}atX0SecondsPastTheMinute(){return this.data.atX0SecondsPastTheMinute}everyX0Minutes(){return this.data.everyX0Minutes}minutesX0ThroughX1PastTheHour(){return this.data.minutesX0ThroughX1PastTheHour}atX0MinutesPastTheHour(){return this.data.atX0MinutesPastTheHour}everyX0Hours(){return this.data.everyX0Hours}betweenX0AndX1(){return this.data.betweenX0AndX1}atX0(){return this.data.atX0}commaEveryDay(){return this.data.commaEveryDay}commaEveryX0DaysOfTheWeek(){return this.data.commaEveryX0DaysOfTheWeek}commaX0ThroughX1(){return this.data.commaX0ThroughX1}commaAndX0ThroughX1(){return this.data.commaAndX0ThroughX1}first(){return this.data.first}second(){return this.data.second}third(){return this.data.third}fourth(){return this.data.fourth}fifth(){return this.data.fifth}commaOnThe(){return this.data.commaOnThe}spaceX0OfTheMonth(){return this.data.spaceX0OfTheMonth}lastDay(){return this.data.lastDay}commaOnTheLastX0OfTheMonth(){return this.data.commaOnTheLastX0OfTheMonth}commaOnlyOnX0(){return this.data.commaOnlyOnX0}commaAndOnX0(){return this.data.commaAndOnX0}commaEveryX0Months(){return this.data.commaEveryX0Months}commaOnlyInX0(){return this.data.commaOnlyInX0}commaOnTheLastDayOfTheMonth(){return this.data.commaOnTheLastDayOfTheMonth}commaOnTheLastWeekdayOfTheMonth(){return this.data.commaOnTheLastWeekdayOfTheMonth}commaDaysBeforeTheLastDayOfTheMonth(){return this.data.commaDaysBeforeTheLastDayOfTheMonth}firstWeekday(){return this.data.firstWeekday}weekdayNearestDayX0(){return this.data.weekdayNearestDayX0}commaOnTheX0OfTheMonth(){return this.data.commaOnTheX0OfTheMonth}commaEveryX0Days(){return this.data.commaEveryX0Days}commaBetweenDayX0AndX1OfTheMonth(){return this.data.commaBetweenDayX0AndX1OfTheMonth}commaOnDayX0OfTheMonth(){return this.data.commaOnDayX0OfTheMonth}commaEveryHour(){return this.data.commaEveryHour}commaEveryX0Years(){return this.data.commaEveryX0Years}commaStartingX0(){return this.data.commaStartingX0}daysOfTheWeek(){return this.data.daysOfTheWeek}monthsOfTheYear(){return this.data.monthsOfTheYear}constructor(e){this.data=e}}let be=e=>{(cronstrue__rspack_import_82_default().default?cronstrue__rspack_import_82_default().default:cronstrue__rspack_import_82_default()).initialize({load(t){t[null==e?void 0:e.lang]=new v7(null==e?void 0:e.cronstrue)}})};class bt extends iz{async afterAdd(){let e=this.app.apiClient,t=e.auth.locale;try{var l;let o=await e.request({url:"app:getLang",params:{locale:t},headers:{"X-Role":"anonymous"}}),n=(null==o||null==(l=o.data)?void 0:l.data)||{};this.engine.context.defineProperty("locales",{value:n}),this.app.use(g.App,{component:!1}),n.lang&&(e.auth.setLocale(n.lang),this.app.setDocumentLanguage(n.lang),this.app.i18n.changeLanguage(n.lang)),Object.keys(n.resources||{}).forEach(e=>{this.app.i18n.addResources(n.lang,e,n.resources[e]||{})}),(0,_formily_validator__rspack_import_81.setValidateLanguage)(n.lang),be(n);let i=v9[n.lang]||"en";await __nested_rspack_require_1176521__(8817)(`./${i}`),m6.default.locale(i),window.cronLocale=n.cron}catch(e){throw e}}}let bl=["/signin","/signup","/forgot-password","/reset-password"];function bo(e,t){if(!t)return e;let l=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=RegExp(`^${l.replace(/\/?$/,"")}(\\/|$)`);return e.replace(o,"/")||e}function bn(e,t){let l=bo(e,t);return bl.some(e=>l===e||l.startsWith(`${e}/`))}function bi(e,t){let l=bo(e,t);return"/admin"===l||l.startsWith("/admin/")}function br(e,t){return(e.router.matchRoutes(t)||[]).some(e=>{var t;return(null==e||null==(t=e.route)?void 0:t.authCheck)===!0})}function ba(e,t){return bi(t,e.router.getBasename())||br(e,t)}function bs(e,t){return bn(t,e.router.getBasename())||e.router.isSkippedAuthCheckRoute(t)?"skipped":ba(e,t)?"required":"unchecked"}let bd=(0,p.createContext)(null);function bu(){return(0,p.useContext)(bd)}function bc(){var e,t;let{allowAnonymous:l}=(0,lg.v6)(),o=(0,u.useFlowEngine)(),n=null==o||null==(t=o.context)||null==(e=t.user)?void 0:e.roles;return(0,p.useMemo)(()=>{let e=e=>{var t;return null==e?"":(null==o||null==(t=o.context)?void 0:t.t)?o.context.t(e):e},t=(n||[]).filter(e=>(null==e?void 0:e.name)!=="__union__").map(t=>({name:t.name,title:e(t.title)}));return l&&t.push({name:"anonymous",title:"Anonymous"}),t},[l,o,n])}bd.displayName="CurrentUserContext";let bp=e=>{let{children:t}=e,l=(0,f.n)(),o=(0,h.useLocation)(),[n,i]=(0,p.useState)(!0),[r,a]=(0,p.useState)(null),d=(0,p.useRef)(!1);if((0,p.useEffect)(()=>{let e=!0,t=l.router.getBasename(),n=bn(o.pathname,t)||l.router.isSkippedAuthCheckRoute(o.pathname),r=ba(l,o.pathname);if(n||!r){i(!1),a(null);return}return d.current||i(!0),a(null),(async()=>{try{await l.dataSourceManager.ensureLoaded(),d.current=!0,e&&i(!1)}catch(t){if(!e)return;i(!1),a(t instanceof Error?t:Error(String(t)))}})(),()=>{e=!1}},[l,o.pathname]),r)throw r;return n?l.renderComponent("AppSpin"):(0,s.jsx)(s.Fragment,{children:t})},bm=e=>{let{children:t}=e,l=(0,f.n)(),o=(0,h.useLocation)(),n=(0,h.useNavigate)(),[i,r]=(0,p.useState)({loading:!0}),a=(0,p.useRef)(o);a.current=o;let d=bs(l,o.pathname);return((0,p.useEffect)(()=>{let e=!0;return"required"!==d?void r({loading:!1}):(r(e=>e.loading?e:{...e,loading:!0}),(async()=>{var t,o;try{let o=await l.apiClient.request({url:"/auth:check",skipNotify:!0,skipAuth:!0});if(!e)return;let i=null==o||null==(t=o.data)?void 0:t.data;if((null==i?void 0:i.code)===302)return void r({loading:!1});if((null==i?void 0:i.id)==null)return void n(`/signin?redirect=${encodeURIComponent(eT(l,a.current))}`,{replace:!0});let s=(0,u.createCollectionContextMeta)(()=>{var e,t;return(null==(t=l.flowEngine.context.dataSourceManager)||null==(e=t.getDataSource("main"))?void 0:e.getCollection("users"))||null},l.flowEngine.translate("Current user"));s.sort=1e3,l.flowEngine.context.defineProperty("user",{value:i,resolveOnServer:!0,meta:s}),r({data:null==o?void 0:o.data,loading:!1})}catch(t){if(!e)return;if((null==t||null==(o=t.response)?void 0:o.status)===401||(null==t?void 0:t.status)===401)return void n(`/signin?redirect=${encodeURIComponent(eT(l,a.current))}`,{replace:!0});throw r({loading:!1}),t}})(),()=>{e=!1})},[l,d,n]),i.loading)?l.renderComponent("AppSpin"):(0,s.jsx)(bd.Provider,{value:i,children:t})},bh=()=>{var e,t;let l=(0,f.n)(),o=!!(null==l||null==(t=l.apiClient)||null==(e=t.auth)?void 0:e.token),n=eP(l);return o?(0,s.jsx)(h.Navigate,{replace:!0,to:"/admin"}):(0,s.jsx)(h.Navigate,{replace:!0,to:`/signin?redirect=${encodeURIComponent(n)}`})};class bf extends iz{async afterAdd(){await this.addPlugins()}async load(){this.addComponents(),this.addRoutes(),this.app.use(bp),this.app.use(bm),this.app.flowEngine.registerModels({AdminLayoutModel:oH,AdminLayoutMenuItemModel:t9,AdminSettingsLayoutModel:v8.C}),this.app.layoutManager.registerLayout({routeName:"admin",routePath:"/admin",uid:eX,layoutModelClass:"AdminLayoutModel"}),this.app.pluginSettingsManager.addMenuItem({key:"plugin-manager",title:this.app.i18n.t("Plugin manager"),icon:"ApiOutlined",aclSnippet:"pm",sort:-200}),this.app.pluginSettingsManager.addPageTabItem({menuKey:"plugin-manager",key:"index",title:this.app.i18n.t("Plugin manager"),componentLoader:()=>Promise.resolve().then(__nested_rspack_require_1176521__.bind(__nested_rspack_require_1176521__,9784)),aclSnippet:"pm",sort:-200}),this.app.pluginSettingsManager.addMenuItem({key:"system-settings",title:this.app.i18n.t("System settings"),icon:"SettingOutlined",aclSnippet:"pm.system-settings.system-settings",sort:-100}),this.app.pluginSettingsManager.addPageTabItem({menuKey:"system-settings",key:"index",title:this.app.i18n.t("System settings"),componentLoader:()=>Promise.resolve().then(__nested_rspack_require_1176521__.bind(__nested_rspack_require_1176521__,65)),aclSnippet:"pm.system-settings.system-settings",sort:-100}),this.app.pluginSettingsManager.addMenuItem({key:"security",title:this.app.i18n.t("Security"),icon:"SafetyOutlined",aclSnippet:"pm.security"})}addRoutes(){this.router.add("root",{path:"/",element:(0,s.jsx)(bh,{})}),this.router.add("not-found",{path:"*",Component:j.bM}),this.router.add("admin.settings",{path:"/admin/settings",componentLoader:()=>Promise.resolve().then(__nested_rspack_require_1176521__.bind(__nested_rspack_require_1176521__,9652))}),this.router.add("admin.settings.route-empty",{path:"*",Component:h.Outlet})}addComponents(){}async addPlugins(){await this.app.pm.add(v6),await this.app.pm.add(bt,{name:"builtin-locale"})}}var bg=__nested_rspack_require_1176521__(5026);let by={type:"boolean","x-content":'{{t("Unique")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly || primaryKeyOnly }}"},bv={type:"boolean","x-content":'{{t("Primary")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly || primaryKeyOnly }}"},bb={type:"boolean",title:'{{t("Auto increment")}}',"x-content":'{{t("Auto increment")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly }}"},bx={type:"boolean",title:'{{t("Default value")}}',"x-content":'{{t("Automatically generate default values")}}',"x-decorator":"FormItem","x-component":"Checkbox",default:!0},bM={type:"string",title:'{{t("Relationship type")}}',required:!0,"x-disabled":!0,"x-decorator":"FormItem","x-component":"Select",enum:[{label:"{{t('HasOne')}}",value:"hasOne"},{label:"{{t('HasMany')}}",value:"hasMany"},{label:"{{t('BelongsTo')}}",value:"belongsTo"},{label:"{{t('BelongsToMany')}}",value:"belongsToMany"}]},b_={onDelete:{type:"string",title:'{{t("ON DELETE")}}',required:!0,default:"SET NULL","x-disabled":"{{ !createOnly }}","x-decorator":"FormItem","x-component":"Select",enum:[{label:"{{t('SET NULL')}}",value:"SET NULL"},{label:"{{t('RESTRICT')}}",value:"RESTRICT"},{label:"{{t('CASCADE')}}",value:"CASCADE"},{label:"{{t('NO ACTION')}}",value:"NO ACTION"}]}},bS={reverse:{type:"void","x-component":"div",properties:{autoCreateReverseField:{type:"boolean",default:!1,"x-decorator":"FormItem","x-component":"Checkbox","x-content":'{{t("Create inverse field in the target collection")}}'},"reverseField.type":{...bM,title:'{{t("Inverse relationship type")}}'},"reverseField.uiSchema.title":{type:"string",title:'{{t("Inverse field display name")}}',default:"{{record.title}}",required:!0,"x-decorator":"FormItem","x-component":"Input","x-disabled":"{{ !showReverseFieldConfig }}"},"reverseField.name":{type:"string",title:'{{t("Inverse field name")}}',required:!0,"x-decorator":"FormItem","x-component":"Input","x-validator":"uid","x-disabled":"{{ !showReverseFieldConfig }}",description:"{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}"}}}},bw={"uiSchema.x-component-props.picker":{type:"string",title:'{{t("Picker")}}',"x-decorator":"FormItem","x-component":"Radio.Group",default:"date",enum:[{label:'{{t("Date")}}',value:"date"},{label:'{{t("Month")}}',value:"month"},{label:'{{t("Quarter")}}',value:"quarter"},{label:'{{t("Year")}}',value:"year"}]},"uiSchema.x-component-props.dateFormat":{type:"string",title:'{{t("Date format")}}',"x-decorator":"FormItem","x-component":"ExpiresRadio","x-decorator-props":{},"x-component-props":{className:(0,w.css)`
1243
+ `,children:"x"})})})]})};class vZ{render(e,t){if(!e)return null;try{return(0,s.jsx)(vU,{value:e,...t})}catch(e){return console.error("渲染失败:",e),(0,s.jsxs)("pre",{style:{color:"red"},children:["Markdown 渲染错误:",e.message]})}}edit(e){try{return(0,s.jsx)(vQ,{...e})}catch(e){return(0,s.jsxs)("pre",{style:{color:"red"},children:["Markdown 编辑器加载错误:",e.message]})}}}class v0 extends liquidjs__rspack_import_80.Liquid{transformLiquidContext(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t={};for(let l of e){let e=l.replace(/^ctx\./,"").split("."),o=t;for(let t=0;t<e.length;t++){let n=e[t];t===e.length-1?o[n]=`{{${l}}}`:(o[n]=o[n]||{},o=o[n])}}return t}async render(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};try{return await this.parseAndRender(e,t)}catch(e){return console.error("[Liquid] 模板解析失败:",e),`<pre style="color:red;">Liquid 模板错误:${e.message}</pre>`}}isFieldUsed(e,t){return t.some(t=>t.replace(/^ctx\./,"").endsWith(e))}enrichArrayFieldsSelective(e,t){if(e&&"object"==typeof e)for(let l in e){let o=e[l];if(Array.isArray(o)&&o.length&&"object"==typeof o[0]){let e=o;Object.keys(e[0]).filter(o=>["string","number","boolean"].includes(typeof e[0][o])&&this.isFieldUsed(`${l}.${o}`,t)).forEach(t=>{e[t]=e.map(e=>null!=e[t]?e[t]:"").join(",")}),e.forEach(e=>this.enrichArrayFieldsSelective(e,t))}else o&&"object"==typeof o&&this.enrichArrayFieldsSelective(o,t)}}async renderWithFullContext(e,t){if(e)try{"number"==typeof e&&(e=String(e)),e=e.replace(/\{\{\s*t\s*\(\s*(['"])([\s\S]*?)\1\s*(?:,\s*\{\s*ns\s*:\s*(['"])([\s\S]*?)\3\s*\}\s*)?\)\s*\}\}/g,(e,l,o,n,i)=>{try{let e=i?t.t(o,{ns:i}):t.t(o);if(null==e)return"";return/[{][{%]/.test(e)?`{% raw %}${e}{% endraw %}`:e}catch{return e}});let l=await this.fullVariables(e),o=l.map(e=>this.transformLiquidContext([e])),n=(await Promise.all(o.map(e=>t.resolveJsonTemplate(e)))).reduce((e,t)=>(0,c.merge)(e,t),{});return this.enrichArrayFieldsSelective(n,l),await this.render(e,{ctx:n})}catch(t){return e}}constructor(e){super({extname:".liquid",cache:!0,...e}),this.registerFilter("t",e.ctx.t),this.registerFilter("log",e=>(console.log("[Liquid log]",e),e))}}let v1=()=>{let e=(0,u.useFlowEngine)({throwError:!1});if(!e)return{isMobileLayout:!1,setIsMobileLayout:()=>{}};let t=e.getModel(eX);return t?{isMobileLayout:t.isMobileLayout,setIsMobileLayout:t.setIsMobileLayout.bind(t)}:{isMobileLayout:!1,setIsMobileLayout:()=>{}}};function v2(e){let{flowEngine:t,pageUid:l,refreshDesktopRoutes:o,layoutContentRef:n}=e;return o$({flowEngine:t,pageUid:l,refreshDesktopRoutes:o,layoutContentRef:n,getLayoutModel:e=>oq(e,{required:!0})})}var v5=__nested_rspack_require_1176521__(9652),v8=__nested_rspack_require_1176521__(6681),v4=__nested_rspack_require_1176521__(9784),v3=__nested_rspack_require_1176521__(65);class v6 extends iz{async load(){this.app.addComponents({FlowRoute:oX}),this.app.flowEngine.setModelRepository(new vS(this.app));let e=Object.fromEntries(Object.entries(l).filter(e=>{let[,t]=e;return"function"==typeof t&&t.prototype instanceof u.FlowModel}));this.flowEngine.registerModels(e),this.flowEngine.registerActions(o),this.flowEngine.registerActions(t),this.flowEngine.flowSettings.registerComponents({IconPicker:ed.ar,DefaultValue:vM,FlowSettingsVariableTextArea:iK.n}),this.flowEngine.flowSettings.addToolbarItem({key:"dynamic-flows-editor",component:vA,visible:e=>e.getEvents().size>0,sort:0});let n=new vZ;this.flowEngine.context.defineProperty("markdown",{get:()=>n});let i=new v0({ctx:this.flowEngine.context});this.flowEngine.context.defineProperty("liquid",{get:()=>i}),this.flowEngine.context.defineMethod("previewRunJS",async function(e,t){let l=await Promise.resolve().then(__nested_rspack_require_1176521__.bind(__nested_rspack_require_1176521__,426));return await l.previewRunJS(String(e??""),this,{version:t})},{description:"Preview/diagnose a RunJS snippet (lint + sandbox execution).",detail:"(code: string, version?: string) => Promise<{ success: boolean; message: string }>",params:[{name:"code",type:"string",description:"RunJS code to preview."},{name:"version",type:"string",description:"RunJS version override (e.g. v1/v2)."}],returns:{type:"Promise<PreviewRunJSResult>",description:"Preview result."},completion:{insertText:"await ctx.previewRunJS('console.log(1)', 'v2')"}})}}let v9={"ar-EG":"ar","az-AZ":"az","bg-BG":"bg","bn-BD":"bn-bd","by-BY":"en","ca-ES":"ca","cs-CZ":"cs","da-DK":"da","de-DE":"de","el-GR":"el","en-GB":"en-gb","en-US":"en","es-ES":"es","et-EE":"et","fa-IR":"fa","fi-FI":"fi","fr-BE":"fr","fr-CA":"fr","fr-FR":"fr","ga-IE":"ga","gl-ES":"gl","he-IL":"he","hi-IN":"hi","hr-HR":"hr","hu-HU":"hu","hy-AM":"hy-am","id-ID":"id","is-IS":"is","it-IT":"it","ja-JP":"ja","ka-GE":"ka","kk-KZ":"kk","km-KH":"km","kn-IN":"kn","ko-KR":"ko","ku-IQ":"ku","lt-LT":"lt","lv-LV":"lv","mk-MK":"mk","ml-IN":"ml","mn-MN":"mn","ms-MY":"ms","nb-NO":"nb","ne-NP":"ne","nl-BE":"nl-be","nl-NL":"nl","pl-PL":"pl","pt-BR":"pt-br","pt-PT":"pt","ro-RO":"ro","ru-RU":"ru","si-LK":"si","sk-SK":"sk","sl-SI":"sl","sr-RS":"sr","sv-SE":"sv","ta-IN":"ta","th-TH":"th","tk-TK":"tk","tr-TR":"tr","uk-UA":"uk","ur-PK":"ur","vi-VN":"vi","zh-CN":"zh-cn","zh-HK":"zh-hk","zh-TW":"zh-tw"};class v7{atX0SecondsPastTheMinuteGt20(){return this.data.atX0SecondsPastTheMinuteGt20}atX0MinutesPastTheHourGt20(){return this.data.atX0MinutesPastTheHourGt20}commaMonthX0ThroughMonthX1(){return this.data.commaMonthX0ThroughMonthX1}commaYearX0ThroughYearX1(){return this.data.commaYearX0ThroughYearX1}use24HourTimeFormatByDefault(){return this.data.use24HourTimeFormatByDefault}anErrorOccuredWhenGeneratingTheExpressionD(){return this.data.anErrorOccuredWhenGeneratingTheExpressionD}everyMinute(){return this.data.everyMinute}everyHour(){return this.data.everyHour}atSpace(){return this.data.atSpace}everyMinuteBetweenX0AndX1(){return this.data.everyMinuteBetweenX0AndX1}at(){return this.data.at}spaceAnd(){return this.data.spaceAnd}everySecond(){return this.data.everySecond}everyX0Seconds(){return this.data.everyX0Seconds}secondsX0ThroughX1PastTheMinute(){return this.data.secondsX0ThroughX1PastTheMinute}atX0SecondsPastTheMinute(){return this.data.atX0SecondsPastTheMinute}everyX0Minutes(){return this.data.everyX0Minutes}minutesX0ThroughX1PastTheHour(){return this.data.minutesX0ThroughX1PastTheHour}atX0MinutesPastTheHour(){return this.data.atX0MinutesPastTheHour}everyX0Hours(){return this.data.everyX0Hours}betweenX0AndX1(){return this.data.betweenX0AndX1}atX0(){return this.data.atX0}commaEveryDay(){return this.data.commaEveryDay}commaEveryX0DaysOfTheWeek(){return this.data.commaEveryX0DaysOfTheWeek}commaX0ThroughX1(){return this.data.commaX0ThroughX1}commaAndX0ThroughX1(){return this.data.commaAndX0ThroughX1}first(){return this.data.first}second(){return this.data.second}third(){return this.data.third}fourth(){return this.data.fourth}fifth(){return this.data.fifth}commaOnThe(){return this.data.commaOnThe}spaceX0OfTheMonth(){return this.data.spaceX0OfTheMonth}lastDay(){return this.data.lastDay}commaOnTheLastX0OfTheMonth(){return this.data.commaOnTheLastX0OfTheMonth}commaOnlyOnX0(){return this.data.commaOnlyOnX0}commaAndOnX0(){return this.data.commaAndOnX0}commaEveryX0Months(){return this.data.commaEveryX0Months}commaOnlyInX0(){return this.data.commaOnlyInX0}commaOnTheLastDayOfTheMonth(){return this.data.commaOnTheLastDayOfTheMonth}commaOnTheLastWeekdayOfTheMonth(){return this.data.commaOnTheLastWeekdayOfTheMonth}commaDaysBeforeTheLastDayOfTheMonth(){return this.data.commaDaysBeforeTheLastDayOfTheMonth}firstWeekday(){return this.data.firstWeekday}weekdayNearestDayX0(){return this.data.weekdayNearestDayX0}commaOnTheX0OfTheMonth(){return this.data.commaOnTheX0OfTheMonth}commaEveryX0Days(){return this.data.commaEveryX0Days}commaBetweenDayX0AndX1OfTheMonth(){return this.data.commaBetweenDayX0AndX1OfTheMonth}commaOnDayX0OfTheMonth(){return this.data.commaOnDayX0OfTheMonth}commaEveryHour(){return this.data.commaEveryHour}commaEveryX0Years(){return this.data.commaEveryX0Years}commaStartingX0(){return this.data.commaStartingX0}daysOfTheWeek(){return this.data.daysOfTheWeek}monthsOfTheYear(){return this.data.monthsOfTheYear}constructor(e){this.data=e}}let be=e=>{(cronstrue__rspack_import_82_default().default?cronstrue__rspack_import_82_default().default:cronstrue__rspack_import_82_default()).initialize({load(t){t[null==e?void 0:e.lang]=new v7(null==e?void 0:e.cronstrue)}})};class bt extends iz{async afterAdd(){let e=this.app.apiClient,t=e.auth.locale;try{var l;let o=await e.request({url:"app:getLang",params:{locale:t},headers:{"X-Role":"anonymous"}}),n=(null==o||null==(l=o.data)?void 0:l.data)||{};this.engine.context.defineProperty("locales",{value:n}),this.app.use(g.App,{component:!1}),n.lang&&(e.auth.setLocale(n.lang),this.app.setDocumentLanguage(n.lang),this.app.i18n.changeLanguage(n.lang)),Object.keys(n.resources||{}).forEach(e=>{this.app.i18n.addResources(n.lang,e,n.resources[e]||{})}),(0,_formily_validator__rspack_import_81.setValidateLanguage)(n.lang),be(n);let i=v9[n.lang]||"en";await __nested_rspack_require_1176521__(8817)(`./${i}`),m6.default.locale(i),window.cronLocale=n.cron}catch(e){throw e}}}let bl=["/signin","/signup","/forgot-password","/reset-password"];function bo(e,t){if(!t)return e;let l=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=RegExp(`^${l.replace(/\/?$/,"")}(\\/|$)`);return e.replace(o,"/")||e}function bn(e,t){let l=bo(e,t);return bl.some(e=>l===e||l.startsWith(`${e}/`))}function bi(e,t){let l=bo(e,t);return"/admin"===l||l.startsWith("/admin/")}function br(e,t){return(e.router.matchRoutes(t)||[]).some(e=>{var t;return(null==e||null==(t=e.route)?void 0:t.authCheck)===!0})}function ba(e,t){return bi(t,e.router.getBasename())||br(e,t)}function bs(e,t){return bn(t,e.router.getBasename())||e.router.isSkippedAuthCheckRoute(t)?"skipped":ba(e,t)?"required":"unchecked"}let bd=(0,p.createContext)(null);function bu(){return(0,p.useContext)(bd)}function bc(){var e,t;let{allowAnonymous:l}=(0,lg.v6)(),o=(0,u.useFlowEngine)(),n=null==o||null==(t=o.context)||null==(e=t.user)?void 0:e.roles;return(0,p.useMemo)(()=>{let e=e=>{var t;return null==e?"":(null==o||null==(t=o.context)?void 0:t.t)?o.context.t(e):e},t=(n||[]).filter(e=>(null==e?void 0:e.name)!=="__union__").map(t=>({name:t.name,title:e(t.title)}));return l&&t.push({name:"anonymous",title:"Anonymous"}),t},[l,o,n])}bd.displayName="CurrentUserContext";let bp=e=>{let{children:t}=e,l=(0,f.n)(),o=(0,h.useLocation)(),[n,i]=(0,p.useState)(!0),[r,a]=(0,p.useState)(null),d=(0,p.useRef)(!1);if((0,p.useEffect)(()=>{let e=!0,t=l.router.getBasename(),n=bn(o.pathname,t)||l.router.isSkippedAuthCheckRoute(o.pathname),r=ba(l,o.pathname);if(n||!r){i(!1),a(null);return}return d.current||i(!0),a(null),(async()=>{try{await l.dataSourceManager.ensureLoaded(),d.current=!0,e&&i(!1)}catch(t){if(!e)return;i(!1),a(t instanceof Error?t:Error(String(t)))}})(),()=>{e=!1}},[l,o.pathname]),r)throw r;return n?l.renderComponent("AppSpin"):(0,s.jsx)(s.Fragment,{children:t})},bm=e=>{let{children:t}=e,l=(0,f.n)(),o=(0,h.useLocation)(),n=(0,h.useNavigate)(),[i,r]=(0,p.useState)({loading:!0,authStatus:"unknown"}),a=(0,p.useRef)(o);a.current=o;let d=bs(l,o.pathname),c="required"===d&&"authenticated"!==i.authStatus,m=(0,p.useMemo)(()=>({data:i.data,loading:i.loading}),[i.data,i.loading]);if((0,p.useEffect)(()=>{let e=!0;return"required"!==d?void r({loading:!1,authStatus:"unauthenticated",error:null}):(r(e=>"authenticated"===e.authStatus?e:{data:e.data,loading:!0,authStatus:"unknown",error:null}),(async()=>{var t,o;try{let o=await l.apiClient.request({url:"/auth:check",skipNotify:!0,skipAuth:!0});if(!e)return;let i=null==o||null==(t=o.data)?void 0:t.data;if((null==i?void 0:i.code)===302)return void r({loading:!1,authStatus:"redirecting",error:null});if((null==i?void 0:i.id)==null){r({loading:!0,authStatus:"unauthenticated",error:null}),n(`/signin?redirect=${encodeURIComponent(eT(l,a.current))}`,{replace:!0});return}let s=(0,u.createCollectionContextMeta)(()=>{var e,t;return(null==(t=l.flowEngine.context.dataSourceManager)||null==(e=t.getDataSource("main"))?void 0:e.getCollection("users"))||null},l.flowEngine.translate("Current user"));s.sort=1e3,l.flowEngine.context.defineProperty("user",{value:i,resolveOnServer:!0,meta:s}),r({data:null==o?void 0:o.data,loading:!1,authStatus:"authenticated",error:null})}catch(i){if(!e)return;let t=i;if((null==t||null==(o=t.response)?void 0:o.status)===401||(null==t?void 0:t.status)===401){r({loading:!0,authStatus:"unauthenticated",error:null}),n(`/signin?redirect=${encodeURIComponent(eT(l,a.current))}`,{replace:!0});return}r({loading:!1,authStatus:"unknown",error:i instanceof Error?i:Error(String(i))})}})(),()=>{e=!1})},[l,d,n]),i.error)throw i.error;return i.loading||c?l.renderComponent("AppSpin"):(0,s.jsx)(bd.Provider,{value:m,children:t})},bh=()=>{var e,t;let l=(0,f.n)(),o=!!(null==l||null==(t=l.apiClient)||null==(e=t.auth)?void 0:e.token),n=eP(l);return o?(0,s.jsx)(h.Navigate,{replace:!0,to:"/admin"}):(0,s.jsx)(h.Navigate,{replace:!0,to:`/signin?redirect=${encodeURIComponent(n)}`})};class bf extends iz{async afterAdd(){await this.addPlugins()}async load(){this.addComponents(),this.addRoutes(),this.app.use(bm),this.app.use(bp),this.app.flowEngine.registerModels({AdminLayoutModel:oH,AdminLayoutMenuItemModel:t9,AdminSettingsLayoutModel:v8.C}),this.app.layoutManager.registerLayout({routeName:"admin",routePath:"/admin",uid:eX,layoutModelClass:"AdminLayoutModel"}),this.app.pluginSettingsManager.addMenuItem({key:"plugin-manager",title:this.app.i18n.t("Plugin manager"),icon:"ApiOutlined",aclSnippet:"pm",sort:-200}),this.app.pluginSettingsManager.addPageTabItem({menuKey:"plugin-manager",key:"index",title:this.app.i18n.t("Plugin manager"),componentLoader:()=>Promise.resolve().then(__nested_rspack_require_1176521__.bind(__nested_rspack_require_1176521__,9784)),aclSnippet:"pm",sort:-200}),this.app.pluginSettingsManager.addMenuItem({key:"system-settings",title:this.app.i18n.t("System settings"),icon:"SettingOutlined",aclSnippet:"pm.system-settings.system-settings",sort:-100}),this.app.pluginSettingsManager.addPageTabItem({menuKey:"system-settings",key:"index",title:this.app.i18n.t("System settings"),componentLoader:()=>Promise.resolve().then(__nested_rspack_require_1176521__.bind(__nested_rspack_require_1176521__,65)),aclSnippet:"pm.system-settings.system-settings",sort:-100}),this.app.pluginSettingsManager.addMenuItem({key:"security",title:this.app.i18n.t("Security"),icon:"SafetyOutlined",aclSnippet:"pm.security"})}addRoutes(){this.router.add("root",{path:"/",element:(0,s.jsx)(bh,{})}),this.router.add("not-found",{path:"*",Component:j.bM}),this.router.add("admin.settings",{path:"/admin/settings",componentLoader:()=>Promise.resolve().then(__nested_rspack_require_1176521__.bind(__nested_rspack_require_1176521__,9652))}),this.router.add("admin.settings.route-empty",{path:"*",Component:h.Outlet})}addComponents(){}async addPlugins(){await this.app.pm.add(v6),await this.app.pm.add(bt,{name:"builtin-locale"})}}var bg=__nested_rspack_require_1176521__(5026);let by={type:"boolean","x-content":'{{t("Unique")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly || primaryKeyOnly }}"},bv={type:"boolean","x-content":'{{t("Primary")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly || primaryKeyOnly }}"},bb={type:"boolean",title:'{{t("Auto increment")}}',"x-content":'{{t("Auto increment")}}',"x-decorator":"FormItem","x-component":"Checkbox","x-disabled":"{{ !createMainOnly }}"},bx={type:"boolean",title:'{{t("Default value")}}',"x-content":'{{t("Automatically generate default values")}}',"x-decorator":"FormItem","x-component":"Checkbox",default:!0},bM={type:"string",title:'{{t("Relationship type")}}',required:!0,"x-disabled":!0,"x-decorator":"FormItem","x-component":"Select",enum:[{label:"{{t('HasOne')}}",value:"hasOne"},{label:"{{t('HasMany')}}",value:"hasMany"},{label:"{{t('BelongsTo')}}",value:"belongsTo"},{label:"{{t('BelongsToMany')}}",value:"belongsToMany"}]},b_={onDelete:{type:"string",title:'{{t("ON DELETE")}}',required:!0,default:"SET NULL","x-disabled":"{{ !createOnly }}","x-decorator":"FormItem","x-component":"Select",enum:[{label:"{{t('SET NULL')}}",value:"SET NULL"},{label:"{{t('RESTRICT')}}",value:"RESTRICT"},{label:"{{t('CASCADE')}}",value:"CASCADE"},{label:"{{t('NO ACTION')}}",value:"NO ACTION"}]}},bS={reverse:{type:"void","x-component":"div",properties:{autoCreateReverseField:{type:"boolean",default:!1,"x-decorator":"FormItem","x-component":"Checkbox","x-content":'{{t("Create inverse field in the target collection")}}'},"reverseField.type":{...bM,title:'{{t("Inverse relationship type")}}'},"reverseField.uiSchema.title":{type:"string",title:'{{t("Inverse field display name")}}',default:"{{record.title}}",required:!0,"x-decorator":"FormItem","x-component":"Input","x-disabled":"{{ !showReverseFieldConfig }}"},"reverseField.name":{type:"string",title:'{{t("Inverse field name")}}',required:!0,"x-decorator":"FormItem","x-component":"Input","x-validator":"uid","x-disabled":"{{ !showReverseFieldConfig }}",description:"{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}"}}}},bw={"uiSchema.x-component-props.picker":{type:"string",title:'{{t("Picker")}}',"x-decorator":"FormItem","x-component":"Radio.Group",default:"date",enum:[{label:'{{t("Date")}}',value:"date"},{label:'{{t("Month")}}',value:"month"},{label:'{{t("Quarter")}}',value:"quarter"},{label:'{{t("Year")}}',value:"year"}]},"uiSchema.x-component-props.dateFormat":{type:"string",title:'{{t("Date format")}}',"x-decorator":"FormItem","x-component":"ExpiresRadio","x-decorator-props":{},"x-component-props":{className:(0,w.css)`
1244
1244
  .ant-radio-wrapper {
1245
1245
  display: flex;
1246
1246
  margin: 5px 0px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/client-v2",
3
- "version": "2.2.0-beta.1",
3
+ "version": "2.2.0-beta.2",
4
4
  "license": "Apache-2.0",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.mjs",
@@ -27,11 +27,11 @@
27
27
  "@formily/antd-v5": "1.2.3",
28
28
  "@formily/react": "^2.2.27",
29
29
  "@formily/shared": "^2.2.27",
30
- "@nocobase/evaluators": "2.2.0-beta.1",
31
- "@nocobase/flow-engine": "2.2.0-beta.1",
32
- "@nocobase/sdk": "2.2.0-beta.1",
33
- "@nocobase/shared": "2.2.0-beta.1",
34
- "@nocobase/utils": "2.2.0-beta.1",
30
+ "@nocobase/evaluators": "2.2.0-beta.2",
31
+ "@nocobase/flow-engine": "2.2.0-beta.2",
32
+ "@nocobase/sdk": "2.2.0-beta.2",
33
+ "@nocobase/shared": "2.2.0-beta.2",
34
+ "@nocobase/utils": "2.2.0-beta.2",
35
35
  "ahooks": "^3.7.2",
36
36
  "antd": "5.24.2",
37
37
  "antd-style": "3.7.1",
@@ -46,5 +46,5 @@
46
46
  "react-i18next": "^11.15.1",
47
47
  "react-router-dom": "^6.30.1"
48
48
  },
49
- "gitHead": "f82fa9d0c3aa8e00e53dd94e404a312483b4866b"
49
+ "gitHead": "2fe3e6a86fc1d0cd039349a68b2e4d1d6945ce45"
50
50
  }
@@ -12,6 +12,10 @@ import { act, render, screen, waitFor } from '@testing-library/react';
12
12
  import React from 'react';
13
13
  import { NocoBaseBuildInPlugin } from '../nocobase-buildin-plugin';
14
14
 
15
+ const TestingAppSpin = () => <div data-testid="app-spin">app spin</div>;
16
+
17
+ const TestingAppError = ({ error }: { error: Error }) => <div role="alert">{error.message}</div>;
18
+
15
19
  class SkippedPublicRoutePlugin extends Plugin {
16
20
  async load() {
17
21
  this.router.add('public', {
@@ -22,6 +26,31 @@ class SkippedPublicRoutePlugin extends Plugin {
22
26
  }
23
27
  }
24
28
 
29
+ class DummySigninRoutePlugin extends Plugin {
30
+ async load() {
31
+ this.router.add('signin-test', {
32
+ path: '/signin',
33
+ skipAuthCheck: true,
34
+ Component: () => <div>signin page</div>,
35
+ });
36
+ }
37
+ }
38
+
39
+ class AuthBootstrapRoutePlugin extends Plugin {
40
+ async load() {
41
+ this.router.add('secure', {
42
+ path: '/secure',
43
+ authCheck: true,
44
+ Component: () => <div>secure page</div>,
45
+ });
46
+ this.router.add('guest', {
47
+ path: '/guest',
48
+ authCheck: false,
49
+ Component: () => <div>guest page</div>,
50
+ });
51
+ }
52
+ }
53
+
25
54
  describe('nocobase buildin plugin auth redirect', () => {
26
55
  const originalLocation = globalThis.window.location;
27
56
 
@@ -155,6 +184,176 @@ describe('nocobase buildin plugin auth redirect', () => {
155
184
  });
156
185
  });
157
186
 
187
+ it('should defer data source bootstrap until auth-required route is authenticated after signin redirect', async () => {
188
+ const app = createMockClient({
189
+ publicPath: '/v2/',
190
+ plugins: [NocoBaseBuildInPlugin as any, DummySigninRoutePlugin as any, AuthBootstrapRoutePlugin as any],
191
+ components: { AppSpin: TestingAppSpin },
192
+ router: { type: 'memory', initialEntries: ['/v2/secure'] },
193
+ });
194
+ app.apiMock.onGet('app:getLang').reply(200, {
195
+ data: { lang: 'en-US', resources: { client: {} }, cron: {} },
196
+ });
197
+ const events: string[] = [];
198
+ app.apiMock.onGet('/auth:check').replyOnce(() => {
199
+ events.push('auth:first');
200
+ return [200, { data: {} }];
201
+ });
202
+ app.apiMock.onGet('/auth:check').reply(() => {
203
+ events.push('auth:second');
204
+ return [200, { data: { id: 1 } }];
205
+ });
206
+
207
+ const ensureLoaded = vi.spyOn(app.dataSourceManager, 'ensureLoaded').mockImplementation(() => {
208
+ if (!app.apiClient.auth.token) {
209
+ const pending = new Promise<void>(() => undefined);
210
+ app.dataSourceManager.loadingPromise = pending;
211
+ return pending;
212
+ }
213
+ events.push('bootstrap');
214
+ expect(events).toContain('auth:second');
215
+ return Promise.resolve();
216
+ });
217
+
218
+ const Root = app.getRootComponent();
219
+ render(<Root />);
220
+
221
+ await waitFor(() => {
222
+ expect(app.router.router.state.location.pathname).toBe('/v2/signin');
223
+ expect(app.router.router.state.location.search).toBe('?redirect=%2Fv2%2Fsecure');
224
+ });
225
+ expect(await screen.findByText('signin page')).toBeInTheDocument();
226
+ expect(screen.queryByTestId('app-spin')).not.toBeInTheDocument();
227
+ expect(ensureLoaded).not.toHaveBeenCalled();
228
+ expect(app.dataSourceManager.loadingPromise).toBeNull();
229
+ expect(events).toEqual(['auth:first']);
230
+
231
+ act(() => {
232
+ app.apiClient.auth.setToken('test-token');
233
+ });
234
+
235
+ await act(async () => {
236
+ await app.router.router.navigate('/secure');
237
+ });
238
+
239
+ expect(await screen.findByText('secure page')).toBeInTheDocument();
240
+ await waitFor(() => {
241
+ expect(document.querySelector('.ant-spin-spinning')).not.toBeInTheDocument();
242
+ });
243
+ expect(ensureLoaded).toHaveBeenCalledTimes(1);
244
+ });
245
+
246
+ it('should redirect on auth-required /auth:check 401 without bootstrapping data sources', async () => {
247
+ const app = createMockClient({
248
+ publicPath: '/v2/',
249
+ plugins: [NocoBaseBuildInPlugin as any, DummySigninRoutePlugin as any, AuthBootstrapRoutePlugin as any],
250
+ components: { AppSpin: TestingAppSpin },
251
+ router: { type: 'memory', initialEntries: ['/v2/secure'] },
252
+ });
253
+ app.apiMock.onGet('app:getLang').reply(200, {
254
+ data: { lang: 'en-US', resources: { client: {} }, cron: {} },
255
+ });
256
+ app.apiMock.onGet('/auth:check').reply(401, { errors: [{ code: 'EMPTY_TOKEN' }] });
257
+ const ensureLoaded = vi.spyOn(app.dataSourceManager, 'ensureLoaded').mockImplementation(() => {
258
+ const pending = new Promise<void>(() => undefined);
259
+ app.dataSourceManager.loadingPromise = pending;
260
+ return pending;
261
+ });
262
+
263
+ const Root = app.getRootComponent();
264
+ render(<Root />);
265
+
266
+ await waitFor(() => {
267
+ expect(app.router.router.state.location.pathname).toBe('/v2/signin');
268
+ expect(app.router.router.state.location.search).toBe('?redirect=%2Fv2%2Fsecure');
269
+ });
270
+ expect(await screen.findByText('signin page')).toBeInTheDocument();
271
+ expect(screen.queryByTestId('app-spin')).not.toBeInTheDocument();
272
+ expect(ensureLoaded).not.toHaveBeenCalled();
273
+ expect(app.dataSourceManager.loadingPromise).toBeNull();
274
+ });
275
+
276
+ it('should surface non-auth /auth:check errors instead of leaving auth-required route spinning', async () => {
277
+ const app = createMockClient({
278
+ publicPath: '/v2/',
279
+ plugins: [NocoBaseBuildInPlugin as any, AuthBootstrapRoutePlugin as any],
280
+ components: { AppSpin: TestingAppSpin, AppError: TestingAppError },
281
+ router: { type: 'memory', initialEntries: ['/v2/secure'] },
282
+ });
283
+ app.apiMock.onGet('app:getLang').reply(200, {
284
+ data: { lang: 'en-US', resources: { client: {} }, cron: {} },
285
+ });
286
+ app.apiMock.onGet('/auth:check').reply(500, { errors: [{ message: 'auth check failed' }] });
287
+ const ensureLoaded = vi.spyOn(app.dataSourceManager, 'ensureLoaded').mockResolvedValue(undefined);
288
+
289
+ const Root = app.getRootComponent();
290
+ render(<Root />);
291
+
292
+ expect(await screen.findByRole('alert')).toHaveTextContent('Request failed with status code 500');
293
+ expect(screen.queryByTestId('app-spin')).not.toBeInTheDocument();
294
+ expect(ensureLoaded).not.toHaveBeenCalled();
295
+ });
296
+
297
+ it.each(['/v2/signin', '/v2/public'])('should not bootstrap data sources on skipped auth route: %s', async (path) => {
298
+ const app = createMockClient({
299
+ publicPath: '/v2/',
300
+ plugins: [NocoBaseBuildInPlugin as any, DummySigninRoutePlugin as any, SkippedPublicRoutePlugin as any],
301
+ components: { AppSpin: TestingAppSpin },
302
+ router: { type: 'memory', initialEntries: [path] },
303
+ });
304
+ app.apiMock.onGet('app:getLang').reply(200, {
305
+ data: { lang: 'en-US', resources: { client: {} }, cron: {} },
306
+ });
307
+ const ensureLoaded = vi.spyOn(app.dataSourceManager, 'ensureLoaded').mockResolvedValue(undefined);
308
+
309
+ const Root = app.getRootComponent();
310
+ render(<Root />);
311
+
312
+ expect(await screen.findByText(path === '/v2/signin' ? 'signin page' : 'public page')).toBeInTheDocument();
313
+ expect(screen.queryByTestId('app-spin')).not.toBeInTheDocument();
314
+ expect(ensureLoaded).not.toHaveBeenCalled();
315
+ expect(app.apiMock.history.get.filter((request) => request.url === '/auth:check')).toHaveLength(0);
316
+ });
317
+
318
+ it('should bootstrap data sources for authenticated auth-required route access', async () => {
319
+ const app = createMockClient({
320
+ publicPath: '/v2/',
321
+ plugins: [NocoBaseBuildInPlugin as any, AuthBootstrapRoutePlugin as any],
322
+ router: { type: 'memory', initialEntries: ['/v2/secure'] },
323
+ });
324
+ app.apiClient.auth.setToken('test-token');
325
+ app.apiMock.onGet('app:getLang').reply(200, {
326
+ data: { lang: 'en-US', resources: { client: {} }, cron: {} },
327
+ });
328
+ app.apiMock.onGet('/auth:check').reply(200, { data: { id: 1 } });
329
+ const ensureLoaded = vi.spyOn(app.dataSourceManager, 'ensureLoaded').mockResolvedValue(undefined);
330
+
331
+ const Root = app.getRootComponent();
332
+ render(<Root />);
333
+
334
+ expect(await screen.findByText('secure page')).toBeInTheDocument();
335
+ expect(ensureLoaded).toHaveBeenCalledTimes(1);
336
+ });
337
+
338
+ it('should not auth-check or bootstrap authCheck false routes', async () => {
339
+ const app = createMockClient({
340
+ publicPath: '/v2/',
341
+ plugins: [NocoBaseBuildInPlugin as any, AuthBootstrapRoutePlugin as any],
342
+ router: { type: 'memory', initialEntries: ['/v2/guest'] },
343
+ });
344
+ app.apiMock.onGet('app:getLang').reply(200, {
345
+ data: { lang: 'en-US', resources: { client: {} }, cron: {} },
346
+ });
347
+ const ensureLoaded = vi.spyOn(app.dataSourceManager, 'ensureLoaded').mockResolvedValue(undefined);
348
+
349
+ const Root = app.getRootComponent();
350
+ render(<Root />);
351
+
352
+ expect(await screen.findByText('guest page')).toBeInTheDocument();
353
+ expect(ensureLoaded).not.toHaveBeenCalled();
354
+ expect(app.apiMock.history.get.filter((request) => request.url === '/auth:check')).toHaveLength(0);
355
+ });
356
+
158
357
  it('should render v2 admin root without redirecting away', async () => {
159
358
  const app = createMockClient({
160
359
  publicPath: '/v2/',
@@ -28,6 +28,13 @@ export type CurrentUserState = {
28
28
  loading: boolean;
29
29
  };
30
30
 
31
+ type CurrentUserAuthStatus = 'unknown' | 'authenticated' | 'unauthenticated' | 'redirecting';
32
+
33
+ type CurrentUserInternalState = CurrentUserState & {
34
+ authStatus: CurrentUserAuthStatus;
35
+ error?: Error | null;
36
+ };
37
+
31
38
  export type CurrentRoleOption = {
32
39
  name: string;
33
40
  title: string;
@@ -151,7 +158,7 @@ const DataSourceBootstrapProvider: FC = ({ children }) => {
151
158
  }
152
159
  };
153
160
 
154
- void run();
161
+ run();
155
162
 
156
163
  return () => {
157
164
  mounted = false;
@@ -173,21 +180,33 @@ const CurrentUserProvider: FC = ({ children }) => {
173
180
  const app = useApp<Application>();
174
181
  const location = useLocation();
175
182
  const navigate = useNavigate();
176
- const [state, setState] = useState<CurrentUserState>({ loading: true });
183
+ const [state, setState] = useState<CurrentUserInternalState>({ loading: true, authStatus: 'unknown' });
177
184
  const locationRef = useRef(location);
178
185
  locationRef.current = location;
179
186
  const authCheckRouteState = getCurrentUserAuthCheckRouteState(app, location.pathname);
187
+ const shouldBlockAuthRequiredRoute = authCheckRouteState === 'required' && state.authStatus !== 'authenticated';
188
+ const contextValue = useMemo<CurrentUserState>(
189
+ () => ({
190
+ data: state.data,
191
+ loading: state.loading,
192
+ }),
193
+ [state.data, state.loading],
194
+ );
180
195
 
181
196
  useEffect(() => {
182
197
  let mounted = true;
183
198
 
184
199
  if (authCheckRouteState !== 'required') {
185
200
  // 认证页等免鉴权路由不应再执行 `/auth:check`,否则未登录时会重复鉴权并触发重定向抖动。
186
- setState({ loading: false });
201
+ setState({ loading: false, authStatus: 'unauthenticated', error: null });
187
202
  return;
188
203
  }
189
204
 
190
- setState((previous) => (previous.loading ? previous : { ...previous, loading: true }));
205
+ setState((previous) =>
206
+ previous.authStatus === 'authenticated'
207
+ ? previous
208
+ : { data: previous.data, loading: true, authStatus: 'unknown', error: null },
209
+ );
191
210
 
192
211
  const run = async () => {
193
212
  try {
@@ -204,11 +223,12 @@ const CurrentUserProvider: FC = ({ children }) => {
204
223
  const user = res?.data?.data;
205
224
  // 服务端通过 `{ code: 302, redirect }` 通知客户端先去某个中间页(例如 2FA 验证页)。这类响应没有 user.id,但也不能视为未登录——否则会和处理 302 的全局响应拦截器 (例如 plugin-two-factor-authentication 注册的那一个)竞态,而 `window.location.replace` 会覆盖更早发出的 `window.location.href`,把用户错误地弹回登录页。让响应拦截器接管跳转。
206
225
  if (user?.code === 302) {
207
- setState({ loading: false });
226
+ setState({ loading: false, authStatus: 'redirecting', error: null });
208
227
  return;
209
228
  }
210
229
  if (user?.id == null) {
211
230
  // 用 react-router navigate (虚拟跳转)而不是 location.replace, 这样如果有其他响应拦截器已经发起了 window.location.href 整页跳转(例如 2FA 插件接收到服务端 302 重定向), 真实跳转可以胜出 navigate, 不会被这里的 signin 重定向覆盖。
231
+ setState({ loading: true, authStatus: 'unauthenticated', error: null });
212
232
  navigate(`/signin?redirect=${encodeURIComponent(getCurrentV2RedirectPath(app, locationRef.current))}`, {
213
233
  replace: true,
214
234
  });
@@ -230,21 +250,28 @@ const CurrentUserProvider: FC = ({ children }) => {
230
250
  setState({
231
251
  data: res?.data,
232
252
  loading: false,
253
+ authStatus: 'authenticated',
254
+ error: null,
233
255
  });
234
- } catch (error: any) {
256
+ } catch (error: unknown) {
235
257
  if (!mounted) {
236
258
  return;
237
259
  }
238
260
 
239
- const isAuthError = error?.response?.status === 401 || error?.status === 401;
261
+ const errorLike = error as { response?: { status?: number }; status?: number };
262
+ const isAuthError = errorLike?.response?.status === 401 || errorLike?.status === 401;
240
263
  if (isAuthError) {
264
+ setState({ loading: true, authStatus: 'unauthenticated', error: null });
241
265
  navigate(`/signin?redirect=${encodeURIComponent(getCurrentV2RedirectPath(app, locationRef.current))}`, {
242
266
  replace: true,
243
267
  });
244
268
  return;
245
269
  }
246
- setState({ loading: false });
247
- throw error;
270
+ setState({
271
+ loading: false,
272
+ authStatus: 'unknown',
273
+ error: error instanceof Error ? error : new Error(String(error)),
274
+ });
248
275
  }
249
276
  };
250
277
 
@@ -255,11 +282,15 @@ const CurrentUserProvider: FC = ({ children }) => {
255
282
  };
256
283
  }, [app, authCheckRouteState, navigate]);
257
284
 
258
- if (state.loading) {
285
+ if (state.error) {
286
+ throw state.error;
287
+ }
288
+
289
+ if (state.loading || shouldBlockAuthRequiredRoute) {
259
290
  return app.renderComponent('AppSpin');
260
291
  }
261
292
 
262
- return <CurrentUserContext.Provider value={state}>{children}</CurrentUserContext.Provider>;
293
+ return <CurrentUserContext.Provider value={contextValue}>{children}</CurrentUserContext.Provider>;
263
294
  };
264
295
 
265
296
  const RootRedirect: FC = () => {
@@ -289,8 +320,9 @@ export class NocoBaseBuildInPlugin extends Plugin<any, Application> {
289
320
  this.addComponents();
290
321
  this.addRoutes();
291
322
 
292
- this.app.use(DataSourceBootstrapProvider);
323
+ // Auth-required routes must finish auth check or redirect before data source metadata requests can start.
293
324
  this.app.use(CurrentUserProvider);
325
+ this.app.use(DataSourceBootstrapProvider);
294
326
  this.app.flowEngine.registerModels({
295
327
  AdminLayoutModel,
296
328
  AdminLayoutMenuItemModel,