41
41
</template >
42
42
<template #content >
43
43
<ContentDivider />
44
- <div class =" flex flex-1 p-5 mt-3 cursor-pointer" >
45
- <div class =" flex-shrink-0 mr-4" >
46
- <PackIcon :node-pack =" nodePack" />
47
- </div >
48
- <div class =" flex flex-col flex-1 min-w-0" >
44
+ <div
45
+ class =" self-stretch px-4 py-3 inline-flex justify-start items-start cursor-pointer"
46
+ >
47
+ <PackIcon :node-pack =" nodePack" />
48
+ <div
49
+ class =" px-4 inline-flex flex-col justify-start items-start overflow-hidden"
50
+ >
49
51
<span
50
- class =" text-lg font-bold pb-4 truncate overflow-hidden text-ellipsis"
52
+ class =" text-sm font-bold truncate overflow-hidden text-ellipsis"
51
53
:title =" nodePack.name"
52
54
>
53
55
{{ nodePack.name }}
54
56
</span >
55
- <div class =" flex-1" >
57
+ <div
58
+ class =" self-stretch inline-flex justify-center items-center gap-2.5"
59
+ >
56
60
<p
57
61
v-if =" nodePack.description"
58
- class =" text-sm text-color-secondary m-0 line-clamp-3 overflow-hidden"
62
+ class =" flex-1 justify-start text-muted text-sm font-medium leading-3 break-words overflow-hidden min-h-12 line-clamp-3 "
59
63
:title =" nodePack.description"
60
64
>
61
65
{{ nodePack.description }}
62
66
</p >
63
67
</div >
68
+ <div
69
+ class =" self-stretch inline-flex justify-start items-center gap-2"
70
+ >
71
+ <div
72
+ v-if =" nodesCount"
73
+ class =" px-2 py-1 flex justify-center text-sm items-center gap-1"
74
+ >
75
+ <div class =" text-center justify-center font-medium leading-3" >
76
+ {{ nodesCount }} {{ $t('g.nodes') }}
77
+ </div >
78
+ </div >
79
+ <div class =" px-2 py-1 flex justify-center items-center gap-1" >
80
+ <div
81
+ v-if =" isUpdateAvailable"
82
+ class =" w-4 h-4 relative overflow-hidden"
83
+ >
84
+ <i class =" pi pi-arrow-circle-up text-blue-600" />
85
+ </div >
86
+ <PackVersionBadge :node-pack =" nodePack" />
87
+ </div >
88
+ </div >
64
89
</div >
65
90
</div >
66
91
</template >
@@ -76,21 +101,37 @@ import Card from 'primevue/card'
76
101
import { computed } from ' vue'
77
102
78
103
import ContentDivider from ' @/components/common/ContentDivider.vue'
104
+ import PackVersionBadge from ' @/components/dialog/content/manager/PackVersionBadge.vue'
79
105
import PackEnableToggle from ' @/components/dialog/content/manager/button/PackEnableToggle.vue'
80
106
import PackInstallButton from ' @/components/dialog/content/manager/button/PackInstallButton.vue'
81
107
import PackCardFooter from ' @/components/dialog/content/manager/packCard/PackCardFooter.vue'
82
108
import PackIcon from ' @/components/dialog/content/manager/packIcon/PackIcon.vue'
83
109
import { useComfyManagerStore } from ' @/stores/comfyManagerStore'
84
110
import type { components } from ' @/types/comfyRegistryTypes'
111
+ import { compareVersions , isSemVer } from ' @/utils/formatUtil'
85
112
86
113
const { nodePack, isSelected = false } = defineProps <{
87
114
nodePack: components [' schemas' ][' Node' ]
88
115
isSelected? : boolean
89
116
}>()
90
117
91
- const managerStore = useComfyManagerStore ()
118
+ const { isPackInstalled, getInstalledPackVersion } = useComfyManagerStore ()
119
+
120
+ const isInstalled = computed (() => isPackInstalled (nodePack ?.id ))
121
+ const isUpdateAvailable = computed (() => {
122
+ if (! isInstalled .value ) return false
123
+
124
+ const latestVersion = nodePack .latest_version ?.version
125
+ if (! latestVersion ) return false
126
+
127
+ const installedVersion = getInstalledPackVersion (nodePack .id )
128
+
129
+ // Don't attempt to show update available for nightly GitHub packs
130
+ if (installedVersion && ! isSemVer (installedVersion )) return false
131
+
132
+ return compareVersions (latestVersion , installedVersion ) > 0
133
+ })
92
134
93
- const isPackInstalled = computed (() =>
94
- managerStore .isPackInstalled (nodePack ?.id )
95
- )
135
+ // TODO: remove type assertion once comfy_nodes is added to node (pack) info type in backend
136
+ const nodesCount = computed (() => (nodePack as any ).comfy_nodes ?.length )
96
137
</script >
0 commit comments