Skip to content

Added MaskEditor Rotate and Mirror Functions#7841

Merged
DrJKL merged 13 commits intoComfy-Org:mainfrom
brucew4yn3rp:maskeditor-rotation-logic
Jan 10, 2026
Merged

Added MaskEditor Rotate and Mirror Functions#7841
DrJKL merged 13 commits intoComfy-Org:mainfrom
brucew4yn3rp:maskeditor-rotation-logic

Conversation

@brucew4yn3rp
Copy link
Collaborator

@brucew4yn3rp brucew4yn3rp commented Jan 4, 2026

Canvas Rotation and Mirroring

Overview

Adds rotation (90° left/right) and mirroring (horizontal/vertical) capabilities to the mask editor canvas. All three layers (image, mask, RGB) transform together. Redo and Undo respect transformations as new states. Keyboard shortcuts also added for all four functions in Keybinding settings.

Additionally, fixed the issue of ctrl+z and ctrl+y keyboard commands not restricting to the mask editor canvas while opened.

MaskEditor.Rotate.and.Mirror.mp4

What Changed

New Files

  • src/composables/maskeditor/useCanvasTransform.ts
    • Core transformation logic for rotation and mirroring
    • GPU texture recreation after transformations

Modified Files

src/composables/useCoreCommands.ts

  • Added check to see if Mask Editor is opened for undo and redo commands

src/stores/maskEditorStore.ts

  • Added GPU texture recreation signals

src/composables/maskeditor/useBrushDrawing.ts

  • Added watcher for gpuTexturesNeedRecreation signal
  • Handles GPU texture recreation when canvas dimensions change
  • Recreates textures with new dimensions after rotation
  • Updates preview canvas and readback buffers accordingly
  • Ensures proper ArrayBuffer backing for WebGPU compatibility

src/components/maskeditor/TopBarHeader.vue

  • Added 4 new transform buttons with icons:
    • Rotate Left (counter-clockwise)
    • Rotate Right (clockwise)
    • Mirror Horizontal
    • Mirror Vertical
  • Added visual separators between button groups

src/extensions/core/maskEditor.ts

  • Added keyboard shortcut settings for rotate and mirror

Translation Files (e.g., src/locales/en.json)

  • Added i18n keys:

┆Issue is synchronized with this Notion page by Unito

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jan 4, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 4, 2026

📝 Walkthrough

Walkthrough

Adds rotate (left/right) and mirror (horizontal/vertical) actions to the mask editor UI; implements useCanvasTransform() to transform mask/rgb/img canvases with GPU buffer handling and history recording; expands canvas history to three layers; updates store GPU refs, undo/redo routing, extension commands, tests, and localization.

Changes

Cohort / File(s) Summary
UI Toolbar Actions
src/components/maskeditor/dialog/TopBarHeader.vue, src/locales/en/main.json
Adds four toolbar buttons (rotate left/right, mirror horizontal/vertical) with icons, tooltips, dividers and updated button classes; handlers call useCanvasTransform; localization keys added.
Canvas Transformation Composable
src/composables/maskeditor/useCanvasTransform.ts
New useCanvasTransform() exposing rotateClockwise, rotateCounterclockwise, mirrorHorizontal, mirrorVertical; performs pixel transforms on mask/rgb/img, premultiplies alpha, prepares pending GPU buffers, triggers GPU recreation and records history.
Canvas History Expansion
src/composables/maskeditor/useCanvasHistory.ts, src/composables/maskeditor/useCanvasHistory.test.ts
History storage expanded from two to three layers (mask,rgb,img); save/restore/cleanup updated to capture and restore all three layers and manage ImageBitmap cleanup; tests updated accordingly.
GPU Texture State & Brush Drawing
src/stores/maskEditorStore.ts, src/composables/maskeditor/useBrushDrawing.ts
Store adds refs: gpuTexturesNeedRecreation, gpuTextureWidth, gpuTextureHeight, pendingGPUMaskData, pendingGPURgbData; brush drawing adds watcher to destroy/recreate GPU textures, upload pending or canvas data, resize preview/readback buffers, and clear flags.
Undo/Redo Routing & Extension Commands
src/composables/useCoreCommands.ts, src/extensions/core/maskeditor.ts
Routes global undo/redo to mask editor history when its dialog is open; adds four extension commands invoking useCanvasTransform methods when editor is open.
Transform Tests
src/composables/maskeditor/useCanvasTransform.test.ts
Adds comprehensive tests validating rotate/mirror pixel transforms, dimension swaps, GPU recreation flags and pending buffers, history saves, and error handling.
UI/Event Small Change
src/components/maskeditor/MaskEditorContent.vue
Adds keydown.stop on the root mask editor container to stop keydown propagation.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant TopBar as TopBarHeader
    participant Transform as useCanvasTransform
    participant Store as maskEditorStore
    participant Brush as useBrushDrawing
    participant GPU as GPU

    User->>TopBar: Click rotate/mirror
    TopBar->>Transform: invoke rotate/mirror method
    Transform->>Transform: read mask/rgb/img pixels, apply transform, premultiply, swap dims if needed, save history
    Transform->>Store: set gpuTexturesNeedRecreation, gpuTextureWidth/Height, pending GPU buffers
    Store->>Brush: gpuTexturesNeedRecreation watcher triggers
    Brush->>GPU: destroy/create/upload textures with new size (or upload pending buffers)
    GPU-->>Brush: confirm textures
    Brush->>Store: clear gpu recreation flags and pending buffers
    Brush->>User: updated canvases displayed
Loading

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Jan 4, 2026

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 01/10/2026, 01:49:54 PM UTC

📈 Summary

  • Total Tests: 512
  • Passed: 502 ✅
  • Failed: 0
  • Flaky: 2 ⚠️
  • Skipped: 8 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 490 / ❌ 0 / ⚠️ 2 / ⏭️ 8
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 9 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@github-actions
Copy link

github-actions bot commented Jan 4, 2026

🎨 Storybook Build Status

loading Build is starting...

⏰ Started at: 01/10/2026, 01:43:03 PM UTC

🚀 Building Storybook

  • 📦 Installing dependencies...
  • 🔧 Building Storybook components...
  • 🌐 Preparing deployment to Cloudflare Pages...

⏱️ Please wait while the Storybook build is in progress...

@github-actions
Copy link

github-actions bot commented Jan 4, 2026

Bundle Size Report

Summary

  • Raw size: 18.8 MB baseline 18.8 MB — 🔴 +18.9 kB
  • Gzip: 3.84 MB baseline 3.84 MB — 🔴 +3.1 kB
  • Brotli: 2.93 MB baseline 2.93 MB — 🔴 +2 kB
  • Bundles: 94 current • 94 baseline • 38 added / 38 removed

