mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-20 23:04:06 +00:00
Updated manager dialog components, pack cards, version selectors, and action buttons to work with the new manager API and state management structure.
191 lines
6.1 KiB
Vue
191 lines
6.1 KiB
Vue
<template>
|
|
<Card
|
|
class="w-full h-full inline-flex flex-col justify-between items-start overflow-hidden rounded-lg shadow-elevation-3 dark-theme:bg-dark-elevation-2 transition-all duration-200"
|
|
:class="{
|
|
'selected-card': isSelected,
|
|
'opacity-60': isDisabled
|
|
}"
|
|
:pt="{
|
|
body: { class: 'p-0 flex flex-col w-full h-full rounded-lg gap-0' },
|
|
content: { class: 'flex-1 flex flex-col rounded-lg min-h-0' },
|
|
title: { class: 'w-full h-full rounded-t-lg cursor-pointer' },
|
|
footer: { class: 'p-0 m-0' }
|
|
}"
|
|
>
|
|
<template #title>
|
|
<PackBanner :node-pack="nodePack" />
|
|
</template>
|
|
<template #content>
|
|
<template v-if="isInstalling">
|
|
<div
|
|
class="self-stretch inline-flex flex-col justify-center items-center gap-2 h-full"
|
|
>
|
|
<ProgressSpinner />
|
|
<div
|
|
class="self-stretch text-center justify-start text-sm font-medium leading-none"
|
|
>
|
|
{{ $t('g.installing') }}...
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template v-else>
|
|
<div
|
|
class="self-stretch inline-flex flex-col justify-start items-start"
|
|
>
|
|
<div
|
|
class="px-4 py-3 inline-flex justify-start items-start cursor-pointer w-full"
|
|
>
|
|
<div
|
|
class="inline-flex flex-col justify-start items-start overflow-hidden gap-y-3 w-full"
|
|
>
|
|
<span
|
|
class="text-base font-bold truncate overflow-hidden text-ellipsis"
|
|
>
|
|
{{ nodePack.name }}
|
|
</span>
|
|
<p
|
|
v-if="nodePack.description"
|
|
class="flex-1 justify-start text-muted text-sm font-medium break-words overflow-hidden min-h-12 line-clamp-3 my-0 leading-5"
|
|
>
|
|
{{ nodePack.description }}
|
|
</p>
|
|
<div class="flex flex-col gap-y-2">
|
|
<div
|
|
class="self-stretch inline-flex justify-start items-center gap-1"
|
|
>
|
|
<div
|
|
v-if="nodesCount"
|
|
class="pr-2 py-1 flex justify-center text-sm items-center gap-1"
|
|
>
|
|
<div
|
|
class="text-center justify-center font-medium leading-3"
|
|
>
|
|
{{ nodesCount }} {{ $t('g.nodes') }}
|
|
</div>
|
|
</div>
|
|
<div class="px-2 py-1 flex justify-center items-center gap-1">
|
|
<div
|
|
v-if="isUpdateAvailable"
|
|
class="w-4 h-4 relative overflow-hidden"
|
|
>
|
|
<i class="pi pi-arrow-circle-up text-blue-600" />
|
|
</div>
|
|
<PackVersionBadge
|
|
:node-pack="nodePack"
|
|
:is-selected="isSelected"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-if="formattedLatestVersionDate"
|
|
class="px-2 py-1 flex justify-center items-center gap-1 text-xs text-muted font-medium"
|
|
>
|
|
{{ formattedLatestVersionDate }}
|
|
</div>
|
|
</div>
|
|
<div class="flex">
|
|
<span
|
|
v-if="publisherName"
|
|
class="text-xs text-muted font-medium leading-3 max-w-40 truncate"
|
|
>
|
|
{{ publisherName }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
<template #footer>
|
|
<ContentDivider :width="0.1" />
|
|
<PackCardFooter :node-pack="nodePack" />
|
|
</template>
|
|
</Card>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { whenever } from '@vueuse/core'
|
|
import Card from 'primevue/card'
|
|
import ProgressSpinner from 'primevue/progressspinner'
|
|
import { computed, provide, ref } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import ContentDivider from '@/components/common/ContentDivider.vue'
|
|
import PackVersionBadge from '@/components/dialog/content/manager/PackVersionBadge.vue'
|
|
import PackBanner from '@/components/dialog/content/manager/packBanner/PackBanner.vue'
|
|
import PackCardFooter from '@/components/dialog/content/manager/packCard/PackCardFooter.vue'
|
|
import { usePackUpdateStatus } from '@/composables/nodePack/usePackUpdateStatus'
|
|
import { useComfyManagerStore } from '@/stores/comfyManagerStore'
|
|
import {
|
|
IsInstallingKey,
|
|
type MergedNodePack,
|
|
type RegistryPack,
|
|
isMergedNodePack
|
|
} from '@/types/comfyManagerTypes'
|
|
|
|
const { nodePack, isSelected = false } = defineProps<{
|
|
nodePack: MergedNodePack | RegistryPack
|
|
isSelected?: boolean
|
|
}>()
|
|
|
|
const { d } = useI18n()
|
|
|
|
const isInstalling = ref(false)
|
|
provide(IsInstallingKey, isInstalling)
|
|
|
|
const { isPackInstalled, isPackEnabled } = useComfyManagerStore()
|
|
const { isUpdateAvailable } = usePackUpdateStatus(nodePack)
|
|
|
|
const isDisabled = ref(false)
|
|
const managerStore = useComfyManagerStore()
|
|
|
|
// Watch the installedPacks object directly (which gets updated from WebSocket)
|
|
whenever(
|
|
() => managerStore.installedPacksIds,
|
|
() => {
|
|
const isInstalled = isPackInstalled(nodePack?.id)
|
|
isDisabled.value = isInstalled && !isPackEnabled(nodePack?.id)
|
|
|
|
// Update isInstalling state after installation is complete
|
|
if (isInstalling.value && isInstalled) isInstalling.value = false
|
|
}
|
|
)
|
|
|
|
const nodesCount = computed(() =>
|
|
isMergedNodePack(nodePack) ? nodePack.comfy_nodes?.length : undefined
|
|
)
|
|
const publisherName = computed(() => {
|
|
if (!nodePack) return null
|
|
|
|
const { publisher, author } = nodePack
|
|
return publisher?.name ?? publisher?.id ?? author
|
|
})
|
|
|
|
const formattedLatestVersionDate = computed(() => {
|
|
if (!nodePack.latest_version?.createdAt) return null
|
|
|
|
return d(new Date(nodePack.latest_version.createdAt), {
|
|
dateStyle: 'medium'
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.selected-card {
|
|
position: relative;
|
|
}
|
|
|
|
.selected-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
border: 3px solid var(--p-primary-color);
|
|
border-radius: 0.5rem;
|
|
pointer-events: none;
|
|
z-index: 100;
|
|
}
|
|
</style>
|