@nocobase/client-v2 2.1.29 → 2.1.30
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/components/form/ScanInput/useCodeScanner.d.ts +2 -2
- package/es/flow/models/base/BlockGridModel.d.ts +3 -0
- package/es/flow/models/fields/DateTimeFieldModel/dateLimit.d.ts +15 -7
- package/es/index.mjs +97 -94
- package/lib/index.js +88 -85
- package/package.json +7 -7
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +7 -2
- package/src/components/form/ScanInput/CodeScanner.tsx +61 -34
- package/src/components/form/ScanInput/__tests__/CodeScanner.test.tsx +101 -0
- package/src/components/form/ScanInput/__tests__/useCodeScanner.test.tsx +114 -18
- package/src/components/form/ScanInput/useCodeScanner.ts +166 -23
- package/src/flow/__tests__/FlowRoute.test.tsx +172 -11
- package/src/flow/actions/__tests__/actionLinkageRules.forkProps.test.ts +115 -0
- package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +102 -0
- package/src/flow/actions/linkageRules.tsx +24 -12
- package/src/flow/components/FlowRoute.tsx +72 -4
- package/src/flow/models/base/BlockGridModel.tsx +26 -0
- package/src/flow/models/base/__tests__/BlockGridModel.selectSceneActivation.test.ts +124 -0
- package/src/flow/models/fields/DateTimeFieldModel/__tests__/DateTimeNoTzFieldModel.dateLimit.test.tsx +149 -0
- package/src/flow/models/fields/DateTimeFieldModel/dateLimit.ts +149 -113
- package/src/flow/utils/dataScopeFormValueClear.ts +4 -3
|
@@ -8,140 +8,176 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { autorun } from '@formily/reactive';
|
|
11
|
-
import { Form } from 'antd';
|
|
12
|
-
import { useFlowContext } from '@nocobase/flow-engine';
|
|
11
|
+
import { Form, type FormInstance } from 'antd';
|
|
12
|
+
import { resolveRunJSObjectValues, useFlowContext } from '@nocobase/flow-engine';
|
|
13
13
|
import { dayjs } from '@nocobase/utils/client';
|
|
14
|
+
import type { ConfigType, Dayjs } from 'dayjs';
|
|
14
15
|
import { first, last } from 'lodash';
|
|
15
|
-
import
|
|
16
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
16
17
|
|
|
17
18
|
type DateLimitProps = {
|
|
18
|
-
_minDate?:
|
|
19
|
-
_maxDate?:
|
|
20
|
-
currentForm?:
|
|
19
|
+
_minDate?: unknown;
|
|
20
|
+
_maxDate?: unknown;
|
|
21
|
+
currentForm?: unknown;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const [maxDate, setMaxDate] = useState<dayjs.Dayjs | null>(null);
|
|
29
|
-
const [disabledDate, setDisabledDate] = useState<any>(null);
|
|
30
|
-
const [disabledTime, setDisabledTime] = useState<any>(null);
|
|
31
|
-
const disposeRef = useRef<any>(null);
|
|
24
|
+
type DisabledTimeConfig = {
|
|
25
|
+
disabledHours: () => number[];
|
|
26
|
+
disabledMinutes: (selectedHour: number) => number[];
|
|
27
|
+
disabledSeconds: (selectedHour: number, selectedMinute: number) => number[];
|
|
28
|
+
};
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
disposeRef.current();
|
|
36
|
-
}
|
|
30
|
+
type DisabledDate = (current: Dayjs) => boolean;
|
|
31
|
+
type DisabledTime = (current: Dayjs | null) => DisabledTimeConfig;
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
function isAntdFormInstance(value: unknown): value is FormInstance {
|
|
34
|
+
if (!value || typeof value !== 'object') return false;
|
|
35
|
+
return typeof (value as Partial<FormInstance>).getFieldsValue === 'function';
|
|
36
|
+
}
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
function parseDateLimitValue(value: unknown): Dayjs | null {
|
|
39
|
+
if (!value) return null;
|
|
40
|
+
const parsed = dayjs(value as ConfigType);
|
|
41
|
+
return parsed.isValid() ? parsed : null;
|
|
42
|
+
}
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
export function useDateLimit(props: DateLimitProps) {
|
|
45
|
+
const ctx = useFlowContext();
|
|
46
|
+
const currentForm = isAntdFormInstance(props.currentForm) ? props.currentForm : undefined;
|
|
47
|
+
const currentFormValues = Form.useWatch([], currentForm);
|
|
48
|
+
const [minDate, setMinDate] = useState<Dayjs | null>(null);
|
|
49
|
+
const [maxDate, setMaxDate] = useState<Dayjs | null>(null);
|
|
50
|
+
const [disabledDate, setDisabledDate] = useState<DisabledDate | null>(null);
|
|
51
|
+
const [disabledTime, setDisabledTime] = useState<DisabledTime | null>(null);
|
|
52
|
+
const evaluationIdRef = useRef(0);
|
|
53
|
+
|
|
54
|
+
const limitDate = useCallback(async () => {
|
|
55
|
+
const evaluationId = ++evaluationIdRef.current;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const runJSResolvedParams = await resolveRunJSObjectValues(ctx, {
|
|
59
|
+
_minDate: props._minDate,
|
|
60
|
+
_maxDate: props._maxDate,
|
|
61
|
+
});
|
|
62
|
+
const resolvedParams = (await ctx.resolveJsonTemplate({
|
|
63
|
+
_minDate: runJSResolvedParams._minDate,
|
|
64
|
+
_maxDate: runJSResolvedParams._maxDate,
|
|
65
|
+
})) as { _minDate?: unknown; _maxDate?: unknown };
|
|
66
|
+
|
|
67
|
+
if (evaluationId !== evaluationIdRef.current) return;
|
|
68
|
+
|
|
69
|
+
const nextMinRaw = Array.isArray(resolvedParams?._minDate)
|
|
70
|
+
? first(resolvedParams._minDate)
|
|
71
|
+
: resolvedParams?._minDate;
|
|
72
|
+
const nextMaxRaw = Array.isArray(resolvedParams?._maxDate)
|
|
73
|
+
? last(resolvedParams._maxDate)
|
|
74
|
+
: resolvedParams?._maxDate;
|
|
75
|
+
const nextMinDate = parseDateLimitValue(nextMinRaw);
|
|
76
|
+
const nextMaxDate = parseDateLimitValue(nextMaxRaw);
|
|
77
|
+
|
|
78
|
+
setMinDate(nextMinDate);
|
|
79
|
+
setMaxDate(nextMaxDate);
|
|
80
|
+
|
|
81
|
+
const fullTimeArr = Array.from({ length: 60 }, (_, i) => i);
|
|
82
|
+
|
|
83
|
+
const nextDisabledDate: DisabledDate = (current) => {
|
|
84
|
+
if (!dayjs.isDayjs(current)) return false;
|
|
85
|
+
|
|
86
|
+
const min = nextMinDate?.startOf('day') || null;
|
|
87
|
+
const max = nextMaxDate?.endOf('day') || null;
|
|
88
|
+
|
|
89
|
+
if (min && current.startOf('day').isBefore(min)) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
if (max && current.startOf('day').isAfter(max)) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
};
|
|
52
97
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
? last(resolvedParams._maxDate)
|
|
58
|
-
: resolvedParams?._maxDate;
|
|
59
|
-
const nextMinDate = nextMinRaw ? dayjs(nextMinRaw) : null;
|
|
60
|
-
const nextMaxDate = nextMaxRaw ? dayjs(nextMaxRaw) : null;
|
|
61
|
-
|
|
62
|
-
setMinDate(nextMinDate?.isValid?.() ? nextMinDate : null);
|
|
63
|
-
setMaxDate(nextMaxDate?.isValid?.() ? nextMaxDate : null);
|
|
64
|
-
|
|
65
|
-
const fullTimeArr = Array.from({ length: 60 }, (_, i) => i);
|
|
66
|
-
|
|
67
|
-
const nextDisabledDate = (current: dayjs.Dayjs) => {
|
|
68
|
-
if (!dayjs.isDayjs(current)) return false;
|
|
69
|
-
|
|
70
|
-
const min = nextMinDate?.isValid?.() ? nextMinDate.startOf('day') : null;
|
|
71
|
-
const max = nextMaxDate?.isValid?.() ? nextMaxDate.endOf('day') : null;
|
|
72
|
-
|
|
73
|
-
if (min && current.startOf('day').isBefore(min)) {
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
if (max && current.startOf('day').isAfter(max)) {
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
return false;
|
|
80
|
-
};
|
|
98
|
+
const nextDisabledTime: DisabledTime = (current) => {
|
|
99
|
+
if (!current || (!nextMinDate && !nextMaxDate)) {
|
|
100
|
+
return { disabledHours: () => [], disabledMinutes: () => [], disabledSeconds: () => [] };
|
|
101
|
+
}
|
|
81
102
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return { disabledHours: () => [], disabledMinutes: () => [], disabledSeconds: () => [] };
|
|
85
|
-
}
|
|
103
|
+
const isCurrentMinDay = !!nextMinDate && current.isSame(nextMinDate, 'day');
|
|
104
|
+
const isCurrentMaxDay = !!nextMaxDate && current.isSame(nextMaxDate, 'day');
|
|
86
105
|
|
|
87
|
-
|
|
88
|
-
|
|
106
|
+
const disabledHours = () => {
|
|
107
|
+
const hours = [];
|
|
108
|
+
if (isCurrentMinDay && nextMinDate) {
|
|
109
|
+
for (let hour = 0; hour < nextMinDate.hour(); hour++) {
|
|
110
|
+
hours.push(hour);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (isCurrentMaxDay && nextMaxDate) {
|
|
114
|
+
for (let hour = nextMaxDate.hour() + 1; hour < 24; hour++) {
|
|
115
|
+
hours.push(hour);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return hours;
|
|
119
|
+
};
|
|
89
120
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
for (let hour = 0; hour < nextMinDate.hour(); hour++) {
|
|
94
|
-
hours.push(hour);
|
|
121
|
+
const disabledMinutes = (selectedHour: number) => {
|
|
122
|
+
if (isCurrentMinDay && nextMinDate && selectedHour === nextMinDate.hour()) {
|
|
123
|
+
return fullTimeArr.filter((minute) => minute < nextMinDate.minute());
|
|
95
124
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
for (let hour = nextMaxDate.hour() + 1; hour < 24; hour++) {
|
|
99
|
-
hours.push(hour);
|
|
125
|
+
if (isCurrentMaxDay && nextMaxDate && selectedHour === nextMaxDate.hour()) {
|
|
126
|
+
return fullTimeArr.filter((minute) => minute > nextMaxDate.minute());
|
|
100
127
|
}
|
|
101
|
-
|
|
102
|
-
|
|
128
|
+
return [];
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const disabledSeconds = (selectedHour: number, selectedMinute: number) => {
|
|
132
|
+
if (
|
|
133
|
+
isCurrentMinDay &&
|
|
134
|
+
nextMinDate &&
|
|
135
|
+
selectedHour === nextMinDate.hour() &&
|
|
136
|
+
selectedMinute === nextMinDate.minute()
|
|
137
|
+
) {
|
|
138
|
+
return fullTimeArr.filter((second) => second < nextMinDate.second());
|
|
139
|
+
}
|
|
140
|
+
if (
|
|
141
|
+
isCurrentMaxDay &&
|
|
142
|
+
nextMaxDate &&
|
|
143
|
+
selectedHour === nextMaxDate.hour() &&
|
|
144
|
+
selectedMinute === nextMaxDate.minute()
|
|
145
|
+
) {
|
|
146
|
+
return fullTimeArr.filter((second) => second > nextMaxDate.second());
|
|
147
|
+
}
|
|
148
|
+
return [];
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
disabledHours,
|
|
153
|
+
disabledMinutes,
|
|
154
|
+
disabledSeconds,
|
|
155
|
+
};
|
|
103
156
|
};
|
|
104
157
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (isCurrentMaxDay && nextMaxDate && selectedHour === nextMaxDate.hour()) {
|
|
110
|
-
return fullTimeArr.filter((minute) => minute > nextMaxDate.minute());
|
|
111
|
-
}
|
|
112
|
-
return [];
|
|
113
|
-
};
|
|
158
|
+
setDisabledDate(() => nextDisabledDate);
|
|
159
|
+
setDisabledTime(() => nextDisabledTime);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (evaluationId !== evaluationIdRef.current) return;
|
|
114
162
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return fullTimeArr.filter((second) => second < nextMinDate.second());
|
|
123
|
-
}
|
|
124
|
-
if (
|
|
125
|
-
isCurrentMaxDay &&
|
|
126
|
-
nextMaxDate &&
|
|
127
|
-
selectedHour === nextMaxDate.hour() &&
|
|
128
|
-
selectedMinute === nextMaxDate.minute()
|
|
129
|
-
) {
|
|
130
|
-
return fullTimeArr.filter((second) => second > nextMaxDate.second());
|
|
131
|
-
}
|
|
132
|
-
return [];
|
|
133
|
-
};
|
|
163
|
+
ctx.logger?.warn?.({ err: error }, 'Failed to resolve date range limit');
|
|
164
|
+
setMinDate(null);
|
|
165
|
+
setMaxDate(null);
|
|
166
|
+
setDisabledDate(null);
|
|
167
|
+
setDisabledTime(null);
|
|
168
|
+
}
|
|
169
|
+
}, [ctx, props._maxDate, props._minDate]);
|
|
134
170
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
};
|
|
140
|
-
};
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
const dispose = autorun(() => {
|
|
173
|
+
limitDate();
|
|
174
|
+
});
|
|
141
175
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
176
|
+
return () => {
|
|
177
|
+
evaluationIdRef.current += 1;
|
|
178
|
+
dispose();
|
|
179
|
+
};
|
|
180
|
+
}, [currentFormValues, limitDate]);
|
|
145
181
|
|
|
146
182
|
return {
|
|
147
183
|
minDate,
|
|
@@ -105,9 +105,6 @@ function resolveItemDependencyPath(ctx: FlowContext, depPath: NamePath): DataSco
|
|
|
105
105
|
ctx,
|
|
106
106
|
parseFieldIndexEntries((ctx.model as any)?.context?.fieldIndex ?? (ctx as any)?.fieldIndex),
|
|
107
107
|
);
|
|
108
|
-
if (!entries.length) {
|
|
109
|
-
return wildcardDeps();
|
|
110
|
-
}
|
|
111
108
|
|
|
112
109
|
let parentDepth = 0;
|
|
113
110
|
let cursor = [...depPath];
|
|
@@ -121,6 +118,10 @@ function resolveItemDependencyPath(ctx: FlowContext, depPath: NamePath): DataSco
|
|
|
121
118
|
return wildcardDeps();
|
|
122
119
|
}
|
|
123
120
|
|
|
121
|
+
if (!entries.length) {
|
|
122
|
+
return parentDepth === 0 ? resolveRootItemDependencyPath(cursor) : emptyDeps();
|
|
123
|
+
}
|
|
124
|
+
|
|
124
125
|
if (parentDepth === entries.length) {
|
|
125
126
|
return resolveRootItemDependencyPath(cursor);
|
|
126
127
|
}
|