@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
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
extensionCategoryIconTone,
|
|
8
8
|
formatExtensionCategoryLabel,
|
|
9
9
|
} from './extension-category-display.js';
|
|
10
|
+
import { resolveExtensionInstallOptions } from './extension-install-approval.js';
|
|
11
|
+
import { filterBrowseEntries, filterInstalledEntries } from './extension-management-filters.js';
|
|
10
12
|
import { ManagementFilterChips } from './ManagementFilterChips.js';
|
|
11
13
|
import { ManagementCard, ManagementCardList } from './ManagementCard.js';
|
|
12
14
|
import { ManagementGroup, ManagementGroups } from './ManagementGroup.js';
|
|
@@ -22,6 +24,7 @@ import type {
|
|
|
22
24
|
ExtensionManagementEntry,
|
|
23
25
|
ExtensionManagementFeatureSummary,
|
|
24
26
|
ExtensionManagementPanelProps,
|
|
27
|
+
ExtensionManagementTransition,
|
|
25
28
|
} from './types.js';
|
|
26
29
|
|
|
27
30
|
const BROWSE_CATEGORIES = ['all', 'feature', 'editor', 'theme', 'language'] as const;
|
|
@@ -40,8 +43,11 @@ export function ExtensionManagementPanel({
|
|
|
40
43
|
catalogLoading = false,
|
|
41
44
|
className,
|
|
42
45
|
installedEntries,
|
|
46
|
+
isInstallTrusted,
|
|
43
47
|
onInstall,
|
|
48
|
+
onRememberInstallTrust,
|
|
44
49
|
onToggleEnabled,
|
|
50
|
+
onUninstall,
|
|
45
51
|
}: ExtensionManagementPanelProps) {
|
|
46
52
|
const [activeTab, setActiveTab] = useState<'installed' | 'browse'>(
|
|
47
53
|
EXTENSION_MANAGEMENT_DEFAULT_TAB,
|
|
@@ -89,6 +95,7 @@ export function ExtensionManagementPanel({
|
|
|
89
95
|
summary={`${filteredInstalled.length} of ${installedEntries.length} visible`}
|
|
90
96
|
onQueryChange={setInstalledQuery}
|
|
91
97
|
onToggleEnabled={onToggleEnabled}
|
|
98
|
+
onUninstall={onUninstall}
|
|
92
99
|
/>
|
|
93
100
|
),
|
|
94
101
|
},
|
|
@@ -103,12 +110,14 @@ export function ExtensionManagementPanel({
|
|
|
103
110
|
emptyLabel="No catalog extensions match the current filter."
|
|
104
111
|
entries={filteredBrowse}
|
|
105
112
|
groups={browseGroups}
|
|
113
|
+
isInstallTrusted={isInstallTrusted}
|
|
106
114
|
query={browseQuery}
|
|
107
115
|
showGroups={showBrowseGroups}
|
|
108
116
|
summary={`${filteredBrowse.length} of ${browseEntries.length} in catalog`}
|
|
109
117
|
onCategoryChange={setCategoryFilter}
|
|
110
118
|
onInstall={onInstall}
|
|
111
119
|
onQueryChange={setBrowseQuery}
|
|
120
|
+
onRememberInstallTrust={onRememberInstallTrust}
|
|
112
121
|
/>
|
|
113
122
|
),
|
|
114
123
|
},
|
|
@@ -116,7 +125,8 @@ export function ExtensionManagementPanel({
|
|
|
116
125
|
onSelect={(tabId) => setActiveTab(tabId as 'installed' | 'browse')}
|
|
117
126
|
/>
|
|
118
127
|
<ManagementPanelNotice>
|
|
119
|
-
|
|
128
|
+
Eligible unselected theme packs apply immediately. Other extension changes reload the
|
|
129
|
+
workbench.
|
|
120
130
|
</ManagementPanelNotice>
|
|
121
131
|
</ManagementPanelFrame>
|
|
122
132
|
);
|
|
@@ -127,6 +137,7 @@ function InstalledExtensionsTab({
|
|
|
127
137
|
entries,
|
|
128
138
|
onQueryChange,
|
|
129
139
|
onToggleEnabled,
|
|
140
|
+
onUninstall,
|
|
130
141
|
query,
|
|
131
142
|
summary,
|
|
132
143
|
}: {
|
|
@@ -134,6 +145,7 @@ function InstalledExtensionsTab({
|
|
|
134
145
|
entries: readonly ExtensionManagementEntry[];
|
|
135
146
|
onQueryChange: (query: string) => void;
|
|
136
147
|
onToggleEnabled?: ExtensionManagementPanelProps['onToggleEnabled'];
|
|
148
|
+
onUninstall?: ExtensionManagementPanelProps['onUninstall'];
|
|
137
149
|
query: string;
|
|
138
150
|
summary: string;
|
|
139
151
|
}) {
|
|
@@ -154,15 +166,27 @@ function InstalledExtensionsTab({
|
|
|
154
166
|
<li key={entry.id}>
|
|
155
167
|
<ManagementCard
|
|
156
168
|
actions={
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
169
|
+
<>
|
|
170
|
+
<Button
|
|
171
|
+
compact
|
|
172
|
+
disabled={!onToggleEnabled || entry.source === 'bundled'}
|
|
173
|
+
type="button"
|
|
174
|
+
variant={entry.enabled ? 'default' : 'primary'}
|
|
175
|
+
onClick={() => onToggleEnabled?.(entry, !entry.enabled)}
|
|
176
|
+
>
|
|
177
|
+
{entry.enabled ? 'Disable' : 'Enable'}
|
|
178
|
+
</Button>
|
|
179
|
+
{entry.canUninstall === true && onUninstall ? (
|
|
180
|
+
<Button
|
|
181
|
+
compact
|
|
182
|
+
type="button"
|
|
183
|
+
variant="danger"
|
|
184
|
+
onClick={() => onUninstall(entry)}
|
|
185
|
+
>
|
|
186
|
+
Uninstall
|
|
187
|
+
</Button>
|
|
188
|
+
) : null}
|
|
189
|
+
</>
|
|
166
190
|
}
|
|
167
191
|
badges={
|
|
168
192
|
<>
|
|
@@ -174,6 +198,14 @@ function InstalledExtensionsTab({
|
|
|
174
198
|
{entry.enabled ? 'Enabled' : 'Disabled'}
|
|
175
199
|
</Badge>
|
|
176
200
|
)}
|
|
201
|
+
{entry.transition ? (
|
|
202
|
+
<Badge
|
|
203
|
+
title={entry.transition.message}
|
|
204
|
+
variant={extensionTransitionBadgeVariant(entry.transition.kind)}
|
|
205
|
+
>
|
|
206
|
+
{extensionTransitionLabel(entry.transition.kind)}
|
|
207
|
+
</Badge>
|
|
208
|
+
) : null}
|
|
177
209
|
</>
|
|
178
210
|
}
|
|
179
211
|
description={entry.description}
|
|
@@ -192,6 +224,22 @@ function InstalledExtensionsTab({
|
|
|
192
224
|
);
|
|
193
225
|
}
|
|
194
226
|
|
|
227
|
+
function extensionTransitionLabel(kind: ExtensionManagementTransition['kind']): string {
|
|
228
|
+
if (kind === 'reloadRequired') {
|
|
229
|
+
return 'Reload required';
|
|
230
|
+
}
|
|
231
|
+
return kind === 'failed' ? 'Failed' : 'Applied';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function extensionTransitionBadgeVariant(
|
|
235
|
+
kind: ExtensionManagementTransition['kind'],
|
|
236
|
+
): 'accent' | 'danger' | 'muted' {
|
|
237
|
+
if (kind === 'failed') {
|
|
238
|
+
return 'danger';
|
|
239
|
+
}
|
|
240
|
+
return kind === 'applied' ? 'accent' : 'muted';
|
|
241
|
+
}
|
|
242
|
+
|
|
195
243
|
function ExtensionFeatureDetails({ entry }: { entry: ExtensionManagementEntry }) {
|
|
196
244
|
const rows = getExtensionFeatureDetailRows(entry.features);
|
|
197
245
|
const diagnostics = entry.diagnostics ?? [];
|
|
@@ -273,9 +321,11 @@ function BrowseExtensionsTab({
|
|
|
273
321
|
emptyLabel,
|
|
274
322
|
entries,
|
|
275
323
|
groups,
|
|
324
|
+
isInstallTrusted,
|
|
276
325
|
onCategoryChange,
|
|
277
326
|
onInstall,
|
|
278
327
|
onQueryChange,
|
|
328
|
+
onRememberInstallTrust,
|
|
279
329
|
query,
|
|
280
330
|
showGroups,
|
|
281
331
|
summary,
|
|
@@ -286,9 +336,11 @@ function BrowseExtensionsTab({
|
|
|
286
336
|
emptyLabel: string;
|
|
287
337
|
entries: readonly ExtensionCatalogBrowseEntry[];
|
|
288
338
|
groups: ReadonlyArray<{ category: string; entries: readonly ExtensionCatalogBrowseEntry[] }>;
|
|
339
|
+
isInstallTrusted?: ExtensionManagementPanelProps['isInstallTrusted'];
|
|
289
340
|
onCategoryChange: (category: BrowseCategoryFilter) => void;
|
|
290
341
|
onInstall?: ExtensionManagementPanelProps['onInstall'];
|
|
291
342
|
onQueryChange: (query: string) => void;
|
|
343
|
+
onRememberInstallTrust?: ExtensionManagementPanelProps['onRememberInstallTrust'];
|
|
292
344
|
query: string;
|
|
293
345
|
showGroups: boolean;
|
|
294
346
|
summary: string;
|
|
@@ -335,7 +387,9 @@ function BrowseExtensionsTab({
|
|
|
335
387
|
<li key={entry.id}>
|
|
336
388
|
<ExtensionCatalogCard
|
|
337
389
|
entry={entry}
|
|
390
|
+
isInstallTrusted={isInstallTrusted}
|
|
338
391
|
onInstall={onInstall}
|
|
392
|
+
onRememberInstallTrust={onRememberInstallTrust}
|
|
339
393
|
showCategory={false}
|
|
340
394
|
/>
|
|
341
395
|
</li>
|
|
@@ -349,7 +403,13 @@ function BrowseExtensionsTab({
|
|
|
349
403
|
<ManagementCardList>
|
|
350
404
|
{flatEntries.map((entry) => (
|
|
351
405
|
<li key={entry.id}>
|
|
352
|
-
<ExtensionCatalogCard
|
|
406
|
+
<ExtensionCatalogCard
|
|
407
|
+
entry={entry}
|
|
408
|
+
isInstallTrusted={isInstallTrusted}
|
|
409
|
+
onInstall={onInstall}
|
|
410
|
+
onRememberInstallTrust={onRememberInstallTrust}
|
|
411
|
+
showCategory
|
|
412
|
+
/>
|
|
353
413
|
</li>
|
|
354
414
|
))}
|
|
355
415
|
</ManagementCardList>
|
|
@@ -360,11 +420,15 @@ function BrowseExtensionsTab({
|
|
|
360
420
|
|
|
361
421
|
function ExtensionCatalogCard({
|
|
362
422
|
entry,
|
|
423
|
+
isInstallTrusted,
|
|
363
424
|
onInstall,
|
|
425
|
+
onRememberInstallTrust,
|
|
364
426
|
showCategory,
|
|
365
427
|
}: {
|
|
366
428
|
entry: ExtensionCatalogBrowseEntry;
|
|
429
|
+
isInstallTrusted?: ExtensionManagementPanelProps['isInstallTrusted'];
|
|
367
430
|
onInstall?: ExtensionManagementPanelProps['onInstall'];
|
|
431
|
+
onRememberInstallTrust?: ExtensionManagementPanelProps['onRememberInstallTrust'];
|
|
368
432
|
showCategory: boolean;
|
|
369
433
|
}) {
|
|
370
434
|
return (
|
|
@@ -378,7 +442,15 @@ function ExtensionCatalogCard({
|
|
|
378
442
|
}
|
|
379
443
|
type="button"
|
|
380
444
|
variant={entry.installed ? 'default' : 'primary'}
|
|
381
|
-
onClick={() =>
|
|
445
|
+
onClick={() => {
|
|
446
|
+
if (!onInstall) return;
|
|
447
|
+
const options = resolveExtensionInstallOptions(entry, {
|
|
448
|
+
isTrusted: isInstallTrusted,
|
|
449
|
+
rememberTrust: onRememberInstallTrust,
|
|
450
|
+
});
|
|
451
|
+
if (!options) return;
|
|
452
|
+
onInstall(entry, options);
|
|
453
|
+
}}
|
|
382
454
|
>
|
|
383
455
|
{entry.installed ? 'Installed' : entry.installPlan?.blocked ? 'Blocked' : 'Install'}
|
|
384
456
|
</Button>
|
|
@@ -462,37 +534,3 @@ function groupBrowseEntries(entries: readonly ExtensionCatalogBrowseEntry[]) {
|
|
|
462
534
|
})
|
|
463
535
|
.map(([category, categoryEntries]) => ({ category, entries: categoryEntries }));
|
|
464
536
|
}
|
|
465
|
-
|
|
466
|
-
function filterInstalledEntries(entries: readonly ExtensionManagementEntry[], query: string) {
|
|
467
|
-
const normalized = query.trim().toLowerCase();
|
|
468
|
-
if (!normalized) {
|
|
469
|
-
return entries;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return entries.filter((entry) =>
|
|
473
|
-
[entry.displayName, entry.id, entry.category, entry.description ?? '']
|
|
474
|
-
.join(' ')
|
|
475
|
-
.toLowerCase()
|
|
476
|
-
.includes(normalized),
|
|
477
|
-
);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
function filterBrowseEntries(
|
|
481
|
-
entries: readonly ExtensionCatalogBrowseEntry[],
|
|
482
|
-
query: string,
|
|
483
|
-
category?: string,
|
|
484
|
-
) {
|
|
485
|
-
const normalized = query.trim().toLowerCase();
|
|
486
|
-
return entries.filter((entry) => {
|
|
487
|
-
if (category && entry.category !== category) {
|
|
488
|
-
return false;
|
|
489
|
-
}
|
|
490
|
-
if (!normalized) {
|
|
491
|
-
return true;
|
|
492
|
-
}
|
|
493
|
-
return [entry.displayName, entry.id, entry.category, entry.description]
|
|
494
|
-
.join(' ')
|
|
495
|
-
.toLowerCase()
|
|
496
|
-
.includes(normalized);
|
|
497
|
-
});
|
|
498
|
-
}
|
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
extensionCategoryIconTone,
|
|
18
18
|
formatExtensionCategoryLabel,
|
|
19
19
|
} from './extension-category-display.js';
|
|
20
|
+
import { resolveExtensionInstallOptions } from './extension-install-approval.js';
|
|
21
|
+
import { filterBrowseEntries, filterInstalledEntries } from './extension-management-filters.js';
|
|
20
22
|
import { ManagementFilterChips } from './ManagementFilterChips.js';
|
|
21
23
|
import type {
|
|
22
24
|
ExtensionCatalogBrowseEntry,
|
|
@@ -24,6 +26,7 @@ import type {
|
|
|
24
26
|
ExtensionManagementEntry,
|
|
25
27
|
ExtensionManagementFeatureSummary,
|
|
26
28
|
ExtensionManagementPanelProps,
|
|
29
|
+
ExtensionManagementTransition,
|
|
27
30
|
} from './types.js';
|
|
28
31
|
|
|
29
32
|
const BROWSE_CATEGORIES = ['all', 'feature', 'editor', 'theme', 'language'] as const;
|
|
@@ -41,6 +44,7 @@ export interface ExtensionManagementSidebarProps extends ExtensionManagementPane
|
|
|
41
44
|
emptyMarketplaceLabel?: string | undefined;
|
|
42
45
|
missingExtensionIds?: readonly string[] | undefined;
|
|
43
46
|
pendingAction?: ExtensionManagementPendingAction | undefined;
|
|
47
|
+
pendingUninstallEntryId?: string | undefined;
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
export interface ExtensionManagementPendingAction {
|
|
@@ -57,10 +61,14 @@ export function ExtensionManagementSidebar({
|
|
|
57
61
|
emptyInstalledLabel = 'No installed extensions match the filter.',
|
|
58
62
|
emptyMarketplaceLabel = 'No marketplace extensions match the filter.',
|
|
59
63
|
installedEntries,
|
|
64
|
+
isInstallTrusted,
|
|
60
65
|
missingExtensionIds = [],
|
|
61
66
|
onInstall,
|
|
67
|
+
onRememberInstallTrust,
|
|
62
68
|
onToggleEnabled,
|
|
69
|
+
onUninstall,
|
|
63
70
|
pendingAction,
|
|
71
|
+
pendingUninstallEntryId,
|
|
64
72
|
}: ExtensionManagementSidebarProps) {
|
|
65
73
|
const [activeTab, setActiveTab] = useState<'installed' | 'marketplace'>(defaultTab);
|
|
66
74
|
const [query, setQuery] = useState('');
|
|
@@ -98,7 +106,8 @@ export function ExtensionManagementSidebar({
|
|
|
98
106
|
footer={
|
|
99
107
|
<p className="workbench-extensions-sidebar__notice" role="note">
|
|
100
108
|
<i aria-hidden className={cxCodicon('codicon-info')} />
|
|
101
|
-
|
|
109
|
+
Eligible unselected theme packs apply immediately. Other extension changes reload the
|
|
110
|
+
workbench.
|
|
102
111
|
</p>
|
|
103
112
|
}
|
|
104
113
|
footerPlacement="overlay"
|
|
@@ -153,15 +162,19 @@ export function ExtensionManagementSidebar({
|
|
|
153
162
|
catalogLoading={catalogLoading}
|
|
154
163
|
emptyLabel={emptyMarketplaceLabel}
|
|
155
164
|
entries={filteredBrowse}
|
|
165
|
+
isInstallTrusted={isInstallTrusted}
|
|
156
166
|
pendingAction={pendingAction}
|
|
157
167
|
onInstall={onInstall}
|
|
168
|
+
onRememberInstallTrust={onRememberInstallTrust}
|
|
158
169
|
/>
|
|
159
170
|
) : (
|
|
160
171
|
<InstalledExtensionList
|
|
161
172
|
emptyLabel={emptyInstalledLabel}
|
|
162
173
|
entries={filteredInstalled}
|
|
163
174
|
pendingAction={pendingAction}
|
|
175
|
+
pendingUninstallEntryId={pendingUninstallEntryId}
|
|
164
176
|
onToggleEnabled={onToggleEnabled}
|
|
177
|
+
onUninstall={onUninstall}
|
|
165
178
|
/>
|
|
166
179
|
)}
|
|
167
180
|
</SideBarViewFrame>
|
|
@@ -172,12 +185,16 @@ function InstalledExtensionList({
|
|
|
172
185
|
emptyLabel,
|
|
173
186
|
entries,
|
|
174
187
|
onToggleEnabled,
|
|
188
|
+
onUninstall,
|
|
175
189
|
pendingAction,
|
|
190
|
+
pendingUninstallEntryId,
|
|
176
191
|
}: {
|
|
177
192
|
emptyLabel: string;
|
|
178
193
|
entries: readonly ExtensionManagementEntry[];
|
|
179
194
|
onToggleEnabled?: ExtensionManagementPanelProps['onToggleEnabled'];
|
|
195
|
+
onUninstall?: ExtensionManagementPanelProps['onUninstall'];
|
|
180
196
|
pendingAction?: ExtensionManagementPendingAction | undefined;
|
|
197
|
+
pendingUninstallEntryId?: string | undefined;
|
|
181
198
|
}) {
|
|
182
199
|
if (entries.length === 0) {
|
|
183
200
|
return (
|
|
@@ -192,6 +209,8 @@ function InstalledExtensionList({
|
|
|
192
209
|
{entries.map((entry) => {
|
|
193
210
|
const isPendingToggle =
|
|
194
211
|
pendingAction?.kind === 'toggle' && pendingAction.entryId === entry.id;
|
|
212
|
+
const isPendingUninstall = pendingUninstallEntryId === entry.id;
|
|
213
|
+
const isPending = isPendingToggle || isPendingUninstall;
|
|
195
214
|
const errorDiagnostics = (entry.diagnostics ?? []).filter(
|
|
196
215
|
(diagnostic) => diagnostic.severity === 'error',
|
|
197
216
|
);
|
|
@@ -203,15 +222,28 @@ function InstalledExtensionList({
|
|
|
203
222
|
<ExtensionSidebarListItem
|
|
204
223
|
key={entry.id}
|
|
205
224
|
action={
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
225
|
+
<>
|
|
226
|
+
<Button
|
|
227
|
+
compact
|
|
228
|
+
disabled={!onToggleEnabled || entry.source === 'bundled' || isPending}
|
|
229
|
+
type="button"
|
|
230
|
+
variant={entry.enabled ? 'default' : 'primary'}
|
|
231
|
+
onClick={() => onToggleEnabled?.(entry, !entry.enabled)}
|
|
232
|
+
>
|
|
233
|
+
{isPendingToggle ? 'Reloading…' : entry.enabled ? 'Disable' : 'Enable'}
|
|
234
|
+
</Button>
|
|
235
|
+
{entry.canUninstall === true && onUninstall ? (
|
|
236
|
+
<Button
|
|
237
|
+
compact
|
|
238
|
+
disabled={isPending}
|
|
239
|
+
type="button"
|
|
240
|
+
variant="danger"
|
|
241
|
+
onClick={() => onUninstall(entry)}
|
|
242
|
+
>
|
|
243
|
+
{isPendingUninstall ? 'Reloading…' : 'Uninstall'}
|
|
244
|
+
</Button>
|
|
245
|
+
) : null}
|
|
246
|
+
</>
|
|
215
247
|
}
|
|
216
248
|
category={entry.category}
|
|
217
249
|
description={entry.description}
|
|
@@ -242,6 +274,14 @@ function InstalledExtensionList({
|
|
|
242
274
|
{warningDiagnostics.length} warning{warningDiagnostics.length === 1 ? '' : 's'}
|
|
243
275
|
</Badge>
|
|
244
276
|
) : null}
|
|
277
|
+
{entry.transition ? (
|
|
278
|
+
<Badge
|
|
279
|
+
title={entry.transition.message}
|
|
280
|
+
variant={extensionTransitionBadgeVariant(entry.transition.kind)}
|
|
281
|
+
>
|
|
282
|
+
{extensionTransitionLabel(entry.transition.kind)}
|
|
283
|
+
</Badge>
|
|
284
|
+
) : null}
|
|
245
285
|
</>
|
|
246
286
|
}
|
|
247
287
|
title={entry.displayName}
|
|
@@ -252,19 +292,39 @@ function InstalledExtensionList({
|
|
|
252
292
|
);
|
|
253
293
|
}
|
|
254
294
|
|
|
295
|
+
function extensionTransitionLabel(kind: ExtensionManagementTransition['kind']): string {
|
|
296
|
+
if (kind === 'reloadRequired') {
|
|
297
|
+
return 'Reload required';
|
|
298
|
+
}
|
|
299
|
+
return kind === 'failed' ? 'Failed' : 'Applied';
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function extensionTransitionBadgeVariant(
|
|
303
|
+
kind: ExtensionManagementTransition['kind'],
|
|
304
|
+
): 'accent' | 'danger' | 'muted' {
|
|
305
|
+
if (kind === 'failed') {
|
|
306
|
+
return 'danger';
|
|
307
|
+
}
|
|
308
|
+
return kind === 'applied' ? 'accent' : 'muted';
|
|
309
|
+
}
|
|
310
|
+
|
|
255
311
|
function MarketplaceExtensionList({
|
|
256
312
|
catalogError,
|
|
257
313
|
catalogLoading,
|
|
258
314
|
emptyLabel,
|
|
259
315
|
entries,
|
|
316
|
+
isInstallTrusted,
|
|
260
317
|
onInstall,
|
|
318
|
+
onRememberInstallTrust,
|
|
261
319
|
pendingAction,
|
|
262
320
|
}: {
|
|
263
321
|
catalogError?: string | undefined;
|
|
264
322
|
catalogLoading?: boolean | undefined;
|
|
265
323
|
emptyLabel: string;
|
|
266
324
|
entries: readonly ExtensionCatalogBrowseEntry[];
|
|
325
|
+
isInstallTrusted?: ExtensionManagementPanelProps['isInstallTrusted'];
|
|
267
326
|
onInstall?: ExtensionManagementPanelProps['onInstall'];
|
|
327
|
+
onRememberInstallTrust?: ExtensionManagementPanelProps['onRememberInstallTrust'];
|
|
268
328
|
pendingAction?: ExtensionManagementPendingAction | undefined;
|
|
269
329
|
}) {
|
|
270
330
|
if (catalogLoading) {
|
|
@@ -318,7 +378,15 @@ function MarketplaceExtensionList({
|
|
|
318
378
|
}
|
|
319
379
|
type="button"
|
|
320
380
|
variant={entry.installed ? 'default' : 'primary'}
|
|
321
|
-
onClick={() =>
|
|
381
|
+
onClick={() => {
|
|
382
|
+
if (!onInstall) return;
|
|
383
|
+
const options = resolveExtensionInstallOptions(entry, {
|
|
384
|
+
isTrusted: isInstallTrusted,
|
|
385
|
+
rememberTrust: onRememberInstallTrust,
|
|
386
|
+
});
|
|
387
|
+
if (!options) return;
|
|
388
|
+
onInstall(entry, options);
|
|
389
|
+
}}
|
|
322
390
|
>
|
|
323
391
|
{entry.installed
|
|
324
392
|
? 'Installed'
|
|
@@ -456,37 +524,3 @@ function formatFeatureBadge(label: string, count: number) {
|
|
|
456
524
|
|
|
457
525
|
return `${label} ${count}`;
|
|
458
526
|
}
|
|
459
|
-
|
|
460
|
-
function filterInstalledEntries(entries: readonly ExtensionManagementEntry[], query: string) {
|
|
461
|
-
const normalized = query.trim().toLowerCase();
|
|
462
|
-
if (!normalized) {
|
|
463
|
-
return entries;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
return entries.filter((entry) =>
|
|
467
|
-
[entry.displayName, entry.id, entry.category, entry.description ?? '']
|
|
468
|
-
.join(' ')
|
|
469
|
-
.toLowerCase()
|
|
470
|
-
.includes(normalized),
|
|
471
|
-
);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
function filterBrowseEntries(
|
|
475
|
-
entries: readonly ExtensionCatalogBrowseEntry[],
|
|
476
|
-
query: string,
|
|
477
|
-
category?: string,
|
|
478
|
-
) {
|
|
479
|
-
const normalized = query.trim().toLowerCase();
|
|
480
|
-
return entries.filter((entry) => {
|
|
481
|
-
if (category && entry.category !== category) {
|
|
482
|
-
return false;
|
|
483
|
-
}
|
|
484
|
-
if (!normalized) {
|
|
485
|
-
return true;
|
|
486
|
-
}
|
|
487
|
-
return [entry.displayName, entry.id, entry.category, entry.description]
|
|
488
|
-
.join(' ')
|
|
489
|
-
.toLowerCase()
|
|
490
|
-
.includes(normalized);
|
|
491
|
-
});
|
|
492
|
-
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import { Button } from '../../primitives/button';
|
|
3
3
|
import { WorkbenchPropertyInline } from '../../layout/WorkbenchPropertyPanel';
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
export interface IntegrationCommandAction<TCommandId extends string = string> {
|
|
6
|
+
readonly enabled: boolean;
|
|
7
|
+
readonly execute: () => Promise<void> | void;
|
|
8
|
+
readonly id: TCommandId;
|
|
9
|
+
readonly label: string;
|
|
10
|
+
readonly visible?: boolean | undefined;
|
|
11
|
+
}
|
|
5
12
|
|
|
6
13
|
type IntegrationActionRowAlign = 'center' | 'start';
|
|
7
14
|
type IntegrationActionRowJustify = 'between' | 'end' | 'start';
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
WorkbenchPropertySection,
|
|
8
8
|
WorkbenchPropertyStack,
|
|
9
9
|
} from '../../primitives/index';
|
|
10
|
+
import { cx } from '../../utils/cx';
|
|
10
11
|
|
|
11
12
|
type IntegrationSettingsDensity = 'compact' | 'default';
|
|
12
13
|
type IntegrationSettingsInset = 'default' | 'flush';
|
|
@@ -206,7 +207,7 @@ export function IntegrationAccountRowEditor({
|
|
|
206
207
|
export function IntegrationBodyText({ children, size = 'default' }: IntegrationBodyTextProps) {
|
|
207
208
|
return (
|
|
208
209
|
<WorkbenchPropertyHint
|
|
209
|
-
className={
|
|
210
|
+
className={cx('block', size === 'compact' ? 'text-xs' : undefined)}
|
|
210
211
|
data-size={size}
|
|
211
212
|
>
|
|
212
213
|
{children}
|
|
@@ -284,7 +285,3 @@ function IntegrationEditorDescription({ children }: { children?: ReactNode }) {
|
|
|
284
285
|
function hasRenderableNode(node: ReactNode | undefined): boolean {
|
|
285
286
|
return node !== undefined && node !== null && node !== false;
|
|
286
287
|
}
|
|
287
|
-
|
|
288
|
-
function joinClasses(...classes: Array<string | undefined>): string {
|
|
289
|
-
return classes.filter(Boolean).join(' ');
|
|
290
|
-
}
|
|
@@ -2,7 +2,7 @@ import type { ReactNode } from 'react';
|
|
|
2
2
|
import { PanelHeader } from '../../layout/panel';
|
|
3
3
|
import { WorkbenchEditorFrame, WorkbenchPanelScroll } from '../../layout/WorkbenchLayoutBase';
|
|
4
4
|
import { WorkbenchPropertyHint } from '../../layout/WorkbenchPropertyPanel';
|
|
5
|
-
import { SplitView } from '../SplitView';
|
|
5
|
+
import { SplitView } from '../shell/SplitView';
|
|
6
6
|
|
|
7
7
|
export interface IntegrationsShellProps {
|
|
8
8
|
children: ReactNode;
|
|
@@ -2,6 +2,7 @@ import { useEffect, useId, useRef, useState, type KeyboardEvent } from 'react';
|
|
|
2
2
|
import { formatKeybindingLabel } from '@workbench-kit/platform';
|
|
3
3
|
import { Button } from '../../primitives/button';
|
|
4
4
|
import { cx } from '../../utils/cx';
|
|
5
|
+
import { normalizeKeyToken } from '../../utils/normalizeKeyToken';
|
|
5
6
|
|
|
6
7
|
export interface KeybindingCaptureFieldProps {
|
|
7
8
|
ariaLabel?: string | undefined;
|
|
@@ -131,12 +132,3 @@ function normalizeKeybindingKeyFromEvent(
|
|
|
131
132
|
parts.push(normalizeKeyToken(event.key));
|
|
132
133
|
return parts.join('+');
|
|
133
134
|
}
|
|
134
|
-
|
|
135
|
-
function normalizeKeyToken(token: string): string {
|
|
136
|
-
const key = token.trim().toLowerCase();
|
|
137
|
-
if (key === 'del') return 'delete';
|
|
138
|
-
if (key === 'esc') return 'escape';
|
|
139
|
-
if (key === 'return') return 'enter';
|
|
140
|
-
if (key === 'spacebar' || key === 'space') return 'space';
|
|
141
|
-
return key.length === 1 ? key : key;
|
|
142
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { FormEventHandler, ReactNode } from 'react';
|
|
2
2
|
import { Modal, type ModalBodyLayout, type ModalBodyPadding } from '../../modal/Modal';
|
|
3
|
-
import type { WorkbenchWindowChromeMode } from '../workbenchPlatformChrome';
|
|
4
|
-
import { WorkbenchModalPortal } from '../WorkbenchModalPortal';
|
|
3
|
+
import type { WorkbenchWindowChromeMode } from '../chrome/workbenchPlatformChrome';
|
|
4
|
+
import { WorkbenchModalPortal } from '../chrome/WorkbenchModalPortal';
|
|
5
5
|
|
|
6
6
|
export type WorkbenchDialogBodyLayout = 'column-fill' | 'default' | 'padded-fill';
|
|
7
7
|
export type WorkbenchDialogFrameSize =
|
|
@@ -149,16 +149,16 @@ export function WorkbenchNoticeViewport({
|
|
|
149
149
|
|
|
150
150
|
return (
|
|
151
151
|
<div
|
|
152
|
-
|
|
153
|
-
className={resolveNoticeViewportClassName(position)}
|
|
152
|
+
className="ui-workbench-notice-viewport"
|
|
154
153
|
data-position={position}
|
|
154
|
+
style={resolveNoticeViewportStyle(position)}
|
|
155
155
|
{...(dataAttributes ?? {})}
|
|
156
156
|
>
|
|
157
157
|
{visibleNotices.map((notice) => (
|
|
158
158
|
<WorkbenchBanner
|
|
159
|
-
className="pointer-events-auto"
|
|
160
159
|
data-tone={notice.tone}
|
|
161
160
|
key={notice.id}
|
|
161
|
+
role={notice.tone === 'error' ? 'alert' : 'status'}
|
|
162
162
|
style={resolveNoticeBannerStyle(notice.tone)}
|
|
163
163
|
tone={notice.tone === 'warning' ? 'warning' : 'default'}
|
|
164
164
|
{...(notice.dataAttributes ?? {})}
|
|
@@ -186,13 +186,6 @@ export function useWorkbenchNotice(): WorkbenchNoticeController {
|
|
|
186
186
|
return controller;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
function resolveNoticeViewportClassName(position: WorkbenchNoticePosition): string {
|
|
190
|
-
return joinClasses(
|
|
191
|
-
'pointer-events-none fixed inset-x-0 bottom-4 z-50 flex flex-col gap-2 px-4',
|
|
192
|
-
position === 'bottom-center' ? 'items-center' : 'items-end',
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
189
|
function resolveNoticeBannerStyle(tone: WorkbenchNoticeTone): CSSProperties {
|
|
197
190
|
return {
|
|
198
191
|
borderColor:
|
|
@@ -203,9 +196,21 @@ function resolveNoticeBannerStyle(tone: WorkbenchNoticeTone): CSSProperties {
|
|
|
203
196
|
: undefined,
|
|
204
197
|
maxWidth: 'min(520px, calc(100vw - 32px))',
|
|
205
198
|
minWidth: 'min(420px, calc(100vw - 32px))',
|
|
199
|
+
pointerEvents: 'auto',
|
|
206
200
|
};
|
|
207
201
|
}
|
|
208
202
|
|
|
209
|
-
function
|
|
210
|
-
return
|
|
203
|
+
function resolveNoticeViewportStyle(position: WorkbenchNoticePosition): CSSProperties {
|
|
204
|
+
return {
|
|
205
|
+
alignItems: position === 'bottom-center' ? 'center' : 'flex-end',
|
|
206
|
+
bottom: 16,
|
|
207
|
+
display: 'flex',
|
|
208
|
+
flexDirection: 'column',
|
|
209
|
+
gap: 8,
|
|
210
|
+
insetInline: 0,
|
|
211
|
+
paddingInline: 16,
|
|
212
|
+
pointerEvents: 'none',
|
|
213
|
+
position: 'fixed',
|
|
214
|
+
zIndex: 50,
|
|
215
|
+
};
|
|
211
216
|
}
|