@nocobase/client-v2 2.1.0-alpha.46 → 2.1.0-alpha.47
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/collection-manager/filter-operators/index.d.ts +1 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +5 -1
- package/es/components/form/filter/FilterValueInput.d.ts +5 -0
- package/es/flow/internal/utils/operatorSchemaHelper.d.ts +26 -3
- package/es/flow/models/blocks/filter-manager/utils.d.ts +23 -1
- package/es/index.mjs +77 -77
- package/lib/index.js +82 -82
- package/package.json +7 -7
- package/src/__tests__/browserChecker.test.ts +103 -0
- package/src/__tests__/dataSourceRuntime.test.tsx +22 -1
- package/src/collection-field-interface/CollectionFieldInterface.ts +14 -7
- package/src/collection-manager/filter-operators/index.ts +29 -2
- package/src/components/form/filter/CollectionFilterItem.tsx +10 -2
- package/src/components/form/filter/FilterValueInput.tsx +27 -2
- package/src/components/form/filter/__tests__/FilterValueInput.test.tsx +39 -0
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +369 -2
- package/src/flow/actions/linkageRules.tsx +53 -0
- package/src/flow/components/DefaultValue.tsx +14 -8
- package/src/flow/components/FieldAssignValueInput.tsx +6 -10
- package/src/flow/components/filter/LinkageFilterItem.tsx +4 -3
- package/src/flow/components/filter/VariableFilterItem.tsx +5 -4
- package/src/flow/internal/utils/operatorSchemaHelper.ts +112 -5
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +13 -11
- package/src/flow/models/blocks/filter-manager/__tests__/getDefaultOperator.test.ts +35 -1
- package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +148 -0
- package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/defaultOperator.test.tsx +85 -0
- package/src/flow/models/blocks/filter-manager/flow-actions/customizeFilterRender.tsx +14 -44
- package/src/flow/models/blocks/filter-manager/flow-actions/defaultOperator.tsx +3 -5
- package/src/flow/models/blocks/filter-manager/flow-actions/operatorComponentProps.tsx +2 -12
- package/src/flow/models/blocks/filter-manager/utils.ts +143 -4
|
@@ -9,9 +9,15 @@
|
|
|
9
9
|
|
|
10
10
|
import React from 'react';
|
|
11
11
|
import { fireEvent, render, screen } from '@testing-library/react';
|
|
12
|
-
import { FlowSettingsContextProvider } from '@nocobase/flow-engine';
|
|
12
|
+
import { FlowEngine, FlowModel, FlowSettingsContextProvider } from '@nocobase/flow-engine';
|
|
13
13
|
import { describe, expect, it, vi } from 'vitest';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
fieldLinkageRules,
|
|
16
|
+
linkageAssignField,
|
|
17
|
+
linkageSetFieldProps,
|
|
18
|
+
subFormFieldLinkageRules,
|
|
19
|
+
subFormLinkageSetFieldProps,
|
|
20
|
+
} from '../linkageRules';
|
|
15
21
|
|
|
16
22
|
const createSubFormFieldModel = ({
|
|
17
23
|
uid,
|
|
@@ -335,6 +341,110 @@ describe('subFormLinkageSetFieldProps action', () => {
|
|
|
335
341
|
expect(row0CollectedModel.hidden).toBe(false);
|
|
336
342
|
expect(row1CollectedModel.hidden).toBe(true);
|
|
337
343
|
});
|
|
344
|
+
|
|
345
|
+
it('should clear the current row value when a subform list field is hidden without reserving value', async () => {
|
|
346
|
+
const setFormValues = vi.fn(async () => undefined);
|
|
347
|
+
const form = {
|
|
348
|
+
getFieldValue: vi.fn((path: Array<string | number>) => {
|
|
349
|
+
if (JSON.stringify(path) === JSON.stringify(['items', 0, 'a'])) {
|
|
350
|
+
return 'row value';
|
|
351
|
+
}
|
|
352
|
+
return undefined;
|
|
353
|
+
}),
|
|
354
|
+
setFieldValue: vi.fn(),
|
|
355
|
+
};
|
|
356
|
+
const engine = new FlowEngine();
|
|
357
|
+
|
|
358
|
+
const rowGridFork = new FlowModel({ uid: 'row-grid-fork', flowEngine: engine }) as any;
|
|
359
|
+
rowGridFork.hidden = false;
|
|
360
|
+
rowGridFork.context.defineProperty('fieldKey', { value: ['items:0'] });
|
|
361
|
+
rowGridFork.context.defineProperty('fieldIndex', { value: ['items:0'] });
|
|
362
|
+
rowGridFork.context.defineProperty('form', { value: form });
|
|
363
|
+
rowGridFork.context.defineProperty('setFormValues', { value: setFormValues });
|
|
364
|
+
rowGridFork.context.defineProperty('app', {
|
|
365
|
+
value: {
|
|
366
|
+
jsonLogic: {
|
|
367
|
+
apply: () => true,
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
rowGridFork.getAction = vi.fn((name: string) => {
|
|
372
|
+
if (name === 'subFormLinkageSetFieldProps') {
|
|
373
|
+
return subFormLinkageSetFieldProps;
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
const targetFieldFork: any = {
|
|
378
|
+
uid: 'field-a',
|
|
379
|
+
isFork: true,
|
|
380
|
+
hidden: false,
|
|
381
|
+
props: {},
|
|
382
|
+
context: {
|
|
383
|
+
fieldIndex: ['items:0'],
|
|
384
|
+
},
|
|
385
|
+
getStepParams: vi.fn((flowKey: string, stepKey: string) => {
|
|
386
|
+
if (flowKey === 'fieldSettings' && stepKey === 'init') {
|
|
387
|
+
return { fieldPath: 'a' };
|
|
388
|
+
}
|
|
389
|
+
}),
|
|
390
|
+
setProps(key: any, value?: any) {
|
|
391
|
+
if (typeof key === 'string') {
|
|
392
|
+
this.props[key] = value;
|
|
393
|
+
} else {
|
|
394
|
+
this.props = { ...this.props, ...key };
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
const formItemModel: any = {
|
|
400
|
+
uid: 'field-a',
|
|
401
|
+
getFork: vi.fn((key: string) => (key === 'items:0:field-a' ? targetFieldFork : undefined)),
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
engine.getModel = vi.fn((uid: string) => (uid === 'field-a' ? formItemModel : undefined)) as any;
|
|
405
|
+
|
|
406
|
+
await subFormFieldLinkageRules.handler(
|
|
407
|
+
{
|
|
408
|
+
model: {
|
|
409
|
+
hidden: false,
|
|
410
|
+
subModels: {
|
|
411
|
+
grid: {
|
|
412
|
+
forks: [rowGridFork],
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
flowKey: 'eventSettings',
|
|
417
|
+
} as any,
|
|
418
|
+
{
|
|
419
|
+
value: [
|
|
420
|
+
{
|
|
421
|
+
key: 'rule-1',
|
|
422
|
+
enable: true,
|
|
423
|
+
condition: { logic: '$and', items: [] },
|
|
424
|
+
actions: [
|
|
425
|
+
{
|
|
426
|
+
name: 'subFormLinkageSetFieldProps',
|
|
427
|
+
params: {
|
|
428
|
+
value: {
|
|
429
|
+
fields: ['field-a'],
|
|
430
|
+
state: 'hidden',
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
],
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
},
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
expect(form.getFieldValue).toHaveBeenCalledWith(['items', 0, 'a']);
|
|
441
|
+
expect(targetFieldFork.hidden).toBe(true);
|
|
442
|
+
expect(setFormValues).toHaveBeenCalledWith(
|
|
443
|
+
[{ path: ['items', 0, 'a'], value: undefined }],
|
|
444
|
+
expect.objectContaining({ source: 'linkage' }),
|
|
445
|
+
);
|
|
446
|
+
expect(form.setFieldValue).not.toHaveBeenCalled();
|
|
447
|
+
});
|
|
338
448
|
});
|
|
339
449
|
|
|
340
450
|
describe('linkageSetFieldProps action', () => {
|
|
@@ -541,6 +651,263 @@ describe('linkageSetFieldProps action', () => {
|
|
|
541
651
|
expect(form.setFieldValue).not.toHaveBeenCalled();
|
|
542
652
|
});
|
|
543
653
|
|
|
654
|
+
it('should clear form value when a field is hidden without reserving value', async () => {
|
|
655
|
+
const setFormValues = vi.fn(async () => undefined);
|
|
656
|
+
const form = {
|
|
657
|
+
getFieldValue: vi.fn(() => '123'),
|
|
658
|
+
setFieldValue: vi.fn(),
|
|
659
|
+
};
|
|
660
|
+
const fieldModel: any = {
|
|
661
|
+
uid: 'name-field',
|
|
662
|
+
hidden: false,
|
|
663
|
+
context: { form },
|
|
664
|
+
props: {
|
|
665
|
+
label: 'Name',
|
|
666
|
+
},
|
|
667
|
+
getStepParams: vi.fn((flowKey: string, stepKey: string) => {
|
|
668
|
+
if (flowKey === 'fieldSettings' && stepKey === 'init') {
|
|
669
|
+
return { fieldPath: 'name' };
|
|
670
|
+
}
|
|
671
|
+
}),
|
|
672
|
+
setProps(key: any, value?: any) {
|
|
673
|
+
if (typeof key === 'string') {
|
|
674
|
+
this.props[key] = value;
|
|
675
|
+
} else {
|
|
676
|
+
this.props = { ...this.props, ...key };
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
};
|
|
680
|
+
const ctx: any = {
|
|
681
|
+
app: {
|
|
682
|
+
jsonLogic: {
|
|
683
|
+
apply: vi.fn(() => true),
|
|
684
|
+
},
|
|
685
|
+
},
|
|
686
|
+
model: {
|
|
687
|
+
context: { form },
|
|
688
|
+
subModels: {
|
|
689
|
+
grid: {
|
|
690
|
+
subModels: {
|
|
691
|
+
items: [fieldModel],
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
},
|
|
695
|
+
},
|
|
696
|
+
setFormValues,
|
|
697
|
+
getAction: (name: string) => (name === 'linkageSetFieldProps' ? linkageSetFieldProps : null),
|
|
698
|
+
resolveJsonTemplate: vi.fn(async (value) => value),
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
await fieldLinkageRules.handler(ctx, {
|
|
702
|
+
value: [
|
|
703
|
+
{
|
|
704
|
+
key: 'rule-1',
|
|
705
|
+
enable: true,
|
|
706
|
+
condition: { logic: '$and', items: [] },
|
|
707
|
+
actions: [
|
|
708
|
+
{
|
|
709
|
+
key: 'action-1',
|
|
710
|
+
name: 'linkageSetFieldProps',
|
|
711
|
+
params: {
|
|
712
|
+
value: {
|
|
713
|
+
fields: ['name-field'],
|
|
714
|
+
state: 'hidden',
|
|
715
|
+
},
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
],
|
|
719
|
+
},
|
|
720
|
+
],
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
expect(fieldModel.hidden).toBe(true);
|
|
724
|
+
expect(setFormValues).toHaveBeenCalledWith(
|
|
725
|
+
[{ path: ['name'], value: undefined }],
|
|
726
|
+
expect.objectContaining({ source: 'linkage' }),
|
|
727
|
+
);
|
|
728
|
+
expect(form.setFieldValue).not.toHaveBeenCalled();
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
it('should keep hidden clear after same-round assignment for the same field', async () => {
|
|
732
|
+
const formValues: { name?: string } = {};
|
|
733
|
+
const setFormValues = vi.fn(async (patches: Array<{ path: Array<string | number>; value: string | undefined }>) => {
|
|
734
|
+
for (const patch of patches) {
|
|
735
|
+
if (patch.path.length === 1 && patch.path[0] === 'name') {
|
|
736
|
+
formValues.name = patch.value;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
const form = {
|
|
741
|
+
getFieldValue: vi.fn((path: Array<string | number>) => {
|
|
742
|
+
if (path.length === 1 && path[0] === 'name') {
|
|
743
|
+
return formValues.name;
|
|
744
|
+
}
|
|
745
|
+
return undefined;
|
|
746
|
+
}),
|
|
747
|
+
setFieldValue: vi.fn(),
|
|
748
|
+
};
|
|
749
|
+
const fieldModel: any = {
|
|
750
|
+
uid: 'name-field',
|
|
751
|
+
hidden: false,
|
|
752
|
+
context: { form },
|
|
753
|
+
props: {
|
|
754
|
+
label: 'Name',
|
|
755
|
+
},
|
|
756
|
+
getStepParams: vi.fn((flowKey: string, stepKey: string) => {
|
|
757
|
+
if (flowKey === 'fieldSettings' && stepKey === 'init') {
|
|
758
|
+
return { fieldPath: 'name' };
|
|
759
|
+
}
|
|
760
|
+
}),
|
|
761
|
+
setProps(key: any, value?: any) {
|
|
762
|
+
if (typeof key === 'string') {
|
|
763
|
+
this.props[key] = value;
|
|
764
|
+
} else {
|
|
765
|
+
this.props = { ...this.props, ...key };
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
};
|
|
769
|
+
const ctx: any = {
|
|
770
|
+
app: {
|
|
771
|
+
jsonLogic: {
|
|
772
|
+
apply: vi.fn(() => true),
|
|
773
|
+
},
|
|
774
|
+
},
|
|
775
|
+
model: {
|
|
776
|
+
context: { form },
|
|
777
|
+
subModels: {
|
|
778
|
+
grid: {
|
|
779
|
+
subModels: {
|
|
780
|
+
items: [fieldModel],
|
|
781
|
+
},
|
|
782
|
+
},
|
|
783
|
+
},
|
|
784
|
+
},
|
|
785
|
+
setFormValues,
|
|
786
|
+
getAction: (name: string) => {
|
|
787
|
+
if (name === 'linkageSetFieldProps') return linkageSetFieldProps;
|
|
788
|
+
if (name === 'linkageAssignField') return linkageAssignField;
|
|
789
|
+
return null;
|
|
790
|
+
},
|
|
791
|
+
resolveJsonTemplate: vi.fn(async (value) => value),
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
await fieldLinkageRules.handler(ctx, {
|
|
795
|
+
value: [
|
|
796
|
+
{
|
|
797
|
+
key: 'rule-1',
|
|
798
|
+
enable: true,
|
|
799
|
+
condition: { logic: '$and', items: [] },
|
|
800
|
+
actions: [
|
|
801
|
+
{
|
|
802
|
+
key: 'action-1',
|
|
803
|
+
name: 'linkageSetFieldProps',
|
|
804
|
+
params: {
|
|
805
|
+
value: {
|
|
806
|
+
fields: ['name-field'],
|
|
807
|
+
state: 'hidden',
|
|
808
|
+
},
|
|
809
|
+
},
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
key: 'action-2',
|
|
813
|
+
name: 'linkageAssignField',
|
|
814
|
+
params: {
|
|
815
|
+
value: [
|
|
816
|
+
{
|
|
817
|
+
key: 'assign-1',
|
|
818
|
+
enable: true,
|
|
819
|
+
targetPath: 'name',
|
|
820
|
+
value: 'assigned',
|
|
821
|
+
},
|
|
822
|
+
],
|
|
823
|
+
},
|
|
824
|
+
},
|
|
825
|
+
],
|
|
826
|
+
},
|
|
827
|
+
],
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
expect(fieldModel.hidden).toBe(true);
|
|
831
|
+
expect(formValues.name).toBeUndefined();
|
|
832
|
+
expect(setFormValues).not.toHaveBeenCalled();
|
|
833
|
+
expect(form.setFieldValue).not.toHaveBeenCalled();
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
it('should not clear form value when a field is hidden with reserved value', async () => {
|
|
837
|
+
const setFormValues = vi.fn(async () => undefined);
|
|
838
|
+
const form = {
|
|
839
|
+
getFieldValue: vi.fn(() => '123'),
|
|
840
|
+
setFieldValue: vi.fn(),
|
|
841
|
+
};
|
|
842
|
+
const fieldModel: any = {
|
|
843
|
+
uid: 'name-field',
|
|
844
|
+
hidden: false,
|
|
845
|
+
context: { form },
|
|
846
|
+
props: {
|
|
847
|
+
label: 'Name',
|
|
848
|
+
},
|
|
849
|
+
getStepParams: vi.fn((flowKey: string, stepKey: string) => {
|
|
850
|
+
if (flowKey === 'fieldSettings' && stepKey === 'init') {
|
|
851
|
+
return { fieldPath: 'name' };
|
|
852
|
+
}
|
|
853
|
+
}),
|
|
854
|
+
setProps(key: any, value?: any) {
|
|
855
|
+
if (typeof key === 'string') {
|
|
856
|
+
this.props[key] = value;
|
|
857
|
+
} else {
|
|
858
|
+
this.props = { ...this.props, ...key };
|
|
859
|
+
}
|
|
860
|
+
},
|
|
861
|
+
};
|
|
862
|
+
const ctx: any = {
|
|
863
|
+
app: {
|
|
864
|
+
jsonLogic: {
|
|
865
|
+
apply: vi.fn(() => true),
|
|
866
|
+
},
|
|
867
|
+
},
|
|
868
|
+
model: {
|
|
869
|
+
context: { form },
|
|
870
|
+
subModels: {
|
|
871
|
+
grid: {
|
|
872
|
+
subModels: {
|
|
873
|
+
items: [fieldModel],
|
|
874
|
+
},
|
|
875
|
+
},
|
|
876
|
+
},
|
|
877
|
+
},
|
|
878
|
+
setFormValues,
|
|
879
|
+
getAction: (name: string) => (name === 'linkageSetFieldProps' ? linkageSetFieldProps : null),
|
|
880
|
+
resolveJsonTemplate: vi.fn(async (value) => value),
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
await fieldLinkageRules.handler(ctx, {
|
|
884
|
+
value: [
|
|
885
|
+
{
|
|
886
|
+
key: 'rule-1',
|
|
887
|
+
enable: true,
|
|
888
|
+
condition: { logic: '$and', items: [] },
|
|
889
|
+
actions: [
|
|
890
|
+
{
|
|
891
|
+
key: 'action-1',
|
|
892
|
+
name: 'linkageSetFieldProps',
|
|
893
|
+
params: {
|
|
894
|
+
value: {
|
|
895
|
+
fields: ['name-field'],
|
|
896
|
+
state: 'hiddenReservedValue',
|
|
897
|
+
},
|
|
898
|
+
},
|
|
899
|
+
},
|
|
900
|
+
],
|
|
901
|
+
},
|
|
902
|
+
],
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
expect(fieldModel.hidden).toBe(false);
|
|
906
|
+
expect(fieldModel.props.hidden).toBe(true);
|
|
907
|
+
expect(setFormValues).not.toHaveBeenCalled();
|
|
908
|
+
expect(form.setFieldValue).not.toHaveBeenCalled();
|
|
909
|
+
});
|
|
910
|
+
|
|
544
911
|
it('should keep all options selectable after options were limited once', async () => {
|
|
545
912
|
const fieldComponentModel: any = {
|
|
546
913
|
uid: 'status-field-component',
|
|
@@ -1768,6 +1768,7 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
|
|
|
1768
1768
|
const allModels: FlowModel[] = ctx.model.__allModels || (ctx.model.__allModels = []);
|
|
1769
1769
|
const modelsToApply = new Set<FlowModel>(allModels);
|
|
1770
1770
|
const patchPropsByModel = new Map<FlowModel, any>();
|
|
1771
|
+
const clearValueOnHiddenModelUids = new Set<string>();
|
|
1771
1772
|
const directValuePatches: Array<{ path: Array<string | number>; value: any; whenEmpty?: boolean }> = [];
|
|
1772
1773
|
const rootCollection = getCollectionFromModel((ctx.model as any)?.context?.blockModel ?? ctx.model);
|
|
1773
1774
|
const isSafeToWriteAssociationSubpath = (namePath: any): boolean => {
|
|
@@ -1878,6 +1879,16 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
|
|
|
1878
1879
|
...(whenEmpty ? { whenEmpty: true } : {}),
|
|
1879
1880
|
});
|
|
1880
1881
|
};
|
|
1882
|
+
const removePendingFormValuePatches = (path: any) => {
|
|
1883
|
+
const resolvedPath = resolveNamePathForPatch(path);
|
|
1884
|
+
if (!resolvedPath) return;
|
|
1885
|
+
const resolvedPathKey = namePathToPathKey(resolvedPath);
|
|
1886
|
+
for (let i = directValuePatches.length - 1; i >= 0; i--) {
|
|
1887
|
+
if (namePathToPathKey(directValuePatches[i].path) === resolvedPathKey) {
|
|
1888
|
+
directValuePatches.splice(i, 1);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
};
|
|
1881
1892
|
|
|
1882
1893
|
const getModelTargetPathForPatch = (model: any): string | null => {
|
|
1883
1894
|
if (!model || typeof model !== 'object') return null;
|
|
@@ -1973,6 +1984,23 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
|
|
|
1973
1984
|
|
|
1974
1985
|
return out;
|
|
1975
1986
|
};
|
|
1987
|
+
const getModelTargetPathForHiddenClear = (model: any): string | Array<string | number> | null => {
|
|
1988
|
+
const fieldPathArray = normalizeNamePathForKey(model?.context?.fieldPathArray);
|
|
1989
|
+
const targetPath = getModelTargetPathForPatch(model);
|
|
1990
|
+
if (fieldPathArray) {
|
|
1991
|
+
const targetPathLastString = targetPath
|
|
1992
|
+
? ([...parsePathString(targetPath)].reverse().find((seg) => typeof seg === 'string') as string | undefined)
|
|
1993
|
+
: undefined;
|
|
1994
|
+
const fieldPathArrayLastString = [...fieldPathArray].reverse().find((seg) => typeof seg === 'string');
|
|
1995
|
+
if (!targetPathLastString || targetPathLastString === fieldPathArrayLastString) {
|
|
1996
|
+
return fieldPathArray;
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
if (!targetPath) return null;
|
|
2001
|
+
|
|
2002
|
+
return resolveIndexedRelativePath(targetPath, model?.context?.fieldIndex) || targetPath;
|
|
2003
|
+
};
|
|
1976
2004
|
const getModelTargetPathKeys = (model: any): Set<string> => {
|
|
1977
2005
|
const keys = new Set<string>();
|
|
1978
2006
|
const fieldPathArray = normalizeNamePathForKey(model?.context?.fieldPathArray);
|
|
@@ -2060,6 +2088,13 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
|
|
|
2060
2088
|
...props,
|
|
2061
2089
|
});
|
|
2062
2090
|
|
|
2091
|
+
if (
|
|
2092
|
+
(action.name === 'linkageSetFieldProps' || action.name === 'subFormLinkageSetFieldProps') &&
|
|
2093
|
+
props?.hiddenModel === true
|
|
2094
|
+
) {
|
|
2095
|
+
clearValueOnHiddenModelUids.add(model?.uid || String(model));
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2063
2098
|
if (allModels.indexOf(model) === -1) {
|
|
2064
2099
|
allModels.push(model);
|
|
2065
2100
|
}
|
|
@@ -2147,6 +2182,24 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
|
|
|
2147
2182
|
}
|
|
2148
2183
|
}
|
|
2149
2184
|
|
|
2185
|
+
if (
|
|
2186
|
+
clearValueOnHiddenModelUids.has(uid) &&
|
|
2187
|
+
Object.prototype.hasOwnProperty.call(patchProps, 'hiddenModel') &&
|
|
2188
|
+
patchProps.hiddenModel === true
|
|
2189
|
+
) {
|
|
2190
|
+
const targetPath = getModelTargetPathForHiddenClear(model);
|
|
2191
|
+
if (!targetPath) {
|
|
2192
|
+
console.warn('[linkageRules] Skip clearing hidden field value due to missing target path', {
|
|
2193
|
+
flowKey: ctx.flowKey,
|
|
2194
|
+
modelUid: ctx.model?.uid,
|
|
2195
|
+
targetUid: model?.uid,
|
|
2196
|
+
});
|
|
2197
|
+
} else {
|
|
2198
|
+
removePendingFormValuePatches(targetPath);
|
|
2199
|
+
addFormValuePatch({ path: targetPath, value: undefined });
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2150
2203
|
model.__props = null;
|
|
2151
2204
|
});
|
|
2152
2205
|
hiddenStatePatches.forEach(({ model, hidden }) => {
|
|
@@ -31,7 +31,7 @@ import { FieldModel } from '../models';
|
|
|
31
31
|
import { RecordSelectFieldModel } from '../models/fields/AssociationFieldModel';
|
|
32
32
|
import { InputFieldModel } from '../models/fields/InputFieldModel';
|
|
33
33
|
import { ensureOptionsFromUiSchemaEnumIfAbsent } from '../internal/utils/enumOptionsUtils';
|
|
34
|
-
import { resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
|
|
34
|
+
import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
|
|
35
35
|
import { RunJSValueEditor } from './RunJSValueEditor';
|
|
36
36
|
import { buildDynamicNamePath } from '../models/blocks/form/dynamicNamePath';
|
|
37
37
|
|
|
@@ -592,7 +592,7 @@ export const DefaultValue = connect((props: Props) => {
|
|
|
592
592
|
}
|
|
593
593
|
}
|
|
594
594
|
}
|
|
595
|
-
}, [inputProps
|
|
595
|
+
}, [inputProps]);
|
|
596
596
|
return (
|
|
597
597
|
<div style={{ flexGrow: 1 }}>
|
|
598
598
|
<FlowModelRenderer model={tempRoot} showFlowSettings={false} />
|
|
@@ -600,11 +600,13 @@ export const DefaultValue = connect((props: Props) => {
|
|
|
600
600
|
);
|
|
601
601
|
};
|
|
602
602
|
return ConstantValueEditor;
|
|
603
|
-
}, [tempRoot]);
|
|
603
|
+
}, [tempRoot, value]);
|
|
604
|
+
|
|
605
|
+
const modelOperator = (model as { operator?: string })?.operator;
|
|
604
606
|
|
|
605
607
|
// 文本类多关键词:根据已注册的 operator schema 渲染(用于默认值配置)
|
|
606
608
|
React.useEffect(() => {
|
|
607
|
-
const operator =
|
|
609
|
+
const operator = modelOperator;
|
|
608
610
|
const fieldModel = tempRoot?.subModels?.fields?.[0];
|
|
609
611
|
if (!operator || !fieldModel) return;
|
|
610
612
|
const originalRender = fieldModel['__originalRender'] || fieldModel.render;
|
|
@@ -622,17 +624,21 @@ export const DefaultValue = connect((props: Props) => {
|
|
|
622
624
|
<Comp
|
|
623
625
|
{...fieldModel.props}
|
|
624
626
|
{...xProps}
|
|
625
|
-
style={{
|
|
627
|
+
style={{
|
|
628
|
+
width: '100%',
|
|
629
|
+
...pickStyle((fieldModel.props as Record<string, unknown>)?.style),
|
|
630
|
+
...pickStyle(xProps?.style),
|
|
631
|
+
}}
|
|
626
632
|
/>
|
|
627
633
|
);
|
|
628
634
|
} else if (typeof originalRender === 'function') {
|
|
629
635
|
fieldModel.render = originalRender;
|
|
630
636
|
}
|
|
631
|
-
}, [model, tempRoot,
|
|
637
|
+
}, [model, tempRoot, modelOperator]);
|
|
632
638
|
|
|
633
639
|
// 根据操作符 schema 的 x-component-props 补全临时字段的输入属性(如多选)
|
|
634
640
|
React.useEffect(() => {
|
|
635
|
-
const operator =
|
|
641
|
+
const operator = modelOperator;
|
|
636
642
|
const fieldModel = tempRoot?.subModels?.fields?.[0];
|
|
637
643
|
if (!fieldModel || !operator) return;
|
|
638
644
|
const ops = model.collectionField?.filterable?.operators || [];
|
|
@@ -641,7 +647,7 @@ export const DefaultValue = connect((props: Props) => {
|
|
|
641
647
|
if (xComponentProps) {
|
|
642
648
|
fieldModel.setProps(xComponentProps);
|
|
643
649
|
}
|
|
644
|
-
}, [model, tempRoot,
|
|
650
|
+
}, [model, tempRoot, modelOperator]);
|
|
645
651
|
|
|
646
652
|
const NullComponent = useMemo(() => {
|
|
647
653
|
function NullValuePlaceholder() {
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
isToManyAssociationField,
|
|
37
37
|
} from '../internal/utils/modelUtils';
|
|
38
38
|
import { RunJSValueEditor } from './RunJSValueEditor';
|
|
39
|
-
import { resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
|
|
39
|
+
import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
|
|
40
40
|
import { InputFieldModel } from '../models/fields/InputFieldModel';
|
|
41
41
|
import { normalizeFilterValueByOperator } from '../models/blocks/filter-form/valueNormalization';
|
|
42
42
|
import { FieldAssignExactDatePicker, type ExactDatePickerMode } from './FieldAssignExactDatePicker';
|
|
@@ -354,14 +354,6 @@ type ResolvedFieldContext = {
|
|
|
354
354
|
collectionField: CollectionField | null;
|
|
355
355
|
};
|
|
356
356
|
|
|
357
|
-
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
358
|
-
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
function pickStyle(value: unknown): React.CSSProperties | undefined {
|
|
362
|
-
return isPlainObject(value) ? (value as React.CSSProperties) : undefined;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
357
|
function withFullWidthStyle(style?: React.CSSProperties): React.CSSProperties {
|
|
366
358
|
return { ...style, width: '100%', minWidth: 0 };
|
|
367
359
|
}
|
|
@@ -1175,7 +1167,11 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
1175
1167
|
<Comp
|
|
1176
1168
|
{...fieldModel.props}
|
|
1177
1169
|
{...xProps}
|
|
1178
|
-
style={{
|
|
1170
|
+
style={{
|
|
1171
|
+
width: '100%',
|
|
1172
|
+
...pickStyle((fieldModel.props as Record<string, unknown>)?.style),
|
|
1173
|
+
...pickStyle(xProps?.style),
|
|
1174
|
+
}}
|
|
1179
1175
|
/>
|
|
1180
1176
|
);
|
|
1181
1177
|
rewrapReactiveRender(fieldModel);
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
UiSchemaEnumItem,
|
|
30
30
|
} from '../../internal/utils/enumOptionsUtils';
|
|
31
31
|
import { mergeItemMetaTreeForAssignValue } from '../FieldAssignValueInput';
|
|
32
|
-
import { resolveOperatorComponent } from '../../internal/utils/operatorSchemaHelper';
|
|
32
|
+
import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../../internal/utils/operatorSchemaHelper';
|
|
33
33
|
import { limitAssociationMetaTree } from './metaTreeAssociationDepth';
|
|
34
34
|
|
|
35
35
|
const { DateFilterDynamicComponent: DateFilterDynamicComponentLazy } = lazy(
|
|
@@ -354,7 +354,8 @@ export const LinkageFilterItem: React.FC<LinkageFilterItemProps> = observer((pro
|
|
|
354
354
|
return (inputProps: { value?: any; onChange?: (v: any) => void } & Record<string, any>) => {
|
|
355
355
|
const { value: inputValue, onChange, ...rest } = inputProps || {};
|
|
356
356
|
const nextProps = { ...componentProps };
|
|
357
|
-
|
|
357
|
+
const options = Array.isArray(nextProps.options) ? nextProps.options : undefined;
|
|
358
|
+
if ((!options || options.length === 0) && enumOptions.length > 0) {
|
|
358
359
|
nextProps.options = enumOptions;
|
|
359
360
|
}
|
|
360
361
|
const normalizedValue = Array.isArray(inputValue)
|
|
@@ -372,7 +373,7 @@ export const LinkageFilterItem: React.FC<LinkageFilterItemProps> = observer((pro
|
|
|
372
373
|
{...rest}
|
|
373
374
|
value={normalizedValue}
|
|
374
375
|
onChange={onChange}
|
|
375
|
-
style={{ width: 200, ...(nextProps
|
|
376
|
+
style={{ width: 200, ...pickStyle(nextProps.style), ...pickStyle(rest?.style) }}
|
|
376
377
|
/>
|
|
377
378
|
);
|
|
378
379
|
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
import _ from 'lodash';
|
|
27
27
|
import { NumberPicker } from '@formily/antd-v5';
|
|
28
28
|
import { enumToOptions, normalizeSelectRenderValue, UiSchemaEnumItem } from '../../internal/utils/enumOptionsUtils';
|
|
29
|
-
import { resolveOperatorComponent } from '../../internal/utils/operatorSchemaHelper';
|
|
29
|
+
import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../../internal/utils/operatorSchemaHelper';
|
|
30
30
|
import { limitAssociationMetaTree } from './metaTreeAssociationDepth';
|
|
31
31
|
|
|
32
32
|
const { DateFilterDynamicComponent: DateFilterDynamicComponentLazy } = lazy(
|
|
@@ -495,14 +495,15 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
|
|
|
495
495
|
if (resolved && supportKeyword) {
|
|
496
496
|
const { Comp, props: xProps } = resolved;
|
|
497
497
|
const nextProps = { ...xProps };
|
|
498
|
-
|
|
498
|
+
const options = Array.isArray(nextProps.options) ? nextProps.options : undefined;
|
|
499
|
+
if ((!options || options.length === 0) && enumOptions?.length) {
|
|
499
500
|
nextProps.options = enumOptions;
|
|
500
501
|
}
|
|
501
502
|
const style = {
|
|
502
503
|
flex: '1 1 40%',
|
|
503
504
|
minWidth: 160,
|
|
504
505
|
maxWidth: '100%',
|
|
505
|
-
...(nextProps
|
|
506
|
+
...pickStyle(nextProps.style),
|
|
506
507
|
};
|
|
507
508
|
const normalized =
|
|
508
509
|
Array.isArray(rightValue) && rightValue.every((v) => typeof v === 'string' || typeof v === 'number')
|
|
@@ -517,7 +518,7 @@ export const VariableFilterItem: React.FC<VariableFilterItemProps> = observer(
|
|
|
517
518
|
<div style={style}>
|
|
518
519
|
<Comp
|
|
519
520
|
{...nextProps}
|
|
520
|
-
style={{ width: '100%', ...(nextProps
|
|
521
|
+
style={{ width: '100%', ...pickStyle(nextProps.style) }}
|
|
521
522
|
value={normalized}
|
|
522
523
|
onChange={(vals: any) => setRightValue(vals)}
|
|
523
524
|
/>
|