Category Glance
App Entry Points 🔴 +18.5 kB (3.26 MB) · Graph Workspace 🔴 +392 B (1.05 MB) · Vendor & Third-Party ⚪ 0 B (9.19 MB) · Other ⚪ 0 B (4.73 MB) · Panels & Settings ⚪ 0 B (337 kB) · UI Components ⚪ 0 B (199 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.26 MB (baseline 3.25 MB) • 🔴 +18.5 kB

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-ChMR3ud9.js (new) 3.07 MB 🔴 +3.07 MB 🔴 +643 kB 🔴 +489 kB
assets/index-C45L82H6.js (removed) 3.05 MB 🟢 -3.05 MB 🟢 -641 kB 🟢 -487 kB
assets/index-D7v5fDvX.js (new) 195 kB 🔴 +195 kB 🔴 +42.7 kB 🔴 +35.3 kB
assets/index-CI3-3TPx.js (removed) 194 kB 🟢 -194 kB 🟢 -42.3 kB 🟢 -35.2 kB
assets/index-Do9nZyf4.js (new) 345 B 🔴 +345 B 🔴 +245 B 🔴 +238 B
assets/index-wwTK11iU.js (removed) 345 B 🟢 -345 B 🟢 -247 B 🟢 -200 B

Status: 3 added / 3 removed

Graph Workspace — 1.05 MB (baseline 1.05 MB) • 🔴 +392 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CdzJ3SN5.js (new) 1.05 MB 🔴 +1.05 MB 🔴 +204 kB 🔴 +154 kB
assets/GraphView-ChGgmVaa.js (removed) 1.05 MB 🟢 -1.05 MB 🟢 -203 kB 🟢 -154 kB

Status: 1 added / 1 removed

Views & Navigation — 6.63 kB (baseline 6.63 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-BmbK-Wb1.js (removed) 6.63 kB 🟢 -6.63 kB 🟢 -2.14 kB 🟢 -1.9 kB
assets/UserSelectView-JUQKKMUE.js (new) 6.63 kB 🔴 +6.63 kB 🔴 +2.15 kB 🔴 +1.9 kB

Status: 1 added / 1 removed

Panels & Settings — 337 kB (baseline 337 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LegacyCreditsPanel-BCcqnEMp.js (removed) 25.1 kB 🟢 -25.1 kB 🟢 -5.74 kB 🟢 -5.01 kB
assets/LegacyCreditsPanel-C7Bpr-XY.js (new) 25.1 kB 🔴 +25.1 kB 🔴 +5.74 kB 🔴 +4.99 kB
assets/KeybindingPanel-DctKHCDR.js (new) 14.8 kB 🔴 +14.8 kB 🔴 +3.57 kB 🔴 +3.13 kB
assets/KeybindingPanel-JuJAkir7.js (removed) 14.8 kB 🟢 -14.8 kB 🟢 -3.57 kB 🟢 -3.12 kB
assets/ExtensionPanel-BC7OV40b.js (new) 11.1 kB 🔴 +11.1 kB 🔴 +2.62 kB 🔴 +2.3 kB
assets/ExtensionPanel-DKrHFCjJ.js (removed) 11.1 kB 🟢 -11.1 kB 🟢 -2.62 kB 🟢 -2.3 kB
assets/AboutPanel-Bn-_je9U.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/AboutPanel-Dmbw0xfw.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/ServerConfigPanel-BE4FulMk.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -2.04 kB 🟢 -1.81 kB
assets/ServerConfigPanel-DxhwGhpg.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +2.04 kB 🔴 +1.81 kB
assets/UserPanel-Ct6ZXpIn.js (new) 6.88 kB 🔴 +6.88 kB 🔴 +1.79 kB 🔴 +1.57 kB
assets/UserPanel-CtL5hOEX.js (removed) 6.88 kB 🟢 -6.88 kB 🟢 -1.79 kB 🟢 -1.56 kB
assets/settings-BbW1wrcp.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CtIClcWI.js 26 kB 26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D_f3uAqO.js 22.4 kB 22.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DiVjuKQX.js 34.4 kB 34.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DJiF1Y59.js 25.8 kB 25.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DKkx6nFR.js 28.2 kB 28.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DX5qVgIQ.js 24.9 kB 24.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-MzsBgiwB.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-pR7Ue3ei.js 26.7 kB 26.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-y_-zNlA6.js 27.5 kB 27.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

UI Components — 199 kB (baseline 199 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LazyImage.vue_vue_type_script_setup_true_lang-Dk1yDWSV.js (new) 64.5 kB 🔴 +64.5 kB 🔴 +13.1 kB 🔴 +11.4 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-WG0NteAi.js (removed) 64.5 kB 🟢 -64.5 kB 🟢 -13.1 kB 🟢 -11.4 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-2x2Vicp6.js (removed) 56.4 kB 🟢 -56.4 kB 🟢 -8.78 kB 🟢 -7.53 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-Dxc_6H9W.js (new) 56.4 kB 🔴 +56.4 kB 🔴 +8.78 kB 🔴 +7.53 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-Ba0MOSik.js (removed) 49 kB 🟢 -49 kB 🟢 -10.5 kB 🟢 -9.16 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-C9z5sw0J.js (new) 49 kB 🔴 +49 kB 🔴 +10.5 kB 🔴 +9.14 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-CBwROsBq.js (new) 10.9 kB 🔴 +10.9 kB 🔴 +2.9 kB 🔴 +2.57 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-CnUUnUgX.js (removed) 10.9 kB 🟢 -10.9 kB 🟢 -2.89 kB 🟢 -2.55 kB
assets/ComfyQueueButton-BaJzsVK1.js (new) 8.83 kB 🔴 +8.83 kB 🔴 +2.58 kB 🔴 +2.3 kB
assets/ComfyQueueButton-U1Csmy1C.js (removed) 8.83 kB 🟢 -8.83 kB 🟢 -2.58 kB 🟢 -2.3 kB
assets/WidgetWithControl.vue_vue_type_script_setup_true_lang-CsvOfBB_.js (removed) 3.72 kB 🟢 -3.72 kB 🟢 -1.46 kB 🟢 -1.32 kB
assets/WidgetWithControl.vue_vue_type_script_setup_true_lang-iweiRnoZ.js (new) 3.72 kB 🔴 +3.72 kB 🔴 +1.45 kB 🔴 +1.32 kB
assets/WidgetButton-2BmVOA3g.js (new) 2.21 kB 🔴 +2.21 kB 🔴 +996 B 🔴 +874 B
assets/WidgetButton-plCLjDFE.js (removed) 2.21 kB 🟢 -2.21 kB 🟢 -997 B 🟢 -892 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-CYnKYT9m.js (new) 2.14 kB 🔴 +2.14 kB 🔴 +890 B 🔴 +769 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-DQY0wowX.js (removed) 2.14 kB 🟢 -2.14 kB 🟢 -892 B 🟢 -772 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-DIK87nsO.js 1.34 kB 1.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 8 added / 8 removed

Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-BSprk9Ls.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.83 kB 🟢 -1.58 kB
assets/keybindingService-DZqCwUI6.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/audioService-CqJWIrfc.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -963 B 🟢 -824 B
assets/audioService-lbrKdV91.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +960 B 🔴 +822 B
assets/serverConfigStore-B2t_j388.js 2.83 kB 2.83 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 2 added / 2 removed

Utilities & Hooks — 1.41 kB (baseline 1.41 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-BQaWf9p_.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +650 B 🔴 +546 B
assets/audioUtils-C3ghlRBb.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -651 B 🟢 -550 B

Status: 1 added / 1 removed

Vendor & Third-Party — 9.19 MB (baseline 9.19 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-DUP4WQ_9.js 452 kB 452 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-CTAuztsb.js 3.9 MB 3.9 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-VcXE4r8X.js 1.95 MB 1.95 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-B_f9r0GW.js 2.08 MB 2.08 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-B8b7Kqfl.js 232 kB 232 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-BggM5WRa.js 160 kB 160 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-BF8peZ5_.js 420 kB 420 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 4.73 MB (baseline 4.73 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SubscriptionRequiredDialogContent-fazUbwuH.js (removed) 29.3 kB 🟢 -29.3 kB 🟢 -6.51 kB 🟢 -5.64 kB
assets/SubscriptionRequiredDialogContent-GCFevrcR.js (new) 29.3 kB 🔴 +29.3 kB 🔴 +6.51 kB 🔴 +5.65 kB
assets/WidgetRecordAudio-BG8DqdrH.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.23 kB 🟢 -4.63 kB
assets/WidgetRecordAudio-CHs9SKpj.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.23 kB 🔴 +4.63 kB
assets/AudioPreviewPlayer-gq_BgpP9.js (new) 13.3 kB 🔴 +13.3 kB 🔴 +3.35 kB 🔴 +2.99 kB
assets/AudioPreviewPlayer-zJZmrblV.js (removed) 13.3 kB 🟢 -13.3 kB 🟢 -3.35 kB 🟢 -2.99 kB
assets/ValueControlPopover-BNXaYGr2.js (new) 5.49 kB 🔴 +5.49 kB 🔴 +1.71 kB 🔴 +1.51 kB
assets/ValueControlPopover-BRyGmgO1.js (removed) 5.49 kB 🟢 -5.49 kB 🟢 -1.71 kB 🟢 -1.51 kB
assets/WidgetGalleria-B1-kOjL2.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.45 kB 🟢 -1.31 kB
assets/WidgetGalleria-DcKbh7pr.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.45 kB 🔴 +1.3 kB
assets/WidgetColorPicker-CkKpwqij.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetColorPicker-v63J6E_P.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetTextarea-BsZ6FOCr.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.22 kB 🔴 +1.08 kB
assets/WidgetTextarea-Mz-GwfUU.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.22 kB 🟢 -1.08 kB
assets/WidgetMarkdown-BEfHH_IY.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.13 kB
assets/WidgetMarkdown-BlsF2OI4.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetAudioUI-B4GDSaQc.js (new) 2.89 kB 🔴 +2.89 kB 🔴 +1.17 kB 🔴 +1.05 kB
assets/WidgetAudioUI-CpvZh99H.js (removed) 2.89 kB 🟢 -2.89 kB 🟢 -1.17 kB 🟢 -1.05 kB
assets/WidgetToggleSwitch-BSa8X_ej.js (removed) 2.66 kB 🟢 -2.66 kB 🟢 -1.13 kB 🟢 -1.02 kB
assets/WidgetToggleSwitch-CGB7cAtH.js (new) 2.66 kB 🔴 +2.66 kB 🔴 +1.13 kB 🔴 +1.02 kB
assets/WidgetInputText-Bf6cEBAK.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -923 B 🟢 -851 B
assets/WidgetInputText-Dk_itEw2.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +922 B 🔴 +856 B
assets/Media3DTop-BFQ1-esP.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -769 B 🟢 -654 B
assets/Media3DTop-i4w3y5Ga.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +761 B 🔴 +651 B
assets/WidgetSelect-_T8s42Bp.js (new) 733 B 🔴 +733 B 🔴 +362 B 🔴 +307 B
assets/WidgetSelect-Nn_UiUUL.js (removed) 733 B 🟢 -733 B 🟢 -363 B 🟢 -328 B
assets/WidgetInputNumber-BZoavcno.js (removed) 673 B 🟢 -673 B 🟢 -350 B 🟢 -287 B
assets/WidgetInputNumber-C8qIBm8O.js (new) 673 B 🔴 +673 B 🔴 +347 B 🔴 +287 B
assets/Load3D-D9H4LTvI.js (removed) 424 B 🟢 -424 B 🟢 -269 B 🟢 -224 B
assets/Load3D-DmfFjI82.js (new) 424 B 🔴 +424 B 🔴 +268 B 🔴 +224 B
assets/WidgetLegacy-DVBwvUfE.js (removed) 364 B 🟢 -364 B 🟢 -238 B 🟢 -195 B
assets/WidgetLegacy-HNjey-GG.js (new) 364 B 🔴 +364 B 🔴 +238 B 🔴 +195 B
assets/commands-BtYX0Lg9.js 17.7 kB 17.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BwenEAzL.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CXF6rcF5.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CyGop0zh.js 15.1 kB 15.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DDahbUT-.js 15.7 kB 15.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DlbDMAz3.js 15.2 kB 15.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DLFlLaoZ.js 16.4 kB 16.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-edqUNgZp.js 16 kB 16 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-SQ5j-1oJ.js 14.3 kB 14.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-zgiVm_G2.js 15.1 kB 15.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-7lTF3od4.js 148 kB 148 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B2EzieSY.js 108 kB 108 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B9UYJSy5.js 106 kB 106 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BKj_6mJM.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BQbZqz2p.js 128 kB 128 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Byq_ZSjS.js 122 kB 122 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CCgU1dqT.js 106 kB 106 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CeY1eBVB.js 94.4 kB 94.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CM3nY77t.js 93.7 kB 93.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CzXbUjyx.js 112 kB 112 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-Dc3cUA9O.js 1.46 kB 1.46 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-B_idcQw8.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-9cP_AzIo.js 2.65 kB 2.65 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-B-XzzBeS.js 317 kB 317 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BGwoeek4.js 329 kB 329 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-C6xl5-mL.js 358 kB 358 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CRZGOJB7.js 310 kB 310 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-D8-Yzlzh.js 289 kB 289 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Du8VrAwA.js 320 kB 320 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-jjlLVrIs.js 317 kB 317 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-JQwk1kgy.js 292 kB 292 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-JuuXdMpv.js 391 kB 391 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-l2Y20bod.js 314 kB 314 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-CZhjICiW.js 2.48 kB 2.48 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-BpH9qHbL.js 3.21 kB 3.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 16 added / 16 removed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d1f8ed and 0d936a4.

📒 Files selected for processing (5)
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/locales/en/main.json
  • src/stores/maskEditorStore.ts
🧰 Additional context used
📓 Path-based instructions (18)
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3.5+ with TypeScript in .vue files, exclusively using Composition API with <script setup lang="ts"> syntax
Use Tailwind 4 for styling in Vue components; avoid <style> blocks
Name Vue components using PascalCase (e.g., MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer computed() over ref with watch when deriving values
Prefer useModel over separately defining prop and emit for two-way binding
Use vue-i18n in composition API for string literals; place new translation entries in src/locales/en/main.json
Use cn() utility function from @/utils/tailwindUtil for merging Tailwind class names; do not use :class="[]" syntax
Do not use the dark: Tailwind variant; use semantic values from the style.css theme instead (e.g., bg-node-component-surface)
Do not use !important or the ! important prefix for Tailwind classes; find and correct interfering !important classes instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
  • src/locales/en/main.json
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
**/**/use[A-Z]*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the pattern useXyz.ts

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize the surface area (exported values) of each module and composable

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/maskEditorStore.ts
**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia stores using the pattern *Store.ts

Files:

  • src/stores/maskEditorStore.ts
🧠 Learnings (19)
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Leverage VueUse functions for performance-enhancing styles in Vue components

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use defineExpose only for imperative operations (such as form.validate(), modal.open())

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/stores/maskEditorStore.ts
🧬 Code graph analysis (1)
src/composables/maskeditor/useCanvasTransform.ts (1)
src/stores/maskEditorStore.ts (1)
  • useMaskEditorStore (19-301)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: setup
  • GitHub Check: test
  • GitHub Check: lint-and-format
  • GitHub Check: collect
🔇 Additional comments (4)
src/locales/en/main.json (1)

968-971: LGTM!

The new localization keys for rotation and mirroring operations are clear, well-named, and follow the existing conventions. The placement after the redo entry is logical.

src/stores/maskEditorStore.ts (1)

221-226: LGTM!

The reset logic for GPU-related state is comprehensive and properly clears all flags and pending data. This ensures clean state transitions and prevents memory leaks from retained ArrayBuffers.

src/composables/maskeditor/useCanvasTransform.ts (2)

108-115: Premultiplication logic is correct.

The alpha premultiplication implementation correctly converts from straight alpha (used by Canvas 2D) to premultiplied alpha (required by WebGPU). The formula color = color * alpha is applied per-channel with proper rounding.


221-253: LGTM! Mirror operations maintain canvas dimensions correctly.

The mirroring logic correctly:

  • Maintains original canvas dimensions (no swap needed)
  • Applies transformations to all three layers (mask, rgb, img)
  • Triggers GPU texture updates with unchanged dimensions
  • Saves the result to history for undo/redo support

The implementation is clean and follows the same pattern as rotation operations.

@brucew4yn3rp brucew4yn3rp requested a review from trsommer as a code owner January 4, 2026 14:13
@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jan 4, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d936a4 and 2bcbe39.

📒 Files selected for processing (8)
  • src/components/maskeditor/MaskEditorContent.vue
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/useCoreCommands.ts
  • src/extensions/core/maskeditor.ts
  • src/stores/maskEditorStore.ts
🧰 Additional context used
📓 Path-based instructions (18)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/components/maskeditor/MaskEditorContent.vue
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/components/maskeditor/MaskEditorContent.vue
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/components/maskeditor/MaskEditorContent.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/components/maskeditor/MaskEditorContent.vue
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/components/maskeditor/MaskEditorContent.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/components/maskeditor/MaskEditorContent.vue
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
**/**/use[A-Z]*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the pattern useXyz.ts

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/components/maskeditor/MaskEditorContent.vue
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize the surface area (exported values) of each module and composable

Files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3.5+ with TypeScript in .vue files, exclusively using Composition API with <script setup lang="ts"> syntax
Use Tailwind 4 for styling in Vue components; avoid <style> blocks
Name Vue components using PascalCase (e.g., MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer computed() over ref with watch when deriving values
Prefer useModel over separately defining prop and emit for two-way binding
Use vue-i18n in composition API for string literals; place new translation entries in src/locales/en/main.json
Use cn() utility function from @/utils/tailwindUtil for merging Tailwind class names; do not use :class="[]" syntax
Do not use the dark: Tailwind variant; use semantic values from the style.css theme instead (e.g., bg-node-component-surface)
Do not use !important or the ! important prefix for Tailwind classes; find and correct interfering !important classes instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/maskEditorStore.ts
**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia stores using the pattern *Store.ts

Files:

  • src/stores/maskEditorStore.ts
🧠 Learnings (35)
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Prefer `computed()` over `ref` with `watch` when deriving values

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/maskeditor/useCanvasHistory.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use watch and watchEffect for side effects

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
📚 Learning: 2025-12-04T21:43:49.363Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7137
File: src/components/rightSidePanel/parameters/TabParameters.vue:10-0
Timestamp: 2025-12-04T21:43:49.363Z
Learning: Vue 3.5+ supports reactive props destructure in <script setup>. Destructuring props directly (e.g., `const { nodes } = defineProps<{ nodes: LGraphNode[] }>()`) maintains reactivity through compiler transformation. This is the recommended modern approach and does not require using `props.x` or `toRef`/`toRefs`.

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Implement cleanup for async operations in Vue components

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Leverage VueUse functions for performance-enhancing styles in Vue components

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/maskeditor/useBrushDrawing.ts
  • src/composables/useCoreCommands.ts
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/components/maskeditor/MaskEditorContent.vue
  • src/stores/maskEditorStore.ts
  • src/extensions/core/maskeditor.ts
📚 Learning: 2025-12-11T03:55:57.926Z
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Implement proper error handling in code

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Implement proper error handling

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use defineExpose only for imperative operations (such as form.validate(), modal.open())

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/components/maskeditor/MaskEditorContent.vue
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Check tests-ui/README.md for test guidelines

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.test.ts : Aim for behavioral coverage of critical and new features in unit tests

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Take advantage of `TypedArray` `subarray` when appropriate

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
🧬 Code graph analysis (1)
src/extensions/core/maskeditor.ts (1)
src/composables/maskeditor/useCanvasTransform.ts (1)
  • useCanvasTransform (6-264)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: playwright-tests-chromium-sharded (4, 8)
  • GitHub Check: playwright-tests-chromium-sharded (1, 8)
  • GitHub Check: playwright-tests-chromium-sharded (3, 8)
  • GitHub Check: playwright-tests-chromium-sharded (5, 8)
  • GitHub Check: playwright-tests-chromium-sharded (7, 8)
  • GitHub Check: playwright-tests-chromium-sharded (8, 8)
  • GitHub Check: playwright-tests-chromium-sharded (6, 8)
  • GitHub Check: playwright-tests-chromium-sharded (2, 8)
  • GitHub Check: playwright-tests (chromium-0.5x)
  • GitHub Check: playwright-tests (mobile-chrome)
  • GitHub Check: playwright-tests (chromium-2x)
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (17)
src/composables/useCoreCommands.ts (2)

63-65: LGTM! Clean integration with mask editor state.

The imports are correctly added following the repository's pattern of keeping type imports separate from regular imports.


204-223: LGTM! Proper conditional routing for undo/redo commands.

The implementation correctly routes undo/redo operations to the mask editor's history when the mask editor dialog is open, and falls back to the workflow change tracker otherwise. The pattern is clean and maintains separation of concerns.

src/composables/maskeditor/useBrushDrawing.ts (2)

1-1: LGTM! Proper WebGPU types reference.

The triple-slash directive correctly enables WebGPU type definitions for this file.


237-357: LGTM! Race condition guard properly implemented.

The isRecreatingTextures guard addresses the race condition concern from the previous review by preventing concurrent texture recreation. The implementation properly:

  1. Checks all preconditions including the guard flag
  2. Destroys old textures before creating new ones (addressing memory pressure concerns)
  3. Handles both pending data upload and canvas fallback scenarios
  4. Recreates readback buffers with correct dimensions
  5. Cleans up flags in a finally block ensuring proper state reset even on error

The fallback to updateGPUFromCanvas() when pending data is null is reasonable, though it assumes canvas state is current.

src/components/maskeditor/dialog/TopBarHeader.vue (2)

38-102: LGTM! Clean UI implementation with proper visual separation.

The four new transformation buttons (rotate left/right, mirror horizontal/vertical) are well-integrated with:

  • Consistent styling using iconButtonClass
  • Clear SVG icons for each action
  • Proper tooltips using i18n keys
  • Visual separators (dividers) between control groups for better UX

161-191: LGTM! Error handling properly implemented.

The transformation handlers correctly implement try-catch error handling as requested in the previous review. Each handler:

  • Awaits the async transformation operation
  • Logs errors to console with clear context
  • Prevents unhandled promise rejections

This addresses the past review comment about adding error handling to transformation handlers.

src/composables/maskeditor/useCanvasHistory.ts (4)

4-9: Well-structured interface for three-layer state.

The CanvasState interface cleanly captures all three canvas layers (mask, rgb, img) with appropriate union type supporting both ImageData and ImageBitmap. This enables efficient history management for rotation operations that produce ImageBitmap instances.


29-75: LGTM: Initialization logic correctly extended to three layers.

The function properly validates all three canvas contexts and their dimensions before capturing state. The requestAnimationFrame retry pattern handles async canvas initialization gracefully.


106-119: Verify the "all-or-nothing" requirement for provided data is intentional.

The condition if (providedMaskData && providedRgbData && providedImgData) requires all three data parameters to be provided together, otherwise fresh data is captured from all canvases. This ensures consistency but callers must supply all three or none.

This design is correct for the current use case (transforms always produce all three), but consider adding a comment documenting this requirement.


166-177: Good memory management for ImageBitmap resources.

The cleanupState function properly checks instanceof ImageBitmap before calling close(), ensuring GPU-backed resources are released. The clearStates function correctly iterates all states for cleanup before clearing the array.

src/stores/maskEditorStore.ts (2)

226-232: GPU state reset is complete and consistent.

All five GPU-related refs are properly reset to their initial values, ensuring clean state when the mask editor is reset.


279-284: GPU texture signals properly exposed for cross-module coordination.

The exported refs enable useCanvasTransform to signal texture recreation needs and provide data, while useBrushDrawing can watch these signals to perform the actual GPU texture recreation. This decoupled design is appropriate.

src/composables/maskeditor/useCanvasTransform.ts (5)

61-103: Mirror algorithm is correct.

The coordinate transformations for mirroring are correct:

  • Horizontal: (x,y) → (width-1-x, y)
  • Vertical: (x,y) → (x, height-1-y)

Dimensions remain unchanged, and the index calculation correctly uses width.


108-115: Premultiplication implementation is correct.

Standard premultiplied alpha calculation: R' = R * (A/255), etc. The in-place mutation is intentional for performance.


177-221: Rotation workflow is well-structured.

The function correctly:

  1. Validates all canvas/context dependencies
  2. Captures original dimensions before transformation
  3. Rotates all three layers consistently
  4. Swaps canvas dimensions to match rotated data
  5. Applies rotated ImageData to canvases
  6. Conditionally recreates GPU textures
  7. Saves state to history for undo/redo support

The async/await pattern with recreateGPUTextures ensures GPU operations complete before history save.


226-258: Mirror workflow correctly preserves dimensions.

The function follows the same pattern as rotateAllLayers but correctly omits dimension swapping since mirroring doesn't change canvas size. GPU texture recreation and history save are handled appropriately.


260-263: Minimal API surface exposed.

Only the two public operations are exported, keeping helper functions (rotateCanvas, mirrorCanvas, premultiplyData, recreateGPUTextures) as private implementation details. This follows the guideline to minimize exported surface area.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/composables/maskeditor/useCanvasTransform.ts (1)

160-165: Remove commented-out code.

Commented code should not remain in production. Either enable this defensive check or remove it entirely.

🔎 Option 1: Enable the check (recommended)
-   /*
-   if (maskData.buffer instanceof SharedArrayBuffer || rgbData.buffer instanceof SharedArrayBuffer) {
-     console.error('[useCanvasTransform] SharedArrayBuffer detected, WebGPU writeTexture will fail')
-     return
-   }
-   */
+   if (maskData.buffer instanceof SharedArrayBuffer || rgbData.buffer instanceof SharedArrayBuffer) {
+     console.error('[useCanvasTransform] SharedArrayBuffer detected, WebGPU writeTexture will fail')
+     return
+   }
🔎 Option 2: Remove commented code
-   /*
-   if (maskData.buffer instanceof SharedArrayBuffer || rgbData.buffer instanceof SharedArrayBuffer) {
-     console.error('[useCanvasTransform] SharedArrayBuffer detected, WebGPU writeTexture will fail')
-     return
-   }
-   */
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2bcbe39 and 7f5ffae.

📒 Files selected for processing (2)
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
🧰 Additional context used
📓 Path-based instructions (11)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
**/**/use[A-Z]*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the pattern useXyz.ts

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize the surface area (exported values) of each module and composable

Files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
🧠 Learnings (8)
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Take advantage of `TypedArray` `subarray` when appropriate

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
  • src/composables/maskeditor/useCanvasHistory.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (14)
src/composables/maskeditor/useCanvasTransform.ts (8)

1-8: LGTM: Clean composable structure.

The composable setup follows proper conventions with the store access at the top level.


12-56: Rotation logic is mathematically correct.

The coordinate transformations are accurate:

  • Clockwise 90°: (x,y) → (height-1-y, x)
  • Counter-clockwise 90°: (x,y) → (y, width-1-x)

The destination index calculation correctly uses height as the new row width since dimensions are swapped.

Per coding guidelines, prefer function declarations over function expressions for pure functions. However, since these are internal helpers with consistent patterns throughout the file, this is acceptable.


61-103: Mirror logic is correct.

The pixel mirroring transformations are accurate:

  • Horizontal: (x,y) → (width-1-x, y)
  • Vertical: (x,y) → (x, height-1-y)

The implementation maintains dimensions correctly and copies RGBA values properly.


108-115: Premultiplication logic is correct for GPU upload.

Alpha premultiplication is properly applied in-place. The division by 255 and multiplication correctly converts straight alpha to premultiplied alpha format required by GPU pipelines.


121-133: Context validation is properly implemented.

The guard clause correctly validates all required resources including maskCtx and rgbCtx, addressing the previous concern about non-null assertions.


183-227: Rotation flow is well-structured.

The method correctly:

  1. Validates all required canvases and contexts
  2. Captures original dimensions before transformation
  3. Rotates all three layers consistently
  4. Swaps canvas dimensions appropriately
  5. Applies rotated data back to canvases
  6. Triggers GPU texture recreation when needed
  7. Saves state to history for undo/redo support

232-264: Mirror flow correctly preserves dimensions.

Unlike rotation, mirroring maintains the original dimensions while transforming pixel data. The implementation correctly handles GPU texture updates (data changes, not dimensions) and history recording.


266-269: Minimal public API surface.

Only rotateAllLayers and mirrorAllLayers are exported, keeping internal helpers private. This aligns with the coding guideline to minimize the surface area of each module.

src/composables/maskeditor/useCanvasHistory.ts (6)

4-9: Well-defined state interface.

The CanvasState interface clearly documents the three-layer structure and supports both ImageData (for direct pixel manipulation) and ImageBitmap (for efficient storage/rendering).


77-132: Three-layer state management is correct.

The saveState function properly:

  1. Validates all required contexts and canvases
  2. Handles both provided data and fresh captures
  3. Prunes redo history when new state is saved
  4. Maintains max history size with proper cleanup

134-144: Simplified undo/redo with early returns.

The refactored undo and redo functions use clean early returns instead of alert dialogs, improving UX and code clarity.


174-188: Layer restoration handles both ImageBitmap and ImageData.

The forEach loop correctly distinguishes between ImageBitmap (requires clearRect + drawImage) and ImageData (uses putImageData). This supports efficient storage while maintaining full restoration capability.


190-194: Proper ImageBitmap cleanup prevents memory leaks.

The cleanupState helper correctly calls .close() on ImageBitmap instances to release GPU resources. This aligns with the coding guideline to clean up subscriptions and resources.


196-201: clearStates properly cleans up all history.

Using forEach(cleanupState) ensures all ImageBitmap resources are released before clearing the array, preventing memory leaks.

trsommer
trsommer previously approved these changes Jan 4, 2026
Copy link
Collaborator

@trsommer trsommer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works as described. Only thing I can see is that rotation and undo/redo buttons are very similar in design. That could lead to some confusion

@brucew4yn3rp
Copy link
Collaborator Author

brucew4yn3rp commented Jan 4, 2026

Thank you @trsommer. Just updated the rotate buttons with a different SVG for ease of interpretation.

image

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f5ffae and 1b03bd0.

📒 Files selected for processing (1)
  • src/components/maskeditor/dialog/TopBarHeader.vue
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3.5+ with TypeScript in .vue files, exclusively using Composition API with <script setup lang="ts"> syntax
Use Tailwind 4 for styling in Vue components; avoid <style> blocks
Name Vue components using PascalCase (e.g., MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer computed() over ref with watch when deriving values
Prefer useModel over separately defining prop and emit for two-way binding
Use vue-i18n in composition API for string literals; place new translation entries in src/locales/en/main.json
Use cn() utility function from @/utils/tailwindUtil for merging Tailwind class names; do not use :class="[]" syntax
Do not use the dark: Tailwind variant; use semantic values from the style.css theme instead (e.g., bg-node-component-surface)
Do not use !important or the ! important prefix for Tailwind classes; find and correct interfering !important classes instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
🧠 Learnings (18)
📚 Learning: 2025-12-11T03:55:57.926Z
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Implement proper error handling in code

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Implement proper error handling

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Leverage VueUse functions for performance-enhancing styles in Vue components

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use defineExpose only for imperative operations (such as form.validate(), modal.open())

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint-and-format
  • GitHub Check: setup
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (2)
src/components/maskeditor/dialog/TopBarHeader.vue (2)

134-134: LGTM! Proper composition API usage.

The import and instantiation of useCanvasTransform follows the established pattern used for useCanvasTools.

Also applies to: 143-143


38-105: LGTM! Clean implementation of transform UI controls.

The rotate and mirror buttons are well-integrated, following the existing patterns for undo/redo buttons. The visual separators provide clear grouping, and the inline SVG icons are consistent with the component's style. All required i18n keys (maskEditor.rotateLeft, maskEditor.rotateRight, maskEditor.mirrorHorizontal, maskEditor.mirrorVertical) are present in the translation files.

Note: A past review comment suggested adding keyboard shortcuts. Per the PR description, keyboard shortcuts for these transform actions were added in src/extensions/core/maskEditor.ts, so that concern has been addressed.

@DrJKL DrJKL added the Design Used to request Product feedback on design decisions label Jan 6, 2026
@brucew4yn3rp
Copy link
Collaborator Author

Thank you for catching some of the improvements and the unnecessary ternary, @DrJKL. Made the changes you mentioned but unfortunately don't think we can consolidate the mask, rgb, and img ImageData | ImageBitmap.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/maskeditor/dialog/TopBarHeader.vue (1)

12-36: Inconsistent icon fill classes between undo and redo buttons.

The undo button (line 14) uses fill-current while the redo button (line 29) uses fill-[var(--input-text)]. This inconsistency could cause visual differences between the two icons. Consider using the same fill class for both.

🔧 Suggested fix
          <svg
            viewBox="0 0 15 15"
-            class="h-6.25 w-6.25 pointer-events-none fill-current"
+            class="h-6.25 w-6.25 pointer-events-none fill-[var(--input-text)]"
          >

Or alternatively, update the redo icon to use fill-current for consistency.

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4d6331 and 9de5a39.

📒 Files selected for processing (5)
  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
  • src/extensions/core/maskeditor.ts
  • src/locales/en/main.json
🧰 Additional context used
📓 Path-based instructions (14)
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

src/**/*.vue: Use Vue 3 Single File Components (SFCs) with Composition API only
Use <script setup lang="ts"> for component logic in Vue SFCs
Avoid <style> blocks in Vue components - use Tailwind 4 styling instead
Use vue-i18n for all string literals in Vue components - place translation entries in src/locales/en/main.json
Use Tailwind utility classes instead of dark: variant - use semantic values from style.css theme (e.g., bg-node-component-surface)
Use cn() utility from @/utils/tailwindUtil for merging Tailwind class names instead of :class="[]" or hardcoding
Never use !important or ! Tailwind prefix - fix interfering classes instead
Use Tailwind fraction utilities instead of arbitrary percentage values (e.g., w-4/5 instead of w-[80%])
Use TypeScript Vue 3.5 style default prop declaration with reactive props destructuring - avoid withDefaults or runtime props
Prefer defineModel over separately defining a prop and emit for v-model bindings
Define slots via template usage, not via defineSlots
Use same-name shorthand for slot prop bindings (e.g., :isExpanded instead of :is-expanded="isExpanded")
Do not import Vue macros unnecessarily
Avoid new usage of PrimeVue components
Use Tailwind's plurals system via i18n instead of hardcoding ...

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements instead of inline type in mixed imports
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, 80-character width
Sort and group imports by plugin, run pnpm format before committing
Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue
Write code that is expressive and self-documenting - avoid unnecessary comments
Do not add or retain redundant comments - clean as you go
Avoid mutable state - prefer immutability and assignment at point of declaration
Watch out for Code Smells and refactor to avoid them

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Name Vue components in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
src/**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,vue}: Use ref for reactive state, computed() for derived values, and watch/watchEffect for side effects in Composition API
Avoid using ref with watch if a computed would suffice - minimize refs and derived state
Use provide/inject for dependency injection only when simpler alternatives (Store or shared composable) won't work
Leverage VueUse functions for performance-enhancing composables
Use VueUse function for useI18n in composition API for string literals

Files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Use es-toolkit for utility functions
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones

Files:

  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/composables/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables as useXyz.ts (e.g., useForm.ts)

Files:

  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional
Minimize nesting (if statements, for loops, etc.)
Use function declarations instead of function expressions when possible

Files:

  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
🧠 Learnings (30)
📚 Learning: 2025-12-11T03:55:57.926Z
Learnt from: simula-r
Repo: Comfy-Org/ComfyUI_frontend PR: 7252
File: src/renderer/extensions/vueNodes/components/ImagePreview.vue:151-158
Timestamp: 2025-12-11T03:55:57.926Z
Learning: In src/renderer/extensions/vueNodes/components/ImagePreview.vue and LGraphNode.vue, keyboard navigation for image galleries should respond to node-level focus (via keyEvent injection from LGraphNode), not require focus within the image preview wrapper itself. This allows users to navigate the gallery with arrow keys immediately when the node is focused/selected.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Implement proper error handling

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/extensions/core/maskeditor.ts
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,vue} : Leverage VueUse functions for performance-enhancing composables

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use defineExpose only for imperative operations (such as form.validate(), modal.open())

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,vue} : Use VueUse function for useI18n in composition API for string literals

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2026-01-08T02:26:18.357Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7893
File: src/components/button/IconGroup.vue:5-6
Timestamp: 2026-01-08T02:26:18.357Z
Learning: In components that use the cn utility from '@/utils/tailwindUtil' with tailwind-merge, rely on the behavior that conflicting Tailwind classes are resolved by keeping the last one. For example, cn('base-classes bg-default', propClass) will have any conflicting background class from propClass override bg-default. This additive pattern is intentional and aligns with the shadcn-ui convention; ensure you document or review expectations accordingly in Vue components.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.

Applied to files:

  • src/components/maskeditor/dialog/TopBarHeader.vue
📚 Learning: 2026-01-06T19:17:12.355Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:12.355Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.ts
  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.ts
  • src/extensions/core/maskeditor.ts
  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.

Applied to files:

  • src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead

Applied to files:

  • src/extensions/core/maskeditor.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Take advantage of `TypedArray` `subarray` when appropriate

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Do not add or retain redundant comments - clean as you go

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
📚 Learning: 2025-12-05T06:11:09.383Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7177
File: src/platform/assets/components/UploadModelFooter.vue:72-78
Timestamp: 2025-12-05T06:11:09.383Z
Learning: For the ComfyUI_frontend repository, avoid suggesting comments that would be redundant when the code is already self-explanatory through descriptive naming (e.g., filenames, prop names, aria-labels). The project prefers clean code without unnecessary documentation comments.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.ts
🧬 Code graph analysis (1)
src/extensions/core/maskeditor.ts (1)
src/composables/maskeditor/useCanvasTransform.ts (1)
  • useCanvasTransform (6-359)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint-and-format
  • GitHub Check: setup
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (16)
src/locales/en/main.json (1)

977-980: LGTM!

The new localization keys follow the existing naming conventions and are appropriately placed within the maskEditor section. Based on learnings, other locale files are auto-generated on release, so only these English entries are required.

src/composables/maskeditor/useCanvasHistory.ts (5)

4-9: LGTM!

The CanvasState interface provides clear typing for the three-layer state structure. Using a union type ImageData | ImageBitmap correctly accommodates both state capture methods.


29-75: LGTM!

The saveInitialState function properly validates all three canvases and their contexts before capturing state. The requestAnimationFrame retry pattern handles async canvas initialization gracefully.


77-132: LGTM!

The saveState function correctly handles both provided data (from transformations) and captured data paths. The all-or-nothing check on line 106 ensures consistency when external data is passed. Memory cleanup via cleanupState on pruned states prevents memory leaks.


146-186: LGTM!

The restoreState function properly handles dimension changes during rotation undo/redo by resizing all canvases before rendering. The dual handling of ImageBitmap (via drawImage) and ImageData (via putImageData) is correct, and the loop pattern reduces code duplication.


188-199: LGTM!

Proper memory management with ImageBitmap.close() for all three layers. This prevents GPU memory leaks during extended editing sessions.

src/components/maskeditor/dialog/TopBarHeader.vue (2)

40-103: LGTM!

The new rotate and mirror buttons are well-implemented with proper i18n tooltips and consistent styling. The SVG icons are appropriately sized and use pointer-events-none to prevent interaction issues.


163-193: LGTM!

The async transform handlers properly use try/catch for error handling. While errors are only logged to console, the underlying transform functions provide detailed error information. Consider adding user-facing error notifications in a future iteration for better UX.

src/extensions/core/maskeditor.ts (1)

114-149: LGTM!

The new extension commands follow the established pattern and properly guard against execution when the mask editor is closed. The async/await usage is correct, and error handling is delegated to the underlying transform functions.

src/composables/maskeditor/useCanvasTransform.ts (7)

61-103: LGTM!

The mirror logic correctly handles both horizontal (X-axis flip) and vertical (Y-axis flip) operations. Since dimensions don't change, the stride calculation remains the original width.


108-115: LGTM!

The premultiplication logic is correct for WebGPU texture uploads. Using Math.round() prevents floating-point artifacts in the color values.


184-228: LGTM!

The rotateClockwise method correctly orchestrates the full transformation workflow: validation, rotation of all three layers, dimension swap, GPU texture recreation (when active), and history recording.


233-351: LGTM!

The remaining transform methods (rotateCounterclockwise, mirrorHorizontal, mirrorVertical) follow a consistent pattern and correctly handle their respective transformations. Mirror operations appropriately preserve canvas dimensions while rotation operations swap width and height.


353-358: LGTM!

The composable exposes a clean, focused API with only the four transform operations. This follows the guideline to minimize the surface area of composables.


121-179: The imgCanvas layer is intentionally excluded from GPU texture recreation because it does not participate in GPU rendering. The brush drawing system only maintains GPU textures for the mask and RGB layers (see useBrushDrawing.ts lines 63-64, 502-525). The imgCanvas serves solely as the base image for CPU-side composition in useMaskEditorSaver when exporting the final result; it is never accessed during GPU brush rendering operations.


12-56: Rotation coordinate calculation is correct.

The destination index calculation on line 45 properly handles the coordinate transformation for 90° rotations. After rotation, the new stride correctly uses the original height value, and this works correctly for non-square images since the dimensions are properly swapped (lines 209-214, 258-263). Both clockwise and counter-clockwise transformations are mathematically sound, and the accompanying mirror operations are also correctly implemented.

@DrJKL
Copy link
Contributor

DrJKL commented Jan 10, 2026

Looks like the unit tests need to be updated, otherwise should be good.

@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Jan 10, 2026
@brucew4yn3rp
Copy link
Collaborator Author

@DrJKL Updated useCanvasHistory.test.ts to track all three layers and added a useCanvasTransform.test.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/composables/maskeditor/useCanvasHistory.test.ts (1)

5-23: Replace any mocks with typed mocks and use vi.hoisted() for the store mock.

The current mocks use any type (mockImgCanvas, mockImgCtx, plus null as any), which violates the repo rule "Never use any type." Additionally, the shared mutable mockStore should use vi.hoisted() to keep module mocks contained and prevent global mutable state, following the established pattern throughout the codebase.

Proposed refactor
 import { beforeEach, describe, expect, it, vi } from 'vitest'
 import { nextTick } from 'vue'
 import { useCanvasHistory } from '@/composables/maskeditor/useCanvasHistory'

-let mockMaskCanvas: any
-let mockRgbCanvas: any
-let mockImgCanvas: any
-let mockMaskCtx: any
-let mockRgbCtx: any
-let mockImgCtx: any
+type MockCanvas = Pick<HTMLCanvasElement, 'width' | 'height'>
+type MockCtx = Pick<
+  CanvasRenderingContext2D,
+  'getImageData' | 'putImageData' | 'clearRect' | 'drawImage'
+>
+
+let mockMaskCanvas: MockCanvas
+let mockRgbCanvas: MockCanvas
+let mockImgCanvas: MockCanvas
+let mockMaskCtx: MockCtx
+let mockRgbCtx: MockCtx
+let mockImgCtx: MockCtx

-const mockStore = {
-  maskCanvas: null as any,
-  rgbCanvas: null as any,
-  imgCanvas: null as any,
-  maskCtx: null as any,
-  rgbCtx: null as any,
-  imgCtx: null as any
-}
+const { mockStore } = vi.hoisted(() => ({
+  mockStore: {
+    maskCanvas: null as MockCanvas | null,
+    rgbCanvas: null as MockCanvas | null,
+    imgCanvas: null as MockCanvas | null,
+    maskCtx: null as MockCtx | null,
+    rgbCtx: null as MockCtx | null,
+    imgCtx: null as MockCtx | null
+  }
+}))

 vi.mock('@/stores/maskEditorStore', () => ({
   useMaskEditorStore: vi.fn(() => mockStore)
 }))
🤖 Fix all issues with AI agents
In @src/composables/maskeditor/useCanvasHistory.test.ts:
- Around line 246-256: The test for no-op undo in useCanvasHistory only checks
mockMaskCtx.putImageData call count; instead clear relevant spies before
invoking the action and assert none of the canvas layer spies were called: call
mockMaskCtx.putImageData.mockClear(), mockRgbCtx.putImageData.mockClear(), and
mockImgCtx.drawImage.mockClear() (or their equivalents) before history.undo(),
then assert each spy not.toHaveBeenCalled(); apply the same change pattern to
the other no-op undo/redo tests referenced (the tests around lines 282-289,
313-323, 347-361) so all mask/rgb/img layers are verified untouched.

In @src/composables/maskeditor/useCanvasTransform.test.ts:
- Around line 145-151: The test for useCanvasTransform currently only checks
that mockCanvasHistory.saveState was called; update it to assert the saved
argument matches the actual transformed state by capturing the expected state
after rotateClockwise and verifying mockCanvasHistory.saveState was calledWith
that state (or use toMatchObject/toEqual against a snapshot). Locate
useCanvasTransform and the rotateClockwise invocation in the test, call or read
the transform's state/getState after rotation to build the expected object, and
replace the loose expect(mockCanvasHistory.saveState).toHaveBeenCalled() with an
assertion that the first argument equals the expected transformed state.
- Around line 31-33: Replace the top-level vi.mock call with a hoisted mock so
module mock state is explicit: wrap the existing
vi.mock('@/stores/maskEditorStore', () => ({ useMaskEditorStore: vi.fn(() =>
mockStore) })) inside vi.hoisted(() => { ... }); ensure any mutable mockStore is
declared/initialized in a scope compatible with the hoisted wrapper so the
useMaskEditorStore mock returns the intended mockStore instance.
- Around line 334-380: The mirrorVertical tests are missing the GPU texture
recreation assertions present in mirrorHorizontal; update the mirrorVertical
spec for useCanvasTransform.mirrorVertical to also verify GPU-related calls by
adding the same assertions used in the mirrorHorizontal test (e.g., assert the
mocked GPU/renderer texture recreation or upload methods were called after
mirrorVertical runs), referencing the same mocks used in the file
(mirrorVertical, mockMaskCanvas/mockRgbCanvas/mockImgCanvas,
mockMaskCtx/mockRgbCtx/mockImgCtx, mockCanvasHistory) so GPU texture recreation
is covered similarly to the horizontal case.
- Around line 507-547: Add stricter assertions for pendingGPUMaskData and
pendingGPURgbData after calling rotateClockwise/mirrorHorizontal: assert each is
an instance of Uint8ClampedArray, its .buffer is an ArrayBuffer (not a
SharedArrayBuffer), its .length equals expectedWidth * expectedHeight * 4 (use
mockMaskCanvas.width/height or swapped dims for rotation), and verify
premultiplied-alpha semantics by checking for all pixel indices that R <= A, G
<= A, and B <= A (sample a few indices or loop all pixels) to ensure color
channels are premultiplied by alpha.
- Around line 4-29: Replace all uses of the loose any mocks with explicit mock
types: define lightweight interfaces for the canvas and context objects (e.g.,
IMockCanvas, IMockContext) or reuse existing DOM/Canvas types, then type
mockMaskCanvas, mockRgbCanvas, mockImgCanvas, mockMaskCtx, mockRgbCtx,
mockImgCtx accordingly; for mockStore, use the Partial<StoreState> as StoreState
(or Partial<YourStoreType> as YourStoreType) pattern and assign
mockCanvasHistory to its typed canvasHistory property so tests keep strong
typing while still allowing partial mocks.
- Around line 237-272: The test only checks dimensions after
rotateCounterclockwise() but never verifies pixel differences vs
rotateClockwise(); update the test in useCanvasTransform.test.ts to (1) reuse
the asymmetric pattern creator (createAsymmetricImageData) and
mockMaskCtx.getImageData for a fresh copy before each rotation, (2) call
transform.rotateCounterclockwise() and capture the first
mockMaskCtx.putImageData call, then reset mocks, call
transform.rotateClockwise() and capture its putImageData result, and (3) assert
that the two resulting ImageData objects from mockMaskCtx.putImageData have
different pixel buffers (compare their .data contents) and that widths/heights
are swapped appropriately for each rotation to ensure direction matters. Use the
functions/mocks rotateCounterclockwise, rotateClockwise,
createAsymmetricImageData, mockMaskCtx.getImageData, and
mockMaskCtx.putImageData to locate where to change the test.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9de5a39 and 60e9bab.

📒 Files selected for processing (2)
  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Use es-toolkit for utility functions
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements instead of inline type in mixed imports
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, 80-character width
Sort and group imports by plugin, run pnpm format before committing
Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue
Write code that is expressive and self-documenting - avoid unnecessary comments
Do not add or retain redundant comments - clean as you go
Avoid mutable state - prefer immutability and assignment at point of declaration
Watch out for Code Smells and refactor to avoid them

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
src/composables/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables as useXyz.ts (e.g., useForm.ts)

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
+(tests-ui|src)/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src)/**/*.test.ts: Unit and component tests belong in tests-ui/ or src/**/*.test.ts using Vitest
Write tests for all changes, especially bug fixes to catch future regressions
Do not write tests dependent on non-behavioral features like utility classes or styles
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Leverage Vitest's utilities for mocking where possible
Keep module mocks contained - do not use global mutable state within test files; use vi.hoisted() if necessary
Use Vue Test Utils for Component testing and follow best practices for making components easy to test
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
src/**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,vue}: Use ref for reactive state, computed() for derived values, and watch/watchEffect for side effects in Composition API
Avoid using ref with watch if a computed would suffice - minimize refs and derived state
Use provide/inject for dependency injection only when simpler alternatives (Store or shared composable) won't work
Leverage VueUse functions for performance-enhancing composables
Use VueUse function for useI18n in composition API for string literals

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional
Minimize nesting (if statements, for loops, etc.)
Use function declarations instead of function expressions when possible

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts)

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts): Do not write change detector tests - avoid tests that only assert default values
Be parsimonious in testing - do not write redundant tests
Don't Mock What You Don't Own

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
🧠 Learnings (14)
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files; use `vi.hoisted()` if necessary

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Leverage Vitest's utilities for mocking where possible

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In TypeScript test files (e.g., any test under src), avoid duplicating interface/type definitions. Import real type definitions from the component modules under test and reference them directly, so there is a single source of truth and to prevent type drift. This improves maintainability and consistency across tests.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2026-01-09T02:07:54.558Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7898
File: src/composables/usePaste.test.ts:248-248
Timestamp: 2026-01-09T02:07:54.558Z
Learning: In test files (e.g., any .test.ts or .test.tsx under src/...), when you create mock objects that partially implement an interface (such as LGraphNode), prefer casting with as Partial<InterfaceType> as InterfaceType rather than as any or as unknown as InterfaceType. This makes the incomplete implementation explicit while preserving type safety, improving readability and maintainability of tests.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
  • src/composables/maskeditor/useCanvasHistory.test.ts
🧬 Code graph analysis (2)
src/composables/maskeditor/useCanvasTransform.test.ts (1)
src/composables/maskeditor/useCanvasTransform.ts (1)
  • useCanvasTransform (6-359)
src/composables/maskeditor/useCanvasHistory.test.ts (1)
src/composables/maskeditor/useCanvasHistory.ts (1)
  • useCanvasHistory (11-211)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test
  • GitHub Check: setup
  • GitHub Check: lint-and-format
  • GitHub Check: collect
🔇 Additional comments (3)
src/composables/maskeditor/useCanvasTransform.test.ts (2)

275-332: LGTM!

The mirrorHorizontal tests provide good behavioral coverage: dimension preservation, canvas API calls, history persistence, and GPU integration.


382-477: Good pixel-level verification.

These tests validate actual transformation correctness at the pixel level, which is valuable for catching bugs in the rotation/mirror algorithms. Consider adding similar tests for rotateCounterclockwise and mirrorVertical to complete coverage.

src/composables/maskeditor/useCanvasHistory.test.ts (1)

73-101: Good: tests now consistently assert 3-layer behavior (mask/rgb/img).

The added img mocks and assertions align with the new 3-layer history behavior (initial save, saveState, undo/redo, clearStates, and missing-context early returns).

Also applies to: 111-121, 150-165, 202-210, 230-244, 292-311, 378-393, 477-495

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @src/composables/maskeditor/useCanvasHistory.test.ts:
- Around line 5-19: Replace the broad `any` types on mockMaskCanvas,
mockRgbCanvas, mockImgCanvas and mockMaskCtx, mockRgbCtx, mockImgCtx with proper
DOM/Canvas types (e.g., HTMLCanvasElement | null for canvas variables and
CanvasRenderingContext2D | null for context variables) and type `mockStore` as a
partial of the real store shape (e.g., use `Partial<YourStoreInterface>` or
`Partial<typeof realStore>` then cast to the expected type using the `as
Partial<...> as ...` pattern) so tests use strict TypeScript types instead of
`any`; update references in this test file (useCanvasHistory.test.ts) to match
those typed symbols.

In @src/composables/maskeditor/useCanvasTransform.test.ts:
- Line 27: The tgpuRoot test variable is typed as any which violates guidelines;
change its type to unknown (e.g., replace the declaration of tgpuRoot from any
to unknown) since the tests only check its truthiness and the concrete shape
isn’t used, ensuring stricter type safety without affecting the mock usage.
- Around line 65-100: The test global mocks for ImageData and ImageBitmap use
forbidden `as any` casts; instead remove `as any` and either cast via `as
unknown as typeof globalThis.ImageData` / `as unknown as typeof
globalThis.ImageBitmap` or add a module/global declaration to augment the global
types and assign the classes directly to `globalThis.ImageData` and
`globalThis.ImageBitmap`; update the assignments for the ImageData and
ImageBitmap mocks (the mock classes and their constructors) to use one of those
safe casts or proper global augmentation so the mocks satisfy TypeScript without
`as any`.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60e9bab and e8b0938.

📒 Files selected for processing (2)
  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Use es-toolkit for utility functions
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements instead of inline type in mixed imports
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, 80-character width
Sort and group imports by plugin, run pnpm format before committing
Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue
Write code that is expressive and self-documenting - avoid unnecessary comments
Do not add or retain redundant comments - clean as you go
Avoid mutable state - prefer immutability and assignment at point of declaration
Watch out for Code Smells and refactor to avoid them

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/composables/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables as useXyz.ts (e.g., useForm.ts)

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src)/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src)/**/*.test.ts: Unit and component tests belong in tests-ui/ or src/**/*.test.ts using Vitest
Write tests for all changes, especially bug fixes to catch future regressions
Do not write tests dependent on non-behavioral features like utility classes or styles
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Leverage Vitest's utilities for mocking where possible
Keep module mocks contained - do not use global mutable state within test files; use vi.hoisted() if necessary
Use Vue Test Utils for Component testing and follow best practices for making components easy to test
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,vue}: Use ref for reactive state, computed() for derived values, and watch/watchEffect for side effects in Composition API
Avoid using ref with watch if a computed would suffice - minimize refs and derived state
Use provide/inject for dependency injection only when simpler alternatives (Store or shared composable) won't work
Leverage VueUse functions for performance-enhancing composables
Use VueUse function for useI18n in composition API for string literals

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional
Minimize nesting (if statements, for loops, etc.)
Use function declarations instead of function expressions when possible

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts)

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts): Do not write change detector tests - avoid tests that only assert default values
Be parsimonious in testing - do not write redundant tests
Don't Mock What You Don't Own

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
🧠 Learnings (24)
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files; use `vi.hoisted()` if necessary

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-09T02:07:54.558Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7898
File: src/composables/usePaste.test.ts:248-248
Timestamp: 2026-01-09T02:07:54.558Z
Learning: In test files (e.g., any .test.ts or .test.tsx under src/...), when you create mock objects that partially implement an interface (such as LGraphNode), prefer casting with as Partial<InterfaceType> as InterfaceType rather than as any or as unknown as InterfaceType. This makes the incomplete implementation explicit while preserving type safety, improving readability and maintainability of tests.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Be parsimonious in testing - do not write redundant tests

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Do not write change detector tests - avoid tests that only assert default values

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Don't Mock What You Don't Own

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Leverage Vitest's utilities for mocking where possible

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In TypeScript test files (e.g., any test under src), avoid duplicating interface/type definitions. Import real type definitions from the component modules under test and reference them directly, so there is a single source of truth and to prevent type drift. This improves maintainability and consistency across tests.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `any` type - use proper TypeScript types

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Use Vue Test Utils for Component testing and follow best practices for making components easy to test

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
🧬 Code graph analysis (2)
src/composables/maskeditor/useCanvasHistory.test.ts (1)
src/composables/maskeditor/useCanvasHistory.ts (1)
  • useCanvasHistory (11-211)
src/composables/maskeditor/useCanvasTransform.test.ts (1)
src/composables/maskeditor/useCanvasTransform.ts (1)
  • useCanvasTransform (6-359)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: playwright-tests-chromium-sharded (7, 8)
  • GitHub Check: playwright-tests-chromium-sharded (8, 8)
  • GitHub Check: playwright-tests-chromium-sharded (1, 8)
  • GitHub Check: playwright-tests-chromium-sharded (3, 8)
  • GitHub Check: playwright-tests-chromium-sharded (5, 8)
  • GitHub Check: playwright-tests-chromium-sharded (6, 8)
  • GitHub Check: playwright-tests-chromium-sharded (2, 8)
  • GitHub Check: playwright-tests-chromium-sharded (4, 8)
  • GitHub Check: playwright-tests (chromium-2x)
  • GitHub Check: playwright-tests (chromium-0.5x)
  • GitHub Check: playwright-tests (mobile-chrome)
🔇 Additional comments (3)
src/composables/maskeditor/useCanvasTransform.test.ts (1)

179-716: Excellent test coverage and structure!

The test suite provides comprehensive behavioral coverage:

  • Rotation tests validate dimension swapping, correct data handling, history persistence, and distinct results for clockwise vs counterclockwise rotations
  • Mirroring tests verify dimension preservation and correct transformations
  • Pixel-level tests (lines 501-596) are particularly valuable—they validate actual pixel manipulations using 2x2 test patterns with distinct colors, ensuring transformations are correct at the data level
  • Error handling tests verify graceful handling of missing canvases/contexts
  • GPU integration tests (lines 626-716) thoroughly validate texture recreation flags, dimension handling, ArrayBuffer backing, premultiplied alpha constraints, and inactive GPU behavior

The asymmetric pattern test (lines 323-380) is a clever approach to verify that clockwise and counterclockwise rotations produce different results, catching potential bugs where both operations might use the same logic.

Tests follow best practices: they validate actual behavior rather than just mocking, cover both happy paths and edge cases, and ensure proper integration with the GPU subsystem.

Based on learnings: Write tests for all changes, especially bug fixes to catch future regressions.

src/composables/maskeditor/useCanvasHistory.test.ts (2)

73-100: Excellent three-layer test coverage.

The img layer integration is consistently applied across all test scenarios:

  • Initialization checks all three contexts (Line 118)
  • State saving validates all three layers (Lines 157-163, 209-210)
  • Undo/redo operations verify all three contexts (Lines 241, 253-254, 259, 310, 316)
  • Cleanup paths include the img layer (Lines 402-403, 408, 503)

The mock setup for imgCtx and imgCanvas mirrors the existing mask/rgb structure, ensuring uniform test behavior across all layers.

Also applies to: 118-118, 157-163, 209-210, 220-221, 241-241, 253-254, 259-259, 310-310, 316-316, 402-403, 408-408, 503-503


246-260: Improved boundary condition tests.

The updated boundary tests properly verify that undo/redo operations:

  • Clear previous mock calls before testing boundaries
  • Verify that putImageData is not called when no states are available
  • Test all three contexts consistently

This aligns with the PR objective to remove alert-based feedback and rely on early returns, ensuring global undo/redo shortcuts are properly restricted when the Mask Editor is at history boundaries.

Also applies to: 280-297, 321-335, 359-377

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @src/composables/maskeditor/useCanvasHistory.test.ts:
- Around line 5-30: Replace the module-level mutable mock variables
(mockMaskCanvas, mockRgbCanvas, mockImgCanvas, mockMaskCtx, mockRgbCtx,
mockImgCtx and the mockStore object) with a hoisted container created via
vi.hoisted() (e.g., const mockRefs = vi.hoisted(() => ({ maskCanvas: null,
rgbCanvas: null, imgCanvas: null, maskCtx: null, rgbCtx: null, imgCtx: null
}))). Update tests to read/write mockRefs.maskCtx, mockRefs.maskCanvas, etc.,
instead of the top-level variables so each test run gets isolated mock state and
avoids cross-test pollution while preserving the same MaskEditorStoreState
shape.
- Around line 70-106: Replace the use of "as unknown as" with the explicit
partial-cast pattern for the mock objects; update mockMaskCtx, mockRgbCtx,
mockImgCtx to use "as Partial<CanvasRenderingContext2D> as
CanvasRenderingContext2D" and update mockMaskCanvas, mockRgbCanvas,
mockImgCanvas to use "as Partial<HTMLCanvasElement> as HTMLCanvasElement" so the
tests clearly express these are partial implementations while satisfying the
strict types.

In @src/composables/maskeditor/useCanvasTransform.test.ts:
- Around line 283-322: The test only asserts that clockwise vs counterclockwise
rotations differ but doesn't verify correctness; update or add explicit
pixel-based assertions for useCanvasTransform's rotateCounterclockwise and
rotateClockwise by using a small deterministic pattern (e.g., 2x2) returned from
mockMaskCtx.getImageData, then call transform.rotateCounterclockwise() (and
separately rotateClockwise()) and assert exact RGBA values at specific indices
in the ImageData passed to mockMaskCtx.putImageData (reference the functions
useCanvasTransform, rotateCounterclockwise, rotateClockwise and the mocks
mockMaskCtx/mockMaskCanvas) to ensure the rotations map source pixels to the
expected destination indices.
- Around line 346-354: Add three tests to the mirrorVertical suite: (1) a GPU
texture recreation test that sets mockStore.tgpuRoot (or equivalent) before
calling useCanvasTransform().mirrorVertical() and then asserts
mockStore.gpuTexturesNeedRecreation is true and mockStore.gpuTextureWidth/Height
match the new canvas dimensions; (2) a pixel-level verification that sets
mockMaskCanvas.width/height to 2, stubs mockMaskCtx.getImageData to return a
known 2x2 ImageData pattern, calls mirrorVertical(), and inspects the first
argument passed to mockMaskCtx.putImageData to assert pixels were flipped
vertically (check appropriate indices in result.data); and (3) an error-handling
test mirroring the pattern used in rotateClockwise tests to ensure
mirrorVertical throws or handles invalid state (use the same setup used in
rotateClockwise error test and assert the expected error/logging behavior).
Ensure all tests call useCanvasTransform() and reference mirrorVertical() so
they target the correct function.
- Around line 71-86: The test polyfill constructor for the ImageData replacement
uses non-null assertions on width and height (dataOrWidth, width, height) which
bypass type safety; replace those `!` assertions by adding an explicit runtime
guard or TypeScript overloads: check at the start of the constructor whether
dataOrWidth is a Uint8ClampedArray or a number, and if number-branch ensure
width and height are present (throw a clear error if missing) or define
constructor overloads so width/height are required in that signature; update
uses in the Uint8ClampedArray branch to read width/height only after the guard
so no `!` is needed, keeping the exported object cast as the ImageData polyfill.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8b0938 and 85a6863.

📒 Files selected for processing (2)
  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Use es-toolkit for utility functions
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements instead of inline type in mixed imports
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, 80-character width
Sort and group imports by plugin, run pnpm format before committing
Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue
Write code that is expressive and self-documenting - avoid unnecessary comments
Do not add or retain redundant comments - clean as you go
Avoid mutable state - prefer immutability and assignment at point of declaration
Watch out for Code Smells and refactor to avoid them

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/composables/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables as useXyz.ts (e.g., useForm.ts)

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src)/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src)/**/*.test.ts: Unit and component tests belong in tests-ui/ or src/**/*.test.ts using Vitest
Write tests for all changes, especially bug fixes to catch future regressions
Do not write tests dependent on non-behavioral features like utility classes or styles
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Leverage Vitest's utilities for mocking where possible
Keep module mocks contained - do not use global mutable state within test files; use vi.hoisted() if necessary
Use Vue Test Utils for Component testing and follow best practices for making components easy to test
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,vue}: Use ref for reactive state, computed() for derived values, and watch/watchEffect for side effects in Composition API
Avoid using ref with watch if a computed would suffice - minimize refs and derived state
Use provide/inject for dependency injection only when simpler alternatives (Store or shared composable) won't work
Leverage VueUse functions for performance-enhancing composables
Use VueUse function for useI18n in composition API for string literals

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional
Minimize nesting (if statements, for loops, etc.)
Use function declarations instead of function expressions when possible

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts)

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts): Do not write change detector tests - avoid tests that only assert default values
Be parsimonious in testing - do not write redundant tests
Don't Mock What You Don't Own

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
🧠 Learnings (26)
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files; use `vi.hoisted()` if necessary

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-09T02:07:54.558Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7898
File: src/composables/usePaste.test.ts:248-248
Timestamp: 2026-01-09T02:07:54.558Z
Learning: In test files (e.g., any .test.ts or .test.tsx under src/...), when you create mock objects that partially implement an interface (such as LGraphNode), prefer casting with as Partial<InterfaceType> as InterfaceType rather than as any or as unknown as InterfaceType. This makes the incomplete implementation explicit while preserving type safety, improving readability and maintainability of tests.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Don't Mock What You Don't Own

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In TypeScript test files (e.g., any test under src), avoid duplicating interface/type definitions. Import real type definitions from the component modules under test and reference them directly, so there is a single source of truth and to prevent type drift. This improves maintainability and consistency across tests.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Leverage Vitest's utilities for mocking where possible

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to browser_tests/**/*.spec.ts : Follow Playwright best practices for E2E testing

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Do not write change detector tests - avoid tests that only assert default values

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Be parsimonious in testing - do not write redundant tests

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `any` type - use proper TypeScript types

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Use Vue Test Utils for Component testing and follow best practices for making components easy to test

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{ts,tsx} : Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
🧬 Code graph analysis (2)
src/composables/maskeditor/useCanvasHistory.test.ts (1)
src/composables/maskeditor/useCanvasHistory.ts (1)
  • useCanvasHistory (11-211)
src/composables/maskeditor/useCanvasTransform.test.ts (1)
src/composables/maskeditor/useCanvasTransform.ts (1)
  • useCanvasTransform (6-359)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test
  • GitHub Check: lint-and-format
  • GitHub Check: setup
  • GitHub Check: collect
🔇 Additional comments (9)
src/composables/maskeditor/useCanvasHistory.test.ts (6)

36-47: LGTM!

The ImageBitmap polyfill pattern is appropriate for test environments that lack native browser API support.


117-166: LGTM!

The initialization tests properly verify all three contexts (mask, rgb, img) are captured, and correctly test the deferred initialization behavior when canvas or context is not ready.


168-246: LGTM!

The saveState tests comprehensively cover the three-layer capture behavior, redo state clearing, maxStates limit enforcement, and guard conditions for missing contexts.


248-316: LGTM!

The undo tests properly verify restoration across all three layers and correctly test the boundary conditions (no undo available, multiple undos, preventing undo beyond first state).


318-396: LGTM!

The redo tests mirror the undo tests appropriately, verifying three-layer restoration and boundary behavior.


531-583: LGTM!

The edge case tests provide good coverage for stress scenarios (rapid saves, maxStates boundary, undo/redo cycling) and graceful handling of invalid states (zero-sized canvas).

src/composables/maskeditor/useCanvasTransform.test.ts (3)

1-34: LGTM! Strong TypeScript foundation for test mocks.

The interface definitions provide excellent type safety for the mock structures, and the use of unknown for tgpuRoot (line 27) demonstrates proper type safety while still allowing truthiness checks.


36-62: LGTM! Proper use of vi.hoisted() for module mocking.

The hoisted mock setup follows best practices for keeping module mocks contained and avoiding global mutable state.


110-176: LGTM! Comprehensive test setup.

The beforeEach properly resets all mock state and initializes the three canvas layers with appropriate test data.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/composables/maskeditor/useCanvasHistory.test.ts (1)

623-636: Unnecessary guard for mockRefs.maskCanvas.

The if (mockRefs.maskCanvas) guard at line 624 is unnecessary since beforeEach always initializes mockRefs.maskCanvas before each test runs. The guard adds slight confusion about when this could be null.

♻️ Suggested simplification
     it('should handle zero-sized canvas', () => {
-      if (mockRefs.maskCanvas) {
-        mockRefs.maskCanvas = {
-          width: 0,
-          height: 0
-        } as Partial<HTMLCanvasElement> as HTMLCanvasElement
-      }
+      mockRefs.maskCanvas = {
+        width: 0,
+        height: 0
+      } as Partial<HTMLCanvasElement> as HTMLCanvasElement

       const history = useCanvasHistory()

       history.saveInitialState()

       expect(window.requestAnimationFrame).toHaveBeenCalled()
     })
🤖 Fix all issues with AI agents
In @src/composables/maskeditor/useCanvasTransform.test.ts:
- Around line 278-337: The test "should correctly rotate pixels clockwise at
pixel level" is duplicated elsewhere in the "pixel-level transformations"
describe block; remove the redundant copy so only one comprehensive pixel-level
rotation test remains. Locate the duplicate by the test title "should correctly
rotate pixels clockwise at pixel level" (and the other occurrence in the
"pixel-level transformations" block) and delete one of them (prefer keeping the
version with clearer color naming and more comprehensive assertions) to avoid
redundant coverage.
- Around line 608-622: Add an assertion to the GPU integration test to also
verify pendingGPURgbData is created with the expected size after rotation: in
the 'should set GPU recreation flags for rotation' test where you call
useCanvasTransform() and await rotateClockwise(), assert that
mockStore.pendingGPURgbData exists and its length equals
mockStore.gpuTextureWidth * mockStore.gpuTextureHeight * 4 (or specifically 50 *
100 * 4 given the mocked dimensions), similar to the existing check for
pendingGPUMaskData; update the expectations around mockStore.pendingGPURgbData
alongside pendingGPUMaskData to ensure both buffers are validated.
- Around line 459-478: Add a pixel-level test for mirrorHorizontal analogous to
the mirrorVertical tests: create a test that draws known pixel data on
mockMaskCanvas (e.g., distinct left/right pixel colors), call
useCanvasTransform().mirrorHorizontal(), then read back canvas pixel data and
assert pixels have been horizontally flipped (left pixels now on right and vice
versa). Also include a variant that sets mockStore.tgpuRoot to simulate GPU
active and assert gpuTexturesNeedRecreation and gpuTextureWidth/Height are set
correctly after the flip; reference useCanvasTransform, mirrorHorizontal,
mockMaskCanvas, and mockStore in the assertions.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85a6863 and 3eb3223.

📒 Files selected for processing (2)
  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Use es-toolkit for utility functions
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements instead of inline type in mixed imports
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, 80-character width
Sort and group imports by plugin, run pnpm format before committing
Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue
Write code that is expressive and self-documenting - avoid unnecessary comments
Do not add or retain redundant comments - clean as you go
Avoid mutable state - prefer immutability and assignment at point of declaration
Watch out for Code Smells and refactor to avoid them

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/composables/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables as useXyz.ts (e.g., useForm.ts)

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src)/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src)/**/*.test.ts: Unit and component tests belong in tests-ui/ or src/**/*.test.ts using Vitest
Write tests for all changes, especially bug fixes to catch future regressions
Do not write tests dependent on non-behavioral features like utility classes or styles
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Leverage Vitest's utilities for mocking where possible
Keep module mocks contained - do not use global mutable state within test files; use vi.hoisted() if necessary
Use Vue Test Utils for Component testing and follow best practices for making components easy to test
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,vue}: Use ref for reactive state, computed() for derived values, and watch/watchEffect for side effects in Composition API
Avoid using ref with watch if a computed would suffice - minimize refs and derived state
Use provide/inject for dependency injection only when simpler alternatives (Store or shared composable) won't work
Leverage VueUse functions for performance-enhancing composables
Use VueUse function for useI18n in composition API for string literals

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional
Minimize nesting (if statements, for loops, etc.)
Use function declarations instead of function expressions when possible

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts)

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts): Do not write change detector tests - avoid tests that only assert default values
Be parsimonious in testing - do not write redundant tests
Don't Mock What You Don't Own

