Files
ComfyUI_frontend/src/components/rightSidePanel/errors/executionItemList.ts
jaeone94 6850d22d99 Redesign error overlay count and toast behavior (#12871)
## Summary

Redesign the run error overlay so its count and copy use the same
grouped error semantics as the redesigned Error tab, while keeping
single-error toast copy precise.

This is a stacked follow-up to #12828. The parent PR redesigns the Error
tab cards and centralizes their grouped/row-based presentation. This PR
applies the same mental model to the compact overlay shown from the Run
button path, so users no longer see one count in the Error tab and a
different count in the overlay.

## Changes

- **What**: Align the error overlay count with the Error tab's grouped
error count.
- The overlay now reads the same grouped error surface that powers the
Error tab hero instead of independently summing raw store error counts.
- Validation/runtime/prompt execution groups use their grouped `count`.
- Missing model/media/node/swap groups keep the row/group count
semantics introduced by the Error tab redesign.
- This avoids cases where the overlay headline says one number while the
panel summarizes another.

- **What**: Preserve the existing single-error toast behavior while
adding explicit multi-row handling.
- A single true leaf still uses the catalog/resolver toast title and
toast message.
- A single grouped execution error with multiple node/input items uses
that group's title/message instead of the generic aggregate copy.
- A single missing model/media group with multiple model/file rows uses
the generic aggregate copy because it represents multiple actionable
rows.
- A single missing model/media row referenced by multiple nodes uses the
group title/message, since there is still only one model/file to
resolve.
- Multiple top-level groups continue to use the aggregate "N errors
found" style copy.

- **What**: Restyle the overlay toast to match the new error-surface
direction.
- Adds a compact dark card with a destructive left accent and a visible
outline for better contrast against the workspace.
  - Keeps the close button in the card header area.
- Keeps the primary "View details" action, but adjusts spacing, size,
and typography to better match the Figma direction.
- Removes the older footer-style dismiss action so the overlay behaves
like a focused status toast rather than a secondary dialog.

- **What**: Share error grouping/count helpers instead of duplicating
local logic.
- Extracts execution item-list detection for reuse between the Error tab
render path and count logic.
- Extracts missing-model grouping/count helpers so missing-model row
count semantics have one implementation.
- Removes `groupedErrorMessages`, which became unused after the overlay
copy decision moved to grouped error state.

- **Breaking**: None.

- **Dependencies**: None.

## Review Focus

- **Stack boundary**: Please review this against
`jaeone/fe-816-error-card-redesign`, not against `main` directly. The
parent PR is #12828 and contains the Error tab card redesign that this
overlay work builds on.

- **Count semantics**: The visible overlay count intentionally changes
from raw store counts to grouped Error tab counts. This is not just a
refactor; it is the intended product behavior so the compact overlay and
the panel hero agree.

- **Overlay message branches**: The overlay can now choose between three
message modes. The goal is to keep precise single-error copy where it is
useful, but avoid showing one node-specific toast message when the
overlay actually represents multiple actionable rows.

| Branch | When it applies | Overlay title source | Overlay message
source | Example output |
| --- | --- | --- | --- | --- |
| Aggregate summary | More than one top-level error group, or one
missing model/media group with multiple actionable model/file rows. |
Generic aggregate title using grouped count. | Generic aggregate
message. | Title: `2 errors found`<br>Message: `Resolve them before
running the workflow.`<br>Example case: one Missing Models group
containing `first.safetensors` and `second.safetensors`. |
| Group summary | Exactly one error group that is not a true single
leaf, but should still be described by the group. This includes one
execution catalog group with multiple items, or one missing model/media
row referenced by multiple nodes. | The group's `displayTitle`. | The
group's `displayMessage`. | Title: `Missing connection`<br>Message:
`Required input slots have no connection feeding them.`<br>Example case:
one validation group with `KSampler - model` and `KSampler - positive`
rows. |
| Single leaf toast | Exactly one group, one actionable row/card, and at
most one node reference. | Resolver/catalog `toastTitle`. |
Resolver/catalog `toastMessage`. | Title: `Model missing`<br>Message:
`CheckpointLoaderSimple is missing missing.safetensors.`<br>Example
case: one missing model file referenced by one node. |

- **Scope control**: This PR intentionally does not redesign the full
Error Overlay flow beyond the compact toast/card. It also does not
revisit the deeper Error tab card layouts already handled in #12828.

- **Accessibility**: The toast keeps `role="status"` for polite
announcement semantics. The duplicate `aria-live` attribute was removed
during cleanup because `role="status"` already implies polite
live-region behavior.

## Validation

- `pnpm format`
- `pnpm lint`
- `pnpm typecheck`
- `pnpm knip`
- `pnpm test:unit src/components/error/useErrorOverlayState.test.ts
src/platform/missingModel/missingModelGrouping.test.ts
src/components/error/ErrorOverlay.test.ts
src/components/rightSidePanel/errors/useErrorGroups.test.ts`
- Pre-commit staged checks passed.
- Pre-push `knip` passed.

## Screenshots (if applicable)
<img width="454" height="179" alt="스크린샷 2026-06-16 오후 6 00 10"
src="https://github.com/user-attachments/assets/a85376ba-2b22-4cf8-a6fa-79f83fb8b244"
/>
<img width="453" height="179" alt="스크린샷 2026-06-16 오후 6 00 31"
src="https://github.com/user-attachments/assets/d9a1d4bd-92ab-451a-bb79-e7cfbc3af7c6"
/>
<img width="486" height="148" alt="스크린샷 2026-06-16 오후 6 00 55"
src="https://github.com/user-attachments/assets/b66faf96-65c8-4a22-9ff9-e8ccd450986e"
/>
<img width="395" height="127" alt="스크린샷 2026-06-16 오후 6 01 22"
src="https://github.com/user-attachments/assets/c64443f9-0eba-4b2b-8049-c1887c788b1e"
/>
<img width="384" height="134" alt="스크린샷 2026-06-16 오후 6 01 30"
src="https://github.com/user-attachments/assets/42f4fcae-b003-4df9-8f3a-0fda85a90880"
/>
<img width="376" height="129" alt="스크린샷 2026-06-16 오후 6 01 53"
src="https://github.com/user-attachments/assets/ce9030d0-2a98-4b38-9e7d-7a9c3103960f"
/>
<img width="379" height="128" alt="스크린샷 2026-06-16 오후 6 02 01"
src="https://github.com/user-attachments/assets/3d4ce356-1c22-4e3b-a1d0-fece351d9fbb"
/>
<img width="463" height="133" alt="스크린샷 2026-06-16 오후 6 02 33"
src="https://github.com/user-attachments/assets/6ae13a44-02aa-4167-8878-4906db468ad6"
/>
2026-06-17 13:31:07 +00:00

22 lines
557 B
TypeScript

import type { ErrorCardData, ErrorGroup } from './types'
export function shouldRenderExecutionItemList(cards: ErrorCardData[]): boolean {
return (
cards.length > 0 &&
cards.every(
(card) =>
card.nodeId &&
card.errors.length > 0 &&
card.errors.every(
(error) => !error.isRuntimeError && Boolean(error.displayItemLabel)
)
)
)
}
export function isExecutionItemListGroup(group: ErrorGroup): boolean {
return (
group.type === 'execution' && shouldRenderExecutionItemList(group.cards)
)
}