@workbench-kit/react 0.0.2-prototype.0.2.4 → 0.0.2-prototype.0.2.40
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 +172 -0
- package/package.json +38 -21
- package/src/index.ts +74 -34
- package/src/jdw/JsonCodeEditorPane.tsx +7 -6
- package/src/jdw/builtins/renderBuiltinWidgetLeaf.tsx +1 -3
- package/src/jdw/createBuiltinJdwRegistry.ts +1 -4
- package/src/jdw/cssRenderBackend.tsx +1 -4
- package/src/jdw/fixtures/jdw-fixtures.ts +0 -15
- package/src/json-config/JsonConfigWorkbench.tsx +1 -1
- package/src/layout/index.ts +11 -2
- package/src/layout/panel/Panel.tsx +0 -3
- package/src/layout/panel/index.ts +0 -2
- package/src/layout/sidebar/SideBarTree.tsx +301 -0
- package/src/layout/sidebar/SidebarActionIconBar.tsx +3 -3
- package/src/layout/sidebar/WorkbenchSidebarActions.tsx +1 -1
- package/src/layout/sidebar/index.ts +13 -0
- package/src/modal/Modal.tsx +55 -25
- package/src/modal/ModalTitlebar.tsx +8 -8
- package/src/modal/modalPosition.ts +3 -6
- package/src/modal/useModalFocusTrap.ts +142 -0
- package/src/modal/useModalWindowFrame.ts +2 -2
- package/src/overlay/ContextMenu.tsx +133 -21
- package/src/overlay/context-menu-density.css +22 -0
- package/src/overlay/context-menu-item.ts +17 -0
- package/src/overlay/context-menu.css +6 -2
- package/src/overlay/index.ts +6 -1
- package/src/overlay/measureAnchoredOverlayPanel.ts +4 -6
- package/src/overlay/pointerPassthroughRegion.ts +17 -1
- package/src/overlay/usePointerPassthroughRegion.ts +35 -6
- package/src/primitives/absolute-box/AbsoluteBox.tsx +4 -4
- package/src/primitives/app-icon/AppIcon.tsx +33 -0
- package/src/primitives/app-icon/app-icon.css +28 -0
- package/src/primitives/button/Button.tsx +4 -4
- package/src/primitives/catalog-browse-card/CatalogBrowseCard.tsx +6 -6
- package/src/primitives/catalog-browse-pane/CatalogBrowsePane.tsx +39 -32
- package/src/primitives/catalog-browse-pane/catalog-browse-pane.css +4 -0
- package/src/primitives/catalog-filter-overlay/CatalogFilterOverlay.tsx +2 -2
- package/src/primitives/checkbox/Checkbox.tsx +1 -1
- package/src/primitives/chip/Chip.tsx +3 -12
- package/src/primitives/chip/index.ts +2 -2
- package/src/primitives/codicon/Codicon.tsx +1 -1
- package/src/primitives/file-icon/FileIcon.tsx +1 -1
- package/src/primitives/icon-button/IconButton.tsx +1 -1
- package/src/primitives/index.ts +7 -2
- package/src/primitives/library-detail-layout/LibraryDetailLayout.tsx +123 -9
- package/src/primitives/library-detail-layout/library-detail-layout.css +57 -0
- package/src/primitives/library-detail-layout/resolve-hero-cover-media.ts +80 -0
- package/src/primitives/library-facet-filter-panel/LibraryFacetFilterPanel.tsx +12 -12
- package/src/primitives/library-facet-filter-strip/LibraryFacetFilterStrip.tsx +4 -4
- package/src/primitives/number-input/NumberInput.tsx +5 -5
- package/src/primitives/primitives.css +1 -0
- package/src/primitives/record-media-hero/RecordMediaHero.tsx +10 -6
- package/src/primitives/scroll-area/ScrollArea.tsx +5 -5
- package/src/primitives/scroll-area-infinite-load/useScrollAreaInfiniteLoad.ts +5 -5
- package/src/primitives/searchable-multi-select/SearchableMultiSelect.tsx +7 -7
- package/src/primitives/select/Select.tsx +1 -13
- package/src/primitives/text-area/TextArea.tsx +1 -1
- package/src/primitives/text-input/TextInput.tsx +1 -1
- package/src/primitives/workbench-media-slot/WorkbenchMediaPlaceholder.tsx +2 -2
- package/src/primitives/workbench-media-slot/WorkbenchMediaSlot.tsx +16 -10
- package/src/primitives/workbench-thumbnail/WorkbenchThumbnail.tsx +4 -4
- package/src/scrollbars.css +2 -6
- package/src/styles/core.css +16 -0
- package/src/styles/foundation.css +4 -0
- package/src/styles/overlay.css +2 -0
- package/src/styles.css +1 -15
- package/src/utils/clamp.ts +4 -0
- package/src/utils/normalizeKeyToken.ts +13 -0
- package/src/utils/readNumber.ts +4 -0
- package/src/widget-tree/WidgetSourceEditor.tsx +0 -14
- package/src/widget-tree/WidgetTreeCanvasPreview.tsx +3 -10
- package/src/widget-tree/WidgetTreeLab.tsx +2 -23
- package/src/widget-tree/WidgetTreeSidePanel.tsx +0 -5
- package/src/widget-tree/WidgetTreeWorkspaceShell.tsx +2 -2
- package/src/widget-tree/index.ts +1 -5
- package/src/workbench/auth/WorkbenchLoginView.tsx +1 -2
- package/src/workbench/auth/auth-flows.css +14 -0
- package/src/workbench/chat/ChatCommandProposalCard.tsx +4 -4
- package/src/workbench/chat/ChatConversationBar.tsx +3 -3
- package/src/workbench/chat/ChatHistoryMenu.tsx +1 -1
- package/src/workbench/chat/ChatMessageCollapsible.tsx +4 -0
- package/src/workbench/chat/ChatMessageItem.tsx +68 -10
- package/src/workbench/chat/ChatMessageList.tsx +1 -1
- package/src/workbench/chat/ChatPanel.tsx +32 -23
- package/src/workbench/chat/ChatPhasedRunProgress.tsx +86 -13
- package/src/workbench/chat/ChatRenameDialog.tsx +1 -1
- package/src/workbench/chat/chat-conversation.css +2 -2
- package/src/workbench/chat/chat-ui.css +8 -0
- package/src/workbench/chat/chatConversation.ts +2 -2
- package/src/workbench/chat/chatMessageMeta.tsx +4 -4
- package/src/workbench/chat/index.ts +1 -0
- package/src/workbench/chat/types.ts +7 -7
- package/src/workbench/chat/useCancelRuntimeOnUnmount.ts +4 -4
- package/src/workbench/chat/useChatPrependPagination.ts +10 -10
- package/src/workbench/chat/useSlashCommandSuggest.ts +1 -1
- package/src/workbench/{WorkbenchModalPortal.tsx → chrome/WorkbenchModalPortal.tsx} +1 -1
- package/src/workbench/chrome/workbench-chrome.css +4 -0
- package/src/workbench/chrome/workbench-layout-regions.css +13 -0
- package/src/workbench/chrome/workbench-shell-titlebar.css +0 -8
- package/src/workbench/{CommandGroupShell.tsx → commands/CommandGroupShell.tsx} +2 -2
- package/src/workbench/{CommandList.tsx → commands/CommandList.tsx} +6 -5
- package/src/workbench/{CommandPalette.tsx → commands/CommandPalette.tsx} +16 -42
- package/src/workbench/{ConfirmationFlow.tsx → commands/ConfirmationFlow.tsx} +5 -5
- package/src/workbench/{ShortcutCommandBridge.tsx → commands/ShortcutCommandBridge.tsx} +17 -13
- package/src/workbench/commands/WorkbenchQuickOpen.tsx +462 -0
- package/src/workbench/{command-model.ts → commands/command-model.ts} +5 -1
- package/src/workbench/commands/command-ui.ts +3 -0
- package/src/workbench/{commands.ts → commands/commands.ts} +45 -1
- package/src/workbench/commands/createWorkspaceFilesQuickOpenProvider.ts +86 -0
- package/src/workbench/commands/quick-open-model.ts +66 -0
- package/src/workbench/{WorkbenchEditorTabs.tsx → editor/WorkbenchEditorTabs.tsx} +13 -3
- package/src/workbench/{editor-tabs-dnd.ts → editor/editor-tabs-dnd.ts} +1 -1
- package/src/workbench/{editorTabContextMenu.ts → editor/editorTabContextMenu.ts} +43 -4
- package/src/workbench/{useEditorTabsStripDnd.ts → editor/useEditorTabsStripDnd.ts} +1 -1
- package/src/workbench/{useWorkbenchEditorTabContextMenu.tsx → editor/useWorkbenchEditorTabContextMenu.tsx} +16 -2
- package/src/workbench/editor-tabs/index.ts +10 -9
- package/src/workbench/index.ts +114 -74
- package/src/workbench/management/CommandManagementSidebar.tsx +16 -30
- package/src/workbench/management/ExtensionManagementPanel.tsx +84 -46
- package/src/workbench/management/ExtensionManagementSidebar.tsx +79 -45
- package/src/workbench/management/IntegrationCommandActions.tsx +8 -1
- package/src/workbench/management/IntegrationSettingsSurface.tsx +2 -5
- package/src/workbench/management/IntegrationsShell.tsx +1 -1
- package/src/workbench/management/KeybindingCaptureField.tsx +1 -9
- package/src/workbench/management/WorkbenchDialogFrame.tsx +2 -2
- package/src/workbench/management/WorkbenchNotice.tsx +17 -12
- package/src/workbench/management/createWorkbenchNotify.tsx +88 -0
- package/src/workbench/management/extension-install-approval.ts +72 -0
- package/src/workbench/management/extension-management-filters.ts +38 -0
- package/src/workbench/management/index.ts +18 -3
- package/src/workbench/management/management.css +28 -0
- package/src/workbench/management/types.ts +23 -1
- package/src/workbench/management/useWorkbenchNotify.ts +10 -0
- package/src/workbench/{MarkdownPreview.tsx → markdown/MarkdownPreview.tsx} +22 -7
- package/src/workbench/markdown/markdownRemarkPlugins.ts +12 -0
- package/src/workbench/markdown/sanitizeMarkdownHref.ts +29 -0
- package/src/workbench/schema/workbenchDocumentRenderer.tsx +48 -121
- package/src/workbench/settings/StructuredDataForm.tsx +1 -4
- package/src/workbench/settings/StructuredDataSchemaPanel.tsx +39 -44
- package/src/workbench/settings/sectionedPanelScrollSpy.ts +0 -81
- package/src/workbench/settings/structuredDataFormModel.ts +2 -1
- package/src/workbench/settings/structuredDataSchema.ts +24 -13
- package/src/workbench/settings/structuredDataSchemaSection.ts +4 -0
- package/src/workbench/settings/structuredDataSchemaTable.ts +5 -2
- package/src/workbench/{ActivityBar.tsx → shell/ActivityBar.tsx} +8 -12
- package/src/workbench/{ArtifactShell.tsx → shell/ArtifactShell.tsx} +25 -25
- package/src/workbench/{SplitView.tsx → shell/SplitView.tsx} +3 -3
- package/src/workbench/{StatusBar.tsx → shell/StatusBar.tsx} +8 -8
- package/src/workbench/{StructuredArtifactEditor.tsx → shell/StructuredArtifactEditor.tsx} +9 -9
- package/src/workbench/{Timeline.tsx → shell/Timeline.tsx} +77 -20
- package/src/workbench/{WorkbenchCanvasShell.defaults.ts → shell/WorkbenchCanvasShell.defaults.ts} +1 -1
- package/src/workbench/{WorkbenchCanvasShell.model.ts → shell/WorkbenchCanvasShell.model.ts} +5 -5
- package/src/workbench/{WorkbenchCanvasShell.tsx → shell/WorkbenchCanvasShell.tsx} +6 -6
- package/src/workbench/{WorkbenchDesktopTitleBar.tsx → shell/WorkbenchDesktopTitleBar.tsx} +15 -15
- package/src/workbench/{WorkbenchShell.tsx → shell/WorkbenchShell.tsx} +45 -6
- package/src/workbench/{WorkbenchShellTitleBarLayoutControls.tsx → shell/WorkbenchShellTitleBarLayoutControls.tsx} +16 -19
- package/src/workbench/{WorkbenchStandaloneShell.tsx → shell/WorkbenchStandaloneShell.tsx} +15 -22
- package/src/workbench/{WorkbenchViewEditor.tsx → shell/WorkbenchViewEditor.tsx} +7 -7
- package/src/workbench/{WorkbenchViewSidebar.tsx → shell/WorkbenchViewSidebar.tsx} +7 -7
- package/src/workbench/{WorkbenchWindowChromeControls.tsx → shell/WorkbenchWindowChromeControls.tsx} +18 -15
- package/src/workbench/shell/activity-bar.css +47 -0
- package/src/workbench/{activityBarOrder.ts → shell/activityBarOrder.ts} +2 -1
- package/src/workbench/{shell.ts → shell/shell.ts} +20 -13
- package/src/workbench/{shellViewModel.ts → shell/shellViewModel.ts} +3 -3
- package/src/workbench/{standalone.ts → shell/standalone.ts} +14 -2
- package/src/workbench/{useDeferredWorkbenchMount.ts → shell/useDeferredWorkbenchMount.ts} +3 -3
- package/src/workbench/{useWorkbenchAppearanceDocumentSync.tsx → shell/useWorkbenchAppearanceDocumentSync.tsx} +1 -1
- package/src/workbench/{useWorkbenchSidebarActionBarDnd.ts → shell/useWorkbenchSidebarActionBarDnd.ts} +1 -1
- package/src/workbench/{useWorkbenchSidebarViewPlacementDropZone.ts → shell/useWorkbenchSidebarViewPlacementDropZone.ts} +2 -2
- package/src/workbench/{workbenchSidebarLayoutContext.ts → shell/workbenchSidebarLayoutContext.ts} +0 -6
- package/src/workbench/{workbenchViewRouteState.ts → shell/workbenchViewRouteState.ts} +4 -4
- package/src/workbench/{WorkbenchThemeProvider.tsx → theme/WorkbenchThemeProvider.tsx} +4 -4
- package/src/workbench/{theme.ts → theme/theme.ts} +1 -1
- package/src/workbench/{themePresets.ts → theme/themePresets.ts} +3 -2
- package/src/workbench/views/command-list-density.css +36 -0
- package/src/workbench/views/command-list.css +2 -0
- package/src/workbench/views/extensions-sidebar.css +2 -0
- package/src/workbench/views/view-hosts.css +3 -3
- package/src/workbench/workspace/WorkspaceEditorPanel.tsx +1 -1
- package/src/workbench/workspace/WorkspaceExplorer.tsx +105 -4
- package/src/workbench/workspace/createVirtualWorkspaceExplorerPort.ts +1 -14
- package/src/workbench/workspace/workspaceExplorerKeyboard.ts +109 -0
- package/src/workbench/workspace/workspaceJsonDiagnostics.ts +6 -5
- package/src/workbench-menu-surfaces.css +3 -57
- package/src/brand/TilepaperAppIcon.tsx +0 -181
- package/src/brand/index.ts +0 -2
- package/src/brand/tilepaper-app-icon-geometry.ts +0 -201
- package/src/primitives/absolute-box/index.ts +0 -1
- package/src/primitives/catalog-browse-card/index.ts +0 -1
- package/src/primitives/catalog-browse-pane/index.ts +0 -3
- package/src/primitives/catalog-filter-overlay/index.ts +0 -1
- package/src/primitives/codicon/index.ts +0 -1
- package/src/primitives/external-link-button/index.ts +0 -1
- package/src/primitives/library-detail-layout/index.ts +0 -1
- package/src/primitives/library-facet-filter-panel/index.ts +0 -1
- package/src/primitives/library-facet-filter-strip/index.ts +0 -1
- package/src/primitives/panel-loading/index.ts +0 -1
- package/src/primitives/scroll-area-infinite-load/index.ts +0 -2
- package/src/primitives/workbench-thumbnail/index.ts +0 -1
- package/src/test-utils/workbenchMonacoMock.tsx +0 -37
- package/src/workbench/jdw/jdw-editors.css +0 -4
- package/src/workbench/jdw/jdw.css +0 -2
- package/src/workbench/management/integration-command-action.ts +0 -25
- package/src/workbench/markdownRemarkPlugins.ts +0 -4
- package/src/workbench/workbench-chrome.css +0 -4
- /package/src/workbench/{WorkbenchPlatformContext.tsx → chrome/WorkbenchPlatformContext.tsx} +0 -0
- /package/src/workbench/{workbenchModalViewState.ts → chrome/workbenchModalViewState.ts} +0 -0
- /package/src/workbench/{workbenchOverlaysContext.tsx → chrome/workbenchOverlaysContext.tsx} +0 -0
- /package/src/workbench/{workbenchPlatformChrome.ts → chrome/workbenchPlatformChrome.ts} +0 -0
- /package/src/workbench/{command-execution-policy.ts → commands/command-execution-policy.ts} +0 -0
- /package/src/workbench/{keyboard.ts → commands/keyboard.ts} +0 -0
- /package/src/workbench/{workbenchContextMenu.ts → commands/workbenchContextMenu.ts} +0 -0
- /package/src/workbench/{appearanceLabels.ts → shell/appearanceLabels.ts} +0 -0
- /package/src/workbench/{hardReset.ts → shell/hardReset.ts} +0 -0
- /package/src/workbench/{shellPresets.ts → shell/shellPresets.ts} +0 -0
- /package/src/workbench/{shellState.ts → shell/shellState.ts} +0 -0
- /package/src/workbench/{sidebarViewPlacementDnd.ts → shell/sidebarViewPlacementDnd.ts} +0 -0
- /package/src/workbench/{status.ts → shell/status.ts} +0 -0
- /package/src/workbench/{useWorkbenchSidebarLayout.tsx → shell/useWorkbenchSidebarLayout.tsx} +0 -0
- /package/src/workbench/{useWorkbenchStandaloneShellStateSync.tsx → shell/useWorkbenchStandaloneShellStateSync.tsx} +0 -0
- /package/src/workbench/{workbenchStandaloneShellReactContext.tsx → shell/workbenchStandaloneShellReactContext.tsx} +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
ShowWorkbenchNoticeInput,
|
|
5
|
+
WorkbenchNoticeController,
|
|
6
|
+
WorkbenchNoticeTone,
|
|
7
|
+
} from './WorkbenchNotice.js';
|
|
8
|
+
|
|
9
|
+
export interface WorkbenchNotificationAction {
|
|
10
|
+
readonly label: string;
|
|
11
|
+
readonly onAction: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface WorkbenchNotifyOptions {
|
|
15
|
+
readonly actions?: readonly WorkbenchNotificationAction[];
|
|
16
|
+
readonly dataAttributes?: ShowWorkbenchNoticeInput['dataAttributes'];
|
|
17
|
+
readonly durationMs?: number;
|
|
18
|
+
readonly id?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* NotificationService-shaped facade over {@link WorkbenchNoticeController}.
|
|
23
|
+
* Prefer this for command/install/save feedback; keep modal confirms separate.
|
|
24
|
+
*/
|
|
25
|
+
export interface WorkbenchNotify {
|
|
26
|
+
info(message: ReactNode, options?: WorkbenchNotifyOptions): string;
|
|
27
|
+
error(message: ReactNode, options?: WorkbenchNotifyOptions): string;
|
|
28
|
+
success(message: ReactNode, options?: WorkbenchNotifyOptions): string;
|
|
29
|
+
warning(message: ReactNode, options?: WorkbenchNotifyOptions): string;
|
|
30
|
+
dismiss(id: string): void;
|
|
31
|
+
clear(): void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function showTone(
|
|
35
|
+
controller: WorkbenchNoticeController,
|
|
36
|
+
tone: WorkbenchNoticeTone,
|
|
37
|
+
message: ReactNode,
|
|
38
|
+
options: WorkbenchNotifyOptions = {},
|
|
39
|
+
): string {
|
|
40
|
+
const { actions, dataAttributes, durationMs, id } = options;
|
|
41
|
+
const noticeId = id ?? `workbench-notify-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
42
|
+
|
|
43
|
+
const noticeMessage =
|
|
44
|
+
actions && actions.length > 0 ? (
|
|
45
|
+
<span className="ui-workbench-notify-message">
|
|
46
|
+
<span className="ui-workbench-notify-message__text">{message}</span>
|
|
47
|
+
<span className="ui-workbench-notify-message__actions">
|
|
48
|
+
{actions.map((action) => (
|
|
49
|
+
<button
|
|
50
|
+
className="ui-workbench-notify-message__action"
|
|
51
|
+
key={action.label}
|
|
52
|
+
type="button"
|
|
53
|
+
onClick={() => {
|
|
54
|
+
action.onAction();
|
|
55
|
+
controller.dismissNotice(noticeId);
|
|
56
|
+
}}
|
|
57
|
+
>
|
|
58
|
+
{action.label}
|
|
59
|
+
</button>
|
|
60
|
+
))}
|
|
61
|
+
</span>
|
|
62
|
+
</span>
|
|
63
|
+
) : (
|
|
64
|
+
message
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return controller.showNotice({
|
|
68
|
+
...(dataAttributes === undefined ? {} : { dataAttributes }),
|
|
69
|
+
...(durationMs === undefined ? {} : { durationMs }),
|
|
70
|
+
id: noticeId,
|
|
71
|
+
message: noticeMessage,
|
|
72
|
+
tone,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create a `notify.info` / `notify.error` facade over an existing notice controller.
|
|
78
|
+
*/
|
|
79
|
+
export function createWorkbenchNotify(controller: WorkbenchNoticeController): WorkbenchNotify {
|
|
80
|
+
return {
|
|
81
|
+
info: (message, options) => showTone(controller, 'info', message, options),
|
|
82
|
+
error: (message, options) => showTone(controller, 'error', message, options),
|
|
83
|
+
success: (message, options) => showTone(controller, 'success', message, options),
|
|
84
|
+
warning: (message, options) => showTone(controller, 'warning', message, options),
|
|
85
|
+
dismiss: (noticeId) => controller.dismissNotice(noticeId),
|
|
86
|
+
clear: () => controller.clearNotices(),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ExtensionCatalogBrowseEntry, ExtensionInstallOptions } from './types.js';
|
|
2
|
+
|
|
3
|
+
export function extensionInstallRequiresApproval(entry: ExtensionCatalogBrowseEntry): boolean {
|
|
4
|
+
return Boolean(
|
|
5
|
+
entry.installPlan?.requiresApproval && !entry.installed && !entry.installPlan.blocked,
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function formatExtensionInstallApprovalMessage(entry: ExtensionCatalogBrowseEntry): string {
|
|
10
|
+
const permissions = entry.installPlan?.permissions ?? [];
|
|
11
|
+
const permissionLine =
|
|
12
|
+
permissions.length > 0
|
|
13
|
+
? `Requested permissions: ${permissions.join(', ')}.`
|
|
14
|
+
: 'This package requests privileges that require approval.';
|
|
15
|
+
|
|
16
|
+
return [
|
|
17
|
+
`Install "${entry.displayName}"?`,
|
|
18
|
+
'',
|
|
19
|
+
permissionLine,
|
|
20
|
+
'Continue only if you trust this package.',
|
|
21
|
+
].join('\n');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ResolveExtensionInstallOptionsInput {
|
|
25
|
+
readonly confirm?: ((message: string) => boolean) | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* When true (or when the predicate returns true), skip the confirm prompt and
|
|
28
|
+
* return `{ approved: true }`. Hosts typically back this with a durable trust
|
|
29
|
+
* store keyed by extension id + permission fingerprint.
|
|
30
|
+
*/
|
|
31
|
+
readonly isTrusted?: boolean | ((entry: ExtensionCatalogBrowseEntry) => boolean) | undefined;
|
|
32
|
+
/** Called after the user explicitly confirms trust for this install. */
|
|
33
|
+
readonly rememberTrust?: ((entry: ExtensionCatalogBrowseEntry) => void) | undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolve install options for UI actions.
|
|
38
|
+
*
|
|
39
|
+
* Approval is required when the install plan requests permissions. A trusted
|
|
40
|
+
* predicate may skip the prompt; otherwise the host confirm dialog runs and
|
|
41
|
+
* successful consent may be persisted via `rememberTrust`.
|
|
42
|
+
*/
|
|
43
|
+
export function resolveExtensionInstallOptions(
|
|
44
|
+
entry: ExtensionCatalogBrowseEntry,
|
|
45
|
+
confirmOrOptions: ((message: string) => boolean) | ResolveExtensionInstallOptionsInput = (
|
|
46
|
+
message,
|
|
47
|
+
) => (typeof globalThis.confirm === 'function' ? globalThis.confirm(message) : false),
|
|
48
|
+
): ExtensionInstallOptions | undefined {
|
|
49
|
+
if (!extensionInstallRequiresApproval(entry)) {
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const options =
|
|
54
|
+
typeof confirmOrOptions === 'function' ? { confirm: confirmOrOptions } : confirmOrOptions;
|
|
55
|
+
const confirm =
|
|
56
|
+
options.confirm ??
|
|
57
|
+
((message: string) =>
|
|
58
|
+
typeof globalThis.confirm === 'function' ? globalThis.confirm(message) : false);
|
|
59
|
+
|
|
60
|
+
const trusted =
|
|
61
|
+
typeof options.isTrusted === 'function' ? options.isTrusted(entry) : Boolean(options.isTrusted);
|
|
62
|
+
if (trusted) {
|
|
63
|
+
return { approved: true };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!confirm(formatExtensionInstallApprovalMessage(entry))) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
options.rememberTrust?.(entry);
|
|
71
|
+
return { approved: true };
|
|
72
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ExtensionCatalogBrowseEntry, ExtensionManagementEntry } from './types.js';
|
|
2
|
+
|
|
3
|
+
export function filterInstalledEntries(
|
|
4
|
+
entries: readonly ExtensionManagementEntry[],
|
|
5
|
+
query: string,
|
|
6
|
+
): readonly ExtensionManagementEntry[] {
|
|
7
|
+
const normalized = query.trim().toLowerCase();
|
|
8
|
+
if (!normalized) {
|
|
9
|
+
return entries;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return entries.filter((entry) =>
|
|
13
|
+
[entry.displayName, entry.id, entry.category, entry.description ?? '']
|
|
14
|
+
.join(' ')
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.includes(normalized),
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function filterBrowseEntries(
|
|
21
|
+
entries: readonly ExtensionCatalogBrowseEntry[],
|
|
22
|
+
query: string,
|
|
23
|
+
category?: string,
|
|
24
|
+
): readonly ExtensionCatalogBrowseEntry[] {
|
|
25
|
+
const normalized = query.trim().toLowerCase();
|
|
26
|
+
return entries.filter((entry) => {
|
|
27
|
+
if (category && entry.category !== category) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (!normalized) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return [entry.displayName, entry.id, entry.category, entry.description]
|
|
34
|
+
.join(' ')
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.includes(normalized);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -22,10 +22,10 @@ export type {
|
|
|
22
22
|
ExtensionManagementPendingAction,
|
|
23
23
|
} from './ExtensionManagementSidebar.js';
|
|
24
24
|
export {
|
|
25
|
-
|
|
25
|
+
IntegrationActionRow,
|
|
26
|
+
IntegrationCommandButton,
|
|
26
27
|
type IntegrationCommandAction,
|
|
27
|
-
} from './
|
|
28
|
-
export { IntegrationActionRow, IntegrationCommandButton } from './IntegrationCommandActions.js';
|
|
28
|
+
} from './IntegrationCommandActions.js';
|
|
29
29
|
export { IntegrationsShell } from './IntegrationsShell.js';
|
|
30
30
|
export type { IntegrationsShellProps } from './IntegrationsShell.js';
|
|
31
31
|
export {
|
|
@@ -75,6 +75,13 @@ export type {
|
|
|
75
75
|
WorkbenchNoticePosition,
|
|
76
76
|
WorkbenchNoticeTone,
|
|
77
77
|
} from './WorkbenchNotice.js';
|
|
78
|
+
export { createWorkbenchNotify } from './createWorkbenchNotify.js';
|
|
79
|
+
export type {
|
|
80
|
+
WorkbenchNotificationAction,
|
|
81
|
+
WorkbenchNotify,
|
|
82
|
+
WorkbenchNotifyOptions,
|
|
83
|
+
} from './createWorkbenchNotify.js';
|
|
84
|
+
export { useWorkbenchNotify } from './useWorkbenchNotify.js';
|
|
78
85
|
export { KeybindingCaptureField } from './KeybindingCaptureField.js';
|
|
79
86
|
export type { KeybindingCaptureFieldProps } from './KeybindingCaptureField.js';
|
|
80
87
|
export { KeybindingManagementPanel } from './KeybindingManagementPanel.js';
|
|
@@ -112,6 +119,12 @@ export {
|
|
|
112
119
|
extensionCategoryIconTone,
|
|
113
120
|
formatExtensionCategoryLabel,
|
|
114
121
|
} from './extension-category-display.js';
|
|
122
|
+
export {
|
|
123
|
+
extensionInstallRequiresApproval,
|
|
124
|
+
formatExtensionInstallApprovalMessage,
|
|
125
|
+
resolveExtensionInstallOptions,
|
|
126
|
+
type ResolveExtensionInstallOptionsInput,
|
|
127
|
+
} from './extension-install-approval.js';
|
|
115
128
|
export type {
|
|
116
129
|
AccountManagementEntry,
|
|
117
130
|
AccountManagementEntryStatus,
|
|
@@ -122,9 +135,11 @@ export type {
|
|
|
122
135
|
CommandManagementPanelProps,
|
|
123
136
|
CommandManagementRunState,
|
|
124
137
|
ExtensionCatalogBrowseEntry,
|
|
138
|
+
ExtensionInstallOptions,
|
|
125
139
|
ExtensionManagementDiagnosticSummary,
|
|
126
140
|
ExtensionManagementEntry,
|
|
127
141
|
ExtensionManagementFeatureItem,
|
|
128
142
|
ExtensionManagementFeatureSummary,
|
|
129
143
|
ExtensionManagementPanelProps,
|
|
144
|
+
ExtensionManagementTransition,
|
|
130
145
|
} from './types.js';
|
|
@@ -2,3 +2,31 @@
|
|
|
2
2
|
@import './library-catalog-picker-dialog.css';
|
|
3
3
|
@import './library-facet-filter-dialog.css';
|
|
4
4
|
@import './management-panel.css';
|
|
5
|
+
|
|
6
|
+
.ui-workbench-notify-message {
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
flex-wrap: wrap;
|
|
9
|
+
gap: 8px;
|
|
10
|
+
align-items: center;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.ui-workbench-notify-message__actions {
|
|
14
|
+
display: inline-flex;
|
|
15
|
+
flex-wrap: wrap;
|
|
16
|
+
gap: 6px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.ui-workbench-notify-message__action {
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 2px 8px;
|
|
22
|
+
border: 1px solid var(--color-border, currentColor);
|
|
23
|
+
border-radius: var(--radius-sm, 4px);
|
|
24
|
+
background: transparent;
|
|
25
|
+
color: inherit;
|
|
26
|
+
font: inherit;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.ui-workbench-notify-message__action:hover {
|
|
31
|
+
background: var(--color-surface-hover, rgba(255, 255, 255, 0.08));
|
|
32
|
+
}
|
|
@@ -82,6 +82,11 @@ export interface ExtensionManagementDiagnosticSummary {
|
|
|
82
82
|
readonly severity: 'error' | 'warning';
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
export interface ExtensionManagementTransition {
|
|
86
|
+
readonly kind: 'applied' | 'reloadRequired' | 'failed';
|
|
87
|
+
readonly message: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
85
90
|
export interface ExtensionInstallPlanSummary {
|
|
86
91
|
readonly blocked: boolean;
|
|
87
92
|
readonly diagnostics?: readonly ExtensionManagementDiagnosticSummary[] | undefined;
|
|
@@ -92,6 +97,8 @@ export interface ExtensionInstallPlanSummary {
|
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
export interface ExtensionManagementEntry {
|
|
100
|
+
/** True only when a persisted installed record currently owns this entry. */
|
|
101
|
+
readonly canUninstall?: boolean;
|
|
95
102
|
readonly category: string;
|
|
96
103
|
readonly description?: string | undefined;
|
|
97
104
|
readonly diagnostics?: readonly ExtensionManagementDiagnosticSummary[] | undefined;
|
|
@@ -102,6 +109,7 @@ export interface ExtensionManagementEntry {
|
|
|
102
109
|
readonly installedAt?: string | undefined;
|
|
103
110
|
readonly manifestUrl?: string | undefined;
|
|
104
111
|
readonly source: ExtensionManagementEntrySource;
|
|
112
|
+
readonly transition?: ExtensionManagementTransition;
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
export interface ExtensionCatalogBrowseEntry {
|
|
@@ -115,12 +123,26 @@ export interface ExtensionCatalogBrowseEntry {
|
|
|
115
123
|
readonly manifestUrl: string;
|
|
116
124
|
}
|
|
117
125
|
|
|
126
|
+
export interface ExtensionInstallOptions {
|
|
127
|
+
/** Required when the install plan sets `requiresApproval`. */
|
|
128
|
+
readonly approved?: boolean | undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
118
131
|
export interface ExtensionManagementPanelProps {
|
|
119
132
|
browseEntries: readonly ExtensionCatalogBrowseEntry[];
|
|
120
133
|
catalogError?: string | undefined;
|
|
121
134
|
catalogLoading?: boolean | undefined;
|
|
122
135
|
className?: string | undefined;
|
|
123
136
|
installedEntries: readonly ExtensionManagementEntry[];
|
|
124
|
-
onInstall?:
|
|
137
|
+
onInstall?:
|
|
138
|
+
((entry: ExtensionCatalogBrowseEntry, options?: ExtensionInstallOptions) => void) | undefined;
|
|
139
|
+
onUninstall?: (entry: ExtensionManagementEntry) => void;
|
|
125
140
|
onToggleEnabled?: ((entry: ExtensionManagementEntry, enabled: boolean) => void) | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* Host-owned durable trust check. When true for an entry, the install confirm
|
|
143
|
+
* prompt is skipped and `{ approved: true }` is used.
|
|
144
|
+
*/
|
|
145
|
+
isInstallTrusted?: ((entry: ExtensionCatalogBrowseEntry) => boolean) | undefined;
|
|
146
|
+
/** Persist trust after the user confirms a permissioned install. */
|
|
147
|
+
onRememberInstallTrust?: ((entry: ExtensionCatalogBrowseEntry) => void) | undefined;
|
|
126
148
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { createWorkbenchNotify, type WorkbenchNotify } from './createWorkbenchNotify.js';
|
|
4
|
+
import { useWorkbenchNotice } from './WorkbenchNotice.js';
|
|
5
|
+
|
|
6
|
+
/** Convenience hook: NotificationService-shaped API inside a notice provider. */
|
|
7
|
+
export function useWorkbenchNotify(): WorkbenchNotify {
|
|
8
|
+
const controller = useWorkbenchNotice();
|
|
9
|
+
return useMemo(() => createWorkbenchNotify(controller), [controller]);
|
|
10
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import Markdown from 'react-markdown';
|
|
2
2
|
import { Children, isValidElement, type ComponentPropsWithoutRef, type ReactNode } from 'react';
|
|
3
|
-
import { cx } from '
|
|
4
|
-
import {
|
|
3
|
+
import { cx } from '../../utils/cx';
|
|
4
|
+
import {
|
|
5
|
+
workbenchMarkdownRemarkPlugins,
|
|
6
|
+
workbenchMarkdownRehypePlugins,
|
|
7
|
+
} from './markdownRemarkPlugins';
|
|
8
|
+
import { sanitizeMarkdownHref } from './sanitizeMarkdownHref';
|
|
5
9
|
|
|
6
10
|
export interface WorkbenchMarkdownPreviewProps extends ComponentPropsWithoutRef<'article'> {
|
|
7
11
|
source: string;
|
|
@@ -16,12 +20,23 @@ export function WorkbenchMarkdownPreview({
|
|
|
16
20
|
<article className={cx('ui-workbench-markdown-preview', className)} {...props}>
|
|
17
21
|
<Markdown
|
|
18
22
|
remarkPlugins={workbenchMarkdownRemarkPlugins}
|
|
23
|
+
rehypePlugins={workbenchMarkdownRehypePlugins}
|
|
19
24
|
components={{
|
|
20
|
-
a: ({ children, href }) =>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
a: ({ children, href }) => {
|
|
26
|
+
const safeHref = sanitizeMarkdownHref(href);
|
|
27
|
+
if (!safeHref) {
|
|
28
|
+
return <span>{children}</span>;
|
|
29
|
+
}
|
|
30
|
+
return (
|
|
31
|
+
<a
|
|
32
|
+
href={safeHref}
|
|
33
|
+
rel="noreferrer"
|
|
34
|
+
target={safeHref.startsWith('#') ? undefined : '_blank'}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</a>
|
|
38
|
+
);
|
|
39
|
+
},
|
|
25
40
|
code: ({ children, className: codeClassName }) => (
|
|
26
41
|
<code className={cx('ui-workbench-markdown-preview__code', codeClassName)}>
|
|
27
42
|
{children}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import remarkGfm from 'remark-gfm';
|
|
2
|
+
import rehypeSanitize from 'rehype-sanitize';
|
|
3
|
+
|
|
4
|
+
/** Shared remark plugins for workbench markdown surfaces (preview, chat, etc.). */
|
|
5
|
+
export const workbenchMarkdownRemarkPlugins = [remarkGfm];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Default rehype pipeline for untrusted markdown (chat / preview).
|
|
9
|
+
* Strips script/event handlers and dangerous URLs via rehype-sanitize.
|
|
10
|
+
* Hosts that need raw HTML must render outside these kit surfaces.
|
|
11
|
+
*/
|
|
12
|
+
export const workbenchMarkdownRehypePlugins = [rehypeSanitize];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Allowlist markdown link targets for safe preview rendering.
|
|
3
|
+
* Blocks javascript:/data:/vbscript: and other non-navigation schemes.
|
|
4
|
+
*/
|
|
5
|
+
export function sanitizeMarkdownHref(href: string | undefined): string | undefined {
|
|
6
|
+
if (href == null || href.trim() === '') {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const trimmed = href.trim();
|
|
11
|
+
if (trimmed.startsWith('#')) {
|
|
12
|
+
return trimmed;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const base =
|
|
17
|
+
typeof globalThis.location?.href === 'string' && globalThis.location.href.length > 0
|
|
18
|
+
? globalThis.location.href
|
|
19
|
+
: 'https://workbench.local/';
|
|
20
|
+
const url = new URL(trimmed, base);
|
|
21
|
+
const protocol = url.protocol.toLowerCase();
|
|
22
|
+
if (protocol === 'http:' || protocol === 'https:' || protocol === 'mailto:') {
|
|
23
|
+
return trimmed;
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
} catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -219,56 +219,16 @@ function renderResizeHandle(
|
|
|
219
219
|
);
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
<div
|
|
233
|
-
key={node.id}
|
|
234
|
-
data-node-id={node.id}
|
|
235
|
-
style={style}
|
|
236
|
-
onClick={onClick}
|
|
237
|
-
onPointerDown={onPointerDown}
|
|
238
|
-
>
|
|
239
|
-
<div style={{ position: 'relative', width: '100%', height: '100%' }}>{children}</div>
|
|
240
|
-
{renderResizeHandle(resizeHandleLabel, onResizeHandlePointerDown)}
|
|
241
|
-
</div>
|
|
242
|
-
),
|
|
243
|
-
group: ({
|
|
244
|
-
node,
|
|
245
|
-
style,
|
|
246
|
-
children,
|
|
247
|
-
onClick,
|
|
248
|
-
onPointerDown,
|
|
249
|
-
onResizeHandlePointerDown,
|
|
250
|
-
resizeHandleLabel,
|
|
251
|
-
}) => (
|
|
252
|
-
<div
|
|
253
|
-
key={node.id}
|
|
254
|
-
data-node-id={node.id}
|
|
255
|
-
style={style}
|
|
256
|
-
onClick={onClick}
|
|
257
|
-
onPointerDown={onPointerDown}
|
|
258
|
-
>
|
|
259
|
-
<div style={{ position: 'relative', width: '100%', height: '100%' }}>{children}</div>
|
|
260
|
-
{renderResizeHandle(resizeHandleLabel, onResizeHandlePointerDown)}
|
|
261
|
-
</div>
|
|
262
|
-
),
|
|
263
|
-
component: ({
|
|
264
|
-
node,
|
|
265
|
-
style,
|
|
266
|
-
children,
|
|
267
|
-
onClick,
|
|
268
|
-
onPointerDown,
|
|
269
|
-
onResizeHandlePointerDown,
|
|
270
|
-
resizeHandleLabel,
|
|
271
|
-
}) => (
|
|
222
|
+
function renderContainerNode({
|
|
223
|
+
node,
|
|
224
|
+
style,
|
|
225
|
+
children,
|
|
226
|
+
onClick,
|
|
227
|
+
onPointerDown,
|
|
228
|
+
onResizeHandlePointerDown,
|
|
229
|
+
resizeHandleLabel,
|
|
230
|
+
}: NodeRendererProps) {
|
|
231
|
+
return (
|
|
272
232
|
<div
|
|
273
233
|
key={node.id}
|
|
274
234
|
data-node-id={node.id}
|
|
@@ -279,35 +239,39 @@ const nodeRendererRegistry: Record<string, (params: NodeRendererProps) => ReactN
|
|
|
279
239
|
<div style={{ position: 'relative', width: '100%', height: '100%' }}>{children}</div>
|
|
280
240
|
{renderResizeHandle(resizeHandleLabel, onResizeHandlePointerDown)}
|
|
281
241
|
</div>
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function renderEmptyNode({
|
|
246
|
+
node,
|
|
247
|
+
style,
|
|
248
|
+
onClick,
|
|
249
|
+
onPointerDown,
|
|
250
|
+
onResizeHandlePointerDown,
|
|
251
|
+
resizeHandleLabel,
|
|
252
|
+
}: NodeRendererProps) {
|
|
253
|
+
return (
|
|
292
254
|
<div
|
|
293
255
|
key={node.id}
|
|
294
256
|
data-node-id={node.id}
|
|
295
257
|
style={style}
|
|
296
|
-
onClick={onClick}
|
|
258
|
+
onClick={wrapNodeClick(onClick)}
|
|
297
259
|
onPointerDown={onPointerDown}
|
|
298
260
|
>
|
|
299
|
-
<div style={{ position: 'relative', width: '100%', height: '100%' }}>{children}</div>
|
|
300
261
|
{renderResizeHandle(resizeHandleLabel, onResizeHandlePointerDown)}
|
|
301
262
|
</div>
|
|
302
|
-
)
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function renderContentNode({
|
|
267
|
+
node,
|
|
268
|
+
style,
|
|
269
|
+
onClick,
|
|
270
|
+
onPointerDown,
|
|
271
|
+
onResizeHandlePointerDown,
|
|
272
|
+
resizeHandleLabel,
|
|
273
|
+
}: NodeRendererProps) {
|
|
274
|
+
return (
|
|
311
275
|
<div
|
|
312
276
|
key={node.id}
|
|
313
277
|
data-node-id={node.id}
|
|
@@ -315,9 +279,18 @@ const nodeRendererRegistry: Record<string, (params: NodeRendererProps) => ReactN
|
|
|
315
279
|
onClick={wrapNodeClick(onClick)}
|
|
316
280
|
onPointerDown={onPointerDown}
|
|
317
281
|
>
|
|
282
|
+
{(node as { content?: string }).content ?? ''}
|
|
318
283
|
{renderResizeHandle(resizeHandleLabel, onResizeHandlePointerDown)}
|
|
319
284
|
</div>
|
|
320
|
-
)
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const nodeRendererRegistry: Record<string, (params: NodeRendererProps) => ReactNode> = {
|
|
289
|
+
frame: renderContainerNode,
|
|
290
|
+
group: renderContainerNode,
|
|
291
|
+
component: renderContainerNode,
|
|
292
|
+
instance: renderContainerNode,
|
|
293
|
+
rectangle: renderEmptyNode,
|
|
321
294
|
circle: ({
|
|
322
295
|
node,
|
|
323
296
|
style,
|
|
@@ -336,18 +309,7 @@ const nodeRendererRegistry: Record<string, (params: NodeRendererProps) => ReactN
|
|
|
336
309
|
{renderResizeHandle(resizeHandleLabel, onResizeHandlePointerDown)}
|
|
337
310
|
</div>
|
|
338
311
|
),
|
|
339
|
-
text:
|
|
340
|
-
<div
|
|
341
|
-
key={node.id}
|
|
342
|
-
data-node-id={node.id}
|
|
343
|
-
style={style}
|
|
344
|
-
onClick={wrapNodeClick(onClick)}
|
|
345
|
-
onPointerDown={onPointerDown}
|
|
346
|
-
>
|
|
347
|
-
{(node as { content?: string }).content ?? ''}
|
|
348
|
-
{renderResizeHandle(resizeHandleLabel, onResizeHandlePointerDown)}
|
|
349
|
-
</div>
|
|
350
|
-
),
|
|
312
|
+
text: renderContentNode,
|
|
351
313
|
image: ({
|
|
352
314
|
node,
|
|
353
315
|
style,
|
|
@@ -394,43 +356,8 @@ const nodeRendererRegistry: Record<string, (params: NodeRendererProps) => ReactN
|
|
|
394
356
|
</div>
|
|
395
357
|
);
|
|
396
358
|
},
|
|
397
|
-
vector:
|
|
398
|
-
|
|
399
|
-
style,
|
|
400
|
-
onClick,
|
|
401
|
-
onPointerDown,
|
|
402
|
-
onResizeHandlePointerDown,
|
|
403
|
-
resizeHandleLabel,
|
|
404
|
-
}) => (
|
|
405
|
-
<div
|
|
406
|
-
key={node.id}
|
|
407
|
-
data-node-id={node.id}
|
|
408
|
-
style={style}
|
|
409
|
-
onClick={wrapNodeClick(onClick)}
|
|
410
|
-
onPointerDown={onPointerDown}
|
|
411
|
-
>
|
|
412
|
-
{(node as { content?: string }).content ?? ''}
|
|
413
|
-
{renderResizeHandle(resizeHandleLabel, onResizeHandlePointerDown)}
|
|
414
|
-
</div>
|
|
415
|
-
),
|
|
416
|
-
unknown: ({
|
|
417
|
-
node,
|
|
418
|
-
style,
|
|
419
|
-
onClick,
|
|
420
|
-
onPointerDown,
|
|
421
|
-
onResizeHandlePointerDown,
|
|
422
|
-
resizeHandleLabel,
|
|
423
|
-
}) => (
|
|
424
|
-
<div
|
|
425
|
-
key={node.id}
|
|
426
|
-
data-node-id={node.id}
|
|
427
|
-
style={style}
|
|
428
|
-
onClick={wrapNodeClick(onClick)}
|
|
429
|
-
onPointerDown={onPointerDown}
|
|
430
|
-
>
|
|
431
|
-
{renderResizeHandle(resizeHandleLabel, onResizeHandlePointerDown)}
|
|
432
|
-
</div>
|
|
433
|
-
),
|
|
359
|
+
vector: renderContentNode,
|
|
360
|
+
unknown: renderEmptyNode,
|
|
434
361
|
};
|
|
435
362
|
|
|
436
363
|
function renderNode(
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
type WorkbenchStructuredDataSchemaFieldInputProps,
|
|
38
38
|
type WorkbenchStructuredDataTextArrayInputProps,
|
|
39
39
|
} from './structuredDataSchema';
|
|
40
|
+
import { isRenderableWorkbenchStructuredDataFormError } from './structuredDataFormModel';
|
|
40
41
|
|
|
41
42
|
export function WorkbenchStructuredDataForm({
|
|
42
43
|
ariaLabel,
|
|
@@ -156,10 +157,6 @@ export function WorkbenchStructuredDataForm({
|
|
|
156
157
|
);
|
|
157
158
|
}
|
|
158
159
|
|
|
159
|
-
function isRenderableWorkbenchStructuredDataFormError(error: ReactNode) {
|
|
160
|
-
return error !== undefined && error !== null && error !== false && error !== '';
|
|
161
|
-
}
|
|
162
|
-
|
|
163
160
|
function StructuredDataSection({
|
|
164
161
|
data,
|
|
165
162
|
disabled,
|