@nocobase/client-v2 2.1.31 → 2.2.0-alpha.10

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 (170) hide show
  1. package/es/APIClient.d.ts +1 -3
  2. package/es/BaseApplication.d.ts +2 -0
  3. package/es/PluginSettingsManager.d.ts +33 -0
  4. package/es/RouteRepository.d.ts +29 -6
  5. package/es/RouterManager.d.ts +15 -0
  6. package/es/authRedirect.d.ts +1 -0
  7. package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
  8. package/es/components/category-tabs/index.d.ts +9 -0
  9. package/es/components/form/TypedVariableInput.d.ts +31 -5
  10. package/es/components/form/filter/CollectionFilter.d.ts +2 -0
  11. package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
  12. package/es/components/form/filter/CollectionFilterPanel.d.ts +2 -0
  13. package/es/components/form/filter/index.d.ts +2 -0
  14. package/es/components/form/filter/useFilterActionProps.d.ts +2 -0
  15. package/es/components/index.d.ts +2 -0
  16. package/es/entry-actions/EntryActionManager.d.ts +24 -0
  17. package/es/entry-actions/index.d.ts +9 -0
  18. package/es/flow/actions/index.d.ts +1 -1
  19. package/es/flow/actions/linkageRules.d.ts +2 -0
  20. package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +2 -0
  21. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.d.ts +2 -1
  22. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +3 -0
  23. package/es/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.d.ts +3 -2
  24. package/es/flow/admin-shell/admin-layout/AdminLayoutSlotModels.d.ts +5 -0
  25. package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +2 -1
  26. package/es/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.d.ts +24 -0
  27. package/es/flow/admin-shell/admin-layout/index.d.ts +1 -0
  28. package/es/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.d.ts +6 -0
  29. package/es/flow/admin-shell/admin-layout/useApplications.d.ts +7 -2
  30. package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
  31. package/es/flow/components/FieldAssignValueInput.d.ts +9 -0
  32. package/es/flow/components/RunJSValueEditor.d.ts +1 -0
  33. package/es/flow/components/filter/FilterGroup.d.ts +1 -0
  34. package/es/flow/components/filter/VariableFilterItem.d.ts +6 -1
  35. package/es/flow/index.d.ts +1 -0
  36. package/es/flow/models/base/ActionModelCore.d.ts +2 -0
  37. package/es/flow/models/base/GridModel.d.ts +1 -1
  38. package/es/flow/models/base/PageModel/PageModel.d.ts +12 -0
  39. package/es/flow/models/base/PageModel/PageModelTabBar.d.ts +22 -0
  40. package/es/flow/models/base/PageModel/PageTabModel.d.ts +12 -0
  41. package/es/flow/models/blocks/form/value-runtime/runtime.d.ts +9 -0
  42. package/es/flow-compat/routeTypes.d.ts +1 -0
  43. package/es/index.d.ts +7 -1
  44. package/es/index.mjs +223 -135
  45. package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
  46. package/es/utils/index.d.ts +1 -0
  47. package/lib/index.js +220 -132
  48. package/package.json +7 -7
  49. package/src/APIClient.ts +1 -10
  50. package/src/Application.tsx +4 -0
  51. package/src/BaseApplication.tsx +2 -0
  52. package/src/PluginSettingsManager.ts +53 -0
  53. package/src/RouteRepository.ts +151 -24
  54. package/src/RouterManager.tsx +142 -1
  55. package/src/__tests__/PluginSettingsManager.test.ts +13 -0
  56. package/src/__tests__/RouteRepository.test.ts +239 -0
  57. package/src/__tests__/RouterManager.test.ts +125 -0
  58. package/src/__tests__/app.test.tsx +18 -0
  59. package/src/__tests__/authRedirect.test.ts +17 -0
  60. package/src/__tests__/browserChecker.test.ts +61 -0
  61. package/src/__tests__/exports.test.ts +16 -0
  62. package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
  63. package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +28 -0
  64. package/src/__tests__/plugin-manager.test.tsx +44 -2
  65. package/src/__tests__/settings-center.test.tsx +40 -1
  66. package/src/authRedirect.ts +38 -0
  67. package/src/components/README.md +7 -1
  68. package/src/components/README.zh-CN.md +6 -1
  69. package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
  70. package/src/components/category-tabs/index.ts +10 -0
  71. package/src/components/form/JsonTextArea.tsx +4 -0
  72. package/src/components/form/TypedVariableInput.tsx +452 -101
  73. package/src/components/form/__tests__/TypedVariableInput.test.tsx +364 -12
  74. package/src/components/form/filter/CollectionFilter.tsx +4 -0
  75. package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
  76. package/src/components/form/filter/CollectionFilterPanel.tsx +4 -0
  77. package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
  78. package/src/components/form/filter/__tests__/useFilterActionProps.test.tsx +95 -0
  79. package/src/components/form/filter/index.ts +2 -0
  80. package/src/components/form/filter/useFilterActionProps.ts +37 -6
  81. package/src/components/index.ts +2 -0
  82. package/src/entry-actions/EntryActionManager.ts +76 -0
  83. package/src/entry-actions/index.ts +10 -0
  84. package/src/flow/__tests__/FlowRoute.test.tsx +1084 -145
  85. package/src/flow/actions/__tests__/linkageRules.tab.test.ts +171 -0
  86. package/src/flow/actions/customVariable.tsx +1 -2
  87. package/src/flow/actions/index.ts +2 -0
  88. package/src/flow/actions/linkageRules.tsx +65 -8
  89. package/src/flow/actions/runjs.tsx +2 -14
  90. package/src/flow/admin-shell/BaseLayoutModel.tsx +13 -0
  91. package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +46 -13
  92. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +486 -0
  93. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +64 -8
  94. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.ts +5 -3
  95. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +61 -9
  96. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +71 -8
  97. package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +1 -1
  98. package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +23 -9
  99. package/src/flow/admin-shell/admin-layout/AppListRender.tsx +13 -2
  100. package/src/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.tsx +289 -0
  101. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +435 -0
  102. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +99 -0
  103. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +77 -0
  104. package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +214 -2
  105. package/src/flow/admin-shell/admin-layout/index.ts +1 -0
  106. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +20 -0
  107. package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +33 -5
  108. package/src/flow/admin-shell/admin-layout/useApplications.tsx +81 -12
  109. package/src/flow/components/DefaultValue.tsx +1 -2
  110. package/src/flow/components/FieldAssignExactDatePicker.tsx +25 -11
  111. package/src/flow/components/FieldAssignValueInput.tsx +76 -9
  112. package/src/flow/components/FlowRoute.tsx +185 -28
  113. package/src/flow/components/RunJSValueEditor.tsx +9 -1
  114. package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +84 -2
  115. package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +2 -17
  116. package/src/flow/components/code-editor/hooks/useCodeRunner.ts +2 -14
  117. package/src/flow/components/code-editor/runjsDiagnostics.ts +8 -45
  118. package/src/flow/components/filter/FilterGroup.tsx +33 -5
  119. package/src/flow/components/filter/VariableFilterItem.tsx +158 -10
  120. package/src/flow/components/filter/__tests__/FilterGroup.test.tsx +45 -0
  121. package/src/flow/components/filter/__tests__/VariableFilterItem.leftMetaTree.test.tsx +9 -0
  122. package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +70 -1
  123. package/src/flow/index.ts +1 -0
  124. package/src/flow/models/actions/JSActionModel.tsx +2 -7
  125. package/src/flow/models/actions/JSCollectionActionModel.tsx +2 -7
  126. package/src/flow/models/actions/JSItemActionModel.tsx +2 -7
  127. package/src/flow/models/actions/JSRecordActionModel.tsx +2 -7
  128. package/src/flow/models/base/ActionModel.tsx +21 -8
  129. package/src/flow/models/base/ActionModelCore.tsx +5 -0
  130. package/src/flow/models/base/GridModel.tsx +38 -7
  131. package/src/flow/models/base/PageModel/PageModel.tsx +387 -53
  132. package/src/flow/models/base/PageModel/PageModelTabBar.tsx +114 -0
  133. package/src/flow/models/base/PageModel/PageTabModel.tsx +186 -3
  134. package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +790 -14
  135. package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.module-isolation.test.tsx +130 -0
  136. package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.test.tsx +118 -0
  137. package/src/flow/models/base/PageModel/__tests__/PageTabModel.test.ts +586 -1
  138. package/src/flow/models/base/__tests__/ActionModel.test.ts +83 -0
  139. package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +239 -1
  140. package/src/flow/models/base/__tests__/transformRowsToSingleColumn.test.ts +48 -0
  141. package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +1 -2
  142. package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
  143. package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
  144. package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +87 -0
  145. package/src/flow/models/blocks/form/value-runtime/rules.ts +2 -2
  146. package/src/flow/models/blocks/form/value-runtime/runtime.ts +91 -0
  147. package/src/flow/models/blocks/js-block/JSBlock.tsx +2 -7
  148. package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
  149. package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +1 -1
  150. package/src/flow/models/blocks/table/TableBlockModel.tsx +13 -3
  151. package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +54 -0
  152. package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
  153. package/src/flow/models/fields/JSEditableFieldModel.tsx +2 -11
  154. package/src/flow/models/fields/JSFieldModel.tsx +2 -7
  155. package/src/flow/models/fields/JSItemModel.tsx +2 -14
  156. package/src/flow/models/fields/VariableFieldFormModel.tsx +3 -3
  157. package/src/flow/models/fields/__tests__/VariableFieldFormModel.test.tsx +51 -0
  158. package/src/flow/models/topbar/TopbarActionModel.tsx +168 -10
  159. package/src/flow-compat/Popover.tsx +43 -4
  160. package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
  161. package/src/flow-compat/routeTypes.ts +1 -0
  162. package/src/index.ts +13 -1
  163. package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
  164. package/src/nocobase-buildin-plugin/index.tsx +19 -3
  165. package/src/settings-center/AdminSettingsLayout.tsx +10 -2
  166. package/src/settings-center/SystemSettingsPage.tsx +0 -1
  167. package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
  168. package/src/settings-center/utils.tsx +0 -6
  169. package/src/utils/getRouteRuntimeVersion.ts +185 -0
  170. package/src/utils/index.tsx +1 -0
