diff --git a/browser_tests/ComfyPage.ts b/browser_tests/ComfyPage.ts
index 673319003..593aef8e5 100644
--- a/browser_tests/ComfyPage.ts
+++ b/browser_tests/ComfyPage.ts
@@ -38,9 +38,11 @@ class ComfyNodeSearchBox {
}
class ComfyMenu {
+ public readonly sideToolBar: Locator
public readonly themeToggleButton: Locator
constructor(public readonly page: Page) {
+ this.sideToolBar = page.locator('.side-tool-bar-container')
this.themeToggleButton = page.locator('.comfy-vue-theme-toggle')
}
diff --git a/browser_tests/menu.spec.ts b/browser_tests/menu.spec.ts
index 1c74a8e98..369cc27c4 100644
--- a/browser_tests/menu.spec.ts
+++ b/browser_tests/menu.spec.ts
@@ -42,4 +42,29 @@ test.describe('Menu', () => {
expect(await comfyPage.menu.getThemeId()).toBe('dark')
})
+
+ test('Can register sidebar tab', async ({ comfyPage }) => {
+ const initialChildrenCount = await comfyPage.menu.sideToolBar.evaluate(
+ (el) => el.children.length
+ )
+
+ await comfyPage.page.evaluate(async () => {
+ window['app'].extensionManager.registerSidebarTab({
+ id: 'search',
+ icon: 'pi pi-search',
+ title: 'search',
+ tooltip: 'search',
+ type: 'custom',
+ render: (el) => {
+ el.innerHTML = '
Custom search tab
'
+ }
+ })
+ })
+ await comfyPage.nextFrame()
+
+ const newChildrenCount = await comfyPage.menu.sideToolBar.evaluate(
+ (el) => el.children.length
+ )
+ expect(newChildrenCount).toBe(initialChildrenCount + 1)
+ })
})
diff --git a/src/App.vue b/src/App.vue
index 3ede732a2..691dbdfc1 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -21,8 +21,8 @@ import QueueSideBarTab from '@/components/sidebar/tabs/QueueSideBarTab.vue'
import ProgressSpinner from 'primevue/progressspinner'
import { app } from './scripts/app'
import { useSettingStore } from './stores/settingStore'
-import { ExtensionManagerImpl } from './scripts/extensionManager'
import { useI18n } from 'vue-i18n'
+import { useWorkspaceStore } from './stores/workspaceStateStore'
const isLoading = ref(true)
const nodeSearchEnabled = computed(
@@ -52,8 +52,7 @@ const { t } = useI18n()
const init = () => {
useSettingStore().addSettings(app.ui.settings)
app.vueAppReady = true
- // lazy init as extension manager needs to access pinia store.
- app.extensionManager = new ExtensionManagerImpl()
+ app.extensionManager = useWorkspaceStore()
app.extensionManager.registerSidebarTab({
id: 'queue',
icon: 'pi pi-history',
diff --git a/src/components/sidebar/SideToolBar.vue b/src/components/sidebar/SideToolBar.vue
index a338d8491..caaebda82 100644
--- a/src/components/sidebar/SideToolBar.vue
+++ b/src/components/sidebar/SideToolBar.vue
@@ -39,25 +39,24 @@ import SideBarIcon from './SideBarIcon.vue'
import SideBarThemeToggleIcon from './SideBarThemeToggleIcon.vue'
import SideBarSettingsToggleIcon from './SideBarSettingsToggleIcon.vue'
import { computed, onBeforeUnmount } from 'vue'
-import { app } from '@/scripts/app'
import { useWorkspaceStore } from '@/stores/workspaceStateStore'
import {
CustomSidebarTabExtension,
SidebarTabExtension
} from '@/types/extensionTypes'
-const workspaceStateStore = useWorkspaceStore()
-const tabs = computed(() => app.extensionManager.getSidebarTabs())
+const workspaceStore = useWorkspaceStore()
+const tabs = computed(() => workspaceStore.getSidebarTabs())
const selectedTab = computed(() => {
- const tabId = workspaceStateStore.activeSidebarTab
+ const tabId = workspaceStore.activeSidebarTab
return tabs.value.find((tab) => tab.id === tabId) || null
})
const mountCustomTab = (tab: CustomSidebarTabExtension, el: HTMLElement) => {
tab.render(el)
}
const onTabClick = (item: SidebarTabExtension) => {
- workspaceStateStore.updateActiveSidebarTab(
- workspaceStateStore.activeSidebarTab === item.id ? null : item.id
+ workspaceStore.updateActiveSidebarTab(
+ workspaceStore.activeSidebarTab === item.id ? null : item.id
)
}
onBeforeUnmount(() => {
diff --git a/src/scripts/extensionManager.ts b/src/scripts/extensionManager.ts
deleted file mode 100644
index d64e3ca2b..000000000
--- a/src/scripts/extensionManager.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { useWorkspaceStore } from '@/stores/workspaceStateStore'
-import { ExtensionManager, SidebarTabExtension } from '@/types/extensionTypes'
-
-export class ExtensionManagerImpl implements ExtensionManager {
- private sidebarTabs: SidebarTabExtension[] = []
- private workspaceStore = useWorkspaceStore()
-
- registerSidebarTab(tab: SidebarTabExtension) {
- this.sidebarTabs.push(tab)
- this.updateSidebarOrder()
- }
-
- unregisterSidebarTab(id: string) {
- const index = this.sidebarTabs.findIndex((tab) => tab.id === id)
- if (index !== -1) {
- const tab = this.sidebarTabs[index]
- if (tab.type === 'custom' && tab.destroy) {
- tab.destroy()
- }
- this.sidebarTabs.splice(index, 1)
- this.updateSidebarOrder()
- }
- }
-
- getSidebarTabs() {
- return this.sidebarTabs.sort((a, b) => {
- const orderA = this.workspaceStore.sidebarTabsOrder.indexOf(a.id)
- const orderB = this.workspaceStore.sidebarTabsOrder.indexOf(b.id)
- return orderA - orderB
- })
- }
-
- private updateSidebarOrder() {
- const currentOrder = this.workspaceStore.sidebarTabsOrder
- const newTabs = this.sidebarTabs.filter(
- (tab) => !currentOrder.includes(tab.id)
- )
- this.workspaceStore.updateSidebarOrder([
- ...currentOrder,
- ...newTabs.map((tab) => tab.id)
- ])
- }
-}
diff --git a/src/stores/workspaceStateStore.ts b/src/stores/workspaceStateStore.ts
index 8ff2a6af5..b8f75928b 100644
--- a/src/stores/workspaceStateStore.ts
+++ b/src/stores/workspaceStateStore.ts
@@ -1,32 +1,37 @@
+import { SidebarTabExtension } from '@/types/extensionTypes'
import { defineStore } from 'pinia'
interface WorkspaceState {
activeSidebarTab: string | null
- sidebarTabsOrder: string[] // Array of tab IDs in order
+ sidebarTabs: SidebarTabExtension[]
}
export const useWorkspaceStore = defineStore('workspace', {
state: (): WorkspaceState => ({
activeSidebarTab: null,
- sidebarTabsOrder: []
+ sidebarTabs: []
}),
actions: {
updateActiveSidebarTab(tabId: string) {
this.activeSidebarTab = tabId
},
- updateSidebarOrder(newOrder: string[]) {
- this.sidebarTabsOrder = newOrder
+ registerSidebarTab(tab: SidebarTabExtension) {
+ this.sidebarTabs = [...this.sidebarTabs, tab]
},
- serialize() {
- return JSON.stringify({
- activeSidebarTab: this.activeSidebarTab,
- sidebarTabsOrder: this.sidebarTabsOrder
- })
+ unregisterSidebarTab(id: string) {
+ const index = this.sidebarTabs.findIndex((tab) => tab.id === id)
+ if (index !== -1) {
+ const tab = this.sidebarTabs[index]
+ if (tab.type === 'custom' && tab.destroy) {
+ tab.destroy()
+ }
+ const newSidebarTabs = [...this.sidebarTabs]
+ newSidebarTabs.splice(index, 1)
+ this.sidebarTabs = newSidebarTabs
+ }
},
- deserialize(state: string) {
- const parsedState = JSON.parse(state)
- this.sidebarTabsOrder = parsedState.sidebarTabsOrder
- this.activeSidebarTab = parsedState.activeSidebarTab
+ getSidebarTabs() {
+ return [...this.sidebarTabs]
}
}
})