@workbench-kit/shell-react 0.0.2-prototype.0.2.32 → 0.0.2-prototype.0.2.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/package.json +9 -9
- package/src/commands/use-command-descriptors.ts +7 -3
- package/src/commands/use-extension-registry-command-descriptors.ts +23 -6
- package/src/devtools/use-workbench-devtools-snapshot.ts +39 -14
- package/src/devtools/workbench-devtools-snapshot.ts +32 -13
- package/src/editor/area.tsx +3 -2
- package/src/editor/state-storage.ts +31 -0
- package/src/editor/tab-context-menu.ts +8 -8
- package/src/editor/use-editor.ts +6 -6
- package/src/explorer/context-menu.ts +8 -4
- package/src/explorer/view.tsx +4 -3
- package/src/extensions/canonical-extension-descriptions.ts +58 -0
- package/src/extensions/context-menu.ts +9 -6
- package/src/extensions/extension-enablement-context.ts +15 -0
- package/src/extensions/extension-enablement-controller.ts +453 -0
- package/src/extensions/management-model.ts +111 -47
- package/src/extensions/theme-selection-protection.ts +98 -0
- package/src/extensions/uninstall-eligibility.ts +103 -0
- package/src/extensions/use-extension-management.ts +151 -67
- package/src/extensions/view.tsx +4 -0
- package/src/field-remap/chrome-labels.ts +87 -2
- package/src/field-remap/convert-palette.tsx +164 -18
- package/src/field-remap/demo.tsx +48 -3
- package/src/field-remap/detail-panel.tsx +6 -5
- package/src/field-remap/flow.tsx +341 -155
- package/src/field-remap/history.ts +99 -0
- package/src/field-remap/index.ts +9 -1
- package/src/field-remap/panel.tsx +388 -97
- package/src/field-remap/preview-controller.ts +122 -0
- package/src/field-remap/preview.tsx +171 -0
- package/src/field-remap/view.css +154 -2
- package/src/index.ts +16 -1
- package/src/management/keybinding-overrides-storage.ts +28 -0
- package/src/management/preference-settings-storage.ts +28 -0
- package/src/management/settings.tsx +2 -0
- package/src/management/use-command-management.ts +31 -26
- package/src/management/use-keybinding-management.ts +25 -12
- package/src/shell/focused-extension-services.ts +138 -0
- package/src/shell/host-shell.tsx +13 -10
- package/src/shell/persistence-diagnostic-context.ts +11 -0
- package/src/shell/provider.tsx +373 -69
- package/src/shell/settings.tsx +25 -16
- package/src/shell/shell.tsx +119 -78
- package/src/shell/view-host.tsx +23 -22
- package/src/storage/local-json-storage.ts +43 -29
- package/src/storage/persistence-diagnostics.ts +72 -0
- package/src/workbench/appearance-storage.ts +28 -0
- package/src/workbench/command-host.tsx +19 -22
- package/src/workbench/command-palette.ts +14 -13
- package/src/workbench/layout-storage.ts +52 -5
- package/src/workbench/use-persisted-appearance.ts +38 -12
package/src/field-remap/flow.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Children,
|
|
2
3
|
useCallback,
|
|
3
4
|
useEffect,
|
|
4
5
|
useImperativeHandle,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
type KeyboardEvent,
|
|
10
11
|
type MouseEvent,
|
|
11
12
|
type Ref,
|
|
13
|
+
type ReactNode,
|
|
12
14
|
} from 'react';
|
|
13
15
|
import {
|
|
14
16
|
Background,
|
|
@@ -28,7 +30,8 @@ import {
|
|
|
28
30
|
type NodeProps,
|
|
29
31
|
} from '@xyflow/react';
|
|
30
32
|
import '@xyflow/react/dist/style.css';
|
|
31
|
-
import { Badge,
|
|
33
|
+
import { Badge, IconButton } from '@workbench-kit/react/primitives';
|
|
34
|
+
import { SplitView } from '@workbench-kit/react/workbench/split-view';
|
|
32
35
|
import {
|
|
33
36
|
MAX_TRANSFORM_CHAIN,
|
|
34
37
|
type MappingEdge,
|
|
@@ -81,6 +84,7 @@ import {
|
|
|
81
84
|
type FieldRemapDraftTransform,
|
|
82
85
|
type FieldRemapSelection,
|
|
83
86
|
} from './flow-ops.js';
|
|
87
|
+
import { FieldRemapPreviewRail, type FieldRemapPreviewState } from './preview.js';
|
|
84
88
|
import './view.css';
|
|
85
89
|
|
|
86
90
|
function TypeBadge({ dataType }: { readonly dataType?: string }): JSX.Element | null {
|
|
@@ -323,6 +327,22 @@ export interface FieldRemapFlowMapperProps {
|
|
|
323
327
|
readonly edges: readonly MappingEdge[];
|
|
324
328
|
readonly transforms: ValueTransformRegistry;
|
|
325
329
|
readonly onEdgesChange: (edges: readonly MappingEdge[]) => void;
|
|
330
|
+
/**
|
|
331
|
+
* `card` preserves the demo chrome. `embed` omits the flow hint and binding list;
|
|
332
|
+
* explicit `show*` props below take precedence.
|
|
333
|
+
*/
|
|
334
|
+
readonly chrome?: 'card' | 'embed' | undefined;
|
|
335
|
+
/** Show the empty-selection detail hint, or collapse that rail until a selection exists. */
|
|
336
|
+
readonly emptyDetail?: 'hint' | 'collapse' | undefined;
|
|
337
|
+
/** Show the convert-first hint. Defaults to true for `card`, false for `embed`. */
|
|
338
|
+
readonly showFlowHint?: boolean | undefined;
|
|
339
|
+
/** Show the bottom binding list. Defaults to true for `card`, false for `embed`. */
|
|
340
|
+
readonly showBindingsList?: boolean | undefined;
|
|
341
|
+
/**
|
|
342
|
+
* Mount the primary Convert palette. Defaults to true for both chrome modes; when false,
|
|
343
|
+
* the workspace expands without leaving an empty grid track.
|
|
344
|
+
*/
|
|
345
|
+
readonly showConvertPalette?: boolean | undefined;
|
|
326
346
|
/** Document v2 n→m operators (display + authoring when onOperatorsChange is set). */
|
|
327
347
|
readonly operators?: readonly MappingOperator[] | undefined;
|
|
328
348
|
readonly onOperatorsChange?: ((operators: readonly MappingOperator[]) => void) | undefined;
|
|
@@ -330,6 +350,10 @@ export interface FieldRemapFlowMapperProps {
|
|
|
330
350
|
readonly targetTitle?: string | undefined;
|
|
331
351
|
readonly selection?: FieldRemapSelection | undefined;
|
|
332
352
|
readonly onSelectionChange?: ((next: FieldRemapSelection) => void) | undefined;
|
|
353
|
+
/** Precomputed runtime-only preview. Flow never evaluates mappings itself. */
|
|
354
|
+
readonly preview?: FieldRemapPreviewState;
|
|
355
|
+
/** Explicitly hide an injected preview without reserving a splitter track. */
|
|
356
|
+
readonly showPreview?: boolean;
|
|
333
357
|
/**
|
|
334
358
|
* When false, MiniMap is not mounted (not CSS-hidden). Defaults to true for
|
|
335
359
|
* backward compatibility with existing samples.
|
|
@@ -380,18 +404,117 @@ export interface FieldRemapFlowMapperProps {
|
|
|
380
404
|
readonly t?: FieldRemapTranslate | undefined;
|
|
381
405
|
}
|
|
382
406
|
|
|
407
|
+
interface FieldRemapSplitWorkspaceProps {
|
|
408
|
+
readonly children: ReactNode;
|
|
409
|
+
readonly layout: 'wide' | 'medium' | 'narrow';
|
|
410
|
+
readonly showConvertPalette: boolean;
|
|
411
|
+
readonly showDetail: boolean;
|
|
412
|
+
readonly surface: 'binding' | 'convert-note' | 'draft-convert' | 'operator';
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* The Flow rails are deliberately composed from the shared SplitView primitive so keyboard and
|
|
417
|
+
* pointer resizing stay consistent with the rest of the workbench. At narrower host widths the
|
|
418
|
+
* palette and/or detail move above or below the canvas rather than squeezing its usable width.
|
|
419
|
+
*/
|
|
420
|
+
function FieldRemapSplitWorkspace({
|
|
421
|
+
children,
|
|
422
|
+
layout,
|
|
423
|
+
showConvertPalette,
|
|
424
|
+
showDetail,
|
|
425
|
+
surface,
|
|
426
|
+
}: FieldRemapSplitWorkspaceProps): JSX.Element {
|
|
427
|
+
const [palette, canvas, detail] = Children.toArray(children);
|
|
428
|
+
const isNarrow = layout === 'narrow';
|
|
429
|
+
const [paletteSizeByLayout, setPaletteSizeByLayout] = useState({
|
|
430
|
+
wide: 240,
|
|
431
|
+
medium: 240,
|
|
432
|
+
narrow: 192,
|
|
433
|
+
});
|
|
434
|
+
const [detailSizeByLayout, setDetailSizeByLayout] = useState({
|
|
435
|
+
wide: 320,
|
|
436
|
+
medium: 320,
|
|
437
|
+
narrow: 220,
|
|
438
|
+
});
|
|
439
|
+
const paletteSizePx = paletteSizeByLayout[layout];
|
|
440
|
+
const detailSizePx = detailSizeByLayout[layout];
|
|
441
|
+
const canvasWithDetail = (
|
|
442
|
+
<SplitView
|
|
443
|
+
className={
|
|
444
|
+
showDetail
|
|
445
|
+
? 'workbench-field-remap-flow__canvas-detail-split'
|
|
446
|
+
: 'workbench-field-remap-flow__canvas-detail-split ui-workbench-split-view--secondary-collapsed'
|
|
447
|
+
}
|
|
448
|
+
layoutMode="secondary-fixed"
|
|
449
|
+
maxSecondarySizePx={isNarrow ? 320 : 480}
|
|
450
|
+
minPrimarySizePx={isNarrow ? 200 : 280}
|
|
451
|
+
minSecondarySizePx={isNarrow ? 160 : 256}
|
|
452
|
+
onSecondarySizePxChange={(nextSize) => {
|
|
453
|
+
setDetailSizeByLayout((current) => ({ ...current, [layout]: nextSize }));
|
|
454
|
+
}}
|
|
455
|
+
orientation={isNarrow ? 'vertical' : 'horizontal'}
|
|
456
|
+
primary={canvas}
|
|
457
|
+
secondary={detail}
|
|
458
|
+
secondarySizePx={detailSizePx}
|
|
459
|
+
/>
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
const content = (
|
|
463
|
+
<SplitView
|
|
464
|
+
className={
|
|
465
|
+
showConvertPalette
|
|
466
|
+
? 'workbench-field-remap-flow__palette-split'
|
|
467
|
+
: 'workbench-field-remap-flow__palette-split ui-workbench-split-view--primary-collapsed'
|
|
468
|
+
}
|
|
469
|
+
maxPrimarySizePx={isNarrow ? 288 : 320}
|
|
470
|
+
minPrimarySizePx={isNarrow ? 160 : 192}
|
|
471
|
+
minSecondarySizePx={isNarrow ? 200 : 280}
|
|
472
|
+
onPrimarySizePxChange={(nextSize) => {
|
|
473
|
+
setPaletteSizeByLayout((current) => ({ ...current, [layout]: nextSize }));
|
|
474
|
+
}}
|
|
475
|
+
orientation={layout === 'wide' ? 'horizontal' : 'vertical'}
|
|
476
|
+
primary={palette}
|
|
477
|
+
primarySizePx={paletteSizePx}
|
|
478
|
+
primarySizeUnit="pixels"
|
|
479
|
+
secondary={canvasWithDetail}
|
|
480
|
+
/>
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
return (
|
|
484
|
+
<div
|
|
485
|
+
className={
|
|
486
|
+
showConvertPalette
|
|
487
|
+
? 'workbench-field-remap-flow__workspace workbench-field-remap-flow__workspace--split'
|
|
488
|
+
: 'workbench-field-remap-flow__workspace workbench-field-remap-flow__workspace--split workbench-field-remap-flow__workspace--without-palette'
|
|
489
|
+
}
|
|
490
|
+
data-layout={layout}
|
|
491
|
+
data-surface={surface}
|
|
492
|
+
data-testid="field-remap-workspace"
|
|
493
|
+
>
|
|
494
|
+
{content}
|
|
495
|
+
</div>
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
|
|
383
499
|
function FieldRemapFlowCanvas({
|
|
384
500
|
sources,
|
|
385
501
|
targets,
|
|
386
502
|
edges,
|
|
387
503
|
transforms,
|
|
388
504
|
onEdgesChange,
|
|
505
|
+
chrome = 'card',
|
|
506
|
+
emptyDetail: emptyDetailProp,
|
|
507
|
+
showFlowHint: showFlowHintProp,
|
|
508
|
+
showBindingsList: showBindingsListProp,
|
|
509
|
+
showConvertPalette = true,
|
|
389
510
|
operators = [],
|
|
390
511
|
onOperatorsChange,
|
|
391
512
|
sourceTitle,
|
|
392
513
|
targetTitle,
|
|
393
514
|
selection: selectionProp,
|
|
394
515
|
onSelectionChange: onSelectionChangeProp,
|
|
516
|
+
preview,
|
|
517
|
+
showPreview = true,
|
|
395
518
|
showMinimap = true,
|
|
396
519
|
onShowMinimapChange,
|
|
397
520
|
includeHidden = false,
|
|
@@ -407,9 +530,15 @@ function FieldRemapFlowCanvas({
|
|
|
407
530
|
() => resolveFieldRemapChromeLabels(labelOverrides, t),
|
|
408
531
|
[labelOverrides, t],
|
|
409
532
|
);
|
|
533
|
+
const showFlowHint = showFlowHintProp ?? chrome !== 'embed';
|
|
534
|
+
const showBindingsList = showBindingsListProp ?? chrome !== 'embed';
|
|
535
|
+
const emptyDetail = emptyDetailProp ?? (chrome === 'embed' ? 'collapse' : 'hint');
|
|
536
|
+
const mapperRef = useRef<HTMLDivElement>(null);
|
|
537
|
+
const [workspaceLayout, setWorkspaceLayout] = useState<'wide' | 'medium' | 'narrow'>('wide');
|
|
410
538
|
const [internalSelection, setInternalSelection] = useState<FieldRemapSelection>(null);
|
|
411
539
|
const selection = selectionProp !== undefined ? selectionProp : internalSelection;
|
|
412
540
|
const setSelection = onSelectionChangeProp ?? setInternalSelection;
|
|
541
|
+
const previewVisible = showPreview && preview !== undefined && preview.status !== 'unavailable';
|
|
413
542
|
const [drafts, setDrafts] = useState<readonly FieldRemapDraftTransform[]>([]);
|
|
414
543
|
const [placeTransformId, setPlaceTransformId] = useState(() => {
|
|
415
544
|
const first = transforms.list().find((definition) => definition.id !== 'identity');
|
|
@@ -417,6 +546,29 @@ function FieldRemapFlowCanvas({
|
|
|
417
546
|
});
|
|
418
547
|
const transformRegistrySignature = createTransformRegistrySignature(transforms);
|
|
419
548
|
|
|
549
|
+
useEffect(() => {
|
|
550
|
+
const element = mapperRef.current;
|
|
551
|
+
if (!element || typeof ResizeObserver === 'undefined') {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const updateLayout = () => {
|
|
556
|
+
const remSize = Number.parseFloat(getComputedStyle(element).fontSize) || 16;
|
|
557
|
+
const width = element.getBoundingClientRect().width;
|
|
558
|
+
if (width <= 0) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const nextLayout =
|
|
562
|
+
width <= 60 * remSize ? 'narrow' : width <= 68.75 * remSize ? 'medium' : 'wide';
|
|
563
|
+
setWorkspaceLayout((current) => (current === nextLayout ? current : nextLayout));
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
updateLayout();
|
|
567
|
+
const observer = new ResizeObserver(updateLayout);
|
|
568
|
+
observer.observe(element);
|
|
569
|
+
return () => observer.disconnect();
|
|
570
|
+
}, []);
|
|
571
|
+
|
|
420
572
|
const graph = useMemo(
|
|
421
573
|
() =>
|
|
422
574
|
mappingToFlowGraph({
|
|
@@ -746,26 +898,33 @@ function FieldRemapFlowCanvas({
|
|
|
746
898
|
|
|
747
899
|
return (
|
|
748
900
|
<div
|
|
901
|
+
ref={mapperRef}
|
|
749
902
|
className="workbench-field-remap-flow"
|
|
750
903
|
data-testid="field-remap-mapper"
|
|
904
|
+
data-chrome={chrome}
|
|
905
|
+
data-flow-hint={showFlowHint ? 'on' : 'off'}
|
|
906
|
+
data-bindings-list={showBindingsList ? 'on' : 'off'}
|
|
907
|
+
data-convert-palette={showConvertPalette ? 'on' : 'off'}
|
|
908
|
+
data-empty-detail={emptyDetail}
|
|
751
909
|
data-minimap={showMinimap ? 'on' : 'off'}
|
|
752
910
|
data-hidden-fields={includeHidden ? 'on' : 'off'}
|
|
911
|
+
data-preview={previewVisible ? 'on' : 'off'}
|
|
753
912
|
onKeyDown={onKeyDown}
|
|
754
913
|
>
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
914
|
+
{showFlowHint ? (
|
|
915
|
+
<p className="workbench-field-remap-mapper__hint" data-testid="field-remap-hint">
|
|
916
|
+
Convert-first: pick a convert in the palette, place it, then wire source → draft → target.
|
|
917
|
+
Select a convert note for the Convert editor; select a binding for lighter mapping detail.
|
|
918
|
+
Use n→m actions to author combine/split. Alt-click removes a convert step or operator.
|
|
919
|
+
Escape clears selection and unfinished drafts.
|
|
920
|
+
</p>
|
|
921
|
+
) : null}
|
|
761
922
|
|
|
762
|
-
<
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
768
|
-
data-surface={
|
|
923
|
+
<FieldRemapSplitWorkspace
|
|
924
|
+
layout={workspaceLayout}
|
|
925
|
+
showConvertPalette={showConvertPalette}
|
|
926
|
+
showDetail={emptyDetail === 'hint' || selection !== null || previewVisible}
|
|
927
|
+
surface={
|
|
769
928
|
selection?.kind === 'transformStep'
|
|
770
929
|
? 'convert-note'
|
|
771
930
|
: selection?.kind === 'draft'
|
|
@@ -775,31 +934,35 @@ function FieldRemapFlowCanvas({
|
|
|
775
934
|
: 'binding'
|
|
776
935
|
}
|
|
777
936
|
>
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
937
|
+
<>
|
|
938
|
+
{showConvertPalette ? (
|
|
939
|
+
<FieldRemapConvertPalette
|
|
940
|
+
transforms={transforms}
|
|
941
|
+
selectedTransformId={placeTransformId}
|
|
942
|
+
onSelectedTransformIdChange={setPlaceTransformId}
|
|
943
|
+
onPlaceDraft={placeDraft}
|
|
944
|
+
chromeLabels={chromeLabels}
|
|
945
|
+
onAddCombine={
|
|
946
|
+
onOperatorsChange
|
|
947
|
+
? () => {
|
|
948
|
+
const next = createCombineOperator();
|
|
949
|
+
onOperatorsChange([...operators, next]);
|
|
950
|
+
setSelection({ kind: 'operator', operatorId: next.id });
|
|
951
|
+
}
|
|
952
|
+
: undefined
|
|
953
|
+
}
|
|
954
|
+
onAddSplit={
|
|
955
|
+
onOperatorsChange
|
|
956
|
+
? () => {
|
|
957
|
+
const next = createSplitOperator();
|
|
958
|
+
onOperatorsChange([...operators, next]);
|
|
959
|
+
setSelection({ kind: 'operator', operatorId: next.id });
|
|
960
|
+
}
|
|
961
|
+
: undefined
|
|
962
|
+
}
|
|
963
|
+
/>
|
|
964
|
+
) : null}
|
|
965
|
+
</>
|
|
803
966
|
|
|
804
967
|
<div className="workbench-field-remap-flow__canvas" data-testid="field-remap-flow">
|
|
805
968
|
<ReactFlow
|
|
@@ -930,130 +1093,153 @@ function FieldRemapFlowCanvas({
|
|
|
930
1093
|
</ReactFlow>
|
|
931
1094
|
</div>
|
|
932
1095
|
|
|
933
|
-
<
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1096
|
+
<div className="workbench-field-remap-flow__side-rail">
|
|
1097
|
+
{emptyDetail === 'hint' || selection !== null ? (
|
|
1098
|
+
<FieldRemapDetailPanel
|
|
1099
|
+
selection={selection}
|
|
1100
|
+
edges={edges}
|
|
1101
|
+
sources={sources}
|
|
1102
|
+
targets={targets}
|
|
1103
|
+
transforms={transforms}
|
|
1104
|
+
onEdgesChange={onEdgesChange}
|
|
1105
|
+
onSelectionChange={setSelection}
|
|
1106
|
+
drafts={drafts}
|
|
1107
|
+
onDiscardDraft={(localId) => {
|
|
1108
|
+
setDrafts((current) => current.filter((item) => item.localId !== localId));
|
|
1109
|
+
}}
|
|
1110
|
+
operators={operators}
|
|
1111
|
+
onOperatorsChange={onOperatorsChange}
|
|
1112
|
+
emptyDetailTitle={chromeLabels.emptyDetailTitle}
|
|
1113
|
+
emptyDetailDescription={chromeLabels.emptyDetailDescription}
|
|
1114
|
+
/>
|
|
1115
|
+
) : null}
|
|
1116
|
+
{previewVisible && preview ? (
|
|
1117
|
+
<FieldRemapPreviewRail
|
|
1118
|
+
preview={preview}
|
|
1119
|
+
selection={selection}
|
|
1120
|
+
edges={edges}
|
|
1121
|
+
operatorExists={
|
|
1122
|
+
selection?.kind === 'operator'
|
|
1123
|
+
? operators.some((operator) => operator.id === selection.operatorId)
|
|
1124
|
+
: false
|
|
1125
|
+
}
|
|
1126
|
+
labels={chromeLabels}
|
|
1127
|
+
/>
|
|
1128
|
+
) : null}
|
|
1129
|
+
</div>
|
|
1130
|
+
</FieldRemapSplitWorkspace>
|
|
949
1131
|
|
|
950
|
-
|
|
951
|
-
<
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1132
|
+
{showBindingsList ? (
|
|
1133
|
+
<div className="workbench-field-remap-flow__bindings" data-testid="field-remap-edges">
|
|
1134
|
+
<h4>{chromeLabels.bindingsTitle}</h4>
|
|
1135
|
+
<ul>
|
|
1136
|
+
{edges.map((edge) => {
|
|
1137
|
+
const portTypes = edgePortTypes(edge, sources, targets);
|
|
1138
|
+
const appendCatalog = listCompatibleTransforms({
|
|
1139
|
+
registry: transforms,
|
|
1140
|
+
edge,
|
|
1141
|
+
stepIndex: edge.transformIds?.length ?? 0,
|
|
1142
|
+
sourceType: portTypes.sourceType,
|
|
1143
|
+
targetType: portTypes.targetType,
|
|
1144
|
+
mode: 'append',
|
|
1145
|
+
});
|
|
1146
|
+
const defaultAddId = appendCatalog[0]?.id;
|
|
1147
|
+
const listContext = canEditListContext(edge, sources, targets);
|
|
1148
|
+
const selected =
|
|
1149
|
+
(selection?.kind === 'edge' || selection?.kind === 'transformStep') &&
|
|
1150
|
+
selection.edgeId === edge.id;
|
|
968
1151
|
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
>
|
|
975
|
-
<button
|
|
976
|
-
type="button"
|
|
977
|
-
className="workbench-field-remap-flow__binding-select"
|
|
978
|
-
data-testid={`field-remap-select-edge-${edge.id}`}
|
|
979
|
-
onClick={() => setSelection({ kind: 'edge', edgeId: edge.id })}
|
|
1152
|
+
return (
|
|
1153
|
+
<li
|
|
1154
|
+
key={edge.id}
|
|
1155
|
+
className={selected ? 'is-selected' : undefined}
|
|
1156
|
+
data-testid={`field-remap-lane-${edge.id}`}
|
|
980
1157
|
>
|
|
981
|
-
<
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1158
|
+
<button
|
|
1159
|
+
type="button"
|
|
1160
|
+
className="workbench-field-remap-flow__binding-select"
|
|
1161
|
+
data-testid={`field-remap-select-edge-${edge.id}`}
|
|
1162
|
+
onClick={() => setSelection({ kind: 'edge', edgeId: edge.id })}
|
|
1163
|
+
>
|
|
1164
|
+
<code>
|
|
1165
|
+
{edge.sourceFieldId} →{' '}
|
|
1166
|
+
{(edge.transformIds ?? []).length > 0
|
|
1167
|
+
? `${(edge.transformIds ?? []).join(' → ')} → `
|
|
1168
|
+
: ''}
|
|
1169
|
+
{edge.targetSlotId}
|
|
1170
|
+
{edge.itemEdges ? ` · ${edge.itemEdges.length} item fields` : ''}
|
|
1171
|
+
</code>
|
|
1172
|
+
</button>
|
|
1173
|
+
<span className="workbench-field-remap-mapper__edge-actions">
|
|
1174
|
+
{(edge.transformIds?.length ?? 0) < MAX_TRANSFORM_CHAIN && defaultAddId ? (
|
|
1175
|
+
<IconButton
|
|
1176
|
+
compact
|
|
1177
|
+
type="button"
|
|
1178
|
+
data-testid={`field-remap-add-node-${edge.id}`}
|
|
1179
|
+
icon="codicon-add"
|
|
1180
|
+
label={chromeLabels.addTransform}
|
|
1181
|
+
onClick={() => {
|
|
1182
|
+
const next = addTransformStepToEdge(edge, defaultAddId, {
|
|
1183
|
+
registry: transforms,
|
|
1184
|
+
sourceType: portTypes.sourceType,
|
|
1185
|
+
targetType: portTypes.targetType,
|
|
1186
|
+
});
|
|
1187
|
+
if (!next) {
|
|
1188
|
+
return;
|
|
1189
|
+
}
|
|
1190
|
+
onEdgesChange(edges.map((item) => (item.id === edge.id ? next : item)));
|
|
1191
|
+
setSelection({
|
|
1192
|
+
kind: 'transformStep',
|
|
1193
|
+
edgeId: edge.id,
|
|
1194
|
+
stepIndex: (next.transformIds?.length ?? 1) - 1,
|
|
1195
|
+
});
|
|
1196
|
+
}}
|
|
1197
|
+
/>
|
|
1198
|
+
) : null}
|
|
1199
|
+
{listContext ? (
|
|
1200
|
+
<IconButton
|
|
1201
|
+
compact
|
|
1202
|
+
type="button"
|
|
1203
|
+
data-testid={`field-remap-edit-items-${edge.id}`}
|
|
1204
|
+
icon="codicon-edit"
|
|
1205
|
+
label={chromeLabels.editItems}
|
|
1206
|
+
onClick={() => {
|
|
1207
|
+
if (!edge.itemEdges) {
|
|
1208
|
+
onEdgesChange(
|
|
1209
|
+
edges.map((item) =>
|
|
1210
|
+
item.id === edge.id ? enableListContextOnEdge(item) : item,
|
|
1211
|
+
),
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
setSelection({ kind: 'edge', edgeId: edge.id });
|
|
1215
|
+
}}
|
|
1216
|
+
/>
|
|
1217
|
+
) : null}
|
|
1218
|
+
<IconButton
|
|
1018
1219
|
compact
|
|
1019
1220
|
type="button"
|
|
1020
|
-
data-testid={`field-remap-
|
|
1221
|
+
data-testid={`field-remap-remove-edge-${edge.id}`}
|
|
1222
|
+
icon="codicon-trash"
|
|
1223
|
+
label={chromeLabels.removeBinding}
|
|
1224
|
+
variant="danger"
|
|
1021
1225
|
onClick={() => {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1226
|
+
onEdgesChange(edges.filter((item) => item.id !== edge.id));
|
|
1227
|
+
if (
|
|
1228
|
+
selection &&
|
|
1229
|
+
(selection.kind === 'edge' || selection.kind === 'transformStep') &&
|
|
1230
|
+
selection.edgeId === edge.id
|
|
1231
|
+
) {
|
|
1232
|
+
setSelection(null);
|
|
1028
1233
|
}
|
|
1029
|
-
setSelection({ kind: 'edge', edgeId: edge.id });
|
|
1030
1234
|
}}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
onEdgesChange(edges.filter((item) => item.id !== edge.id));
|
|
1040
|
-
if (
|
|
1041
|
-
selection &&
|
|
1042
|
-
(selection.kind === 'edge' || selection.kind === 'transformStep') &&
|
|
1043
|
-
selection.edgeId === edge.id
|
|
1044
|
-
) {
|
|
1045
|
-
setSelection(null);
|
|
1046
|
-
}
|
|
1047
|
-
}}
|
|
1048
|
-
>
|
|
1049
|
-
Remove
|
|
1050
|
-
</Button>
|
|
1051
|
-
</span>
|
|
1052
|
-
</li>
|
|
1053
|
-
);
|
|
1054
|
-
})}
|
|
1055
|
-
</ul>
|
|
1056
|
-
</div>
|
|
1235
|
+
/>
|
|
1236
|
+
</span>
|
|
1237
|
+
</li>
|
|
1238
|
+
);
|
|
1239
|
+
})}
|
|
1240
|
+
</ul>
|
|
1241
|
+
</div>
|
|
1242
|
+
) : null}
|
|
1057
1243
|
</div>
|
|
1058
1244
|
);
|
|
1059
1245
|
}
|