mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-17 02:47:35 +00:00
Compare commits
4 Commits
fix/load-a
...
feature/sm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d915ba7e7e | ||
|
|
e004919712 | ||
|
|
d81d5f9ac7 | ||
|
|
f5eb533615 |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
@@ -64,12 +64,12 @@ import { storeToRefs } from 'pinia'
|
||||
import { computed, onMounted, toRefs } from 'vue'
|
||||
|
||||
import HelpCenterMenuContent from '@/components/helpcenter/HelpCenterMenuContent.vue'
|
||||
import { useNodeConflictDialog } from '@/composables/useNodeConflictDialog'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useTelemetry } from '@/platform/telemetry'
|
||||
import { useReleaseStore } from '@/platform/updates/common/releaseStore'
|
||||
import ReleaseNotificationToast from '@/platform/updates/components/ReleaseNotificationToast.vue'
|
||||
import WhatsNewPopup from '@/platform/updates/components/WhatsNewPopup.vue'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useHelpCenterStore } from '@/stores/helpCenterStore'
|
||||
import { useConflictAcknowledgment } from '@/workbench/extensions/manager/composables/useConflictAcknowledgment'
|
||||
import { useConflictDetection } from '@/workbench/extensions/manager/composables/useConflictDetection'
|
||||
@@ -84,7 +84,7 @@ const { shouldShowRedDot: showReleaseRedDot } = storeToRefs(releaseStore)
|
||||
|
||||
const conflictDetection = useConflictDetection()
|
||||
|
||||
const { showNodeConflictDialog } = useDialogService()
|
||||
const { show: showNodeConflictDialog } = useNodeConflictDialog()
|
||||
|
||||
// Use conflict acknowledgment state from composable - call only once
|
||||
const { shouldShowRedDot: shouldShowConflictRedDot, markConflictsAsSeen } =
|
||||
|
||||
29
src/composables/useMissingNodesDialog.ts
Normal file
29
src/composables/useMissingNodesDialog.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import MissingNodesContent from '@/components/dialog/content/MissingNodesContent.vue'
|
||||
import MissingNodesFooter from '@/components/dialog/content/MissingNodesFooter.vue'
|
||||
import MissingNodesHeader from '@/components/dialog/content/MissingNodesHeader.vue'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useDialogStore } from '@/stores/dialogStore'
|
||||
import type { ComponentProps } from 'vue-component-type-helpers'
|
||||
|
||||
const DIALOG_KEY = 'global-missing-nodes'
|
||||
|
||||
export const useMissingNodesDialog = () => {
|
||||
const dialogService = useDialogService()
|
||||
const dialogStore = useDialogStore()
|
||||
|
||||
function hide() {
|
||||
dialogStore.closeDialog({ key: DIALOG_KEY })
|
||||
}
|
||||
|
||||
function show(props: ComponentProps<typeof MissingNodesContent>) {
|
||||
dialogService.showSmallDialog({
|
||||
key: DIALOG_KEY,
|
||||
headerComponent: MissingNodesHeader,
|
||||
footerComponent: MissingNodesFooter,
|
||||
component: MissingNodesContent,
|
||||
props
|
||||
})
|
||||
}
|
||||
|
||||
return { show, hide }
|
||||
}
|
||||
48
src/composables/useNodeConflictDialog.ts
Normal file
48
src/composables/useNodeConflictDialog.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import NodeConflictDialogContent from '@/workbench/extensions/manager/components/manager/NodeConflictDialogContent.vue'
|
||||
import NodeConflictFooter from '@/workbench/extensions/manager/components/manager/NodeConflictFooter.vue'
|
||||
import NodeConflictHeader from '@/workbench/extensions/manager/components/manager/NodeConflictHeader.vue'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useDialogStore } from '@/stores/dialogStore'
|
||||
import type { DialogComponentProps } from '@/stores/dialogStore'
|
||||
import type { ConflictDetectionResult } from '@/workbench/extensions/manager/types/conflictDetectionTypes'
|
||||
|
||||
const DIALOG_KEY = 'global-node-conflict'
|
||||
|
||||
export const useNodeConflictDialog = () => {
|
||||
const dialogService = useDialogService()
|
||||
const dialogStore = useDialogStore()
|
||||
|
||||
function hide() {
|
||||
dialogStore.closeDialog({ key: DIALOG_KEY })
|
||||
}
|
||||
|
||||
function show(
|
||||
options: {
|
||||
showAfterWhatsNew?: boolean
|
||||
conflictedPackages?: ConflictDetectionResult[]
|
||||
dialogComponentProps?: DialogComponentProps
|
||||
buttonText?: string
|
||||
onButtonClick?: () => void
|
||||
} = {}
|
||||
) {
|
||||
const { buttonText, onButtonClick, showAfterWhatsNew, conflictedPackages } =
|
||||
options
|
||||
|
||||
return dialogService.showSmallDialog({
|
||||
key: DIALOG_KEY,
|
||||
headerComponent: NodeConflictHeader,
|
||||
footerComponent: NodeConflictFooter,
|
||||
component: NodeConflictDialogContent,
|
||||
props: {
|
||||
showAfterWhatsNew,
|
||||
conflictedPackages
|
||||
},
|
||||
footerProps: {
|
||||
buttonText,
|
||||
onButtonClick
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return { show, hide }
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
ComponentWidgetImpl,
|
||||
DOMWidgetImpl
|
||||
} from '@/scripts/domWidget'
|
||||
import { useMissingNodesDialog } from '@/composables/useMissingNodesDialog'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
|
||||
import { useExtensionService } from '@/services/extensionService'
|
||||
@@ -1029,7 +1030,7 @@ export class ComfyApp {
|
||||
|
||||
private showMissingNodesError(missingNodeTypes: MissingNodeType[]) {
|
||||
if (useSettingStore().get('Comfy.Workflow.ShowMissingNodesWarning')) {
|
||||
useDialogService().showLoadWorkflowWarning({ missingNodeTypes })
|
||||
useMissingNodesDialog().show({ missingNodeTypes })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,6 @@ import { merge } from 'es-toolkit/compat'
|
||||
import type { Component } from 'vue'
|
||||
|
||||
import ApiNodesSignInContent from '@/components/dialog/content/ApiNodesSignInContent.vue'
|
||||
import MissingNodesContent from '@/components/dialog/content/MissingNodesContent.vue'
|
||||
import MissingNodesFooter from '@/components/dialog/content/MissingNodesFooter.vue'
|
||||
import MissingNodesHeader from '@/components/dialog/content/MissingNodesHeader.vue'
|
||||
import ConfirmationDialogContent from '@/components/dialog/content/ConfirmationDialogContent.vue'
|
||||
import ErrorDialogContent from '@/components/dialog/content/ErrorDialogContent.vue'
|
||||
import MissingModelsWarning from '@/components/dialog/content/MissingModelsWarning.vue'
|
||||
@@ -30,11 +27,7 @@ import ManagerProgressFooter from '@/workbench/extensions/manager/components/Man
|
||||
import ManagerProgressHeader from '@/workbench/extensions/manager/components/ManagerProgressHeader.vue'
|
||||
import ManagerDialogContent from '@/workbench/extensions/manager/components/manager/ManagerDialogContent.vue'
|
||||
import ManagerHeader from '@/workbench/extensions/manager/components/manager/ManagerHeader.vue'
|
||||
import NodeConflictDialogContent from '@/workbench/extensions/manager/components/manager/NodeConflictDialogContent.vue'
|
||||
import NodeConflictFooter from '@/workbench/extensions/manager/components/manager/NodeConflictFooter.vue'
|
||||
import NodeConflictHeader from '@/workbench/extensions/manager/components/manager/NodeConflictHeader.vue'
|
||||
import type { ConflictDetectionResult } from '@/workbench/extensions/manager/types/conflictDetectionTypes'
|
||||
import type { ComponentAttrs } from 'vue-component-type-helpers'
|
||||
import type { ComponentAttrs, ComponentProps } from 'vue-component-type-helpers'
|
||||
|
||||
export type ConfirmationDialogType =
|
||||
| 'default'
|
||||
@@ -47,32 +40,6 @@ export type ConfirmationDialogType =
|
||||
export const useDialogService = () => {
|
||||
const dialogStore = useDialogStore()
|
||||
|
||||
function showLoadWorkflowWarning(
|
||||
props: ComponentAttrs<typeof MissingNodesContent>
|
||||
) {
|
||||
dialogStore.showDialog({
|
||||
key: 'global-missing-nodes',
|
||||
headerComponent: MissingNodesHeader,
|
||||
footerComponent: MissingNodesFooter,
|
||||
component: MissingNodesContent,
|
||||
dialogComponentProps: {
|
||||
closable: true,
|
||||
pt: {
|
||||
root: { class: 'bg-base-background border-border-default' },
|
||||
header: { class: '!p-0 !m-0' },
|
||||
content: { class: '!p-0 overflow-y-hidden' },
|
||||
footer: { class: '!p-0' },
|
||||
pcCloseButton: {
|
||||
root: {
|
||||
class: '!w-7 !h-7 !border-none !outline-none !p-2 !m-1.5'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
props
|
||||
})
|
||||
}
|
||||
|
||||
function showMissingModelsWarning(
|
||||
props: ComponentAttrs<typeof MissingModelsWarning>
|
||||
) {
|
||||
@@ -450,6 +417,44 @@ export const useDialogService = () => {
|
||||
}
|
||||
}
|
||||
|
||||
function showSmallDialog<T extends Component>(options: {
|
||||
key: string
|
||||
component: T
|
||||
headerComponent?: Component
|
||||
footerComponent?: Component
|
||||
props?: ComponentProps<T>
|
||||
footerProps?: Record<string, unknown>
|
||||
dialogComponentProps?: DialogComponentProps
|
||||
}) {
|
||||
const smallDialogDefaultProps: DialogComponentProps = {
|
||||
closable: true,
|
||||
pt: {
|
||||
root: { class: 'bg-base-background border-border-default' },
|
||||
header: { class: '!p-0 !m-0' },
|
||||
content: { class: '!p-0 overflow-y-hidden' },
|
||||
footer: { class: '!p-0' },
|
||||
pcCloseButton: {
|
||||
root: {
|
||||
class: '!w-7 !h-7 !border-none !outline-none !p-2 !m-1.5'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dialogStore.showDialog({
|
||||
key: options.key,
|
||||
component: options.component,
|
||||
headerComponent: options.headerComponent,
|
||||
footerComponent: options.footerComponent,
|
||||
props: options.props,
|
||||
footerProps: options.footerProps,
|
||||
dialogComponentProps: merge(
|
||||
smallDialogDefaultProps,
|
||||
options.dialogComponentProps || {}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function showLayoutDialog(options: {
|
||||
key: string
|
||||
component: Component
|
||||
@@ -482,54 +487,6 @@ export const useDialogService = () => {
|
||||
})
|
||||
}
|
||||
|
||||
function showNodeConflictDialog(
|
||||
options: {
|
||||
showAfterWhatsNew?: boolean
|
||||
conflictedPackages?: ConflictDetectionResult[]
|
||||
dialogComponentProps?: DialogComponentProps
|
||||
buttonText?: string
|
||||
onButtonClick?: () => void
|
||||
} = {}
|
||||
) {
|
||||
const {
|
||||
dialogComponentProps,
|
||||
buttonText,
|
||||
onButtonClick,
|
||||
showAfterWhatsNew,
|
||||
conflictedPackages
|
||||
} = options
|
||||
|
||||
return dialogStore.showDialog({
|
||||
key: 'global-node-conflict',
|
||||
headerComponent: NodeConflictHeader,
|
||||
footerComponent: NodeConflictFooter,
|
||||
component: NodeConflictDialogContent,
|
||||
dialogComponentProps: {
|
||||
closable: true,
|
||||
pt: {
|
||||
header: { class: '!p-0 !m-0' },
|
||||
content: { class: '!p-0 overflow-y-hidden' },
|
||||
footer: { class: '!p-0' },
|
||||
pcCloseButton: {
|
||||
root: {
|
||||
class:
|
||||
'!w-7 !h-7 !border-none !outline-none !p-2 !m-1.5 bg-dialog-surface text-white'
|
||||
}
|
||||
}
|
||||
},
|
||||
...dialogComponentProps
|
||||
},
|
||||
props: {
|
||||
showAfterWhatsNew,
|
||||
conflictedPackages
|
||||
},
|
||||
footerProps: {
|
||||
buttonText,
|
||||
onButtonClick
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function showSubscriptionRequiredDialog() {
|
||||
if (!isCloud || !window.__CONFIG__?.subscription_required) {
|
||||
return
|
||||
@@ -542,7 +499,6 @@ export const useDialogService = () => {
|
||||
}
|
||||
|
||||
return {
|
||||
showLoadWorkflowWarning,
|
||||
showMissingModelsWarning,
|
||||
showSettingsDialog,
|
||||
showAboutDialog,
|
||||
@@ -560,7 +516,7 @@ export const useDialogService = () => {
|
||||
confirm,
|
||||
toggleManagerDialog,
|
||||
toggleManagerProgressDialog,
|
||||
showLayoutDialog,
|
||||
showNodeConflictDialog
|
||||
showSmallDialog,
|
||||
showLayoutDialog
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,12 +215,19 @@ export const useDialogStore = defineStore('dialog', () => {
|
||||
F extends Component = Component
|
||||
>(options: ShowDialogOptions<H, B, F>) {
|
||||
const dialogKey = options.key || genDialogKey()
|
||||
|
||||
let dialog = dialogStack.value.find((d) => d.key === dialogKey)
|
||||
|
||||
const existingIndex = dialogStack.value.findIndex(
|
||||
(d) => d.key === dialogKey
|
||||
)
|
||||
let dialog =
|
||||
existingIndex !== -1 ? dialogStack.value[existingIndex] : undefined
|
||||
if (dialog) {
|
||||
dialog.visible = true
|
||||
riseDialog(dialog)
|
||||
if (!dialog.visible) {
|
||||
dialogStack.value.splice(existingIndex, 1)
|
||||
dialog = createDialog({ ...options, key: dialogKey })
|
||||
} else {
|
||||
dialog.visible = true
|
||||
riseDialog(dialog)
|
||||
}
|
||||
} else {
|
||||
dialog = createDialog({ ...options, key: dialogKey })
|
||||
}
|
||||
|
||||
@@ -185,18 +185,25 @@ describe('NodeConflictDialogContent', () => {
|
||||
const wrapper = createWrapper()
|
||||
|
||||
// Import Failed Extensions section should show 1 package
|
||||
const importFailedSection = wrapper.findAll(
|
||||
'.w-full.flex.flex-col.bg-base-background'
|
||||
)[0]
|
||||
expect(importFailedSection.text()).toContain('1')
|
||||
expect(importFailedSection.text()).toContain('Import Failed Extensions')
|
||||
const sections = wrapper.findAll('.bg-secondary-background')
|
||||
expect(sections.length).toBeGreaterThan(0)
|
||||
|
||||
const importFailedSection = sections.find((section) =>
|
||||
section.text().includes('Import Failed Extensions')
|
||||
)
|
||||
expect(importFailedSection).toBeDefined()
|
||||
expect(importFailedSection!.text()).toContain('1')
|
||||
expect(importFailedSection!.text()).toContain('Import Failed Extensions')
|
||||
|
||||
// Conflicts section should show 3 conflicts (excluding import_failed)
|
||||
const conflictsSection = wrapper.findAll(
|
||||
'.w-full.flex.flex-col.bg-base-background'
|
||||
)[1]
|
||||
expect(conflictsSection.text()).toContain('3')
|
||||
expect(conflictsSection.text()).toContain('Conflicts')
|
||||
const conflictsSection = sections.find(
|
||||
(section) =>
|
||||
section.text().includes('Conflicts') &&
|
||||
!section.text().includes('Import Failed')
|
||||
)
|
||||
expect(conflictsSection).toBeDefined()
|
||||
expect(conflictsSection!.text()).toContain('3')
|
||||
expect(conflictsSection!.text()).toContain('Conflicts')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -208,10 +215,14 @@ describe('NodeConflictDialogContent', () => {
|
||||
it('should toggle import failed panel', async () => {
|
||||
const wrapper = createWrapper()
|
||||
|
||||
// Find import failed panel header (first one)
|
||||
const importFailedHeader = wrapper.find(
|
||||
// Find import failed panel header - look for the one containing "Import Failed Extensions"
|
||||
const headers = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-toggle"]'
|
||||
)
|
||||
const importFailedHeader = headers.find((header) =>
|
||||
header.text().includes('Import Failed Extensions')
|
||||
)
|
||||
expect(importFailedHeader).toBeDefined()
|
||||
|
||||
// Initially collapsed
|
||||
expect(
|
||||
@@ -219,7 +230,7 @@ describe('NodeConflictDialogContent', () => {
|
||||
).toBe(false)
|
||||
|
||||
// Click to expand import failed panel
|
||||
await importFailedHeader.trigger('click')
|
||||
await importFailedHeader!.trigger('click')
|
||||
|
||||
// Should be expanded now and show package name
|
||||
const expandedContent = wrapper.find(
|
||||
@@ -236,34 +247,46 @@ describe('NodeConflictDialogContent', () => {
|
||||
it('should toggle conflicts panel', async () => {
|
||||
const wrapper = createWrapper()
|
||||
|
||||
// Find conflicts panel header (second one)
|
||||
const conflictsHeader = wrapper.findAll(
|
||||
// Find conflicts panel header - look for the one containing "Conflicts"
|
||||
const headers = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-toggle"]'
|
||||
)[1]
|
||||
)
|
||||
const conflictsHeader = headers.find(
|
||||
(header) =>
|
||||
header.text().includes('Conflicts') &&
|
||||
!header.text().includes('Import Failed')
|
||||
)
|
||||
expect(conflictsHeader).toBeDefined()
|
||||
|
||||
// Click to expand conflicts panel
|
||||
await conflictsHeader.trigger('click')
|
||||
await conflictsHeader!.trigger('click')
|
||||
|
||||
// Should be expanded now
|
||||
const conflictItems = wrapper.findAll('.conflict-list-item')
|
||||
expect(conflictItems.length).toBeGreaterThan(0)
|
||||
// Should be expanded now - look for the expanded content
|
||||
const expandedPanels = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-expanded"]'
|
||||
)
|
||||
expect(expandedPanels.length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('should toggle extensions panel', async () => {
|
||||
const wrapper = createWrapper()
|
||||
|
||||
// Find extensions panel header (third one)
|
||||
const extensionsHeader = wrapper.findAll(
|
||||
// Find extensions panel header - look for the one containing "Extensions at Risk"
|
||||
const headers = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-toggle"]'
|
||||
)[2]
|
||||
)
|
||||
const extensionsHeader = headers.find((header) =>
|
||||
header.text().includes('Extensions at Risk')
|
||||
)
|
||||
expect(extensionsHeader).toBeDefined()
|
||||
|
||||
// Click to expand extensions panel
|
||||
await extensionsHeader.trigger('click')
|
||||
await extensionsHeader!.trigger('click')
|
||||
|
||||
// Should be expanded now and show all package names
|
||||
const expandedContent = wrapper.findAll(
|
||||
const expandedContent = wrapper.find(
|
||||
'[data-testid="conflict-dialog-panel-expanded"]'
|
||||
)[0]
|
||||
)
|
||||
expect(expandedContent.exists()).toBe(true)
|
||||
expect(expandedContent.text()).toContain('Test Package 1')
|
||||
expect(expandedContent.text()).toContain('Test Package 2')
|
||||
@@ -273,18 +296,27 @@ describe('NodeConflictDialogContent', () => {
|
||||
it('should collapse other panels when opening one', async () => {
|
||||
const wrapper = createWrapper()
|
||||
|
||||
const importFailedHeader = wrapper.findAll(
|
||||
const headers = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-toggle"]'
|
||||
)[0]
|
||||
const conflictsHeader = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-toggle"]'
|
||||
)[1]
|
||||
const extensionsHeader = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-toggle"]'
|
||||
)[2]
|
||||
)
|
||||
const importFailedHeader = headers.find((header) =>
|
||||
header.text().includes('Import Failed Extensions')
|
||||
)
|
||||
const conflictsHeader = headers.find(
|
||||
(header) =>
|
||||
header.text().includes('Conflicts') &&
|
||||
!header.text().includes('Import Failed')
|
||||
)
|
||||
const extensionsHeader = headers.find((header) =>
|
||||
header.text().includes('Extensions at Risk')
|
||||
)
|
||||
|
||||
expect(importFailedHeader).toBeDefined()
|
||||
expect(conflictsHeader).toBeDefined()
|
||||
expect(extensionsHeader).toBeDefined()
|
||||
|
||||
// Open import failed panel first
|
||||
await importFailedHeader.trigger('click')
|
||||
await importFailedHeader!.trigger('click')
|
||||
|
||||
// Verify import failed panel is open
|
||||
expect((wrapper.vm as any).importFailedExpanded).toBe(true)
|
||||
@@ -292,7 +324,7 @@ describe('NodeConflictDialogContent', () => {
|
||||
expect((wrapper.vm as any).extensionsExpanded).toBe(false)
|
||||
|
||||
// Open conflicts panel
|
||||
await conflictsHeader.trigger('click')
|
||||
await conflictsHeader!.trigger('click')
|
||||
|
||||
// Verify conflicts panel is open and others are closed
|
||||
expect((wrapper.vm as any).importFailedExpanded).toBe(false)
|
||||
@@ -300,7 +332,7 @@ describe('NodeConflictDialogContent', () => {
|
||||
expect((wrapper.vm as any).extensionsExpanded).toBe(false)
|
||||
|
||||
// Open extensions panel
|
||||
await extensionsHeader.trigger('click')
|
||||
await extensionsHeader!.trigger('click')
|
||||
|
||||
// Verify extensions panel is open and others are closed
|
||||
expect((wrapper.vm as any).importFailedExpanded).toBe(false)
|
||||
@@ -317,28 +349,50 @@ describe('NodeConflictDialogContent', () => {
|
||||
it('should display individual conflict details excluding import_failed', async () => {
|
||||
const wrapper = createWrapper()
|
||||
|
||||
// Expand conflicts panel (second header)
|
||||
const conflictsHeader = wrapper.findAll(
|
||||
// Expand conflicts panel - find the one containing "Conflicts"
|
||||
const headers = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-toggle"]'
|
||||
)[1]
|
||||
await conflictsHeader.trigger('click')
|
||||
)
|
||||
const conflictsHeader = headers.find(
|
||||
(header) =>
|
||||
header.text().includes('Conflicts') &&
|
||||
!header.text().includes('Import Failed')
|
||||
)
|
||||
expect(conflictsHeader).toBeDefined()
|
||||
await conflictsHeader!.trigger('click')
|
||||
|
||||
// Should display conflict messages (excluding import_failed)
|
||||
const conflictItems = wrapper.findAll('.conflict-list-item')
|
||||
expect(conflictItems).toHaveLength(3) // 2 from Package1 + 1 from Package2
|
||||
// Look for the expanded panel content that contains conflict items
|
||||
const expandedPanel = wrapper.find(
|
||||
'[data-testid="conflict-dialog-panel-expanded"]'
|
||||
)
|
||||
expect(expandedPanel.exists()).toBe(true)
|
||||
|
||||
// Check that it contains the expected conflict details
|
||||
const conflictElements = expandedPanel.findAll('.flex.h-6')
|
||||
expect(conflictElements).toHaveLength(3) // 2 from Package1 + 1 from Package2
|
||||
})
|
||||
|
||||
it('should display import failed packages separately', async () => {
|
||||
const wrapper = createWrapper()
|
||||
|
||||
// Expand import failed panel (first header)
|
||||
const importFailedHeader = wrapper.findAll(
|
||||
// Expand import failed panel - find the one containing "Import Failed Extensions"
|
||||
const headers = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-toggle"]'
|
||||
)[0]
|
||||
await importFailedHeader.trigger('click')
|
||||
)
|
||||
const importFailedHeader = headers.find((header) =>
|
||||
header.text().includes('Import Failed Extensions')
|
||||
)
|
||||
expect(importFailedHeader).toBeDefined()
|
||||
await importFailedHeader!.trigger('click')
|
||||
|
||||
// Should display only import failed package
|
||||
const importFailedItems = wrapper.findAll('.conflict-list-item')
|
||||
const expandedPanel = wrapper.find(
|
||||
'[data-testid="conflict-dialog-panel-expanded"]'
|
||||
)
|
||||
expect(expandedPanel.exists()).toBe(true)
|
||||
|
||||
const importFailedItems = expandedPanel.findAll('.flex.h-6')
|
||||
expect(importFailedItems).toHaveLength(1)
|
||||
expect(importFailedItems[0].text()).toContain('Test Package 3')
|
||||
})
|
||||
@@ -346,16 +400,24 @@ describe('NodeConflictDialogContent', () => {
|
||||
it('should display all package names in extensions list', async () => {
|
||||
const wrapper = createWrapper()
|
||||
|
||||
// Expand extensions panel (third header)
|
||||
const extensionsHeader = wrapper.findAll(
|
||||
// Expand extensions panel - find the one containing "Extensions at Risk"
|
||||
const headers = wrapper.findAll(
|
||||
'[data-testid="conflict-dialog-panel-toggle"]'
|
||||
)[2]
|
||||
await extensionsHeader.trigger('click')
|
||||
)
|
||||
const extensionsHeader = headers.find((header) =>
|
||||
header.text().includes('Extensions at Risk')
|
||||
)
|
||||
expect(extensionsHeader).toBeDefined()
|
||||
await extensionsHeader!.trigger('click')
|
||||
|
||||
// Should display all package names
|
||||
expect(wrapper.text()).toContain('Test Package 1')
|
||||
expect(wrapper.text()).toContain('Test Package 2')
|
||||
expect(wrapper.text()).toContain('Test Package 3')
|
||||
const expandedPanel = wrapper.find(
|
||||
'[data-testid="conflict-dialog-panel-expanded"]'
|
||||
)
|
||||
expect(expandedPanel.exists()).toBe(true)
|
||||
expect(expandedPanel.text()).toContain('Test Package 1')
|
||||
expect(expandedPanel.text()).toContain('Test Package 2')
|
||||
expect(expandedPanel.text()).toContain('Test Package 3')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<!-- Import Failed List Wrapper -->
|
||||
<div
|
||||
v-if="importFailedConflicts.length > 0"
|
||||
class="flex min-h-8 w-full flex-col rounded-lg bg-base-background"
|
||||
class="flex min-h-8 w-full flex-col rounded-lg bg-secondary-background"
|
||||
>
|
||||
<div
|
||||
data-testid="conflict-dialog-panel-toggle"
|
||||
@@ -50,7 +50,7 @@
|
||||
<div
|
||||
v-for="(packageName, i) in importFailedConflicts"
|
||||
:key="i"
|
||||
class="conflict-list-item flex h-6 shrink-0 items-center justify-between px-4"
|
||||
class="hover:bg-alpha-azure-600-30 flex h-6 flex-shrink-0 items-center justify-between px-4"
|
||||
>
|
||||
<span class="text-xs text-muted">
|
||||
{{ packageName }}
|
||||
@@ -62,7 +62,7 @@
|
||||
<!-- Conflict List Wrapper -->
|
||||
<div
|
||||
v-if="allConflictDetails.length > 0"
|
||||
class="flex min-h-8 w-full flex-col rounded-lg bg-base-background"
|
||||
class="flex min-h-8 w-full flex-col rounded-lg bg-secondary-background"
|
||||
>
|
||||
<div
|
||||
data-testid="conflict-dialog-panel-toggle"
|
||||
@@ -98,7 +98,7 @@
|
||||
<div
|
||||
v-for="(conflict, i) in allConflictDetails"
|
||||
:key="i"
|
||||
class="conflict-list-item flex h-6 shrink-0 items-center justify-between px-4"
|
||||
class="hover:bg-alpha-azure-600-30 flex h-6 flex-shrink-0 items-center justify-between px-4"
|
||||
>
|
||||
<span class="text-xs text-muted">{{
|
||||
getConflictMessage(conflict, t)
|
||||
@@ -110,7 +110,7 @@
|
||||
<!-- Extension List Wrapper -->
|
||||
<div
|
||||
v-if="conflictData.length > 0"
|
||||
class="flex min-h-8 w-full flex-col rounded-lg bg-base-background"
|
||||
class="flex min-h-8 w-full flex-col rounded-lg bg-secondary-background"
|
||||
>
|
||||
<div
|
||||
data-testid="conflict-dialog-panel-toggle"
|
||||
@@ -146,7 +146,7 @@
|
||||
<div
|
||||
v-for="conflictResult in conflictData"
|
||||
:key="conflictResult.package_id"
|
||||
class="conflict-list-item flex h-6 shrink-0 items-center justify-between px-4"
|
||||
class="hover:bg-alpha-azure-600-30 flex h-6 flex-shrink-0 items-center justify-between px-4"
|
||||
>
|
||||
<span class="text-xs text-muted">
|
||||
{{ conflictResult.package_name }}
|
||||
@@ -236,8 +236,3 @@ const toggleExtensionsPanel = () => {
|
||||
importFailedExpanded.value = false
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.conflict-list-item:hover {
|
||||
background-color: rgb(0 122 255 / 0.2);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<template>
|
||||
<div class="flex h-12 w-full items-center justify-between pl-6">
|
||||
<div class="flex w-full items-center justify-between p-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- Warning Icon -->
|
||||
<i class="pi pi-exclamation-triangle text-lg"></i>
|
||||
<!-- Title -->
|
||||
<p class="text-base font-bold">
|
||||
<i class="icon-[lucide--triangle-alert] text-gold-600"></i>
|
||||
<p class="m-0 text-sm">
|
||||
{{ $t('manager.conflicts.title') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -34,7 +34,7 @@ import ToggleSwitch from 'primevue/toggleswitch'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useNodeConflictDialog } from '@/composables/useNodeConflictDialog'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import { useConflictAcknowledgment } from '@/workbench/extensions/manager/composables/useConflictAcknowledgment'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
@@ -51,7 +51,7 @@ const { t } = useI18n()
|
||||
const { isPackEnabled, enablePack, disablePack, installedPacks } =
|
||||
useComfyManagerStore()
|
||||
const { getConflictsForPackageByID } = useConflictDetectionStore()
|
||||
const { showNodeConflictDialog } = useDialogService()
|
||||
const { show: showNodeConflictDialog } = useNodeConflictDialog()
|
||||
const { acknowledgmentState, markConflictsAsSeen } = useConflictAcknowledgment()
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import DotSpinner from '@/components/common/DotSpinner.vue'
|
||||
import Button from '@/components/ui/button/Button.vue'
|
||||
import type { ButtonVariants } from '@/components/ui/button/button.variants'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useNodeConflictDialog } from '@/composables/useNodeConflictDialog'
|
||||
import { t } from '@/i18n'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
import { useConflictDetection } from '@/workbench/extensions/manager/composables/useConflictDetection'
|
||||
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
||||
@@ -54,8 +54,7 @@ const {
|
||||
}>()
|
||||
|
||||
const managerStore = useComfyManagerStore()
|
||||
const { showNodeConflictDialog } = useDialogService()
|
||||
const { t } = useI18n()
|
||||
const { show: showNodeConflictDialog } = useNodeConflictDialog()
|
||||
|
||||
// Check if any of the packs are currently being installed
|
||||
const isInstalling = computed(() => {
|
||||
|
||||
Reference in New Issue
Block a user