## Summary
When the built-in logs terminal stayed open during a backend restart,
the buffer froze on pre-restart entries and live log streaming silently
stopped — only closing and reopening the panel resynced. Listen for the
api `reconnected` event and rebuild the terminal contents the same way a
fresh open would.
## Changes
- **What**:
- Extract `useLogsTerminal` composable. The SFC is now a thin shell
holding `terminal: shallowRef<Terminal>` and forwarding to the
composable, so `onMounted`/`onScopeDispose` no longer rely on the
child's emit callback timing.
- Subscribe to `api`'s `reconnected` event via `useEventListener`,
registered synchronously before any awaits. On reconnect:
`terminal.reset()` → refetch raw logs → `scrollToBottom()` →
`subscribeLogs(true)` (the backend loses the per-client subscription on
restart, so re-subscribe is required for live streaming to resume).
- Wrap in-flight resync/mount fetches in AbortControllers. Overlapping
reconnects abort the prior resync, and unmount mid-fetch suppresses
writes to the disposed xterm.
- Hide BaseTerminal whenever `errorMessage` is set so the error layout
doesn't expose an empty xterm container behind the message;
`loading=false` after both load failure and resync success so a later
successful reconnect can clear a stuck spinner.
- Migrate the load/resync error strings to vue-i18n
(`logsTerminal.loadError`, `logsTerminal.resyncError`).
## Review Focus
- **Re-subscribe is the non-obvious half of the fix** — without it, even
after the WebSocket reconnects the backend never resumes streaming logs
to this client because its subscription state was wiped on restart. The
visible "stale buffer" is only one symptom; the silent "no new logs"
symptom needed the explicit `subscribeLogs(true)` re-call in resync.
- `terminal.reset()` lives after a successful raw-logs fetch (not
before) so a failed resync leaves the prior buffer visible instead of
blanking it; resync errors surface via the same inline error message the
mount path uses.
- 8 unit tests around the composable: mount + subscribe, resync ordering
(reset → write → scroll → subscribe via `invocationCallOrder`),
in-flight resync abort on double reconnect, resync error surfacing,
mount-failure-then-recovery, unmount-mid-fetch terminal-write
suppression, listener cleanup on unmount.
- 2 E2E tests using `ws.close()` on the proxied WebSocket as the
reconnect trigger and `subscribeLogs` HTTP fetch count as the sync point
(same pattern as `wsReconnectStaleJob.spec.ts`). Red-checked: disabling
the `reconnected` listener fails exactly the two new tests, all 8
pre-existing tests stay green.
Fixes FE-712
## Screenshots
Before - (After rebooting, the console window does not update from its
state before the reboot must remount the console window for it to
resync.)
https://github.com/user-attachments/assets/b1e49c2c-89a4-4a4a-82b4-064412acee12
After - (The console window syncs automatically after a reboot.)
https://github.com/user-attachments/assets/54b582c5-ad42-41c0-9886-18f4495859da
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-12270-fix-terminal-resync-logs-console-on-backend-reconnect-3606d73d3650812fb13fd1934c632344)
by [Unito](https://www.unito.io)
*PR Created by the Glary-Bot Agent*
---
## Summary
- Replace all `cn` / `ClassValue` imports from the
`@/utils/tailwindUtil` re-export shim with direct imports from
`@comfyorg/tailwind-utils` across 198 source files in `src/` and 3 in
`apps/desktop-ui/`
- Delete both shim files (`src/utils/tailwindUtil.ts` and
`apps/desktop-ui/src/utils/tailwindUtil.ts`)
- Add explicit `@comfyorg/tailwind-utils` dependency to
`apps/desktop-ui/package.json`
- Update documentation references in `AGENTS.md`,
`docs/guidance/design-standards.md`, and
`docs/guidance/vue-components.md`
Fixes#11288
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11453-refactor-migrate-cn-imports-from-utils-tailwindUtil-shim-to-comfyorg-tailwind-utils--3486d73d365081ec92cce91fbf88e6e4)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
## Summary
Enable `better-tailwindcss/enforce-consistent-class-order` lint rule and
auto-fix all 1027 violations across 263 files. Stacked on #9427.
## Changes
- **What**: Sort Tailwind classes into consistent order via `eslint
--fix`
- Enable `enforce-consistent-class-order` as `'error'` in eslint config
- Purely cosmetic reordering — no behavioral or visual changes
## Review Focus
Mechanical auto-fix PR — all changes are class reordering only. This is
the largest diff but lowest risk since it changes no class names, only
their order.
**Stack:** #9417 → #9427 → **this PR**
Fixes#9300 (partial — 3 of 3 rules)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9428-fix-enable-enforce-consistent-class-order-tailwind-lint-rule-31a6d73d3650811c9065f5178ba3e724)
by [Unito](https://www.unito.io)
## Summary
Enable `better-tailwindcss/enforce-canonical-classes` lint rule and
auto-fix all 611 violations across 173 files. Stacked on #9417.
## Changes
- **What**: Simplify Tailwind classes to canonical forms via `eslint
--fix`:
- `h-X w-X` → `size-X`
- `overflow-x-hidden overflow-y-hidden` → `overflow-hidden`
- and other canonical simplifications
- Enable `enforce-canonical-classes` as `'error'` in eslint config
## Review Focus
Mechanical auto-fix PR — all changes produced by `eslint --fix`. No
visual or behavioral changes; canonical forms are functionally
identical.
**Stack:** #9417 → **this PR** → PR 3 (class order)
Fixes#9300 (partial — 2 of 3 rules)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9427-fix-enable-enforce-canonical-classes-tailwind-lint-rule-31a6d73d365081a49340d7d4640ede45)
by [Unito](https://www.unito.io)
## Summary
Enable `better-tailwindcss/no-deprecated-classes` lint rule and auto-fix
all 103 violations across 65 files. First PR in a stacked series for
#9300.
## Changes
- **What**: Replace deprecated Tailwind v3 classes with v4 equivalents:
- `rounded` → `rounded-sm` (85)
- `flex-shrink-0` → `shrink-0` (16)
- `flex-grow` → `grow` (2)
- Enable `no-deprecated-classes` as `'error'` in eslint config
- Update one test asserting on `'rounded'` class string
## Review Focus
Mechanical auto-fix PR — all changes produced by `eslint --fix`. No
visual or behavioral changes (Tailwind v4 aliases these classes
identically).
Fixes#9300 (partial — 1 of 3 rules)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9417-fix-enable-no-deprecated-classes-tailwind-lint-rule-31a6d73d3650819eaef4cf8ad84fb186)
by [Unito](https://www.unito.io)
Co-authored-by: Alexander Brown <drjkl@comfy.org>
## Summary
Remove Tailwind `@apply` from Vue styles across `src/` and
`apps/desktop-ui/src/` to align with Tailwind v4 guidance, replacing
usages with template utilities or native CSS while preserving behavior.
## Changes
- **What**:
- Batch 1: migrated low-risk template/style utility bundles out of
`@apply`.
- Batch 2: converted PrimeVue/`:deep()` override `@apply` blocks to
native CSS declarations.
- Batch 3: converted `src/components/node/NodeHelpContent.vue` markdown
styling from `@apply` to native CSS/token-based declarations.
- Batch 4: converted final desktop pseudo-element `@apply` styles and
removed stale `@reference` directives no longer required.
- Verified `rg -n "^\s*@apply\b" src apps -g "*.vue"` has no real CSS
`@apply` directives remaining (only known template false-positive event
binding in `NodeSearchContent.vue`).
## Review Focus
- Visual parity in components that previously depended on `@apply` in
`:deep()` selectors and markdown content:
- topbar tabs/popovers, dialogs, breadcrumb, terminal overrides
- desktop install/dialog/update/maintenance surfaces
- node help markdown rendering
- Confirm no regressions from removal of now-unneeded `@reference`
directives.
## Screenshots (if applicable)
- No new screenshots included in this PR.
- Screenshot Playwright suite was run with `--grep="@screenshot"` and
reports baseline diffs in this environment (164 passed, 39 failed, 3
skipped) plus a teardown `EPERM` restore error on local path
`C:\Users\DrJKL\ComfyUI\LTXV\user`.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9146-fix-eradicate-tailwind-apply-usage-in-vue-styles-3116d73d3650813d8642e0bada13df32)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
## Summary
Replace all runtime `isElectron()` function calls with the build-time
`isDesktop` constant from `@/platform/distribution/types`, enabling
dead-code elimination in non-desktop builds.
## Changes
- **What**: Migrate 30 files from runtime `isElectron()` detection
(checking `window.electronAPI`) to the compile-time `isDesktop` constant
(driven by `__DISTRIBUTION__` Vite define). Remove `isElectron` from
`envUtil.ts`. Update `isNativeWindow()` to use `isDesktop`. Guard
`electronAPI()` calls behind `isDesktop` checks in stores. Update 7 test
files to use `vi.hoisted` + getter mock pattern for per-test `isDesktop`
toggling. Add `DISTRIBUTION=desktop` to `dev:electron` script.
## Review Focus
- The `electronDownloadStore.ts` now guards the top-level
`electronAPI()` call behind `isDesktop` to prevent crashes on
non-desktop builds.
- Test mocking pattern uses `vi.hoisted` with a getter to allow per-test
toggling of the `isDesktop` value.
- Pre-existing issues not addressed: `as ElectronAPI` cast in
`envUtil.ts`, `:class="[]"` in `BaseViewTemplate.vue`,
`@ts-expect-error` in `ModelLibrarySidebarTab.vue`.
- This subsumes PR #8627 and renders PR #6122 and PR #7374 obsolete.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8710-refactor-replace-runtime-isElectron-with-build-time-isDesktop-constant-3006d73d365081c08037f0e61c2f6c77)
by [Unito](https://www.unito.io)
## Summary
Major refactoring of browser tests to improve reliability,
maintainability, and type safety.
## Changes
### Test Infrastructure Decomposition
- Decomposed `ComfyPage.ts` (~1000 lines) into focused helpers:
- `CanvasHelper`, `DebugHelper`, `SubgraphHelper`,
`NodeOperationsHelper`
- `SettingsHelper`, `WorkflowHelper`, `ClipboardHelper`,
`KeyboardHelper`
- Created `ContextMenu` page object, `BaseDialog` base class, and
`BottomPanel` page object
- Extracted `DefaultGraphPositions` constants
### Locator Stability
- Added `data-testid` attributes to Vue components (sidebar, dialogs,
node library)
- Created centralized `selectors.ts` with test ID constants
- Replaced fragile CSS selectors (`.nth()`, `:nth-child()`) with
`getByTestId`/`getByRole`
### Performance & Reliability
- Removed `setTimeout` anti-patterns (replaced with `waitForFunction`)
- Replaced `waitForTimeout` with retrying assertions
- Replaced hardcoded coordinates with computed `NodeReference` positions
- Enforced LF line endings for all text files
### Type Safety
- Enabled `no-explicit-any` lint rule for browser_tests via oxlint
- Purged `as any` casts from browser_tests
- Added Window type augmentation for standardized window access
- Added proper type annotations throughout
### Bug Fixes
- Restored `ExtensionManager` API contract
- Removed test-only settings from production schema
- Fixed flaky selectors and missing test setup
## Testing
- All browser tests pass
- Typecheck passes
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Overhauled browser E2E test infrastructure with many new
helpers/fixtures, updated test APIs, and CI test container image bumped
for consistency.
* **Chores**
* Standardized line endings and applied stricter lint rules for browser
tests; workspace dependency version updated.
* **Documentation**
* Updated Playwright and TypeScript testing guidance and test-run
commands.
* **UI**
* Added stable data-testids to multiple components to improve
testability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
## Summary
Improves type safety in test files by replacing unsafe type patterns
with proper TypeScript idioms.
## Changes
- Define typed `TestWindow` interface extending `Window` for Playwright
tests with custom properties
- Use `Partial<HTMLElement>` with single type assertion for DOM element
mocks
- Remove redundant type imports
- Fix `console.log` → `console.warn` in test fixture
## Files Changed
16 test files across browser_tests, packages, and src/components
## Test Plan
- ✅ `pnpm typecheck` passes
- ✅ No new `any` types introduced
- ✅ All pre-commit hooks pass
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8253-refactor-improve-TypeScript-patterns-in-test-files-Group-1-8-2f16d73d365081548f9ece7bcf0525ee)
by [Unito](https://www.unito.io)
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
## Summary
Migrates all unit tests from `tests-ui/` to colocate with their source
files in `src/`, improving discoverability and maintainability.
## Changes
- **What**: Relocated all unit tests to be adjacent to the code they
test, following the `<source>.test.ts` naming convention
- **Config**: Updated `vitest.config.ts` to remove `tests-ui` include
pattern and `@tests-ui` alias
- **Docs**: Moved testing documentation to `docs/testing/` with updated
paths and patterns
## Review Focus
- Migration patterns documented in
`temp/plans/migrate-tests-ui-to-src.md`
- Tests use `@/` path aliases instead of relative imports
- Shared fixtures placed in `__fixtures__/` directories
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7811-chore-migrate-tests-from-tests-ui-to-colocate-with-source-files-2da6d73d36508147a4cce85365dee614)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Unify the current sidebar tabs, structurally and aesthetically.
## Changes
- Removes the Assets only Layout
- Standardizes the title styling and spacing across the tabs.
## Review Focus
<!-- Critical design decisions or edge cases that need attention -->
<!-- If this PR fixes an issue, uncomment and update the line below -->
<!-- Fixes #ISSUE_NUMBER -->
## Screenshots (if applicable)
<!-- Add screenshots or video recording to help explain your changes -->
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7215-WIP-Sidebar-Tabs-component-and-style-alignment-2c26d73d3650817193bfd752e0d0bbde)
by [Unito](https://www.unito.io)
## Summary
Enhancing and further modernizing the UI, giving users more usable area
whilst keeping farmiliar positioning and feel of elements.
## Changes
- **What**: Significant restructure of the UI elements, changing
elements from large blocks to floating elements, updating:
- Side toolbar menu (floating style, supports small/normal mode,
combines to scroll on height overflow)
- Bottom tabs panel (floating style, tabs redesigned)
- Action bar (support for docking/undocking menu)
- Added login/user menu button to top right
- Restyled breadcrumbs (still collapse when overflows)
- Add litegraph support for fps info position (so it isn't covered by
the sidebar)
- **Breaking**:
- Removed various elements and added new ones, I have tested custom
sidebars, custom actions, etc but if scripts are inserting elements into
"other" elements they may have been (re)moved.
- Remove support for bottom menu
- Remove support for 2nd-row tabs
## Screenshots
<img width="1116" height="907" alt="ui"
src="https://github.com/user-attachments/assets/b040a215-67d3-4c88-8c4d-f402a16a34f6"
/>
https://github.com/user-attachments/assets/571dbda5-01ec-47e8-b235-ee1b88c93dd0
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5980-Floating-Menus-UI-rework-2866d73d3650810aac60cc1afe979b60)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
* Add copyTerminal translation key
* Add copy terminal button with select all functionality
* Remove copy button from error view button group
* Add hover-based copy button overlay to terminal
* Fix clipboard copy implementation in BaseTerminal
* Add 'Copy all' tooltip to terminal copy button
* Fix copy button to be away from right hand side
* Update copy button to respect existing selection
- Copy only selected text if any exists
- Copy all text and clear selection if nothing selected
- Update tooltip to reflect new behavior
* Add dynamic tooltip showing actual copy action
- Show 'Copy selection' when text is selected
- Show 'Copy all' when no text is selected
* Remove redundant i18n
* Fix aria-label to use dynamic tooltip text
* Remove debug console.error statements from useTerminal
Clean up debug logging added during development:
- Remove selection change debug logging
- Remove focus state debug logging
- Remove keyboard event debug logging
- Remove copy/paste debug logging
* Remove redundant keyboard handling from useTerminal
The rebase commit already fixed basic copy/paste.
Removed only the complex keyboard event handling that
duplicates the rebase fix. Kept the valuable UI features:
- Hover copy button overlay
- Right-click context menu
* Use Tailwind transition classes instead of custom CSS
Replace custom .animate-fade-in with standard Tailwind
transition-opacity duration-200 classes
* Use VueUse useElementHover for robust hover handling
Replace manual mouseenter/mouseleave events with VueUse
useElementHover composable which properly handles all
edge cases including mouseout and interrupted events
* Move tooltip to left of button
Relieves squished tooltip
* Simplify code
* Fix listener lifecycle management
Consolidate setup into single onMounted block instead
of creating unnecessary duplicate lifecycle hooks
* Replace any type with proper IDisposable type
* Refactor copy logic for clarity
* Use v-show for proper opacity transitions
* Prefer optional chaining
* Use useEventListener for context menu
* Remove redundant opacity classes
* Add BaseTerminal component tests
* Use pointer-events for button interactivity
* Update tests for pointer-events button behavior
* Fix clipboard mock in tests
* Fix test expectations for opacity classes
* Simplify hover tests for button state
* Remove low-value 'renders terminal container' test
* Remove non-functional 'button responds to hover' test
* Remove implementation detail test for dispose listener
* Remove redundant 'tracks selection changes' test
* Remove obvious comments from test file
* Use cn() utility for conditional classes
* Update tests-ui/tests/components/bottomPanel/tabs/terminal/BaseTerminal.spec.ts
Co-authored-by: Alexander Brown <drjkl@comfy.org>
* [auto-fix] Apply ESLint and Prettier fixes
* Remove 'any' types from wrapper and terminalMock variables
Add assertion to verify onSelectionChange was called
* Move mountBaseTerminal factory to module scope
* Rename test file
- Current consensus is .test.ts for component files
* Update src/components/bottomPanel/tabs/terminal/BaseTerminal.vue
* nit
---------
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
* Add text context menu to terminal on right-click
Enable single right-click context menu in BaseTerminal for desktop app users. Previously required two right clicks.
* Use useEventListener for context menu
* Fix overzealous tab-complete
* nit
* temp: move tailwind calls out of the layer
* temp: ts tailwind config
* upgrade: Tailwind v4
This got a little out of hand.
Had to add a relative reference to the stylesheet in any component that uses @apply instead of the utility classes directly.
* upgrade: bg-opacity is now a modifier
* fix: Classic menu buttons assume a border
* Update test expectations [skip ci]
* fix: New preflight removal pattern
* fix: Skeletons don't have skin
* Update test expectations [skip ci]
* fix: Missing @reference
* [auto-fix] Apply ESLint and Prettier fixes
---------
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: GitHub Action <action@github.com>
* fix: Update command label rendering to use i18n normalization
* fix: Replace deprecated with t for command label rendering
* fix: Simplify command rendering check in ShortcutsList tests
* fix: Add missing translation for command label in ShortcutsList tests