[bugfix] Disable install button when already installed version is selected (#8412)

## Summary
Prevent re-installing an already installed version by disabling the
Install button and the version option in the selector.

## Changes
- Add `isVersionInstalled()` function to check if a version is already
installed
- Add `isInstallDisabled` computed to disable Install button when
selected version is installed
- Add `option-disabled="isInstalled"` to Listbox to prevent selecting
installed versions

Fixes the issue where users could trigger duplicate install operations
by selecting the currently installed version.

🤖 Generated with [Claude Code](https://claude.ai/code)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8412-bugfix-Disable-install-button-when-already-installed-version-is-selected-2f76d73d365081cb859ff98a3d1c64e6)
by [Unito](https://www.unito.io)
This commit is contained in:
Jin Yi
2026-01-29 16:58:12 +09:00
committed by GitHub
parent 23a5baef43
commit 4debbf8268
2 changed files with 23 additions and 7 deletions

View File

@@ -55,6 +55,8 @@ const mockNodePack = {
const mockGetPackVersions = vi.fn()
const mockInstallPack = vi.fn().mockResolvedValue(undefined)
const mockCheckNodeCompatibility = vi.fn()
const mockIsPackInstalled = vi.fn(() => false)
const mockGetInstalledPackVersion = vi.fn(() => undefined)
// Mock the registry service
vi.mock('@/services/comfyRegistryService', () => ({
@@ -70,8 +72,8 @@ vi.mock('@/workbench/extensions/manager/stores/comfyManagerStore', () => ({
call: mockInstallPack,
clear: vi.fn()
},
isPackInstalled: vi.fn(() => false),
getInstalledPackVersion: vi.fn(() => undefined)
isPackInstalled: mockIsPackInstalled,
getInstalledPackVersion: mockGetInstalledPackVersion
}))
}))
@@ -98,6 +100,8 @@ describe('PackVersionSelectorPopover', () => {
mockCheckNodeCompatibility
.mockReset()
.mockReturnValue({ hasConflict: false, conflicts: [] })
mockIsPackInstalled.mockReset().mockReturnValue(false)
mockGetInstalledPackVersion.mockReset().mockReturnValue(undefined)
})
const mountComponent = ({

View File

@@ -25,6 +25,7 @@
v-model="selectedVersion"
option-label="label"
option-value="value"
option-disabled="isInstalled"
:options="processedVersionOptions"
:highlight-on-select="false"
class="max-h-[50vh] w-full rounded-md border-none shadow-none"
@@ -71,7 +72,7 @@
<Button
variant="secondary"
class="rounded-lg bg-secondary-background px-4 py-2.5 text-sm text-base-foreground"
:disabled="isQueueing"
:disabled="isInstallDisabled"
@click="handleSubmit"
>
{{ $t('g.install') }}
@@ -136,8 +137,10 @@ const managerStore = useComfyManagerStore()
const { checkNodeCompatibility } = useConflictDetection()
const isQueueing = ref(false)
const selectedVersion = ref<string>(SelectedVersionValues.LATEST)
const isInstallDisabled = computed(
() => isQueueing.value || isVersionInstalled(selectedVersion.value)
)
onMounted(() => {
const initialVersion =
getInitialSelectedVersion() ?? SelectedVersionValues.LATEST
@@ -299,16 +302,25 @@ const isOptionSelected = (optionValue: string) => {
}
return false
}
// Checks if an option is selected, treating 'latest' as an alias for the actual latest version number.
const isVersionInstalled = (version: string) => {
const installed = nodePack.id
? managerStore.getInstalledPackVersion(nodePack.id)
: undefined
if (!installed) return false
if (version === 'latest')
return installed === nodePack.latest_version?.version
return version === installed
}
const processedVersionOptions = computed(() => {
return versionOptions.value.map((option) => {
const compatibility = getVersionCompatibility(option.value)
const isSelected = isOptionSelected(option.value)
return {
...option,
hasConflict: compatibility.hasConflict,
conflictMessage: compatibility.conflictMessage,
isSelected: isSelected
isSelected: isOptionSelected(option.value),
isInstalled: isVersionInstalled(option.value)
}
})
})