Files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
🧠 Learnings (28)
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files; use `vi.hoisted()` if necessary

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Don't Mock What You Don't Own

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Leverage Vitest's utilities for mocking where possible

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-09T02:07:54.558Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7898
File: src/composables/usePaste.test.ts:248-248
Timestamp: 2026-01-09T02:07:54.558Z
Learning: In test files (e.g., any .test.ts or .test.tsx under src/...), when you create mock objects that partially implement an interface (such as LGraphNode), prefer casting with as Partial<InterfaceType> as InterfaceType rather than as any or as unknown as InterfaceType. This makes the incomplete implementation explicit while preserving type safety, improving readability and maintainability of tests.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In TypeScript test files (e.g., any test under src), avoid duplicating interface/type definitions. Import real type definitions from the component modules under test and reference them directly, so there is a single source of truth and to prevent type drift. This improves maintainability and consistency across tests.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `any` type - use proper TypeScript types

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to browser_tests/**/*.spec.ts : Follow Playwright best practices for E2E testing

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.ts : Favor pure functions, especially testable ones

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/maskeditor/useCanvasHistory.test.ts
  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Use Vue Test Utils for Component testing and follow best practices for making components easy to test

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{ts,tsx} : Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Aim for behavioral coverage of critical and new features in unit tests

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Be parsimonious in testing - do not write redundant tests

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
🧬 Code graph analysis (2)
src/composables/maskeditor/useCanvasHistory.test.ts (1)
src/composables/maskeditor/useCanvasHistory.ts (1)
  • useCanvasHistory (11-211)
