@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.
- package/es/flow/actions/linkageRules.d.ts +24 -0
- package/es/flow/components/FieldAssignValueInput.d.ts +4 -30
- package/es/flow/components/field-value-variable/DateVariableEditor.d.ts +24 -0
- package/es/flow/components/field-value-variable/FieldValueVariableInput.d.ts +31 -0
- package/es/flow/components/field-value-variable/dateValue.d.ts +36 -0
- package/es/flow/components/field-value-variable/index.d.ts +11 -0
- package/es/flow/models/blocks/form/FormBlockModel.d.ts +6 -0
- package/es/flow/models/blocks/form/FormGridModel.d.ts +6 -0
- package/es/flow/models/blocks/form/value-runtime/rules.d.ts +1 -0
- package/es/index.mjs +101 -110
- package/lib/index.js +93 -102
- package/package.json +7 -7
- package/src/__tests__/app.test.tsx +15 -6
- package/src/components/AppComponents.tsx +4 -4
- package/src/flow/actions/__tests__/linkageRules.actionStates.test.ts +33 -0
- package/src/flow/actions/linkageRules.tsx +25 -7
- package/src/flow/components/FieldAssignValueInput.tsx +38 -621
- package/src/flow/components/field-value-variable/DateVariableEditor.tsx +181 -0
- package/src/flow/components/field-value-variable/FieldValueVariableInput.tsx +326 -0
- package/src/flow/components/field-value-variable/__tests__/FieldValueVariableInput.test.tsx +380 -0
- package/src/flow/components/field-value-variable/dateValue.ts +223 -0
- package/src/flow/components/field-value-variable/index.ts +12 -0
- package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +28 -53
- package/src/flow/models/blocks/form/FormBlockModel.tsx +4 -0
- package/src/flow/models/blocks/form/FormGridModel.tsx +4 -0
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +435 -0
- package/src/flow/models/blocks/form/value-runtime/rules.ts +67 -14
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +43 -19
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +8 -0
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/__tests__/popupContext.test.ts +120 -0
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/actions/PopupSubTableEditActionModel.tsx +10 -2
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +1 -0
- package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +20 -2
|
@@ -8,21 +8,12 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import React from 'react';
|
|
11
|
-
import {
|
|
12
|
-
import { Divider, Input, InputNumber, Select, Space, theme } from 'antd';
|
|
13
|
-
import { dayjs } from '@nocobase/utils/client';
|
|
11
|
+
import { Input } from 'antd';
|
|
14
12
|
import {
|
|
15
13
|
FlowModelRenderer,
|
|
16
|
-
VariableInput,
|
|
17
|
-
tExpr,
|
|
18
|
-
isVariableExpression,
|
|
19
|
-
parseValueToPath,
|
|
20
|
-
isRunJSValue,
|
|
21
|
-
isCtxDateExpression,
|
|
22
|
-
parseCtxDateExpression,
|
|
23
|
-
serializeCtxDateValue,
|
|
24
14
|
type CollectionField,
|
|
25
15
|
type MetaTreeNode,
|
|
16
|
+
type VariableInputProps,
|
|
26
17
|
useFlowContext,
|
|
27
18
|
EditableItemModel,
|
|
28
19
|
FlowModelContext,
|
|
@@ -39,289 +30,21 @@ import { RunJSValueEditor } from './RunJSValueEditor';
|
|
|
39
30
|
import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
|
|
40
31
|
import { InputFieldModel } from '../models/fields/InputFieldModel';
|
|
41
32
|
import { normalizeFilterValueByOperator } from '../models/blocks/filter-form/valueNormalization';
|
|
42
|
-
import { FieldAssignExactDatePicker, type ExactDatePickerMode } from './FieldAssignExactDatePicker';
|
|
43
33
|
import { limitAssociationMetaTree } from './filter/metaTreeAssociationDepth';
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
export type DateVariableExactNormalizeMode = 'none' | 'date' | 'datetimeNoTz' | 'iso';
|
|
59
|
-
|
|
60
|
-
const DATE_DYNAMIC_OPTION_KEYS = [
|
|
61
|
-
'exact',
|
|
62
|
-
'past',
|
|
63
|
-
'next',
|
|
64
|
-
'today',
|
|
65
|
-
'yesterday',
|
|
66
|
-
'tomorrow',
|
|
67
|
-
'thisWeek',
|
|
68
|
-
'lastWeek',
|
|
69
|
-
'nextWeek',
|
|
70
|
-
'thisMonth',
|
|
71
|
-
'lastMonth',
|
|
72
|
-
'nextMonth',
|
|
73
|
-
'thisQuarter',
|
|
74
|
-
'lastQuarter',
|
|
75
|
-
'nextQuarter',
|
|
76
|
-
'thisYear',
|
|
77
|
-
'lastYear',
|
|
78
|
-
'nextYear',
|
|
79
|
-
] as const;
|
|
80
|
-
|
|
81
|
-
type DateDynamicOptionValue = (typeof DATE_DYNAMIC_OPTION_KEYS)[number] | 'now';
|
|
82
|
-
|
|
83
|
-
const DATE_DYNAMIC_OPTION_LABELS: Record<(typeof DATE_DYNAMIC_OPTION_KEYS)[number], string> = {
|
|
84
|
-
exact: 'Exact day',
|
|
85
|
-
past: 'Past',
|
|
86
|
-
next: 'Next',
|
|
87
|
-
today: 'Today',
|
|
88
|
-
yesterday: 'Yesterday',
|
|
89
|
-
tomorrow: 'Tomorrow',
|
|
90
|
-
thisWeek: 'This Week',
|
|
91
|
-
lastWeek: 'Last Week',
|
|
92
|
-
nextWeek: 'Next Week',
|
|
93
|
-
thisMonth: 'This Month',
|
|
94
|
-
lastMonth: 'Last Month',
|
|
95
|
-
nextMonth: 'Next Month',
|
|
96
|
-
thisQuarter: 'This Quarter',
|
|
97
|
-
lastQuarter: 'Last Quarter',
|
|
98
|
-
nextQuarter: 'Next Quarter',
|
|
99
|
-
thisYear: 'This Year',
|
|
100
|
-
lastYear: 'Last Year',
|
|
101
|
-
nextYear: 'Next Year',
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
function buildDateDynamicOptions(t?: (key: string) => string, includeNow = false) {
|
|
105
|
-
const options: Array<{ value: DateDynamicOptionValue; label: string }> = DATE_DYNAMIC_OPTION_KEYS.map((key) => ({
|
|
106
|
-
value: key,
|
|
107
|
-
label: t?.(DATE_DYNAMIC_OPTION_LABELS[key]) ?? DATE_DYNAMIC_OPTION_LABELS[key],
|
|
108
|
-
}));
|
|
109
|
-
|
|
110
|
-
if (includeNow) {
|
|
111
|
-
options.splice(3, 0, { value: 'now', label: t?.('Now') ?? 'Now' });
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return options;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function parseDateByFormat(value: string, format: string): dayjs.Dayjs | null {
|
|
118
|
-
const raw = String(value || '').trim();
|
|
119
|
-
if (!raw) return null;
|
|
120
|
-
|
|
121
|
-
const hasTimezone = /(?:Z|[+-]\d{2}:\d{2})$/i.test(raw);
|
|
122
|
-
if (hasTimezone) {
|
|
123
|
-
const parsed = dayjs(raw);
|
|
124
|
-
if (parsed.isValid()) {
|
|
125
|
-
return parsed;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (format) {
|
|
130
|
-
const strict = dayjs(raw, format, true);
|
|
131
|
-
if (strict.isValid()) {
|
|
132
|
-
return strict;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const fallback = dayjs(raw);
|
|
137
|
-
if (fallback.isValid()) {
|
|
138
|
-
return fallback;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (format) {
|
|
142
|
-
const loose = dayjs(raw, format);
|
|
143
|
-
if (loose.isValid()) {
|
|
144
|
-
return loose;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function parseDateFromRawValue(value: unknown, format: string): dayjs.Dayjs | null {
|
|
152
|
-
if (dayjs.isDayjs(value)) {
|
|
153
|
-
return value;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (value instanceof Date) {
|
|
157
|
-
const parsedDate = dayjs(value);
|
|
158
|
-
return parsedDate.isValid() ? parsedDate : null;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (typeof value === 'string') {
|
|
162
|
-
return parseDateByFormat(value, format);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function normalizeExactDateValue(
|
|
169
|
-
value: unknown,
|
|
170
|
-
options: {
|
|
171
|
-
format: string;
|
|
172
|
-
showTime: boolean;
|
|
173
|
-
exactNormalizeMode: DateVariableExactNormalizeMode;
|
|
174
|
-
},
|
|
175
|
-
): unknown {
|
|
176
|
-
const parsed = parseDateFromRawValue(value, options.format);
|
|
177
|
-
if (!parsed?.isValid()) {
|
|
178
|
-
return value;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
switch (options.exactNormalizeMode) {
|
|
182
|
-
case 'date':
|
|
183
|
-
return parsed.format(DATE_ONLY_OUTPUT_FORMAT);
|
|
184
|
-
case 'datetimeNoTz':
|
|
185
|
-
return parsed.format(options.showTime ? DATETIME_NO_TZ_OUTPUT_FORMAT : DATE_ONLY_OUTPUT_FORMAT);
|
|
186
|
-
case 'iso':
|
|
187
|
-
return parsed.toISOString();
|
|
188
|
-
default:
|
|
189
|
-
return value;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function toExactPickerSingleValue(rawValue: unknown, format: string): dayjs.Dayjs | null {
|
|
194
|
-
const parsed = parseDateFromRawValue(rawValue, format);
|
|
195
|
-
return parsed?.isValid() ? parsed : null;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function toExactPickerRangeValue(rawValue: unknown, format: string): [dayjs.Dayjs, dayjs.Dayjs] | null {
|
|
199
|
-
if (!Array.isArray(rawValue)) return null;
|
|
200
|
-
const left = toExactPickerSingleValue(rawValue[0], format);
|
|
201
|
-
const right = toExactPickerSingleValue(rawValue[1], format);
|
|
202
|
-
if (!left || !right) return null;
|
|
203
|
-
return [left, right];
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export function toExactPickerDisplayValue(
|
|
207
|
-
rawValue: unknown,
|
|
208
|
-
options: {
|
|
209
|
-
format: string;
|
|
210
|
-
isRange: boolean;
|
|
211
|
-
},
|
|
212
|
-
): dayjs.Dayjs | [dayjs.Dayjs, dayjs.Dayjs] | null {
|
|
213
|
-
if (options.isRange) {
|
|
214
|
-
return toExactPickerRangeValue(rawValue, options.format);
|
|
215
|
-
}
|
|
216
|
-
return toExactPickerSingleValue(rawValue, options.format);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function getDateVariableExactNormalizeMode(fieldInterface: string): DateVariableExactNormalizeMode {
|
|
220
|
-
if (fieldInterface === 'date') {
|
|
221
|
-
return 'date';
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (fieldInterface === 'datetimeNoTz') {
|
|
225
|
-
return 'datetimeNoTz';
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (TZ_AWARE_DATE_INTERFACES.has(fieldInterface)) {
|
|
229
|
-
return 'iso';
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return 'none';
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export function normalizeDateVariableExactValue(
|
|
236
|
-
rawValue: any,
|
|
237
|
-
options: {
|
|
238
|
-
exactNormalizeMode: DateVariableExactNormalizeMode;
|
|
239
|
-
format: string;
|
|
240
|
-
showTime: boolean;
|
|
241
|
-
},
|
|
242
|
-
): any {
|
|
243
|
-
if (options.exactNormalizeMode === 'none') {
|
|
244
|
-
return rawValue;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (typeof rawValue === 'string') {
|
|
248
|
-
return normalizeExactDateValue(rawValue, options);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (dayjs.isDayjs(rawValue) || rawValue instanceof Date) {
|
|
252
|
-
return normalizeExactDateValue(rawValue, options);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (Array.isArray(rawValue)) {
|
|
256
|
-
return rawValue.map((item) => {
|
|
257
|
-
if (typeof item === 'string' || dayjs.isDayjs(item) || item instanceof Date) {
|
|
258
|
-
return normalizeExactDateValue(item, options);
|
|
259
|
-
}
|
|
260
|
-
return item;
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
return rawValue;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
type DateVariableComponentProps = {
|
|
268
|
-
picker: ExactDatePickerMode;
|
|
269
|
-
showTime: boolean;
|
|
270
|
-
timeFormat: string;
|
|
271
|
-
format: string;
|
|
272
|
-
exactNormalizeMode: DateVariableExactNormalizeMode;
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
function normalizeExactDatePickerMode(value: unknown): ExactDatePickerMode {
|
|
276
|
-
if (value === 'year' || value === 'quarter' || value === 'month' || value === 'date') {
|
|
277
|
-
return value;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return 'date';
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const DEFAULT_DATE_VARIABLE_COMPONENT_PROPS: DateVariableComponentProps = {
|
|
284
|
-
picker: 'date',
|
|
285
|
-
showTime: false,
|
|
286
|
-
timeFormat: 'HH:mm:ss',
|
|
287
|
-
format: 'YYYY-MM-DD',
|
|
288
|
-
exactNormalizeMode: 'none',
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
function getFieldInterface(field: any): string {
|
|
292
|
-
return typeof field?.interface === 'string' ? field.interface : '';
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
function getFieldComponentProps(field: any): Record<string, any> {
|
|
296
|
-
return (
|
|
297
|
-
(typeof field?.getComponentProps === 'function' ? field.getComponentProps() : null) ||
|
|
298
|
-
field?.uiSchema?.['x-component-props'] ||
|
|
299
|
-
{}
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
export function normalizeDateVariableOutput(rawValue: any, options: DateVariableComponentProps): any {
|
|
304
|
-
if (rawValue === null || isRunJSValue(rawValue)) {
|
|
305
|
-
return rawValue;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (typeof rawValue === 'string' && isVariableExpression(rawValue) && !isCtxDateExpression(rawValue)) {
|
|
309
|
-
return rawValue;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (rawValue === '' || typeof rawValue === 'undefined') {
|
|
313
|
-
return '';
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const normalized = normalizeDateVariableExactValue(rawValue, {
|
|
317
|
-
exactNormalizeMode: options.exactNormalizeMode,
|
|
318
|
-
format: options.format || 'YYYY-MM-DD HH:mm:ss',
|
|
319
|
-
showTime: options.showTime,
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
const serialized = serializeCtxDateValue(normalized);
|
|
323
|
-
return serialized || normalized;
|
|
324
|
-
}
|
|
34
|
+
import {
|
|
35
|
+
DEFAULT_DATE_VARIABLE_COMPONENT_PROPS,
|
|
36
|
+
FieldValueVariableInput,
|
|
37
|
+
getFieldInterface,
|
|
38
|
+
isDateLikeField as isDateLikeCollectionField,
|
|
39
|
+
resolveDateVariableComponentProps,
|
|
40
|
+
} from './field-value-variable';
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
normalizeDateVariableExactValue,
|
|
44
|
+
normalizeDateVariableOutput,
|
|
45
|
+
toExactPickerDisplayValue,
|
|
46
|
+
type DateVariableExactNormalizeMode,
|
|
47
|
+
} from './field-value-variable';
|
|
325
48
|
|
|
326
49
|
interface Props {
|
|
327
50
|
/** 赋值目标路径,例如 `title` / `users.nickname` / `user.name` */
|
|
@@ -343,15 +66,14 @@ interface Props {
|
|
|
343
66
|
value?: string;
|
|
344
67
|
};
|
|
345
68
|
/**
|
|
346
|
-
*
|
|
347
|
-
* 默认 false,保持历史行为。
|
|
69
|
+
* @deprecated Date 已作为独立一级变量提供,此参数仅为调用兼容保留。
|
|
348
70
|
*/
|
|
349
71
|
enableDateVariableAsConstant?: boolean;
|
|
350
72
|
/** 是否允许在变量选择器中使用 RunJS。默认 true,保持历史行为。 */
|
|
351
73
|
allowRunJS?: boolean;
|
|
352
74
|
maxAssociationFieldDepth?: number;
|
|
353
75
|
disabled?: boolean;
|
|
354
|
-
variableConverters?:
|
|
76
|
+
variableConverters?: VariableInputProps['converters'];
|
|
355
77
|
}
|
|
356
78
|
|
|
357
79
|
type ResolvedFieldContext = {
|
|
@@ -721,7 +443,6 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
721
443
|
operatorMetaList,
|
|
722
444
|
preferFormItemFieldModel,
|
|
723
445
|
associationFieldNamesOverride,
|
|
724
|
-
enableDateVariableAsConstant = false,
|
|
725
446
|
allowRunJS = true,
|
|
726
447
|
maxAssociationFieldDepth = 2,
|
|
727
448
|
disabled = false,
|
|
@@ -905,69 +626,18 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
905
626
|
}, [cf, currentAllowMultiple, itemCollectionField]);
|
|
906
627
|
|
|
907
628
|
const isDateLikeField = React.useMemo(() => {
|
|
908
|
-
if (sourceInterface && DATE_FIELD_INTERFACES.has(sourceInterface)) {
|
|
909
|
-
return true;
|
|
910
|
-
}
|
|
911
|
-
|
|
912
629
|
const leaf =
|
|
913
630
|
(typeof fieldName === 'string' && fieldName) ||
|
|
914
631
|
(typeof targetPath === 'string' ? targetPath.split('.').filter(Boolean).slice(-1)[0] : '');
|
|
915
632
|
|
|
916
|
-
return
|
|
917
|
-
}, [fieldName, sourceInterface, targetPath]);
|
|
918
|
-
|
|
919
|
-
const useDateVariableConstant = enableDateVariableAsConstant && isDateLikeField;
|
|
633
|
+
return isDateLikeCollectionField(sourceCollectionField, leaf, sourceInterface);
|
|
634
|
+
}, [fieldName, sourceCollectionField, sourceInterface, targetPath]);
|
|
920
635
|
|
|
921
636
|
const dateVariableComponentProps = React.useMemo(() => {
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
const componentProps = getFieldComponentProps(sourceCollectionField);
|
|
927
|
-
|
|
928
|
-
const picker = normalizeExactDatePickerMode(componentProps?.picker);
|
|
929
|
-
const inferredShowTime = ['datetime', 'datetimeNoTz', 'createdAt', 'updatedAt', 'unixTimestamp'].includes(
|
|
930
|
-
sourceInterface,
|
|
931
|
-
);
|
|
932
|
-
const showTime = typeof componentProps?.showTime === 'boolean' ? componentProps.showTime : inferredShowTime;
|
|
933
|
-
|
|
934
|
-
const dateFormat =
|
|
935
|
-
typeof componentProps?.dateFormat === 'string' && componentProps.dateFormat
|
|
936
|
-
? componentProps.dateFormat
|
|
937
|
-
: typeof componentProps?.format === 'string' && componentProps.format
|
|
938
|
-
? componentProps.format.split(' ')[0]
|
|
939
|
-
: 'YYYY-MM-DD';
|
|
940
|
-
const timeFormat =
|
|
941
|
-
typeof componentProps?.timeFormat === 'string' && componentProps.timeFormat
|
|
942
|
-
? componentProps.timeFormat
|
|
943
|
-
: 'HH:mm:ss';
|
|
944
|
-
|
|
945
|
-
const format =
|
|
946
|
-
typeof componentProps?.format === 'string' && componentProps.format
|
|
947
|
-
? componentProps.format
|
|
948
|
-
: showTime
|
|
949
|
-
? `${dateFormat} ${timeFormat}`
|
|
950
|
-
: dateFormat;
|
|
951
|
-
|
|
952
|
-
return {
|
|
953
|
-
picker,
|
|
954
|
-
showTime,
|
|
955
|
-
timeFormat,
|
|
956
|
-
format,
|
|
957
|
-
exactNormalizeMode: getDateVariableExactNormalizeMode(sourceInterface),
|
|
958
|
-
};
|
|
959
|
-
}, [sourceCollectionField, sourceInterface, useDateVariableConstant]);
|
|
960
|
-
|
|
961
|
-
const dateVariableDisplayProps = React.useMemo(() => {
|
|
962
|
-
const { exactNormalizeMode, ...rest } = dateVariableComponentProps;
|
|
963
|
-
return rest;
|
|
964
|
-
}, [dateVariableComponentProps]);
|
|
965
|
-
|
|
966
|
-
const dateVariableDisplayPropsRef = React.useRef(dateVariableDisplayProps);
|
|
967
|
-
dateVariableDisplayPropsRef.current = dateVariableDisplayProps;
|
|
968
|
-
|
|
969
|
-
const dateVariableTranslateRef = React.useRef(flowCtx.t);
|
|
970
|
-
dateVariableTranslateRef.current = flowCtx.t;
|
|
637
|
+
return isDateLikeField
|
|
638
|
+
? resolveDateVariableComponentProps(sourceCollectionField, sourceInterface)
|
|
639
|
+
: DEFAULT_DATE_VARIABLE_COMPONENT_PROPS;
|
|
640
|
+
}, [isDateLikeField, sourceCollectionField, sourceInterface]);
|
|
971
641
|
|
|
972
642
|
const coerceEmptyValueForRenderer = React.useCallback(
|
|
973
643
|
(v: any) => {
|
|
@@ -1255,182 +925,6 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
1255
925
|
return C;
|
|
1256
926
|
}, [placeholder, tempRoot, coerceEmptyValueForRenderer, normalizeEventValue, operator]);
|
|
1257
927
|
|
|
1258
|
-
const DateVariableConstantEditor = React.useMemo(() => {
|
|
1259
|
-
const C: React.FC<any> = (inputProps) => {
|
|
1260
|
-
const wrapperStyle = pickStyle(inputProps?.style);
|
|
1261
|
-
const raw = inputProps?.value;
|
|
1262
|
-
const isDisabled = Boolean(inputProps?.disabled);
|
|
1263
|
-
const parsed = isCtxDateExpression(raw) ? parseCtxDateExpression(raw) : raw;
|
|
1264
|
-
const parsedValue = typeof parsed === 'undefined' ? undefined : parsed;
|
|
1265
|
-
const { token } = theme.useToken();
|
|
1266
|
-
const [open, setOpen] = React.useState(false);
|
|
1267
|
-
const t = dateVariableTranslateRef.current;
|
|
1268
|
-
const datePickerProps = dateVariableDisplayPropsRef.current;
|
|
1269
|
-
const options = React.useMemo(() => buildDateDynamicOptions(t, true), [t]);
|
|
1270
|
-
|
|
1271
|
-
const dynamicType =
|
|
1272
|
-
parsedValue && typeof parsedValue === 'object' && !Array.isArray(parsedValue)
|
|
1273
|
-
? (parsedValue as any)?.type
|
|
1274
|
-
: undefined;
|
|
1275
|
-
const selectedType = typeof dynamicType === 'string' && dynamicType ? dynamicType : 'exact';
|
|
1276
|
-
const isRange = Array.isArray(parsedValue);
|
|
1277
|
-
const exactSingleValue = toExactPickerDisplayValue(parsedValue, {
|
|
1278
|
-
format: datePickerProps.format,
|
|
1279
|
-
isRange: false,
|
|
1280
|
-
});
|
|
1281
|
-
const exactRangeValue = toExactPickerDisplayValue(parsedValue, {
|
|
1282
|
-
format: datePickerProps.format,
|
|
1283
|
-
isRange: true,
|
|
1284
|
-
});
|
|
1285
|
-
|
|
1286
|
-
const handleSelect = (val: string) => {
|
|
1287
|
-
if (isDisabled) {
|
|
1288
|
-
return;
|
|
1289
|
-
}
|
|
1290
|
-
setOpen(false);
|
|
1291
|
-
if (val === 'exact') {
|
|
1292
|
-
inputProps?.onChange?.('');
|
|
1293
|
-
return;
|
|
1294
|
-
}
|
|
1295
|
-
const next: any = { type: val };
|
|
1296
|
-
if (val === 'past' || val === 'next') {
|
|
1297
|
-
next.number = 1;
|
|
1298
|
-
next.unit = 'day';
|
|
1299
|
-
}
|
|
1300
|
-
inputProps?.onChange?.(next);
|
|
1301
|
-
};
|
|
1302
|
-
|
|
1303
|
-
const handleExactSingleChange = (nextValue: any) => {
|
|
1304
|
-
if (isDisabled) {
|
|
1305
|
-
return;
|
|
1306
|
-
}
|
|
1307
|
-
inputProps?.onChange?.(nextValue || '');
|
|
1308
|
-
};
|
|
1309
|
-
|
|
1310
|
-
const handleExactRangeChange = (nextValue: any) => {
|
|
1311
|
-
if (isDisabled) {
|
|
1312
|
-
return;
|
|
1313
|
-
}
|
|
1314
|
-
inputProps?.onChange?.(nextValue || '');
|
|
1315
|
-
};
|
|
1316
|
-
|
|
1317
|
-
const dropdownRender = () => {
|
|
1318
|
-
const firstPart = options.slice(0, 3);
|
|
1319
|
-
const secondPart = options.slice(3);
|
|
1320
|
-
const optionStyle = css`
|
|
1321
|
-
padding: 3px 10px;
|
|
1322
|
-
cursor: pointer;
|
|
1323
|
-
white-space: nowrap;
|
|
1324
|
-
overflow: hidden;
|
|
1325
|
-
text-overflow: ellipsis;
|
|
1326
|
-
&:hover {
|
|
1327
|
-
background-color: ${token.colorFillSecondary};
|
|
1328
|
-
}
|
|
1329
|
-
`;
|
|
1330
|
-
return (
|
|
1331
|
-
<div style={{ maxHeight: 300, overflowY: 'auto' }}>
|
|
1332
|
-
{firstPart.map((opt) => (
|
|
1333
|
-
<div key={opt.value} role="option" onClick={() => handleSelect(opt.value)} className={optionStyle}>
|
|
1334
|
-
{opt.label}
|
|
1335
|
-
</div>
|
|
1336
|
-
))}
|
|
1337
|
-
<Divider style={{ margin: '4px 0' }} />
|
|
1338
|
-
{secondPart.map((opt) => (
|
|
1339
|
-
<div
|
|
1340
|
-
key={opt.value}
|
|
1341
|
-
role="option"
|
|
1342
|
-
className={optionStyle}
|
|
1343
|
-
onClick={() => handleSelect(opt.value)}
|
|
1344
|
-
title={opt.label}
|
|
1345
|
-
>
|
|
1346
|
-
{opt.label}
|
|
1347
|
-
</div>
|
|
1348
|
-
))}
|
|
1349
|
-
</div>
|
|
1350
|
-
);
|
|
1351
|
-
};
|
|
1352
|
-
|
|
1353
|
-
return (
|
|
1354
|
-
<Space.Compact style={withFullWidthStyle(wrapperStyle)}>
|
|
1355
|
-
<Select
|
|
1356
|
-
options={options}
|
|
1357
|
-
open={open}
|
|
1358
|
-
onDropdownVisibleChange={(nextOpen) => {
|
|
1359
|
-
if (!isDisabled) {
|
|
1360
|
-
setOpen(nextOpen);
|
|
1361
|
-
}
|
|
1362
|
-
}}
|
|
1363
|
-
allowClear={false}
|
|
1364
|
-
style={{
|
|
1365
|
-
width: '100%',
|
|
1366
|
-
minWidth: 100,
|
|
1367
|
-
maxWidth: ['past', 'next', 'exact', undefined].includes(dynamicType) ? 100 : null,
|
|
1368
|
-
}}
|
|
1369
|
-
value={selectedType}
|
|
1370
|
-
onChange={handleSelect}
|
|
1371
|
-
dropdownRender={dropdownRender}
|
|
1372
|
-
disabled={isDisabled}
|
|
1373
|
-
/>
|
|
1374
|
-
{['past', 'next'].includes(selectedType) && [
|
|
1375
|
-
<InputNumber
|
|
1376
|
-
key="number"
|
|
1377
|
-
style={{ flex: 1 }}
|
|
1378
|
-
value={(parsedValue as any)?.number}
|
|
1379
|
-
disabled={isDisabled}
|
|
1380
|
-
onChange={(nextNumber) => {
|
|
1381
|
-
if (isDisabled) {
|
|
1382
|
-
return;
|
|
1383
|
-
}
|
|
1384
|
-
inputProps?.onChange?.({
|
|
1385
|
-
...(parsedValue as any),
|
|
1386
|
-
type: selectedType,
|
|
1387
|
-
number: nextNumber,
|
|
1388
|
-
unit: (parsedValue as any)?.unit || 'day',
|
|
1389
|
-
});
|
|
1390
|
-
}}
|
|
1391
|
-
/>,
|
|
1392
|
-
<Select
|
|
1393
|
-
key="unit"
|
|
1394
|
-
value={(parsedValue as any)?.unit}
|
|
1395
|
-
style={{ minWidth: 130, maxWidth: 140 }}
|
|
1396
|
-
disabled={isDisabled}
|
|
1397
|
-
onChange={(nextUnit) => {
|
|
1398
|
-
if (isDisabled) {
|
|
1399
|
-
return;
|
|
1400
|
-
}
|
|
1401
|
-
inputProps?.onChange?.({
|
|
1402
|
-
...(parsedValue as any),
|
|
1403
|
-
type: selectedType,
|
|
1404
|
-
unit: nextUnit,
|
|
1405
|
-
number: (parsedValue as any)?.number || 1,
|
|
1406
|
-
});
|
|
1407
|
-
}}
|
|
1408
|
-
options={[
|
|
1409
|
-
{ value: 'day', label: t?.('Day') ?? 'Day' },
|
|
1410
|
-
{ value: 'week', label: t?.('Calendar week') ?? 'Calendar week' },
|
|
1411
|
-
{ value: 'month', label: t?.('Calendar Month') ?? 'Calendar Month' },
|
|
1412
|
-
{ value: 'year', label: t?.('Calendar Year') ?? 'Calendar Year' },
|
|
1413
|
-
]}
|
|
1414
|
-
popupMatchSelectWidth
|
|
1415
|
-
/>,
|
|
1416
|
-
]}
|
|
1417
|
-
{(selectedType === 'exact' || !selectedType) && (
|
|
1418
|
-
<FieldAssignExactDatePicker
|
|
1419
|
-
{...datePickerProps}
|
|
1420
|
-
isRange={isRange}
|
|
1421
|
-
value={isRange ? exactRangeValue : exactSingleValue}
|
|
1422
|
-
onChange={isRange ? handleExactRangeChange : handleExactSingleChange}
|
|
1423
|
-
disabled={isDisabled}
|
|
1424
|
-
style={{ flex: 1 }}
|
|
1425
|
-
/>
|
|
1426
|
-
)}
|
|
1427
|
-
</Space.Compact>
|
|
1428
|
-
);
|
|
1429
|
-
};
|
|
1430
|
-
|
|
1431
|
-
return C;
|
|
1432
|
-
}, []);
|
|
1433
|
-
|
|
1434
928
|
const NullComponent = React.useMemo(() => {
|
|
1435
929
|
const N: React.FC = () => (
|
|
1436
930
|
<Input placeholder={`<${flowCtx.t?.('Null') ?? 'Null'}>`} readOnly style={{ width: '100%' }} />
|
|
@@ -1450,60 +944,15 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
1450
944
|
return C;
|
|
1451
945
|
}, [flowCtx]);
|
|
1452
946
|
|
|
1453
|
-
const
|
|
1454
|
-
|
|
1455
|
-
const metaTree = React.useMemo<() => Promise<any[]>>(() => {
|
|
947
|
+
const baseMetaTree = React.useMemo<() => Promise<MetaTreeNode[]>>(() => {
|
|
1456
948
|
return async () => {
|
|
1457
949
|
const base = (await flowCtx.getPropertyMetaTree?.()) || [];
|
|
1458
950
|
const extra = extraMetaTreeRef.current;
|
|
1459
951
|
const extraTree = Array.isArray(extra) ? extra : [];
|
|
1460
952
|
const mergedBase = mergeItemMetaTreeForAssignValue(base as MetaTreeNode[], extraTree as MetaTreeNode[]);
|
|
1461
|
-
|
|
1462
|
-
return [
|
|
1463
|
-
{
|
|
1464
|
-
title: tExpr('Constant'),
|
|
1465
|
-
name: 'constant',
|
|
1466
|
-
type: 'string',
|
|
1467
|
-
paths: ['constant'],
|
|
1468
|
-
render: ConstantEditor,
|
|
1469
|
-
},
|
|
1470
|
-
{ title: tExpr('Null'), name: 'null', type: 'object', paths: ['null'], render: NullComponent },
|
|
1471
|
-
...(allowRunJS
|
|
1472
|
-
? [{ title: tExpr('RunJS'), name: 'runjs', type: 'object', paths: ['runjs'], render: RunJSComponent }]
|
|
1473
|
-
: []),
|
|
1474
|
-
...limitedBase,
|
|
1475
|
-
];
|
|
953
|
+
return limitAssociationMetaTree(mergedBase, { maxAssociationDepth: maxAssociationFieldDepth });
|
|
1476
954
|
};
|
|
1477
|
-
}, [flowCtx,
|
|
1478
|
-
|
|
1479
|
-
const displayValue = React.useMemo(() => {
|
|
1480
|
-
if (!useDateVariableConstant) {
|
|
1481
|
-
return value;
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
if (isCtxDateExpression(value)) {
|
|
1485
|
-
const parsed = parseCtxDateExpression(value);
|
|
1486
|
-
return typeof parsed === 'undefined' ? '' : parsed;
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
return value;
|
|
1490
|
-
}, [useDateVariableConstant, value]);
|
|
1491
|
-
|
|
1492
|
-
const handleVariableInputChange = React.useCallback(
|
|
1493
|
-
(nextValue: any) => {
|
|
1494
|
-
if (disabled) {
|
|
1495
|
-
return;
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
if (!useDateVariableConstant) {
|
|
1499
|
-
onChange(nextValue);
|
|
1500
|
-
return;
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
onChange(normalizeDateVariableOutput(nextValue, dateVariableComponentProps));
|
|
1504
|
-
},
|
|
1505
|
-
[dateVariableComponentProps, disabled, onChange, useDateVariableConstant],
|
|
1506
|
-
);
|
|
955
|
+
}, [flowCtx, maxAssociationFieldDepth]);
|
|
1507
956
|
|
|
1508
957
|
if (!fieldPath) {
|
|
1509
958
|
// 不可用占位
|
|
@@ -1511,52 +960,20 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
1511
960
|
}
|
|
1512
961
|
|
|
1513
962
|
return (
|
|
1514
|
-
<
|
|
1515
|
-
value={
|
|
1516
|
-
onChange={
|
|
1517
|
-
|
|
963
|
+
<FieldValueVariableInput
|
|
964
|
+
value={value}
|
|
965
|
+
onChange={onChange}
|
|
966
|
+
baseMetaTree={baseMetaTree}
|
|
967
|
+
constantComponent={ConstantValueEditor}
|
|
968
|
+
nullComponent={NullComponent}
|
|
969
|
+
runJSComponent={RunJSComponent}
|
|
970
|
+
isDateLikeField={isDateLikeField}
|
|
971
|
+
dateComponentProps={dateVariableComponentProps}
|
|
1518
972
|
style={{ width: '100%' }}
|
|
1519
973
|
clearValue={''}
|
|
974
|
+
allowRunJS={allowRunJS}
|
|
1520
975
|
disabled={disabled}
|
|
1521
|
-
converters={
|
|
1522
|
-
...variableConverters,
|
|
1523
|
-
renderInputComponent: (meta) => {
|
|
1524
|
-
const external = variableConverters?.renderInputComponent?.(meta ?? null);
|
|
1525
|
-
if (external) {
|
|
1526
|
-
return external;
|
|
1527
|
-
}
|
|
1528
|
-
const firstPath = meta?.paths?.[0];
|
|
1529
|
-
if (firstPath === 'constant') return ConstantEditor;
|
|
1530
|
-
if (firstPath === 'null') return NullComponent;
|
|
1531
|
-
if (allowRunJS && firstPath === 'runjs') return RunJSComponent;
|
|
1532
|
-
return null;
|
|
1533
|
-
},
|
|
1534
|
-
resolveValueFromPath: (item) => {
|
|
1535
|
-
const external = variableConverters?.resolveValueFromPath?.(item);
|
|
1536
|
-
if (external !== undefined) {
|
|
1537
|
-
return external;
|
|
1538
|
-
}
|
|
1539
|
-
const firstPath = item?.paths?.[0];
|
|
1540
|
-
if (firstPath === 'constant') {
|
|
1541
|
-
return useDateVariableConstant ? { type: 'today' } : '';
|
|
1542
|
-
}
|
|
1543
|
-
if (firstPath === 'null') return null;
|
|
1544
|
-
if (allowRunJS && firstPath === 'runjs') return { code: '', version: 'v2' };
|
|
1545
|
-
return undefined;
|
|
1546
|
-
},
|
|
1547
|
-
resolvePathFromValue: (currentValue) => {
|
|
1548
|
-
const external = variableConverters?.resolvePathFromValue?.(currentValue);
|
|
1549
|
-
if (external !== undefined) {
|
|
1550
|
-
return external;
|
|
1551
|
-
}
|
|
1552
|
-
if (currentValue === null) return ['null'];
|
|
1553
|
-
if (allowRunJS && isRunJSValue(currentValue)) return ['runjs'];
|
|
1554
|
-
if (useDateVariableConstant && isCtxDateExpression(currentValue)) {
|
|
1555
|
-
return ['constant'];
|
|
1556
|
-
}
|
|
1557
|
-
return isVariableExpression(currentValue) ? parseValueToPath(currentValue) : ['constant'];
|
|
1558
|
-
},
|
|
1559
|
-
}}
|
|
976
|
+
converters={variableConverters}
|
|
1560
977
|
/>
|
|
1561
978
|
);
|
|
1562
979
|
};
|