mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-15 11:44:10 +00:00
## Summary Redesigns the Errors tab cards to match the new Figma error-panel spec (file `Czv0JcCfcUiizeEZURevpq`): every error group is now wrapped in a single bordered card led by an error-count summary hero, with each category rendered as a collapsible section whose count lives in a circular badge rather than a parenthetical title suffix. > Rebased onto `main` after #12793 was merged. This PR now contains only the error-card redesign slice. ## Changes - **What**: - **New `ErrorCardSection.vue`** — the shared section shell used by every error type. Renders a 32px header (circular count badge + neutral title + `actions` slot + collapse chevron) and a `TransitionCollapse` body. Replaces the per-group `PropertiesAccordionItem`, dropping the old octagon-alert icon + red title + `(n)` suffix and the sticky-header behavior. - **`TabErrors.vue`** — wraps all groups in one `rounded-lg` card bordered with `secondary-background`. Adds a summary **hero** (large severity-colored total count, vertical divider, "N Errors detected / Resolve before running the workflow"). Moves the per-group action buttons (Install All / Replace All / missing-model Refresh) into the section's `actions` slot. Adds `getGroupCount()` / `totalErrorCount` and switches content background to `interface-panel-surface`. Most of the line count here is re-indentation from the template restructure, not behavior change. - **`missingErrorResolver.ts`** — drops the `formatCountTitle` helper so display titles are `"Missing Models"` instead of `"Missing Models (4)"`; the badge now carries the count. Toast titles/messages are untouched. - **`ErrorNodeCard.vue`** — restyles the runtime/validation error-log box to the Figma spec: borderless `base-foreground/5` surface, `ERROR LOG` header, 12px non-mono body at 50% opacity, inset footer divider with Get Help / Find on GitHub links. - **Row components** (`MissingModelRow`, `MissingPackGroupRow`, `SwapNodeGroupRow`, `MissingMediaCard`, `MissingNodeCard`, `MissingModelCard`) — align spacing, fonts, badges, and button sizes with Figma: 12px row labels, `size="sm"` (24px) action buttons, 16px count badges (`rounded-sm`, `secondary-background-hover`, 9px), 32px reference-row heights, `px-3` card padding. Model-name wrapping is kept independent of its count badge and link button so they never reflow into the metadata sub-label. - **i18n** — adds `errorsDetected` (pluralized), `resolveBeforeRun`, `expand`, `collapse` to `en/main.json`. - **Breaking**: None. No store, composable, action, or data-flow changes — all handlers and emitted events are preserved. The only user-visible copy change is the removal of the `(n)` count suffix from section titles. ## Review Focus - **Title copy change**: `"Missing Models (4)"` → `"Missing Models"`. Search-filter matching against the old `(n)` string no longer applies, but the count is shown by the badge and the hero total. - **Sticky header removed**: section headers no longer pin to the top on scroll (intentional per the new design). - **Collapse click target**: the old single-button header (which nested action buttons inside a `<button>` — invalid HTML) is split into a separate title button and chevron button. Behavior is unchanged and accessibility improves; the empty space beside an action button no longer toggles collapse. - All semantic colors map to existing design-system tokens (no `dark:` variants, no hardcoded hex). Verified the artifact hex values match the tokens (e.g. `#262729` = `secondary-background`, `#e04e48` = `destructive-background-hover`, `#171718` = `interface-panel-surface`). ## Follow-up This PR intentionally keeps the error-count ownership cleanup out of the current diff so the card redesign remains reviewable. A follow-up PR will centralize error counting around a single source of truth so the Errors tab summary hero, section badges, and any overlay surfaces cannot drift from one another. That follow-up will also address the current count mismatch in the ErrorOverlay and continue the ErrorOverlay redesign there, instead of expanding this PR after review. ## Screenshots (if applicable) After <img width="603" height="703" alt="스크린샷 2026-06-13 오후 1 00 02" src="https://github.com/user-attachments/assets/065d7c19-9748-4e99-9b43-675a31e92949" /> <img width="601" height="197" alt="스크린샷 2026-06-13 오후 1 01 07" src="https://github.com/user-attachments/assets/0fa1fbda-9091-4a45-9eca-e99c43089c0e" /> <img width="617" height="612" alt="스크린샷 2026-06-13 오후 1 02 43" src="https://github.com/user-attachments/assets/3d67a057-bf65-4e51-bcf5-70ecce851826" /> <img width="495" height="723" alt="스크린샷 2026-06-13 오후 1 03 28" src="https://github.com/user-attachments/assets/6dcc4021-0fc3-4955-a68b-c0533c66a3cf" /> --------- Co-authored-by: GitHub Action <action@github.com>
172 lines
5.8 KiB
Vue
172 lines
5.8 KiB
Vue
<template>
|
|
<div data-testid="missing-node-card" class="px-3">
|
|
<!-- Core node version warning (OSS only) -->
|
|
<div
|
|
v-if="!isCloud && hasMissingCoreNodes"
|
|
role="alert"
|
|
class="mb-3 flex gap-2.5 rounded-lg border border-warning-background/30 bg-warning-background/10 p-3"
|
|
>
|
|
<i
|
|
aria-hidden="true"
|
|
class="mt-0.5 icon-[lucide--triangle-alert] size-4 shrink-0 text-warning-background"
|
|
/>
|
|
<div class="flex flex-col gap-1.5 text-xs/relaxed text-muted-foreground">
|
|
<p class="m-0">
|
|
{{
|
|
currentComfyUIVersion
|
|
? t('loadWorkflowWarning.outdatedVersion', {
|
|
version: currentComfyUIVersion
|
|
})
|
|
: t('loadWorkflowWarning.outdatedVersionGeneric')
|
|
}}
|
|
</p>
|
|
<div
|
|
v-for="[version, nodes] in sortedMissingCoreNodes"
|
|
:key="version"
|
|
class="ml-2"
|
|
>
|
|
<span class="font-medium">
|
|
{{
|
|
t('loadWorkflowWarning.coreNodesFromVersion', {
|
|
version: version || t('loadWorkflowWarning.unknownVersion')
|
|
})
|
|
}}
|
|
</span>
|
|
<span class="ml-1">{{ getUniqueNodeNames(nodes).join(', ') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Manager disabled hint: shown on OSS when manager is not active -->
|
|
<i18n-t
|
|
v-if="showManagerHint"
|
|
keypath="rightSidePanel.missingNodePacks.ossManagerDisabledHint"
|
|
tag="p"
|
|
class="m-0 pb-5 text-sm/relaxed text-muted-foreground"
|
|
>
|
|
<template #pipCmd>
|
|
<code
|
|
class="rounded-sm bg-comfy-menu-bg px-1 py-0.5 font-mono text-xs text-comfy-input-foreground"
|
|
>pip install -U --pre comfyui-manager</code
|
|
>
|
|
</template>
|
|
<template #flag>
|
|
<code
|
|
class="rounded-sm bg-comfy-menu-bg px-1 py-0.5 font-mono text-xs text-comfy-input-foreground"
|
|
>--enable-manager</code
|
|
>
|
|
</template>
|
|
</i18n-t>
|
|
<div class="flex flex-col gap-1 overflow-hidden">
|
|
<MissingPackGroupRow
|
|
v-for="group in missingPackGroups"
|
|
:key="group.packId ?? '__unknown__'"
|
|
:group="group"
|
|
:show-info-button="showInfoButton"
|
|
@locate-node="emit('locateNode', $event)"
|
|
@open-manager-info="emit('openManagerInfo', $event)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Apply Changes: shown when manager enabled and at least one pack install succeeded -->
|
|
<div v-if="shouldShowManagerButtons" class="px-4">
|
|
<Button
|
|
v-if="hasInstalledPacksPendingRestart"
|
|
variant="secondary"
|
|
size="sm"
|
|
:disabled="isRestarting"
|
|
class="mt-2 h-8 w-full min-w-0 rounded-md text-xs"
|
|
@click="applyChanges()"
|
|
>
|
|
<DotSpinner v-if="isRestarting" duration="1s" :size="12" />
|
|
<i
|
|
v-else
|
|
aria-hidden="true"
|
|
class="icon-[lucide--refresh-cw] size-4 shrink-0"
|
|
/>
|
|
<span class="min-w-0 truncate">{{
|
|
t('rightSidePanel.missingNodePacks.applyChanges')
|
|
}}</span>
|
|
</Button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { compare, valid } from 'semver'
|
|
import Button from '@/components/ui/button/Button.vue'
|
|
import DotSpinner from '@/components/common/DotSpinner.vue'
|
|
import { useApplyChanges } from '@/workbench/extensions/manager/composables/useApplyChanges'
|
|
import { useComfyManagerStore } from '@/workbench/extensions/manager/stores/comfyManagerStore'
|
|
import { isCloud } from '@/platform/distribution/types'
|
|
import { useManagerState } from '@/workbench/extensions/manager/composables/useManagerState'
|
|
import { useMissingNodes } from '@/workbench/extensions/manager/composables/nodePack/useMissingNodes'
|
|
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
|
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
|
import type { MissingPackGroup } from '@/components/rightSidePanel/errors/useErrorGroups'
|
|
import MissingPackGroupRow from '@/components/rightSidePanel/errors/MissingPackGroupRow.vue'
|
|
|
|
const { showInfoButton, missingPackGroups } = defineProps<{
|
|
showInfoButton: boolean
|
|
missingPackGroups: MissingPackGroup[]
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
locateNode: [nodeId: string]
|
|
openManagerInfo: [packId: string]
|
|
}>()
|
|
|
|
const { t } = useI18n()
|
|
|
|
const { missingCoreNodes } = useMissingNodes()
|
|
const systemStatsStore = useSystemStatsStore()
|
|
|
|
const hasMissingCoreNodes = computed(
|
|
() => Object.keys(missingCoreNodes.value).length > 0
|
|
)
|
|
|
|
const currentComfyUIVersion = computed<string | null>(() => {
|
|
if (!hasMissingCoreNodes.value) return null
|
|
return systemStatsStore.systemStats?.system?.comfyui_version ?? null
|
|
})
|
|
|
|
const sortedMissingCoreNodes = computed(() =>
|
|
Object.entries(missingCoreNodes.value).sort(([a], [b]) => {
|
|
const aValid = valid(a)
|
|
const bValid = valid(b)
|
|
if (!aValid && !bValid) return 0
|
|
if (!aValid) return 1
|
|
if (!bValid) return -1
|
|
return compare(b, a)
|
|
})
|
|
)
|
|
|
|
function getUniqueNodeNames(nodes: LGraphNode[]): string[] {
|
|
const types = new Set(nodes.map((node) => node.type).filter(Boolean))
|
|
return [...types].sort()
|
|
}
|
|
|
|
const comfyManagerStore = useComfyManagerStore()
|
|
const { isRestarting, applyChanges } = useApplyChanges()
|
|
const { shouldShowManagerButtons } = useManagerState()
|
|
|
|
/**
|
|
* Show the --enable-manager hint when:
|
|
* - Not on Cloud (OSS/local only)
|
|
* - Manager is disabled (showInfoButton is false)
|
|
*/
|
|
const showManagerHint = computed(() => !isCloud && !showInfoButton)
|
|
|
|
/**
|
|
* Show Apply Changes when any pack from the error group is already installed
|
|
* on disk but ComfyUI hasn't restarted yet to load it.
|
|
* This is server-state based → persists across browser refreshes.
|
|
*/
|
|
const hasInstalledPacksPendingRestart = computed(() =>
|
|
missingPackGroups.some(
|
|
(g) => g.packId !== null && comfyManagerStore.isPackInstalled(g.packId)
|
|
)
|
|
)
|
|
</script>
|