@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,59 @@
|
|
|
1
|
+
import type { MappingEdge } from '@workbench-kit/field-remap';
|
|
2
|
+
import type { FieldItemInput, Mapping } from 'react-table-mapping';
|
|
3
|
+
|
|
4
|
+
/** One column: field name (static string cell). */
|
|
5
|
+
export const FIELD_REMAP_NAME_COLUMNS = [{ title: 'Field', key: 'name' }] as const;
|
|
6
|
+
|
|
7
|
+
export interface FieldRemapLeaf {
|
|
8
|
+
/** Kit field/slot id (may contain dots, e.g. `a.user_name`). */
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* react-table-mapping builds connectors with `querySelector('#connector-…'+id)`.
|
|
15
|
+
* Dots in ids break CSS selectors (`#a.user_name` → id=a + class=user_name).
|
|
16
|
+
* Encode kit ids for the OSS UI and decode when adapting mappings.
|
|
17
|
+
*/
|
|
18
|
+
export function toTableMappingFieldId(kitFieldId: string): string {
|
|
19
|
+
return kitFieldId.split('.').join('__');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function fromTableMappingFieldId(tableFieldId: string): string {
|
|
23
|
+
return tableFieldId.split('__').join('.');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Build react-table-mapping source/target rows from leaf field descriptors. */
|
|
27
|
+
export function toTableMappingFields(leaves: readonly FieldRemapLeaf[]): FieldItemInput[] {
|
|
28
|
+
return leaves.map((leaf) => {
|
|
29
|
+
const id = toTableMappingFieldId(leaf.id);
|
|
30
|
+
return {
|
|
31
|
+
id,
|
|
32
|
+
key: id,
|
|
33
|
+
name: {
|
|
34
|
+
type: 'string' as const,
|
|
35
|
+
columnKey: 'name',
|
|
36
|
+
value: leaf.label,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** OSS Mapping[] → kit MappingEdge[] (identity / pass-through). */
|
|
43
|
+
export function tableMappingsToEdges(mappings: readonly Mapping[]): MappingEdge[] {
|
|
44
|
+
return mappings.map((mapping) => ({
|
|
45
|
+
id: mapping.id,
|
|
46
|
+
sourceFieldId: fromTableMappingFieldId(mapping.source),
|
|
47
|
+
targetSlotId: fromTableMappingFieldId(mapping.target),
|
|
48
|
+
transformIds: ['identity'] as const,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** kit MappingEdge[] → OSS Mapping[] for controlled mappings. */
|
|
53
|
+
export function edgesToTableMappings(edges: readonly MappingEdge[]): Mapping[] {
|
|
54
|
+
return edges.map((edge) => ({
|
|
55
|
+
id: edge.id,
|
|
56
|
+
source: toTableMappingFieldId(edge.sourceFieldId),
|
|
57
|
+
target: toTableMappingFieldId(edge.targetSlotId),
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { useEffect, useId, useState, type JSX } from 'react';
|
|
2
|
+
import { Button } from '@workbench-kit/react/primitives';
|
|
3
|
+
import type { TransformOptionField } from '@workbench-kit/field-remap';
|
|
4
|
+
|
|
5
|
+
export interface TransformOptionsEditorProps {
|
|
6
|
+
readonly fields: readonly TransformOptionField[];
|
|
7
|
+
readonly value: Readonly<Record<string, unknown>>;
|
|
8
|
+
readonly onChange: (next: Record<string, unknown>) => void;
|
|
9
|
+
readonly disabled?: boolean | undefined;
|
|
10
|
+
/** Prefix for stable test ids (`field-remap-option-<key>`). */
|
|
11
|
+
readonly testIdPrefix?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function asStringMap(value: unknown): Record<string, string> {
|
|
15
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
const next: Record<string, string> = {};
|
|
19
|
+
for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {
|
|
20
|
+
if (typeof entry === 'string') {
|
|
21
|
+
next[key] = entry;
|
|
22
|
+
} else if (entry !== undefined && entry !== null) {
|
|
23
|
+
next[key] = String(entry);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return next;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function StringMapEditor({
|
|
30
|
+
field,
|
|
31
|
+
value,
|
|
32
|
+
disabled,
|
|
33
|
+
onChange,
|
|
34
|
+
testId,
|
|
35
|
+
}: {
|
|
36
|
+
readonly field: TransformOptionField;
|
|
37
|
+
readonly value: unknown;
|
|
38
|
+
readonly disabled: boolean;
|
|
39
|
+
readonly onChange: (next: Record<string, string>) => void;
|
|
40
|
+
readonly testId: string;
|
|
41
|
+
}): JSX.Element {
|
|
42
|
+
const map = asStringMap(value);
|
|
43
|
+
const rows = Object.entries(map);
|
|
44
|
+
const [draftKey, setDraftKey] = useState('');
|
|
45
|
+
const [draftValue, setDraftValue] = useState('');
|
|
46
|
+
|
|
47
|
+
const commitRow = (key: string, entryValue: string, previousKey?: string) => {
|
|
48
|
+
const trimmedKey = key.trim();
|
|
49
|
+
const next = { ...map };
|
|
50
|
+
if (previousKey && previousKey !== trimmedKey) {
|
|
51
|
+
delete next[previousKey];
|
|
52
|
+
}
|
|
53
|
+
if (!trimmedKey) {
|
|
54
|
+
onChange(next);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
next[trimmedKey] = entryValue;
|
|
58
|
+
onChange(next);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className="workbench-field-remap-options__string-map" data-testid={testId}>
|
|
63
|
+
<ul className="workbench-field-remap-options__string-map-rows">
|
|
64
|
+
{rows.map(([key, entryValue]) => (
|
|
65
|
+
<li key={key}>
|
|
66
|
+
<input
|
|
67
|
+
type="text"
|
|
68
|
+
aria-label={`${field.label} key`}
|
|
69
|
+
disabled={disabled}
|
|
70
|
+
value={key}
|
|
71
|
+
onChange={(event) => commitRow(event.target.value, entryValue, key)}
|
|
72
|
+
/>
|
|
73
|
+
<input
|
|
74
|
+
type="text"
|
|
75
|
+
aria-label={`${field.label} value for ${key}`}
|
|
76
|
+
disabled={disabled}
|
|
77
|
+
value={entryValue}
|
|
78
|
+
onChange={(event) => commitRow(key, event.target.value, key)}
|
|
79
|
+
/>
|
|
80
|
+
<Button
|
|
81
|
+
compact
|
|
82
|
+
type="button"
|
|
83
|
+
disabled={disabled}
|
|
84
|
+
aria-label={`Remove ${key}`}
|
|
85
|
+
onClick={() => {
|
|
86
|
+
const next = { ...map };
|
|
87
|
+
delete next[key];
|
|
88
|
+
onChange(next);
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
×
|
|
92
|
+
</Button>
|
|
93
|
+
</li>
|
|
94
|
+
))}
|
|
95
|
+
</ul>
|
|
96
|
+
<div className="workbench-field-remap-options__string-map-add">
|
|
97
|
+
<input
|
|
98
|
+
type="text"
|
|
99
|
+
aria-label={`New ${field.label} key`}
|
|
100
|
+
disabled={disabled}
|
|
101
|
+
placeholder="Key"
|
|
102
|
+
value={draftKey}
|
|
103
|
+
onChange={(event) => setDraftKey(event.target.value)}
|
|
104
|
+
/>
|
|
105
|
+
<input
|
|
106
|
+
type="text"
|
|
107
|
+
aria-label={`New ${field.label} value`}
|
|
108
|
+
disabled={disabled}
|
|
109
|
+
placeholder="Value"
|
|
110
|
+
value={draftValue}
|
|
111
|
+
onChange={(event) => setDraftValue(event.target.value)}
|
|
112
|
+
/>
|
|
113
|
+
<Button
|
|
114
|
+
compact
|
|
115
|
+
type="button"
|
|
116
|
+
disabled={disabled || !draftKey.trim()}
|
|
117
|
+
onClick={() => {
|
|
118
|
+
commitRow(draftKey, draftValue);
|
|
119
|
+
setDraftKey('');
|
|
120
|
+
setDraftValue('');
|
|
121
|
+
}}
|
|
122
|
+
>
|
|
123
|
+
Add
|
|
124
|
+
</Button>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function JsonOptionEditor({
|
|
131
|
+
field,
|
|
132
|
+
value,
|
|
133
|
+
disabled,
|
|
134
|
+
onChange,
|
|
135
|
+
testId,
|
|
136
|
+
}: {
|
|
137
|
+
readonly field: TransformOptionField;
|
|
138
|
+
readonly value: unknown;
|
|
139
|
+
readonly disabled: boolean;
|
|
140
|
+
readonly onChange: (next: unknown) => void;
|
|
141
|
+
readonly testId: string;
|
|
142
|
+
}): JSX.Element {
|
|
143
|
+
const [draft, setDraft] = useState(() =>
|
|
144
|
+
value === undefined ? '' : JSON.stringify(value, null, 2),
|
|
145
|
+
);
|
|
146
|
+
const [error, setError] = useState<string | undefined>();
|
|
147
|
+
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
setDraft(value === undefined ? '' : JSON.stringify(value, null, 2));
|
|
150
|
+
setError(undefined);
|
|
151
|
+
}, [value]);
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<div className="workbench-field-remap-options__json">
|
|
155
|
+
<textarea
|
|
156
|
+
aria-label={field.label}
|
|
157
|
+
data-testid={testId}
|
|
158
|
+
disabled={disabled}
|
|
159
|
+
rows={5}
|
|
160
|
+
value={draft}
|
|
161
|
+
onChange={(event) => {
|
|
162
|
+
setDraft(event.target.value);
|
|
163
|
+
setError(undefined);
|
|
164
|
+
}}
|
|
165
|
+
onBlur={(event) => {
|
|
166
|
+
// Read from the DOM so blur after a same-tick edit is not stale.
|
|
167
|
+
const trimmed = event.currentTarget.value.trim();
|
|
168
|
+
if (!trimmed) {
|
|
169
|
+
setError(undefined);
|
|
170
|
+
onChange(undefined);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
const parsed: unknown = JSON.parse(trimmed);
|
|
175
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
176
|
+
setError('JSON must be a plain object.');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
setError(undefined);
|
|
180
|
+
setDraft(JSON.stringify(parsed, null, 2));
|
|
181
|
+
onChange(parsed);
|
|
182
|
+
} catch {
|
|
183
|
+
setError('Invalid JSON.');
|
|
184
|
+
}
|
|
185
|
+
}}
|
|
186
|
+
/>
|
|
187
|
+
{error ? (
|
|
188
|
+
<p className="workbench-field-remap-options__error" role="alert">
|
|
189
|
+
{error}
|
|
190
|
+
</p>
|
|
191
|
+
) : null}
|
|
192
|
+
</div>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Presentational editor for `TransformOptionField` kinds (string / number / boolean /
|
|
198
|
+
* stringMap / json). Emits a full options record; callers typically pass through
|
|
199
|
+
* `patchOptionStep` / `sanitizeOptionRecord`.
|
|
200
|
+
*/
|
|
201
|
+
export function TransformOptionsEditor({
|
|
202
|
+
fields,
|
|
203
|
+
value,
|
|
204
|
+
onChange,
|
|
205
|
+
disabled = false,
|
|
206
|
+
testIdPrefix = 'field-remap-option',
|
|
207
|
+
}: TransformOptionsEditorProps): JSX.Element {
|
|
208
|
+
const baseId = useId();
|
|
209
|
+
|
|
210
|
+
if (fields.length === 0) {
|
|
211
|
+
return (
|
|
212
|
+
<p className="workbench-field-remap-options__empty" data-testid={`${testIdPrefix}-empty`}>
|
|
213
|
+
No options for this transform.
|
|
214
|
+
</p>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const setKey = (key: string, nextValue: unknown) => {
|
|
219
|
+
const next: Record<string, unknown> = { ...value };
|
|
220
|
+
if (nextValue === undefined) {
|
|
221
|
+
delete next[key];
|
|
222
|
+
} else {
|
|
223
|
+
next[key] = nextValue;
|
|
224
|
+
}
|
|
225
|
+
onChange(next);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<div className="workbench-field-remap-options" data-testid={`${testIdPrefix}-editor`}>
|
|
230
|
+
{fields.map((field) => {
|
|
231
|
+
const controlId = `${baseId}-${field.key}`;
|
|
232
|
+
const testId = `${testIdPrefix}-${field.key}`;
|
|
233
|
+
const current = value[field.key];
|
|
234
|
+
|
|
235
|
+
return (
|
|
236
|
+
<label
|
|
237
|
+
key={field.key}
|
|
238
|
+
className="workbench-field-remap-options__field"
|
|
239
|
+
htmlFor={field.kind === 'boolean' ? controlId : undefined}
|
|
240
|
+
>
|
|
241
|
+
<span className="workbench-field-remap-options__label">{field.label}</span>
|
|
242
|
+
{field.kind === 'string' ? (
|
|
243
|
+
<input
|
|
244
|
+
id={controlId}
|
|
245
|
+
type="text"
|
|
246
|
+
data-testid={testId}
|
|
247
|
+
disabled={disabled}
|
|
248
|
+
aria-label={field.label}
|
|
249
|
+
value={
|
|
250
|
+
typeof current === 'string' ? current : current == null ? '' : String(current)
|
|
251
|
+
}
|
|
252
|
+
onChange={(event) => setKey(field.key, event.target.value)}
|
|
253
|
+
/>
|
|
254
|
+
) : null}
|
|
255
|
+
{field.kind === 'number' ? (
|
|
256
|
+
<input
|
|
257
|
+
id={controlId}
|
|
258
|
+
type="number"
|
|
259
|
+
data-testid={testId}
|
|
260
|
+
disabled={disabled}
|
|
261
|
+
aria-label={field.label}
|
|
262
|
+
value={typeof current === 'number' ? current : ''}
|
|
263
|
+
onChange={(event) => {
|
|
264
|
+
const raw = event.target.value;
|
|
265
|
+
if (raw === '') {
|
|
266
|
+
setKey(field.key, undefined);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const parsed = Number(raw);
|
|
270
|
+
if (Number.isFinite(parsed)) {
|
|
271
|
+
setKey(field.key, parsed);
|
|
272
|
+
}
|
|
273
|
+
}}
|
|
274
|
+
/>
|
|
275
|
+
) : null}
|
|
276
|
+
{field.kind === 'boolean' ? (
|
|
277
|
+
<input
|
|
278
|
+
id={controlId}
|
|
279
|
+
type="checkbox"
|
|
280
|
+
data-testid={testId}
|
|
281
|
+
disabled={disabled}
|
|
282
|
+
aria-label={field.label}
|
|
283
|
+
checked={Boolean(current)}
|
|
284
|
+
onChange={(event) => setKey(field.key, event.target.checked)}
|
|
285
|
+
/>
|
|
286
|
+
) : null}
|
|
287
|
+
{field.kind === 'stringMap' ? (
|
|
288
|
+
<StringMapEditor
|
|
289
|
+
field={field}
|
|
290
|
+
value={current}
|
|
291
|
+
disabled={disabled}
|
|
292
|
+
testId={testId}
|
|
293
|
+
onChange={(next) =>
|
|
294
|
+
setKey(field.key, Object.keys(next).length > 0 ? next : undefined)
|
|
295
|
+
}
|
|
296
|
+
/>
|
|
297
|
+
) : null}
|
|
298
|
+
{field.kind === 'json' ? (
|
|
299
|
+
<JsonOptionEditor
|
|
300
|
+
field={field}
|
|
301
|
+
value={current}
|
|
302
|
+
disabled={disabled}
|
|
303
|
+
testId={testId}
|
|
304
|
+
onChange={(next) => setKey(field.key, next)}
|
|
305
|
+
/>
|
|
306
|
+
) : null}
|
|
307
|
+
</label>
|
|
308
|
+
);
|
|
309
|
+
})}
|
|
310
|
+
</div>
|
|
311
|
+
);
|
|
312
|
+
}
|