@@ -7,10 +7,11 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- import { FlowModel, FlowModelRenderer, observable, tExpr } from '@nocobase/flow-engine';
10
+ import { FlowModel, FlowModelRenderer, observable, type ParamObject, tExpr } from '@nocobase/flow-engine';
11
11
  import { Icon, type NocoBaseDesktopRoute } from '../../../../flow-compat';
12
12
  import type { RouteRepository } from '../../../../RouteRepository';
13
13
  import { useRequest } from 'ahooks';
14
+ import _ from 'lodash';
14
15
  import React from 'react';
15
16
  import { SkeletonFallback } from '../../../components/SkeletonFallback';
16
17
  import { TextAreaWithContextSelector } from '../../../components/TextAreaWithContextSelector';
@@ -53,6 +54,24 @@ function normalizePersistedRoute(payload: unknown): Partial<NocoBaseDesktopRoute
53
54
  return undefined;
54
55
  }
55
56
 
57
+ type PersistedFlowModelAnchor = Record<string, unknown> & {
58
+ uid?: unknown;
59
+ stepParams?: unknown;
60
+ subModels?: unknown;
61
+ };
62
+
63
+ type LinkageRulesStepParams = ParamObject & {
64
+ value?: unknown;
65
+ };
66
+
67
+ function isRecord(value: unknown): value is Record<string, unknown> {
68
+ return !!value && typeof value === 'object' && !Array.isArray(value);
69
+ }
70
+
71
+ function isLinkageRulesStepParams(value: unknown): value is LinkageRulesStepParams {
72
+ return isRecord(value);
73
+ }
74
+
56
75
  type RefreshableRouteRepository = Pick<RouteRepository, 'refreshAccessible'>;
