@nocobase/client-v2 2.2.0-beta.1 → 2.2.0-beta.11
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/BaseApplication.d.ts +3 -0
- package/es/PluginSettingsManager.d.ts +33 -0
- package/es/RouteRepository.d.ts +29 -6
- package/es/RouterManager.d.ts +15 -0
- package/es/authRedirect.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterface.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +1 -0
- package/es/components/form/JsonTextArea.d.ts +2 -1
- package/es/components/form/VariableJsonTextArea.d.ts +19 -0
- package/es/components/form/index.d.ts +1 -0
- package/es/components/index.d.ts +1 -0
- package/es/entry-actions/EntryActionManager.d.ts +24 -0
- package/es/entry-actions/index.d.ts +9 -0
- package/es/flow/actions/afterSuccess.d.ts +8 -1
- package/es/flow/actions/index.d.ts +1 -1
- package/es/flow/admin-shell/BaseLayoutModel.d.ts +6 -0
- package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +7 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +2 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +2 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.d.ts +3 -2
- package/es/flow/admin-shell/admin-layout/AdminLayoutSlotModels.d.ts +5 -0
- package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.d.ts +24 -0
- package/es/flow/admin-shell/admin-layout/index.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.d.ts +6 -0
- package/es/flow/admin-shell/admin-layout/useApplications.d.ts +7 -2
- package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
- package/es/flow/models/base/ActionModelCore.d.ts +2 -0
- package/es/flow/models/base/GridModel.d.ts +1 -1
- package/es/flow/models/blocks/filter-form/FilterFormBlockModel.d.ts +5 -0
- package/es/flow/models/blocks/form/FormBlockModel.d.ts +4 -0
- package/es/flow/models/blocks/form/QuickEditFormModel.d.ts +17 -2
- package/es/flow/models/blocks/form/submitHandler.d.ts +1 -1
- package/es/flow/models/blocks/form/value-runtime/rules.d.ts +21 -0
- package/es/flow/models/blocks/form/value-runtime/runtime.d.ts +30 -0
- package/es/flow/models/blocks/form/value-runtime/types.d.ts +2 -2
- package/es/flow/models/blocks/js-block/JSBlock.d.ts +1 -0
- package/es/flow/models/blocks/table/TableActionsColumnModel.d.ts +1 -0
- package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
- package/es/flow/models/blocks/table/dragSort/dragSortHooks.d.ts +1 -1
- package/es/flow/models/blocks/table/dragSort/dragSortSettings.d.ts +2 -1
- package/es/flow/models/blocks/table/dragSort/dragSortUtils.d.ts +6 -4
- package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +2 -0
- package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +6 -0
- package/es/flow/resolveViewParamsToViewList.d.ts +1 -1
- package/es/flow/routeTransientInputArgs.d.ts +14 -0
- package/es/flow/utils/dataScopeRowSnapshot.d.ts +59 -0
- package/es/flow/utils/dateTimeDisplayProps.d.ts +49 -0
- package/es/flow/utils/formValueDeps.d.ts +32 -0
- package/es/flow-compat/FieldValidation.d.ts +2 -1
- package/es/index.d.ts +4 -1
- package/es/index.mjs +315 -167
- package/es/utils/markdownSanitize.d.ts +11 -0
- package/lib/index.js +315 -167
- package/package.json +8 -7
- package/src/BaseApplication.tsx +12 -5
- package/src/PluginSettingsManager.ts +53 -0
- package/src/RouteRepository.ts +151 -24
- package/src/RouterManager.tsx +142 -1
- package/src/__tests__/PluginSettingsManager.test.ts +13 -0
- package/src/__tests__/RouteRepository.test.ts +239 -0
- package/src/__tests__/RouterManager.test.ts +125 -0
- package/src/__tests__/app.test.tsx +55 -0
- package/src/__tests__/authRedirect.test.ts +17 -0
- package/src/__tests__/exports.test.ts +16 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +199 -0
- package/src/__tests__/plugin-manager.test.tsx +44 -2
- package/src/__tests__/settings-center.test.tsx +40 -1
- package/src/authRedirect.ts +38 -0
- package/src/collection-field-interface/CollectionFieldInterface.ts +1 -0
- package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +1 -0
- package/src/collection-manager/field-configure.ts +1 -1
- package/src/collection-manager/interfaces/id.ts +1 -1
- package/src/collection-manager/interfaces/m2m.tsx +2 -2
- package/src/collection-manager/interfaces/m2o.tsx +2 -2
- package/src/collection-manager/interfaces/nanoid.ts +1 -1
- package/src/collection-manager/interfaces/o2m.tsx +2 -2
- package/src/collection-manager/interfaces/obo.tsx +2 -2
- package/src/collection-manager/interfaces/oho.tsx +2 -2
- package/src/collection-manager/interfaces/properties/index.ts +2 -2
- package/src/collection-manager/interfaces/uuid.ts +1 -1
- package/src/components/AppComponents.tsx +19 -3
- package/src/components/form/JsonTextArea.tsx +21 -11
- package/src/components/form/ScanInput/__tests__/useCodeScanner.test.tsx +145 -2
- package/src/components/form/ScanInput/useCodeScanner.ts +154 -2
- package/src/components/form/VariableJsonTextArea.tsx +175 -0
- package/src/components/form/__tests__/JsonTextArea.test.tsx +43 -0
- package/src/components/form/__tests__/VariableJsonTextArea.test.tsx +86 -0
- package/src/components/form/index.tsx +1 -0
- package/src/components/index.ts +1 -0
- package/src/entry-actions/EntryActionManager.ts +76 -0
- package/src/entry-actions/index.ts +10 -0
- package/src/flow/FlowPage.tsx +38 -3
- package/src/flow/__tests__/FlowPage.test.tsx +201 -27
- package/src/flow/__tests__/FlowRoute.test.tsx +1088 -105
- package/src/flow/__tests__/getKey.test.ts +7 -0
- package/src/flow/__tests__/resolveViewParamsToViewList.test.ts +34 -0
- package/src/flow/actions/__tests__/afterSuccess.test.ts +73 -0
- package/src/flow/actions/__tests__/dataScopeFilter.test.ts +120 -0
- package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +1022 -0
- package/src/flow/actions/__tests__/fieldLinkageRules.scopeDepth.test.ts +150 -1
- package/src/flow/actions/__tests__/linkageAssignField.legacy.test.ts +135 -0
- package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +19 -5
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +92 -0
- package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +7 -3
- package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +164 -0
- package/src/flow/actions/__tests__/subFormFieldLinkageRules.inputArgs.test.ts +2 -2
- package/src/flow/actions/afterSuccess.tsx +142 -3
- package/src/flow/actions/customVariable.tsx +1 -2
- package/src/flow/actions/dataScopeFilter.ts +20 -1
- package/src/flow/actions/dateTimeFormat.tsx +42 -28
- package/src/flow/actions/index.ts +1 -1
- package/src/flow/actions/linkageRules.tsx +123 -35
- package/src/flow/actions/linkageRulesFormValueRefresh.ts +22 -130
- package/src/flow/actions/linkageRulesRefresh.tsx +2 -6
- package/src/flow/actions/openView.tsx +59 -5
- package/src/flow/actions/runjs.tsx +2 -14
- package/src/flow/actions/validation.tsx +62 -30
- package/src/flow/admin-shell/BaseLayoutModel.tsx +149 -3
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +187 -42
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +1020 -110
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +74 -13
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +486 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +64 -8
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.ts +5 -3
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +61 -9
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +71 -8
- package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +1 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +23 -9
- package/src/flow/admin-shell/admin-layout/AppListRender.tsx +13 -2
- package/src/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.tsx +289 -0
- package/src/flow/admin-shell/admin-layout/HelpLite.tsx +1 -3
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +188 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +99 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +518 -2
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +214 -2
- package/src/flow/admin-shell/admin-layout/index.ts +1 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +20 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +33 -5
- package/src/flow/admin-shell/admin-layout/useApplications.tsx +81 -12
- package/src/flow/common/Markdown/Display.tsx +14 -3
- package/src/flow/common/Markdown/Edit.tsx +19 -7
- package/src/flow/components/DefaultValue.tsx +1 -2
- package/src/flow/components/DynamicFlowsIcon.tsx +447 -126
- package/src/flow/components/FieldAssignRulesEditor.tsx +128 -21
- package/src/flow/components/FieldAssignValueInput.tsx +15 -11
- package/src/flow/components/FlowRoute.tsx +186 -25
- package/src/flow/components/__tests__/DynamicFlowsIcon.test.tsx +148 -2
- package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +508 -4
- package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +134 -0
- package/src/flow/components/__tests__/fieldAssignOptions.test.ts +151 -3
- package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +2 -17
- package/src/flow/components/code-editor/hooks/useCodeRunner.ts +2 -14
- package/src/flow/components/code-editor/runjsDiagnostics.ts +8 -45
- package/src/flow/components/fieldAssignOptions.ts +155 -27
- package/src/flow/flows/editMarkdownFlow.tsx +1 -1
- package/src/flow/getViewDiffAndUpdateHidden.tsx +1 -0
- package/src/flow/index.ts +1 -1
- package/src/flow/internal/components/Markdown/util.ts +2 -1
- package/src/flow/internal/utils/operatorSchemaHelper.ts +15 -1
- package/src/flow/models/actions/JSActionModel.tsx +2 -7
- package/src/flow/models/actions/JSCollectionActionModel.tsx +2 -7
- package/src/flow/models/actions/JSItemActionModel.tsx +2 -7
- package/src/flow/models/actions/JSRecordActionModel.tsx +2 -7
- package/src/flow/models/base/ActionModel.tsx +21 -8
- package/src/flow/models/base/ActionModelCore.tsx +11 -4
- package/src/flow/models/base/GridModel.tsx +38 -7
- package/src/flow/models/base/PageModel/PageModel.tsx +4 -1
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +28 -4
- package/src/flow/models/base/__tests__/ActionModel.test.ts +83 -0
- package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +37 -0
- package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +239 -1
- package/src/flow/models/base/__tests__/transformRowsToSingleColumn.test.ts +48 -0
- package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +32 -3
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +27 -12
- package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +36 -0
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +111 -0
- package/src/flow/models/blocks/filter-form/fields/FilterFormCustomFieldModel.tsx +1 -1
- package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +56 -1
- package/src/flow/models/blocks/form/EditFormModel.tsx +1 -0
- package/src/flow/models/blocks/form/FormActionModel.tsx +1 -1
- package/src/flow/models/blocks/form/FormBlockModel.tsx +7 -0
- package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
- package/src/flow/models/blocks/form/QuickEditFormModel.tsx +189 -36
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
- package/src/flow/models/blocks/form/__tests__/QuickEditFormModel.quickEdit.test.ts +350 -2
- package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +54 -1
- package/src/flow/models/blocks/form/submitHandler.ts +17 -3
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +940 -75
- package/src/flow/models/blocks/form/value-runtime/rules.ts +445 -13
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +348 -13
- package/src/flow/models/blocks/form/value-runtime/types.ts +2 -2
- package/src/flow/models/blocks/js-block/JSBlock.tsx +225 -9
- package/src/flow/models/blocks/js-block/__tests__/JSBlockModel.test.tsx +150 -0
- package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
- package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +38 -14
- package/src/flow/models/blocks/table/TableBlockModel.tsx +38 -17
- package/src/flow/models/blocks/table/TableColumnModel.tsx +42 -5
- package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +111 -1
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.dragSort.test.ts +127 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +1 -0
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +210 -1
- package/src/flow/models/blocks/table/dragSort/dragSortHooks.tsx +28 -17
- package/src/flow/models/blocks/table/dragSort/dragSortSettings.ts +13 -6
- package/src/flow/models/blocks/table/dragSort/dragSortUtils.ts +15 -2
- package/src/flow/models/fields/AssociationFieldModel/AssociationFieldModel.tsx +1 -1
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +30 -6
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +61 -17
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +141 -19
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +13 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +197 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableFieldModel.reset.test.ts +180 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -4
- package/src/flow/models/fields/AssociationFieldModel/__tests__/AssociationFieldModel.updateAssociation.test.ts +72 -0
- package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +23 -0
- package/src/flow/models/fields/ClickableFieldModel.tsx +5 -0
- package/src/flow/models/fields/DisplayDateTimeFieldModel.tsx +29 -1
- package/src/flow/models/fields/InputFieldModel.tsx +40 -2
- package/src/flow/models/fields/JSEditableFieldModel.tsx +2 -11
- package/src/flow/models/fields/JSFieldModel.tsx +2 -7
- package/src/flow/models/fields/JSItemModel.tsx +2 -14
- package/src/flow/models/fields/SelectFieldModel.tsx +6 -4
- package/src/flow/models/fields/TextareaFieldModel.tsx +72 -3
- package/src/flow/models/fields/__tests__/DisplayDateTimeFieldModel.test.tsx +96 -0
- package/src/flow/models/fields/__tests__/InputFieldModel.test.tsx +117 -1
- package/src/flow/models/fields/__tests__/SelectFieldModel.test.tsx +43 -0
- package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +131 -0
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +20 -10
- package/src/flow/models/fields/mobile-components/MobileSelect.tsx +24 -12
- package/src/flow/models/topbar/TopbarActionModel.tsx +168 -10
- package/src/flow/resolveViewParamsToViewList.tsx +11 -3
- package/src/flow/routeTransientInputArgs.ts +27 -0
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +300 -0
- package/src/flow/utils/dataScopeFormValueClear.ts +218 -81
- package/src/flow/utils/dataScopeRowSnapshot.ts +616 -0
- package/src/flow/utils/dateTimeDisplayProps.ts +135 -0
- package/src/flow/utils/formValueDeps.ts +170 -0
- package/src/flow-compat/FieldValidation.tsx +122 -60
- package/src/flow-compat/Popover.tsx +43 -4
- package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
- package/src/index.ts +10 -1
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
- package/src/nocobase-buildin-plugin/index.tsx +51 -15
- package/src/settings-center/AdminSettingsLayout.tsx +10 -2
- package/src/settings-center/SystemSettingsPage.tsx +1 -2
- package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
- package/src/settings-center/plugin-manager/index.tsx +3 -0
- package/src/settings-center/utils.tsx +0 -6
- package/src/utils/markdownSanitize.ts +88 -0
|
@@ -0,0 +1,43 @@
|
|
|
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 React from 'react';
|
|
11
|
+
import { describe, expect, it } from 'vitest';
|
|
12
|
+
import { SelectFieldModel } from '../SelectFieldModel';
|
|
13
|
+
|
|
14
|
+
function mockT(text: string) {
|
|
15
|
+
if (text === '{{t("Yes")}}') return '是';
|
|
16
|
+
if (text === '{{t("No")}}') return '否';
|
|
17
|
+
return text;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('SelectFieldModel', () => {
|
|
21
|
+
it('translates enum fallback labels for selected values', () => {
|
|
22
|
+
const model = {
|
|
23
|
+
props: {
|
|
24
|
+
value: true,
|
|
25
|
+
},
|
|
26
|
+
context: {
|
|
27
|
+
collectionField: {
|
|
28
|
+
uiSchema: {
|
|
29
|
+
enum: [
|
|
30
|
+
{ label: '{{t("Yes")}}', value: true },
|
|
31
|
+
{ label: '{{t("No")}}', value: false },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
translate: mockT,
|
|
37
|
+
} as unknown as SelectFieldModel;
|
|
38
|
+
|
|
39
|
+
const element = SelectFieldModel.prototype.render.call(model) as React.ReactElement;
|
|
40
|
+
|
|
41
|
+
expect(element.props.value).toEqual({ label: '是', value: true });
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
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 { FieldModelRenderer, FlowEngine, FlowEngineProvider } from '@nocobase/flow-engine';
|
|
11
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
12
|
+
import { Form } from 'antd';
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
15
|
+
import { TextareaFieldModel } from '../TextareaFieldModel';
|
|
16
|
+
|
|
17
|
+
function createTextareaFieldModel(props?: Record<string, unknown>) {
|
|
18
|
+
const engine = new FlowEngine();
|
|
19
|
+
return new TextareaFieldModel({
|
|
20
|
+
uid: 'textarea-field-model-test',
|
|
21
|
+
flowEngine: engine,
|
|
22
|
+
props,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe('TextareaFieldModel', () => {
|
|
27
|
+
it('syncs multiline values assigned through the form renderer', async () => {
|
|
28
|
+
const flowEngine = new FlowEngine();
|
|
29
|
+
const model = createTextareaFieldModel();
|
|
30
|
+
model.dispatchEvent = vi.fn().mockResolvedValue([]);
|
|
31
|
+
|
|
32
|
+
function FormHost() {
|
|
33
|
+
const [form] = Form.useForm();
|
|
34
|
+
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
form.setFieldsValue({ address: 'aaaaaa\nbbbbbb' });
|
|
37
|
+
}, [form]);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<FlowEngineProvider engine={flowEngine}>
|
|
41
|
+
<Form form={form}>
|
|
42
|
+
<Form.Item name="address">
|
|
43
|
+
<FieldModelRenderer model={model} />
|
|
44
|
+
</Form.Item>
|
|
45
|
+
</Form>
|
|
46
|
+
</FlowEngineProvider>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
render(<FormHost />);
|
|
51
|
+
|
|
52
|
+
await waitFor(() => {
|
|
53
|
+
expect((screen.getByRole('textbox') as HTMLTextAreaElement).value).toBe('aaaaaa\nbbbbbb');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('keeps IME composition text visible before the parent value is committed', () => {
|
|
58
|
+
const onChange = vi.fn();
|
|
59
|
+
const onCompositionStart = vi.fn();
|
|
60
|
+
const onCompositionEnd = vi.fn();
|
|
61
|
+
const model = createTextareaFieldModel({
|
|
62
|
+
value: '',
|
|
63
|
+
onChange,
|
|
64
|
+
onCompositionStart,
|
|
65
|
+
onCompositionEnd,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
render(<>{model.render()}</>);
|
|
69
|
+
|
|
70
|
+
const textarea = screen.getByRole('textbox') as HTMLTextAreaElement;
|
|
71
|
+
|
|
72
|
+
fireEvent.compositionStart(textarea);
|
|
73
|
+
fireEvent.change(textarea, { target: { value: 'ni' }, nativeEvent: { isComposing: true } });
|
|
74
|
+
|
|
75
|
+
expect(textarea.value).toBe('ni');
|
|
76
|
+
expect(onChange).toHaveBeenCalledTimes(1);
|
|
77
|
+
expect(onCompositionStart).toHaveBeenCalledTimes(1);
|
|
78
|
+
|
|
79
|
+
fireEvent.compositionEnd(textarea, { target: { value: '你' } });
|
|
80
|
+
|
|
81
|
+
expect(textarea.value).toBe('你');
|
|
82
|
+
expect(onCompositionEnd).toHaveBeenCalledTimes(1);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('does not overwrite in-progress DOM input with a stale parent value', async () => {
|
|
86
|
+
const onChange = vi.fn();
|
|
87
|
+
const createModel = (value: string) =>
|
|
88
|
+
createTextareaFieldModel({
|
|
89
|
+
value,
|
|
90
|
+
onChange,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const { rerender } = render(<>{createModel('').render()}</>);
|
|
94
|
+
const textarea = screen.getByRole('textbox') as HTMLTextAreaElement;
|
|
95
|
+
|
|
96
|
+
fireEvent.change(textarea, { target: { value: 'té' } });
|
|
97
|
+
rerender(<>{createModel('').render()}</>);
|
|
98
|
+
|
|
99
|
+
expect(textarea.value).toBe('té');
|
|
100
|
+
|
|
101
|
+
rerender(<>{createModel('reset').render()}</>);
|
|
102
|
+
|
|
103
|
+
await waitFor(() => {
|
|
104
|
+
expect((screen.getByRole('textbox') as HTMLTextAreaElement).value).toBe('reset');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('keeps replacement-style Vietnamese IME edits in the DOM', () => {
|
|
109
|
+
const onChange = vi.fn();
|
|
110
|
+
const createModel = (value: string) =>
|
|
111
|
+
createTextareaFieldModel({
|
|
112
|
+
value,
|
|
113
|
+
onChange,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const { rerender } = render(<>{createModel('').render()}</>);
|
|
117
|
+
const textarea = screen.getByRole('textbox') as HTMLTextAreaElement;
|
|
118
|
+
|
|
119
|
+
fireEvent.change(textarea, { target: { value: 'te' } });
|
|
120
|
+
rerender(<>{createModel('te').render()}</>);
|
|
121
|
+
expect(textarea.value).toBe('te');
|
|
122
|
+
|
|
123
|
+
fireEvent.change(textarea, { target: { value: 'té' } });
|
|
124
|
+
rerender(<>{createModel('te').render()}</>);
|
|
125
|
+
expect(textarea.value).toBe('té');
|
|
126
|
+
|
|
127
|
+
fireEvent.change(textarea, { target: { value: 'tét' } });
|
|
128
|
+
rerender(<>{createModel('té').render()}</>);
|
|
129
|
+
expect(textarea.value).toBe('tét');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -23,6 +23,20 @@ import {
|
|
|
23
23
|
} from '../AssociationFieldModel/recordSelectShared';
|
|
24
24
|
import _ from 'lodash';
|
|
25
25
|
|
|
26
|
+
const mobileSelectSafeAreaPaddingBottom = 'calc(12px + env(safe-area-inset-bottom, 0px))';
|
|
27
|
+
|
|
28
|
+
const mobileSelectConfirmFooterStyle: CSSProperties = {
|
|
29
|
+
paddingBottom: mobileSelectSafeAreaPaddingBottom,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function getMobileSelectListStyle(hasConfirmFooter: boolean): CSSProperties {
|
|
33
|
+
return {
|
|
34
|
+
maxHeight: '60vh',
|
|
35
|
+
overflowY: 'auto',
|
|
36
|
+
paddingBottom: hasConfirmFooter ? undefined : mobileSelectSafeAreaPaddingBottom,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
const labelClassName = css`
|
|
27
41
|
div {
|
|
28
42
|
white-space: nowrap !important;
|
|
@@ -280,13 +294,7 @@ export function MobileLazySelect(props: Readonly<LazySelectProps>) {
|
|
|
280
294
|
showCancelButton
|
|
281
295
|
/>
|
|
282
296
|
</div>
|
|
283
|
-
<div
|
|
284
|
-
style={{
|
|
285
|
-
maxHeight: '60vh',
|
|
286
|
-
overflowY: 'auto',
|
|
287
|
-
}}
|
|
288
|
-
onScroll={handleScroll}
|
|
289
|
-
>
|
|
297
|
+
<div style={getMobileSelectListStyle(isMultiple)} onScroll={handleScroll}>
|
|
290
298
|
<CheckList multiple={isMultiple} value={selectedValueIds} onChange={handleListChange}>
|
|
291
299
|
{realOptions.map((item) => {
|
|
292
300
|
const optionValue = item?.[valueKey];
|
|
@@ -311,9 +319,11 @@ export function MobileLazySelect(props: Readonly<LazySelectProps>) {
|
|
|
311
319
|
)}
|
|
312
320
|
</div>
|
|
313
321
|
{isMultiple && (
|
|
314
|
-
<
|
|
315
|
-
{
|
|
316
|
-
|
|
322
|
+
<div style={mobileSelectConfirmFooterStyle}>
|
|
323
|
+
<Button block color="primary" onClick={handleConfirm} style={{ marginTop: '16px' }}>
|
|
324
|
+
{t('Confirm')}
|
|
325
|
+
</Button>
|
|
326
|
+
</div>
|
|
317
327
|
)}
|
|
318
328
|
</Popup>
|
|
319
329
|
</>
|
|
@@ -12,8 +12,23 @@ import { Select } from 'antd';
|
|
|
12
12
|
import { Button, CheckList, Popup, SearchBar } from 'antd-mobile';
|
|
13
13
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
14
14
|
|
|
15
|
+
const mobileSelectSafeAreaPaddingBottom = 'calc(12px + env(safe-area-inset-bottom, 0px))';
|
|
16
|
+
|
|
17
|
+
const mobileSelectConfirmFooterStyle: React.CSSProperties = {
|
|
18
|
+
paddingBottom: mobileSelectSafeAreaPaddingBottom,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function getMobileSelectListStyle(hasConfirmFooter: boolean): React.CSSProperties {
|
|
22
|
+
return {
|
|
23
|
+
maxHeight: '60vh',
|
|
24
|
+
overflowY: 'auto',
|
|
25
|
+
paddingBottom: hasConfirmFooter ? undefined : mobileSelectSafeAreaPaddingBottom,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
15
29
|
export function MobileSelect(props) {
|
|
16
30
|
const { value, displayValue, onChange, onChangeComplete, disabled, options = [], mode } = props;
|
|
31
|
+
const isMultiple = ['multiple', 'tags'].includes(mode);
|
|
17
32
|
const ctx = useFlowModelContext();
|
|
18
33
|
const t = ctx.t;
|
|
19
34
|
const [visible, setVisible] = useState(false);
|
|
@@ -64,17 +79,12 @@ export function MobileSelect(props) {
|
|
|
64
79
|
<div style={{ margin: '10px' }}>
|
|
65
80
|
<SearchBar placeholder={t('search')} value={searchText} onChange={(v) => setSearchText(v)} showCancelButton />
|
|
66
81
|
</div>
|
|
67
|
-
<div
|
|
68
|
-
style={{
|
|
69
|
-
maxHeight: '60vh',
|
|
70
|
-
overflowY: 'auto',
|
|
71
|
-
}}
|
|
72
|
-
>
|
|
82
|
+
<div style={getMobileSelectListStyle(isMultiple)}>
|
|
73
83
|
<CheckList
|
|
74
|
-
multiple={
|
|
84
|
+
multiple={isMultiple}
|
|
75
85
|
value={Array.isArray(selected) ? selected : [selected]}
|
|
76
86
|
onChange={(val) => {
|
|
77
|
-
if (
|
|
87
|
+
if (isMultiple) {
|
|
78
88
|
setSelected(val);
|
|
79
89
|
} else {
|
|
80
90
|
setSelected(val[0]);
|
|
@@ -91,10 +101,12 @@ export function MobileSelect(props) {
|
|
|
91
101
|
))}
|
|
92
102
|
</CheckList>
|
|
93
103
|
</div>
|
|
94
|
-
{
|
|
95
|
-
<
|
|
96
|
-
{
|
|
97
|
-
|
|
104
|
+
{isMultiple && (
|
|
105
|
+
<div style={mobileSelectConfirmFooterStyle}>
|
|
106
|
+
<Button block color="primary" onClick={handleConfirm} style={{ marginTop: '16px' }}>
|
|
107
|
+
{t('Confirm')}
|
|
108
|
+
</Button>
|
|
109
|
+
</div>
|
|
98
110
|
)}
|
|
99
111
|
</Popup>
|
|
100
112
|
</>
|
|
@@ -14,9 +14,11 @@ import { Button, Dropdown, theme, Tooltip, type ButtonProps, type MenuProps } fr
|
|
|
14
14
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
15
15
|
import { useHotkeys } from 'react-hotkeys-hook';
|
|
16
16
|
import { useTranslation } from 'react-i18next';
|
|
17
|
-
import { Link } from 'react-router-dom';
|
|
17
|
+
import { Link, useLocation } from 'react-router-dom';
|
|
18
18
|
import { useACLRoleContext } from '../../../acl';
|
|
19
|
+
import type { BaseApplication } from '../../../BaseApplication';
|
|
19
20
|
import type { PluginSettingsPageType } from '../../../PluginSettingsManager';
|
|
21
|
+
import { shouldOpenAdminRouteInNewWindow } from '../../../RouterManager';
|
|
20
22
|
import { useApp } from '../../../hooks/useApp';
|
|
21
23
|
import {
|
|
22
24
|
filterRenderableSettings,
|
|
@@ -64,6 +66,163 @@ const topbarActionTriggerClassName = css`
|
|
|
64
66
|
height: 100%;
|
|
65
67
|
`;
|
|
66
68
|
|
|
69
|
+
type TopbarSettingsAppLike = Pick<
|
|
70
|
+
BaseApplication<any>,
|
|
71
|
+
'name' | 'router' | 'getPublicPath' | 'getHref' | 'layoutManager'
|
|
72
|
+
>;
|
|
73
|
+
|
|
74
|
+
const normalizeTopbarPath = (pathname?: string) => {
|
|
75
|
+
const trimmed = pathname?.trim();
|
|
76
|
+
if (!trimmed || trimmed === '/') {
|
|
77
|
+
return '/';
|
|
78
|
+
}
|
|
79
|
+
return `/${trimmed.replace(/^\/+/, '')}`;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const normalizeTopbarBasePath = (pathname?: string) => {
|
|
83
|
+
const normalized = normalizeTopbarPath(pathname).replace(/\/+$/, '');
|
|
84
|
+
return normalized === '' || normalized === '/' ? '' : normalized;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const getTopbarRouterBasePath = (app: TopbarSettingsAppLike | undefined) => {
|
|
88
|
+
return app?.router?.getBasename?.() || app?.router?.basename || app?.getPublicPath?.() || '';
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const stripTopbarRouterBasePath = (pathname: string, basename?: string) => {
|
|
92
|
+
const normalizedPath = normalizeTopbarPath(pathname);
|
|
93
|
+
const normalizedBase = normalizeTopbarBasePath(basename);
|
|
94
|
+
|
|
95
|
+
if (!normalizedBase) {
|
|
96
|
+
return normalizedPath;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (normalizedPath === normalizedBase) {
|
|
100
|
+
return '/';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (normalizedPath.startsWith(`${normalizedBase}/`)) {
|
|
104
|
+
return normalizeTopbarPath(normalizedPath.slice(normalizedBase.length));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return normalizedPath;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const getTopbarAppPath = (pathname: string) => {
|
|
111
|
+
const normalizedPath = normalizeTopbarPath(pathname);
|
|
112
|
+
const match = /^(.*?\/(?:apps|_app)\/[^/]+)(?=\/|$)/.exec(normalizedPath);
|
|
113
|
+
const appPath = match?.[1] || '';
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
appPath,
|
|
117
|
+
routePath: appPath ? normalizeTopbarPath(normalizedPath.slice(appPath.length)) : normalizedPath,
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const getTopbarContextAppPath = (app: TopbarSettingsAppLike | undefined, basename?: string) => {
|
|
122
|
+
const basenameAppPath = getTopbarAppPath(basename || '').appPath;
|
|
123
|
+
if (basenameAppPath) {
|
|
124
|
+
return basenameAppPath;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const publicPathAppPath = getTopbarAppPath(app?.getPublicPath?.() || '').appPath;
|
|
128
|
+
if (publicPathAppPath) {
|
|
129
|
+
return publicPathAppPath;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (app?.name && app.name !== 'main' && app.getHref) {
|
|
133
|
+
return normalizeTopbarBasePath(app.getHref('/'));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return '';
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const prependTopbarAppPath = (pathname: string, appPath: string) => {
|
|
140
|
+
const normalizedPath = normalizeTopbarPath(pathname);
|
|
141
|
+
|
|
142
|
+
if (!appPath || normalizedPath === appPath || normalizedPath.startsWith(`${appPath}/`)) {
|
|
143
|
+
return normalizedPath;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return `${appPath}${normalizedPath}`;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const isAdminRuntimePath = (pathname: string) => {
|
|
150
|
+
return pathname === '/admin' || pathname.startsWith('/admin/');
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const getTopbarAdminRoutePath = (app: TopbarSettingsAppLike | undefined) => {
|
|
154
|
+
try {
|
|
155
|
+
return app?.layoutManager?.getLayout?.('admin')?.routePath;
|
|
156
|
+
} catch {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const buildTopbarDocumentHref = (targetPath: string, basename?: string) => {
|
|
162
|
+
const normalizedTarget = normalizeTopbarPath(targetPath);
|
|
163
|
+
const normalizedBase = normalizeTopbarBasePath(basename);
|
|
164
|
+
|
|
165
|
+
if (!normalizedBase || normalizedTarget === normalizedBase || normalizedTarget.startsWith(`${normalizedBase}/`)) {
|
|
166
|
+
return normalizedTarget;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return `${normalizedBase}${normalizedTarget}`;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
function TopbarExternalSettingsLabel(props: { title: React.ReactNode; link: string }) {
|
|
173
|
+
return (
|
|
174
|
+
<div
|
|
175
|
+
onClick={() => {
|
|
176
|
+
window.open(props.link, '_blank', 'noopener,noreferrer');
|
|
177
|
+
}}
|
|
178
|
+
>
|
|
179
|
+
{props.title}
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function TopbarInternalSettingsLabel(props: { title: React.ReactNode; path?: string }) {
|
|
185
|
+
const app = useApp();
|
|
186
|
+
const location = useLocation();
|
|
187
|
+
const targetPath = props.path || '/admin/settings';
|
|
188
|
+
const basename = getTopbarRouterBasePath(app);
|
|
189
|
+
const currentPath = stripTopbarRouterBasePath(location.pathname, basename);
|
|
190
|
+
const currentLocationAppPath = getTopbarAppPath(currentPath);
|
|
191
|
+
const currentAppPath = currentLocationAppPath.appPath || getTopbarContextAppPath(app, basename);
|
|
192
|
+
const currentRoutePath = currentLocationAppPath.appPath ? currentLocationAppPath.routePath : currentPath;
|
|
193
|
+
const targetPathInCurrentApp = prependTopbarAppPath(stripTopbarRouterBasePath(targetPath, basename), currentAppPath);
|
|
194
|
+
|
|
195
|
+
if (currentAppPath) {
|
|
196
|
+
const href = buildTopbarDocumentHref(targetPathInCurrentApp, basename);
|
|
197
|
+
const shouldOpenInNewWindow = shouldOpenAdminRouteInNewWindow({
|
|
198
|
+
currentPathname: currentPath,
|
|
199
|
+
targetPathname: targetPathInCurrentApp,
|
|
200
|
+
basePath: basename,
|
|
201
|
+
adminRoutePath: getTopbarAdminRoutePath(app),
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<a
|
|
206
|
+
href={href}
|
|
207
|
+
target={shouldOpenInNewWindow ? '_blank' : undefined}
|
|
208
|
+
rel={shouldOpenInNewWindow ? 'noopener noreferrer' : undefined}
|
|
209
|
+
>
|
|
210
|
+
{props.title}
|
|
211
|
+
</a>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (isAdminRuntimePath(currentRoutePath)) {
|
|
216
|
+
return <Link to={targetPathInCurrentApp}>{props.title}</Link>;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<a href={buildTopbarDocumentHref(targetPath, basename)} target="_blank" rel="noopener noreferrer">
|
|
221
|
+
{props.title}
|
|
222
|
+
</a>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
67
226
|
/**
|
|
68
227
|
* 将 settings 顶部菜单转换成右上角 dropdown items。
|
|
69
228
|
*
|
|
@@ -112,15 +271,9 @@ export function getTopbarPluginSettingsItems(options: {
|
|
|
112
271
|
title: targetTitle,
|
|
113
272
|
icon: item.icon,
|
|
114
273
|
label: targetLink ? (
|
|
115
|
-
<
|
|
116
|
-
onClick={() => {
|
|
117
|
-
window.open(targetLink, '_blank', 'noopener,noreferrer');
|
|
118
|
-
}}
|
|
119
|
-
>
|
|
120
|
-
{targetTitle}
|
|
121
|
-
</div>
|
|
274
|
+
<TopbarExternalSettingsLabel title={targetTitle} link={targetLink} />
|
|
122
275
|
) : (
|
|
123
|
-
<
|
|
276
|
+
<TopbarInternalSettingsLabel title={targetTitle} path={targetPath} />
|
|
124
277
|
),
|
|
125
278
|
};
|
|
126
279
|
});
|
|
@@ -131,7 +284,12 @@ export function getTopbarPluginSettingsItems(options: {
|
|
|
131
284
|
items.push({
|
|
132
285
|
key: pluginManagerSetting.key,
|
|
133
286
|
icon: pluginManagerSetting.icon || <ApiOutlined />,
|
|
134
|
-
label:
|
|
287
|
+
label: (
|
|
288
|
+
<TopbarInternalSettingsLabel
|
|
289
|
+
title={pluginManagerSetting.title || t('Plugin manager')}
|
|
290
|
+
path={pluginManagerSetting.path}
|
|
291
|
+
/>
|
|
292
|
+
),
|
|
135
293
|
});
|
|
136
294
|
}
|
|
137
295
|
|
|
@@ -49,12 +49,12 @@ export function resolveViewParamsToViewList(
|
|
|
49
49
|
return viewItems;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export function updateViewListHidden(viewItems: ViewItem[]) {
|
|
52
|
+
export function updateViewListHidden(viewItems: ViewItem[], isMobileLayout = false) {
|
|
53
53
|
// Calculate hidden values based on view types and positions
|
|
54
54
|
let hasEmbedAfter = false;
|
|
55
55
|
for (let i = viewItems.length - 1; i >= 0; i--) {
|
|
56
56
|
const viewItem = viewItems[i];
|
|
57
|
-
const viewType = getViewType(viewItem);
|
|
57
|
+
const viewType = getViewType(viewItem, isMobileLayout);
|
|
58
58
|
|
|
59
59
|
if (viewType === 'embed' && !hasEmbedAfter) {
|
|
60
60
|
hasEmbedAfter = true;
|
|
@@ -65,15 +65,23 @@ export function updateViewListHidden(viewItems: ViewItem[]) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
function getViewType(viewItem: ViewItem): string {
|
|
68
|
+
function getViewType(viewItem: ViewItem, isMobileLayout = false): string {
|
|
69
69
|
if (viewItem.model instanceof RouteModel) {
|
|
70
70
|
return 'embed';
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
if (isMobileLayout && viewItem.index > 0) {
|
|
74
|
+
return 'embed';
|
|
75
|
+
}
|
|
76
|
+
|
|
73
77
|
if (!viewItem.model) {
|
|
74
78
|
return 'drawer';
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
if (viewItem.params.openViewRouteState?.mode) {
|
|
82
|
+
return viewItem.params.openViewRouteState.mode;
|
|
83
|
+
}
|
|
84
|
+
|
|
77
85
|
const params = viewItem.model.getStepParams('popupSettings', 'openView');
|
|
78
86
|
return params?.mode || 'drawer';
|
|
79
87
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
export const ROUTE_TRANSIENT_INPUT_ARGS_KEY = '__nocobaseOpenViewInputArgs';
|
|
11
|
+
|
|
12
|
+
export type RouteTransientInputArgsState = {
|
|
13
|
+
[ROUTE_TRANSIENT_INPUT_ARGS_KEY]?: Record<string, Record<string, unknown>>;
|
|
14
|
+
usr?: RouteTransientInputArgsState;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const getRouteTransientInputArgs = (state: unknown, viewUid?: string) => {
|
|
18
|
+
if (!viewUid || !state || typeof state !== 'object') {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const stateValue = state as RouteTransientInputArgsState;
|
|
23
|
+
const values = (stateValue[ROUTE_TRANSIENT_INPUT_ARGS_KEY] || stateValue.usr?.[ROUTE_TRANSIENT_INPUT_ARGS_KEY])?.[
|
|
24
|
+
viewUid
|
|
25
|
+
];
|
|
26
|
+
return values && typeof values === 'object' ? values : {};
|
|
27
|
+
};
|