mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 03:01:54 +00:00
[feat] Add dual mode support to NodeConflictDialogContent and fix TypeScript errors
- Add dual mode support to NodeConflictDialogContent: - Support props (conflictedPackages/conflicts) for specific conflicts - Fallback to global composable data for SidebarHelpCenterIcon usage - Import failed extensions section shows at top with package names - Conditional description display for post-What's-New scenarios - Fix TypeScript errors: - PackEnableToggle: Add missing parameter to showConflictModal call - InfoTabs: Update conflictResult prop to allow undefined - WarningTabPanel: Update conflictResult prop to accept undefined - Update tests for comprehensive dual mode functionality coverage
This commit is contained in:
@@ -169,24 +169,41 @@ import { useI18n } from 'vue-i18n'
|
|||||||
|
|
||||||
import ContentDivider from '@/components/common/ContentDivider.vue'
|
import ContentDivider from '@/components/common/ContentDivider.vue'
|
||||||
import { useConflictDetection } from '@/composables/useConflictDetection'
|
import { useConflictDetection } from '@/composables/useConflictDetection'
|
||||||
|
import type { ConflictDetectionResult } from '@/types/conflictDetectionTypes'
|
||||||
import { getConflictMessage } from '@/utils/conflictMessageUtil'
|
import { getConflictMessage } from '@/utils/conflictMessageUtil'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
conflicts?: ConflictDetectionResult[]
|
||||||
|
conflictedPackages?: ConflictDetectionResult[]
|
||||||
showAfterWhatsNew?: boolean
|
showAfterWhatsNew?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const { showAfterWhatsNew } = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
conflicts: () => [],
|
||||||
|
conflictedPackages: () => [],
|
||||||
showAfterWhatsNew: false
|
showAfterWhatsNew: false
|
||||||
})
|
})
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const { conflictedPackages } = useConflictDetection()
|
const { conflictedPackages: globalConflictedPackages } = useConflictDetection()
|
||||||
|
|
||||||
const conflictsExpanded = ref<boolean>(false)
|
const conflictsExpanded = ref<boolean>(false)
|
||||||
const extensionsExpanded = ref<boolean>(false)
|
const extensionsExpanded = ref<boolean>(false)
|
||||||
const importFailedExpanded = ref<boolean>(false)
|
const importFailedExpanded = ref<boolean>(false)
|
||||||
|
|
||||||
const conflictData = computed(() => conflictedPackages.value)
|
// Use props if provided, otherwise use composable data
|
||||||
|
const conflictData = computed(() => {
|
||||||
|
// If props have conflictedPackages, prioritize them
|
||||||
|
if (props.conflictedPackages.length > 0) {
|
||||||
|
return props.conflictedPackages
|
||||||
|
}
|
||||||
|
// If props have conflicts, use them
|
||||||
|
if (props.conflicts.length > 0) {
|
||||||
|
return props.conflicts
|
||||||
|
}
|
||||||
|
// Otherwise, use global conflicted packages from composable
|
||||||
|
return globalConflictedPackages.value
|
||||||
|
})
|
||||||
|
|
||||||
const allConflictDetails = computed(() => {
|
const allConflictDetails = computed(() => {
|
||||||
const allConflicts = flatMap(conflictData.value, (result) => result.conflicts)
|
const allConflicts = flatMap(conflictData.value, (result) => result.conflicts)
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ const onToggle = debounce(
|
|||||||
const handleToggleInteraction = async (event: Event) => {
|
const handleToggleInteraction = async (event: Event) => {
|
||||||
if (!canToggleDirectly.value) {
|
if (!canToggleDirectly.value) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
showConflictModal()
|
showConflictModal(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ import { ImportFailedKey } from '@/types/importFailedTypes'
|
|||||||
const { nodePack, hasCompatibilityIssues, conflictResult } = defineProps<{
|
const { nodePack, hasCompatibilityIssues, conflictResult } = defineProps<{
|
||||||
nodePack: components['schemas']['Node']
|
nodePack: components['schemas']['Node']
|
||||||
hasCompatibilityIssues?: boolean
|
hasCompatibilityIssues?: boolean
|
||||||
conflictResult?: ConflictDetectionResult | null
|
conflictResult?: ConflictDetectionResult | null | undefined
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
// Inject import failed context from parent
|
// Inject import failed context from parent
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import { getConflictMessage } from '@/utils/conflictMessageUtil'
|
|||||||
|
|
||||||
const { nodePack, conflictResult } = defineProps<{
|
const { nodePack, conflictResult } = defineProps<{
|
||||||
nodePack: components['schemas']['Node']
|
nodePack: components['schemas']['Node']
|
||||||
conflictResult: ConflictDetectionResult | null
|
conflictResult: ConflictDetectionResult | null | undefined
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const packageId = computed(() => nodePack?.id || '')
|
const packageId = computed(() => nodePack?.id || '')
|
||||||
|
|||||||
@@ -124,8 +124,12 @@ const handleWhatsNewDismissed = async () => {
|
|||||||
* Show the node conflict dialog with current conflict data
|
* Show the node conflict dialog with current conflict data
|
||||||
*/
|
*/
|
||||||
const showConflictModal = () => {
|
const showConflictModal = () => {
|
||||||
|
const conflictData = {
|
||||||
|
conflictedPackages: conflictDetection.conflictedPackages.value,
|
||||||
|
showAfterWhatsNew: true
|
||||||
|
}
|
||||||
showNodeConflictDialog({
|
showNodeConflictDialog({
|
||||||
showAfterWhatsNew: true,
|
...conflictData,
|
||||||
dialogComponentProps: {
|
dialogComponentProps: {
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
markConflictsAsSeen()
|
markConflictsAsSeen()
|
||||||
|
|||||||
@@ -432,19 +432,14 @@ export const useDialogService = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showNodeConflictDialog(
|
function showNodeConflictDialog(
|
||||||
options: {
|
options: InstanceType<typeof NodeConflictDialogContent>['$props'] & {
|
||||||
showAfterWhatsNew?: boolean
|
|
||||||
dialogComponentProps?: DialogComponentProps
|
dialogComponentProps?: DialogComponentProps
|
||||||
buttonText?: string
|
buttonText?: string
|
||||||
onButtonClick?: () => void
|
onButtonClick?: () => void
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
const {
|
const { dialogComponentProps, buttonText, onButtonClick, ...props } =
|
||||||
dialogComponentProps,
|
options
|
||||||
buttonText,
|
|
||||||
onButtonClick,
|
|
||||||
showAfterWhatsNew
|
|
||||||
} = options
|
|
||||||
|
|
||||||
return dialogStore.showDialog({
|
return dialogStore.showDialog({
|
||||||
key: 'global-node-conflict',
|
key: 'global-node-conflict',
|
||||||
@@ -466,9 +461,7 @@ export const useDialogService = () => {
|
|||||||
},
|
},
|
||||||
...dialogComponentProps
|
...dialogComponentProps
|
||||||
},
|
},
|
||||||
props: {
|
props,
|
||||||
showAfterWhatsNew
|
|
||||||
},
|
|
||||||
footerProps: {
|
footerProps: {
|
||||||
buttonText,
|
buttonText,
|
||||||
onButtonClick
|
onButtonClick
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import type { ConflictDetectionResult } from '@/types/conflictDetectionTypes'
|
|||||||
|
|
||||||
// Mock getConflictMessage utility
|
// Mock getConflictMessage utility
|
||||||
vi.mock('@/utils/conflictMessageUtil', () => ({
|
vi.mock('@/utils/conflictMessageUtil', () => ({
|
||||||
getConflictMessage: vi.fn((conflict, t) => {
|
getConflictMessage: vi.fn((conflict) => {
|
||||||
return `${conflict.type}: ${conflict.current_value} vs ${conflict.required_value}`
|
return `${conflict.type}: ${conflict.current_value} vs ${conflict.required_value}`
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
@@ -195,6 +195,70 @@ describe('NodeConflictDialogContent', () => {
|
|||||||
expect(conflictsSection.text()).toContain('3')
|
expect(conflictsSection.text()).toContain('3')
|
||||||
expect(conflictsSection.text()).toContain('Conflicts')
|
expect(conflictsSection.text()).toContain('Conflicts')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should render with conflict data from props (conflictedPackages)', () => {
|
||||||
|
// Clear composable data to ensure props are used
|
||||||
|
mockConflictData.value = []
|
||||||
|
|
||||||
|
const wrapper = createWrapper({
|
||||||
|
conflictedPackages: mockConflictResults
|
||||||
|
})
|
||||||
|
|
||||||
|
// Should show 3 total conflicts (2 from Package1 + 1 from Package2, excluding import_failed)
|
||||||
|
expect(wrapper.text()).toContain('3')
|
||||||
|
expect(wrapper.text()).toContain('Conflicts')
|
||||||
|
// Should show 3 extensions at risk (all packages)
|
||||||
|
expect(wrapper.text()).toContain('Extensions at Risk')
|
||||||
|
// Should show import failed section
|
||||||
|
expect(wrapper.text()).toContain('Import Failed Extensions')
|
||||||
|
expect(wrapper.text()).toContain('1') // 1 import failed package
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render with conflict data from props (conflicts)', () => {
|
||||||
|
// Clear composable data to ensure props are used
|
||||||
|
mockConflictData.value = []
|
||||||
|
|
||||||
|
const wrapper = createWrapper({
|
||||||
|
conflicts: mockConflictResults
|
||||||
|
})
|
||||||
|
|
||||||
|
// Should show 3 total conflicts (excluding import_failed)
|
||||||
|
expect(wrapper.text()).toContain('3')
|
||||||
|
expect(wrapper.text()).toContain('Conflicts')
|
||||||
|
expect(wrapper.text()).toContain('Extensions at Risk')
|
||||||
|
expect(wrapper.text()).toContain('Import Failed Extensions')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should prioritize conflictedPackages over conflicts prop', () => {
|
||||||
|
const singleConflict: ConflictDetectionResult[] = [
|
||||||
|
{
|
||||||
|
package_id: 'SinglePackage',
|
||||||
|
package_name: 'Single Package',
|
||||||
|
has_conflict: true,
|
||||||
|
is_compatible: false,
|
||||||
|
conflicts: [
|
||||||
|
{
|
||||||
|
type: 'os',
|
||||||
|
current_value: 'macOS',
|
||||||
|
required_value: 'Windows'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// Clear composable data
|
||||||
|
mockConflictData.value = []
|
||||||
|
|
||||||
|
const wrapper = createWrapper({
|
||||||
|
conflicts: mockConflictResults, // 4 conflicts total
|
||||||
|
conflictedPackages: singleConflict // 1 conflict
|
||||||
|
})
|
||||||
|
|
||||||
|
// Should use conflictedPackages (1 conflict) instead of conflicts (4 conflicts)
|
||||||
|
expect(wrapper.text()).toContain('1')
|
||||||
|
expect(wrapper.text()).toContain('Conflicts')
|
||||||
|
expect(wrapper.text()).toContain('Extensions at Risk')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('panel interactions', () => {
|
describe('panel interactions', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user