diff --git a/browser_tests/fixtures/components/SettingDialog.ts b/browser_tests/fixtures/components/SettingDialog.ts index 4587d85f31..24e64db974 100644 --- a/browser_tests/fixtures/components/SettingDialog.ts +++ b/browser_tests/fixtures/components/SettingDialog.ts @@ -23,9 +23,7 @@ export class SettingDialog extends BaseDialog { * @param value - The value to set */ async setStringSetting(id: string, value: string) { - const settingInputDiv = this.page.locator( - `div.settings-container div[id="${id}"]` - ) + const settingInputDiv = this.root.locator(`div[id="${id}"]`) await settingInputDiv.locator('input').fill(value) } @@ -34,16 +32,15 @@ export class SettingDialog extends BaseDialog { * @param id - The id of the setting */ async toggleBooleanSetting(id: string) { - const settingInputDiv = this.page.locator( - `div.settings-container div[id="${id}"]` - ) + const settingInputDiv = this.root.locator(`div[id="${id}"]`) await settingInputDiv.locator('input').click() } async goToAboutPanel() { - await this.page.getByTestId(TestIds.dialogs.settingsTabAbout).click() - await this.page - .getByTestId(TestIds.dialogs.about) - .waitFor({ state: 'visible' }) + const aboutButton = this.root.locator('nav [role="button"]', { + hasText: 'About' + }) + await aboutButton.click() + await this.page.waitForSelector('.about-container') } } diff --git a/browser_tests/tests/dialog.spec.ts b/browser_tests/tests/dialog.spec.ts index fddbfbc708..6ee5559da0 100644 --- a/browser_tests/tests/dialog.spec.ts +++ b/browser_tests/tests/dialog.spec.ts @@ -244,9 +244,13 @@ test.describe('Missing models warning', () => { test.describe('Settings', () => { test('@mobile Should be visible on mobile', async ({ comfyPage }) => { await comfyPage.page.keyboard.press('Control+,') - const settingsContent = comfyPage.page.locator('.settings-content') - await expect(settingsContent).toBeVisible() - const isUsableHeight = await settingsContent.evaluate( + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) + await expect(settingsDialog).toBeVisible() + const contentArea = settingsDialog.locator('main') + await expect(contentArea).toBeVisible() + const isUsableHeight = await contentArea.evaluate( (el) => el.clientHeight > 30 ) expect(isUsableHeight).toBeTruthy() @@ -256,7 +260,9 @@ test.describe('Settings', () => { await comfyPage.page.keyboard.down('ControlOrMeta') await comfyPage.page.keyboard.press(',') await comfyPage.page.keyboard.up('ControlOrMeta') - const settingsLocator = comfyPage.page.locator('.settings-container') + const settingsLocator = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsLocator).toBeVisible() await comfyPage.page.keyboard.press('Escape') await expect(settingsLocator).not.toBeVisible() @@ -275,10 +281,15 @@ test.describe('Settings', () => { test('Should persist keybinding setting', async ({ comfyPage }) => { // Open the settings dialog await comfyPage.page.keyboard.press('Control+,') - await comfyPage.page.waitForSelector('.settings-container') + await comfyPage.page.waitForSelector('[data-testid="settings-dialog"]') // Open the keybinding tab - await comfyPage.page.getByLabel('Keybinding').click() + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) + await settingsDialog + .locator('nav [role="button"]', { hasText: 'Keybinding' }) + .click() await comfyPage.page.waitForSelector( '[placeholder="Search Keybindings..."]' ) diff --git a/browser_tests/tests/subgraph.spec.ts b/browser_tests/tests/subgraph.spec.ts index cc78b49539..3aac7feb48 100644 --- a/browser_tests/tests/subgraph.spec.ts +++ b/browser_tests/tests/subgraph.spec.ts @@ -820,7 +820,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { // Open settings dialog using hotkey await comfyPage.page.keyboard.press('Control+,') - await comfyPage.page.waitForSelector('.settings-container', { + await comfyPage.page.waitForSelector('[data-testid="settings-dialog"]', { state: 'visible' }) @@ -830,7 +830,7 @@ test.describe('Subgraph Operations', { tag: ['@slow', '@subgraph'] }, () => { // Dialog should be closed await expect( - comfyPage.page.locator('.settings-container') + comfyPage.page.locator('[data-testid="settings-dialog"]') ).not.toBeVisible() // Should still be in subgraph diff --git a/browser_tests/tests/useSettingSearch.spec.ts b/browser_tests/tests/useSettingSearch.spec.ts index 43ddd09e79..371ca7b9b4 100644 --- a/browser_tests/tests/useSettingSearch.spec.ts +++ b/browser_tests/tests/useSettingSearch.spec.ts @@ -22,7 +22,6 @@ test.describe('Settings Search functionality', { tag: '@settings' }, () => { name: 'TestSettingsExtension', settings: [ { - // Extensions can register arbitrary setting IDs id: 'TestHiddenSetting' as TestSettingId, name: 'Test Hidden Setting', type: 'hidden', @@ -30,7 +29,6 @@ test.describe('Settings Search functionality', { tag: '@settings' }, () => { category: ['Test', 'Hidden'] }, { - // Extensions can register arbitrary setting IDs id: 'TestDeprecatedSetting' as TestSettingId, name: 'Test Deprecated Setting', type: 'text', @@ -39,7 +37,6 @@ test.describe('Settings Search functionality', { tag: '@settings' }, () => { category: ['Test', 'Deprecated'] }, { - // Extensions can register arbitrary setting IDs id: 'TestVisibleSetting' as TestSettingId, name: 'Test Visible Setting', type: 'text', @@ -52,16 +49,15 @@ test.describe('Settings Search functionality', { tag: '@settings' }, () => { }) test('can open settings dialog and use search box', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Find the search box - const searchBox = comfyPage.page.locator('.settings-search-box input') + const searchBox = settingsDialog.locator('input[placeholder*="Search"]') await expect(searchBox).toBeVisible() - // Verify search box has the correct placeholder await expect(searchBox).toHaveAttribute( 'placeholder', expect.stringContaining('Search') @@ -69,221 +65,198 @@ test.describe('Settings Search functionality', { tag: '@settings' }, () => { }) test('search box is functional and accepts input', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Find and interact with the search box - const searchBox = comfyPage.page.locator('.settings-search-box input') + const searchBox = settingsDialog.locator('input[placeholder*="Search"]') await searchBox.fill('Comfy') - // Verify the input was accepted await expect(searchBox).toHaveValue('Comfy') }) test('search box clears properly', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Find and interact with the search box - const searchBox = comfyPage.page.locator('.settings-search-box input') + const searchBox = settingsDialog.locator('input[placeholder*="Search"]') await searchBox.fill('test') await expect(searchBox).toHaveValue('test') - // Clear the search box await searchBox.clear() await expect(searchBox).toHaveValue('') }) test('settings categories are visible in sidebar', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Check that the sidebar has categories - const categories = comfyPage.page.locator( - '.settings-sidebar .p-listbox-option' - ) + const categories = settingsDialog.locator('nav [role="button"]') expect(await categories.count()).toBeGreaterThan(0) - // Check that at least one category is visible await expect(categories.first()).toBeVisible() }) test('can select different categories in sidebar', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Click on a specific category (Appearance) to verify category switching - const appearanceCategory = comfyPage.page.getByRole('option', { - name: 'Appearance' - }) - await appearanceCategory.click() + const categories = settingsDialog.locator('nav [role="button"]') + const categoryCount = await categories.count() - // Verify the category is selected - await expect(appearanceCategory).toHaveClass(/p-listbox-option-selected/) + if (categoryCount > 1) { + await categories.nth(1).click() + + await expect(categories.nth(1)).toHaveClass( + /bg-interface-menu-component-surface-selected/ + ) + } }) test('settings content area is visible', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Check that the content area is visible - const contentArea = comfyPage.page.locator('.settings-content') + const contentArea = settingsDialog.locator('main') await expect(contentArea).toBeVisible() - - // Check that tab panels are visible - const tabPanels = comfyPage.page.locator('.settings-tab-panels') - await expect(tabPanels).toBeVisible() }) test('search functionality affects UI state', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Find the search box - const searchBox = comfyPage.page.locator('.settings-search-box input') - - // Type in search box + const searchBox = settingsDialog.locator('input[placeholder*="Search"]') await searchBox.fill('graph') - // Verify that the search input is handled await expect(searchBox).toHaveValue('graph') }) test('settings dialog can be closed', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Close with escape key await comfyPage.page.keyboard.press('Escape') - // Verify dialog is closed await expect(settingsDialog).not.toBeVisible() }) test('search box has proper debouncing behavior', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Type rapidly in search box - const searchBox = comfyPage.page.locator('.settings-search-box input') + const searchBox = settingsDialog.locator('input[placeholder*="Search"]') await searchBox.fill('a') await searchBox.fill('ab') await searchBox.fill('abc') await searchBox.fill('abcd') - // Verify final value await expect(searchBox).toHaveValue('abcd') }) test('search excludes hidden settings from results', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Search for our test settings - const searchBox = comfyPage.page.locator('.settings-search-box input') + const searchBox = settingsDialog.locator('input[placeholder*="Search"]') await searchBox.fill('Test') - // Get all settings content - const settingsContent = comfyPage.page.locator('.settings-tab-panels') + const contentArea = settingsDialog.locator('main') - // Should show visible setting but not hidden setting - await expect(settingsContent).toContainText('Test Visible Setting') - await expect(settingsContent).not.toContainText('Test Hidden Setting') + await expect(contentArea).toContainText('Test Visible Setting') + await expect(contentArea).not.toContainText('Test Hidden Setting') }) test('search excludes deprecated settings from results', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Search for our test settings - const searchBox = comfyPage.page.locator('.settings-search-box input') + const searchBox = settingsDialog.locator('input[placeholder*="Search"]') await searchBox.fill('Test') - // Get all settings content - const settingsContent = comfyPage.page.locator('.settings-tab-panels') + const contentArea = settingsDialog.locator('main') - // Should show visible setting but not deprecated setting - await expect(settingsContent).toContainText('Test Visible Setting') - await expect(settingsContent).not.toContainText('Test Deprecated Setting') + await expect(contentArea).toContainText('Test Visible Setting') + await expect(contentArea).not.toContainText('Test Deprecated Setting') }) test('search shows visible settings but excludes hidden and deprecated', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - // Search for our test settings - const searchBox = comfyPage.page.locator('.settings-search-box input') + const searchBox = settingsDialog.locator('input[placeholder*="Search"]') await searchBox.fill('Test') - // Get all settings content - const settingsContent = comfyPage.page.locator('.settings-tab-panels') + const contentArea = settingsDialog.locator('main') - // Should only show the visible setting - await expect(settingsContent).toContainText('Test Visible Setting') + await expect(contentArea).toContainText('Test Visible Setting') - // Should not show hidden or deprecated settings - await expect(settingsContent).not.toContainText('Test Hidden Setting') - await expect(settingsContent).not.toContainText('Test Deprecated Setting') + await expect(contentArea).not.toContainText('Test Hidden Setting') + await expect(contentArea).not.toContainText('Test Deprecated Setting') }) test('search by setting name excludes hidden and deprecated', async ({ comfyPage }) => { - // Open settings dialog await comfyPage.page.keyboard.press('Control+,') - const settingsDialog = comfyPage.page.locator('.settings-container') + const settingsDialog = comfyPage.page.locator( + '[data-testid="settings-dialog"]' + ) await expect(settingsDialog).toBeVisible() - const searchBox = comfyPage.page.locator('.settings-search-box input') - const settingsContent = comfyPage.page.locator('.settings-tab-panels') + const searchBox = settingsDialog.locator('input[placeholder*="Search"]') + const contentArea = settingsDialog.locator('main') - // Search specifically for hidden setting by name await searchBox.clear() await searchBox.fill('Hidden') - // Should not show the hidden setting even when searching by name - await expect(settingsContent).not.toContainText('Test Hidden Setting') + await expect(contentArea).not.toContainText('Test Hidden Setting') - // Search specifically for deprecated setting by name await searchBox.clear() await searchBox.fill('Deprecated') - // Should not show the deprecated setting even when searching by name - await expect(settingsContent).not.toContainText('Test Deprecated Setting') + await expect(contentArea).not.toContainText('Test Deprecated Setting') - // Search for visible setting by name - should work await searchBox.clear() await searchBox.fill('Visible') - // Should show the visible setting - await expect(settingsContent).toContainText('Test Visible Setting') + await expect(contentArea).toContainText('Test Visible Setting') }) }) diff --git a/src/components/bottomPanel/BottomPanel.vue b/src/components/bottomPanel/BottomPanel.vue index aa68006779..08f23c5098 100644 --- a/src/components/bottomPanel/BottomPanel.vue +++ b/src/components/bottomPanel/BottomPanel.vue @@ -89,12 +89,12 @@ import { useI18n } from 'vue-i18n' import ExtensionSlot from '@/components/common/ExtensionSlot.vue' import Button from '@/components/ui/button/Button.vue' -import { useDialogService } from '@/services/dialogService' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore' import type { BottomPanelExtension } from '@/types/extensionTypes' const bottomPanelStore = useBottomPanelStore() -const dialogService = useDialogService() +const settingsDialog = useSettingsDialog() const { t } = useI18n() const isShortcutsTabActive = computed(() => { @@ -115,7 +115,7 @@ const getTabDisplayTitle = (tab: BottomPanelExtension): string => { } const openKeybindingSettings = async () => { - dialogService.showSettingsDialog('keybinding') + settingsDialog.show('keybinding') } const closeBottomPanel = () => { diff --git a/src/components/dialog/GlobalDialog.vue b/src/components/dialog/GlobalDialog.vue index aede769071..900d843d2f 100644 --- a/src/components/dialog/GlobalDialog.vue +++ b/src/components/dialog/GlobalDialog.vue @@ -4,12 +4,7 @@ v-for="item in dialogStore.dialogStack" :key="item.key" v-model:visible="item.visible" - :class="[ - 'global-dialog', - item.key === 'global-settings' && teamWorkspacesEnabled - ? 'settings-dialog-workspace' - : '' - ]" + class="global-dialog" v-bind="item.dialogComponentProps" :pt="getDialogPt(item)" :aria-labelledby="item.key" diff --git a/src/components/dialog/content/TopUpCreditsDialogContentLegacy.vue b/src/components/dialog/content/TopUpCreditsDialogContentLegacy.vue index 03640fbfa3..536a9c785a 100644 --- a/src/components/dialog/content/TopUpCreditsDialogContentLegacy.vue +++ b/src/components/dialog/content/TopUpCreditsDialogContentLegacy.vue @@ -162,7 +162,7 @@ import { useFeatureFlags } from '@/composables/useFeatureFlags' import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription' import { useTelemetry } from '@/platform/telemetry' import { clearTopupTracking } from '@/platform/telemetry/topupTracker' -import { useDialogService } from '@/services/dialogService' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { useDialogStore } from '@/stores/dialogStore' import { cn } from '@/utils/tailwindUtil' @@ -173,7 +173,7 @@ const { isInsufficientCredits = false } = defineProps<{ const { t } = useI18n() const authActions = useFirebaseAuthActions() const dialogStore = useDialogStore() -const dialogService = useDialogService() +const settingsDialog = useSettingsDialog() const telemetry = useTelemetry() const toast = useToast() const { buildDocsUrl, docsPaths } = useExternalLink() @@ -266,7 +266,7 @@ async function handleBuy() { : isSubscriptionEnabled() ? 'subscription' : 'credits' - dialogService.showSettingsDialog(settingsPanel) + settingsDialog.show(settingsPanel) } catch (error) { console.error('Purchase failed:', error) diff --git a/src/components/dialog/content/TopUpCreditsDialogContentWorkspace.vue b/src/components/dialog/content/TopUpCreditsDialogContentWorkspace.vue index 1f076abe02..e01664b9ad 100644 --- a/src/components/dialog/content/TopUpCreditsDialogContentWorkspace.vue +++ b/src/components/dialog/content/TopUpCreditsDialogContentWorkspace.vue @@ -161,7 +161,7 @@ import { useExternalLink } from '@/composables/useExternalLink' import { useTelemetry } from '@/platform/telemetry' import { clearTopupTracking } from '@/platform/telemetry/topupTracker' import { workspaceApi } from '@/platform/workspace/api/workspaceApi' -import { useDialogService } from '@/services/dialogService' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { useBillingOperationStore } from '@/stores/billingOperationStore' import { useDialogStore } from '@/stores/dialogStore' import { cn } from '@/utils/tailwindUtil' @@ -172,7 +172,7 @@ const { isInsufficientCredits = false } = defineProps<{ const { t } = useI18n() const dialogStore = useDialogStore() -const dialogService = useDialogService() +const settingsDialog = useSettingsDialog() const telemetry = useTelemetry() const toast = useToast() const { buildDocsUrl, docsPaths } = useExternalLink() @@ -266,7 +266,7 @@ async function handleBuy() { }) await fetchBalance() handleClose(false) - dialogService.showSettingsDialog('workspace') + settingsDialog.show('workspace') } else if (response.status === 'pending') { billingOperationStore.startOperation(response.billing_op_id, 'topup') } else { diff --git a/src/components/dialog/content/setting/AboutPanel.vue b/src/components/dialog/content/setting/AboutPanel.vue index d8389cb384..979ac8aa2f 100644 --- a/src/components/dialog/content/setting/AboutPanel.vue +++ b/src/components/dialog/content/setting/AboutPanel.vue @@ -1,9 +1,5 @@ diff --git a/src/components/dialog/content/setting/KeybindingPanel.vue b/src/components/dialog/content/setting/KeybindingPanel.vue index dff5f7dfbb..5beb1ac366 100644 --- a/src/components/dialog/content/setting/KeybindingPanel.vue +++ b/src/components/dialog/content/setting/KeybindingPanel.vue @@ -1,13 +1,9 @@ diff --git a/src/components/dialog/content/setting/UserPanel.vue b/src/components/dialog/content/setting/UserPanel.vue index 82985641d0..e289f16856 100644 --- a/src/components/dialog/content/setting/UserPanel.vue +++ b/src/components/dialog/content/setting/UserPanel.vue @@ -1,5 +1,5 @@ diff --git a/src/components/dialog/content/setting/WorkspacePanelContent.vue b/src/components/dialog/content/setting/WorkspacePanelContent.vue index c4ac049e96..4a390725bf 100644 --- a/src/components/dialog/content/setting/WorkspacePanelContent.vue +++ b/src/components/dialog/content/setting/WorkspacePanelContent.vue @@ -9,128 +9,94 @@ {{ workspaceName }} - -
- - - {{ $t('workspacePanel.tabs.planCredits') }} - - - {{ - $t('workspacePanel.tabs.membersCount', { - count: isInPersonalWorkspace ? 1 : members.length - }) - }} - - - - -
+
+ + {{ $t('workspacePanel.tabs.planCredits') }} + + {{ + $t('workspacePanel.tabs.membersCount', { + count: isInPersonalWorkspace ? 1 : members.length + }) + }} + + - - - - - - - - - + + +
+ +
+ +
+
+ +
diff --git a/src/components/dialog/header/SettingDialogHeader.vue b/src/components/dialog/header/SettingDialogHeader.vue deleted file mode 100644 index 3c098430eb..0000000000 --- a/src/components/dialog/header/SettingDialogHeader.vue +++ /dev/null @@ -1,32 +0,0 @@ - - - - diff --git a/src/components/rightSidePanel/settings/TabGlobalSettings.vue b/src/components/rightSidePanel/settings/TabGlobalSettings.vue index ec291cd983..f91cbcabb4 100644 --- a/src/components/rightSidePanel/settings/TabGlobalSettings.vue +++ b/src/components/rightSidePanel/settings/TabGlobalSettings.vue @@ -11,7 +11,7 @@ import type { LinkRenderType } from '@/lib/litegraph/src/types/globalEnums' import { LinkMarkerShape } from '@/lib/litegraph/src/types/globalEnums' import { useSettingStore } from '@/platform/settings/settingStore' import { WidgetInputBaseClass } from '@/renderer/extensions/vueNodes/widgets/components/layout' -import { useDialogService } from '@/services/dialogService' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { cn } from '@/utils/tailwindUtil' import PropertiesAccordionItem from '../layout/PropertiesAccordionItem.vue' @@ -20,7 +20,7 @@ import LayoutField from './LayoutField.vue' const { t } = useI18n() const settingStore = useSettingStore() -const dialogService = useDialogService() +const settingsDialog = useSettingsDialog() // NODES settings const showAdvancedParameters = computed({ @@ -92,7 +92,7 @@ function updateGridSpacingFromInput(value: number | null | undefined) { } function openFullSettings() { - dialogService.showSettingsDialog() + settingsDialog.show() } diff --git a/src/components/sidebar/ComfyMenuButton.vue b/src/components/sidebar/ComfyMenuButton.vue index 173000f4d7..3f5122a5f6 100644 --- a/src/components/sidebar/ComfyMenuButton.vue +++ b/src/components/sidebar/ComfyMenuButton.vue @@ -108,15 +108,13 @@ import ToggleSwitch from 'primevue/toggleswitch' import { computed, nextTick, ref } from 'vue' import { useI18n } from 'vue-i18n' -import SettingDialogHeader from '@/components/dialog/header/SettingDialogHeader.vue' import ComfyLogo from '@/components/icons/ComfyLogo.vue' import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog' -import SettingDialogContent from '@/platform/settings/components/SettingDialogContent.vue' import { useSettingStore } from '@/platform/settings/settingStore' import { useTelemetry } from '@/platform/telemetry' import { useColorPaletteService } from '@/services/colorPaletteService' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { useCommandStore } from '@/stores/commandStore' -import { useDialogStore } from '@/stores/dialogStore' import { useMenuItemStore } from '@/stores/menuItemStore' import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore' import { normalizeI18nKey } from '@/utils/formatUtil' @@ -129,7 +127,7 @@ const commandStore = useCommandStore() const menuItemStore = useMenuItemStore() const colorPaletteStore = useColorPaletteStore() const colorPaletteService = useColorPaletteService() -const dialogStore = useDialogStore() +const settingsDialog = useSettingsDialog() const managerState = useManagerState() const settingStore = useSettingStore() @@ -167,14 +165,7 @@ const translateMenuItem = (item: MenuItem): MenuItem => { } const showSettings = (defaultPanel?: string) => { - dialogStore.showDialog({ - key: 'global-settings', - headerComponent: SettingDialogHeader, - component: SettingDialogContent, - props: { - defaultPanel - } - }) + settingsDialog.show(defaultPanel as Parameters[0]) } const showManageExtensions = async () => { diff --git a/src/components/topbar/CurrentUserPopoverLegacy.test.ts b/src/components/topbar/CurrentUserPopoverLegacy.test.ts index 8dff976b98..b95101848a 100644 --- a/src/components/topbar/CurrentUserPopoverLegacy.test.ts +++ b/src/components/topbar/CurrentUserPopoverLegacy.test.ts @@ -31,6 +31,15 @@ vi.mock('pinia') const mockShowSettingsDialog = vi.fn() const mockShowTopUpCreditsDialog = vi.fn() +// Mock the settings dialog composable +vi.mock('@/platform/settings/composables/useSettingsDialog', () => ({ + useSettingsDialog: vi.fn(() => ({ + show: mockShowSettingsDialog, + hide: vi.fn(), + showAbout: vi.fn() + })) +})) + // Mock window.open const originalWindowOpen = window.open beforeEach(() => { @@ -64,7 +73,6 @@ vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({ // Mock the dialog service vi.mock('@/services/dialogService', () => ({ useDialogService: vi.fn(() => ({ - showSettingsDialog: mockShowSettingsDialog, showTopUpCreditsDialog: mockShowTopUpCreditsDialog })) })) diff --git a/src/components/topbar/CurrentUserPopoverLegacy.vue b/src/components/topbar/CurrentUserPopoverLegacy.vue index 69961628d9..e6e0bdd871 100644 --- a/src/components/topbar/CurrentUserPopoverLegacy.vue +++ b/src/components/topbar/CurrentUserPopoverLegacy.vue @@ -152,6 +152,7 @@ import { useSubscription } from '@/platform/cloud/subscription/composables/useSu import { useSubscriptionDialog } from '@/platform/cloud/subscription/composables/useSubscriptionDialog' import { isCloud } from '@/platform/distribution/types' import { useTelemetry } from '@/platform/telemetry' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { useDialogService } from '@/services/dialogService' import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' @@ -165,6 +166,7 @@ const { userDisplayName, userEmail, userPhotoUrl, handleSignOut } = useCurrentUser() const authActions = useFirebaseAuthActions() const authStore = useFirebaseAuthStore() +const settingsDialog = useSettingsDialog() const dialogService = useDialogService() const { isActiveSubscription, @@ -198,7 +200,7 @@ const canUpgrade = computed(() => { }) const handleOpenUserSettings = () => { - dialogService.showSettingsDialog('user') + settingsDialog.show('user') emit('close') } @@ -209,9 +211,9 @@ const handleOpenPlansAndPricing = () => { const handleOpenPlanAndCreditsSettings = () => { if (isCloud) { - dialogService.showSettingsDialog('subscription') + settingsDialog.show('subscription') } else { - dialogService.showSettingsDialog('credits') + settingsDialog.show('credits') } emit('close') diff --git a/src/components/topbar/CurrentUserPopoverWorkspace.vue b/src/components/topbar/CurrentUserPopoverWorkspace.vue index 64ea81191c..813782a4a0 100644 --- a/src/components/topbar/CurrentUserPopoverWorkspace.vue +++ b/src/components/topbar/CurrentUserPopoverWorkspace.vue @@ -222,6 +222,7 @@ import { isCloud } from '@/platform/distribution/types' import { useTelemetry } from '@/platform/telemetry' import { useWorkspaceUI } from '@/platform/workspace/composables/useWorkspaceUI' import { useTeamWorkspaceStore } from '@/platform/workspace/stores/teamWorkspaceStore' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { useDialogService } from '@/services/dialogService' const workspaceStore = useTeamWorkspaceStore() @@ -242,6 +243,7 @@ const { buildDocsUrl, docsPaths } = useExternalLink() const { userDisplayName, userEmail, userPhotoUrl, handleSignOut } = useCurrentUser() +const settingsDialog = useSettingsDialog() const dialogService = useDialogService() const { isActiveSubscription, subscription, balance, isLoading, fetchBalance } = useBillingContext() @@ -285,12 +287,12 @@ const showCreditsSection = computed( ) const handleOpenUserSettings = () => { - dialogService.showSettingsDialog('user') + settingsDialog.show('user') emit('close') } const handleOpenWorkspaceSettings = () => { - dialogService.showSettingsDialog('workspace') + settingsDialog.show('workspace') emit('close') } @@ -301,9 +303,9 @@ const handleOpenPlansAndPricing = () => { const handleOpenPlanAndCreditsSettings = () => { if (isCloud) { - dialogService.showSettingsDialog('workspace') + settingsDialog.show('workspace') } else { - dialogService.showSettingsDialog('credits') + settingsDialog.show('credits') } emit('close') diff --git a/src/components/widget/panel/PanelHeader.vue b/src/components/widget/panel/PanelHeader.vue new file mode 100644 index 0000000000..22ec7d700f --- /dev/null +++ b/src/components/widget/panel/PanelHeader.vue @@ -0,0 +1,6 @@ + diff --git a/src/composables/useCoreCommands.ts b/src/composables/useCoreCommands.ts index b2406a08a7..caa9d2f22c 100644 --- a/src/composables/useCoreCommands.ts +++ b/src/composables/useCoreCommands.ts @@ -35,6 +35,7 @@ import { } from '@/renderer/core/canvas/canvasStore' import { api } from '@/scripts/api' import { app } from '@/scripts/app' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { useDialogService } from '@/services/dialogService' import { useLitegraphService } from '@/services/litegraphService' import type { ComfyCommand } from '@/stores/commandStore' @@ -73,6 +74,7 @@ export function useCoreCommands(): ComfyCommand[] { const { isActiveSubscription, showSubscriptionDialog } = useBillingContext() const workflowService = useWorkflowService() const workflowStore = useWorkflowStore() + const settingsDialog = useSettingsDialog() const dialogService = useDialogService() const colorPaletteStore = useColorPaletteStore() const firebaseAuthActions = useFirebaseAuthActions() @@ -582,7 +584,7 @@ export function useCoreCommands(): ComfyCommand[] { versionAdded: '1.3.7', category: 'view-controls' as const, function: () => { - void dialogService.showSettingsDialog() + settingsDialog.show() } }, { @@ -831,7 +833,7 @@ export function useCoreCommands(): ComfyCommand[] { menubarLabel: 'About ComfyUI', versionAdded: '1.6.4', function: () => { - void dialogService.showSettingsDialog('about') + settingsDialog.showAbout() } }, { diff --git a/src/platform/assets/components/UploadModelUrlInput.vue b/src/platform/assets/components/UploadModelUrlInput.vue index 7ce3b1c1d8..0aa679c280 100644 --- a/src/platform/assets/components/UploadModelUrlInput.vue +++ b/src/platform/assets/components/UploadModelUrlInput.vue @@ -86,15 +86,15 @@ import { computed } from 'vue' import Button from '@/components/ui/button/Button.vue' import { useFeatureFlags } from '@/composables/useFeatureFlags' -import { useDialogService } from '@/services/dialogService' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' const { flags } = useFeatureFlags() -const dialogService = useDialogService() +const settingsDialog = useSettingsDialog() const showSecretsHint = computed(() => flags.userSecretsEnabled) function openSecretsSettings() { - dialogService.showSettingsDialog('secrets') + settingsDialog.show('secrets') } const props = defineProps<{ diff --git a/src/platform/cloud/subscription/components/SubscriptionPanel.vue b/src/platform/cloud/subscription/components/SubscriptionPanel.vue index 2c300fffc4..32d8c0a4b6 100644 --- a/src/platform/cloud/subscription/components/SubscriptionPanel.vue +++ b/src/platform/cloud/subscription/components/SubscriptionPanel.vue @@ -1,5 +1,5 @@ diff --git a/src/platform/settings/components/SettingDialogContent.vue b/src/platform/settings/components/SettingDialogContent.vue deleted file mode 100644 index db026e5b5c..0000000000 --- a/src/platform/settings/components/SettingDialogContent.vue +++ /dev/null @@ -1,257 +0,0 @@ - - - - - - - diff --git a/src/platform/settings/composables/useSettingUI.ts b/src/platform/settings/composables/useSettingUI.ts index 79228d0d47..f9a0af8253 100644 --- a/src/platform/settings/composables/useSettingUI.ts +++ b/src/platform/settings/composables/useSettingUI.ts @@ -9,29 +9,35 @@ import { useVueFeatureFlags } from '@/composables/useVueFeatureFlags' import { isCloud, isDesktop } from '@/platform/distribution/types' import type { SettingTreeNode } from '@/platform/settings/settingStore' import { useSettingStore } from '@/platform/settings/settingStore' -import type { SettingParams } from '@/platform/settings/types' - +import type { SettingPanelType, SettingParams } from '@/platform/settings/types' +import type { NavGroupData } from '@/types/navTypes' import { normalizeI18nKey } from '@/utils/formatUtil' import { buildTree } from '@/utils/treeUtil' +const CATEGORY_ICONS: Record = { + Comfy: 'icon-[lucide--settings]', + LiteGraph: 'icon-[lucide--workflow]', + Appearance: 'icon-[lucide--palette]', + '3D': 'icon-[lucide--box]', + 'Mask Editor': 'icon-[lucide--pen-tool]', + Other: 'icon-[lucide--ellipsis]', + about: 'icon-[lucide--info]', + credits: 'icon-[lucide--coins]', + user: 'icon-[lucide--user]', + workspace: 'icon-[lucide--building-2]', + keybinding: 'icon-[lucide--keyboard]', + extension: 'icon-[lucide--puzzle]', + 'server-config': 'icon-[lucide--server]', + PlanCredits: 'icon-[lucide--credit-card]' +} + interface SettingPanelItem { node: SettingTreeNode component: Component props?: Record } -export function useSettingUI( - defaultPanel?: - | 'about' - | 'keybinding' - | 'extension' - | 'server-config' - | 'user' - | 'credits' - | 'subscription' - | 'workspace' - | 'secrets' -) { +export function useSettingUI(defaultPanel?: SettingPanelType) { const { t } = useI18n() const { isLoggedIn } = useCurrentUser() const settingStore = useSettingStore() @@ -343,6 +349,36 @@ export function useSettingUI( : legacyMenuTreeNodes.value ) + const navGroups = computed(() => + groupedMenuTreeNodes.value.map((group) => ({ + title: + (group as SettingTreeNode & { translatedLabel?: string }) + .translatedLabel ?? group.label, + items: (group.children ?? []).map((child) => ({ + id: child.key, + label: + (child as SettingTreeNode & { translatedLabel?: string }) + .translatedLabel ?? child.label, + icon: + CATEGORY_ICONS[child.key] ?? + CATEGORY_ICONS[child.label] ?? + 'icon-[lucide--plug]' + })) + })) + ) + + function findCategoryByKey(key: string): SettingTreeNode | null { + for (const group of groupedMenuTreeNodes.value) { + const found = group.children?.find((node) => node.key === key) + if (found) return found + } + return null + } + + function findPanelByKey(key: string): SettingPanelItem | null { + return panels.value.find((p) => p.node.key === key) ?? null + } + onMounted(() => { activeCategory.value = defaultCategory.value }) @@ -352,6 +388,10 @@ export function useSettingUI( activeCategory, defaultCategory, groupedMenuTreeNodes, - settingCategories + settingCategories, + navGroups, + teamWorkspacesEnabled, + findCategoryByKey, + findPanelByKey } } diff --git a/src/platform/settings/composables/useSettingsDialog.ts b/src/platform/settings/composables/useSettingsDialog.ts new file mode 100644 index 0000000000..a9f74cc9e2 --- /dev/null +++ b/src/platform/settings/composables/useSettingsDialog.ts @@ -0,0 +1,33 @@ +import { useDialogService } from '@/services/dialogService' +import { useDialogStore } from '@/stores/dialogStore' + +import SettingDialog from '@/platform/settings/components/SettingDialog.vue' +import type { SettingPanelType } from '@/platform/settings/types' + +const DIALOG_KEY = 'global-settings' + +export function useSettingsDialog() { + const dialogService = useDialogService() + const dialogStore = useDialogStore() + + function hide() { + dialogStore.closeDialog({ key: DIALOG_KEY }) + } + + function show(panel?: SettingPanelType) { + dialogService.showLayoutDialog({ + key: DIALOG_KEY, + component: SettingDialog, + props: { + onClose: hide, + ...(panel ? { defaultPanel: panel } : {}) + } + }) + } + + function showAbout() { + show('about') + } + + return { show, hide, showAbout } +} diff --git a/src/platform/settings/types.ts b/src/platform/settings/types.ts index 021fac3750..ce18019565 100644 --- a/src/platform/settings/types.ts +++ b/src/platform/settings/types.ts @@ -64,3 +64,14 @@ export interface ISettingGroup { label: string settings: SettingParams[] } + +export type SettingPanelType = + | 'about' + | 'keybinding' + | 'extension' + | 'server-config' + | 'user' + | 'credits' + | 'subscription' + | 'workspace' + | 'secrets' diff --git a/src/platform/workspace/composables/useWorkspaceUI.ts b/src/platform/workspace/composables/useWorkspaceUI.ts index cfe02877ae..393139b8c4 100644 --- a/src/platform/workspace/composables/useWorkspaceUI.ts +++ b/src/platform/workspace/composables/useWorkspaceUI.ts @@ -1,4 +1,4 @@ -import { computed, ref } from 'vue' +import { computed } from 'vue' import { createSharedComposable } from '@vueuse/core' import type { WorkspaceRole, WorkspaceType } from '../api/workspaceApi' @@ -133,13 +133,6 @@ function getUIConfig( function useWorkspaceUIInternal() { const store = useTeamWorkspaceStore() - // Tab management (shared UI state) - const activeTab = ref('plan') - - function setActiveTab(tab: string | number) { - activeTab.value = String(tab) - } - const workspaceType = computed( () => store.activeWorkspace?.type ?? 'personal' ) @@ -157,10 +150,6 @@ function useWorkspaceUIInternal() { ) return { - // Tab management - activeTab: computed(() => activeTab.value), - setActiveTab, - // Permissions and config permissions, uiConfig, diff --git a/src/scripts/ui.ts b/src/scripts/ui.ts index 11a25d5658..cc7c087720 100644 --- a/src/scripts/ui.ts +++ b/src/scripts/ui.ts @@ -1,7 +1,7 @@ import { useSettingStore } from '@/platform/settings/settingStore' import { WORKFLOW_ACCEPT_STRING } from '@/platform/workflow/core/types/formats' import { type StatusWsMessageStatus } from '@/schemas/apiSchema' -import { useDialogService } from '@/services/dialogService' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { isCloud } from '@/platform/distribution/types' import { extractWorkflow } from '@/platform/remote/comfyui/jobs/fetchJobs' import type { JobListItem } from '@/platform/remote/comfyui/jobs/jobTypes' @@ -464,7 +464,7 @@ export class ComfyUI { $el('button.comfy-settings-btn', { textContent: '⚙️', onclick: () => { - useDialogService().showSettingsDialog() + useSettingsDialog().show() } }), $el('button.comfy-close-menu-btn', { diff --git a/src/services/dialogService.ts b/src/services/dialogService.ts index 9f24e0ea27..f838f2d4a1 100644 --- a/src/services/dialogService.ts +++ b/src/services/dialogService.ts @@ -40,10 +40,6 @@ const lazyUpdatePasswordContent = () => import('@/components/dialog/content/UpdatePasswordContent.vue') const lazyComfyOrgHeader = () => import('@/components/dialog/header/ComfyOrgHeader.vue') -const lazySettingDialogHeader = () => - import('@/components/dialog/header/SettingDialogHeader.vue') -const lazySettingDialogContent = () => - import('@/platform/settings/components/SettingDialogContent.vue') const lazyImportFailedNodeContent = () => import('@/workbench/extensions/manager/components/manager/ImportFailedNodeContent.vue') const lazyImportFailedNodeHeader = () => @@ -128,55 +124,6 @@ export const useDialogService = () => { }) } - async function showSettingsDialog( - panel?: - | 'about' - | 'keybinding' - | 'extension' - | 'server-config' - | 'user' - | 'credits' - | 'subscription' - | 'workspace' - | 'secrets' - ) { - const [ - { default: SettingDialogHeader }, - { default: SettingDialogContent } - ] = await Promise.all([ - lazySettingDialogHeader(), - lazySettingDialogContent() - ]) - - const props = panel ? { props: { defaultPanel: panel } } : undefined - - dialogStore.showDialog({ - key: 'global-settings', - headerComponent: SettingDialogHeader, - component: SettingDialogContent, - ...props - }) - } - - async function showAboutDialog() { - const [ - { default: SettingDialogHeader }, - { default: SettingDialogContent } - ] = await Promise.all([ - lazySettingDialogHeader(), - lazySettingDialogContent() - ]) - - dialogStore.showDialog({ - key: 'global-settings', - headerComponent: SettingDialogHeader, - component: SettingDialogContent, - props: { - defaultPanel: 'about' - } - }) - } - function showExecutionErrorDialog(executionError: ExecutionErrorDialogInput) { const props: ComponentAttrs = { error: { @@ -751,8 +698,6 @@ export const useDialogService = () => { return { showLoadWorkflowWarning, showMissingModelsWarning, - showSettingsDialog, - showAboutDialog, showExecutionErrorDialog, showApiNodesSignInDialog, showSignInDialog, diff --git a/src/stores/billingOperationStore.test.ts b/src/stores/billingOperationStore.test.ts index 5c508fb561..8e79e59b76 100644 --- a/src/stores/billingOperationStore.test.ts +++ b/src/stores/billingOperationStore.test.ts @@ -33,9 +33,11 @@ vi.mock('@/i18n', () => ({ t: (key: string) => key })) -vi.mock('@/services/dialogService', () => ({ - useDialogService: () => ({ - showSettingsDialog: vi.fn() +vi.mock('@/platform/settings/composables/useSettingsDialog', () => ({ + useSettingsDialog: () => ({ + show: vi.fn(), + hide: vi.fn(), + showAbout: vi.fn() }) })) diff --git a/src/stores/billingOperationStore.ts b/src/stores/billingOperationStore.ts index ba1348c775..fdb5a0a068 100644 --- a/src/stores/billingOperationStore.ts +++ b/src/stores/billingOperationStore.ts @@ -6,7 +6,7 @@ import { useBillingContext } from '@/composables/billing/useBillingContext' import { t } from '@/i18n' import { useToastStore } from '@/platform/updates/common/toastStore' import { workspaceApi } from '@/platform/workspace/api/workspaceApi' -import { useDialogService } from '@/services/dialogService' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { useDialogStore } from '@/stores/dialogStore' const INITIAL_INTERVAL_MS = 1000 @@ -143,7 +143,7 @@ export const useBillingOperationStore = defineStore('billingOperation', () => { const dialogStore = useDialogStore() dialogStore.closeDialog({ key: 'subscription-required' }) dialogStore.closeDialog({ key: 'top-up-credits' }) - void useDialogService().showSettingsDialog('workspace') + useSettingsDialog().show('workspace') const toastStore = useToastStore() const messageKey = diff --git a/src/stores/firebaseAuthStore.test.ts b/src/stores/firebaseAuthStore.test.ts index 34beee00d9..8dd0ec7735 100644 --- a/src/stores/firebaseAuthStore.test.ts +++ b/src/stores/firebaseAuthStore.test.ts @@ -119,7 +119,6 @@ describe('useFirebaseAuthStore', () => { // Setup dialog service mock vi.mocked(useDialogService, { partial: true }).mockReturnValue({ - showSettingsDialog: vi.fn(), showErrorDialog: vi.fn() }) diff --git a/src/workbench/extensions/manager/composables/useManagerState.test.ts b/src/workbench/extensions/manager/composables/useManagerState.test.ts index 710ea6d321..d14fbb2fcf 100644 --- a/src/workbench/extensions/manager/composables/useManagerState.test.ts +++ b/src/workbench/extensions/manager/composables/useManagerState.test.ts @@ -28,18 +28,13 @@ vi.mock('@/composables/useFeatureFlags', () => { } }) -vi.mock('@/services/dialogService', () => { - const showManagerPopup = vi.fn() - const showLegacyManagerPopup = vi.fn() - const showSettingsDialog = vi.fn() - return { - useDialogService: vi.fn(() => ({ - showManagerPopup, - showLegacyManagerPopup, - showSettingsDialog - })) - } -}) +vi.mock('@/platform/settings/composables/useSettingsDialog', () => ({ + useSettingsDialog: vi.fn(() => ({ + show: vi.fn(), + hide: vi.fn(), + showAbout: vi.fn() + })) +})) vi.mock('@/stores/commandStore', () => ({ useCommandStore: vi.fn(() => ({ diff --git a/src/workbench/extensions/manager/composables/useManagerState.ts b/src/workbench/extensions/manager/composables/useManagerState.ts index 3a161b76fa..f435a65308 100644 --- a/src/workbench/extensions/manager/composables/useManagerState.ts +++ b/src/workbench/extensions/manager/composables/useManagerState.ts @@ -4,7 +4,7 @@ import { computed, readonly } from 'vue' import { t } from '@/i18n' import { useToastStore } from '@/platform/updates/common/toastStore' import { api } from '@/scripts/api' -import { useDialogService } from '@/services/dialogService' +import { useSettingsDialog } from '@/platform/settings/composables/useSettingsDialog' import { useCommandStore } from '@/stores/commandStore' import { useSystemStatsStore } from '@/stores/systemStatsStore' import { useManagerDialog } from '@/workbench/extensions/manager/composables/useManagerDialog' @@ -148,12 +148,12 @@ export function useManagerState() { isLegacyOnly?: boolean }): Promise => { const state = managerUIState.value - const dialogService = useDialogService() + const settingsDialog = useSettingsDialog() const commandStore = useCommandStore() switch (state) { case ManagerUIState.DISABLED: - void dialogService.showSettingsDialog('extension') + settingsDialog.show('extension') break case ManagerUIState.LEGACY_UI: { @@ -173,7 +173,7 @@ export function useManagerState() { } // Fallback to extensions panel if not showing toast if (options?.showToastOnLegacyError === false) { - void dialogService.showSettingsDialog('extension') + settingsDialog.show('extension') } } break