@nocobase/client-v2 2.2.0-beta.13 → 2.2.0-beta.15
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/APIClient.d.ts +1 -3
- package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
- package/es/components/category-tabs/index.d.ts +9 -0
- package/es/components/form/ScanInput/useCodeScanner.d.ts +2 -1
- package/es/components/form/TypedVariableInput.d.ts +31 -5
- package/es/components/form/filter/CollectionFilter.d.ts +2 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
- package/es/components/form/filter/CollectionFilterPanel.d.ts +2 -0
- package/es/components/form/filter/index.d.ts +2 -0
- package/es/components/form/filter/useFilterActionProps.d.ts +2 -0
- package/es/components/index.d.ts +1 -0
- package/es/flow/actions/index.d.ts +1 -1
- package/es/flow/actions/linkageRules.d.ts +2 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +1 -0
- package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
- package/es/flow/components/FieldAssignValueInput.d.ts +9 -0
- package/es/flow/components/RunJSValueEditor.d.ts +1 -0
- package/es/flow/components/filter/FilterGroup.d.ts +1 -0
- package/es/flow/components/filter/VariableFilterItem.d.ts +6 -1
- package/es/flow/index.d.ts +1 -0
- package/es/flow/models/base/PageModel/PageModel.d.ts +12 -0
- package/es/flow/models/base/PageModel/PageModelTabBar.d.ts +22 -0
- package/es/flow/models/base/PageModel/PageTabModel.d.ts +12 -0
- package/es/flow-compat/fieldValidationConstants.d.ts +1 -1
- package/es/flow-compat/routeTypes.d.ts +1 -0
- package/es/index.d.ts +4 -0
- package/es/index.mjs +144 -109
- package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
- package/es/utils/index.d.ts +1 -0
- package/lib/index.js +153 -118
- package/lib/locale/languageCodes.js +2 -1
- package/package.json +7 -7
- package/src/APIClient.ts +1 -10
- package/src/Application.tsx +4 -0
- package/src/BaseApplication.tsx +1 -1
- package/src/__tests__/app.test.tsx +18 -0
- package/src/__tests__/browserChecker.test.ts +61 -0
- package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +28 -0
- package/src/collection-manager/field-validation.ts +1 -1
- package/src/components/README.md +7 -1
- package/src/components/README.zh-CN.md +6 -1
- package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
- package/src/components/category-tabs/index.ts +10 -0
- package/src/components/form/JsonTextArea.tsx +4 -0
- package/src/components/form/ScanInput/CodeScanner.tsx +23 -6
- package/src/components/form/ScanInput/__tests__/useCodeScanner.test.tsx +35 -1
- package/src/components/form/ScanInput/useCodeScanner.ts +16 -3
- package/src/components/form/TypedVariableInput.tsx +452 -101
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +364 -12
- package/src/components/form/filter/CollectionFilter.tsx +4 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
- package/src/components/form/filter/CollectionFilterPanel.tsx +4 -0
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
- package/src/components/form/filter/__tests__/useFilterActionProps.test.tsx +95 -0
- package/src/components/form/filter/index.ts +2 -0
- package/src/components/form/filter/useFilterActionProps.ts +37 -6
- package/src/components/index.ts +1 -0
- package/src/flow/actions/__tests__/linkageRules.tab.test.ts +171 -0
- package/src/flow/actions/index.ts +2 -0
- package/src/flow/actions/linkageRules.tsx +86 -11
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +0 -1
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +253 -6
- package/src/flow/components/FieldAssignExactDatePicker.tsx +25 -11
- package/src/flow/components/FieldAssignValueInput.tsx +76 -9
- package/src/flow/components/RunJSValueEditor.tsx +9 -1
- package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +84 -2
- package/src/flow/components/filter/FilterGroup.tsx +33 -5
- package/src/flow/components/filter/VariableFilterItem.tsx +158 -10
- package/src/flow/components/filter/__tests__/FilterGroup.test.tsx +45 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.leftMetaTree.test.tsx +9 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +70 -1
- package/src/flow/index.ts +1 -0
- package/src/flow/models/base/PageModel/PageModel.tsx +387 -53
- package/src/flow/models/base/PageModel/PageModelTabBar.tsx +114 -0
- package/src/flow/models/base/PageModel/PageTabModel.tsx +184 -3
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +790 -10
- package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.module-isolation.test.tsx +130 -0
- package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.test.tsx +118 -0
- package/src/flow/models/base/PageModel/__tests__/PageTabModel.test.ts +572 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +1 -1
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +1 -1
- package/src/flow/models/fields/VariableFieldFormModel.tsx +3 -3
- package/src/flow/models/fields/__tests__/VariableFieldFormModel.test.tsx +51 -0
- package/src/flow-compat/fieldValidationConstants.ts +1 -1
- package/src/flow-compat/routeTypes.ts +1 -0
- package/src/index.ts +4 -0
- package/src/locale/languageCodes.ts +2 -1
- package/src/nocobase-buildin-plugin/index.tsx +12 -0
- package/src/utils/getRouteRuntimeVersion.ts +185 -0
- package/src/utils/index.tsx +1 -0
|
@@ -49,6 +49,21 @@ function CodeScannerContent({ visible, formatsToSupport, onClose, onScanSuccess
|
|
|
49
49
|
message.error(t('Code recognition failed, please scan again'));
|
|
50
50
|
}, [t]);
|
|
51
51
|
|
|
52
|
+
const showCameraStartFailure = useCallback(
|
|
53
|
+
(error: unknown) => {
|
|
54
|
+
const errorName = error instanceof Error ? error.name : '';
|
|
55
|
+
const errorMessage = error instanceof Error ? error.message : '';
|
|
56
|
+
const errorMap: Record<string, string> = {
|
|
57
|
+
NotFoundError: t('No camera device detected'),
|
|
58
|
+
NotAllowedError: t('You have not granted permission to use the camera'),
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
message.error(errorMap[errorName] || errorMessage || t('You have not granted permission to use the camera'));
|
|
62
|
+
onClose();
|
|
63
|
+
},
|
|
64
|
+
[onClose, t],
|
|
65
|
+
);
|
|
66
|
+
|
|
52
67
|
const handleScanSuccess = useCallback(
|
|
53
68
|
(text: string) => {
|
|
54
69
|
onScanSuccess(text);
|
|
@@ -64,6 +79,7 @@ function CodeScannerContent({ visible, formatsToSupport, onClose, onScanSuccess
|
|
|
64
79
|
scanBoxSize,
|
|
65
80
|
onScanSuccess: handleScanSuccess,
|
|
66
81
|
onScanFailure: showScanFailure,
|
|
82
|
+
onCameraStartFailure: showCameraStartFailure,
|
|
67
83
|
});
|
|
68
84
|
|
|
69
85
|
useEffect(() => {
|
|
@@ -129,7 +145,7 @@ function CodeScannerContent({ visible, formatsToSupport, onClose, onScanSuccess
|
|
|
129
145
|
inset: 0;
|
|
130
146
|
z-index: ${token.zIndexPopupBase + 1000};
|
|
131
147
|
overflow: hidden;
|
|
132
|
-
background:
|
|
148
|
+
background: #000;
|
|
133
149
|
`;
|
|
134
150
|
const scannerWrapperClass = css`
|
|
135
151
|
position: absolute;
|
|
@@ -137,16 +153,17 @@ function CodeScannerContent({ visible, formatsToSupport, onClose, onScanSuccess
|
|
|
137
153
|
overflow: hidden;
|
|
138
154
|
`;
|
|
139
155
|
const scannerClass = css`
|
|
156
|
+
position: relative;
|
|
140
157
|
width: 100%;
|
|
141
158
|
height: 100%;
|
|
142
|
-
|
|
143
|
-
justify-content: center;
|
|
144
|
-
align-items: center;
|
|
159
|
+
overflow: hidden;
|
|
145
160
|
|
|
146
161
|
video {
|
|
147
|
-
|
|
162
|
+
position: absolute !important;
|
|
163
|
+
inset: 0 !important;
|
|
164
|
+
width: 100% !important;
|
|
148
165
|
height: 100% !important;
|
|
149
|
-
|
|
166
|
+
object-fit: cover !important;
|
|
150
167
|
}
|
|
151
168
|
|
|
152
169
|
#qr-shaded-region {
|
|
@@ -74,13 +74,23 @@ vi.mock('html5-qrcode', () => ({
|
|
|
74
74
|
|
|
75
75
|
vi.mock('jsqr', () => jsQrMocks);
|
|
76
76
|
|
|
77
|
-
function ScannerHost({
|
|
77
|
+
function ScannerHost({
|
|
78
|
+
onCameraStartFailure,
|
|
79
|
+
onScanFailure,
|
|
80
|
+
scanBoxSize,
|
|
81
|
+
}: {
|
|
82
|
+
onCameraStartFailure?: (error: unknown) => void;
|
|
83
|
+
onScanFailure?: () => void;
|
|
84
|
+
scanBoxSize?: { width: number; height: number };
|
|
85
|
+
} = {}) {
|
|
78
86
|
const handleScanSuccess = useCallback(() => undefined, []);
|
|
79
87
|
|
|
80
88
|
useCodeScanner({
|
|
81
89
|
elementId: 'scanner',
|
|
82
90
|
enabled: true,
|
|
83
91
|
scanBoxSize,
|
|
92
|
+
onCameraStartFailure,
|
|
93
|
+
onScanFailure,
|
|
84
94
|
onScanSuccess: handleScanSuccess,
|
|
85
95
|
});
|
|
86
96
|
|
|
@@ -194,6 +204,30 @@ describe('useCodeScanner', () => {
|
|
|
194
204
|
expect(config?.qrbox?.(1200, 844)).toEqual({ width: 319, height: 240 });
|
|
195
205
|
});
|
|
196
206
|
|
|
207
|
+
it('clamps the scan box to the camera viewfinder size', async () => {
|
|
208
|
+
render(<ScannerHost scanBoxSize={{ width: 319, height: 240 }} />);
|
|
209
|
+
|
|
210
|
+
await waitFor(() => expect(mocks.start).toHaveBeenCalled());
|
|
211
|
+
|
|
212
|
+
const config = mocks.start.mock.calls[0]?.[1] as
|
|
213
|
+
| { qrbox?: (width: number, height: number) => { width: number; height: number } }
|
|
214
|
+
| undefined;
|
|
215
|
+
|
|
216
|
+
expect(config?.qrbox?.(200, 160)).toEqual({ width: 200, height: 160 });
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('reports camera start failures through the dedicated handler', async () => {
|
|
220
|
+
const cameraStartError = Object.assign(new Error('Camera failed'), { name: 'NotAllowedError' });
|
|
221
|
+
const handleCameraStartFailure = vi.fn();
|
|
222
|
+
const handleScanFailure = vi.fn();
|
|
223
|
+
mocks.start.mockRejectedValueOnce(cameraStartError);
|
|
224
|
+
|
|
225
|
+
render(<ScannerHost onCameraStartFailure={handleCameraStartFailure} onScanFailure={handleScanFailure} />);
|
|
226
|
+
|
|
227
|
+
await waitFor(() => expect(handleCameraStartFailure).toHaveBeenCalledWith(cameraStartError));
|
|
228
|
+
expect(handleScanFailure).not.toHaveBeenCalled();
|
|
229
|
+
});
|
|
230
|
+
|
|
197
231
|
it('uses jsQR first for Safari uploaded QR images', async () => {
|
|
198
232
|
const handleScanSuccess = vi.fn();
|
|
199
233
|
jsQrMocks.default.mockReturnValueOnce({ data: 'JSQR-CODE' });
|
|
@@ -25,6 +25,7 @@ type UseCodeScannerOptions = {
|
|
|
25
25
|
onScannerSizeChanged?: (size: ScannerSize) => void;
|
|
26
26
|
onScanSuccess: (text: string) => void;
|
|
27
27
|
onScanFailure?: () => void;
|
|
28
|
+
onCameraStartFailure?: (error: unknown) => void;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
type ImageDataVariant = {
|
|
@@ -70,6 +71,13 @@ export function getCodeScanBoxSize(width: number, height: number) {
|
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
function clampCodeScanBoxSize(scanBoxSize: ScannerSize, width: number, height: number) {
|
|
75
|
+
return {
|
|
76
|
+
width: Math.min(scanBoxSize.width, width),
|
|
77
|
+
height: Math.min(scanBoxSize.height, height),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
73
81
|
async function stopScanner(scanner?: Html5Qrcode, options: { clear?: boolean } = {}) {
|
|
74
82
|
if (!scanner) {
|
|
75
83
|
return;
|
|
@@ -212,6 +220,7 @@ export function useCodeScanner({
|
|
|
212
220
|
onScannerSizeChanged,
|
|
213
221
|
onScanSuccess,
|
|
214
222
|
onScanFailure,
|
|
223
|
+
onCameraStartFailure,
|
|
215
224
|
}: UseCodeScannerOptions) {
|
|
216
225
|
const [scanner, setScanner] = useState<Html5Qrcode>();
|
|
217
226
|
|
|
@@ -223,7 +232,7 @@ export function useCodeScanner({
|
|
|
223
232
|
fps: 10,
|
|
224
233
|
qrbox(width, height) {
|
|
225
234
|
onScannerSizeChanged?.({ width, height });
|
|
226
|
-
return scanBoxSize ?? getCodeScanBoxSize(width, height);
|
|
235
|
+
return clampCodeScanBoxSize(scanBoxSize ?? getCodeScanBoxSize(width, height), width, height);
|
|
227
236
|
},
|
|
228
237
|
},
|
|
229
238
|
(decodedText) => {
|
|
@@ -273,14 +282,18 @@ export function useCodeScanner({
|
|
|
273
282
|
verbose: false,
|
|
274
283
|
});
|
|
275
284
|
setScanner(scannerInstance);
|
|
276
|
-
startScanCamera(scannerInstance).catch(() => {
|
|
285
|
+
startScanCamera(scannerInstance).catch((error: unknown) => {
|
|
286
|
+
if (onCameraStartFailure) {
|
|
287
|
+
onCameraStartFailure(error);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
277
290
|
onScanFailure?.();
|
|
278
291
|
});
|
|
279
292
|
|
|
280
293
|
return () => {
|
|
281
294
|
stopScanner(scannerInstance, { clear: true }).catch(() => undefined);
|
|
282
295
|
};
|
|
283
|
-
}, [elementId, enabled, formatsToSupport, onScanFailure, startScanCamera]);
|
|
296
|
+
}, [elementId, enabled, formatsToSupport, onCameraStartFailure, onScanFailure, startScanCamera]);
|
|
284
297
|
|
|
285
298
|
return {
|
|
286
299
|
startScanFile,
|