@nocobase/client-v2 2.2.0-alpha.1 → 2.2.0-alpha.3
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/PluginSettingsManager.d.ts +33 -0
- package/es/RouteRepository.d.ts +21 -6
- package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
- package/es/components/category-tabs/index.d.ts +9 -0
- package/es/components/form/JsonTextArea.d.ts +2 -1
- package/es/components/form/TypedVariableInput.d.ts +22 -4
- package/es/components/form/VariableJsonTextArea.d.ts +19 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
- package/es/components/form/filter/index.d.ts +2 -0
- package/es/components/form/index.d.ts +1 -0
- package/es/components/index.d.ts +2 -0
- package/es/flow/actions/afterSuccess.d.ts +8 -1
- package/es/flow/actions/index.d.ts +1 -1
- 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/resolveAdminRouteRuntimeTarget.d.ts +6 -0
- package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
- package/es/flow/components/FieldAssignValueInput.d.ts +2 -0
- package/es/flow/index.d.ts +1 -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/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/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 +2 -1
- package/es/index.mjs +233 -137
- package/lib/index.js +234 -138
- package/package.json +7 -7
- package/src/PluginSettingsManager.ts +53 -0
- package/src/RouteRepository.ts +126 -24
- package/src/__tests__/PluginSettingsManager.test.ts +13 -0
- package/src/__tests__/RouteRepository.test.ts +216 -0
- package/src/__tests__/browserChecker.test.ts +61 -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/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/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 +21 -11
- package/src/components/form/TypedVariableInput.tsx +416 -93
- package/src/components/form/VariableJsonTextArea.tsx +175 -0
- package/src/components/form/__tests__/JsonTextArea.test.tsx +43 -0
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +268 -9
- package/src/components/form/__tests__/VariableJsonTextArea.test.tsx +86 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
- package/src/components/form/filter/index.ts +2 -0
- package/src/components/form/index.tsx +1 -0
- package/src/components/index.ts +2 -0
- package/src/flow/__tests__/FlowRoute.test.tsx +443 -5
- 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 +58 -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__/openView.defineProps.route.test.tsx +104 -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 +10 -0
- 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/openView.tsx +38 -4
- package/src/flow/actions/runjs.tsx +2 -14
- package/src/flow/actions/validation.tsx +62 -30
- package/src/flow/admin-shell/BaseLayoutModel.tsx +25 -3
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +5 -2
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +13 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +34 -10
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +310 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +44 -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/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 +82 -0
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +166 -2
- 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/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 +10 -5
- package/src/flow/components/FlowRoute.tsx +56 -11
- 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__/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 +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 +12 -1
- package/src/flow/models/base/ActionModelCore.tsx +6 -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 +31 -3
- package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +77 -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/__tests__/FormBlockModel.test.tsx +17 -0
- 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 +36 -13
- package/src/flow/models/blocks/table/TableBlockModel.tsx +38 -17
- package/src/flow/models/blocks/table/TableColumnModel.tsx +36 -3
- 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 +159 -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 +29 -6
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +16 -4
- 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 +49 -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 +100 -0
- package/src/flow/models/topbar/TopbarActionModel.tsx +93 -10
- package/src/flow/resolveViewParamsToViewList.tsx +11 -3
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +258 -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 +8 -1
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
- package/src/nocobase-buildin-plugin/index.tsx +44 -14
- 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
|
@@ -10,13 +10,15 @@
|
|
|
10
10
|
import { CloseCircleFilled } from '@ant-design/icons';
|
|
11
11
|
import {
|
|
12
12
|
buildContextSelectorItems,
|
|
13
|
+
loadMetaTreeChildren,
|
|
13
14
|
useFlowContext,
|
|
14
15
|
type ContextSelectorItem,
|
|
15
16
|
type MetaTreeNode,
|
|
16
17
|
} from '@nocobase/flow-engine';
|
|
17
18
|
import { Button, Cascader, DatePicker, Input, InputNumber, Select, Space, Tag, theme, type CascaderProps } from 'antd';
|
|
18
19
|
import dayjs from 'dayjs';
|
|
19
|
-
import React, { useCallback, useMemo } from 'react';
|
|
20
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
21
|
+
import { css } from '@emotion/css';
|
|
20
22
|
import {
|
|
21
23
|
makeFormatVariablePath,
|
|
22
24
|
makeParseVariablePath,
|
|
@@ -25,11 +27,11 @@ import {
|
|
|
25
27
|
} from './VariableInput';
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
|
-
* Constant types this input can edit.
|
|
29
|
-
* `useTypedConstant`
|
|
30
|
-
*
|
|
30
|
+
* Constant types this input can edit. Matches v1 `Variable.Input`
|
|
31
|
+
* `useTypedConstant` minus `'null'` (handled by the dedicated `nullable` prop).
|
|
32
|
+
* `'object'` renders an inline JSON editor (textarea).
|
|
31
33
|
*/
|
|
32
|
-
export type TypedConstantType = 'string' | 'number' | 'boolean' | 'date';
|
|
34
|
+
export type TypedConstantType = 'string' | 'number' | 'boolean' | 'date' | 'object';
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
37
|
* One allowed constant type. Either a bare type name (`'number'`) or a
|
|
@@ -57,16 +59,34 @@ export interface TypedVariableInputProps {
|
|
|
57
59
|
* Restrict the variable picker to specific top-level meta-tree namespaces
|
|
58
60
|
* (e.g. `['$env']`). When omitted, every registered top-level property is
|
|
59
61
|
* exposed — matching `VariableInput`'s default behaviour.
|
|
62
|
+
*
|
|
63
|
+
* Ignored when `metaTree` is supplied (an explicit tree wins).
|
|
60
64
|
*/
|
|
61
65
|
namespaces?: string[];
|
|
62
66
|
/** Additional leaves appended to the picker after the namespace-filtered nodes. */
|
|
63
67
|
extraNodes?: MetaTreeNode[];
|
|
68
|
+
/**
|
|
69
|
+
* Provide the variable tree explicitly instead of reading the global
|
|
70
|
+
* FlowContext meta tree. When set, `namespaces`/`extraNodes` are ignored and
|
|
71
|
+
* this tree is used verbatim — use for context-scoped variable sources that
|
|
72
|
+
* are not part of the global registry (e.g. a workflow node's upstream
|
|
73
|
+
* outputs). Lazy `children` thunks are resolved on demand as the user
|
|
74
|
+
* expands the cascader.
|
|
75
|
+
*/
|
|
76
|
+
metaTree?: MetaTreeNode[];
|
|
64
77
|
/**
|
|
65
78
|
* When true (default), the switcher exposes a `Null` option that resets the
|
|
66
79
|
* value to `null`. When false, the value is constrained to one of the
|
|
67
80
|
* allowed types or a variable reference.
|
|
68
81
|
*/
|
|
69
82
|
nullable?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Opt-in: when the incoming `value` is `undefined`, initialize the editor to
|
|
85
|
+
* the first allowed constant type instead of rendering the null-mode
|
|
86
|
+
* placeholder. `null` still keeps its explicit null semantics; only
|
|
87
|
+
* `undefined` triggers this path.
|
|
88
|
+
*/
|
|
89
|
+
defaultToFirstConstantTypeWhenUndefined?: boolean;
|
|
70
90
|
/** Variable-token delimiters. Default `['{{', '}}']` — see `VariableInput`. */
|
|
71
91
|
delimiters?: VariableDelimiters;
|
|
72
92
|
disabled?: boolean;
|
|
@@ -82,6 +102,7 @@ const TYPE_LABEL_KEYS: Record<TypedConstantType, string> = {
|
|
|
82
102
|
number: 'Number',
|
|
83
103
|
boolean: 'Boolean',
|
|
84
104
|
date: 'Date',
|
|
105
|
+
object: 'JSON',
|
|
85
106
|
};
|
|
86
107
|
|
|
87
108
|
type NormalizedType = { type: TypedConstantType; props: Record<string, unknown> };
|
|
@@ -104,6 +125,8 @@ function defaultValueFor(type: TypedConstantType): unknown {
|
|
|
104
125
|
const now = new Date();
|
|
105
126
|
return new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
|
|
106
127
|
}
|
|
128
|
+
case 'object':
|
|
129
|
+
return {};
|
|
107
130
|
default:
|
|
108
131
|
return null;
|
|
109
132
|
}
|
|
@@ -121,6 +144,7 @@ function detectMode(value: unknown, parseVariablePath: (v?: string) => string[]
|
|
|
121
144
|
if (typeof value === 'number') return { mode: 'number' };
|
|
122
145
|
if (typeof value === 'boolean') return { mode: 'boolean' };
|
|
123
146
|
if (value instanceof Date) return { mode: 'date' };
|
|
147
|
+
if (typeof value === 'object') return { mode: 'object' };
|
|
124
148
|
return { mode: 'string' };
|
|
125
149
|
}
|
|
126
150
|
|
|
@@ -131,6 +155,7 @@ interface SwitcherOption {
|
|
|
131
155
|
value: string;
|
|
132
156
|
label: React.ReactNode;
|
|
133
157
|
isLeaf?: boolean;
|
|
158
|
+
loading?: boolean;
|
|
134
159
|
children?: SwitcherOption[];
|
|
135
160
|
meta?: MetaTreeNode;
|
|
136
161
|
paths?: string[];
|
|
@@ -175,9 +200,10 @@ function renderConstantEditor(
|
|
|
175
200
|
disabled?: boolean;
|
|
176
201
|
placeholder?: string;
|
|
177
202
|
t: (text: string) => string;
|
|
203
|
+
onJsonError?: (message: string | null) => void;
|
|
178
204
|
},
|
|
179
205
|
): React.ReactNode {
|
|
180
|
-
const { typedProps, disabled, placeholder, t } = options;
|
|
206
|
+
const { typedProps, disabled, placeholder, t, onJsonError } = options;
|
|
181
207
|
switch (type) {
|
|
182
208
|
case 'string':
|
|
183
209
|
return (
|
|
@@ -229,11 +255,126 @@ function renderConstantEditor(
|
|
|
229
255
|
/>
|
|
230
256
|
);
|
|
231
257
|
}
|
|
258
|
+
case 'object':
|
|
259
|
+
return (
|
|
260
|
+
<JsonConstantEditor
|
|
261
|
+
value={value}
|
|
262
|
+
onChange={onChange}
|
|
263
|
+
onError={onJsonError}
|
|
264
|
+
disabled={disabled}
|
|
265
|
+
typedProps={typedProps}
|
|
266
|
+
/>
|
|
267
|
+
);
|
|
232
268
|
default:
|
|
233
269
|
return null;
|
|
234
270
|
}
|
|
235
271
|
}
|
|
236
272
|
|
|
273
|
+
const jsonEditorClassName = css`
|
|
274
|
+
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
|
275
|
+
font-size: 80%;
|
|
276
|
+
`;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Inline JSON editor for the `'object'` constant type. Formily-free port of v1's
|
|
280
|
+
* `Json` input (which used a Formily field for error feedback): keeps the raw
|
|
281
|
+
* text as local draft state, parses on blur, and writes the parsed object up via
|
|
282
|
+
* `onChange`. A parse error is reported up through `onError` (the raw
|
|
283
|
+
* `JSON.parse` message, matching v1) so the parent can render it on its own row
|
|
284
|
+
* below the input — keeping the textarea + switcher button row intact.
|
|
285
|
+
*/
|
|
286
|
+
function JsonConstantEditor({
|
|
287
|
+
value,
|
|
288
|
+
onChange,
|
|
289
|
+
onError,
|
|
290
|
+
disabled,
|
|
291
|
+
typedProps,
|
|
292
|
+
}: {
|
|
293
|
+
value: unknown;
|
|
294
|
+
onChange?: (next: unknown) => void;
|
|
295
|
+
onError?: (message: string | null) => void;
|
|
296
|
+
disabled?: boolean;
|
|
297
|
+
typedProps: Record<string, unknown>;
|
|
298
|
+
}) {
|
|
299
|
+
const stringify = useCallback((v: unknown) => {
|
|
300
|
+
if (v == null) return '';
|
|
301
|
+
if (typeof v === 'string') return v;
|
|
302
|
+
try {
|
|
303
|
+
return JSON.stringify(v, null, 2);
|
|
304
|
+
} catch {
|
|
305
|
+
return '';
|
|
306
|
+
}
|
|
307
|
+
}, []);
|
|
308
|
+
|
|
309
|
+
const [text, setText] = useState<string>(() => stringify(value));
|
|
310
|
+
const [hasError, setHasError] = useState(false);
|
|
311
|
+
|
|
312
|
+
// Re-sync the draft when the external value changes (e.g. switching type).
|
|
313
|
+
useEffect(() => {
|
|
314
|
+
setText(stringify(value));
|
|
315
|
+
setHasError(false);
|
|
316
|
+
onError?.(null);
|
|
317
|
+
// `onError` intentionally omitted — only resync on external value change.
|
|
318
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
319
|
+
}, [value, stringify]);
|
|
320
|
+
|
|
321
|
+
// Validate as the user types (live red border + error row), mirroring v1's `Json` which calls `setFeedback` on every
|
|
322
|
+
// change — not just on blur.
|
|
323
|
+
const handleChange = useCallback(
|
|
324
|
+
(raw: string) => {
|
|
325
|
+
setText(raw);
|
|
326
|
+
const trimmed = raw.trim();
|
|
327
|
+
if (trimmed === '') {
|
|
328
|
+
setHasError(false);
|
|
329
|
+
onError?.(null);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
try {
|
|
333
|
+
JSON.parse(trimmed);
|
|
334
|
+
setHasError(false);
|
|
335
|
+
onError?.(null);
|
|
336
|
+
} catch (err) {
|
|
337
|
+
setHasError(true);
|
|
338
|
+
onError?.((err as Error).message);
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
[onError],
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
// Commit the parsed object up on blur (v1 emits the value on blur). A still-invalid value keeps its error and is not
|
|
345
|
+
// emitted.
|
|
346
|
+
const commit = useCallback(
|
|
347
|
+
(raw: string) => {
|
|
348
|
+
const trimmed = raw.trim();
|
|
349
|
+
if (trimmed === '') {
|
|
350
|
+
onChange?.(null);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
onChange?.(JSON.parse(trimmed));
|
|
355
|
+
} catch {
|
|
356
|
+
/* error already shown live via handleChange */
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
[onChange],
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
return (
|
|
363
|
+
// No `autoSize` — it would disable the resize grip. Default to 2 rows (mirrors v1's `Json`) and let the user
|
|
364
|
+
// drag-resize from the corner.
|
|
365
|
+
<Input.TextArea
|
|
366
|
+
className={jsonEditorClassName}
|
|
367
|
+
value={text}
|
|
368
|
+
onChange={(ev) => handleChange(ev.target.value)}
|
|
369
|
+
onBlur={(ev) => commit(ev.target.value)}
|
|
370
|
+
disabled={disabled}
|
|
371
|
+
rows={2}
|
|
372
|
+
status={hasError ? 'error' : undefined}
|
|
373
|
+
{...typedProps}
|
|
374
|
+
/>
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
|
|
237
378
|
/**
|
|
238
379
|
* Constant-or-variable input. Port of v1 `Variable.Input` typed-constant
|
|
239
380
|
* Cascader pattern (the `[Null | Constant<type> | Variable<…namespaces>]`
|
|
@@ -255,7 +396,9 @@ export function TypedVariableInput(props: TypedVariableInputProps) {
|
|
|
255
396
|
types = DEFAULT_TYPES,
|
|
256
397
|
namespaces,
|
|
257
398
|
extraNodes,
|
|
399
|
+
metaTree: metaTreeProp,
|
|
258
400
|
nullable = true,
|
|
401
|
+
defaultToFirstConstantTypeWhenUndefined = true,
|
|
259
402
|
delimiters,
|
|
260
403
|
disabled,
|
|
261
404
|
placeholder,
|
|
@@ -266,16 +409,77 @@ export function TypedVariableInput(props: TypedVariableInputProps) {
|
|
|
266
409
|
const t = useCallback((text: string): string => (typeof ctx?.t === 'function' ? ctx.t(text) : text), [ctx]);
|
|
267
410
|
const { token } = theme.useToken();
|
|
268
411
|
|
|
269
|
-
|
|
412
|
+
// An explicit `metaTree` wins over the global FlowContext tree. The hook is still called unconditionally (Rules of
|
|
413
|
+
// Hooks); its result is simply unused when a tree is injected.
|
|
414
|
+
const filteredMetaTree = useFilteredMetaTree({ namespaces, extraNodes });
|
|
415
|
+
const metaTree = metaTreeProp ?? filteredMetaTree;
|
|
270
416
|
|
|
271
417
|
const parseVariablePath = useMemo(() => makeParseVariablePath(delimiters), [delimiters]);
|
|
272
418
|
const formatVariablePath = useMemo(() => makeFormatVariablePath(delimiters), [delimiters]);
|
|
273
419
|
|
|
274
420
|
const normalizedTypes = useMemo(() => normalizeTypes(types), [types]);
|
|
275
|
-
const
|
|
276
|
-
|
|
421
|
+
const defaultedValue = useMemo(() => {
|
|
422
|
+
if (!defaultToFirstConstantTypeWhenUndefined || value !== undefined) {
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
const firstType = normalizedTypes[0];
|
|
426
|
+
return firstType ? defaultValueFor(firstType.type) : undefined;
|
|
427
|
+
}, [defaultToFirstConstantTypeWhenUndefined, normalizedTypes, value]);
|
|
428
|
+
const effectiveValue = value === undefined && defaultedValue !== undefined ? defaultedValue : value;
|
|
429
|
+
const detected = useMemo(() => detectMode(effectiveValue, parseVariablePath), [effectiveValue, parseVariablePath]);
|
|
430
|
+
|
|
431
|
+
useEffect(() => {
|
|
432
|
+
if (value === undefined && defaultedValue !== undefined) {
|
|
433
|
+
onChange?.(defaultedValue);
|
|
434
|
+
}
|
|
435
|
+
}, [defaultedValue, onChange, value]);
|
|
436
|
+
|
|
437
|
+
// rc-cascader caches its options by *reference* (useEntities), so lazily filling a node's children in place is
|
|
438
|
+
// invisible to it. We mirror `FlowContextSelector`: lazy `loadData` mutates the **meta tree** in place, bumps
|
|
439
|
+
// `updateFlag`, and the options are rebuilt from scratch (fresh references) on every bump — forcing rc-cascader to
|
|
440
|
+
// re-index the new column.
|
|
441
|
+
const [updateFlag, setUpdateFlag] = useState(0);
|
|
442
|
+
const triggerUpdate = useCallback(() => setUpdateFlag((prev) => prev + 1), []);
|
|
443
|
+
|
|
444
|
+
const loadData = useCallback(
|
|
445
|
+
(selectedOptions: SwitcherOption[]) => {
|
|
446
|
+
const target = selectedOptions[selectedOptions.length - 1];
|
|
447
|
+
// Only variable nodes lazy-load; the Null / Constant switcher entries never do.
|
|
448
|
+
if (!target || target.value === NULL_KEY || target.value === CONST_KEY) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const meta = target.meta;
|
|
452
|
+
if (!meta) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
// Already-resolved children (array): nothing to fetch.
|
|
456
|
+
if (Array.isArray(meta.children)) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (typeof meta.children !== 'function') {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
target.loading = true;
|
|
463
|
+
triggerUpdate();
|
|
464
|
+
// `loadMetaTreeChildren` already swallows its own errors (returns []), so a bare chain is safe; `return`
|
|
465
|
+
// satisfies the promise/catch-or-return rule.
|
|
466
|
+
return loadMetaTreeChildren(meta)
|
|
467
|
+
.then((childMetas) => {
|
|
468
|
+
// Cache resolved children on the meta node; the options tree is then rebuilt from the mutated meta tree on
|
|
469
|
+
// the next `updateFlag` bump.
|
|
470
|
+
meta.children = childMetas;
|
|
471
|
+
})
|
|
472
|
+
.finally(() => {
|
|
473
|
+
target.loading = false;
|
|
474
|
+
triggerUpdate();
|
|
475
|
+
});
|
|
476
|
+
},
|
|
477
|
+
[triggerUpdate],
|
|
478
|
+
);
|
|
277
479
|
|
|
278
480
|
const switcherOptions = useMemo<SwitcherOption[]>(() => {
|
|
481
|
+
// `updateFlag` is read so this recomputes (with fresh option references) after a lazy load mutates the meta tree.
|
|
482
|
+
void updateFlag;
|
|
279
483
|
const items: SwitcherOption[] = [];
|
|
280
484
|
if (nullable) {
|
|
281
485
|
items.push({ value: NULL_KEY, label: t('Null'), isLeaf: true });
|
|
@@ -294,9 +498,9 @@ export function TypedVariableInput(props: TypedVariableInputProps) {
|
|
|
294
498
|
})),
|
|
295
499
|
});
|
|
296
500
|
}
|
|
297
|
-
items.push(...
|
|
501
|
+
items.push(...buildContextSelectorItems(metaTree).map(fromContextItem));
|
|
298
502
|
return items;
|
|
299
|
-
}, [nullable, normalizedTypes,
|
|
503
|
+
}, [nullable, normalizedTypes, metaTree, updateFlag, t]);
|
|
300
504
|
|
|
301
505
|
const onSwitcherChange = useCallback<NonNullable<CascaderProps<SwitcherOption>['onChange']>>(
|
|
302
506
|
(path, selectedOptions) => {
|
|
@@ -326,17 +530,19 @@ export function TypedVariableInput(props: TypedVariableInputProps) {
|
|
|
326
530
|
);
|
|
327
531
|
|
|
328
532
|
const onClearVariable = useCallback(() => {
|
|
533
|
+
const first = normalizedTypes[0];
|
|
534
|
+
if (first) {
|
|
535
|
+
onChange?.(defaultValueFor(first.type));
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
329
538
|
if (nullable) {
|
|
330
539
|
onChange?.(null);
|
|
331
|
-
return;
|
|
332
540
|
}
|
|
333
|
-
const first = normalizedTypes[0];
|
|
334
|
-
if (first) onChange?.(defaultValueFor(first.type));
|
|
335
541
|
}, [nullable, normalizedTypes, onChange]);
|
|
336
542
|
|
|
337
543
|
const constantTypeForRendering: TypedConstantType = useMemo(() => {
|
|
338
544
|
const m = detected.mode;
|
|
339
|
-
if (m === 'string' || m === 'number' || m === 'boolean' || m === 'date') return m;
|
|
545
|
+
if (m === 'string' || m === 'number' || m === 'boolean' || m === 'date' || m === 'object') return m;
|
|
340
546
|
return normalizedTypes[0]?.type ?? 'string';
|
|
341
547
|
}, [detected.mode, normalizedTypes]);
|
|
342
548
|
|
|
@@ -348,93 +554,210 @@ export function TypedVariableInput(props: TypedVariableInputProps) {
|
|
|
348
554
|
const isVariable = detected.mode === 'variable';
|
|
349
555
|
const isNull = detected.mode === 'null';
|
|
350
556
|
|
|
351
|
-
const variableLabels = useMemo(
|
|
352
|
-
|
|
353
|
-
|
|
557
|
+
const variableLabels = useMemo(() => {
|
|
558
|
+
// `updateFlag` is read so this recomputes after the preload effect below resolves a lazy level in the tree (same
|
|
559
|
+
// pattern as `switcherOptions`).
|
|
560
|
+
void updateFlag;
|
|
561
|
+
return isVariable && detected.variablePath ? resolveVariableLabels(detected.variablePath, metaTree) : [];
|
|
562
|
+
}, [isVariable, detected.variablePath, metaTree, updateFlag]);
|
|
563
|
+
|
|
564
|
+
const switcherValue = useMemo(() => {
|
|
565
|
+
if (isVariable && detected.variablePath?.length) {
|
|
566
|
+
return detected.variablePath;
|
|
567
|
+
}
|
|
568
|
+
if (isNull) {
|
|
569
|
+
return [NULL_KEY];
|
|
570
|
+
}
|
|
571
|
+
return [CONST_KEY, constantTypeForRendering];
|
|
572
|
+
}, [constantTypeForRendering, detected.variablePath, isNull, isVariable]);
|
|
573
|
+
|
|
574
|
+
// Preload a saved variable's label path across lazy levels. `resolveVariableLabels` can only read already-loaded
|
|
575
|
+
// `children`; when a saved reference points below a node whose children are still a lazy thunk (e.g. a relation field
|
|
576
|
+
// that hasn't been expanded), the deep segments render as raw names. Walk the saved path on mount / value change,
|
|
577
|
+
// resolving each lazy level in place (then bump `updateFlag` so the labels recompute). Mirrors v1 `Variable.Input`'s
|
|
578
|
+
// preload effect.
|
|
579
|
+
useEffect(() => {
|
|
580
|
+
if (!isVariable || !detected.variablePath?.length) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
let cancelled = false;
|
|
584
|
+
const run = async () => {
|
|
585
|
+
let nodes: MetaTreeNode[] | undefined = metaTree;
|
|
586
|
+
let didLoad = false;
|
|
587
|
+
for (const segment of detected.variablePath as string[]) {
|
|
588
|
+
if (!nodes) {
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
const matched: MetaTreeNode | undefined = nodes.find((node) => node.name === segment);
|
|
592
|
+
if (!matched) {
|
|
593
|
+
break;
|
|
594
|
+
}
|
|
595
|
+
if (typeof matched.children === 'function') {
|
|
596
|
+
const resolved = await loadMetaTreeChildren(matched);
|
|
597
|
+
if (cancelled) {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
matched.children = resolved;
|
|
601
|
+
didLoad = true;
|
|
602
|
+
}
|
|
603
|
+
nodes = Array.isArray(matched.children) ? matched.children : undefined;
|
|
604
|
+
}
|
|
605
|
+
if (didLoad && !cancelled) {
|
|
606
|
+
triggerUpdate();
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
run();
|
|
610
|
+
return () => {
|
|
611
|
+
cancelled = true;
|
|
612
|
+
};
|
|
613
|
+
// `metaTree` identity is stable per structural change (see consumers); re-run when the saved path or the tree
|
|
614
|
+
// changes.
|
|
615
|
+
}, [isVariable, detected.variablePath, metaTree, triggerUpdate]);
|
|
616
|
+
|
|
617
|
+
// JSON parse error from the object editor, rendered on its own row below the input (not squeezed into the compact
|
|
618
|
+
// row). Cleared whenever the value is no longer an object literal.
|
|
619
|
+
const [jsonError, setJsonError] = useState<string | null>(null);
|
|
620
|
+
useEffect(() => {
|
|
621
|
+
if (constantTypeForRendering !== 'object') setJsonError(null);
|
|
622
|
+
}, [constantTypeForRendering]);
|
|
623
|
+
|
|
624
|
+
const variableValueClassName = useMemo(
|
|
625
|
+
() => css`
|
|
626
|
+
&:hover .clear-button,
|
|
627
|
+
&:focus-within .clear-button {
|
|
628
|
+
visibility: visible;
|
|
629
|
+
pointer-events: auto;
|
|
630
|
+
opacity: 1;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.clear-button {
|
|
634
|
+
display: inline-flex;
|
|
635
|
+
align-items: center;
|
|
636
|
+
justify-content: center;
|
|
637
|
+
width: ${token.fontSizeIcon}px;
|
|
638
|
+
height: ${token.fontSizeIcon}px;
|
|
639
|
+
padding: 0;
|
|
640
|
+
color: ${token.colorTextQuaternary};
|
|
641
|
+
background: transparent;
|
|
642
|
+
cursor: pointer;
|
|
643
|
+
visibility: hidden;
|
|
644
|
+
pointer-events: none;
|
|
645
|
+
opacity: 0;
|
|
646
|
+
transition:
|
|
647
|
+
visibility ${token.motionDurationMid} ease,
|
|
648
|
+
color ${token.motionDurationMid} ease,
|
|
649
|
+
opacity ${token.motionDurationSlow} ease;
|
|
650
|
+
|
|
651
|
+
&:hover {
|
|
652
|
+
color: ${token.colorTextTertiary};
|
|
653
|
+
background: transparent;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
`,
|
|
657
|
+
[token],
|
|
354
658
|
);
|
|
355
659
|
|
|
356
660
|
return (
|
|
357
|
-
<
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
border: `1px solid ${token.colorBorder}`,
|
|
370
|
-
borderRadius: token.borderRadius,
|
|
371
|
-
borderTopRightRadius: 0,
|
|
372
|
-
borderBottomRightRadius: 0,
|
|
373
|
-
background: disabled ? token.colorBgContainerDisabled : token.colorBgContainer,
|
|
374
|
-
overflow: 'hidden',
|
|
375
|
-
}}
|
|
376
|
-
>
|
|
377
|
-
<Tag
|
|
378
|
-
color="blue"
|
|
661
|
+
<div style={{ width: '100%' }}>
|
|
662
|
+
{/* Default `Space.Compact` (align-items: stretch) so the switcher button
|
|
663
|
+
grows to the value component's height — its `height: auto` (below) lets
|
|
664
|
+
a multi-line value (the JSON textarea) stretch the button to match,
|
|
665
|
+
joined like v1 (which sets `.ant-btn { height: auto }` likewise). */}
|
|
666
|
+
<Space.Compact style={{ display: 'flex', width: '100%', ...style }} className={className}>
|
|
667
|
+
<div style={{ flex: 1, minWidth: 0, overflow: 'hidden' }}>
|
|
668
|
+
{isVariable ? (
|
|
669
|
+
<div
|
|
670
|
+
className={variableValueClassName}
|
|
671
|
+
role="button"
|
|
672
|
+
aria-label="variable-tag"
|
|
379
673
|
style={{
|
|
380
|
-
|
|
381
|
-
|
|
674
|
+
display: 'flex',
|
|
675
|
+
alignItems: 'center',
|
|
676
|
+
gap: token.marginXXS,
|
|
677
|
+
padding: `0 ${token.paddingSM}px`,
|
|
678
|
+
minHeight: token.controlHeight,
|
|
679
|
+
border: `1px solid ${token.colorBorder}`,
|
|
680
|
+
borderRadius: token.borderRadius,
|
|
681
|
+
borderTopRightRadius: 0,
|
|
682
|
+
borderBottomRightRadius: 0,
|
|
683
|
+
background: disabled ? token.colorBgContainerDisabled : token.colorBgContainer,
|
|
382
684
|
overflow: 'hidden',
|
|
383
|
-
textOverflow: 'ellipsis',
|
|
384
|
-
whiteSpace: 'nowrap',
|
|
385
685
|
}}
|
|
386
686
|
>
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
687
|
+
<Tag
|
|
688
|
+
color="blue"
|
|
689
|
+
style={{
|
|
690
|
+
marginInlineEnd: 0,
|
|
691
|
+
maxWidth: '100%',
|
|
692
|
+
overflow: 'hidden',
|
|
693
|
+
textOverflow: 'ellipsis',
|
|
694
|
+
whiteSpace: 'nowrap',
|
|
695
|
+
}}
|
|
696
|
+
>
|
|
697
|
+
{variableLabels.map((label, index) => (
|
|
698
|
+
<React.Fragment key={`${label}-${index}`}>
|
|
699
|
+
{index ? ' / ' : ''}
|
|
700
|
+
{label}
|
|
701
|
+
</React.Fragment>
|
|
702
|
+
))}
|
|
703
|
+
</Tag>
|
|
704
|
+
{!disabled ? (
|
|
705
|
+
<Button
|
|
706
|
+
type="text"
|
|
707
|
+
size="small"
|
|
708
|
+
className="clear-button"
|
|
709
|
+
aria-label="icon-close"
|
|
710
|
+
onClick={onClearVariable}
|
|
711
|
+
icon={<CloseCircleFilled />}
|
|
712
|
+
/>
|
|
713
|
+
) : null}
|
|
714
|
+
</div>
|
|
715
|
+
) : isNull ? (
|
|
716
|
+
// v1 used the `placeholder` slot (not `value`) so the antd default placeholder colour applies — keeps the
|
|
717
|
+
// field looking visibly empty/inactive rather than holding a real text value.
|
|
718
|
+
<Input placeholder={`<${t('Null')}>`} readOnly disabled={disabled} style={{ width: '100%' }} />
|
|
719
|
+
) : (
|
|
720
|
+
renderConstantEditor(constantTypeForRendering, effectiveValue, onChange, {
|
|
721
|
+
typedProps,
|
|
722
|
+
disabled,
|
|
723
|
+
placeholder,
|
|
724
|
+
t,
|
|
725
|
+
onJsonError: setJsonError,
|
|
726
|
+
})
|
|
727
|
+
)}
|
|
728
|
+
</div>
|
|
729
|
+
<Cascader<SwitcherOption>
|
|
730
|
+
options={switcherOptions}
|
|
731
|
+
value={switcherValue}
|
|
732
|
+
onChange={onSwitcherChange}
|
|
733
|
+
loadData={loadData}
|
|
426
734
|
disabled={disabled}
|
|
427
|
-
|
|
428
|
-
style={{
|
|
429
|
-
flexShrink: 0,
|
|
430
|
-
fontStyle: 'italic',
|
|
431
|
-
fontFamily: '"New York", "Times New Roman", Times, serif',
|
|
432
|
-
}}
|
|
735
|
+
changeOnSelect
|
|
433
736
|
>
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
737
|
+
<Button
|
|
738
|
+
aria-label="variable-switcher"
|
|
739
|
+
disabled={disabled}
|
|
740
|
+
type={isVariable ? 'primary' : 'default'}
|
|
741
|
+
style={{
|
|
742
|
+
flexShrink: 0,
|
|
743
|
+
// `height: auto` (instead of antd's fixed control height) lets the button stretch to the value
|
|
744
|
+
// component's height under the compact row's default `align-items: stretch` — so it stays joined to a
|
|
745
|
+
// tall JSON textarea. Mirrors v1's `.ant-btn { height: auto }`.
|
|
746
|
+
height: 'auto',
|
|
747
|
+
fontStyle: 'italic',
|
|
748
|
+
fontFamily: '"New York", "Times New Roman", Times, serif',
|
|
749
|
+
}}
|
|
750
|
+
>
|
|
751
|
+
x
|
|
752
|
+
</Button>
|
|
753
|
+
</Cascader>
|
|
754
|
+
</Space.Compact>
|
|
755
|
+
{jsonError ? (
|
|
756
|
+
<div style={{ marginTop: token.marginXXS, color: token.colorError, fontSize: token.fontSizeSM }}>
|
|
757
|
+
{jsonError}
|
|
758
|
+
</div>
|
|
759
|
+
) : null}
|
|
760
|
+
</div>
|
|
438
761
|
);
|
|
439
762
|
}
|
|
440
763
|
|