@nocobase/client-v2 3.0.0-alpha.7 → 3.0.0-alpha.8

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 (33) hide show
  1. package/es/flow/actions/linkageRules.d.ts +24 -0
  2. package/es/flow/components/FieldAssignValueInput.d.ts +4 -30
  3. package/es/flow/components/field-value-variable/DateVariableEditor.d.ts +24 -0
  4. package/es/flow/components/field-value-variable/FieldValueVariableInput.d.ts +31 -0
  5. package/es/flow/components/field-value-variable/dateValue.d.ts +36 -0
  6. package/es/flow/components/field-value-variable/index.d.ts +11 -0
  7. package/es/flow/models/blocks/form/FormBlockModel.d.ts +6 -0
  8. package/es/flow/models/blocks/form/FormGridModel.d.ts +6 -0
  9. package/es/flow/models/blocks/form/value-runtime/rules.d.ts +1 -0
  10. package/es/index.mjs +101 -110
  11. package/lib/index.js +93 -102
  12. package/package.json +7 -7
  13. package/src/__tests__/app.test.tsx +15 -6
  14. package/src/components/AppComponents.tsx +4 -4
  15. package/src/flow/actions/__tests__/linkageRules.actionStates.test.ts +33 -0
  16. package/src/flow/actions/linkageRules.tsx +25 -7
  17. package/src/flow/components/FieldAssignValueInput.tsx +38 -621
  18. package/src/flow/components/field-value-variable/DateVariableEditor.tsx +181 -0
  19. package/src/flow/components/field-value-variable/FieldValueVariableInput.tsx +326 -0
  20. package/src/flow/components/field-value-variable/__tests__/FieldValueVariableInput.test.tsx +380 -0
  21. package/src/flow/components/field-value-variable/dateValue.ts +223 -0
  22. package/src/flow/components/field-value-variable/index.ts +12 -0
  23. package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +28 -53
  24. package/src/flow/models/blocks/form/FormBlockModel.tsx +4 -0
  25. package/src/flow/models/blocks/form/FormGridModel.tsx +4 -0
  26. package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +435 -0
  27. package/src/flow/models/blocks/form/value-runtime/rules.ts +67 -14
  28. package/src/flow/models/blocks/form/value-runtime/runtime.ts +43 -19
  29. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +8 -0
  30. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/__tests__/popupContext.test.ts +120 -0
  31. package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/actions/PopupSubTableEditActionModel.tsx +10 -2
  32. package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +1 -0
  33. package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +20 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/client-v2",
3
- "version": "3.0.0-alpha.7",
3
+ "version": "3.0.0-alpha.8",
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": "3.0.0-alpha.7",
31
- "@nocobase/flow-engine": "3.0.0-alpha.7",
32
- "@nocobase/sdk": "3.0.0-alpha.7",
33
- "@nocobase/shared": "3.0.0-alpha.7",
34
- "@nocobase/utils": "3.0.0-alpha.7",
30
+ "@nocobase/evaluators": "3.0.0-alpha.8",
31
+ "@nocobase/flow-engine": "3.0.0-alpha.8",
32
+ "@nocobase/sdk": "3.0.0-alpha.8",
33
+ "@nocobase/shared": "3.0.0-alpha.8",
34
+ "@nocobase/utils": "3.0.0-alpha.8",
35
35
  "ahooks": "^3.7.2",
36
36
  "antd": "5.24.2",
37
37
  "antd-style": "3.7.1",
@@ -48,5 +48,5 @@
48
48
  "react-i18next": "^11.15.1",
49
49
  "react-router-dom": "^6.30.1"
50
50
  },
51
- "gitHead": "19cd28c710f3b3c614ebe2fd7d5a415d527ee559"
51
+ "gitHead": "ce017f3deb8b2414c6b13818042c4187270d1d8a"
52
52
  }
@@ -379,7 +379,11 @@ describe('app', () => {
379
379
  expect(screen.getByText('maintaining dialog message')).toBeInTheDocument();
380
380
  });
381
381
 
