Refactor conflict detection system and move to manager extension (#5436)

## Refactor conflict detection system and move to manager extension

### Description

This PR refactors the conflict detection system, moving it from the
global composables to the manager extension folder for better code
organization. Additionally, it improves test type safety and adds
comprehensive test coverage for utility functions.

### Main Changes

#### 📦 Code Organization
- **Moved conflict detection to manager extension** - Relocated all
conflict detection related composables, stores, and utilities from
global scope to `/workbench/extensions/manager/` for better modularity
(https://github.com/Comfy-Org/ComfyUI_frontend/pull/5722)
- **Moved from** `src/composables/useConflictDetection.ts` **to**
`src/workbench/extensions/manager/composables/useConflictDetection.ts`
- Moved related stores and composables to maintain cohesive module
structure

#### ♻️ Refactoring
- **Extracted utility functions** - Split conflict detection logic into
separate utility modules:
  - `conflictUtils.ts` - Conflict consolidation and summary generation
- `systemCompatibility.ts` - OS and accelerator compatibility checking
  - `versionUtil.ts` - Version compatibility checking
- **Removed duplicate state management** - Cleaned up redundant state
and unused functions
- **Improved naming conventions** - Renamed functions for better clarity
- **Removed unused system environment code** - Cleaned up deprecated
code

#### 🔧 Test Improvements
- **Fixed TypeScript errors** in all test files - removed all `any` type
usage
- **Added comprehensive test coverage**:
  - `conflictUtils.test.ts` - 299 lines of tests for conflict utilities
- `systemCompatibility.test.ts` - 270 lines of tests for compatibility
checking
  - `versionUtil.test.ts` - 342 lines of tests for version utilities
- **Updated mock objects** to match actual implementations
- **Aligned with backend changes** - Updated SystemStats structure to
include `pytorch_version`, `embedded_python`,
`required_frontend_version`

#### 🐛 Bug Fixes
- **Fixed OS detection bug** - Resolved issue where 'darwin' was
incorrectly matched as 'Windows' due to containing 'win' substring
- **Fixed import paths** - Updated all import paths after moving to
manager extension
- **Fixed unused exports** - Removed all unused function exports
- **Fixed lint errors** - Resolved all ESLint and Prettier issues

### File Structure Changes

```
Before:
src/
├── composables/
│   └── useConflictDetection.ts (1374 lines)
└── types/

After:
src/
├── utils/
│   ├── conflictUtils.ts (114 lines)
│   ├── systemCompatibility.ts (125 lines)
│   └── versionUtil.ts (enhanced)
└── workbench/extensions/manager/
    ├── composables/
    │   ├── useConflictDetection.ts (758 lines)
    │   └── [other composables]
    └── stores/
        └── conflictDetectionStore.ts
```

### Testing

All tests pass successfully:
-  **155 test files passed**
-  **2209 tests passed**
-  19 skipped (intentionally skipped subgraph-related tests)

### Impact

- **Better code organization** - Manager-specific code is now properly
isolated
- **Improved maintainability** - Smaller, focused utility functions are
easier to test and maintain
- **Enhanced type safety** - No more `any` types in tests
- **Comprehensive test coverage** - All utility functions are thoroughly
tested

### Commits in this PR
1. OS detection bug fix and refactor
2. Remove unused system environment code
3. Improve function naming
4. Refactor conflict detection
5. Remove duplicate state and unused functions
6. Fix unused function exports
7. Move manager features to workbench extension folder
8. Fix import paths
9. Rename systemCompatibility file
10. Improve test type safety
11. Apply ESLint and Prettier fixes

## Screenshots (if applicable)

[screen-capture.webm](https://github.com/user-attachments/assets/b4595604-3761-4d98-ae8e-5693cd0c95bd)


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5436-Manager-refactor-conflict-detect-2686d73d36508186ba06f57dae3656e5)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Jin Yi
2025-09-26 12:21:05 +09:00
committed by GitHub
parent 78d585eca0
commit 5c1e00ff8e
36 changed files with 1843 additions and 1912 deletions

View File

@@ -1,62 +0,0 @@
import type { ConflictDetail } from '@/types/conflictDetectionTypes'
/**
* Generates a localized conflict message for a given conflict detail.
* This function should be used anywhere conflict messages need to be displayed.
*
* @param conflict The conflict detail object
* @param t The i18n translation function
* @returns A localized conflict message string
*/
export function getConflictMessage(
conflict: ConflictDetail,
t: (key: string, params?: Record<string, any>) => string
): string {
const messageKey = `manager.conflicts.conflictMessages.${conflict.type}`
// For version and compatibility conflicts, use interpolated message
if (
conflict.type === 'comfyui_version' ||
conflict.type === 'frontend_version' ||
conflict.type === 'os' ||
conflict.type === 'accelerator'
) {
return t(messageKey, {
current: conflict.current_value,
required: conflict.required_value
})
}
// For banned, pending, and import_failed, use simple message
if (
conflict.type === 'banned' ||
conflict.type === 'pending' ||
conflict.type === 'import_failed'
) {
return t(messageKey)
}
// Fallback to generic message with interpolation
return t('manager.conflicts.conflictMessages.generic', {
current: conflict.current_value,
required: conflict.required_value
})
}
/**
* Generates conflict messages for multiple conflicts and joins them.
*
* @param conflicts Array of conflict details
* @param t The i18n translation function
* @param separator The separator to use when joining messages (default: '; ')
* @returns A single string with all conflict messages joined
*/
export function getJoinedConflictMessages(
conflicts: ConflictDetail[],
t: (key: string, params?: Record<string, any>) => string,
separator = '; '
): string {
return conflicts
.map((conflict) => getConflictMessage(conflict, t))
.join(separator)
}

View File

@@ -1,83 +0,0 @@
import { clean, satisfies } from 'semver'
import type {
ConflictDetail,
ConflictType
} from '@/types/conflictDetectionTypes'
/**
* Cleans a version string by removing common prefixes and normalizing format
* @param version Raw version string (e.g., "v1.2.3", "1.2.3-alpha")
* @returns Cleaned version string or original if cleaning fails
*/
export function cleanVersion(version: string): string {
return clean(version) || version
}
/**
* Checks if a version satisfies a version range
* @param version Current version
* @param range Version range (e.g., ">=1.0.0", "^1.2.0", "1.0.0 - 2.0.0")
* @returns true if version satisfies the range
*/
export function satisfiesVersion(version: string, range: string): boolean {
try {
const cleanedVersion = cleanVersion(version)
return satisfies(cleanedVersion, range)
} catch {
return false
}
}
/**
* Checks version compatibility and returns conflict details.
* Supports all semver ranges including >=, <=, >, <, ~, ^ operators.
* @param type Conflict type (e.g., 'comfyui_version', 'frontend_version')
* @param currentVersion Current version string
* @param supportedVersion Required version range string
* @returns ConflictDetail object if incompatible, null if compatible
*/
export function utilCheckVersionCompatibility(
type: ConflictType,
currentVersion: string,
supportedVersion: string
): ConflictDetail | null {
// If current version is unknown, assume compatible (no conflict)
if (!currentVersion || currentVersion === 'unknown') {
return null
}
// If no version requirement specified, assume compatible (no conflict)
if (!supportedVersion || supportedVersion.trim() === '') {
return null
}
try {
// Clean the current version using semver utilities
const cleanCurrent = cleanVersion(currentVersion)
// Check version compatibility using semver library
const isCompatible = satisfiesVersion(cleanCurrent, supportedVersion)
if (!isCompatible) {
return {
type,
current_value: currentVersion,
required_value: supportedVersion
}
}
return null
} catch (error) {
console.warn(
`[VersionUtil] Failed to parse version requirement: ${supportedVersion}`,
error
)
// On error, assume incompatible to be safe
return {
type,
current_value: currentVersion,
required_value: supportedVersion
}
}
}