@nocobase/client-v2 2.1.0-beta.33 → 2.1.0-beta.34
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 +16 -0
- package/es/Application.d.ts +2 -1
- package/es/authRedirect.d.ts +9 -16
- package/es/components/form/EnvVariableInput.d.ts +8 -6
- package/es/components/form/VariableInput.d.ts +73 -0
- package/es/components/form/index.d.ts +1 -0
- package/es/components/form/table/RowOverlayPreview.d.ts +27 -0
- package/es/components/form/table/SelectionCell.d.ts +36 -0
- package/es/components/form/table/Table.d.ts +82 -0
- package/es/components/form/table/constants.d.ts +15 -0
- package/es/components/form/table/dnd/SortableRow.d.ts +40 -0
- package/es/components/form/table/dnd/index.d.ts +9 -0
- package/es/components/form/table/index.d.ts +9 -0
- package/es/components/form/table/styles.d.ts +41 -0
- package/es/components/form/table/utils.d.ts +44 -0
- package/es/components/index.d.ts +2 -0
- package/es/flow/components/TextAreaWithContextSelector.d.ts +15 -0
- package/es/flow/models/blocks/table/dragSort/dragSortComponents.d.ts +1 -6
- package/es/flow/models/blocks/table/dragSort/dragSortHooks.d.ts +5 -1
- package/es/flow-compat/passwordUtils.d.ts +1 -1
- package/es/index.d.ts +1 -0
- package/es/index.mjs +145 -78
- package/es/theme/globalStyles.d.ts +9 -0
- package/es/theme/index.d.ts +1 -0
- package/lib/index.js +161 -94
- package/package.json +8 -6
- package/src/APIClient.ts +68 -0
- package/src/Application.tsx +6 -2
- package/src/__tests__/authRedirect.test.ts +170 -64
- package/src/__tests__/globalDeps.test.ts +2 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +6 -6
- package/src/authRedirect.ts +23 -84
- package/src/components/form/EnvVariableInput.tsx +11 -46
- package/src/components/form/VariableInput.tsx +177 -0
- package/src/components/form/__tests__/EnvVariableInput.test.tsx +175 -0
- package/src/components/form/index.tsx +1 -0
- package/src/components/form/table/RowOverlayPreview.tsx +51 -0
- package/src/components/form/table/SelectionCell.tsx +72 -0
- package/src/components/form/table/Table.tsx +279 -0
- package/src/components/form/table/__tests__/Table.pagination.test.tsx +80 -0
- package/src/components/form/table/constants.ts +16 -0
- package/src/components/form/table/dnd/SortableRow.tsx +106 -0
- package/src/components/form/table/dnd/index.ts +10 -0
- package/src/components/form/table/index.tsx +13 -0
- package/src/components/form/table/styles.ts +110 -0
- package/src/components/form/table/utils.ts +75 -0
- package/src/components/index.ts +2 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +2 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +111 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +2 -1
- package/src/flow/components/TextAreaWithContextSelector.tsx +30 -6
- package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +81 -0
- package/src/flow/components/code-editor/hooks/useCodeRunner.ts +34 -2
- package/src/flow/models/blocks/table/dragSort/dragSortComponents.tsx +1 -81
- package/src/flow/models/fields/JSEditableFieldModel.tsx +107 -7
- package/src/flow/models/fields/__tests__/JSEditableFieldModel.test.tsx +97 -0
- package/src/index.ts +1 -0
- package/src/nocobase-buildin-plugin/index.tsx +4 -4
- package/src/theme/globalStyles.ts +21 -0
- package/src/theme/index.tsx +1 -0
- package/src/utils/globalDeps.ts +5 -1
|
@@ -69,6 +69,106 @@ function resolveScriptCode(codeParam?: string) {
|
|
|
69
69
|
return typeof raw === 'string' ? raw.trim() : '';
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
type NamePathPart = string | number;
|
|
73
|
+
|
|
74
|
+
function toNamePath(input: unknown): NamePathPart[] | null {
|
|
75
|
+
if (Array.isArray(input)) {
|
|
76
|
+
return input.filter((item): item is NamePathPart => typeof item === 'string' || typeof item === 'number');
|
|
77
|
+
}
|
|
78
|
+
if (typeof input === 'number') {
|
|
79
|
+
return [input];
|
|
80
|
+
}
|
|
81
|
+
if (typeof input === 'string') {
|
|
82
|
+
return input
|
|
83
|
+
.split('.')
|
|
84
|
+
.map((item) => item.trim())
|
|
85
|
+
.filter(Boolean);
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function startsWithNamePath(namePath: NamePathPart[], prefix: NamePathPart[]) {
|
|
91
|
+
return prefix.length <= namePath.length && prefix.every((item, index) => String(namePath[index]) === String(item));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getFieldSettingsNamePath(model: any): NamePathPart[] | null {
|
|
95
|
+
const init =
|
|
96
|
+
model?.getStepParams?.('fieldSettings', 'init') || model?.parent?.getStepParams?.('fieldSettings', 'init');
|
|
97
|
+
const fieldPath = toNamePath(init?.fieldPath);
|
|
98
|
+
const associationPath = toNamePath(init?.associationPathName);
|
|
99
|
+
|
|
100
|
+
if (!fieldPath?.length) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!associationPath?.length || startsWithNamePath(fieldPath, associationPath)) {
|
|
105
|
+
return fieldPath;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return [...associationPath, ...fieldPath];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function applyFieldIndex(namePath: NamePathPart[] | null, fieldIndex: unknown): NamePathPart[] | null {
|
|
112
|
+
if (!namePath?.length) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
if (namePath.some((item) => typeof item === 'number') || !Array.isArray(fieldIndex) || fieldIndex.length === 0) {
|
|
116
|
+
return namePath;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const indexQueues = new Map<string, number[]>();
|
|
120
|
+
for (const item of fieldIndex) {
|
|
121
|
+
if (typeof item !== 'string') continue;
|
|
122
|
+
const [fieldName, indexStr] = item.split(':');
|
|
123
|
+
const index = Number(indexStr);
|
|
124
|
+
if (!fieldName || !Number.isFinite(index)) continue;
|
|
125
|
+
const queue = indexQueues.get(fieldName) || [];
|
|
126
|
+
queue.push(index);
|
|
127
|
+
indexQueues.set(fieldName, queue);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!indexQueues.size) {
|
|
131
|
+
return namePath;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const result: NamePathPart[] = [];
|
|
135
|
+
for (const item of namePath) {
|
|
136
|
+
result.push(item);
|
|
137
|
+
const queue = indexQueues.get(String(item));
|
|
138
|
+
if (queue?.length) {
|
|
139
|
+
result.push(queue.shift() as number);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function resolveEffectiveNamePath(ctx: any): NamePathPart[] | null {
|
|
146
|
+
const namePath =
|
|
147
|
+
getFieldSettingsNamePath(ctx.model) || toNamePath(ctx.fieldPathArray) || toNamePath(ctx.model?.props?.name);
|
|
148
|
+
return applyFieldIndex(namePath, ctx.fieldIndex);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function setFormValue(form: any, namePath: NamePathPart[], value: any) {
|
|
152
|
+
if (typeof form?.setFieldValue === 'function') {
|
|
153
|
+
form.setFieldValue(namePath, value);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (typeof form?.setFieldsValue === 'function') {
|
|
158
|
+
const patch: any = {};
|
|
159
|
+
let cursor = patch;
|
|
160
|
+
namePath.forEach((item, index) => {
|
|
161
|
+
if (index === namePath.length - 1) {
|
|
162
|
+
cursor[item] = value;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
cursor[item] = typeof namePath[index + 1] === 'number' ? [] : {};
|
|
166
|
+
cursor = cursor[item];
|
|
167
|
+
});
|
|
168
|
+
form.setFieldsValue(patch);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
72
172
|
const JSFormRuntime: React.FC<{
|
|
73
173
|
model: JSEditableFieldModel;
|
|
74
174
|
value?: any;
|
|
@@ -274,9 +374,9 @@ JSEditableFieldModel.registerFlow({
|
|
|
274
374
|
cache: false,
|
|
275
375
|
});
|
|
276
376
|
ctx.defineMethod('getValue', () => {
|
|
277
|
-
const
|
|
278
|
-
if (
|
|
279
|
-
const fv = ctx.form?.getFieldValue?.(
|
|
377
|
+
const namePath = resolveEffectiveNamePath(ctx);
|
|
378
|
+
if (namePath?.length) {
|
|
379
|
+
const fv = ctx.form?.getFieldValue?.(namePath);
|
|
280
380
|
return fv !== undefined ? fv : ctx.model.props?.value;
|
|
281
381
|
}
|
|
282
382
|
return ctx.model.props?.value;
|
|
@@ -284,15 +384,15 @@ JSEditableFieldModel.registerFlow({
|
|
|
284
384
|
ctx.defineMethod('setValue', (v) => {
|
|
285
385
|
try {
|
|
286
386
|
ctx.model.setProps('value', v);
|
|
287
|
-
const
|
|
288
|
-
if (
|
|
289
|
-
ctx.form
|
|
387
|
+
const namePath = resolveEffectiveNamePath(ctx);
|
|
388
|
+
if (namePath?.length) {
|
|
389
|
+
setFormValue(ctx.form, namePath, v);
|
|
290
390
|
}
|
|
291
391
|
} catch (_) {
|
|
292
392
|
// ignore
|
|
293
393
|
}
|
|
294
394
|
});
|
|
295
|
-
ctx.defineProperty('namePath', { get: () => ctx
|
|
395
|
+
ctx.defineProperty('namePath', { get: () => resolveEffectiveNamePath(ctx), cache: false });
|
|
296
396
|
ctx.defineProperty('disabled', { get: () => !!ctx.model.props?.disabled, cache: false });
|
|
297
397
|
ctx.defineProperty('readOnly', {
|
|
298
398
|
get: () => isReadOnlyMode(ctx.model),
|
|
@@ -11,6 +11,7 @@ import React from 'react';
|
|
|
11
11
|
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
12
12
|
import { describe, expect, it, vi } from 'vitest';
|
|
13
13
|
import { FlowEngine, FlowEngineProvider, FlowModel, FlowModelRenderer } from '@nocobase/flow-engine';
|
|
14
|
+
import { get as lodashGet, set as lodashSet } from 'lodash';
|
|
14
15
|
import { JSEditableFieldModel } from '../JSEditableFieldModel';
|
|
15
16
|
|
|
16
17
|
function createField(props?: Record<string, any>, code = '') {
|
|
@@ -73,6 +74,21 @@ const React = ctx.React;
|
|
|
73
74
|
ctx.render(<span data-testid="js-readonly-state">{String(ctx.readOnly)}</span>);
|
|
74
75
|
`;
|
|
75
76
|
|
|
77
|
+
const SET_VALUE_AND_RENDER_NAME_PATH_CODE = `
|
|
78
|
+
const React = ctx.React;
|
|
79
|
+
ctx.setValue?.('44');
|
|
80
|
+
ctx.render(<span data-testid="js-name-path">{JSON.stringify(ctx.namePath)}</span>);
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
function createFormStub(initialValues: any = {}) {
|
|
84
|
+
const store = JSON.parse(JSON.stringify(initialValues));
|
|
85
|
+
return {
|
|
86
|
+
getFieldValue: (namePath: any) => lodashGet(store, namePath),
|
|
87
|
+
setFieldValue: (namePath: any, value: any) => lodashSet(store, namePath, value),
|
|
88
|
+
getFieldsValue: () => store,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
class ParentModel extends FlowModel<any> {
|
|
77
93
|
render() {
|
|
78
94
|
return <FlowModelRenderer model={this.subModels.field} />;
|
|
@@ -83,6 +99,11 @@ function renderParentFieldWithFlowRenderer(
|
|
|
83
99
|
fieldProps?: Record<string, any>,
|
|
84
100
|
parentProps?: Record<string, any>,
|
|
85
101
|
code = EDITABLE_CODE,
|
|
102
|
+
options?: {
|
|
103
|
+
fieldIndex?: string[];
|
|
104
|
+
fieldStepParams?: Record<string, any>;
|
|
105
|
+
form?: any;
|
|
106
|
+
},
|
|
86
107
|
) {
|
|
87
108
|
const engine = new FlowEngine();
|
|
88
109
|
engine.registerModels({ JSEditableFieldModel, ParentModel });
|
|
@@ -96,6 +117,7 @@ function renderParentFieldWithFlowRenderer(
|
|
|
96
117
|
uid: 'js-field-with-parent',
|
|
97
118
|
props: fieldProps,
|
|
98
119
|
stepParams: {
|
|
120
|
+
...(options?.fieldStepParams || {}),
|
|
99
121
|
jsSettings: {
|
|
100
122
|
runJs: {
|
|
101
123
|
code,
|
|
@@ -106,6 +128,13 @@ function renderParentFieldWithFlowRenderer(
|
|
|
106
128
|
},
|
|
107
129
|
});
|
|
108
130
|
|
|
131
|
+
if (options?.form) {
|
|
132
|
+
parent.context.defineProperty('form', { value: options.form });
|
|
133
|
+
}
|
|
134
|
+
if (options?.fieldIndex) {
|
|
135
|
+
parent.subModels.field.context.defineProperty('fieldIndex', { value: options.fieldIndex });
|
|
136
|
+
}
|
|
137
|
+
|
|
109
138
|
render(
|
|
110
139
|
<FlowEngineProvider engine={engine}>
|
|
111
140
|
<FlowModelRenderer model={parent} />
|
|
@@ -207,4 +236,72 @@ describe('JSEditableFieldModel', () => {
|
|
|
207
236
|
applyFlowSpy.mockRestore();
|
|
208
237
|
}
|
|
209
238
|
});
|
|
239
|
+
|
|
240
|
+
it('writes top-level form values through the effective name path', async () => {
|
|
241
|
+
const form = createFormStub({});
|
|
242
|
+
|
|
243
|
+
renderParentFieldWithFlowRenderer({ name: 'staffname' }, undefined, SET_VALUE_AND_RENDER_NAME_PATH_CODE, {
|
|
244
|
+
form,
|
|
245
|
+
fieldStepParams: {
|
|
246
|
+
fieldSettings: {
|
|
247
|
+
init: {
|
|
248
|
+
fieldPath: 'staffname',
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
await waitFor(() => {
|
|
255
|
+
expect(form.getFieldValue(['staffname'])).toBe('44');
|
|
256
|
+
expect(screen.getByTestId('js-name-path')).toHaveTextContent(JSON.stringify(['staffname']));
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('writes subform list values under the association path instead of the form root', async () => {
|
|
261
|
+
const form = createFormStub({ org_o2m: [{}] });
|
|
262
|
+
|
|
263
|
+
renderParentFieldWithFlowRenderer({ name: 'orgname' }, undefined, SET_VALUE_AND_RENDER_NAME_PATH_CODE, {
|
|
264
|
+
form,
|
|
265
|
+
fieldIndex: ['org_o2m:0'],
|
|
266
|
+
fieldStepParams: {
|
|
267
|
+
fieldSettings: {
|
|
268
|
+
init: {
|
|
269
|
+
fieldPath: 'orgname',
|
|
270
|
+
associationPathName: 'org_o2m',
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
await waitFor(() => {
|
|
277
|
+
expect(form.getFieldValue(['org_o2m', 0, 'orgname'])).toBe('44');
|
|
278
|
+
expect(form.getFieldValue(['orgname'])).toBeUndefined();
|
|
279
|
+
expect(screen.getByTestId('js-name-path')).toHaveTextContent(JSON.stringify(['org_o2m', 0, 'orgname']));
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('writes nested subform list values with the full field index chain', async () => {
|
|
284
|
+
const form = createFormStub({ users: [{ roles: [{}, {}] }] });
|
|
285
|
+
|
|
286
|
+
renderParentFieldWithFlowRenderer({ name: 'roleName' }, undefined, SET_VALUE_AND_RENDER_NAME_PATH_CODE, {
|
|
287
|
+
form,
|
|
288
|
+
fieldIndex: ['users:0', 'roles:1'],
|
|
289
|
+
fieldStepParams: {
|
|
290
|
+
fieldSettings: {
|
|
291
|
+
init: {
|
|
292
|
+
fieldPath: 'roleName',
|
|
293
|
+
associationPathName: 'users.roles',
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
await waitFor(() => {
|
|
300
|
+
expect(form.getFieldValue(['users', 0, 'roles', 1, 'roleName'])).toBe('44');
|
|
301
|
+
expect(form.getFieldValue(['roleName'])).toBeUndefined();
|
|
302
|
+
expect(screen.getByTestId('js-name-path')).toHaveTextContent(
|
|
303
|
+
JSON.stringify(['users', 0, 'roles', 1, 'roleName']),
|
|
304
|
+
);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
210
307
|
});
|
package/src/index.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { createCollectionContextMeta } from '@nocobase/flow-engine';
|
|
|
11
11
|
import React, { createContext, type FC, useEffect, useRef, useState } from 'react';
|
|
12
12
|
import { Navigate, Outlet, useLocation } from 'react-router-dom';
|
|
13
13
|
import type { Application } from '../Application';
|
|
14
|
-
import { getCurrentV2RedirectPath, getDefaultV2AdminRedirectPath,
|
|
14
|
+
import { getCurrentV2RedirectPath, getDefaultV2AdminRedirectPath, redirectToV2Signin } from '../authRedirect';
|
|
15
15
|
import { AppNotFound } from '../components';
|
|
16
16
|
import { PluginFlowEngine } from '../flow';
|
|
17
17
|
import { AdminLayoutMenuItemModel, AdminLayoutModel } from '../flow/admin-shell/admin-layout';
|
|
@@ -144,7 +144,7 @@ const CurrentUserProvider: FC = ({ children }) => {
|
|
|
144
144
|
|
|
145
145
|
const user = res?.data?.data;
|
|
146
146
|
if (user?.id == null) {
|
|
147
|
-
|
|
147
|
+
redirectToV2Signin(app, getCurrentV2RedirectPath(app, locationRef.current), { replace: true });
|
|
148
148
|
return;
|
|
149
149
|
}
|
|
150
150
|
|
|
@@ -169,7 +169,7 @@ const CurrentUserProvider: FC = ({ children }) => {
|
|
|
169
169
|
} catch (error: any) {
|
|
170
170
|
const isAuthError = error?.response?.status === 401 || error?.status === 401;
|
|
171
171
|
if (isAuthError) {
|
|
172
|
-
|
|
172
|
+
redirectToV2Signin(app, getCurrentV2RedirectPath(app, locationRef.current), { replace: true });
|
|
173
173
|
return;
|
|
174
174
|
}
|
|
175
175
|
if (mounted) {
|
|
@@ -199,7 +199,7 @@ const RootRedirect: FC = () => {
|
|
|
199
199
|
|
|
200
200
|
useEffect(() => {
|
|
201
201
|
if (!hasToken) {
|
|
202
|
-
|
|
202
|
+
redirectToV2Signin(app, getDefaultV2AdminRedirectPath(app), { replace: true });
|
|
203
203
|
}
|
|
204
204
|
}, [app, hasToken]);
|
|
205
205
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { injectGlobal } from '@emotion/css';
|
|
11
|
+
|
|
12
|
+
// Antd v5 has no labelFontWeight token, so a descendant selector on the
|
|
13
|
+
// stable Form structure is the lowest-risk implementation for the bolder
|
|
14
|
+
// form label default. Injected globally because v1's GlobalThemeProvider
|
|
15
|
+
// re-exports v2's, so any v1 app served from this codebase goes through
|
|
16
|
+
// the same provider and should get the same defaults.
|
|
17
|
+
injectGlobal`
|
|
18
|
+
.ant-form-item-label > label {
|
|
19
|
+
font-weight: 600;
|
|
20
|
+
}
|
|
21
|
+
`;
|
package/src/theme/index.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import React, { createContext, FC, useCallback, useMemo, useRef } from 'react';
|
|
|
13
13
|
import compatOldTheme from './compatOldTheme';
|
|
14
14
|
import { addCustomAlgorithmToTheme } from './customAlgorithm';
|
|
15
15
|
import defaultTheme from './defaultTheme';
|
|
16
|
+
import './globalStyles';
|
|
16
17
|
import { ThemeConfig } from './type';
|
|
17
18
|
|
|
18
19
|
interface ThemeItem {
|
package/src/utils/globalDeps.ts
CHANGED
|
@@ -33,7 +33,8 @@ import * as ReactRouter from 'react-router';
|
|
|
33
33
|
import * as ReactRouterDom from 'react-router-dom';
|
|
34
34
|
import jsxRuntime from 'react/jsx-runtime';
|
|
35
35
|
import * as nocobaseClientV2 from '../index';
|
|
36
|
-
|
|
36
|
+
import * as dndKitCore from '@dnd-kit/core';
|
|
37
|
+
import * as dndKitSortable from '@dnd-kit/sortable';
|
|
37
38
|
import type { RequireJS } from './requirejs';
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -75,6 +76,9 @@ export function defineGlobalDeps(requirejs: RequireJS) {
|
|
|
75
76
|
requirejs.define('@nocobase/evaluators', () => nocobaseEvaluators);
|
|
76
77
|
requirejs.define('@nocobase/evaluators/client', () => nocobaseEvaluators);
|
|
77
78
|
|
|
79
|
+
requirejs.define('@dnd-kit/core', () => dndKitCore);
|
|
80
|
+
requirejs.define('@dnd-kit/sortable', () => dndKitSortable);
|
|
81
|
+
|
|
78
82
|
// utils
|
|
79
83
|
requirejs.define('ahooks', () => ahooks);
|
|
80
84
|
requirejs.define('axios', () => axios);
|