src/composables/maskeditor/useCanvasTransform.test.ts (1)
src/composables/maskeditor/useCanvasTransform.ts (1)
  • useCanvasTransform (6-359)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test
  • GitHub Check: lint-and-format
  • GitHub Check: collect
  • GitHub Check: setup
🔇 Additional comments (10)
src/composables/maskeditor/useCanvasTransform.test.ts (5)

1-35: LGTM!

The mock interfaces are well-typed and provide a clear contract for the test mocks. Using local interfaces for partial mock types is appropriate here since these are test-specific shapes that don't need to match the full implementation types.


36-62: LGTM!

Good use of vi.hoisted() to create isolated mock state, preventing test pollution. The mock structure properly includes all GPU-related properties needed for testing the transform operations.


64-112: LGTM!

The global mocks for ImageData and ImageBitmap correctly handle the constructor overloads and use the as unknown as typeof pattern rather than as any, aligning with the coding guidelines.


122-188: LGTM!

The beforeEach setup properly initializes all three canvas layers with fresh mocks and resets the store state, ensuring test isolation.


340-457: LGTM!

Good test coverage for counterclockwise rotation. The asymmetric data test at lines 417-456 is particularly valuable for verifying that clockwise and counterclockwise rotations produce distinct results.

src/composables/maskeditor/useCanvasHistory.test.ts (5)

