@workbench-kit/shell-react 0.0.2-prototype.0.2.10
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/README.md +98 -0
- package/package.json +51 -0
- package/src/chat/ai-mock-proposals.ts +39 -0
- package/src/chat/command-input.ts +52 -0
- package/src/chat/command-policy.ts +54 -0
- package/src/chat/command-surface.tsx +155 -0
- package/src/chat/use-chat-command-proposals.ts +194 -0
- package/src/chat/view-data.ts +20 -0
- package/src/chat/view.tsx +220 -0
- package/src/commands/inspector-surface.tsx +46 -0
- package/src/commands/use-command-descriptors.ts +41 -0
- package/src/commands/use-context-key-revision.ts +18 -0
- package/src/commands/view-data.ts +17 -0
- package/src/commands/view.tsx +43 -0
- package/src/devtools/WorkbenchDevtoolsPanel.tsx +124 -0
- package/src/devtools/WorkbenchDevtoolsShell.tsx +17 -0
- package/src/devtools/index.ts +11 -0
- package/src/devtools/use-workbench-devtools-snapshot.ts +84 -0
- package/src/devtools/workbench-devtools-snapshot.ts +140 -0
- package/src/devtools/workbench-devtools.css +82 -0
- package/src/editor/area-dnd.ts +69 -0
- package/src/editor/area-model.ts +71 -0
- package/src/editor/area.css +454 -0
- package/src/editor/area.tsx +676 -0
- package/src/editor/host-surface.tsx +691 -0
- package/src/editor/markdown-document-view-data.ts +16 -0
- package/src/editor/pane-visibility.ts +130 -0
- package/src/editor/resource.ts +36 -0
- package/src/editor/state-storage.ts +182 -0
- package/src/editor/tab-context-menu.ts +118 -0
- package/src/editor/use-editor.ts +138 -0
- package/src/editor/view-providers.tsx +504 -0
- package/src/editor/workspace-file-availability.ts +15 -0
- package/src/editor/workspace-reconcile.tsx +31 -0
- package/src/explorer/context-menu.ts +114 -0
- package/src/explorer/create-command-workspace-explorer-port.ts +86 -0
- package/src/explorer/reveal.ts +112 -0
- package/src/explorer/search-view-data.ts +15 -0
- package/src/explorer/search-view.tsx +65 -0
- package/src/explorer/use-active-workspace-path.ts +15 -0
- package/src/explorer/view-data.ts +58 -0
- package/src/explorer/view.tsx +227 -0
- package/src/extensions/context-menu.ts +52 -0
- package/src/extensions/management-model.ts +313 -0
- package/src/extensions/use-extension-management.ts +241 -0
- package/src/extensions/view-data.ts +19 -0
- package/src/extensions/view.tsx +63 -0
- package/src/field-remap/chrome-labels.ts +74 -0
- package/src/field-remap/convert-note-editor.tsx +206 -0
- package/src/field-remap/convert-palette.tsx +126 -0
- package/src/field-remap/demo.tsx +105 -0
- package/src/field-remap/detail-panel.tsx +659 -0
- package/src/field-remap/editor-surface.tsx +36 -0
- package/src/field-remap/flow-adapter.ts +838 -0
- package/src/field-remap/flow-ops.ts +442 -0
- package/src/field-remap/flow.tsx +948 -0
- package/src/field-remap/graph.tsx +559 -0
- package/src/field-remap/index.ts +88 -0
- package/src/field-remap/io-class-browse.tsx +145 -0
- package/src/field-remap/jsonata-transform.ts +166 -0
- package/src/field-remap/panel.tsx +466 -0
- package/src/field-remap/samples.ts +507 -0
- package/src/field-remap/shape-io-editor.tsx +170 -0
- package/src/field-remap/table-mapping-adapter.ts +59 -0
- package/src/field-remap/transform-options-editor.tsx +312 -0
- package/src/field-remap/tree.tsx +404 -0
- package/src/field-remap/view-data.ts +16 -0
- package/src/field-remap/view.css +1367 -0
- package/src/field-remap/view.tsx +86 -0
- package/src/index.ts +294 -0
- package/src/jdw/document-view-data.ts +31 -0
- package/src/jdw/json-form-source-patch.ts +323 -0
- package/src/jdw/lab-view-data.ts +25 -0
- package/src/jdw/lab-view.css +21 -0
- package/src/jdw/lab-view.tsx +79 -0
- package/src/jdw/widget-form-view.tsx +68 -0
- package/src/jdw/widget-preview-view.tsx +54 -0
- package/src/management/keybinding-overrides-storage.ts +49 -0
- package/src/management/keybinding-settings.tsx +16 -0
- package/src/management/palette-commands.ts +38 -0
- package/src/management/preference-settings-storage.ts +50 -0
- package/src/management/settings-ids.ts +12 -0
- package/src/management/settings.tsx +96 -0
- package/src/management/use-command-management.ts +191 -0
- package/src/management/use-keybinding-management.ts +130 -0
- package/src/shell/model.tsx +149 -0
- package/src/shell/provider.tsx +606 -0
- package/src/shell/secondary-actions.tsx +59 -0
- package/src/shell/settings-constants.ts +9 -0
- package/src/shell/settings.tsx +599 -0
- package/src/shell/shell.tsx +680 -0
- package/src/shell/titlebar-layout-controls.tsx +4 -0
- package/src/shell/view-host.tsx +212 -0
- package/src/workbench/appearance-storage.ts +107 -0
- package/src/workbench/command-host.tsx +243 -0
- package/src/workbench/command-palette.ts +208 -0
- package/src/workbench/keybinding-bridge.ts +54 -0
- package/src/workbench/layout-storage.ts +134 -0
- package/src/workbench/profile-modal.tsx +118 -0
- package/src/workbench/shell-command-registration.ts +58 -0
- package/src/workbench/startup-gate.tsx +136 -0
- package/src/workbench/status-sections.ts +43 -0
- package/src/workbench/use-persisted-appearance.ts +33 -0
- package/src/workbench/user-commands.ts +46 -0
- package/src/workbench/workspace-view-state.ts +35 -0
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState, type JSX } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
applyMappingOperators,
|
|
4
|
+
convertToShape,
|
|
5
|
+
createBuiltinValueTransformRegistry,
|
|
6
|
+
defineConversion,
|
|
7
|
+
defineDataShape,
|
|
8
|
+
findParentChildMappingConflicts,
|
|
9
|
+
normalizeMappingOperators,
|
|
10
|
+
projectSourceFields,
|
|
11
|
+
projectTargetSlots,
|
|
12
|
+
pruneMappingEdgesForShapes,
|
|
13
|
+
sourceFieldsFromPlainObject,
|
|
14
|
+
targetSlotsFromPlainObject,
|
|
15
|
+
withConversionEdges,
|
|
16
|
+
type MappingEdge,
|
|
17
|
+
type MappingOperator,
|
|
18
|
+
type SourceField,
|
|
19
|
+
type TargetSlot,
|
|
20
|
+
type ValueTransformRegistry,
|
|
21
|
+
} from '@workbench-kit/field-remap';
|
|
22
|
+
|
|
23
|
+
import { FieldRemapFlowMapper, type FieldRemapFlowMapperProps } from './flow.js';
|
|
24
|
+
import {
|
|
25
|
+
FieldRemapIoClassBrowse,
|
|
26
|
+
resolveFieldRemapIoChrome,
|
|
27
|
+
type FieldRemapIoChrome,
|
|
28
|
+
} from './io-class-browse.js';
|
|
29
|
+
import {
|
|
30
|
+
getFieldRemapSample,
|
|
31
|
+
type FieldRemapSampleDefinition,
|
|
32
|
+
type FieldRemapSampleId,
|
|
33
|
+
} from './samples.js';
|
|
34
|
+
import { jsonataValueTransform } from './jsonata-transform.js';
|
|
35
|
+
import {
|
|
36
|
+
FieldRemapShapeIoEditor,
|
|
37
|
+
ingestSourceShape,
|
|
38
|
+
ingestTargetShape,
|
|
39
|
+
} from './shape-io-editor.js';
|
|
40
|
+
import './view.css';
|
|
41
|
+
|
|
42
|
+
export interface FieldRemapPanelProps {
|
|
43
|
+
/** Catalog sample id, or a full sample definition. Defaults to `nested-ab` labels/ids. */
|
|
44
|
+
readonly sample?: FieldRemapSampleId | FieldRemapSampleDefinition | undefined;
|
|
45
|
+
/** Optional host-owned transform registry (defaults to builtins + JSONata). */
|
|
46
|
+
readonly transforms?: ValueTransformRegistry | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* When true (default), show paste-JSON / type editors for host-owned shapes.
|
|
49
|
+
* Prefer {@link FieldRemapPanelProps.ioChrome} for browse-first hosts; when
|
|
50
|
+
* `ioChrome` is omitted, `true` → `edit` and `false` → `none`.
|
|
51
|
+
*/
|
|
52
|
+
readonly editableShapes?: boolean | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* I/O chrome mode. `browse` = read-only class/field tree; `edit` = shape IO editor;
|
|
55
|
+
* `none` = hide I/O chrome. Defaults from `editableShapes` when omitted.
|
|
56
|
+
*/
|
|
57
|
+
readonly ioChrome?: FieldRemapIoChrome | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* When `false` (default), Flow columns omit `hidden` fields/slots.
|
|
60
|
+
* Browse chrome respects the same flag (show Hidden badges when true).
|
|
61
|
+
*/
|
|
62
|
+
readonly includeHidden?: boolean | undefined;
|
|
63
|
+
readonly onIncludeHiddenChange?: ((next: boolean) => void) | undefined;
|
|
64
|
+
readonly className?: string | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Controlled mapping edges. When provided, the host is the source of truth;
|
|
67
|
+
* pair with `onEdgesChange` for connect/disconnect/transform edits.
|
|
68
|
+
*/
|
|
69
|
+
readonly edges?: readonly MappingEdge[] | undefined;
|
|
70
|
+
readonly onEdgesChange?: ((edges: readonly MappingEdge[]) => void) | undefined;
|
|
71
|
+
/** Optional controlled n→m operators (document v2). */
|
|
72
|
+
readonly operators?: readonly MappingOperator[] | undefined;
|
|
73
|
+
readonly onOperatorsChange?: ((operators: readonly MappingOperator[]) => void) | undefined;
|
|
74
|
+
/** Controlled source field tree (host-owned shapes). */
|
|
75
|
+
readonly sources?: readonly SourceField[] | undefined;
|
|
76
|
+
readonly onSourcesChange?: ((fields: readonly SourceField[]) => void) | undefined;
|
|
77
|
+
/** Controlled target slot tree (host-owned shapes). */
|
|
78
|
+
readonly targets?: readonly TargetSlot[] | undefined;
|
|
79
|
+
readonly onTargetsChange?: ((slots: readonly TargetSlot[]) => void) | undefined;
|
|
80
|
+
/** Preview input bag for the primary source shape. */
|
|
81
|
+
readonly sourceSample?: unknown;
|
|
82
|
+
/** Optional target shape sample JSON (shape editor seed; preview uses edges). */
|
|
83
|
+
readonly targetShape?: unknown;
|
|
84
|
+
/** Forwarded to {@link FieldRemapFlowMapper} (default true). */
|
|
85
|
+
readonly showMinimap?: boolean | undefined;
|
|
86
|
+
readonly onPaneContextMenu?: FieldRemapFlowMapperProps['onPaneContextMenu'];
|
|
87
|
+
readonly onNodeContextMenu?: FieldRemapFlowMapperProps['onNodeContextMenu'];
|
|
88
|
+
readonly onEdgeContextMenu?: FieldRemapFlowMapperProps['onEdgeContextMenu'];
|
|
89
|
+
readonly flowActionsRef?: FieldRemapFlowMapperProps['flowActionsRef'];
|
|
90
|
+
/** Forwarded to {@link FieldRemapFlowMapper} chrome label / `t()` injection. */
|
|
91
|
+
readonly labels?: FieldRemapFlowMapperProps['labels'];
|
|
92
|
+
readonly t?: FieldRemapFlowMapperProps['t'];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
type FieldRemapPreviewResult = {
|
|
96
|
+
readonly output: Record<string, unknown>;
|
|
97
|
+
readonly error?: string;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
function resolveSample(sample: FieldRemapPanelProps['sample']): FieldRemapSampleDefinition {
|
|
101
|
+
if (!sample) {
|
|
102
|
+
return getFieldRemapSample('nested-ab');
|
|
103
|
+
}
|
|
104
|
+
if (typeof sample === 'string') {
|
|
105
|
+
return getFieldRemapSample(sample);
|
|
106
|
+
}
|
|
107
|
+
return sample;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Self-contained field-remap workbench panel:
|
|
112
|
+
* schema columns A/B + optional convert wires (XYFlow) and `convertToShape` preview.
|
|
113
|
+
*
|
|
114
|
+
* Uncontrolled: pass `sample=` (Storybook / demos). Remount with `key={sampleId}` when
|
|
115
|
+
* switching catalog entries so edge state resets.
|
|
116
|
+
*
|
|
117
|
+
* Controlled: pass `edges` + `onEdgesChange` (and optionally shapes / operators) so an
|
|
118
|
+
* integrating host can persist bindings without forking panel state.
|
|
119
|
+
*/
|
|
120
|
+
export function FieldRemapPanel({
|
|
121
|
+
sample: sampleProp,
|
|
122
|
+
transforms: transformsProp,
|
|
123
|
+
editableShapes = true,
|
|
124
|
+
ioChrome: ioChromeProp,
|
|
125
|
+
includeHidden: includeHiddenProp,
|
|
126
|
+
onIncludeHiddenChange,
|
|
127
|
+
className,
|
|
128
|
+
edges: edgesProp,
|
|
129
|
+
onEdgesChange,
|
|
130
|
+
operators: operatorsProp,
|
|
131
|
+
onOperatorsChange,
|
|
132
|
+
sources: sourcesProp,
|
|
133
|
+
onSourcesChange,
|
|
134
|
+
targets: targetsProp,
|
|
135
|
+
onTargetsChange,
|
|
136
|
+
sourceSample: sourceSampleProp,
|
|
137
|
+
targetShape: targetShapeProp,
|
|
138
|
+
showMinimap,
|
|
139
|
+
onPaneContextMenu,
|
|
140
|
+
onNodeContextMenu,
|
|
141
|
+
onEdgeContextMenu,
|
|
142
|
+
flowActionsRef,
|
|
143
|
+
labels,
|
|
144
|
+
t,
|
|
145
|
+
}: FieldRemapPanelProps): JSX.Element {
|
|
146
|
+
const ioChrome = resolveFieldRemapIoChrome(ioChromeProp, editableShapes);
|
|
147
|
+
const [uncontrolledIncludeHidden, setUncontrolledIncludeHidden] = useState(false);
|
|
148
|
+
const includeHiddenControlled = includeHiddenProp !== undefined;
|
|
149
|
+
const includeHidden = includeHiddenControlled ? includeHiddenProp : uncontrolledIncludeHidden;
|
|
150
|
+
const setIncludeHidden = (next: boolean) => {
|
|
151
|
+
if (!includeHiddenControlled) {
|
|
152
|
+
setUncontrolledIncludeHidden(next);
|
|
153
|
+
}
|
|
154
|
+
onIncludeHiddenChange?.(next);
|
|
155
|
+
};
|
|
156
|
+
const sample = resolveSample(sampleProp);
|
|
157
|
+
const registry = useMemo(() => {
|
|
158
|
+
if (transformsProp) {
|
|
159
|
+
return transformsProp;
|
|
160
|
+
}
|
|
161
|
+
const next = createBuiltinValueTransformRegistry();
|
|
162
|
+
next.register(jsonataValueTransform);
|
|
163
|
+
return next;
|
|
164
|
+
}, [transformsProp]);
|
|
165
|
+
|
|
166
|
+
const edgesControlled = edgesProp !== undefined;
|
|
167
|
+
const operatorsControlled = operatorsProp !== undefined;
|
|
168
|
+
const sourcesControlled = sourcesProp !== undefined;
|
|
169
|
+
const targetsControlled = targetsProp !== undefined;
|
|
170
|
+
const sourceSampleControlled = sourceSampleProp !== undefined;
|
|
171
|
+
|
|
172
|
+
const [uncontrolledEdges, setUncontrolledEdges] = useState<readonly MappingEdge[]>(() => [
|
|
173
|
+
...(edgesProp ?? sample.edges),
|
|
174
|
+
]);
|
|
175
|
+
const [uncontrolledOperators, setUncontrolledOperators] = useState<readonly MappingOperator[]>(
|
|
176
|
+
() => [...(operatorsProp ?? sample.operators ?? [])],
|
|
177
|
+
);
|
|
178
|
+
const [result, setResult] = useState<FieldRemapPreviewResult>({ output: {} });
|
|
179
|
+
const [uncontrolledSourceSample, setUncontrolledSourceSample] = useState<unknown>(
|
|
180
|
+
() => sourceSampleProp ?? sample.source,
|
|
181
|
+
);
|
|
182
|
+
const [, setTargetSample] = useState<unknown>(() => targetShapeProp ?? sample.targetShape);
|
|
183
|
+
const [sourceJson, setSourceJson] = useState(() =>
|
|
184
|
+
JSON.stringify(sourceSampleProp ?? sample.source, null, 2),
|
|
185
|
+
);
|
|
186
|
+
const [targetJson, setTargetJson] = useState(() =>
|
|
187
|
+
JSON.stringify(targetShapeProp ?? sample.targetShape, null, 2),
|
|
188
|
+
);
|
|
189
|
+
const [uncontrolledSources, setUncontrolledSources] = useState<readonly SourceField[]>(() =>
|
|
190
|
+
sourcesProp
|
|
191
|
+
? [...sourcesProp]
|
|
192
|
+
: sourceFieldsFromPlainObject(sourceSampleProp ?? sample.source, {
|
|
193
|
+
idPrefix: sample.sourceIdPrefix,
|
|
194
|
+
}),
|
|
195
|
+
);
|
|
196
|
+
const [uncontrolledTargets, setUncontrolledTargets] = useState<readonly TargetSlot[]>(() =>
|
|
197
|
+
targetsProp
|
|
198
|
+
? [...targetsProp]
|
|
199
|
+
: targetSlotsFromPlainObject(targetShapeProp ?? sample.targetShape, {
|
|
200
|
+
idPrefix: sample.targetIdPrefix,
|
|
201
|
+
}),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
const edges = edgesControlled ? edgesProp : uncontrolledEdges;
|
|
205
|
+
const operators = operatorsControlled ? operatorsProp : uncontrolledOperators;
|
|
206
|
+
const sourceFields = sourcesControlled ? sourcesProp : uncontrolledSources;
|
|
207
|
+
const targetSlots = targetsControlled ? targetsProp : uncontrolledTargets;
|
|
208
|
+
const sourceSample = sourceSampleControlled ? sourceSampleProp : uncontrolledSourceSample;
|
|
209
|
+
|
|
210
|
+
const flowSources = useMemo(
|
|
211
|
+
() => projectSourceFields(sourceFields, { includeHidden }),
|
|
212
|
+
[includeHidden, sourceFields],
|
|
213
|
+
);
|
|
214
|
+
const flowTargets = useMemo(
|
|
215
|
+
() => projectTargetSlots(targetSlots, { includeHidden }),
|
|
216
|
+
[includeHidden, targetSlots],
|
|
217
|
+
);
|
|
218
|
+
const flowEdges = useMemo(
|
|
219
|
+
() => pruneMappingEdgesForShapes(edges, flowSources, flowTargets),
|
|
220
|
+
[edges, flowSources, flowTargets],
|
|
221
|
+
);
|
|
222
|
+
const commitFlowEdges = (next: readonly MappingEdge[]) => {
|
|
223
|
+
if (includeHidden) {
|
|
224
|
+
commitEdges(next);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const visibleIds = new Set(flowEdges.map((edge) => edge.id));
|
|
228
|
+
const preserved = edges.filter((edge) => !visibleIds.has(edge.id));
|
|
229
|
+
commitEdges([...preserved, ...next]);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const commitEdges = (next: readonly MappingEdge[]) => {
|
|
233
|
+
if (!edgesControlled) {
|
|
234
|
+
setUncontrolledEdges(next);
|
|
235
|
+
}
|
|
236
|
+
onEdgesChange?.(next);
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const commitOperators = (next: readonly MappingOperator[]) => {
|
|
240
|
+
if (!operatorsControlled) {
|
|
241
|
+
setUncontrolledOperators(next);
|
|
242
|
+
}
|
|
243
|
+
onOperatorsChange?.(next);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const commitSources = (next: readonly SourceField[]) => {
|
|
247
|
+
if (!sourcesControlled) {
|
|
248
|
+
setUncontrolledSources(next);
|
|
249
|
+
}
|
|
250
|
+
onSourcesChange?.(next);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const commitTargets = (next: readonly TargetSlot[]) => {
|
|
254
|
+
if (!targetsControlled) {
|
|
255
|
+
setUncontrolledTargets(next);
|
|
256
|
+
}
|
|
257
|
+
onTargetsChange?.(next);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const shapes = useMemo(
|
|
261
|
+
() => [
|
|
262
|
+
defineDataShape({
|
|
263
|
+
id: sample.sourceIdPrefix,
|
|
264
|
+
label: sample.sourceLabel,
|
|
265
|
+
role: 'source',
|
|
266
|
+
fields: sourceFields,
|
|
267
|
+
}),
|
|
268
|
+
defineDataShape({
|
|
269
|
+
id: sample.targetIdPrefix,
|
|
270
|
+
label: sample.targetLabel,
|
|
271
|
+
role: 'target',
|
|
272
|
+
fields: targetSlots,
|
|
273
|
+
}),
|
|
274
|
+
],
|
|
275
|
+
[sample, sourceFields, targetSlots],
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
const conflicts = useMemo(
|
|
279
|
+
() => findParentChildMappingConflicts(edges, sourceFields, targetSlots),
|
|
280
|
+
[edges, sourceFields, targetSlots],
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
useEffect(() => {
|
|
284
|
+
const controller = new AbortController();
|
|
285
|
+
const conversion = withConversionEdges(
|
|
286
|
+
defineConversion({
|
|
287
|
+
id: `${sample.sourceIdPrefix}→${sample.targetIdPrefix}`,
|
|
288
|
+
sourceShapeIds: [sample.sourceIdPrefix],
|
|
289
|
+
targetShapeId: sample.targetIdPrefix,
|
|
290
|
+
edges: [...sample.edges],
|
|
291
|
+
}),
|
|
292
|
+
edges,
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
void convertToShape({
|
|
296
|
+
conversion,
|
|
297
|
+
shapes,
|
|
298
|
+
inputs: { [sample.sourceIdPrefix]: sourceSample },
|
|
299
|
+
transforms: registry,
|
|
300
|
+
signal: controller.signal,
|
|
301
|
+
})
|
|
302
|
+
.then(async (next) => {
|
|
303
|
+
if (controller.signal.aborted) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const normalizedOps = normalizeMappingOperators(operators);
|
|
307
|
+
if (!normalizedOps?.length) {
|
|
308
|
+
setResult({ output: next.output });
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const merged = await applyMappingOperators({
|
|
312
|
+
operators: normalizedOps,
|
|
313
|
+
sources: sourceFields,
|
|
314
|
+
targets: targetSlots,
|
|
315
|
+
inputs: { [sample.sourceIdPrefix]: sourceSample },
|
|
316
|
+
transforms: registry,
|
|
317
|
+
output: next.output,
|
|
318
|
+
signal: controller.signal,
|
|
319
|
+
});
|
|
320
|
+
if (!controller.signal.aborted) {
|
|
321
|
+
setResult({ output: merged.output });
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
.catch((error: unknown) => {
|
|
325
|
+
if (controller.signal.aborted) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
setResult({
|
|
329
|
+
output: {},
|
|
330
|
+
error: error instanceof Error ? error.message : String(error),
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
return () => {
|
|
335
|
+
controller.abort();
|
|
336
|
+
};
|
|
337
|
+
}, [edges, operators, registry, sample, shapes, sourceFields, sourceSample, targetSlots]);
|
|
338
|
+
|
|
339
|
+
const applySourceShape = (parsed: unknown) => {
|
|
340
|
+
const ingested = ingestSourceShape(parsed, sample.sourceIdPrefix);
|
|
341
|
+
if (!sourceSampleControlled) {
|
|
342
|
+
setUncontrolledSourceSample(parsed);
|
|
343
|
+
}
|
|
344
|
+
setSourceJson(ingested.sampleJson);
|
|
345
|
+
commitSources(ingested.fields);
|
|
346
|
+
commitEdges(pruneMappingEdgesForShapes(edges, ingested.fields, targetSlots));
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
const applyTargetShape = (parsed: unknown) => {
|
|
350
|
+
const ingested = ingestTargetShape(parsed, sample.targetIdPrefix);
|
|
351
|
+
setTargetSample(parsed);
|
|
352
|
+
setTargetJson(ingested.sampleJson);
|
|
353
|
+
commitTargets(ingested.fields);
|
|
354
|
+
commitEdges(pruneMappingEdgesForShapes(edges, sourceFields, ingested.fields));
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
return (
|
|
358
|
+
<div
|
|
359
|
+
className={['workbench-field-remap-demo', className].filter(Boolean).join(' ')}
|
|
360
|
+
data-testid="field-remap-demo"
|
|
361
|
+
data-sample-id={sample.id}
|
|
362
|
+
data-edges-mode={edgesControlled ? 'controlled' : 'uncontrolled'}
|
|
363
|
+
>
|
|
364
|
+
<header className="workbench-field-remap-demo__header">
|
|
365
|
+
<h2 className="workbench-field-remap-demo__title">{sample.title}</h2>
|
|
366
|
+
<p className="workbench-field-remap-demo__intro">{sample.description}</p>
|
|
367
|
+
</header>
|
|
368
|
+
|
|
369
|
+
{ioChrome === 'edit' ? (
|
|
370
|
+
<div className="workbench-field-remap-demo__shapes" data-testid="field-remap-shapes">
|
|
371
|
+
<FieldRemapShapeIoEditor
|
|
372
|
+
role="source"
|
|
373
|
+
title={sample.sourceLabel}
|
|
374
|
+
idPrefix={sample.sourceIdPrefix}
|
|
375
|
+
sampleJson={sourceJson}
|
|
376
|
+
fields={sourceFields}
|
|
377
|
+
onSampleJsonChange={setSourceJson}
|
|
378
|
+
onApplySample={applySourceShape}
|
|
379
|
+
onFieldsChange={(next) => commitSources(next as readonly SourceField[])}
|
|
380
|
+
/>
|
|
381
|
+
<FieldRemapShapeIoEditor
|
|
382
|
+
role="target"
|
|
383
|
+
title={sample.targetLabel}
|
|
384
|
+
idPrefix={sample.targetIdPrefix}
|
|
385
|
+
sampleJson={targetJson}
|
|
386
|
+
fields={targetSlots}
|
|
387
|
+
onSampleJsonChange={setTargetJson}
|
|
388
|
+
onApplySample={applyTargetShape}
|
|
389
|
+
onFieldsChange={(next) => commitTargets(next as readonly TargetSlot[])}
|
|
390
|
+
/>
|
|
391
|
+
</div>
|
|
392
|
+
) : null}
|
|
393
|
+
|
|
394
|
+
{ioChrome === 'browse' ? (
|
|
395
|
+
<div
|
|
396
|
+
className="workbench-field-remap-demo__shapes"
|
|
397
|
+
data-testid="field-remap-io-browse-wrap"
|
|
398
|
+
>
|
|
399
|
+
<label className="workbench-field-remap-io-browse__toggle">
|
|
400
|
+
<input
|
|
401
|
+
checked={includeHidden}
|
|
402
|
+
onChange={(event) => setIncludeHidden(event.target.checked)}
|
|
403
|
+
type="checkbox"
|
|
404
|
+
/>
|
|
405
|
+
Show hidden fields
|
|
406
|
+
</label>
|
|
407
|
+
<FieldRemapIoClassBrowse
|
|
408
|
+
includeHidden={includeHidden}
|
|
409
|
+
sources={sourceFields}
|
|
410
|
+
sourcesTitle={sample.sourceLabel}
|
|
411
|
+
targets={targetSlots}
|
|
412
|
+
targetsTitle={sample.targetLabel}
|
|
413
|
+
/>
|
|
414
|
+
</div>
|
|
415
|
+
) : null}
|
|
416
|
+
|
|
417
|
+
<FieldRemapFlowMapper
|
|
418
|
+
sources={flowSources}
|
|
419
|
+
targets={flowTargets}
|
|
420
|
+
edges={flowEdges}
|
|
421
|
+
transforms={registry}
|
|
422
|
+
onEdgesChange={commitFlowEdges}
|
|
423
|
+
operators={operators}
|
|
424
|
+
onOperatorsChange={commitOperators}
|
|
425
|
+
sourceTitle={sample.sourceLabel}
|
|
426
|
+
targetTitle={sample.targetLabel}
|
|
427
|
+
showMinimap={showMinimap}
|
|
428
|
+
onPaneContextMenu={onPaneContextMenu}
|
|
429
|
+
onNodeContextMenu={onNodeContextMenu}
|
|
430
|
+
onEdgeContextMenu={onEdgeContextMenu}
|
|
431
|
+
flowActionsRef={flowActionsRef}
|
|
432
|
+
labels={labels}
|
|
433
|
+
t={t}
|
|
434
|
+
/>
|
|
435
|
+
|
|
436
|
+
{conflicts.length > 0 ? (
|
|
437
|
+
<p
|
|
438
|
+
className="workbench-field-remap-demo__warn"
|
|
439
|
+
role="status"
|
|
440
|
+
data-testid="field-remap-conflicts"
|
|
441
|
+
>
|
|
442
|
+
Warning: parent and child fields are both mapped (
|
|
443
|
+
{conflicts.map((item) => `${item.parentId} / ${item.childId}`).join('; ')}). Prefer one
|
|
444
|
+
level.
|
|
445
|
+
</p>
|
|
446
|
+
) : null}
|
|
447
|
+
|
|
448
|
+
{result.error ? (
|
|
449
|
+
<p className="workbench-field-remap-demo__error" role="alert">
|
|
450
|
+
{result.error}
|
|
451
|
+
</p>
|
|
452
|
+
) : null}
|
|
453
|
+
|
|
454
|
+
<div className="workbench-field-remap-demo__panes">
|
|
455
|
+
<section className="workbench-field-remap-demo__pane" aria-labelledby="field-remap-source">
|
|
456
|
+
<h3 id="field-remap-source">{sample.sourceLabel}</h3>
|
|
457
|
+
<pre data-testid="field-remap-input">{JSON.stringify(sourceSample, null, 2)}</pre>
|
|
458
|
+
</section>
|
|
459
|
+
<section className="workbench-field-remap-demo__pane" aria-labelledby="field-remap-target">
|
|
460
|
+
<h3 id="field-remap-target">{sample.targetLabel}</h3>
|
|
461
|
+
<pre data-testid="field-remap-result">{JSON.stringify(result.output, null, 2)}</pre>
|
|
462
|
+
</section>
|
|
463
|
+
</div>
|
|
464
|
+
</div>
|
|
465
|
+
);
|
|
466
|
+
}
|