From 549a42716f7872e626485b482e2dca884076e431 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Mon, 7 Apr 2025 06:49:40 +0800 Subject: [PATCH] [Manager] Add tab for outdated node packs (has update available) (#3255) Co-authored-by: github-actions --- .../content/manager/ManagerDialogContent.vue | 34 +++++++++++++++++- .../content/manager/packCard/PackCard.vue | 20 ++--------- .../nodePack/usePackUpdateStatus.ts | 35 +++++++++++++++++++ src/locales/en/main.json | 3 +- src/locales/es/main.json | 1 + src/locales/fr/main.json | 1 + src/locales/ja/main.json | 1 + src/locales/ko/main.json | 1 + src/locales/ru/main.json | 1 + src/locales/zh/main.json | 1 + 10 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 src/composables/nodePack/usePackUpdateStatus.ts diff --git a/src/components/dialog/content/manager/ManagerDialogContent.vue b/src/components/dialog/content/manager/ManagerDialogContent.vue index 539de24ae..38757d23e 100644 --- a/src/components/dialog/content/manager/ManagerDialogContent.vue +++ b/src/components/dialog/content/manager/ManagerDialogContent.vue @@ -107,6 +107,7 @@ import RegistrySearchBar from '@/components/dialog/content/manager/registrySearc import GridSkeleton from '@/components/dialog/content/manager/skeleton/GridSkeleton.vue' import { useResponsiveCollapse } from '@/composables/element/useResponsiveCollapse' import { useInstalledPacks } from '@/composables/nodePack/useInstalledPacks' +import { usePackUpdateStatus } from '@/composables/nodePack/usePackUpdateStatus' import { useWorkflowPacks } from '@/composables/nodePack/useWorkflowPacks' import { useRegistrySearch } from '@/composables/useRegistrySearch' import { useComfyManagerStore } from '@/stores/comfyManagerStore' @@ -118,7 +119,8 @@ enum ManagerTab { All = 'all', Installed = 'installed', Workflow = 'workflow', - Missing = 'missing' + Missing = 'missing', + UpdateAvailable = 'updateAvailable' } const { t } = useI18n() @@ -150,6 +152,11 @@ const tabs = ref([ id: ManagerTab.Missing, label: t('g.missing'), icon: 'pi-exclamation-circle' + }, + { + id: ManagerTab.UpdateAvailable, + label: t('g.updateAvailable'), + icon: 'pi-sync' } ]) const selectedTab = ref(tabs.value[0]) @@ -191,6 +198,9 @@ const { const filterMissingPacks = (packs: components['schemas']['Node'][]) => packs.filter((pack) => !comfyManagerStore.isPackInstalled(pack.id)) +const isUpdateAvailableTab = computed( + () => selectedTab.value?.id === ManagerTab.UpdateAvailable +) const isInstalledTab = computed( () => selectedTab.value?.id === ManagerTab.Installed ) @@ -202,6 +212,25 @@ const isWorkflowTab = computed( ) const isAllTab = computed(() => selectedTab.value?.id === ManagerTab.All) +const isOutdatedPack = (pack: components['schemas']['Node']) => { + const { isUpdateAvailable } = usePackUpdateStatus(pack) + return isUpdateAvailable.value === true +} +const filterOutdatedPacks = (packs: components['schemas']['Node'][]) => + packs.filter(isOutdatedPack) + +watch([isUpdateAvailableTab, installedPacks], () => { + if (!isUpdateAvailableTab.value) return + + if (!isEmptySearch.value) { + displayPacks.value = filterOutdatedPacks(installedPacks.value) + } else if (!installedPacks.value.length) { + startFetchInstalled() + } else { + displayPacks.value = filterOutdatedPacks(installedPacks.value) + } +}) + watch([isInstalledTab, installedPacks], () => { if (!isInstalledTab.value) return @@ -248,6 +277,9 @@ const onResultsChange = () => { filterWorkflowPack(searchResults.value) ) break + case ManagerTab.UpdateAvailable: + displayPacks.value = filterOutdatedPacks(searchResults.value) + break default: displayPacks.value = searchResults.value } diff --git a/src/components/dialog/content/manager/packCard/PackCard.vue b/src/components/dialog/content/manager/packCard/PackCard.vue index 4bf2db3d9..5cd3c98a9 100644 --- a/src/components/dialog/content/manager/packCard/PackCard.vue +++ b/src/components/dialog/content/manager/packCard/PackCard.vue @@ -97,10 +97,10 @@ import ContentDivider from '@/components/common/ContentDivider.vue' import PackVersionBadge from '@/components/dialog/content/manager/PackVersionBadge.vue' import PackCardFooter from '@/components/dialog/content/manager/packCard/PackCardFooter.vue' import PackIcon from '@/components/dialog/content/manager/packIcon/PackIcon.vue' +import { usePackUpdateStatus } from '@/composables/nodePack/usePackUpdateStatus' import { useComfyManagerStore } from '@/stores/comfyManagerStore' import { IsInstallingKey } from '@/types/comfyManagerTypes' import type { components } from '@/types/comfyRegistryTypes' -import { compareVersions, isSemVer } from '@/utils/formatUtil' const { nodePack, isSelected = false } = defineProps<{ nodePack: components['schemas']['Node'] @@ -110,8 +110,8 @@ const { nodePack, isSelected = false } = defineProps<{ const isInstalling = ref(false) provide(IsInstallingKey, isInstalling) -const { isPackInstalled, isPackEnabled, getInstalledPackVersion } = - useComfyManagerStore() +const { isPackInstalled, isPackEnabled } = useComfyManagerStore() +const { isUpdateAvailable } = usePackUpdateStatus(nodePack) const isInstalled = computed(() => isPackInstalled(nodePack?.id)) const isDisabled = computed( @@ -120,20 +120,6 @@ const isDisabled = computed( whenever(isInstalled, () => (isInstalling.value = false)) -const isUpdateAvailable = computed(() => { - if (!isInstalled.value) return false - - const latestVersion = nodePack.latest_version?.version - if (!latestVersion) return false - - const installedVersion = getInstalledPackVersion(nodePack.id ?? '') - - // Don't attempt to show update available for nightly GitHub packs - if (installedVersion && !isSemVer(installedVersion)) return false - - return compareVersions(latestVersion, installedVersion) > 0 -}) - // TODO: remove type assertion once comfy_nodes is added to node (pack) info type in backend const nodesCount = computed(() => (nodePack as any).comfy_nodes?.length) diff --git a/src/composables/nodePack/usePackUpdateStatus.ts b/src/composables/nodePack/usePackUpdateStatus.ts new file mode 100644 index 000000000..f8344cd2b --- /dev/null +++ b/src/composables/nodePack/usePackUpdateStatus.ts @@ -0,0 +1,35 @@ +import { computed } from 'vue' + +import { useComfyManagerStore } from '@/stores/comfyManagerStore' +import type { components } from '@/types/comfyRegistryTypes' +import { compareVersions, isSemVer } from '@/utils/formatUtil' + +export const usePackUpdateStatus = ( + nodePack: components['schemas']['Node'] +) => { + const { isPackInstalled, getInstalledPackVersion } = useComfyManagerStore() + + const isInstalled = computed(() => isPackInstalled(nodePack?.id)) + const installedVersion = computed(() => + getInstalledPackVersion(nodePack.id ?? '') + ) + const latestVersion = computed(() => nodePack.latest_version?.version) + + const isNightlyPack = computed( + () => !!installedVersion.value && !isSemVer(installedVersion.value) + ) + + const isUpdateAvailable = computed(() => { + if (!isInstalled.value || isNightlyPack.value || !latestVersion.value) { + return false + } + return compareVersions(latestVersion.value, installedVersion.value) > 0 + }) + + return { + isUpdateAvailable, + isNightlyPack, + installedVersion, + latestVersion + } +} diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 1c0b53ab5..0a332c047 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -105,7 +105,8 @@ "enabling": "Enabling", "disabling": "Disabling", "updating": "Updating", - "migrate": "Migrate" + "migrate": "Migrate", + "updateAvailable": "Update Available" }, "manager": { "title": "Custom Nodes Manager", diff --git a/src/locales/es/main.json b/src/locales/es/main.json index 86a57be5e..6c6830c82 100644 --- a/src/locales/es/main.json +++ b/src/locales/es/main.json @@ -219,6 +219,7 @@ "systemInfo": "Información del sistema", "terminal": "Terminal", "update": "Actualizar", + "updateAvailable": "Actualización Disponible", "updated": "Actualizado", "updating": "Actualizando", "upload": "Subir", diff --git a/src/locales/fr/main.json b/src/locales/fr/main.json index 13e4ad3b4..c74f352cd 100644 --- a/src/locales/fr/main.json +++ b/src/locales/fr/main.json @@ -219,6 +219,7 @@ "systemInfo": "Informations système", "terminal": "Terminal", "update": "Mettre à jour", + "updateAvailable": "Mise à jour disponible", "updated": "Mis à jour", "updating": "Mise à jour", "upload": "Téléverser", diff --git a/src/locales/ja/main.json b/src/locales/ja/main.json index f65a713ad..324a58505 100644 --- a/src/locales/ja/main.json +++ b/src/locales/ja/main.json @@ -219,6 +219,7 @@ "systemInfo": "システム情報", "terminal": "ターミナル", "update": "更新", + "updateAvailable": "更新が利用可能", "updated": "更新済み", "updating": "更新中", "upload": "アップロード", diff --git a/src/locales/ko/main.json b/src/locales/ko/main.json index 654245ab2..040e2811f 100644 --- a/src/locales/ko/main.json +++ b/src/locales/ko/main.json @@ -219,6 +219,7 @@ "systemInfo": "시스템 정보", "terminal": "터미널", "update": "업데이트", + "updateAvailable": "업데이트 가능", "updated": "업데이트 됨", "updating": "업데이트 중", "upload": "업로드", diff --git a/src/locales/ru/main.json b/src/locales/ru/main.json index 7cc8f2ff5..0b4c5c034 100644 --- a/src/locales/ru/main.json +++ b/src/locales/ru/main.json @@ -219,6 +219,7 @@ "systemInfo": "Информация о системе", "terminal": "Терминал", "update": "Обновить", + "updateAvailable": "Доступно обновление", "updated": "Обновлено", "updating": "Обновление", "upload": "Загрузить", diff --git a/src/locales/zh/main.json b/src/locales/zh/main.json index a353c7751..ea5b0f904 100644 --- a/src/locales/zh/main.json +++ b/src/locales/zh/main.json @@ -219,6 +219,7 @@ "systemInfo": "系统信息", "terminal": "终端", "update": "更新", + "updateAvailable": "有更新可用", "updated": "已更新", "updating": "更新中", "upload": "上传",