5-62: LGTM!

The MaskEditorStoreState interface and the getter/setter proxy pattern for mockStore provide clean, type-safe mock management. Using vi.hoisted() ensures proper isolation per the coding guidelines.


94-139: LGTM!

The beforeEach setup properly initializes all three canvas layers using the recommended as Partial<T> as T casting pattern. The requestAnimationFrame mock includes a safeguard against infinite recursion.


149-164: LGTM!

The initialization tests properly verify that getImageData is called on all three contexts (mask, rgb, img) when saving the initial state, reflecting the expanded three-layer model.


213-297: LGTM!

The saveState tests properly cover the three-layer model with assertions on all contexts. The use of vi.mocked() for mockClear() maintains type safety.


299-447: LGTM!

The undo/redo tests thoroughly verify that putImageData is called (or not called) on all three contexts in appropriate scenarios. The state transition tests are comprehensive.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @src/composables/maskeditor/useCanvasTransform.test.ts:
- Around line 610-638: Remove the redundant "pixel-level transformations"
describe block (including its nested it test) that duplicates the existing
rotateClockwise pixel tests; delete the block referencing
mockMaskCanvas/mockMaskCtx and the call to
useCanvasTransform().rotateClockwise(), leaving the earlier comprehensive
rotateClockwise suite intact and ensuring no other tests rely on the removed
fixtures.
- Around line 4-34: Replace the local mock interfaces (IMockCanvas,
IMockContext, IMockCanvasHistory, IMockStore) with the real store/type
definitions from the implementation: import the MaskEditorStore (or equivalent)
type from '@/stores/maskEditorStore' and create your test mocks as partials cast
back to the full type (e.g., mockStore = { ... } as Partial<MaskEditorStore> as
MaskEditorStore), and similarly use real Canvas/Context types from the
implementation instead of IMockCanvas/IMockContext to avoid type drift while
keeping only the needed mocked fields.
- Around line 640-655: Tests don't cover the SharedArrayBuffer rejection and
premultiply-alpha behavior in the GPU path; add two unit tests that call
useCanvasTransform().rotateClockwise(): (1) simulate a SharedArrayBuffer-backed
ImageData by making mockMaskCtx.getImageData return { data: new
Uint8ClampedArray(new SharedArrayBuffer(...)), width, height } with
mockStore.tgpuRoot set and assert console.error was called with a message
containing "SharedArrayBuffer" to verify the detection branch; (2) simulate a
1x1 ImageData with a semi-transparent pixel (e.g., [200,100,50,128]), set
mockStore.tgpuRoot and canvas size, call rotateClockwise and assert
mockStore.pendingGPUMaskData contains premultiplied RGB values (200*128/255
≈100, 100*128/255 ≈50, 50*128/255 ≈25) and alpha preserved, thereby exercising
the premultiplyData code path used in useCanvasTransform.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3eb3223 and 007a59c.

