@workbench-kit/shell-react 0.0.2-prototype.0.2.43 → 0.0.2-prototype.0.2.44
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 +39 -0
- package/package.json +10 -9
- package/src/editor/workspace-reconcile.tsx +12 -7
- package/src/field-remap/chrome-labels.ts +99 -0
- package/src/field-remap/convert-note-editor.tsx +115 -106
- package/src/field-remap/detail-panel.tsx +524 -456
- package/src/field-remap/document-io.tsx +299 -0
- package/src/field-remap/flow.tsx +188 -126
- package/src/field-remap/panel.tsx +60 -0
- package/src/field-remap/transform-options-editor.tsx +64 -48
- package/src/field-remap/view.css +46 -147
- package/src/keybinding-management-settings.ts +4 -0
- package/src/management/keybinding-settings-view.tsx +31 -0
- package/src/management/keybinding-settings.tsx +4 -21
- package/src/management/use-keybinding-management.ts +3 -3
- package/src/shell/provider.tsx +10 -1
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { useEffect, useId, useMemo, useRef, useState, type FormEvent, type JSX } from 'react';
|
|
2
|
+
import { Modal } from '@workbench-kit/react/modal';
|
|
3
|
+
import { Button, TextArea } from '@workbench-kit/react/primitives';
|
|
4
|
+
import { WorkbenchModalPortal } from '@workbench-kit/react/workbench/modal-portal';
|
|
5
|
+
import type { FieldRemapImportFailureCode } from '@workbench-kit/field-remap';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
resolveFieldRemapChromeLabels,
|
|
9
|
+
type FieldRemapChromeLabels,
|
|
10
|
+
type FieldRemapTranslate,
|
|
11
|
+
} from './chrome-labels.js';
|
|
12
|
+
|
|
13
|
+
export type FieldRemapDocumentImportActionResult =
|
|
14
|
+
| { readonly status: 'accepted' }
|
|
15
|
+
| {
|
|
16
|
+
readonly status: 'rejected';
|
|
17
|
+
readonly code: FieldRemapImportFailureCode;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
interface FieldRemapDocumentIoProps {
|
|
21
|
+
readonly getDocumentJson: () => string;
|
|
22
|
+
readonly importAvailable: boolean;
|
|
23
|
+
readonly labels?: Partial<FieldRemapChromeLabels> | undefined;
|
|
24
|
+
readonly t?: FieldRemapTranslate | undefined;
|
|
25
|
+
readonly onImportText: (text: string) => FieldRemapDocumentImportActionResult;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type DocumentIoStatus =
|
|
29
|
+
| { readonly kind: 'success'; readonly message: string }
|
|
30
|
+
| { readonly kind: 'error'; readonly message: string };
|
|
31
|
+
|
|
32
|
+
function importFailureMessage(
|
|
33
|
+
code: FieldRemapImportFailureCode,
|
|
34
|
+
labels: FieldRemapChromeLabels,
|
|
35
|
+
): string {
|
|
36
|
+
switch (code) {
|
|
37
|
+
case 'invalid-json':
|
|
38
|
+
return labels.documentImportInvalidJson ?? '';
|
|
39
|
+
case 'unsupported-version':
|
|
40
|
+
return labels.documentImportUnsupportedVersion ?? '';
|
|
41
|
+
case 'duplicate-id':
|
|
42
|
+
return labels.documentImportDuplicateId ?? '';
|
|
43
|
+
case 'incompatible-source':
|
|
44
|
+
return labels.documentImportIncompatibleSource ?? '';
|
|
45
|
+
case 'incompatible-target':
|
|
46
|
+
return labels.documentImportIncompatibleTarget ?? '';
|
|
47
|
+
case 'unavailable-transform':
|
|
48
|
+
return labels.documentImportUnavailableTransform ?? '';
|
|
49
|
+
case 'invalid-document':
|
|
50
|
+
return labels.documentImportInvalidDocument ?? '';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function FieldRemapDocumentIo({
|
|
55
|
+
getDocumentJson,
|
|
56
|
+
importAvailable,
|
|
57
|
+
labels: labelOverrides,
|
|
58
|
+
t,
|
|
59
|
+
onImportText,
|
|
60
|
+
}: FieldRemapDocumentIoProps): JSX.Element {
|
|
61
|
+
const labels = useMemo(
|
|
62
|
+
() => resolveFieldRemapChromeLabels(labelOverrides, t),
|
|
63
|
+
[labelOverrides, t],
|
|
64
|
+
);
|
|
65
|
+
const [exportOpen, setExportOpen] = useState(false);
|
|
66
|
+
const [exportText, setExportText] = useState('');
|
|
67
|
+
const [importOpen, setImportOpen] = useState(false);
|
|
68
|
+
const [draft, setDraft] = useState('');
|
|
69
|
+
const [importError, setImportError] = useState<string | null>(null);
|
|
70
|
+
const [status, setStatus] = useState<DocumentIoStatus | null>(null);
|
|
71
|
+
const instanceId = useId();
|
|
72
|
+
const exportTextId = `field-remap-document-export-text-${instanceId}`;
|
|
73
|
+
const importTextId = `field-remap-document-import-text-${instanceId}`;
|
|
74
|
+
const importErrorId = `field-remap-document-import-error-${instanceId}`;
|
|
75
|
+
const exportTextareaRef = useRef<HTMLTextAreaElement>(null);
|
|
76
|
+
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (!importAvailable && importOpen) {
|
|
80
|
+
setImportOpen(false);
|
|
81
|
+
setDraft('');
|
|
82
|
+
setImportError(null);
|
|
83
|
+
}
|
|
84
|
+
}, [importAvailable, importOpen]);
|
|
85
|
+
|
|
86
|
+
const closeImport = () => {
|
|
87
|
+
setImportOpen(false);
|
|
88
|
+
setDraft('');
|
|
89
|
+
setImportError(null);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const closeExport = () => {
|
|
93
|
+
setExportOpen(false);
|
|
94
|
+
setExportText('');
|
|
95
|
+
setStatus(null);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const openExport = () => {
|
|
99
|
+
try {
|
|
100
|
+
setExportText(getDocumentJson());
|
|
101
|
+
setStatus(null);
|
|
102
|
+
setExportOpen(true);
|
|
103
|
+
} catch {
|
|
104
|
+
setStatus({ kind: 'error', message: labels.documentCopyFailed ?? '' });
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const copyDocument = async () => {
|
|
109
|
+
try {
|
|
110
|
+
const clipboard = globalThis.navigator?.clipboard;
|
|
111
|
+
if (!clipboard || typeof clipboard.writeText !== 'function') {
|
|
112
|
+
throw new Error('Clipboard write is unavailable.');
|
|
113
|
+
}
|
|
114
|
+
await clipboard.writeText(exportText);
|
|
115
|
+
setStatus({ kind: 'success', message: labels.documentCopied ?? '' });
|
|
116
|
+
} catch {
|
|
117
|
+
setStatus({ kind: 'error', message: labels.documentCopyFailed ?? '' });
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const openImport = () => {
|
|
122
|
+
if (!importAvailable) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
setDraft('');
|
|
126
|
+
setImportError(null);
|
|
127
|
+
setStatus(null);
|
|
128
|
+
setImportOpen(true);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const applyImport = (event: FormEvent<HTMLFormElement>) => {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
const result = onImportText(draft);
|
|
134
|
+
if (result.status === 'rejected') {
|
|
135
|
+
setImportError(importFailureMessage(result.code, labels));
|
|
136
|
+
queueMicrotask(() => textareaRef.current?.focus());
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
closeImport();
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div className="workbench-field-remap-document-io" data-testid="field-remap-document-io">
|
|
144
|
+
<div className="workbench-field-remap-document-io__actions">
|
|
145
|
+
<Button
|
|
146
|
+
compact
|
|
147
|
+
type="button"
|
|
148
|
+
data-testid="field-remap-export-document"
|
|
149
|
+
onClick={openExport}
|
|
150
|
+
>
|
|
151
|
+
{labels.exportDocumentJson}
|
|
152
|
+
</Button>
|
|
153
|
+
<Button
|
|
154
|
+
compact
|
|
155
|
+
type="button"
|
|
156
|
+
data-testid="field-remap-import-document"
|
|
157
|
+
disabled={!importAvailable}
|
|
158
|
+
onClick={openImport}
|
|
159
|
+
>
|
|
160
|
+
{labels.importDocumentJson}
|
|
161
|
+
</Button>
|
|
162
|
+
</div>
|
|
163
|
+
{!importAvailable ? (
|
|
164
|
+
<span className="workbench-field-remap-document-io__availability">
|
|
165
|
+
{labels.documentImportUnavailable}
|
|
166
|
+
</span>
|
|
167
|
+
) : null}
|
|
168
|
+
{status && !exportOpen ? (
|
|
169
|
+
<span
|
|
170
|
+
className="workbench-field-remap-document-io__status"
|
|
171
|
+
data-status={status.kind}
|
|
172
|
+
role={status.kind === 'error' ? 'alert' : 'status'}
|
|
173
|
+
>
|
|
174
|
+
{status.message}
|
|
175
|
+
</span>
|
|
176
|
+
) : null}
|
|
177
|
+
|
|
178
|
+
{exportOpen ? (
|
|
179
|
+
<WorkbenchModalPortal>
|
|
180
|
+
<Modal
|
|
181
|
+
bodyClassName="workbench-field-remap-document-export__body"
|
|
182
|
+
bodyLayout="stack"
|
|
183
|
+
bodyPadding="lg"
|
|
184
|
+
bodyScroll="auto"
|
|
185
|
+
className="workbench-field-remap-document-export"
|
|
186
|
+
closeLabel={labels.closeDocumentExport}
|
|
187
|
+
footer={
|
|
188
|
+
<>
|
|
189
|
+
<Button
|
|
190
|
+
type="button"
|
|
191
|
+
data-testid="field-remap-copy-document"
|
|
192
|
+
onClick={() => void copyDocument()}
|
|
193
|
+
>
|
|
194
|
+
{labels.copyDocumentJson}
|
|
195
|
+
</Button>
|
|
196
|
+
<Button type="button" onClick={closeExport}>
|
|
197
|
+
{labels.closeDocumentExport}
|
|
198
|
+
</Button>
|
|
199
|
+
</>
|
|
200
|
+
}
|
|
201
|
+
initialFocusRef={exportTextareaRef}
|
|
202
|
+
title={labels.exportDocumentTitle}
|
|
203
|
+
onClose={closeExport}
|
|
204
|
+
>
|
|
205
|
+
<p className="workbench-field-remap-document-export__description">
|
|
206
|
+
{labels.exportDocumentDescription}
|
|
207
|
+
</p>
|
|
208
|
+
<label className="workbench-field-remap-document-export__label" htmlFor={exportTextId}>
|
|
209
|
+
{labels.exportDocumentLabel}
|
|
210
|
+
</label>
|
|
211
|
+
<TextArea
|
|
212
|
+
ref={exportTextareaRef}
|
|
213
|
+
id={exportTextId}
|
|
214
|
+
controlWidth="full"
|
|
215
|
+
data-testid="field-remap-document-export-text"
|
|
216
|
+
monospace
|
|
217
|
+
readOnly
|
|
218
|
+
rows={12}
|
|
219
|
+
value={exportText}
|
|
220
|
+
onFocus={(event) => event.currentTarget.select()}
|
|
221
|
+
/>
|
|
222
|
+
{status ? (
|
|
223
|
+
<p
|
|
224
|
+
className="workbench-field-remap-document-io__status"
|
|
225
|
+
data-status={status.kind}
|
|
226
|
+
role={status.kind === 'error' ? 'alert' : 'status'}
|
|
227
|
+
>
|
|
228
|
+
{status.message}
|
|
229
|
+
</p>
|
|
230
|
+
) : null}
|
|
231
|
+
</Modal>
|
|
232
|
+
</WorkbenchModalPortal>
|
|
233
|
+
) : null}
|
|
234
|
+
|
|
235
|
+
{importOpen ? (
|
|
236
|
+
<WorkbenchModalPortal>
|
|
237
|
+
<Modal
|
|
238
|
+
bodyClassName="workbench-field-remap-document-import__body"
|
|
239
|
+
bodyLayout="stack"
|
|
240
|
+
bodyPadding="lg"
|
|
241
|
+
bodyScroll="auto"
|
|
242
|
+
className="workbench-field-remap-document-import"
|
|
243
|
+
closeLabel={labels.closeDocumentImport}
|
|
244
|
+
footer={
|
|
245
|
+
<>
|
|
246
|
+
<Button type="button" onClick={closeImport}>
|
|
247
|
+
{labels.cancelDocumentImport}
|
|
248
|
+
</Button>
|
|
249
|
+
<Button
|
|
250
|
+
type="submit"
|
|
251
|
+
variant="primary"
|
|
252
|
+
data-testid="field-remap-apply-document-import"
|
|
253
|
+
>
|
|
254
|
+
{labels.applyDocumentImport}
|
|
255
|
+
</Button>
|
|
256
|
+
</>
|
|
257
|
+
}
|
|
258
|
+
initialFocusRef={textareaRef}
|
|
259
|
+
title={labels.importDocumentTitle}
|
|
260
|
+
onClose={closeImport}
|
|
261
|
+
onSubmit={applyImport}
|
|
262
|
+
>
|
|
263
|
+
<p className="workbench-field-remap-document-import__description">
|
|
264
|
+
{labels.importDocumentDescription}
|
|
265
|
+
</p>
|
|
266
|
+
<label className="workbench-field-remap-document-import__label" htmlFor={importTextId}>
|
|
267
|
+
{labels.importDocumentLabel}
|
|
268
|
+
</label>
|
|
269
|
+
<TextArea
|
|
270
|
+
ref={textareaRef}
|
|
271
|
+
id={importTextId}
|
|
272
|
+
aria-describedby={importError ? importErrorId : undefined}
|
|
273
|
+
aria-invalid={importError ? true : undefined}
|
|
274
|
+
controlWidth="full"
|
|
275
|
+
data-testid="field-remap-document-import-text"
|
|
276
|
+
monospace
|
|
277
|
+
placeholder={labels.importDocumentPlaceholder}
|
|
278
|
+
rows={12}
|
|
279
|
+
value={draft}
|
|
280
|
+
onChange={(event) => {
|
|
281
|
+
setDraft(event.currentTarget.value);
|
|
282
|
+
setImportError(null);
|
|
283
|
+
}}
|
|
284
|
+
/>
|
|
285
|
+
{importError ? (
|
|
286
|
+
<p
|
|
287
|
+
id={importErrorId}
|
|
288
|
+
className="workbench-field-remap-document-import__error"
|
|
289
|
+
role="alert"
|
|
290
|
+
>
|
|
291
|
+
{importError}
|
|
292
|
+
</p>
|
|
293
|
+
) : null}
|
|
294
|
+
</Modal>
|
|
295
|
+
</WorkbenchModalPortal>
|
|
296
|
+
) : null}
|
|
297
|
+
</div>
|
|
298
|
+
);
|
|
299
|
+
}
|
package/src/field-remap/flow.tsx
CHANGED
|
@@ -377,8 +377,10 @@ const DEFAULT_FIT_VIEW_OPTIONS = { padding: 0.12, maxZoom: 1.15 } as const;
|
|
|
377
377
|
* to the React Flow store (avoids update loops with controlled nodes).
|
|
378
378
|
*/
|
|
379
379
|
function FieldRemapFlowActionsBridge({
|
|
380
|
+
canFitView,
|
|
380
381
|
flowActionsRef,
|
|
381
382
|
}: {
|
|
383
|
+
readonly canFitView: () => boolean;
|
|
382
384
|
readonly flowActionsRef?: Ref<FieldRemapFlowActions | null> | undefined;
|
|
383
385
|
}): null {
|
|
384
386
|
const { fitView } = useReactFlow();
|
|
@@ -386,13 +388,16 @@ function FieldRemapFlowActionsBridge({
|
|
|
386
388
|
flowActionsRef,
|
|
387
389
|
() => ({
|
|
388
390
|
fitView: (options) => {
|
|
391
|
+
if (!canFitView()) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
389
394
|
void fitView({
|
|
390
395
|
padding: options?.padding ?? DEFAULT_FIT_VIEW_OPTIONS.padding,
|
|
391
396
|
maxZoom: options?.maxZoom ?? DEFAULT_FIT_VIEW_OPTIONS.maxZoom,
|
|
392
397
|
});
|
|
393
398
|
},
|
|
394
399
|
}),
|
|
395
|
-
[fitView],
|
|
400
|
+
[canFitView, fitView],
|
|
396
401
|
);
|
|
397
402
|
return null;
|
|
398
403
|
}
|
|
@@ -700,7 +705,9 @@ function FieldRemapFlowCanvas({
|
|
|
700
705
|
const showAuthoringPalette = showConvertPalette && !readOnly;
|
|
701
706
|
const emptyDetail = emptyDetailProp ?? (chrome === 'embed' ? 'collapse' : 'hint');
|
|
702
707
|
const mapperRef = useRef<HTMLDivElement>(null);
|
|
708
|
+
const canvasRef = useRef<HTMLDivElement>(null);
|
|
703
709
|
const restoreMapperFocusRef = useRef(false);
|
|
710
|
+
const [hasPositiveCanvasSize, setHasPositiveCanvasSize] = useState(false);
|
|
704
711
|
const [workspaceLayout, setWorkspaceLayout] = useState<'wide' | 'medium' | 'narrow'>('wide');
|
|
705
712
|
const [internalSelection, setInternalSelection] = useState<FieldRemapSelection>(null);
|
|
706
713
|
const authoritativeSelection = selectionProp !== undefined ? selectionProp : internalSelection;
|
|
@@ -982,6 +989,48 @@ function FieldRemapFlowCanvas({
|
|
|
982
989
|
return () => observer.disconnect();
|
|
983
990
|
}, []);
|
|
984
991
|
|
|
992
|
+
const canFitView = useCallback(() => {
|
|
993
|
+
const bounds = canvasRef.current?.getBoundingClientRect();
|
|
994
|
+
return bounds !== undefined && bounds.width > 0 && bounds.height > 0;
|
|
995
|
+
}, []);
|
|
996
|
+
|
|
997
|
+
useEffect(() => {
|
|
998
|
+
const element = canvasRef.current;
|
|
999
|
+
if (!element) {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
const updateMountEligibility = () => {
|
|
1004
|
+
const bounds = element.getBoundingClientRect();
|
|
1005
|
+
if (bounds.width > 0 && bounds.height > 0) {
|
|
1006
|
+
setHasPositiveCanvasSize(true);
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
updateMountEligibility();
|
|
1011
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
let pendingFrame: number | undefined;
|
|
1015
|
+
const scheduleMountEligibilityUpdate = () => {
|
|
1016
|
+
if (pendingFrame !== undefined) {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
pendingFrame = requestAnimationFrame(() => {
|
|
1020
|
+
pendingFrame = undefined;
|
|
1021
|
+
updateMountEligibility();
|
|
1022
|
+
});
|
|
1023
|
+
};
|
|
1024
|
+
const observer = new ResizeObserver(scheduleMountEligibilityUpdate);
|
|
1025
|
+
observer.observe(element);
|
|
1026
|
+
return () => {
|
|
1027
|
+
observer.disconnect();
|
|
1028
|
+
if (pendingFrame !== undefined) {
|
|
1029
|
+
cancelAnimationFrame(pendingFrame);
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
}, []);
|
|
1033
|
+
|
|
985
1034
|
const graph = useMemo(
|
|
986
1035
|
() =>
|
|
987
1036
|
mappingToFlowGraph({
|
|
@@ -1837,105 +1886,61 @@ function FieldRemapFlowCanvas({
|
|
|
1837
1886
|
) : null}
|
|
1838
1887
|
</>
|
|
1839
1888
|
|
|
1840
|
-
<div
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
{
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
strokeWidth="1.75"
|
|
1895
|
-
viewBox="0 0 24 24"
|
|
1896
|
-
width="16"
|
|
1889
|
+
<div
|
|
1890
|
+
ref={canvasRef}
|
|
1891
|
+
className="workbench-field-remap-flow__canvas"
|
|
1892
|
+
data-testid="field-remap-flow"
|
|
1893
|
+
>
|
|
1894
|
+
{hasPositiveCanvasSize ? (
|
|
1895
|
+
<ReactFlow
|
|
1896
|
+
nodes={nodes}
|
|
1897
|
+
edges={flowEdges}
|
|
1898
|
+
nodeTypes={nodeTypes}
|
|
1899
|
+
edgeTypes={edgeTypes}
|
|
1900
|
+
onNodesChange={onProjectedNodesChange}
|
|
1901
|
+
onEdgesChange={onProjectedFlowEdgesChange}
|
|
1902
|
+
onConnect={readOnly ? undefined : onConnect}
|
|
1903
|
+
onConnectStart={readOnly ? undefined : onConnectStart}
|
|
1904
|
+
onConnectEnd={readOnly ? undefined : onConnectEnd}
|
|
1905
|
+
onEdgesDelete={readOnly ? undefined : onEdgesDelete}
|
|
1906
|
+
onDragOver={onCanvasDragOver}
|
|
1907
|
+
onDrop={onCanvasDrop}
|
|
1908
|
+
onNodeClick={onNodeClick}
|
|
1909
|
+
onEdgeClick={onEdgeClick}
|
|
1910
|
+
onPaneContextMenu={onPaneContextMenu ? handlePaneContextMenu : undefined}
|
|
1911
|
+
onNodeContextMenu={onNodeContextMenu ? handleNodeContextMenu : undefined}
|
|
1912
|
+
onEdgeContextMenu={onEdgeContextMenu ? handleEdgeContextMenu : undefined}
|
|
1913
|
+
isValidConnection={isValidConnection}
|
|
1914
|
+
nodesDraggable={!readOnly}
|
|
1915
|
+
nodesConnectable={!readOnly}
|
|
1916
|
+
edgesReconnectable={!readOnly}
|
|
1917
|
+
elementsSelectable={false}
|
|
1918
|
+
ariaLabelConfig={flowAriaLabelConfig}
|
|
1919
|
+
deleteKeyCode={null}
|
|
1920
|
+
fitView
|
|
1921
|
+
fitViewOptions={DEFAULT_FIT_VIEW_OPTIONS}
|
|
1922
|
+
proOptions={{ hideAttribution: true }}
|
|
1923
|
+
>
|
|
1924
|
+
<FieldRemapFlowActionsBridge
|
|
1925
|
+
canFitView={canFitView}
|
|
1926
|
+
flowActionsRef={flowActionsRef}
|
|
1927
|
+
/>
|
|
1928
|
+
<Background gap={16} color="var(--xy-background-pattern-color)" />
|
|
1929
|
+
<Controls showInteractive={false} fitViewOptions={DEFAULT_FIT_VIEW_OPTIONS}>
|
|
1930
|
+
{onShowMinimapChange ? (
|
|
1931
|
+
<ControlButton
|
|
1932
|
+
aria-label={showMinimap ? chromeLabels.hideMinimap : chromeLabels.showMinimap}
|
|
1933
|
+
className={
|
|
1934
|
+
showMinimap
|
|
1935
|
+
? 'workbench-field-remap-flow__minimap-toggle is-active'
|
|
1936
|
+
: 'workbench-field-remap-flow__minimap-toggle'
|
|
1937
|
+
}
|
|
1938
|
+
data-testid="field-remap-toggle-minimap"
|
|
1939
|
+
title={showMinimap ? chromeLabels.hideMinimap : chromeLabels.showMinimap}
|
|
1940
|
+
onClick={() => {
|
|
1941
|
+
onShowMinimapChange(!showMinimap);
|
|
1942
|
+
}}
|
|
1897
1943
|
>
|
|
1898
|
-
<path d="M3 6.5 9 4l6 2.5L21 4v13.5L15 20l-6-2.5L3 20z" />
|
|
1899
|
-
<path d="M9 4v13.5" />
|
|
1900
|
-
<path d="M15 6.5V20" />
|
|
1901
|
-
</svg>
|
|
1902
|
-
</ControlButton>
|
|
1903
|
-
) : null}
|
|
1904
|
-
{onIncludeHiddenChange ? (
|
|
1905
|
-
<ControlButton
|
|
1906
|
-
aria-label={
|
|
1907
|
-
includeHidden ? chromeLabels.hideHiddenFields : chromeLabels.showHiddenFields
|
|
1908
|
-
}
|
|
1909
|
-
aria-pressed={includeHidden}
|
|
1910
|
-
className={
|
|
1911
|
-
includeHidden
|
|
1912
|
-
? 'workbench-field-remap-flow__hidden-toggle is-active'
|
|
1913
|
-
: 'workbench-field-remap-flow__hidden-toggle'
|
|
1914
|
-
}
|
|
1915
|
-
data-testid="field-remap-toggle-hidden-fields"
|
|
1916
|
-
title={
|
|
1917
|
-
includeHidden ? chromeLabels.hideHiddenFields : chromeLabels.showHiddenFields
|
|
1918
|
-
}
|
|
1919
|
-
onClick={() => {
|
|
1920
|
-
onIncludeHiddenChange(!includeHidden);
|
|
1921
|
-
}}
|
|
1922
|
-
>
|
|
1923
|
-
{includeHidden ? (
|
|
1924
|
-
<svg
|
|
1925
|
-
aria-hidden="true"
|
|
1926
|
-
fill="none"
|
|
1927
|
-
height="16"
|
|
1928
|
-
stroke="currentColor"
|
|
1929
|
-
strokeLinecap="round"
|
|
1930
|
-
strokeLinejoin="round"
|
|
1931
|
-
strokeWidth="1.75"
|
|
1932
|
-
viewBox="0 0 24 24"
|
|
1933
|
-
width="16"
|
|
1934
|
-
>
|
|
1935
|
-
<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z" />
|
|
1936
|
-
<circle cx="12" cy="12" r="3" />
|
|
1937
|
-
</svg>
|
|
1938
|
-
) : (
|
|
1939
1944
|
<svg
|
|
1940
1945
|
aria-hidden="true"
|
|
1941
1946
|
fill="none"
|
|
@@ -1947,35 +1952,92 @@ function FieldRemapFlowCanvas({
|
|
|
1947
1952
|
viewBox="0 0 24 24"
|
|
1948
1953
|
width="16"
|
|
1949
1954
|
>
|
|
1950
|
-
<path d="M3
|
|
1951
|
-
<path d="
|
|
1952
|
-
<path d="
|
|
1953
|
-
<path d="M6.1 6.1C3.9 7.7 2 12 2 12s3.5 7 10 7a10.4 10.4 0 0 0 4.2-.9" />
|
|
1955
|
+
<path d="M3 6.5 9 4l6 2.5L21 4v13.5L15 20l-6-2.5L3 20z" />
|
|
1956
|
+
<path d="M9 4v13.5" />
|
|
1957
|
+
<path d="M15 6.5V20" />
|
|
1954
1958
|
</svg>
|
|
1955
|
-
|
|
1956
|
-
|
|
1959
|
+
</ControlButton>
|
|
1960
|
+
) : null}
|
|
1961
|
+
{onIncludeHiddenChange ? (
|
|
1962
|
+
<ControlButton
|
|
1963
|
+
aria-label={
|
|
1964
|
+
includeHidden ? chromeLabels.hideHiddenFields : chromeLabels.showHiddenFields
|
|
1965
|
+
}
|
|
1966
|
+
aria-pressed={includeHidden}
|
|
1967
|
+
className={
|
|
1968
|
+
includeHidden
|
|
1969
|
+
? 'workbench-field-remap-flow__hidden-toggle is-active'
|
|
1970
|
+
: 'workbench-field-remap-flow__hidden-toggle'
|
|
1971
|
+
}
|
|
1972
|
+
data-testid="field-remap-toggle-hidden-fields"
|
|
1973
|
+
title={
|
|
1974
|
+
includeHidden ? chromeLabels.hideHiddenFields : chromeLabels.showHiddenFields
|
|
1975
|
+
}
|
|
1976
|
+
onClick={() => {
|
|
1977
|
+
onIncludeHiddenChange(!includeHidden);
|
|
1978
|
+
}}
|
|
1979
|
+
>
|
|
1980
|
+
{includeHidden ? (
|
|
1981
|
+
<svg
|
|
1982
|
+
aria-hidden="true"
|
|
1983
|
+
fill="none"
|
|
1984
|
+
height="16"
|
|
1985
|
+
stroke="currentColor"
|
|
1986
|
+
strokeLinecap="round"
|
|
1987
|
+
strokeLinejoin="round"
|
|
1988
|
+
strokeWidth="1.75"
|
|
1989
|
+
viewBox="0 0 24 24"
|
|
1990
|
+
width="16"
|
|
1991
|
+
>
|
|
1992
|
+
<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z" />
|
|
1993
|
+
<circle cx="12" cy="12" r="3" />
|
|
1994
|
+
</svg>
|
|
1995
|
+
) : (
|
|
1996
|
+
<svg
|
|
1997
|
+
aria-hidden="true"
|
|
1998
|
+
fill="none"
|
|
1999
|
+
height="16"
|
|
2000
|
+
stroke="currentColor"
|
|
2001
|
+
strokeLinecap="round"
|
|
2002
|
+
strokeLinejoin="round"
|
|
2003
|
+
strokeWidth="1.75"
|
|
2004
|
+
viewBox="0 0 24 24"
|
|
2005
|
+
width="16"
|
|
2006
|
+
>
|
|
2007
|
+
<path d="M3 3l18 18" />
|
|
2008
|
+
<path d="M10.6 10.6a3 3 0 0 0 4.2 4.2" />
|
|
2009
|
+
<path d="M9.9 5.1A10.6 10.6 0 0 1 12 5c6.5 0 10 7 10 7a17.4 17.4 0 0 1-3.2 4.4" />
|
|
2010
|
+
<path d="M6.1 6.1C3.9 7.7 2 12 2 12s3.5 7 10 7a10.4 10.4 0 0 0 4.2-.9" />
|
|
2011
|
+
</svg>
|
|
2012
|
+
)}
|
|
2013
|
+
</ControlButton>
|
|
2014
|
+
) : null}
|
|
2015
|
+
</Controls>
|
|
2016
|
+
{showMinimap ? (
|
|
2017
|
+
<MiniMap
|
|
2018
|
+
pannable
|
|
2019
|
+
zoomable
|
|
2020
|
+
bgColor="var(--xy-minimap-background-color)"
|
|
2021
|
+
maskColor="var(--xy-minimap-mask-background-color)"
|
|
2022
|
+
nodeColor={(node) => {
|
|
2023
|
+
const kind = (node.data as FieldRemapFlowNodeData | undefined)?.kind;
|
|
2024
|
+
if (kind === 'source-object') {
|
|
2025
|
+
return 'var(--vscode-charts-blue, #3794ff)';
|
|
2026
|
+
}
|
|
2027
|
+
if (kind === 'target-object') {
|
|
2028
|
+
return 'var(--vscode-charts-green, #89d185)';
|
|
2029
|
+
}
|
|
2030
|
+
return 'var(--vscode-focusBorder, var(--color-accent, #3794ff))';
|
|
2031
|
+
}}
|
|
2032
|
+
nodeStrokeColor="var(--xy-minimap-node-stroke-color)"
|
|
2033
|
+
/>
|
|
1957
2034
|
) : null}
|
|
1958
|
-
</
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
maskColor="var(--xy-minimap-mask-background-color)"
|
|
1965
|
-
nodeColor={(node) => {
|
|
1966
|
-
const kind = (node.data as FieldRemapFlowNodeData | undefined)?.kind;
|
|
1967
|
-
if (kind === 'source-object') {
|
|
1968
|
-
return 'var(--vscode-charts-blue, #3794ff)';
|
|
1969
|
-
}
|
|
1970
|
-
if (kind === 'target-object') {
|
|
1971
|
-
return 'var(--vscode-charts-green, #89d185)';
|
|
1972
|
-
}
|
|
1973
|
-
return 'var(--vscode-focusBorder, var(--color-accent, #3794ff))';
|
|
1974
|
-
}}
|
|
1975
|
-
nodeStrokeColor="var(--xy-minimap-node-stroke-color)"
|
|
1976
|
-
/>
|
|
1977
|
-
) : null}
|
|
1978
|
-
</ReactFlow>
|
|
2035
|
+
</ReactFlow>
|
|
2036
|
+
) : (
|
|
2037
|
+
<p className="workbench-field-remap-demo__warn" role="status">
|
|
2038
|
+
Mapping canvas is waiting for available space.
|
|
2039
|
+
</p>
|
|
2040
|
+
)}
|
|
1979
2041
|
</div>
|
|
1980
2042
|
|
|
1981
2043
|
<div className="workbench-field-remap-flow__side-rail">
|