diff --git a/.github/actions/setup-frontend/action.yml b/.github/actions/setup-frontend/action.yml
new file mode 100644
index 000000000..3ebc12eb3
--- /dev/null
+++ b/.github/actions/setup-frontend/action.yml
@@ -0,0 +1,67 @@
+name: Setup Frontend
+description: 'Setup ComfyUI frontend development environment'
+inputs:
+ extra_server_params:
+ description: 'Additional parameters to pass to ComfyUI server'
+ required: false
+ default: ''
+runs:
+ using: 'composite'
+ steps:
+ - name: Checkout ComfyUI
+ uses: actions/checkout@v4
+ with:
+ repository: 'comfyanonymous/ComfyUI'
+ path: 'ComfyUI'
+
+ - name: Checkout ComfyUI_frontend
+ uses: actions/checkout@v4
+ with:
+ repository: 'Comfy-Org/ComfyUI_frontend'
+ path: 'ComfyUI_frontend'
+
+ - name: Copy ComfyUI_devtools from frontend repo
+ shell: bash
+ run: |
+ mkdir -p ComfyUI/custom_nodes/ComfyUI_devtools
+ cp -r ComfyUI_frontend/tools/devtools/* ComfyUI/custom_nodes/ComfyUI_devtools/
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 'lts/*'
+ cache: 'pnpm'
+ cache-dependency-path: 'ComfyUI_frontend/pnpm-lock.yaml'
+
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.10'
+
+ - name: Install Python requirements
+ shell: bash
+ working-directory: ComfyUI
+ run: |
+ python -m pip install --upgrade pip
+ pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
+ pip install -r requirements.txt
+ pip install wait-for-it
+
+ - name: Build & Install ComfyUI_frontend
+ shell: bash
+ working-directory: ComfyUI_frontend
+ run: |
+ pnpm install --frozen-lockfile
+ pnpm build
+
+ - name: Start ComfyUI server
+ shell: bash
+ working-directory: ComfyUI
+ run: |
+ python main.py --cpu --multi-user --front-end-root ../ComfyUI_frontend/dist ${{ inputs.extra_server_params }} &
+ wait-for-it --service 127.0.0.1:8188 -t 600
\ No newline at end of file
diff --git a/.github/workflows/backport.yaml b/.github/workflows/auto-backport.yaml
similarity index 99%
rename from .github/workflows/backport.yaml
rename to .github/workflows/auto-backport.yaml
index 178bd4ee8..20eadc0c9 100644
--- a/.github/workflows/backport.yaml
+++ b/.github/workflows/auto-backport.yaml
@@ -60,7 +60,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
fetch-depth: 0
diff --git a/.github/workflows/chromatic.yaml b/.github/workflows/chromatic.yaml
deleted file mode 100644
index 127186d68..000000000
--- a/.github/workflows/chromatic.yaml
+++ /dev/null
@@ -1,57 +0,0 @@
-name: 'Chromatic'
-
-# - [Automate Chromatic with GitHub Actions âĸ Chromatic docs]( https://www.chromatic.com/docs/github-actions/ )
-
-on:
- workflow_dispatch: # Allow manual triggering
- pull_request:
- branches: [main]
-
-jobs:
- chromatic-deployment:
- runs-on: ubuntu-latest
- # Only run for PRs from version-bump-* branches or manual triggers
- if: github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'version-bump-')
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Required for Chromatic baseline
-
- - name: Install pnpm
- uses: pnpm/action-setup@v4
- with:
- version: 10
-
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: '20'
- cache: 'pnpm'
-
-
- - name: Cache tool outputs
- uses: actions/cache@v4
- with:
- path: |
- .cache
- storybook-static
- tsconfig.tsbuildinfo
- key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }}
- restore-keys: |
- storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
- storybook-cache-${{ runner.os }}-
- storybook-tools-cache-${{ runner.os }}-
-
- - name: Install dependencies
- run: pnpm install --frozen-lockfile
-
- - name: Build Storybook and run Chromatic
- id: chromatic
- uses: chromaui/action@latest
- with:
- projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
- buildScriptName: build-storybook
- autoAcceptChanges: 'main' # Auto-accept changes on main branch
- exitOnceUploaded: true # Don't wait for UI tests to complete
-
diff --git a/.github/workflows/claude-pr-review.yml b/.github/workflows/claude-pr-review.yml
index d1eecafe3..08ad70727 100644
--- a/.github/workflows/claude-pr-review.yml
+++ b/.github/workflows/claude-pr-review.yml
@@ -29,11 +29,9 @@ jobs:
- name: Check if we should proceed
id: check-status
run: |
- # Get all check runs for this commit
- CHECK_RUNS=$(gh api repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs --jq '.check_runs[] | select(.name | test("lint-and-format|test|playwright-tests")) | {name, conclusion}')
-
- # Check if any required checks failed
- if echo "$CHECK_RUNS" | grep -q '"conclusion": "failure"'; then
+ CHECK_RUNS=$(gh api repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs --jq '.check_runs[] | select(.name | test("lint-and-format")) | {name, conclusion}')
+
+ if echo "$CHECK_RUNS" | grep -Eq '"conclusion": "(failure|cancelled|timed_out|action_required)"'; then
echo "Some CI checks failed - skipping Claude review"
echo "proceed=false" >> $GITHUB_OUTPUT
else
@@ -50,9 +48,10 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
fetch-depth: 0
+ ref: refs/pull/${{ github.event.pull_request.number }}/head
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -86,4 +85,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
- REPOSITORY: ${{ github.repository }}
\ No newline at end of file
+ REPOSITORY: ${{ github.repository }}
diff --git a/.github/workflows/dev-release.yaml b/.github/workflows/create-dev-pypi-package.yaml
similarity index 97%
rename from .github/workflows/dev-release.yaml
rename to .github/workflows/create-dev-pypi-package.yaml
index 0b45420c6..b592a8371 100644
--- a/.github/workflows/dev-release.yaml
+++ b/.github/workflows/create-dev-pypi-package.yaml
@@ -15,7 +15,7 @@ jobs:
version: ${{ steps.current_version.outputs.version }}
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
@@ -62,7 +62,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Download dist artifact
uses: actions/download-artifact@v4
with:
diff --git a/.github/workflows/create-release-candidate-branch.yaml b/.github/workflows/create-release-branch.yaml
similarity index 99%
rename from .github/workflows/create-release-candidate-branch.yaml
rename to .github/workflows/create-release-branch.yaml
index e3fcd9e2b..7891a845d 100644
--- a/.github/workflows/create-release-candidate-branch.yaml
+++ b/.github/workflows/create-release-branch.yaml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
fetch-depth: 0
token: ${{ secrets.PR_GH_TOKEN || secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release.yaml b/.github/workflows/create-release-draft.yaml
similarity index 100%
rename from .github/workflows/release.yaml
rename to .github/workflows/create-release-draft.yaml
diff --git a/.github/workflows/devtools-python.yaml b/.github/workflows/devtools-python-check.yaml
similarity index 93%
rename from .github/workflows/devtools-python.yaml
rename to .github/workflows/devtools-python-check.yaml
index 49ec4c0fe..f0893e99d 100644
--- a/.github/workflows/devtools-python.yaml
+++ b/.github/workflows/devtools-python-check.yaml
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v5
diff --git a/.github/workflows/lint-and-format.yaml b/.github/workflows/lint-and-format.yaml
index 3b6bf1538..d9904b0e0 100644
--- a/.github/workflows/lint-and-format.yaml
+++ b/.github/workflows/lint-and-format.yaml
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout PR
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.event.pull_request.head.ref }}
diff --git a/.github/workflows/pr-playwright-deploy.yaml b/.github/workflows/pr-playwright-deploy-forks.yaml
similarity index 99%
rename from .github/workflows/pr-playwright-deploy.yaml
rename to .github/workflows/pr-playwright-deploy-forks.yaml
index 19bb28253..660fee77f 100644
--- a/.github/workflows/pr-playwright-deploy.yaml
+++ b/.github/workflows/pr-playwright-deploy-forks.yaml
@@ -30,7 +30,7 @@ jobs:
echo "Is forked: ${{ github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name }}"
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Get PR Number
id: pr
diff --git a/.github/workflows/pr-storybook-comment.yaml b/.github/workflows/pr-storybook-comment.yaml
deleted file mode 100644
index 53691d826..000000000
--- a/.github/workflows/pr-storybook-comment.yaml
+++ /dev/null
@@ -1,126 +0,0 @@
-name: PR Storybook Comment
-
-on:
- workflow_run:
- workflows: ['Chromatic']
- types: [requested, completed]
-
-jobs:
- comment-storybook:
- runs-on: ubuntu-latest
- if: >-
- github.repository == 'Comfy-Org/ComfyUI_frontend'
- && github.event.workflow_run.event == 'pull_request'
- && startsWith(github.event.workflow_run.head_branch, 'version-bump-')
- permissions:
- pull-requests: write
- actions: read
- steps:
- - name: Get PR number
- id: pr
- uses: actions/github-script@v7
- with:
- script: |
- const { data: pullRequests } = await github.rest.pulls.list({
- owner: context.repo.owner,
- repo: context.repo.repo,
- state: 'open',
- head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`,
- });
-
- if (pullRequests.length === 0) {
- console.log('No open PR found for this branch');
- return null;
- }
-
- return pullRequests[0].number;
-
- - name: Log when no PR found
- if: steps.pr.outputs.result == 'null'
- run: |
- echo "â ī¸ No open PR found for branch: ${{ github.event.workflow_run.head_branch }}"
- echo "Workflow run ID: ${{ github.event.workflow_run.id }}"
- echo "Repository: ${{ github.event.workflow_run.repository.full_name }}"
- echo "Event: ${{ github.event.workflow_run.event }}"
-
- - name: Get workflow run details
- if: steps.pr.outputs.result != 'null' && github.event.action == 'completed'
- id: workflow-run
- uses: actions/github-script@v7
- with:
- script: |
- const run = await github.rest.actions.getWorkflowRun({
- owner: context.repo.owner,
- repo: context.repo.repo,
- run_id: context.payload.workflow_run.id,
- });
-
- return {
- conclusion: run.data.conclusion,
- html_url: run.data.html_url
- };
-
- - name: Get completion time
- id: completion-time
- run: echo "time=$(date -u '+%m/%d/%Y, %I:%M:%S %p')" >> $GITHUB_OUTPUT
-
- - name: Comment PR - Storybook Started
- if: steps.pr.outputs.result != 'null' && github.event.action == 'requested'
- uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0
- with:
- issue-number: ${{ steps.pr.outputs.result }}
- body-includes: ''
- comment-author: 'github-actions[bot]'
- edit-mode: replace
- body: |
-
- ## đ¨ Storybook Build Status
-
-
**Build is starting...**
-
- â° Started at: ${{ steps.completion-time.outputs.time }} UTC
-
- ### đ Building Storybook
- - đĻ Installing dependencies...
- - đ§ Building Storybook components...
- - đ¨ Running Chromatic visual tests...
-
- ---
- âąī¸ Please wait while the Storybook build is in progress...
-
- - name: Comment PR - Storybook Complete
- if: steps.pr.outputs.result != 'null' && github.event.action == 'completed'
- uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0
- with:
- issue-number: ${{ steps.pr.outputs.result }}
- body-includes: ''
- comment-author: 'github-actions[bot]'
- edit-mode: replace
- body: |
-
- ## đ¨ Storybook Build Status
-
- ${{
- fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && 'â
'
- || fromJSON(steps.workflow-run.outputs.result).conclusion == 'skipped' && 'âī¸'
- || fromJSON(steps.workflow-run.outputs.result).conclusion == 'cancelled' && 'đĢ'
- || 'â'
- }} **${{
- fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && 'Build completed successfully!'
- || fromJSON(steps.workflow-run.outputs.result).conclusion == 'skipped' && 'Build skipped.'
- || fromJSON(steps.workflow-run.outputs.result).conclusion == 'cancelled' && 'Build cancelled.'
- || 'Build failed!'
- }}**
-
- â° Completed at: ${{ steps.completion-time.outputs.time }} UTC
-
- ### đ Links
- - [đ View Workflow Run](${{ fromJSON(steps.workflow-run.outputs.result).html_url }})
-
- ---
- ${{
- fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && 'đ Your Storybook is ready for review!'
- || fromJSON(steps.workflow-run.outputs.result).conclusion == 'skipped' && 'âšī¸ Chromatic was skipped for this PR.'
- || fromJSON(steps.workflow-run.outputs.result).conclusion == 'cancelled' && 'âšī¸ The Chromatic run was cancelled.'
- || 'â ī¸ Please check the workflow logs for error details.'
- }}
diff --git a/.github/workflows/pr-storybook-deploy-forks.yaml b/.github/workflows/pr-storybook-deploy-forks.yaml
new file mode 100644
index 000000000..da27867c4
--- /dev/null
+++ b/.github/workflows/pr-storybook-deploy-forks.yaml
@@ -0,0 +1,90 @@
+name: PR Storybook Deploy (Forks)
+
+on:
+ workflow_run:
+ workflows: ['Storybook and Chromatic CI']
+ types: [requested, completed]
+
+env:
+ DATE_FORMAT: '+%m/%d/%Y, %I:%M:%S %p'
+
+jobs:
+ deploy-and-comment-forked-pr:
+ runs-on: ubuntu-latest
+ if: |
+ github.repository == 'Comfy-Org/ComfyUI_frontend' &&
+ github.event.workflow_run.event == 'pull_request' &&
+ github.event.workflow_run.head_repository != null &&
+ github.event.workflow_run.repository != null &&
+ github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name
+ permissions:
+ pull-requests: write
+ actions: read
+ steps:
+ - name: Log workflow trigger info
+ run: |
+ echo "Repository: ${{ github.repository }}"
+ echo "Event: ${{ github.event.workflow_run.event }}"
+ echo "Head repo: ${{ github.event.workflow_run.head_repository.full_name || 'null' }}"
+ echo "Base repo: ${{ github.event.workflow_run.repository.full_name || 'null' }}"
+ echo "Is forked: ${{ github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name }}"
+
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Get PR Number
+ id: pr
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const { data: prs } = await github.rest.pulls.list({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ state: 'open',
+ });
+
+ const pr = prs.find(p => p.head.sha === context.payload.workflow_run.head_sha);
+
+ if (!pr) {
+ console.log('No PR found for SHA:', context.payload.workflow_run.head_sha);
+ return null;
+ }
+
+ console.log(`Found PR #${pr.number} from fork: ${context.payload.workflow_run.head_repository.full_name}`);
+ return pr.number;
+
+ - name: Handle Storybook Start
+ if: steps.pr.outputs.result != 'null' && github.event.action == 'requested'
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ run: |
+ chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh
+ ./scripts/cicd/pr-storybook-deploy-and-comment.sh \
+ "${{ steps.pr.outputs.result }}" \
+ "${{ github.event.workflow_run.head_branch }}" \
+ "starting" \
+ "$(date -u '${{ env.DATE_FORMAT }}')"
+
+ - name: Download and Deploy Storybook
+ if: steps.pr.outputs.result != 'null' && github.event.action == 'completed' && github.event.workflow_run.conclusion == 'success'
+ uses: actions/download-artifact@v4
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ run-id: ${{ github.event.workflow_run.id }}
+ name: storybook-static
+ path: storybook-static
+
+ - name: Handle Storybook Completion
+ if: steps.pr.outputs.result != 'null' && github.event.action == 'completed'
+ env:
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+ GITHUB_TOKEN: ${{ github.token }}
+ WORKFLOW_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
+ WORKFLOW_URL: ${{ github.event.workflow_run.html_url }}
+ run: |
+ chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh
+ ./scripts/cicd/pr-storybook-deploy-and-comment.sh \
+ "${{ steps.pr.outputs.result }}" \
+ "${{ github.event.workflow_run.head_branch }}" \
+ "completed"
\ No newline at end of file
diff --git a/.github/workflows/storybook-and-chromatic-ci.yaml b/.github/workflows/storybook-and-chromatic-ci.yaml
new file mode 100644
index 000000000..bfac96530
--- /dev/null
+++ b/.github/workflows/storybook-and-chromatic-ci.yaml
@@ -0,0 +1,231 @@
+name: Storybook and Chromatic CI
+
+# - [Automate Chromatic with GitHub Actions âĸ Chromatic docs]( https://www.chromatic.com/docs/github-actions/ )
+
+on:
+ workflow_dispatch: # Allow manual triggering
+ pull_request:
+ branches: [main]
+
+jobs:
+ # Post starting comment for non-forked PRs
+ comment-on-pr-start:
+ runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false
+ permissions:
+ pull-requests: write
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Post starting comment
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ run: |
+ chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh
+ ./scripts/cicd/pr-storybook-deploy-and-comment.sh \
+ "${{ github.event.pull_request.number }}" \
+ "${{ github.head_ref }}" \
+ "starting" \
+ "$(date -u '+%m/%d/%Y, %I:%M:%S %p')"
+
+ # Build Storybook for all PRs (free Cloudflare deployment)
+ storybook-build:
+ runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request'
+ outputs:
+ conclusion: ${{ steps.job-status.outputs.conclusion }}
+ workflow-url: ${{ steps.workflow-url.outputs.url }}
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v5
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'pnpm'
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ storybook-static
+ tsconfig.tsbuildinfo
+ key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }}
+ restore-keys: |
+ storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
+ storybook-cache-${{ runner.os }}-
+ storybook-tools-cache-${{ runner.os }}-
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Build Storybook
+ run: pnpm build-storybook
+
+ - name: Set job status
+ id: job-status
+ if: always()
+ run: |
+ echo "conclusion=${{ job.status }}" >> $GITHUB_OUTPUT
+
+ - name: Get workflow URL
+ id: workflow-url
+ if: always()
+ run: |
+ echo "url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_OUTPUT
+
+ - name: Upload Storybook build
+ if: success() && github.event.pull_request.head.repo.fork == false
+ uses: actions/upload-artifact@v4
+ with:
+ name: storybook-static
+ path: storybook-static/
+ retention-days: 7
+
+ # Chromatic deployment only for version-bump-* branches or manual triggers
+ chromatic-deployment:
+ runs-on: ubuntu-latest
+ if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && startsWith(github.head_ref, 'version-bump-'))
+ outputs:
+ conclusion: ${{ steps.job-status.outputs.conclusion }}
+ workflow-url: ${{ steps.workflow-url.outputs.url }}
+ chromatic-build-url: ${{ steps.chromatic.outputs.buildUrl }}
+ chromatic-storybook-url: ${{ steps.chromatic.outputs.storybookUrl }}
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v5
+ with:
+ fetch-depth: 0 # Required for Chromatic baseline
+
+ - name: Install pnpm
+ uses: pnpm/action-setup@v4
+ with:
+ version: 10
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'pnpm'
+
+ - name: Cache tool outputs
+ uses: actions/cache@v4
+ with:
+ path: |
+ .cache
+ storybook-static
+ tsconfig.tsbuildinfo
+ key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }}
+ restore-keys: |
+ storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
+ storybook-cache-${{ runner.os }}-
+ storybook-tools-cache-${{ runner.os }}-
+
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Build Storybook and run Chromatic
+ id: chromatic
+ uses: chromaui/action@latest
+ with:
+ projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
+ buildScriptName: build-storybook
+ autoAcceptChanges: 'main' # Auto-accept changes on main branch
+ exitOnceUploaded: true # Don't wait for UI tests to complete
+ onlyChanged: true # Only capture changed stories
+
+ - name: Set job status
+ id: job-status
+ if: always()
+ run: |
+ echo "conclusion=${{ job.status }}" >> $GITHUB_OUTPUT
+
+ - name: Get workflow URL
+ id: workflow-url
+ if: always()
+ run: |
+ echo "url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_OUTPUT
+
+ # Deploy and comment for non-forked PRs only
+ deploy-and-comment:
+ needs: [storybook-build]
+ runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false && always()
+ permissions:
+ pull-requests: write
+ contents: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Download Storybook build
+ if: needs.storybook-build.outputs.conclusion == 'success'
+ uses: actions/download-artifact@v4
+ with:
+ name: storybook-static
+ path: storybook-static
+
+ - name: Make deployment script executable
+ run: chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh
+
+ - name: Deploy Storybook and comment on PR
+ env:
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+ GITHUB_TOKEN: ${{ github.token }}
+ WORKFLOW_CONCLUSION: ${{ needs.storybook-build.outputs.conclusion }}
+ WORKFLOW_URL: ${{ needs.storybook-build.outputs.workflow-url }}
+ run: |
+ ./scripts/cicd/pr-storybook-deploy-and-comment.sh \
+ "${{ github.event.pull_request.number }}" \
+ "${{ github.head_ref }}" \
+ "completed"
+
+ # Update comment with Chromatic URLs for version-bump branches
+ update-comment-with-chromatic:
+ needs: [chromatic-deployment, deploy-and-comment]
+ runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false && startsWith(github.head_ref, 'version-bump-') && needs.chromatic-deployment.outputs.chromatic-build-url != ''
+ permissions:
+ pull-requests: write
+ steps:
+ - name: Update comment with Chromatic URLs
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const buildUrl = '${{ needs.chromatic-deployment.outputs.chromatic-build-url }}';
+ const storybookUrl = '${{ needs.chromatic-deployment.outputs.chromatic-storybook-url }}';
+
+ // Find the existing Storybook comment
+ const { data: comments } = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: ${{ github.event.pull_request.number }}
+ });
+
+ const storybookComment = comments.find(comment =>
+ comment.body.includes('')
+ );
+
+ if (storybookComment && buildUrl && storybookUrl) {
+ // Append Chromatic info to existing comment
+ const updatedBody = storybookComment.body.replace(
+ /---\n(.*)$/s,
+ `---\n### đ¨ Chromatic Visual Tests\n- đ [View Chromatic Build](${buildUrl})\n- đ [View Chromatic Storybook](${storybookUrl})\n\n$1`
+ );
+
+ await github.rest.issues.updateComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ comment_id: storybookComment.id,
+ body: updatedBody
+ });
+ }
diff --git a/.github/workflows/test-ui.yaml b/.github/workflows/tests-ci.yaml
similarity index 98%
rename from .github/workflows/test-ui.yaml
rename to .github/workflows/tests-ci.yaml
index 640615d99..01b180b4a 100644
--- a/.github/workflows/test-ui.yaml
+++ b/.github/workflows/tests-ci.yaml
@@ -15,14 +15,14 @@ jobs:
playwright-version: ${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}
steps:
- name: Checkout ComfyUI
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: 'comfyanonymous/ComfyUI'
path: 'ComfyUI'
ref: master
- name: Checkout ComfyUI_frontend
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: 'Comfy-Org/ComfyUI_frontend'
path: 'ComfyUI_frontend'
@@ -250,7 +250,7 @@ jobs:
if: ${{ !cancelled() }}
steps:
- name: Checkout ComfyUI_frontend
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: 'Comfy-Org/ComfyUI_frontend'
path: 'ComfyUI_frontend'
@@ -306,7 +306,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Get start time
id: start-time
@@ -333,7 +333,7 @@ jobs:
contents: read
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Download all playwright reports
uses: actions/download-artifact@v4
diff --git a/.github/workflows/update-registry-types.yaml b/.github/workflows/update-comfy-registry-api-types.yaml
similarity index 98%
rename from .github/workflows/update-registry-types.yaml
rename to .github/workflows/update-comfy-registry-api-types.yaml
index c7d31d1d9..41a4db9ab 100644
--- a/.github/workflows/update-registry-types.yaml
+++ b/.github/workflows/update-comfy-registry-api-types.yaml
@@ -16,7 +16,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -50,7 +50,7 @@ jobs:
comfy-api-repo-${{ runner.os }}-
- name: Checkout comfy-api repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: Comfy-Org/comfy-api
path: comfy-api
diff --git a/.github/workflows/update-manager-types.yaml b/.github/workflows/update-comfyui-manager-api-types.yaml
similarity index 98%
rename from .github/workflows/update-manager-types.yaml
rename to .github/workflows/update-comfyui-manager-api-types.yaml
index de5b799da..7e307dfda 100644
--- a/.github/workflows/update-manager-types.yaml
+++ b/.github/workflows/update-comfyui-manager-api-types.yaml
@@ -17,7 +17,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -51,7 +51,7 @@ jobs:
comfyui-manager-repo-${{ runner.os }}-
- name: Checkout ComfyUI-Manager repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: Comfy-Org/ComfyUI-Manager
path: ComfyUI-Manager
diff --git a/.github/workflows/update-electron-types.yaml b/.github/workflows/update-electron-types.yaml
index 96f85f6b0..45d959b86 100644
--- a/.github/workflows/update-electron-types.yaml
+++ b/.github/workflows/update-electron-types.yaml
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v4
diff --git a/.github/workflows/i18n-custom-nodes.yaml b/.github/workflows/update-locales-for-given-custom-node-repository.yaml
similarity index 98%
rename from .github/workflows/i18n-custom-nodes.yaml
rename to .github/workflows/update-locales-for-given-custom-node-repository.yaml
index 959d01739..74d0267cf 100644
--- a/.github/workflows/i18n-custom-nodes.yaml
+++ b/.github/workflows/update-locales-for-given-custom-node-repository.yaml
@@ -22,13 +22,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout ComfyUI
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: comfyanonymous/ComfyUI
path: ComfyUI
ref: master
- name: Checkout ComfyUI_frontend
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: Comfy-Org/ComfyUI_frontend
path: ComfyUI_frontend
@@ -37,7 +37,7 @@ jobs:
mkdir -p ComfyUI/custom_nodes/ComfyUI_devtools
cp -r ComfyUI_frontend/tools/devtools/* ComfyUI/custom_nodes/ComfyUI_devtools/
- name: Checkout custom node repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
repository: ${{ inputs.owner }}/${{ inputs.repository }}
path: 'ComfyUI/custom_nodes/${{ inputs.repository }}'
diff --git a/.github/workflows/i18n.yaml b/.github/workflows/update-locales.yaml
similarity index 97%
rename from .github/workflows/i18n.yaml
rename to .github/workflows/update-locales.yaml
index 566a335b5..2871209a1 100644
--- a/.github/workflows/i18n.yaml
+++ b/.github/workflows/update-locales.yaml
@@ -14,7 +14,8 @@ jobs:
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository && startsWith(github.head_ref, 'version-bump-'))
runs-on: ubuntu-latest
steps:
- - uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
+ - name: Setup Frontend
+ uses: ./.github/actions/setup-frontend
- name: Cache tool outputs
uses: actions/cache@v4
diff --git a/.github/workflows/i18n-node-defs.yaml b/.github/workflows/update-node-definitions-locales.yaml
similarity index 95%
rename from .github/workflows/i18n-node-defs.yaml
rename to .github/workflows/update-node-definitions-locales.yaml
index d9105a4ac..71cb417d4 100644
--- a/.github/workflows/i18n-node-defs.yaml
+++ b/.github/workflows/update-node-definitions-locales.yaml
@@ -13,7 +13,8 @@ jobs:
update-locales:
runs-on: ubuntu-latest
steps:
- - uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
+ - name: Setup Frontend
+ uses: ./.github/actions/setup-frontend
- name: Install Playwright Browsers
run: pnpm exec playwright install chromium --with-deps
working-directory: ComfyUI_frontend
diff --git a/.github/workflows/test-browser-exp.yaml b/.github/workflows/update-playwright-expectations.yaml
similarity index 92%
rename from .github/workflows/test-browser-exp.yaml
rename to .github/workflows/update-playwright-expectations.yaml
index e174e89c3..4f643cad8 100644
--- a/.github/workflows/test-browser-exp.yaml
+++ b/.github/workflows/update-playwright-expectations.yaml
@@ -10,7 +10,10 @@ jobs:
runs-on: ubuntu-latest
if: github.event.label.name == 'New Browser Test Expectations'
steps:
- - uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
+ - name: Checkout workflow repo
+ uses: actions/checkout@v5
+ - name: Setup Frontend
+ uses: ./.github/actions/setup-frontend
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
diff --git a/.github/workflows/json-validate.yaml b/.github/workflows/validate-json.yaml
similarity index 86%
rename from .github/workflows/json-validate.yaml
rename to .github/workflows/validate-json.yaml
index a29499528..2986d23ed 100644
--- a/.github/workflows/json-validate.yaml
+++ b/.github/workflows/validate-json.yaml
@@ -10,6 +10,6 @@ jobs:
json-lint:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Validate JSON syntax
run: ./scripts/cicd/check-json.sh
diff --git a/.github/workflows/version-bump.yaml b/.github/workflows/version-bump.yaml
index 77021e5c7..4073729db 100644
--- a/.github/workflows/version-bump.yaml
+++ b/.github/workflows/version-bump.yaml
@@ -24,7 +24,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v4
diff --git a/.github/workflows/vitest.yaml b/.github/workflows/vitest-tests.yaml
similarity index 97%
rename from .github/workflows/vitest.yaml
rename to .github/workflows/vitest-tests.yaml
index cba1dbe05..ea49d4a62 100644
--- a/.github/workflows/vitest.yaml
+++ b/.github/workflows/vitest-tests.yaml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v4
diff --git a/.npmrc b/.npmrc
index ae90f7051..1b28e47ce 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1 +1,2 @@
ignore-workspace-root-check=true
+catalog-mode=prefer
diff --git a/browser_tests/README.md b/browser_tests/README.md
index 4954ba9fd..500d665c2 100644
--- a/browser_tests/README.md
+++ b/browser_tests/README.md
@@ -16,7 +16,7 @@ Without this flag, parallel tests will conflict and fail randomly.
### ComfyUI devtools
-ComfyUI_devtools is now included in this repository under `tools/devtools/`. During CI/CD, these files are automatically copied to the `custom_nodes` directory.
+ComfyUI_devtools is included in this repository under `tools/devtools/`. During CI/CD, these files are automatically copied to the `custom_nodes` directory.
_ComfyUI_devtools adds additional API endpoints and nodes to ComfyUI for browser testing._
For local development, copy the devtools files to your ComfyUI installation:
@@ -84,7 +84,7 @@ UI mode features:
- **Console/Network Tabs**: View logs and API calls at each step
- **Attachments Tab**: View all snapshots with expected and actual images
-
+
For CI or headless testing:
diff --git a/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-create-group-chromium-linux.png b/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-create-group-chromium-linux.png
index 0a7817cd9..d19e6a4b8 100644
Binary files a/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-create-group-chromium-linux.png and b/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-create-group-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-fit-to-contents-chromium-linux.png b/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-fit-to-contents-chromium-linux.png
index 955397d55..feb588707 100644
Binary files a/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-fit-to-contents-chromium-linux.png and b/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-fit-to-contents-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png b/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png
index 8fd456924..a61beb8fd 100644
Binary files a/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png and b/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png differ
diff --git a/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts-snapshots/zoomed-in-ctrl-shift-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts-snapshots/zoomed-in-ctrl-shift-chromium-linux.png
index e23bdb168..4cc6eb1a9 100644
Binary files a/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts-snapshots/zoomed-in-ctrl-shift-chromium-linux.png and b/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts-snapshots/zoomed-in-ctrl-shift-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-dragging-link-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-dragging-link-chromium-linux.png
index c4db539bc..9660dea43 100644
Binary files a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-dragging-link-chromium-linux.png and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-dragging-link-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-ctrl-alt-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-ctrl-alt-chromium-linux.png
index 685637384..541ca18a6 100644
Binary files a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-ctrl-alt-chromium-linux.png and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-ctrl-alt-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-reuses-origin-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-reuses-origin-chromium-linux.png
index 0f660f23e..838145eb4 100644
Binary files a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-reuses-origin-chromium-linux.png and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-reuses-origin-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-input-drag-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-input-drag-chromium-linux.png
index 22f5c69f4..59dd9288d 100644
Binary files a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-input-drag-chromium-linux.png and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-input-drag-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-output-shift-drag-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-output-shift-drag-chromium-linux.png
index 7eeef693d..99a372c0b 100644
Binary files a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-output-shift-drag-chromium-linux.png and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-output-shift-drag-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-shift-output-multi-link-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-shift-output-multi-link-chromium-linux.png
index 64d140449..a055bb525 100644
Binary files a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-shift-output-multi-link-chromium-linux.png and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-shift-output-multi-link-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-color-blue-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-color-blue-chromium-linux.png
index ceb84698c..a507a9ca2 100644
Binary files a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-color-blue-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-color-blue-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-dark-all-colors-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-dark-all-colors-chromium-linux.png
index 5997ea26e..8209a045c 100644
Binary files a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-dark-all-colors-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-dark-all-colors-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png
index 0df00782f..618b2d871 100644
Binary files a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-default-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-default-chromium-linux.png
index c61bcbc46..1c19eb714 100644
Binary files a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-default-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-default-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-active-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-active-chromium-linux.png
index 2bbaeaa64..4636050fd 100644
Binary files a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-active-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-active-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-inactive-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-inactive-chromium-linux.png
index 57bca67fa..b332c5f13 100644
Binary files a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-inactive-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-inactive-chromium-linux.png differ
diff --git a/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts-snapshots/vue-nodes-upload-widgets-chromium-linux.png b/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts-snapshots/vue-nodes-upload-widgets-chromium-linux.png
index ac5b685ca..f4624a45b 100644
Binary files a/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts-snapshots/vue-nodes-upload-widgets-chromium-linux.png and b/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts-snapshots/vue-nodes-upload-widgets-chromium-linux.png differ
diff --git a/package.json b/package.json
index bdfdc0378..ee0f556cf 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@comfyorg/comfyui-frontend",
"private": true,
- "version": "1.28.3",
+ "version": "1.28.4",
"type": "module",
"repository": "https://github.com/Comfy-Org/ComfyUI_frontend",
"homepage": "https://comfy.org",
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 0b9e0d06b..50bb8f97a 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -2,6 +2,114 @@ packages:
- apps/**
- packages/**
+catalog:
+ # Core frameworks
+ typescript: ^5.9.2
+ vue: ^3.5.13
+
+ # Build tools
+ '@nx/eslint': 21.4.1
+ '@nx/playwright': 21.4.1
+ '@nx/storybook': 21.4.1
+ '@nx/vite': 21.4.1
+ nx: 21.4.1
+ tsx: ^4.15.6
+ vite: ^5.4.19
+ '@vitejs/plugin-vue': ^5.1.4
+ 'vite-plugin-dts': ^4.5.4
+ vue-tsc: ^3.0.7
+
+ # Testing
+ 'happy-dom': ^15.11.0
+ jsdom: ^26.1.0
+ '@pinia/testing': ^0.1.5
+ '@playwright/test': ^1.52.0
+ '@vitest/coverage-v8': ^3.2.4
+ '@vitest/ui': ^3.0.0
+ vitest: ^3.2.4
+ '@vue/test-utils': ^2.4.6
+
+ # Linting & Formatting
+ '@eslint/js': ^9.35.0
+ eslint: ^9.34.0
+ 'eslint-config-prettier': ^10.1.8
+ 'eslint-plugin-prettier': ^5.5.4
+ 'eslint-plugin-storybook': ^9.1.6
+ 'eslint-plugin-unused-imports': ^4.2.0
+ 'eslint-plugin-vue': ^10.4.0
+ globals: ^15.9.0
+ '@intlify/eslint-plugin-vue-i18n': ^4.1.0
+ prettier: ^3.3.2
+ 'typescript-eslint': ^8.44.0
+ 'vue-eslint-parser': ^10.2.0
+
+ # Vue ecosystem
+ '@sentry/vue': ^8.48.0
+ '@vueuse/core': ^11.0.0
+ '@vueuse/integrations': ^13.9.0
+ 'vite-plugin-html': ^3.2.2
+ 'vite-plugin-vue-devtools': ^7.7.6
+ pinia: ^2.1.7
+ 'vue-i18n': ^9.14.3
+ 'vue-router': ^4.4.3
+ vuefire: ^3.2.1
+
+ # PrimeVue UI framework
+ '@primeuix/forms': 0.0.2
+ '@primeuix/styled': 0.3.2
+ '@primeuix/utils': ^0.3.2
+ '@primevue/core': ^4.2.5
+ '@primevue/forms': ^4.2.5
+ '@primevue/icons': 4.2.5
+ '@primevue/themes': ^4.2.5
+ primeicons: ^7.0.0
+ primevue: ^4.2.5
+
+ # Tailwind CSS and design
+ '@iconify/json': ^2.2.380
+ '@iconify-json/lucide': ^1.1.178
+ '@iconify/tailwind': ^1.1.3
+ '@tailwindcss/vite': ^4.1.12
+ tailwindcss: ^4.1.12
+ 'tailwindcss-primeui': ^0.6.1
+ 'tw-animate-css': ^1.3.8
+ 'unplugin-icons': ^0.22.0
+ 'unplugin-vue-components': ^0.28.0
+
+ # Storybook
+ '@storybook/addon-docs': ^9.1.1
+ storybook: ^9.1.6
+ '@storybook/vue3': ^9.1.1
+ '@storybook/vue3-vite': ^9.1.1
+
+ # Data and validation
+ algoliasearch: ^5.21.0
+ firebase: ^11.6.0
+ yjs: ^13.6.27
+ zod: ^3.23.8
+ 'zod-validation-error': ^3.3.0
+
+ # Dev tools
+ dotenv: ^16.4.5
+ husky: ^9.0.11
+ jiti: 2.4.2
+ knip: ^5.62.0
+ 'lint-staged': ^15.2.7
+
+ # Type definitions
+ '@types/fs-extra': ^11.0.4
+ '@types/jsdom': ^21.1.7
+ '@types/node': ^20.14.8
+ '@types/semver': ^7.7.0
+ '@types/three': ^0.169.0
+ 'vue-component-type-helpers': ^3.0.7
+ 'zod-to-json-schema': ^3.24.1
+
+ # i18n
+ '@alloc/quick-lru': ^5.2.0
+ '@lobehub/i18n-cli': ^1.25.1
+ '@trivago/prettier-plugin-sort-imports': ^5.2.0
+
ignoredBuiltDependencies:
- '@firebase/util'
- protobufjs
diff --git a/scripts/cicd/pr-storybook-deploy-and-comment.sh b/scripts/cicd/pr-storybook-deploy-and-comment.sh
new file mode 100755
index 000000000..a2a1d37e9
--- /dev/null
+++ b/scripts/cicd/pr-storybook-deploy-and-comment.sh
@@ -0,0 +1,247 @@
+#!/bin/bash
+set -e
+
+# Deploy Storybook to Cloudflare Pages and comment on PR
+# Usage: ./pr-storybook-deploy-and-comment.sh [start_time]
+
+# Input validation
+# Validate PR number is numeric
+case "$1" in
+ ''|*[!0-9]*)
+ echo "Error: PR_NUMBER must be numeric" >&2
+ exit 1
+ ;;
+esac
+PR_NUMBER="$1"
+
+# Sanitize and validate branch name (allow alphanumeric, dots, dashes, underscores, slashes)
+BRANCH_NAME=$(echo "$2" | sed 's/[^a-zA-Z0-9._/-]//g')
+if [ -z "$BRANCH_NAME" ]; then
+ echo "Error: Invalid or empty branch name" >&2
+ exit 1
+fi
+
+# Validate status parameter
+STATUS="${3:-completed}"
+case "$STATUS" in
+ starting|completed) ;;
+ *)
+ echo "Error: STATUS must be 'starting' or 'completed'" >&2
+ exit 1
+ ;;
+esac
+
+START_TIME="${4:-$(date -u '+%m/%d/%Y, %I:%M:%S %p')}"
+
+# Required environment variables
+: "${GITHUB_TOKEN:?GITHUB_TOKEN is required}"
+: "${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is required}"
+
+# Cloudflare variables only required for deployment
+if [ "$STATUS" = "completed" ]; then
+ : "${CLOUDFLARE_API_TOKEN:?CLOUDFLARE_API_TOKEN is required for deployment}"
+ : "${CLOUDFLARE_ACCOUNT_ID:?CLOUDFLARE_ACCOUNT_ID is required for deployment}"
+fi
+
+# Configuration
+COMMENT_MARKER=""
+
+# Install wrangler if not available (output to stderr for debugging)
+if ! command -v wrangler > /dev/null 2>&1; then
+ echo "Installing wrangler v4..." >&2
+ npm install -g wrangler@^4.0.0 >&2 || {
+ echo "Failed to install wrangler" >&2
+ echo "failed"
+ return
+ }
+fi
+
+# Deploy Storybook report, WARN: ensure inputs are sanitized before calling this function
+deploy_storybook() {
+ dir="$1"
+ branch="$2"
+
+ [ ! -d "$dir" ] && echo "failed" && return
+
+ project="comfy-storybook"
+
+ echo "Deploying Storybook to project $project on branch $branch..." >&2
+
+ # Try deployment up to 3 times
+ i=1
+ while [ $i -le 3 ]; do
+ echo "Deployment attempt $i of 3..." >&2
+ # Branch is already sanitized, use it directly
+ if output=$(wrangler pages deploy "$dir" \
+ --project-name="$project" \
+ --branch="$branch" 2>&1); then
+
+ # Extract URL from output (improved regex for valid URL characters)
+ url=$(echo "$output" | grep -oE 'https://[a-zA-Z0-9.-]+\.pages\.dev\S*' | head -1)
+ result="${url:-https://${branch}.${project}.pages.dev}"
+ echo "Success! URL: $result" >&2
+ echo "$result" # Only this goes to stdout for capture
+ return
+ else
+ echo "Deployment failed on attempt $i: $output" >&2
+ fi
+ [ $i -lt 3 ] && sleep 10
+ i=$((i + 1))
+ done
+
+ echo "failed"
+}
+
+# Post or update GitHub comment
+post_comment() {
+ body="$1"
+ temp_file=$(mktemp)
+ echo "$body" > "$temp_file"
+
+ if command -v gh > /dev/null 2>&1; then
+ # Find existing comment ID
+ existing=$(gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" \
+ --jq ".[] | select(.body | contains(\"$COMMENT_MARKER\")) | .id" | head -1)
+
+ if [ -n "$existing" ]; then
+ # Update specific comment by ID
+ gh api --method PATCH "repos/$GITHUB_REPOSITORY/issues/comments/$existing" \
+ --field body="$(cat "$temp_file")"
+ else
+ gh pr comment "$PR_NUMBER" --body-file "$temp_file"
+ fi
+ else
+ echo "GitHub CLI not available, outputting comment:"
+ cat "$temp_file"
+ fi
+
+ rm -f "$temp_file"
+}
+
+# Main execution
+if [ "$STATUS" = "starting" ]; then
+ # Check if this is a version-bump branch
+ IS_VERSION_BUMP="false"
+ if echo "$BRANCH_NAME" | grep -q "^version-bump-"; then
+ IS_VERSION_BUMP="true"
+ fi
+
+ # Post starting comment with appropriate message
+ if [ "$IS_VERSION_BUMP" = "true" ]; then
+ comment=$(cat < **Build is starting...**
+
+â° Started at: $START_TIME UTC
+
+### đ Building Storybook
+- đĻ Installing dependencies...
+- đ§ Building Storybook components...
+- đ¨ Running Chromatic visual tests...
+
+---
+âąī¸ Please wait while the Storybook build is in progress...
+EOF
+)
+ else
+ comment=$(cat < **Build is starting...**
+
+â° Started at: $START_TIME UTC
+
+### đ Building Storybook
+- đĻ Installing dependencies...
+- đ§ Building Storybook components...
+- đ Preparing deployment to Cloudflare Pages...
+
+---
+âąī¸ Please wait while the Storybook build is in progress...
+EOF
+)
+ fi
+ post_comment "$comment"
+
+elif [ "$STATUS" = "completed" ]; then
+ # Deploy and post completion comment
+ # Convert branch name to Cloudflare-compatible format (lowercase, only alphanumeric and dashes)
+ cloudflare_branch=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | \
+ sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')
+
+ echo "Looking for Storybook build in: $(pwd)/storybook-static"
+
+ # Deploy Storybook if build exists
+ deployment_url="Not deployed"
+ if [ -d "storybook-static" ]; then
+ echo "Found Storybook build, deploying..."
+ url=$(deploy_storybook "storybook-static" "$cloudflare_branch")
+ if [ "$url" != "failed" ] && [ -n "$url" ]; then
+ deployment_url="[View Storybook]($url)"
+ else
+ deployment_url="Deployment failed"
+ fi
+ else
+ echo "Storybook build not found at storybook-static"
+ fi
+
+ # Get workflow conclusion from environment or default to success
+ WORKFLOW_CONCLUSION="${WORKFLOW_CONCLUSION:-success}"
+ WORKFLOW_URL="${WORKFLOW_URL:-}"
+
+ # Generate completion comment based on conclusion
+ if [ "$WORKFLOW_CONCLUSION" = "success" ]; then
+ status_icon="â
"
+ status_text="Build completed successfully!"
+ footer_text="đ Your Storybook is ready for review!"
+ elif [ "$WORKFLOW_CONCLUSION" = "skipped" ]; then
+ status_icon="âī¸"
+ status_text="Build skipped."
+ footer_text="âšī¸ Chromatic was skipped for this PR."
+ elif [ "$WORKFLOW_CONCLUSION" = "cancelled" ]; then
+ status_icon="đĢ"
+ status_text="Build cancelled."
+ footer_text="âšī¸ The Chromatic run was cancelled."
+ else
+ status_icon="â"
+ status_text="Build failed!"
+ footer_text="â ī¸ Please check the workflow logs for error details."
+ fi
+
+ comment="$COMMENT_MARKER
+## đ¨ Storybook Build Status
+
+$status_icon **$status_text**
+
+â° Completed at: $(date -u '+%m/%d/%Y, %I:%M:%S %p') UTC
+
+### đ Links
+- [đ View Workflow Run]($WORKFLOW_URL)"
+
+ # Add deployment status
+ if [ "$deployment_url" != "Not deployed" ]; then
+ if [ "$deployment_url" = "Deployment failed" ]; then
+ comment="$comment
+- â Storybook deployment failed"
+ elif [ "$WORKFLOW_CONCLUSION" = "success" ]; then
+ comment="$comment
+- đ¨ $deployment_url"
+ else
+ comment="$comment
+- â ī¸ Build failed - $deployment_url"
+ fi
+ elif [ "$WORKFLOW_CONCLUSION" != "success" ]; then
+ comment="$comment
+- âī¸ Storybook deployment skipped (build did not succeed)"
+ fi
+
+ comment="$comment
+
+---
+$footer_text"
+
+ post_comment "$comment"
+fi
\ No newline at end of file
diff --git a/src/platform/workflow/persistence/composables/useWorkflowPersistence.ts b/src/platform/workflow/persistence/composables/useWorkflowPersistence.ts
index 0e3d92b15..f6f5f1828 100644
--- a/src/platform/workflow/persistence/composables/useWorkflowPersistence.ts
+++ b/src/platform/workflow/persistence/composables/useWorkflowPersistence.ts
@@ -104,7 +104,7 @@ export function useWorkflowPersistence() {
}
const paths = openWorkflows.value
- .filter((workflow) => workflow?.isPersisted && !workflow.isModified)
+ .filter((workflow) => workflow?.isPersisted)
.map((workflow) => workflow.path)
const activeIndex = openWorkflows.value.findIndex(
(workflow) => workflow.path === activeWorkflow.value?.path
diff --git a/src/renderer/core/canvas/useCanvasInteractions.ts b/src/renderer/core/canvas/useCanvasInteractions.ts
index a32d5e864..46ce4ae46 100644
--- a/src/renderer/core/canvas/useCanvasInteractions.ts
+++ b/src/renderer/core/canvas/useCanvasInteractions.ts
@@ -30,6 +30,15 @@ export function useCanvasInteractions() {
* when appropriate (e.g., Ctrl+wheel for zoom in standard mode)
*/
const handleWheel = (event: WheelEvent) => {
+ // Check if the wheel event is from an element that wants to capture wheel events
+ const target = event.target as HTMLElement
+ const captureElement = target?.closest('[data-capture-wheel="true"]')
+
+ if (captureElement) {
+ // Element wants to capture wheel events, don't forward to canvas
+ return
+ }
+
// In standard mode, Ctrl+wheel should go to canvas for zoom
if (isStandardNavMode.value && (event.ctrlKey || event.metaKey)) {
forwardEventToCanvas(event)
@@ -72,6 +81,15 @@ export function useCanvasInteractions() {
const forwardEventToCanvas = (
event: WheelEvent | PointerEvent | MouseEvent
) => {
+ // Check if the wheel event is from an element that wants to capture wheel events
+ const target = event.target as HTMLElement
+ const captureElement = target?.closest('[data-capture-wheel="true"]')
+
+ if (captureElement) {
+ // Element wants to capture wheel events, don't forward to canvas
+ return
+ }
+
const canvasEl = app.canvas?.canvas
if (!canvasEl) return
event.preventDefault()
diff --git a/src/renderer/extensions/vueNodes/components/LGraphNode.vue b/src/renderer/extensions/vueNodes/components/LGraphNode.vue
index a61111bcf..bced99338 100644
--- a/src/renderer/extensions/vueNodes/components/LGraphNode.vue
+++ b/src/renderer/extensions/vueNodes/components/LGraphNode.vue
@@ -211,7 +211,8 @@ const isSelected = computed(() => {
})
// Use execution state composable
-const { executing, progress } = useNodeExecutionState(() => nodeData.id)
+const nodeLocatorId = computed(() => getLocatorIdFromNodeData(nodeData))
+const { executing, progress } = useNodeExecutionState(nodeLocatorId)
// Direct access to execution store for error state
const executionStore = useExecutionStore()
diff --git a/src/renderer/extensions/vueNodes/components/NodeHeader.vue b/src/renderer/extensions/vueNodes/components/NodeHeader.vue
index 4f84ff531..252736a26 100644
--- a/src/renderer/extensions/vueNodes/components/NodeHeader.vue
+++ b/src/renderer/extensions/vueNodes/components/NodeHeader.vue
@@ -4,12 +4,12 @@
diff --git a/src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts b/src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts
index e69d21f56..b13e9e23f 100644
--- a/src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts
+++ b/src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts
@@ -1,11 +1,77 @@
import type { TooltipDirectivePassThroughOptions } from 'primevue'
-import { type MaybeRef, type Ref, computed, unref } from 'vue'
+import { type MaybeRef, type Ref, computed, ref, unref } from 'vue'
import type { SafeWidgetData } from '@/composables/graph/useGraphNodeManager'
import { st } from '@/i18n'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useNodeDefStore } from '@/stores/nodeDefStore'
import { normalizeI18nKey } from '@/utils/formatUtil'
+import { cn } from '@/utils/tailwindUtil'
+
+/**
+ * Hide all visible tooltips by dispatching mouseleave events
+ *
+ *
+ * IMPORTANT: this escape is needed for many reason due to primevue's directive tooltip system.
+ * We cannot use PT to conditonally render the tooltips because the entire PT object only run
+ * once during the intialization of the directive not every mount/unmount.
+ * Once the directive is constructed its no longer reactive in the traditional sense.
+ * We have to use something non destructive like mouseevents to dismiss the tooltip.
+ *
+ * TODO: use a better tooltip component like RekaUI for vue nodes specifically.
+ */
+
+const tooltipsTemporarilyDisabled = ref(false)
+
+const hideTooltipsGlobally = () => {
+ // Get all visible tooltip elements
+ const tooltips = document.querySelectorAll('.p-tooltip')
+
+ // Early return if no tooltips are visible
+ if (tooltips.length === 0) return
+
+ tooltips.forEach((tooltipEl) => {
+ const tooltipId = tooltipEl.id
+ if (!tooltipId) return
+
+ // Find the target element that owns this tooltip
+ const targetElements = document.querySelectorAll('[data-pd-tooltip="true"]')
+ for (const targetEl of targetElements) {
+ if ((targetEl as any).$_ptooltipId === tooltipId) {
+ ;(targetEl as HTMLElement).dispatchEvent(
+ new MouseEvent('mouseleave', { bubbles: true })
+ )
+ break
+ }
+ }
+ })
+
+ // Disable tooltips temporarily after hiding (for drag operations)
+ tooltipsTemporarilyDisabled.value = true
+}
+
+/**
+ * Re-enable tooltips after pointer interaction ends
+ */
+const handlePointerUp = () => {
+ tooltipsTemporarilyDisabled.value = false
+}
+
+// Global tooltip hiding system
+const globalTooltipState = { listenersSetup: false }
+
+function setupGlobalTooltipHiding() {
+ if (globalTooltipState.listenersSetup) return
+
+ document.addEventListener('pointerdown', hideTooltipsGlobally)
+ document.addEventListener('pointerup', handlePointerUp)
+ window.addEventListener('wheel', hideTooltipsGlobally, {
+ capture: true, //Need this to bypass the event layer from Litegraph
+ passive: true
+ })
+
+ globalTooltipState.listenersSetup = true
+}
/**
* Composable for managing Vue node tooltips
@@ -18,6 +84,9 @@ export function useNodeTooltips(
const nodeDefStore = useNodeDefStore()
const settingsStore = useSettingStore()
+ // Setup global pointerdown listener once
+ setupGlobalTooltipHiding()
+
// Check if tooltips are globally enabled
const tooltipsEnabled = computed(() =>
settingsStore.get('Comfy.EnableTooltips')
@@ -76,6 +145,7 @@ export function useNodeTooltips(
/**
* Create tooltip configuration object for v-tooltip directive
+ * Components wrap this in computed() for reactivity
*/
const createTooltipConfig = (text: string) => {
const tooltipDelay = settingsStore.get('LiteGraph.Node.TooltipDelay')
@@ -84,21 +154,33 @@ export function useNodeTooltips(
const config: {
value: string
showDelay: number
+ hideDelay: number
disabled: boolean
appendTo?: HTMLElement
pt?: TooltipDirectivePassThroughOptions
} = {
value: tooltipText,
showDelay: tooltipDelay as number,
- disabled: !tooltipsEnabled.value || !tooltipText,
+ hideDelay: 0, // Immediate hiding
+ disabled:
+ !tooltipsEnabled.value ||
+ !tooltipText ||
+ tooltipsTemporarilyDisabled.value, // this reactive value works but only on next mount,
+ // so if the tooltip is already visible changing this will not hide it
pt: {
text: {
class:
- 'bg-pure-white dark-theme:bg-charcoal-800 border dark-theme:border-slate-300 rounded-md px-4 py-2 text-charcoal-700 dark-theme:text-pure-white text-sm font-normal leading-tight max-w-75 shadow-none'
+ 'border-sand-100 bg-pure-white dark-theme:bg-charcoal-800 border dark-theme:border-slate-300 rounded-md px-4 py-2 text-charcoal-700 dark-theme:text-pure-white text-sm font-normal leading-tight max-w-75 shadow-none'
},
- arrow: {
- class: 'before:border-slate-300'
- }
+ arrow: ({ context }) => ({
+ class: cn(
+ context?.top && 'border-t-sand-100 dark-theme:border-t-slate-300',
+ context?.bottom &&
+ 'border-b-sand-100 dark-theme:border-b-slate-300',
+ context?.left && 'border-l-sand-100 dark-theme:border-l-slate-300',
+ context?.right && 'border-r-sand-100 dark-theme:border-r-slate-300'
+ )
+ })
}
}
diff --git a/src/renderer/extensions/vueNodes/execution/useNodeExecutionState.ts b/src/renderer/extensions/vueNodes/execution/useNodeExecutionState.ts
index aa4867db9..8debe0666 100644
--- a/src/renderer/extensions/vueNodes/execution/useNodeExecutionState.ts
+++ b/src/renderer/extensions/vueNodes/execution/useNodeExecutionState.ts
@@ -9,27 +9,27 @@ import { useExecutionStore } from '@/stores/executionStore'
* Provides reactive access to execution state and progress for a specific node
* by injecting execution data from the parent GraphCanvas provider.
*
- * @param nodeIdMaybe - The ID of the node to track execution state for
+ * @param nodeLocatorIdMaybe - Locator ID (root or subgraph scoped) of the node to track
* @returns Object containing reactive execution state and progress
*/
export const useNodeExecutionState = (
- nodeIdMaybe: MaybeRefOrGetter
+ nodeLocatorIdMaybe: MaybeRefOrGetter
) => {
- const nodeId = toValue(nodeIdMaybe)
- const { uniqueExecutingNodeIdStrings, nodeProgressStates } =
- storeToRefs(useExecutionStore())
+ const locatorId = computed(() => toValue(nodeLocatorIdMaybe) ?? '')
+ const { nodeLocationProgressStates } = storeToRefs(useExecutionStore())
- const executing = computed(() => {
- return uniqueExecutingNodeIdStrings.value.has(nodeId)
+ const progressState = computed(() => {
+ const id = locatorId.value
+ return id ? nodeLocationProgressStates.value[id] : undefined
})
+ const executing = computed(() => progressState.value?.state === 'running')
+
const progress = computed(() => {
- const state = nodeProgressStates.value[nodeId]
- return state?.max > 0 ? state.value / state.max : undefined
+ const state = progressState.value
+ return state && state.max > 0 ? state.value / state.max : undefined
})
- const progressState = computed(() => nodeProgressStates.value[nodeId])
-
const progressPercentage = computed(() => {
const prog = progress.value
return prog !== undefined ? Math.round(prog * 100) : undefined
diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetMarkdown.vue b/src/renderer/extensions/vueNodes/widgets/components/WidgetMarkdown.vue
index 7f3995f9e..3ffe47102 100644
--- a/src/renderer/extensions/vueNodes/widgets/components/WidgetMarkdown.vue
+++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetMarkdown.vue
@@ -23,6 +23,7 @@
onBlur: handleBlur
}
}"
+ data-capture-wheel="true"
@update:model-value="onChange"
@click.stop
@keydown.stop
diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue
index 4ac007669..4242c13ae 100644
--- a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue
+++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue
@@ -10,6 +10,7 @@
:pt="{
option: 'text-xs'
}"
+ data-capture-wheel="true"
@update:model-value="onChange"
/>
diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue b/src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue
index bd7ac7818..a2ec58de6 100644
--- a/src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue
+++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue
@@ -8,6 +8,7 @@
:placeholder="placeholder || widget.name || ''"
size="small"
rows="3"
+ data-capture-wheel="true"
@update:model-value="onChange"
/>
diff --git a/src/types/vue-shim.d.ts b/src/types/vue-shim.d.ts
deleted file mode 100644
index 664e5764a..000000000
--- a/src/types/vue-shim.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// vue-shim.d.ts
-declare module '*.vue' {
- import { DefineComponent } from 'vue'
- const component: DefineComponent<{}, {}, any>
- export default component
-}