📒 Files selected for processing (1)
  • src/composables/maskeditor/useCanvasTransform.test.ts
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Use es-toolkit for utility functions
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements instead of inline type in mixed imports
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, 80-character width
Sort and group imports by plugin, run pnpm format before committing
Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue
Write code that is expressive and self-documenting - avoid unnecessary comments
Do not add or retain redundant comments - clean as you go
Avoid mutable state - prefer immutability and assignment at point of declaration
Watch out for Code Smells and refactor to avoid them

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/composables/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables as useXyz.ts (e.g., useForm.ts)

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src)/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src)/**/*.test.ts: Unit and component tests belong in tests-ui/ or src/**/*.test.ts using Vitest
Write tests for all changes, especially bug fixes to catch future regressions
Do not write tests dependent on non-behavioral features like utility classes or styles
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Leverage Vitest's utilities for mocking where possible
Keep module mocks contained - do not use global mutable state within test files; use vi.hoisted() if necessary
Use Vue Test Utils for Component testing and follow best practices for making components easy to test
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,vue}: Use ref for reactive state, computed() for derived values, and watch/watchEffect for side effects in Composition API
Avoid using ref with watch if a computed would suffice - minimize refs and derived state
Use provide/inject for dependency injection only when simpler alternatives (Store or shared composable) won't work
Leverage VueUse functions for performance-enhancing composables
Use VueUse function for useI18n in composition API for string literals

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional
Minimize nesting (if statements, for loops, etc.)
Use function declarations instead of function expressions when possible

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts)

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts): Do not write change detector tests - avoid tests that only assert default values
Be parsimonious in testing - do not write redundant tests
Don't Mock What You Don't Own

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
🧠 Learnings (27)
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files; use `vi.hoisted()` if necessary

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Leverage Vitest's utilities for mocking where possible

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Aim for behavioral coverage of critical and new features in unit tests

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-09T02:07:54.558Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7898
File: src/composables/usePaste.test.ts:248-248
Timestamp: 2026-01-09T02:07:54.558Z
Learning: In test files (e.g., any .test.ts or .test.tsx under src/...), when you create mock objects that partially implement an interface (such as LGraphNode), prefer casting with as Partial<InterfaceType> as InterfaceType rather than as any or as unknown as InterfaceType. This makes the incomplete implementation explicit while preserving type safety, improving readability and maintainability of tests.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Don't Mock What You Don't Own

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In TypeScript test files (e.g., any test under src), avoid duplicating interface/type definitions. Import real type definitions from the component modules under test and reference them directly, so there is a single source of truth and to prevent type drift. This improves maintainability and consistency across tests.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `any` type - use proper TypeScript types

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Use Vue Test Utils for Component testing and follow best practices for making components easy to test

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{ts,tsx} : Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to browser_tests/**/*.spec.ts : Follow Playwright best practices for E2E testing

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Be parsimonious in testing - do not write redundant tests

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
🧬 Code graph analysis (1)
src/composables/maskeditor/useCanvasTransform.test.ts (1)
src/composables/maskeditor/useCanvasTransform.ts (1)
  • useCanvasTransform (6-359)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: setup
  • GitHub Check: collect