57
76
 
58
77
  const routeRefreshQueues = new WeakMap<RefreshableRouteRepository, Promise<unknown>>();
@@ -159,13 +178,100 @@ BasePageTabModel.registerFlow({
159
178
  ctx.model.setProps('title', translate(params.title, { ns: 'lm-desktop-routes' }));
160
179
  ctx.model.setProps('icon', params.icon);
161
180
  const pageModel = ctx.engine.getModel(ctx.model.parentId) as { updateDocumentTitle?: () => Promise<void> };
162
- void pageModel?.updateDocumentTitle?.();
181
+ await pageModel?.updateDocumentTitle?.();
163
182
  },
164
183
  },
184
+ linkageRules: {
185
+ use: 'tabLinkageRules',
186
+ },
165
187
  },
166
188
  });
167
189
 
168
190
  export class RootPageTabModel extends BasePageTabModel {
191
+ private persistedLinkageRulesHydrated = false;
192
+ private persistedLinkageRulesHydrating?: Promise<void>;
193
+
194
+ onInit(options) {
195
+ super.onInit(options);
196
+ if (this.shouldHydratePersistedLinkageRules()) {
197
+ this.hydratePersistedLinkageRules().catch((error) => {
198
+ console.warn('[RootPageTabModel] Failed to hydrate tab linkage rules', error);
199
+ });
200
+ }
201
+ }
202
+
203
+ private hasExplicitLinkageRulesStep() {
204
+ const pageTabSettings = this.stepParams?.pageTabSettings;
205
+ return isRecord(pageTabSettings) && Object.prototype.hasOwnProperty.call(pageTabSettings, 'linkageRules');
206
+ }
207
+
208
+ private shouldHydratePersistedLinkageRules() {
209
+ return !!this.context.flowSettingsEnabled || this.props.route?.options?.hasPersistedPageTabFlowModel === true;
210
+ }
211
+
212
+ private async fetchPersistedAnchor(): Promise<PersistedFlowModelAnchor | undefined> {
213
+ const response = await this.context.api.request({
214
+ url: 'flowModels:findOne',
215
+ params: { uid: this.uid },
216
+ });
217
+ const anchor = response?.data?.data;
218
+ return isRecord(anchor) ? anchor : undefined;
219
+ }
220
+
221
+ private async performPersistedLinkageRulesHydrate() {
222
+ if (this.hasExplicitLinkageRulesStep()) {
223
+ return;
224
+ }
225
+
226
+ const anchor = await this.fetchPersistedAnchor();
227
+ if (this.hasExplicitLinkageRulesStep()) {
228
+ return;
229
+ }
230
+
231
+ const stepParams = isRecord(anchor?.stepParams) ? anchor.stepParams : undefined;
232
+ const pageTabSettings = isRecord(stepParams?.pageTabSettings) ? stepParams.pageTabSettings : undefined;
233
+ const linkageRules = pageTabSettings?.linkageRules;
234
+ if (!isLinkageRulesStepParams(linkageRules)) {
235
+ return;
236
+ }
237
+
238
+ this.setStepParams('pageTabSettings', 'linkageRules', _.cloneDeep(linkageRules));
239
+ this.invalidateFlowCache('beforeRender', true);
240
+ await this.rerender();
241
+ }
242
+
243
+ private hydratePersistedLinkageRules(): Promise<void> {
244
+ if (this.persistedLinkageRulesHydrated) {
245
+ return Promise.resolve();
246
+ }
247
+ if (this.persistedLinkageRulesHydrating) {
248
+ return this.persistedLinkageRulesHydrating;
249
+ }
250
+
251
+ const hydration = this.performPersistedLinkageRulesHydrate();
252
+ this.persistedLinkageRulesHydrating = hydration;
253
+ hydration
254
+ .then(() => {
255
+ if (this.persistedLinkageRulesHydrating === hydration) {
256
+ this.persistedLinkageRulesHydrated = true;
257
+ this.persistedLinkageRulesHydrating = undefined;
258
+ }
259
+ })
260
+ .catch(() => {
261
+ if (this.persistedLinkageRulesHydrating === hydration) {
262
+ this.persistedLinkageRulesHydrating = undefined;
263
+ }
264
+ });
265
+ return hydration;
266
+ }
267
+
268
+ async openFlowSettings(options?: Parameters<FlowModel['openFlowSettings']>[0]) {
269
+ if (options?.flowKey === 'pageTabSettings' && options?.stepKey === 'linkageRules') {
270
+ await this.hydratePersistedLinkageRules();
271
+ }
272
+ return super.openFlowSettings(options);
273
+ }
274
+
169
275
  renderChildren() {
170
276
  return (
171
277
  <PageTabChildrenRenderer
@@ -182,7 +288,15 @@ export class RootPageTabModel extends BasePageTabModel {
182
288
  }
183
289
 
184
290
  async saveStepParams() {
185
- return this.save();
291
+ const hasExplicitLinkageRulesStep = this.hasExplicitLinkageRulesStep();
292
+ const linkageRules = hasExplicitLinkageRulesStep
293
+ ? (_.cloneDeep(this.stepParams.pageTabSettings.linkageRules) as LinkageRulesStepParams)
294
+ : undefined;
295
+
296
+ await this.save();
297
+ if (hasExplicitLinkageRulesStep && linkageRules) {
298
+ await this.persistLinkageRulesToAnchor(linkageRules);
299
+ }
186
300
  }
187
301
 
188
302
  async save() {
@@ -247,6 +361,75 @@ export class RootPageTabModel extends BasePageTabModel {
247
361
  }
248
362
  }
249
363
 
364
+ private buildAnchorPayload(latestAnchor: PersistedFlowModelAnchor | undefined, linkageRules: LinkageRulesStepParams) {
365
+ const hasPersistedAnchor = typeof latestAnchor?.uid === 'string' && latestAnchor.uid.length > 0;
366
+ const anchorRoot: PersistedFlowModelAnchor = hasPersistedAnchor
367
+ ? _.cloneDeep(latestAnchor)
368
+ : { uid: this.uid, use: 'RouteModel' };
369
+ delete anchorRoot.subModels;
370
+
371
+ const latestStepParams = isRecord(anchorRoot.stepParams) ? anchorRoot.stepParams : {};
372
+ const latestPageTabSettings = isRecord(latestStepParams.pageTabSettings) ? latestStepParams.pageTabSettings : {};
373
+
374
+ return {
375
+ ...anchorRoot,
376
+ stepParams: {
377
+ ...latestStepParams,
378
+ pageTabSettings: {
379
+ ...latestPageTabSettings,
380
+ linkageRules: _.cloneDeep(linkageRules),
381
+ },
382
+ },
383
+ };
384
+ }
385
+
386
+ private async persistLinkageRulesToAnchor(linkageRules: LinkageRulesStepParams) {
387
+ const latestAnchor = await this.fetchPersistedAnchor();
388
+ const anchorPayload = this.buildAnchorPayload(latestAnchor, linkageRules);
389
+ await this.context.api.request({
390
+ method: 'post',
391
+ url: 'flowModels:save',
392
+ data: anchorPayload,
393
+ });
394
+
395
+ const hasRules = Array.isArray(linkageRules.value) && linkageRules.value.length > 0;
396
+ await this.syncPersistedPageTabFlowModelMarker(hasRules);
397
+ this.persistedLinkageRulesHydrated = true;
398
+ }
399
+
400
+ private async syncPersistedPageTabFlowModelMarker(hasRules: boolean) {
401
+ const route = this.props.route;
402
+ if (route?.id == null) {
403
+ throw new Error('Cannot persist page tab FlowModel marker before the desktop route is saved.');
404
+ }
405
+ if (typeof this.context.routeRepository?.updateRoute !== 'function') {
406
+ throw new Error('Route repository is unavailable while persisting the page tab FlowModel marker.');
407
+ }
408
+
409
+ const currentRoute = route.schemaUid
410
+ ? this.context.routeRepository.getRouteBySchemaUid?.(route.schemaUid)
411
+ : undefined;
412
+ const nextOptions = {
413
+ ...(currentRoute?.options || route.options || {}),
414
+ };
415
+ if (hasRules) {
416
+ nextOptions.hasPersistedPageTabFlowModel = true;
417
+ } else {
418
+ delete nextOptions.hasPersistedPageTabFlowModel;
419
+ }
420
+ const persistedOptions = Object.keys(nextOptions).length > 0 ? nextOptions : undefined;
421
+
422
+ await this.context.routeRepository.updateRoute(
423
+ route.id,
424
+ { options: persistedOptions },
425
+ { refreshAfterMutation: false },
426
+ );
427
+ this.setProps('route', {
428
+ ...route,
429
+ options: persistedOptions,
430
+ });
431
+ }
432
+
250
433
  async destroy() {
251
434
  this.observerDispose();
252
435
  this.invalidateFlowCache('beforeRender', true);