@nocobase/client-v2 2.1.36 → 2.1.37
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 +2 -23
- package/es/flow/components/field-value-variable/DateVariableEditor.d.ts +23 -0
- package/es/flow/components/field-value-variable/FieldValueVariableInput.d.ts +28 -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/index.mjs +64 -73
- package/lib/index.js +92 -101
- package/package.json +7 -7
- 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 +34 -571
- package/src/flow/components/field-value-variable/DateVariableEditor.tsx +162 -0
- package/src/flow/components/field-value-variable/FieldValueVariableInput.tsx +306 -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/__tests__/FormBlockModel.test.tsx +8 -2
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +398 -0
- package/src/flow/models/blocks/form/value-runtime/rules.ts +39 -9
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +39 -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/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +46 -0
- 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,19 +8,9 @@
|
|
|
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,
|
|
26
16
|
useFlowContext,
|
|
@@ -39,283 +29,21 @@ import { RunJSValueEditor } from './RunJSValueEditor';
|
|
|
39
29
|
import { pickOperatorStyle as pickStyle, resolveOperatorComponent } from '../internal/utils/operatorSchemaHelper';
|
|
40
30
|
import { InputFieldModel } from '../models/fields/InputFieldModel';
|
|
41
31
|
import { normalizeFilterValueByOperator } from '../models/blocks/filter-form/valueNormalization';
|
|
42
|
-
import { FieldAssignExactDatePicker, type ExactDatePickerMode } from './FieldAssignExactDatePicker';
|
|
43
32
|
import { limitAssociationMetaTree } from './filter/metaTreeAssociationDepth';
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
export
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
'today',
|
|
59
|
-
'yesterday',
|
|
60
|
-
'tomorrow',
|
|
61
|
-
'thisWeek',
|
|
62
|
-
'lastWeek',
|
|
63
|
-
'nextWeek',
|
|
64
|
-
'thisMonth',
|
|
65
|
-
'lastMonth',
|
|
66
|
-
'nextMonth',
|
|
67
|
-
'thisQuarter',
|
|
68
|
-
'lastQuarter',
|
|
69
|
-
'nextQuarter',
|
|
70
|
-
'thisYear',
|
|
71
|
-
'lastYear',
|
|
72
|
-
'nextYear',
|
|
73
|
-
] as const;
|
|
74
|
-
|
|
75
|
-
type DateDynamicOptionValue = (typeof DATE_DYNAMIC_OPTION_KEYS)[number] | 'now';
|
|
76
|
-
|
|
77
|
-
const DATE_DYNAMIC_OPTION_LABELS: Record<(typeof DATE_DYNAMIC_OPTION_KEYS)[number], string> = {
|
|
78
|
-
exact: 'Exact day',
|
|
79
|
-
past: 'Past',
|
|
80
|
-
next: 'Next',
|
|
81
|
-
today: 'Today',
|
|
82
|
-
yesterday: 'Yesterday',
|
|
83
|
-
tomorrow: 'Tomorrow',
|
|
84
|
-
thisWeek: 'This Week',
|
|
85
|
-
lastWeek: 'Last Week',
|
|
86
|
-
nextWeek: 'Next Week',
|
|
87
|
-
thisMonth: 'This Month',
|
|
88
|
-
lastMonth: 'Last Month',
|
|
89
|
-
nextMonth: 'Next Month',
|
|
90
|
-
thisQuarter: 'This Quarter',
|
|
91
|
-
lastQuarter: 'Last Quarter',
|
|
92
|
-
nextQuarter: 'Next Quarter',
|
|
93
|
-
thisYear: 'This Year',
|
|
94
|
-
lastYear: 'Last Year',
|
|
95
|
-
nextYear: 'Next Year',
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
function buildDateDynamicOptions(t?: (key: string) => string, includeNow = false) {
|
|
99
|
-
const options: Array<{ value: DateDynamicOptionValue; label: string }> = DATE_DYNAMIC_OPTION_KEYS.map((key) => ({
|
|
100
|
-
value: key,
|
|
101
|
-
label: t?.(DATE_DYNAMIC_OPTION_LABELS[key]) ?? DATE_DYNAMIC_OPTION_LABELS[key],
|
|
102
|
-
}));
|
|
103
|
-
|
|
104
|
-
if (includeNow) {
|
|
105
|
-
options.splice(3, 0, { value: 'now', label: t?.('Now') ?? 'Now' });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return options;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function parseDateByFormat(value: string, format: string): dayjs.Dayjs | null {
|
|
112
|
-
const raw = String(value || '').trim();
|
|
113
|
-
if (!raw) return null;
|
|
114
|
-
|
|
115
|
-
const hasTimezone = /(?:Z|[+-]\d{2}:\d{2})$/i.test(raw);
|
|
116
|
-
if (hasTimezone) {
|
|
117
|
-
const parsed = dayjs(raw);
|
|
118
|
-
if (parsed.isValid()) {
|
|
119
|
-
return parsed;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (format) {
|
|
124
|
-
const strict = dayjs(raw, format, true);
|
|
125
|
-
if (strict.isValid()) {
|
|
126
|
-
return strict;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const fallback = dayjs(raw);
|
|
131
|
-
if (fallback.isValid()) {
|
|
132
|
-
return fallback;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (format) {
|
|
136
|
-
const loose = dayjs(raw, format);
|
|
137
|
-
if (loose.isValid()) {
|
|
138
|
-
return loose;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function parseDateFromRawValue(value: unknown, format: string): dayjs.Dayjs | null {
|
|
146
|
-
if (dayjs.isDayjs(value)) {
|
|
147
|
-
return value;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (value instanceof Date) {
|
|
151
|
-
const parsedDate = dayjs(value);
|
|
152
|
-
return parsedDate.isValid() ? parsedDate : null;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (typeof value === 'string') {
|
|
156
|
-
return parseDateByFormat(value, format);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function normalizeExactDateValue(
|
|
163
|
-
value: unknown,
|
|
164
|
-
options: {
|
|
165
|
-
format: string;
|
|
166
|
-
showTime: boolean;
|
|
167
|
-
exactNormalizeMode: DateVariableExactNormalizeMode;
|
|
168
|
-
},
|
|
169
|
-
): unknown {
|
|
170
|
-
const parsed = parseDateFromRawValue(value, options.format);
|
|
171
|
-
if (!parsed?.isValid()) {
|
|
172
|
-
return value;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
switch (options.exactNormalizeMode) {
|
|
176
|
-
case 'date':
|
|
177
|
-
return parsed.format(DATE_ONLY_OUTPUT_FORMAT);
|
|
178
|
-
case 'datetimeNoTz':
|
|
179
|
-
return parsed.format(options.showTime ? DATETIME_NO_TZ_OUTPUT_FORMAT : DATE_ONLY_OUTPUT_FORMAT);
|
|
180
|
-
case 'iso':
|
|
181
|
-
return parsed.toISOString();
|
|
182
|
-
default:
|
|
183
|
-
return value;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function toExactPickerSingleValue(rawValue: unknown, format: string): dayjs.Dayjs | null {
|
|
188
|
-
const parsed = parseDateFromRawValue(rawValue, format);
|
|
189
|
-
return parsed?.isValid() ? parsed : null;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function toExactPickerRangeValue(rawValue: unknown, format: string): [dayjs.Dayjs, dayjs.Dayjs] | null {
|
|
193
|
-
if (!Array.isArray(rawValue)) return null;
|
|
194
|
-
const left = toExactPickerSingleValue(rawValue[0], format);
|
|
195
|
-
const right = toExactPickerSingleValue(rawValue[1], format);
|
|
196
|
-
if (!left || !right) return null;
|
|
197
|
-
return [left, right];
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export function toExactPickerDisplayValue(
|
|
201
|
-
rawValue: unknown,
|
|
202
|
-
options: {
|
|
203
|
-
format: string;
|
|
204
|
-
isRange: boolean;
|
|
205
|
-
},
|
|
206
|
-
): dayjs.Dayjs | [dayjs.Dayjs, dayjs.Dayjs] | null {
|
|
207
|
-
if (options.isRange) {
|
|
208
|
-
return toExactPickerRangeValue(rawValue, options.format);
|
|
209
|
-
}
|
|
210
|
-
return toExactPickerSingleValue(rawValue, options.format);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function getDateVariableExactNormalizeMode(fieldInterface: string): DateVariableExactNormalizeMode {
|
|
214
|
-
if (fieldInterface === 'date') {
|
|
215
|
-
return 'date';
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (fieldInterface === 'datetimeNoTz') {
|
|
219
|
-
return 'datetimeNoTz';
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (TZ_AWARE_DATE_INTERFACES.has(fieldInterface)) {
|
|
223
|
-
return 'iso';
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return 'none';
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export function normalizeDateVariableExactValue(
|
|
230
|
-
rawValue: any,
|
|
231
|
-
options: {
|
|
232
|
-
exactNormalizeMode: DateVariableExactNormalizeMode;
|
|
233
|
-
format: string;
|
|
234
|
-
showTime: boolean;
|
|
235
|
-
},
|
|
236
|
-
): any {
|
|
237
|
-
if (options.exactNormalizeMode === 'none') {
|
|
238
|
-
return rawValue;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (typeof rawValue === 'string') {
|
|
242
|
-
return normalizeExactDateValue(rawValue, options);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (dayjs.isDayjs(rawValue) || rawValue instanceof Date) {
|
|
246
|
-
return normalizeExactDateValue(rawValue, options);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (Array.isArray(rawValue)) {
|
|
250
|
-
return rawValue.map((item) => {
|
|
251
|
-
if (typeof item === 'string' || dayjs.isDayjs(item) || item instanceof Date) {
|
|
252
|
-
return normalizeExactDateValue(item, options);
|
|
253
|
-
}
|
|
254
|
-
return item;
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return rawValue;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
type DateVariableComponentProps = {
|
|
262
|
-
picker: ExactDatePickerMode;
|
|
263
|
-
showTime: boolean;
|
|
264
|
-
timeFormat: string;
|
|
265
|
-
format: string;
|
|
266
|
-
exactNormalizeMode: DateVariableExactNormalizeMode;
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
function normalizeExactDatePickerMode(value: unknown): ExactDatePickerMode {
|
|
270
|
-
if (value === 'year' || value === 'quarter' || value === 'month' || value === 'date') {
|
|
271
|
-
return value;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return 'date';
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const DEFAULT_DATE_VARIABLE_COMPONENT_PROPS: DateVariableComponentProps = {
|
|
278
|
-
picker: 'date',
|
|
279
|
-
showTime: false,
|
|
280
|
-
timeFormat: 'HH:mm:ss',
|
|
281
|
-
format: 'YYYY-MM-DD',
|
|
282
|
-
exactNormalizeMode: 'none',
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
function getFieldInterface(field: any): string {
|
|
286
|
-
return typeof field?.interface === 'string' ? field.interface : '';
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
function getFieldComponentProps(field: any): Record<string, any> {
|
|
290
|
-
return (
|
|
291
|
-
(typeof field?.getComponentProps === 'function' ? field.getComponentProps() : null) ||
|
|
292
|
-
field?.uiSchema?.['x-component-props'] ||
|
|
293
|
-
{}
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export function normalizeDateVariableOutput(rawValue: any, options: DateVariableComponentProps): any {
|
|
298
|
-
if (rawValue === null || isRunJSValue(rawValue)) {
|
|
299
|
-
return rawValue;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
if (typeof rawValue === 'string' && isVariableExpression(rawValue) && !isCtxDateExpression(rawValue)) {
|
|
303
|
-
return rawValue;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (rawValue === '' || typeof rawValue === 'undefined') {
|
|
307
|
-
return '';
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const normalized = normalizeDateVariableExactValue(rawValue, {
|
|
311
|
-
exactNormalizeMode: options.exactNormalizeMode,
|
|
312
|
-
format: options.format || 'YYYY-MM-DD HH:mm:ss',
|
|
313
|
-
showTime: options.showTime,
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
const serialized = serializeCtxDateValue(normalized);
|
|
317
|
-
return serialized || normalized;
|
|
318
|
-
}
|
|
33
|
+
import {
|
|
34
|
+
DEFAULT_DATE_VARIABLE_COMPONENT_PROPS,
|
|
35
|
+
FieldValueVariableInput,
|
|
36
|
+
getFieldInterface,
|
|
37
|
+
isDateLikeField as isDateLikeCollectionField,
|
|
38
|
+
resolveDateVariableComponentProps,
|
|
39
|
+
} from './field-value-variable';
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
normalizeDateVariableExactValue,
|
|
43
|
+
normalizeDateVariableOutput,
|
|
44
|
+
toExactPickerDisplayValue,
|
|
45
|
+
type DateVariableExactNormalizeMode,
|
|
46
|
+
} from './field-value-variable';
|
|
319
47
|
|
|
320
48
|
interface Props {
|
|
321
49
|
/** 赋值目标路径,例如 `title` / `users.nickname` / `user.name` */
|
|
@@ -337,8 +65,7 @@ interface Props {
|
|
|
337
65
|
value?: string;
|
|
338
66
|
};
|
|
339
67
|
/**
|
|
340
|
-
*
|
|
341
|
-
* 默认 false,保持历史行为。
|
|
68
|
+
* @deprecated Date 已作为独立一级变量提供,此参数仅为调用兼容保留。
|
|
342
69
|
*/
|
|
343
70
|
enableDateVariableAsConstant?: boolean;
|
|
344
71
|
maxAssociationFieldDepth?: number;
|
|
@@ -711,7 +438,6 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
711
438
|
operatorMetaList,
|
|
712
439
|
preferFormItemFieldModel,
|
|
713
440
|
associationFieldNamesOverride,
|
|
714
|
-
enableDateVariableAsConstant = false,
|
|
715
441
|
maxAssociationFieldDepth = 2,
|
|
716
442
|
}) => {
|
|
717
443
|
const flowCtx = useFlowContext<FlowModelContext>();
|
|
@@ -892,69 +618,18 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
892
618
|
}, [cf, currentAllowMultiple, itemCollectionField]);
|
|
893
619
|
|
|
894
620
|
const isDateLikeField = React.useMemo(() => {
|
|
895
|
-
if (sourceInterface && DATE_FIELD_INTERFACES.has(sourceInterface)) {
|
|
896
|
-
return true;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
621
|
const leaf =
|
|
900
622
|
(typeof fieldName === 'string' && fieldName) ||
|
|
901
623
|
(typeof targetPath === 'string' ? targetPath.split('.').filter(Boolean).slice(-1)[0] : '');
|
|
902
624
|
|
|
903
|
-
return
|
|
904
|
-
}, [fieldName, sourceInterface, targetPath]);
|
|
905
|
-
|
|
906
|
-
const useDateVariableConstant = enableDateVariableAsConstant && isDateLikeField;
|
|
625
|
+
return isDateLikeCollectionField(sourceCollectionField, leaf, sourceInterface);
|
|
626
|
+
}, [fieldName, sourceCollectionField, sourceInterface, targetPath]);
|
|
907
627
|
|
|
908
628
|
const dateVariableComponentProps = React.useMemo(() => {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
const componentProps = getFieldComponentProps(sourceCollectionField);
|
|
914
|
-
|
|
915
|
-
const picker = normalizeExactDatePickerMode(componentProps?.picker);
|
|
916
|
-
const inferredShowTime = ['datetime', 'datetimeNoTz', 'createdAt', 'updatedAt', 'unixTimestamp'].includes(
|
|
917
|
-
sourceInterface,
|
|
918
|
-
);
|
|
919
|
-
const showTime = typeof componentProps?.showTime === 'boolean' ? componentProps.showTime : inferredShowTime;
|
|
920
|
-
|
|
921
|
-
const dateFormat =
|
|
922
|
-
typeof componentProps?.dateFormat === 'string' && componentProps.dateFormat
|
|
923
|
-
? componentProps.dateFormat
|
|
924
|
-
: typeof componentProps?.format === 'string' && componentProps.format
|
|
925
|
-
? componentProps.format.split(' ')[0]
|
|
926
|
-
: 'YYYY-MM-DD';
|
|
927
|
-
const timeFormat =
|
|
928
|
-
typeof componentProps?.timeFormat === 'string' && componentProps.timeFormat
|
|
929
|
-
? componentProps.timeFormat
|
|
930
|
-
: 'HH:mm:ss';
|
|
931
|
-
|
|
932
|
-
const format =
|
|
933
|
-
typeof componentProps?.format === 'string' && componentProps.format
|
|
934
|
-
? componentProps.format
|
|
935
|
-
: showTime
|
|
936
|
-
? `${dateFormat} ${timeFormat}`
|
|
937
|
-
: dateFormat;
|
|
938
|
-
|
|
939
|
-
return {
|
|
940
|
-
picker,
|
|
941
|
-
showTime,
|
|
942
|
-
timeFormat,
|
|
943
|
-
format,
|
|
944
|
-
exactNormalizeMode: getDateVariableExactNormalizeMode(sourceInterface),
|
|
945
|
-
};
|
|
946
|
-
}, [sourceCollectionField, sourceInterface, useDateVariableConstant]);
|
|
947
|
-
|
|
948
|
-
const dateVariableDisplayProps = React.useMemo(() => {
|
|
949
|
-
const { exactNormalizeMode, ...rest } = dateVariableComponentProps;
|
|
950
|
-
return rest;
|
|
951
|
-
}, [dateVariableComponentProps]);
|
|
952
|
-
|
|
953
|
-
const dateVariableDisplayPropsRef = React.useRef(dateVariableDisplayProps);
|
|
954
|
-
dateVariableDisplayPropsRef.current = dateVariableDisplayProps;
|
|
955
|
-
|
|
956
|
-
const dateVariableTranslateRef = React.useRef(flowCtx.t);
|
|
957
|
-
dateVariableTranslateRef.current = flowCtx.t;
|
|
629
|
+
return isDateLikeField
|
|
630
|
+
? resolveDateVariableComponentProps(sourceCollectionField, sourceInterface)
|
|
631
|
+
: DEFAULT_DATE_VARIABLE_COMPONENT_PROPS;
|
|
632
|
+
}, [isDateLikeField, sourceCollectionField, sourceInterface]);
|
|
958
633
|
|
|
959
634
|
const coerceEmptyValueForRenderer = React.useCallback(
|
|
960
635
|
(v: any) => {
|
|
@@ -1237,158 +912,6 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
1237
912
|
return C;
|
|
1238
913
|
}, [placeholder, tempRoot, coerceEmptyValueForRenderer, normalizeEventValue, operator]);
|
|
1239
914
|
|
|
1240
|
-
const DateVariableConstantEditor = React.useMemo(() => {
|
|
1241
|
-
const C: React.FC<any> = (inputProps) => {
|
|
1242
|
-
const wrapperStyle = pickStyle(inputProps?.style);
|
|
1243
|
-
const raw = inputProps?.value;
|
|
1244
|
-
const parsed = isCtxDateExpression(raw) ? parseCtxDateExpression(raw) : raw;
|
|
1245
|
-
const parsedValue = typeof parsed === 'undefined' ? undefined : parsed;
|
|
1246
|
-
const { token } = theme.useToken();
|
|
1247
|
-
const [open, setOpen] = React.useState(false);
|
|
1248
|
-
const t = dateVariableTranslateRef.current;
|
|
1249
|
-
const datePickerProps = dateVariableDisplayPropsRef.current;
|
|
1250
|
-
const options = React.useMemo(() => buildDateDynamicOptions(t, true), [t]);
|
|
1251
|
-
|
|
1252
|
-
const dynamicType =
|
|
1253
|
-
parsedValue && typeof parsedValue === 'object' && !Array.isArray(parsedValue)
|
|
1254
|
-
? (parsedValue as any)?.type
|
|
1255
|
-
: undefined;
|
|
1256
|
-
const selectedType = typeof dynamicType === 'string' && dynamicType ? dynamicType : 'exact';
|
|
1257
|
-
const isRange = Array.isArray(parsedValue);
|
|
1258
|
-
const exactSingleValue = toExactPickerDisplayValue(parsedValue, {
|
|
1259
|
-
format: datePickerProps.format,
|
|
1260
|
-
isRange: false,
|
|
1261
|
-
});
|
|
1262
|
-
const exactRangeValue = toExactPickerDisplayValue(parsedValue, {
|
|
1263
|
-
format: datePickerProps.format,
|
|
1264
|
-
isRange: true,
|
|
1265
|
-
});
|
|
1266
|
-
|
|
1267
|
-
const handleSelect = (val: string) => {
|
|
1268
|
-
setOpen(false);
|
|
1269
|
-
if (val === 'exact') {
|
|
1270
|
-
inputProps?.onChange?.('');
|
|
1271
|
-
return;
|
|
1272
|
-
}
|
|
1273
|
-
const next: any = { type: val };
|
|
1274
|
-
if (val === 'past' || val === 'next') {
|
|
1275
|
-
next.number = 1;
|
|
1276
|
-
next.unit = 'day';
|
|
1277
|
-
}
|
|
1278
|
-
inputProps?.onChange?.(next);
|
|
1279
|
-
};
|
|
1280
|
-
|
|
1281
|
-
const handleExactSingleChange = (nextValue: any) => {
|
|
1282
|
-
inputProps?.onChange?.(nextValue || '');
|
|
1283
|
-
};
|
|
1284
|
-
|
|
1285
|
-
const handleExactRangeChange = (nextValue: any) => {
|
|
1286
|
-
inputProps?.onChange?.(nextValue || '');
|
|
1287
|
-
};
|
|
1288
|
-
|
|
1289
|
-
const dropdownRender = () => {
|
|
1290
|
-
const firstPart = options.slice(0, 3);
|
|
1291
|
-
const secondPart = options.slice(3);
|
|
1292
|
-
const optionStyle = css`
|
|
1293
|
-
padding: 3px 10px;
|
|
1294
|
-
cursor: pointer;
|
|
1295
|
-
white-space: nowrap;
|
|
1296
|
-
overflow: hidden;
|
|
1297
|
-
text-overflow: ellipsis;
|
|
1298
|
-
&:hover {
|
|
1299
|
-
background-color: ${token.colorFillSecondary};
|
|
1300
|
-
}
|
|
1301
|
-
`;
|
|
1302
|
-
return (
|
|
1303
|
-
<div style={{ maxHeight: 300, overflowY: 'auto' }}>
|
|
1304
|
-
{firstPart.map((opt) => (
|
|
1305
|
-
<div key={opt.value} role="option" onClick={() => handleSelect(opt.value)} className={optionStyle}>
|
|
1306
|
-
{opt.label}
|
|
1307
|
-
</div>
|
|
1308
|
-
))}
|
|
1309
|
-
<Divider style={{ margin: '4px 0' }} />
|
|
1310
|
-
{secondPart.map((opt) => (
|
|
1311
|
-
<div
|
|
1312
|
-
key={opt.value}
|
|
1313
|
-
role="option"
|
|
1314
|
-
className={optionStyle}
|
|
1315
|
-
onClick={() => handleSelect(opt.value)}
|
|
1316
|
-
title={opt.label}
|
|
1317
|
-
>
|
|
1318
|
-
{opt.label}
|
|
1319
|
-
</div>
|
|
1320
|
-
))}
|
|
1321
|
-
</div>
|
|
1322
|
-
);
|
|
1323
|
-
};
|
|
1324
|
-
|
|
1325
|
-
return (
|
|
1326
|
-
<Space.Compact style={withFullWidthStyle(wrapperStyle)}>
|
|
1327
|
-
<Select
|
|
1328
|
-
options={options}
|
|
1329
|
-
open={open}
|
|
1330
|
-
onDropdownVisibleChange={setOpen}
|
|
1331
|
-
allowClear={false}
|
|
1332
|
-
style={{
|
|
1333
|
-
width: '100%',
|
|
1334
|
-
minWidth: 100,
|
|
1335
|
-
maxWidth: ['past', 'next', 'exact', undefined].includes(dynamicType) ? 100 : null,
|
|
1336
|
-
}}
|
|
1337
|
-
value={selectedType}
|
|
1338
|
-
onChange={handleSelect}
|
|
1339
|
-
dropdownRender={dropdownRender}
|
|
1340
|
-
/>
|
|
1341
|
-
{['past', 'next'].includes(selectedType) && [
|
|
1342
|
-
<InputNumber
|
|
1343
|
-
key="number"
|
|
1344
|
-
style={{ flex: 1 }}
|
|
1345
|
-
value={(parsedValue as any)?.number}
|
|
1346
|
-
onChange={(nextNumber) => {
|
|
1347
|
-
inputProps?.onChange?.({
|
|
1348
|
-
...(parsedValue as any),
|
|
1349
|
-
type: selectedType,
|
|
1350
|
-
number: nextNumber,
|
|
1351
|
-
unit: (parsedValue as any)?.unit || 'day',
|
|
1352
|
-
});
|
|
1353
|
-
}}
|
|
1354
|
-
/>,
|
|
1355
|
-
<Select
|
|
1356
|
-
key="unit"
|
|
1357
|
-
value={(parsedValue as any)?.unit}
|
|
1358
|
-
style={{ minWidth: 130, maxWidth: 140 }}
|
|
1359
|
-
onChange={(nextUnit) => {
|
|
1360
|
-
inputProps?.onChange?.({
|
|
1361
|
-
...(parsedValue as any),
|
|
1362
|
-
type: selectedType,
|
|
1363
|
-
unit: nextUnit,
|
|
1364
|
-
number: (parsedValue as any)?.number || 1,
|
|
1365
|
-
});
|
|
1366
|
-
}}
|
|
1367
|
-
options={[
|
|
1368
|
-
{ value: 'day', label: t?.('Day') ?? 'Day' },
|
|
1369
|
-
{ value: 'week', label: t?.('Calendar week') ?? 'Calendar week' },
|
|
1370
|
-
{ value: 'month', label: t?.('Calendar Month') ?? 'Calendar Month' },
|
|
1371
|
-
{ value: 'year', label: t?.('Calendar Year') ?? 'Calendar Year' },
|
|
1372
|
-
]}
|
|
1373
|
-
popupMatchSelectWidth
|
|
1374
|
-
/>,
|
|
1375
|
-
]}
|
|
1376
|
-
{(selectedType === 'exact' || !selectedType) && (
|
|
1377
|
-
<FieldAssignExactDatePicker
|
|
1378
|
-
{...datePickerProps}
|
|
1379
|
-
isRange={isRange}
|
|
1380
|
-
value={isRange ? exactRangeValue : exactSingleValue}
|
|
1381
|
-
onChange={isRange ? handleExactRangeChange : handleExactSingleChange}
|
|
1382
|
-
style={{ flex: 1 }}
|
|
1383
|
-
/>
|
|
1384
|
-
)}
|
|
1385
|
-
</Space.Compact>
|
|
1386
|
-
);
|
|
1387
|
-
};
|
|
1388
|
-
|
|
1389
|
-
return C;
|
|
1390
|
-
}, []);
|
|
1391
|
-
|
|
1392
915
|
const NullComponent = React.useMemo(() => {
|
|
1393
916
|
const N: React.FC = () => (
|
|
1394
917
|
<Input placeholder={`<${flowCtx.t?.('Null') ?? 'Null'}>`} readOnly style={{ width: '100%' }} />
|
|
@@ -1403,54 +926,15 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
1403
926
|
return C;
|
|
1404
927
|
}, [flowCtx]);
|
|
1405
928
|
|
|
1406
|
-
const
|
|
1407
|
-
|
|
1408
|
-
const metaTree = React.useMemo<() => Promise<any[]>>(() => {
|
|
929
|
+
const baseMetaTree = React.useMemo<() => Promise<MetaTreeNode[]>>(() => {
|
|
1409
930
|
return async () => {
|
|
1410
931
|
const base = (await flowCtx.getPropertyMetaTree?.()) || [];
|
|
1411
932
|
const extra = extraMetaTreeRef.current;
|
|
1412
933
|
const extraTree = Array.isArray(extra) ? extra : [];
|
|
1413
934
|
const mergedBase = mergeItemMetaTreeForAssignValue(base as MetaTreeNode[], extraTree as MetaTreeNode[]);
|
|
1414
|
-
|
|
1415
|
-
return [
|
|
1416
|
-
{
|
|
1417
|
-
title: tExpr('Constant'),
|
|
1418
|
-
name: 'constant',
|
|
1419
|
-
type: 'string',
|
|
1420
|
-
paths: ['constant'],
|
|
1421
|
-
render: ConstantEditor,
|
|
1422
|
-
},
|
|
1423
|
-
{ title: tExpr('Null'), name: 'null', type: 'object', paths: ['null'], render: NullComponent },
|
|
1424
|
-
{ title: tExpr('RunJS'), name: 'runjs', type: 'object', paths: ['runjs'], render: RunJSComponent },
|
|
1425
|
-
...limitedBase,
|
|
1426
|
-
];
|
|
935
|
+
return limitAssociationMetaTree(mergedBase, { maxAssociationDepth: maxAssociationFieldDepth });
|
|
1427
936
|
};
|
|
1428
|
-
}, [flowCtx,
|
|
1429
|
-
|
|
1430
|
-
const displayValue = React.useMemo(() => {
|
|
1431
|
-
if (!useDateVariableConstant) {
|
|
1432
|
-
return value;
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
|
-
if (isCtxDateExpression(value)) {
|
|
1436
|
-
const parsed = parseCtxDateExpression(value);
|
|
1437
|
-
return typeof parsed === 'undefined' ? '' : parsed;
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
return value;
|
|
1441
|
-
}, [useDateVariableConstant, value]);
|
|
1442
|
-
|
|
1443
|
-
const handleVariableInputChange = React.useCallback(
|
|
1444
|
-
(nextValue: any) => {
|
|
1445
|
-
if (!useDateVariableConstant) {
|
|
1446
|
-
onChange(nextValue);
|
|
1447
|
-
return;
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
|
-
onChange(normalizeDateVariableOutput(nextValue, dateVariableComponentProps));
|
|
1451
|
-
},
|
|
1452
|
-
[dateVariableComponentProps, onChange, useDateVariableConstant],
|
|
1453
|
-
);
|
|
937
|
+
}, [flowCtx, maxAssociationFieldDepth]);
|
|
1454
938
|
|
|
1455
939
|
if (!fieldPath) {
|
|
1456
940
|
// 不可用占位
|
|
@@ -1458,38 +942,17 @@ export const FieldAssignValueInput: React.FC<Props> = ({
|
|
|
1458
942
|
}
|
|
1459
943
|
|
|
1460
944
|
return (
|
|
1461
|
-
<
|
|
1462
|
-
value={
|
|
1463
|
-
onChange={
|
|
1464
|
-
|
|
945
|
+
<FieldValueVariableInput
|
|
946
|
+
value={value}
|
|
947
|
+
onChange={onChange}
|
|
948
|
+
baseMetaTree={baseMetaTree}
|
|
949
|
+
constantComponent={ConstantValueEditor}
|
|
950
|
+
nullComponent={NullComponent}
|
|
951
|
+
runJSComponent={RunJSComponent}
|
|
952
|
+
isDateLikeField={isDateLikeField}
|
|
953
|
+
dateComponentProps={dateVariableComponentProps}
|
|
1465
954
|
style={{ width: '100%' }}
|
|
1466
955
|
clearValue={''}
|
|
1467
|
-
converters={{
|
|
1468
|
-
renderInputComponent: (meta) => {
|
|
1469
|
-
const firstPath = meta?.paths?.[0];
|
|
1470
|
-
if (firstPath === 'constant') return ConstantEditor;
|
|
1471
|
-
if (firstPath === 'null') return NullComponent;
|
|
1472
|
-
if (firstPath === 'runjs') return RunJSComponent;
|
|
1473
|
-
return null;
|
|
1474
|
-
},
|
|
1475
|
-
resolveValueFromPath: (item) => {
|
|
1476
|
-
const firstPath = item?.paths?.[0];
|
|
1477
|
-
if (firstPath === 'constant') {
|
|
1478
|
-
return useDateVariableConstant ? { type: 'today' } : '';
|
|
1479
|
-
}
|
|
1480
|
-
if (firstPath === 'null') return null;
|
|
1481
|
-
if (firstPath === 'runjs') return { code: '', version: 'v2' };
|
|
1482
|
-
return undefined;
|
|
1483
|
-
},
|
|
1484
|
-
resolvePathFromValue: (currentValue) => {
|
|
1485
|
-
if (currentValue === null) return ['null'];
|
|
1486
|
-
if (isRunJSValue(currentValue)) return ['runjs'];
|
|
1487
|
-
if (useDateVariableConstant && isCtxDateExpression(currentValue)) {
|
|
1488
|
-
return ['constant'];
|
|
1489
|
-
}
|
|
1490
|
-
return isVariableExpression(currentValue) ? parseValueToPath(currentValue) : ['constant'];
|
|
1491
|
-
},
|
|
1492
|
-
}}
|
|
1493
956
|
/>
|
|
1494
957
|
);
|
|
1495
958
|
};
|