🔇 Additional comments (1)
src/composables/maskeditor/useCanvasTransform.test.ts (1)

486-492: Minor formatting inconsistency.

Multiple assignments per line here differ from the style used elsewhere in the file (e.g., lines 284-303). The CI formatter (pnpm format) will normalize this, so no action required.

@brucew4yn3rp
Copy link
Collaborator Author

@DrJKL I think the tests are fine as they are now and they all seem to pass. Mind reviewing the real changes and approving if satisfactory?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/composables/maskeditor/useCanvasTransform.test.ts:
- Around line 282-305: The createTestPattern helper is duplicated across
multiple tests in useCanvasTransform.test.ts; extract the function named
createTestPattern out of the individual tests and place a single shared helper
at the describe('useCanvasTransform') block scope so all tests (those currently
containing createTestPattern at lines around 282, 360, 483, 548) call the common
createTestPattern(), preserving the same Uint8ClampedArray pixel layout (TL red,
TR green, BL blue, BR yellow) and returned ImageData shape.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 007a59c and 4d6d0d5.

📒 Files selected for processing (1)
  • src/composables/maskeditor/useCanvasTransform.test.ts
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Use es-toolkit for utility functions
Minimize the surface area (exported values) of each module and composable
Favor pure functions, especially testable ones

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements instead of inline type in mixed imports
Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, 80-character width
Sort and group imports by plugin, run pnpm format before committing
Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue
Write code that is expressive and self-documenting - avoid unnecessary comments
Do not add or retain redundant comments - clean as you go
Avoid mutable state - prefer immutability and assignment at point of declaration
Watch out for Code Smells and refactor to avoid them

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/composables/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables as useXyz.ts (e.g., useForm.ts)

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src)/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src)/**/*.test.ts: Unit and component tests belong in tests-ui/ or src/**/*.test.ts using Vitest
Write tests for all changes, especially bug fixes to catch future regressions
Do not write tests dependent on non-behavioral features like utility classes or styles
Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly
Leverage Vitest's utilities for mocking where possible
Keep module mocks contained - do not use global mutable state within test files; use vi.hoisted() if necessary
Use Vue Test Utils for Component testing and follow best practices for making components easy to test
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,vue}: Use ref for reactive state, computed() for derived values, and watch/watchEffect for side effects in Composition API
Avoid using ref with watch if a computed would suffice - minimize refs and derived state
Use provide/inject for dependency injection only when simpler alternatives (Store or shared composable) won't work
Leverage VueUse functions for performance-enhancing composables
Use VueUse function for useI18n in composition API for string literals

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional
Minimize nesting (if statements, for loops, etc.)
Use function declarations instead of function expressions when possible

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts)