382
- it('should keep current content behind maintained dialog state', async () => {
382
+ it.each([
383
+ ['pm.enable', 'Enabling plugin'],
384
+ ['pm.disable', 'Disabling plugin'],
385
+ ['future.command', 'future.command'],
386
+ ])('should keep current content behind the default dialog while app commanding: %s', async (commandName, title) => {
383
387
  const CurrentPage = () => {
384
388
  const [count, setCount] = React.useState(0);
385
389
  return <button onClick={() => setCount((value) => value + 1)}>Current page count: {count}</button>;
@@ -398,12 +402,12 @@ describe('app', () => {
398
402
  act(() => {
399
403
  app.maintained = true;
400
404
  app.maintaining = true;
401
- app.error = { code: 'APP_COMMANDING', command: { name: 'pm.enable' }, message: 'starting sub applications...' };
405
+ app.error = { code: 'APP_COMMANDING', command: { name: commandName }, message: 'starting sub applications...' };
402
406
  });
403
407
 
404
408
  expect(screen.getByRole('button', { name: 'Current page count: 1' })).toBeInTheDocument();
405
409
  expect(screen.getByRole('dialog')).toBeInTheDocument();
406
- expect(screen.getByText('Enabling plugin')).toBeInTheDocument();
410
+ expect(screen.getByText(title)).toBeInTheDocument();
407
411
  });
408
412
 
409
413
  it('should keep current content without a dialog while app upgrading', async () => {
@@ -431,17 +435,22 @@ describe('app', () => {
431
435
  expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
432
436
  });
433
437
 
434
- it('should not show Try again for an app upgrade error state', async () => {
438
+ it.each([
439
+ ['upgrade', 'App upgrading'],
440
+ ['pm.enable', 'Enabling plugin'],
441
+ ['pm.disable', 'Disabling plugin'],
442
+ ['future.command', 'future.command'],
443
+ ])('should not show Try again for an app commanding error state: %s', async (commandName, title) => {
435
444
  class PluginHelloClient extends Plugin {}
436
445
  const app = createMockClient({ plugins: [PluginHelloClient] });
437
446
  app.error = Object.assign(new Error('Loading data sources...'), {
438
447
  code: 'APP_COMMANDING',
439
- command: { name: 'upgrade' },
448
+ command: { name: commandName },
440
449
  });
441
450
 
442
451
  await renderApp(app);
443
452
 
444
- expect(screen.getByText('App upgrading')).toBeInTheDocument();
453
+ expect(screen.getByText(title)).toBeInTheDocument();
445
454
  expect(screen.queryByRole('button', { name: 'Try again' })).not.toBeInTheDocument();
446
455
  });
447
456
 
@@ -30,8 +30,8 @@ interface AppErrorPayload {
30
30
  };
31
31
  }
32
32
 
33
- const isAppUpgrading = (error?: AppErrorPayload) =>
34
- error?.code === 'APP_COMMANDING' && error.command?.name === 'upgrade';
33
+ const isAppCommanding = (error?: AppErrorPayload) => error?.code === 'APP_COMMANDING';
34
+ const isAppUpgrading = (error?: AppErrorPayload) => isAppCommanding(error) && error?.command?.name === 'upgrade';
35
35
 
36
36
  export const AppSpin = () => {
37
37
  return (
@@ -170,7 +170,7 @@ const getProps = (app: Application) => {
170
170
  export const AppError: FC<{ error: Error & { title?: string }; app: Application }> = observer(
171
171
  ({ app, error }) => {
172
172
  const props = getProps(app);
173
- const upgrading = isAppUpgrading(app.error as AppErrorPayload | undefined);
173
+ const commanding = isAppCommanding(app.error as AppErrorPayload | undefined);
174
174
  return (
175
175
  <div>
176
176
  <Result
@@ -184,7 +184,7 @@ export const AppError: FC<{ error: Error & { title?: string }; app: Application
184
184
  title={error?.title || app.i18n.t('App error', { ns: 'client' })}
185
185
  subTitle={app.i18n.t(error?.message)}
186
186
  extra={
187
- upgrading ? null : (
187
+ commanding ? null : (
188
188
  <Button type="primary" key="try" onClick={() => window.location.reload()}>
189
189
  {app.i18n.t('Try again')}
190
190
  </Button>
@@ -0,0 +1,33 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { describe, expect, it } from 'vitest';
11
+ import { getActionLinkageStateOptions } from '../linkageRules';
12
+
13
+ describe('getActionLinkageStateOptions', () => {
14
+ const t = (key: string) => key;
15
+
16
+ it('returns all states for regular action models', () => {
17
+ expect(getActionLinkageStateOptions({}, t).map((option) => option.value)).toEqual([
18
+ 'visible',
19
+ 'hidden',
20
+ 'hiddenText',
21
+ 'enabled',
22
+ 'disabled',
23
+ ]);
24
+ });
25
+
26
+ it('filters states declared unsupported by the action model', () => {
27
+ expect(
28
+ getActionLinkageStateOptions({ supportedActionLinkageStates: ['visible', 'hidden'] }, t).map(
29
+ (option) => option.value,
30
+ ),
31
+ ).toEqual(['visible', 'hidden']);
32
+ });
33
+ });
@@ -660,6 +660,30 @@ export const linkageSetBlockProps = defineAction({
660
660
  },
661
661
  });
662
662
 
663
+ const ACTION_LINKAGE_STATE_OPTIONS = [
664
+ { label: 'Visible', value: 'visible' },
665
+ { label: 'Hidden', value: 'hidden' },
666
+ { label: 'Hidden text', value: 'hiddenText' },
667
+ { label: 'Enabled', value: 'enabled' },
668
+ { label: 'Disabled', value: 'disabled' },
669
+ ] as const;
670
+
671
+ type ActionLinkageState = (typeof ACTION_LINKAGE_STATE_OPTIONS)[number]['value'];
672
+
673
+ export function getActionLinkageStateOptions(
674
+ model: { supportedActionLinkageStates?: readonly ActionLinkageState[] },
675
+ t: (key: string) => string,
676
+ ) {
677
+ const supportedStates = model.supportedActionLinkageStates ? new Set(model.supportedActionLinkageStates) : undefined;
678
+
679
+ return ACTION_LINKAGE_STATE_OPTIONS.filter((option) => !supportedStates || supportedStates.has(option.value)).map(
680
+ (option) => ({
681
+ label: t(option.label),
682
+ value: option.value,
683
+ }),
684
+ );
685
+ }
686
+
663
687
  export const linkageSetActionProps = defineAction({
664
688
  name: 'linkageSetActionProps',
665
689
  title: tExpr('Set button state'),
@@ -680,13 +704,7 @@ export const linkageSetActionProps = defineAction({
680
704
  onChange={onChange}
681
705
  placeholder={t('Please select state')}
682
706
  style={{ width: '100%' }}
683
- options={[
684
- { label: t('Visible'), value: 'visible' },
685
- { label: t('Hidden'), value: 'hidden' },
686
- { label: t('Hidden text'), value: 'hiddenText' },
687
- { label: t('Enabled'), value: 'enabled' },
688
- { label: t('Disabled'), value: 'disabled' },
689
- ]}
707
+ options={getActionLinkageStateOptions(ctx.model, t)}
690
708
  allowClear
691
709
  />
692
710
  );