-
+
{{ $t('manager.conflicts.title') }}
diff --git a/src/workbench/extensions/manager/components/manager/button/PackEnableToggle.vue b/src/workbench/extensions/manager/components/manager/button/PackEnableToggle.vue
index 82805e6c2..2317810cf 100644
--- a/src/workbench/extensions/manager/components/manager/button/PackEnableToggle.vue
+++ b/src/workbench/extensions/manager/components/manager/button/PackEnableToggle.vue
@@ -41,6 +41,8 @@ import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comf
import { useConflictDetectionStore } from '@/workbench/extensions/manager/stores/conflictDetectionStore'
import type { components as ManagerComponents } from '@/workbench/extensions/manager/types/generatedManagerTypes'
+import { useImportFailedDetection } from '../../../composables/useImportFailedDetection'
+
const TOGGLE_DEBOUNCE_MS = 256
const { nodePack } = defineProps<{
@@ -53,6 +55,7 @@ const { isPackEnabled, enablePack, disablePack, installedPacks } =
const { getConflictsForPackageByID } = useConflictDetectionStore()
const { showNodeConflictDialog } = useDialogService()
const { acknowledgmentState, markConflictsAsSeen } = useConflictAcknowledgment()
+const { showImportFailedDialog } = useImportFailedDetection(nodePack.id || '')
const isLoading = ref(false)
@@ -81,23 +84,36 @@ const canToggleDirectly = computed(() => {
const showConflictModal = (skipModalDismissed: boolean) => {
let modal_dismissed = acknowledgmentState.value.modal_dismissed
if (skipModalDismissed) modal_dismissed = false
+
if (packageConflict.value && !modal_dismissed) {
- showNodeConflictDialog({
- conflictedPackages: [packageConflict.value],
- buttonText: !isEnabled.value
- ? t('manager.conflicts.enableAnyway')
- : t('manager.conflicts.understood'),
- onButtonClick: async () => {
- if (!isEnabled.value) {
- await handleEnable()
+ // Check if there's an import failed conflict first
+ const hasImportFailed = packageConflict.value.conflicts.some(
+ (conflict) => conflict.type === 'import_failed'
+ )
+ if (hasImportFailed) {
+ // Show import failed dialog instead of general conflict dialog
+ showImportFailedDialog(() => {
+ markConflictsAsSeen()
+ })
+ } else {
+ // Show general conflict dialog for other types of conflicts
+ showNodeConflictDialog({
+ conflictedPackages: [packageConflict.value],
+ buttonText: !isEnabled.value
+ ? t('manager.conflicts.enableAnyway')
+ : t('manager.conflicts.understood'),
+ onButtonClick: async () => {
+ if (!isEnabled.value) {
+ await handleEnable()
+ }
+ },
+ dialogComponentProps: {
+ onClose: () => {
+ markConflictsAsSeen()
+ }
}
- },
- dialogComponentProps: {
- onClose: () => {
- markConflictsAsSeen()
- }
- }
- })
+ })
+ }
}
}
diff --git a/src/workbench/extensions/manager/components/manager/infoPanel/tabs/WarningTabPanel.vue b/src/workbench/extensions/manager/components/manager/infoPanel/tabs/WarningTabPanel.vue
index f673318da..472a60e1d 100644
--- a/src/workbench/extensions/manager/components/manager/infoPanel/tabs/WarningTabPanel.vue
+++ b/src/workbench/extensions/manager/components/manager/infoPanel/tabs/WarningTabPanel.vue
@@ -1,43 +1,37 @@
-
-
-
+
+
+
+
+
+
+
+
{{ getConflictMessage(conflict, $t) }}
-
+
diff --git a/src/workbench/extensions/manager/composables/useConflictDetection.test.ts b/src/workbench/extensions/manager/composables/useConflictDetection.test.ts
index 70b512bdf..28fa8302c 100644
--- a/src/workbench/extensions/manager/composables/useConflictDetection.test.ts
+++ b/src/workbench/extensions/manager/composables/useConflictDetection.test.ts
@@ -410,7 +410,7 @@ describe('useConflictDetection', () => {
mockComfyManagerService.getImportFailInfoBulk
).mockResolvedValue({
'fail-pack': {
- msg: 'Import error',
+ error: 'Import error',
name: 'fail-pack',
path: '/path/to/pack'
} as any // The actual API returns different structure than types
@@ -428,7 +428,7 @@ describe('useConflictDetection', () => {
// Import failure should match the actual implementation
expect(result.results[0].conflicts).toContainEqual({
type: 'import_failed',
- current_value: 'installed',
+ current_value: 'Import error',
required_value: 'Import error'
})
})
diff --git a/src/workbench/extensions/manager/composables/useConflictDetection.ts b/src/workbench/extensions/manager/composables/useConflictDetection.ts
index 43a6fd3d2..4483e25d9 100644
--- a/src/workbench/extensions/manager/composables/useConflictDetection.ts
+++ b/src/workbench/extensions/manager/composables/useConflictDetection.ts
@@ -389,7 +389,10 @@ export function useConflictDetection() {
* @returns Array of conflict detection results for failed imports
*/
function detectImportFailConflicts(
- importFailInfo: Record
+ importFailInfo: Record<
+ string,
+ { error?: string; traceback?: string } | null
+ >
): ConflictDetectionResult[] {
const results: ConflictDetectionResult[] = []
if (!importFailInfo || typeof importFailInfo !== 'object') {
@@ -400,8 +403,11 @@ export function useConflictDetection() {
for (const [packageId, failureInfo] of Object.entries(importFailInfo)) {
if (failureInfo && typeof failureInfo === 'object') {
// Extract error information from Manager API response
- const errorMsg = failureInfo.msg || 'Unknown import error'
- const modulePath = failureInfo.path || ''
+ const errorMsg = failureInfo.error || 'Unknown import error'
+ const traceback = failureInfo.traceback || ''
+
+ // Combine error and traceback for display
+ const fullErrorInfo = traceback || errorMsg
results.push({
package_id: packageId,
@@ -410,8 +416,8 @@ export function useConflictDetection() {
conflicts: [
{
type: 'import_failed',
- current_value: 'installed',
- required_value: failureInfo.msg
+ current_value: errorMsg,
+ required_value: fullErrorInfo
}
],
is_compatible: false
@@ -420,8 +426,8 @@ export function useConflictDetection() {
console.warn(
`[ConflictDetection] Python import failure detected for ${packageId}:`,
{
- path: modulePath,
- error: errorMsg
+ error: errorMsg,
+ hasTraceback: !!traceback
}
)
}
diff --git a/src/workbench/extensions/manager/composables/useImportFailedDetection.test.ts b/src/workbench/extensions/manager/composables/useImportFailedDetection.test.ts
index 39619d5ed..d548af8da 100644
--- a/src/workbench/extensions/manager/composables/useImportFailedDetection.test.ts
+++ b/src/workbench/extensions/manager/composables/useImportFailedDetection.test.ts
@@ -44,7 +44,8 @@ describe('useImportFailedDetection', () => {
>
mockDialogService = {
- showErrorDialog: vi.fn()
+ showErrorDialog: vi.fn(),
+ showImportFailedNodeDialog: vi.fn()
} as unknown as ReturnType
vi.mocked(comfyManagerStore.useComfyManagerStore).mockReturnValue(
@@ -226,13 +227,22 @@ describe('useImportFailedDetection', () => {
showImportFailedDialog()
- expect(mockDialogService.showErrorDialog).toHaveBeenCalledWith(
- expect.any(Error),
- {
- title: 'manager.failedToInstall',
- reportType: 'importFailedError'
+ expect(mockDialogService.showImportFailedNodeDialog).toHaveBeenCalledWith({
+ conflictedPackages: expect.arrayContaining([
+ expect.objectContaining({
+ package_id: 'test-package',
+ package_name: 'Test Package',
+ conflicts: expect.arrayContaining([
+ expect.objectContaining({
+ type: 'import_failed'
+ })
+ ])
+ })
+ ]),
+ dialogComponentProps: {
+ onClose: undefined
}
- )
+ })
})
it('should handle null packageId', () => {
diff --git a/src/workbench/extensions/manager/composables/useImportFailedDetection.ts b/src/workbench/extensions/manager/composables/useImportFailedDetection.ts
index affd47c3a..1edc65006 100644
--- a/src/workbench/extensions/manager/composables/useImportFailedDetection.ts
+++ b/src/workbench/extensions/manager/composables/useImportFailedDetection.ts
@@ -1,11 +1,13 @@
import { computed, unref } from 'vue'
import type { ComputedRef } from 'vue'
-import { useI18n } from 'vue-i18n'
import { useDialogService } from '@/services/dialogService'
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
import { useConflictDetectionStore } from '@/workbench/extensions/manager/stores/conflictDetectionStore'
-import type { ConflictDetail } from '@/workbench/extensions/manager/types/conflictDetectionTypes'
+import type {
+ ConflictDetail,
+ ConflictDetectionResult
+} from '@/workbench/extensions/manager/types/conflictDetectionTypes'
/**
* Extracting import failed conflicts from conflict list
@@ -24,22 +26,18 @@ function extractImportFailedConflicts(conflicts?: ConflictDetail[] | null) {
* Creating import failed dialog
*/
function createImportFailedDialog() {
- const { t } = useI18n()
- const { showErrorDialog } = useDialogService()
+ const { showImportFailedNodeDialog } = useDialogService()
- return (importFailedInfo: ConflictDetail[] | null) => {
- if (importFailedInfo) {
- const errorMessage =
- importFailedInfo
- .map((conflict) => conflict.required_value)
- .filter(Boolean)
- .join('\n') || t('manager.importFailedGenericError')
-
- const error = new Error(errorMessage)
-
- showErrorDialog(error, {
- title: t('manager.failedToInstall'),
- reportType: 'importFailedError'
+ return (
+ conflictedPackages: ConflictDetectionResult[] | null,
+ onClose?: () => void
+ ) => {
+ if (conflictedPackages && conflictedPackages.length > 0) {
+ showImportFailedNodeDialog({
+ conflictedPackages,
+ dialogComponentProps: {
+ onClose
+ }
})
}
}
@@ -74,13 +72,16 @@ export function useImportFailedDetection(
return importFailedInfo.value !== null
})
- const showImportFailedDialog = createImportFailedDialog()
+ const openDialog = createImportFailedDialog()
return {
importFailedInfo,
importFailed,
- showImportFailedDialog: () =>
- showImportFailedDialog(importFailedInfo.value),
+ showImportFailedDialog: (onClose?: () => void) => {
+ if (conflicts.value) {
+ openDialog([conflicts.value], onClose)
+ }
+ },
isInstalled
}
}