📄 CodeRabbit inference engine (AGENTS.md)

+(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts): Do not write change detector tests - avoid tests that only assert default values
Be parsimonious in testing - do not write redundant tests
Don't Mock What You Don't Own

Files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
🧠 Learnings (31)
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Keep module mocks contained - do not use global mutable state within test files; use `vi.hoisted()` if necessary

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Leverage Vitest's utilities for mocking where possible

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Aim for behavioral coverage of critical and new features in unit tests

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-09T02:07:54.558Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7898
File: src/composables/usePaste.test.ts:248-248
Timestamp: 2026-01-09T02:07:54.558Z
Learning: In test files (e.g., any .test.ts or .test.tsx under src/...), when you create mock objects that partially implement an interface (such as LGraphNode), prefer casting with as Partial<InterfaceType> as InterfaceType rather than as any or as unknown as InterfaceType. This makes the incomplete implementation explicit while preserving type safety, improving readability and maintainability of tests.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Don't Mock What You Don't Own

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Do not write tests that just test the mocks - ensure tests fail when code behaves unexpectedly

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `as any` type assertions - fix the underlying type issue

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In TypeScript test files (e.g., any test under src), avoid duplicating interface/type definitions. Import real type definitions from the component modules under test and reference them directly, so there is a single source of truth and to prevent type drift. This improves maintainability and consistency across tests.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Never use `any` type - use proper TypeScript types

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Avoid using ts-expect-error; use proper TypeScript types instead

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Use Vue Test Utils for Component testing and follow best practices for making components easy to test

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{ts,tsx} : Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to browser_tests/**/*.spec.ts : Follow Playwright best practices for E2E testing

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Be parsimonious in testing - do not write redundant tests

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to src/**/*.ts : Favor pure functions, especially testable ones

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : When writing tests for subgraph-related code, always import from the barrel export at `@/lib/litegraph/src/litegraph` to avoid circular dependency issues

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src)/**/*.test.ts : Do not write tests dependent on non-behavioral features like utility classes or styles

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2026-01-10T00:24:17.662Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-10T00:24:17.662Z
Learning: Applies to +(tests-ui|src|browser_tests)/**/*.+(test.ts|spec.ts) : Do not write change detector tests - avoid tests that only assert default values

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/maskeditor/useCanvasTransform.test.ts
🧬 Code graph analysis (1)
src/composables/maskeditor/useCanvasTransform.test.ts (1)
src/composables/maskeditor/useCanvasTransform.ts (1)
  • useCanvasTransform (6-359)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: collect
  • GitHub Check: lint-and-format
  • GitHub Check: setup
  • GitHub Check: test
🔇 Additional comments (11)
src/composables/maskeditor/useCanvasTransform.test.ts (11)

1-3: LGTM: Clean imports

The import statements are properly structured and import only what's needed for the tests.


4-34: LGTM: Well-typed mock interfaces

The mock interfaces provide clear type definitions for the test doubles. Using ReturnType<typeof vi.fn> for mock functions is idiomatic for Vitest.


36-62: LGTM: Proper use of vi.hoisted() for module mocks

Correctly uses vi.hoisted() to create module-level mocks that are referenced in the vi.mock() call. This follows Vitest best practices and the coding guidelines for keeping module mocks contained.


64-99: LGTM: ImageData polyfill for test environment

The ImageData polyfill correctly implements both constructor overloads and is necessary for the Node.js test environment. The type assertion as unknown as typeof globalThis.ImageData is an acceptable escape hatch for globalThis augmentation in tests.


101-112: LGTM: ImageBitmap polyfill

Minimal but sufficient ImageBitmap polyfill for the test environment.


122-188: LGTM: Comprehensive test setup

The beforeEach block properly resets all mocks and creates fresh test fixtures for each test. The createMockImageData helper returns complete ImageData objects with all required properties.

Note: The type assertion at line 137 (as ImageData) is acceptable since the object implements all required properties. Alternatively, you could use as Partial<ImageData> as ImageData to make the intent explicit, but the current approach is fine.


190-338: LGTM: Comprehensive rotateClockwise test coverage

Excellent behavioral test suite covering:

  • Dimension transformations (width/height swap)
  • Canvas API interactions (getImageData, putImageData)
  • History recording with correct dimensions
  • Error handling when canvases unavailable
  • GPU integration (both active and inactive paths)
  • Pixel-level transformation correctness with distinct color patterns

The pixel-level test (lines 278-337) is particularly thorough, validating the exact transformation logic with a 2x2 grid of distinct colors. This ensures the rotation algorithm works correctly at the implementation level.

Based on learnings: "Aim for behavioral coverage of critical and new features in unit tests" ✅


340-457: LGTM: rotateCounterclockwise tests with differentiation validation

Good test coverage for counterclockwise rotation. The test at lines 417-456 that validates CCW produces different results than CW using asymmetric image data is particularly valuable—it proves both rotations work correctly and distinctly.


459-522: LGTM: mirrorHorizontal test coverage

Good test coverage validating that dimensions remain unchanged (unlike rotation), GPU integration works correctly, and pixel-level horizontal flipping is accurate.


524-620: LGTM: mirrorVertical test coverage including error handling

Comprehensive test coverage including dimension validation, GPU integration, pixel-level transformation, and error handling when canvases aren't ready.


622-682: LGTM: Thorough GPU integration testing

Excellent GPU integration tests that validate:

  • Recreation flags and dimension updates
  • Pending GPU data buffers created with correct size
  • Premultiplication of alpha values with precise mathematical validation

The premultiply alpha test (lines 638-681) is particularly thorough—it uses specific RGBA values and validates the exact mathematical transformation (RGB × alpha/255), ensuring GPU texture data is prepared correctly for WebGPU's premultiplied alpha format.

@DrJKL DrJKL merged commit 7bc6334 into Comfy-Org:main Jan 10, 2026
28 checks passed
@DrJKL
Copy link
Contributor

DrJKL commented Jan 10, 2026

Looks great, thanks!

@DrJKL
Copy link
Contributor

DrJKL commented Jan 10, 2026

@brucew4yn3rp How do you feel about coderabbit so far?

@brucew4yn3rp
Copy link
Collaborator Author

@DrJKL I think it's a useful tool to provide a first layer of review and help identify inefficiencies or potential nascent issues, but at the same time it almost tries too hard and implementing some of its suggestions would either not be practical or not work outright.

@DrJKL
Copy link
Contributor

DrJKL commented Jan 10, 2026

@brucew4yn3rp If you have any specific awkward suggestions to call out, we can try to edit the AGENTS files to better guide it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Design Used to request Product feedback on design decisions size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants