From 298b3c629b65004c96cc268fb8b8f7ff953f122e Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Sun, 26 Oct 2025 22:14:30 -0700 Subject: [PATCH 001/115] ci: update automated backport workflow to skip if backport already in-flight or completed (#6317) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates the backport workflow so it filters out branches that have already been backported, allowing new labels to trigger fresh cherry-picks without reprocessing completed targets. Also adds an automatic cleanup step that removes the `needs-backport` trigger label once a run succeeds, aligning its behavior with the other label-driven automations. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6317-ci-update-automated-backport-workflow-to-skip-if-backport-already-in-flight-or-completed-2996d73d36508113b90df43b1f68344f) by [Unito](https://www.unito.io) --- .github/workflows/pr-backport.yaml | 109 +++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 31 deletions(-) diff --git a/.github/workflows/pr-backport.yaml b/.github/workflows/pr-backport.yaml index 1c9a29230..e70cc262b 100644 --- a/.github/workflows/pr-backport.yaml +++ b/.github/workflows/pr-backport.yaml @@ -69,34 +69,7 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Check if backports already exist - id: check-existing - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || github.event.pull_request.number }} - run: | - # Check for existing backport PRs for this PR number - EXISTING_BACKPORTS=$(gh pr list --state all --search "backport-${PR_NUMBER}-to" --json title,headRefName,baseRefName | jq -r '.[].headRefName') - - if [ -z "$EXISTING_BACKPORTS" ]; then - echo "skip=false" >> $GITHUB_OUTPUT - exit 0 - fi - - # For manual triggers with force_rerun, proceed anyway - if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ "${{ inputs.force_rerun }}" = "true" ]; then - echo "skip=false" >> $GITHUB_OUTPUT - echo "::warning::Force rerun requested - existing backports will be updated" - exit 0 - fi - - echo "Found existing backport PRs:" - echo "$EXISTING_BACKPORTS" - echo "skip=true" >> $GITHUB_OUTPUT - echo "::warning::Backport PRs already exist for PR #${PR_NUMBER}, skipping to avoid duplicates" - - name: Collect backport targets - if: steps.check-existing.outputs.skip != 'true' id: targets run: | TARGETS=() @@ -151,8 +124,76 @@ jobs: echo "targets=${TARGETS[*]}" >> $GITHUB_OUTPUT echo "Found backport targets: ${TARGETS[*]}" + - name: Filter already backported targets + id: filter-targets + env: + EVENT_NAME: ${{ github.event_name }} + FORCE_RERUN_INPUT: >- + ${{ github.event_name == 'workflow_dispatch' && inputs.force_rerun + || 'false' }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: >- + ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number + || github.event.pull_request.number }} + run: | + set -euo pipefail + + REQUESTED_TARGETS="${{ steps.targets.outputs.targets }}" + if [ -z "$REQUESTED_TARGETS" ]; then + echo "skip=true" >> $GITHUB_OUTPUT + echo "pending-targets=" >> $GITHUB_OUTPUT + exit 0 + fi + + FORCE_RERUN=false + if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ "$FORCE_RERUN_INPUT" = "true" ]; then + FORCE_RERUN=true + fi + + mapfile -t EXISTING_BRANCHES < <( + git ls-remote --heads origin "backport-${PR_NUMBER}-to-*" || true + ) + + PENDING=() + SKIPPED=() + + for target in $REQUESTED_TARGETS; do + SAFE_TARGET=$(echo "$target" | tr '/' '-') + BACKPORT_BRANCH="backport-${PR_NUMBER}-to-${SAFE_TARGET}" + + if [ "$FORCE_RERUN" = true ]; then + PENDING+=("$target") + continue + fi + + if printf '%s\n' "${EXISTING_BRANCHES[@]:-}" | + grep -Fq "refs/heads/${BACKPORT_BRANCH}"; then + SKIPPED+=("$target") + else + PENDING+=("$target") + fi + done + + SKIPPED_JOINED="${SKIPPED[*]:-}" + PENDING_JOINED="${PENDING[*]:-}" + + echo "already-exists=${SKIPPED_JOINED}" >> $GITHUB_OUTPUT + echo "pending-targets=${PENDING_JOINED}" >> $GITHUB_OUTPUT + + if [ -z "$PENDING_JOINED" ]; then + echo "skip=true" >> $GITHUB_OUTPUT + if [ -n "$SKIPPED_JOINED" ]; then + echo "::warning::Backport branches already exist for: ${SKIPPED_JOINED}" + fi + else + echo "skip=false" >> $GITHUB_OUTPUT + if [ -n "$SKIPPED_JOINED" ]; then + echo "::notice::Skipping already backported targets: ${SKIPPED_JOINED}" + fi + fi + - name: Backport commits - if: steps.check-existing.outputs.skip != 'true' + if: steps.filter-targets.outputs.skip != 'true' id: backport env: PR_NUMBER: ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || github.event.pull_request.number }} @@ -170,7 +211,7 @@ jobs: MERGE_COMMIT="${{ github.event.pull_request.merge_commit_sha }}" fi - for target in ${{ steps.targets.outputs.targets }}; do + for target in ${{ steps.filter-targets.outputs.pending-targets }}; do TARGET_BRANCH="${target}" SAFE_TARGET=$(echo "$TARGET_BRANCH" | tr '/' '-') BACKPORT_BRANCH="backport-${PR_NUMBER}-to-${SAFE_TARGET}" @@ -219,7 +260,7 @@ jobs: fi - name: Create PR for each successful backport - if: steps.check-existing.outputs.skip != 'true' && steps.backport.outputs.success + if: steps.filter-targets.outputs.skip != 'true' && steps.backport.outputs.success env: GH_TOKEN: ${{ secrets.PR_GH_TOKEN }} PR_NUMBER: ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || github.event.pull_request.number }} @@ -258,7 +299,7 @@ jobs: done - name: Comment on failures - if: steps.check-existing.outputs.skip != 'true' && failure() && steps.backport.outputs.failed + if: steps.filter-targets.outputs.skip != 'true' && failure() && steps.backport.outputs.failed env: GH_TOKEN: ${{ github.token }} run: | @@ -287,3 +328,9 @@ jobs: gh pr comment "${PR_NUMBER}" --body "${COMMENT_BODY}" fi done + + - name: Remove needs-backport label + if: steps.filter-targets.outputs.skip != 'true' && success() + run: gh pr edit ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || github.event.pull_request.number }} --remove-label "needs-backport" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 28a6089a940b6aa4256c5f29c843ea11e4ca869a Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Sun, 26 Oct 2025 22:47:15 -0700 Subject: [PATCH 002/115] ci: automate cloud release branch tagging (#6321) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes the RC minor version branch release automation to create paired `core/x.y` and `cloud/x.y` branches whenever a release bump merges. Then changes the backport workflow to accept labels that match those branch names directly, allowing engineers to route fixes to either OSS or cloud release lines without extra labels or artifacts. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6321-ci-automate-cloud-release-branch-tagging-2996d73d365081b0b036ebd3f088354b) by [Unito](https://www.unito.io) --- .github/workflows/pr-backport.yaml | 8 ++ .github/workflows/release-branch-create.yaml | 118 ++++++++++++------- 2 files changed, 85 insertions(+), 41 deletions(-) diff --git a/.github/workflows/pr-backport.yaml b/.github/workflows/pr-backport.yaml index e70cc262b..0275d1b62 100644 --- a/.github/workflows/pr-backport.yaml +++ b/.github/workflows/pr-backport.yaml @@ -111,6 +111,14 @@ jobs: add_target "$label" "${BASH_REMATCH[1]}" elif [[ "$label" =~ ^backport:(.+)$ ]]; then add_target "$label" "${BASH_REMATCH[1]}" + elif [[ "$label" =~ ^core\/([0-9]+)\.([0-9]+)$ ]]; then + SAFE_MAJOR="${BASH_REMATCH[1]}" + SAFE_MINOR="${BASH_REMATCH[2]}" + add_target "$label" "core/${SAFE_MAJOR}.${SAFE_MINOR}" + elif [[ "$label" =~ ^cloud\/([0-9]+)\.([0-9]+)$ ]]; then + SAFE_MAJOR="${BASH_REMATCH[1]}" + SAFE_MINOR="${BASH_REMATCH[2]}" + add_target "$label" "cloud/${SAFE_MAJOR}.${SAFE_MINOR}" elif [[ "$label" =~ ^[0-9]+\.[0-9]+$ ]]; then add_target "$label" "core/${label}" fi diff --git a/.github/workflows/release-branch-create.yaml b/.github/workflows/release-branch-create.yaml index 992e779dd..434100ff3 100644 --- a/.github/workflows/release-branch-create.yaml +++ b/.github/workflows/release-branch-create.yaml @@ -69,6 +69,9 @@ jobs: echo "prev_version=$PREV_VERSION" >> $GITHUB_OUTPUT echo "prev_minor=$PREV_MINOR" >> $GITHUB_OUTPUT + BASE_COMMIT=$(git rev-parse HEAD) + echo "base_commit=$BASE_COMMIT" >> $GITHUB_OUTPUT + # Get previous major version for comparison PREV_MAJOR=$(echo $PREV_VERSION | cut -d. -f1) @@ -87,13 +90,13 @@ jobs: elif [[ "$MAJOR" -gt "$PREV_MAJOR" && "$MINOR" == "0" && "$PATCH" == "0" ]]; then # Major version bump (e.g., 1.99.x → 2.0.0) echo "is_minor_bump=true" >> $GITHUB_OUTPUT - BRANCH_NAME="core/${PREV_MAJOR}.${PREV_MINOR}" - echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + BRANCH_BASE="${PREV_MAJOR}.${PREV_MINOR}" + echo "branch_base=$BRANCH_BASE" >> $GITHUB_OUTPUT elif [[ "$MAJOR" == "$PREV_MAJOR" && "$MINOR" -gt "$PREV_MINOR" && "$PATCH" == "0" ]]; then # Minor version bump (e.g., 1.23.x → 1.24.0) echo "is_minor_bump=true" >> $GITHUB_OUTPUT - BRANCH_NAME="core/${MAJOR}.${PREV_MINOR}" - echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + BRANCH_BASE="${MAJOR}.${PREV_MINOR}" + echo "branch_base=$BRANCH_BASE" >> $GITHUB_OUTPUT else echo "is_minor_bump=false" >> $GITHUB_OUTPUT fi @@ -101,64 +104,97 @@ jobs: # Return to main branch git checkout main - - name: Create release branch + - name: Create release branches + id: create_branches if: steps.check_version.outputs.is_minor_bump == 'true' run: | - BRANCH_NAME="${{ steps.check_version.outputs.branch_name }}" + BRANCH_BASE="${{ steps.check_version.outputs.branch_base }}" + PREV_VERSION="${{ steps.check_version.outputs.prev_version }}" - # Check if branch already exists - if git ls-remote --heads origin "$BRANCH_NAME" | grep -q "$BRANCH_NAME"; then - echo "⚠️ Branch $BRANCH_NAME already exists, skipping creation" - echo "branch_exists=true" >> $GITHUB_ENV - exit 0 - else - echo "branch_exists=false" >> $GITHUB_ENV + if [[ -z "$BRANCH_BASE" ]]; then + echo "::error::Branch base not set; unable to determine release branches" + exit 1 fi - # Create branch from the commit BEFORE the version bump - # This ensures the release branch has the previous minor version - git checkout -b "$BRANCH_NAME" HEAD^1 + BASE_COMMIT="${{ steps.check_version.outputs.base_commit }}" - # Push the new branch - git push origin "$BRANCH_NAME" + if [[ -z "$BASE_COMMIT" ]]; then + echo "::error::Base commit not provided; cannot create release branches" + exit 1 + fi - echo "✅ Created release branch: $BRANCH_NAME" - echo "This branch is now in feature freeze and will only receive:" - echo "- Bug fixes" - echo "- Critical security patches" - echo "- Documentation updates" + RESULTS_FILE=$(mktemp) + trap 'rm -f "$RESULTS_FILE"' EXIT + for PREFIX in core cloud; do + BRANCH_NAME="${PREFIX}/${BRANCH_BASE}" + + if git ls-remote --exit-code --heads origin \ + "$BRANCH_NAME" >/dev/null 2>&1; then + echo "⚠️ Branch $BRANCH_NAME already exists" + echo "ℹ️ Skipping creation for $BRANCH_NAME" + STATUS="exists" + else + # Create branch from the commit BEFORE the version bump + if ! git push origin "$BASE_COMMIT:refs/heads/$BRANCH_NAME"; then + echo "::error::Failed to push release branch $BRANCH_NAME" + exit 1 + fi + echo "✅ Created release branch: $BRANCH_NAME" + STATUS="created" + fi + + echo "$BRANCH_NAME|$STATUS|$PREV_VERSION" >> "$RESULTS_FILE" + done + + { + echo "results<<'EOF'" + cat "$RESULTS_FILE" + echo "EOF" + } >> $GITHUB_OUTPUT - name: Post summary if: steps.check_version.outputs.is_minor_bump == 'true' run: | - BRANCH_NAME="${{ steps.check_version.outputs.branch_name }}" - PREV_VERSION="${{ steps.check_version.outputs.prev_version }}" CURRENT_VERSION="${{ steps.check_version.outputs.current_version }}" + RESULTS="${{ steps.create_branches.outputs.results }}" - if [[ "${{ env.branch_exists }}" == "true" ]]; then + if [[ -z "$RESULTS" ]]; then cat >> $GITHUB_STEP_SUMMARY << EOF - ## 🌿 Release Branch Already Exists + ## 🌿 Release Branch Summary - The release branch for the previous minor version already exists: - EOF - else - cat >> $GITHUB_STEP_SUMMARY << EOF - ## 🌿 Release Branch Created - - A new release branch has been created for the previous minor version: + Release branch creation skipped; no eligible branches were found. EOF + exit 0 fi cat >> $GITHUB_STEP_SUMMARY << EOF + ## 🌿 Release Branch Summary - - **Branch**: \`$BRANCH_NAME\` - - **Version**: \`$PREV_VERSION\` (feature frozen) - **Main branch**: \`$CURRENT_VERSION\` (active development) + ### Branch Status + EOF + + while IFS='|' read -r BRANCH STATUS PREV_VERSION; do + if [[ "$STATUS" == "created" ]]; then + cat >> $GITHUB_STEP_SUMMARY << EOF + + - \`$BRANCH\` created from version \`$PREV_VERSION\` + EOF + else + cat >> $GITHUB_STEP_SUMMARY << EOF + + - \`$BRANCH\` already existed (based on version \`$PREV_VERSION\`) + EOF + fi + done <<< "$RESULTS" + + cat >> $GITHUB_STEP_SUMMARY << EOF + ### Branch Policy - The \`$BRANCH_NAME\` branch is now in **feature freeze** and will only accept: + Release branches are feature-frozen and only accept: - 🐛 Bug fixes - 🔒 Security patches - 📚 Documentation updates @@ -167,9 +203,9 @@ jobs: ### Backporting Changes - To backport a fix to this release branch: + To backport a fix: 1. Create your fix on \`main\` first - 2. Cherry-pick to \`$BRANCH_NAME\` - 3. Create a PR targeting \`$BRANCH_NAME\` - 4. Use the \`Release\` label on the PR + 2. Cherry-pick to the target release branch + 3. Create a PR targeting that branch + 4. Apply the matching \`core/x.y\` or \`cloud/x.y\` label EOF From 0a957fb2ac791d212bb470c0d6156fdbd62337d5 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Sun, 26 Oct 2025 23:37:22 -0700 Subject: [PATCH 003/115] ci: leave comment and abort early if commit already exists on target branch in backport workflow (#6326) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow up on https://github.com/Comfy-Org/ComfyUI_frontend/pull/6317: Fixes confusing "merge conflicts detected" message when commit already exists on target branch (e.g., PRs #6294 and #6307). ## Changes - Added check to detect if merge commit already exists on target branch before attempting cherry-pick - New failure reason `already-exists` for this case - Clear comment message: "Commit already exists on branch, no backport needed" instead of confusing "Merge conflicts detected" with empty file list ## Before When a commit already existed on the target branch, users would see: > @user Backport to `core/1.30` failed: Merge conflicts detected. > Please manually cherry-pick commit `abc123` to the `core/1.30` branch. >
Conflicting files > >
This was confusing because there were no actual conflicts - the commit was already present. ## After Users now see: > @user Commit `abc123` already exists on branch `core/1.30`. No backport needed. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6326-ci-leave-comment-and-abort-early-if-commit-already-exists-on-target-branch-in-backport-w-2996d73d36508167aff3e6783e832c74) by [Unito](https://www.unito.io) --- .github/workflows/pr-backport.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/pr-backport.yaml b/.github/workflows/pr-backport.yaml index 0275d1b62..8729c5d57 100644 --- a/.github/workflows/pr-backport.yaml +++ b/.github/workflows/pr-backport.yaml @@ -234,6 +234,14 @@ jobs: continue fi + # Check if commit already exists on target branch + if git branch -r --contains "${MERGE_COMMIT}" | grep -q "origin/${TARGET_BRANCH}"; then + echo "::notice::Commit ${MERGE_COMMIT} already exists on ${TARGET_BRANCH}, skipping backport" + FAILED="${FAILED}${TARGET_BRANCH}:already-exists " + echo "::endgroup::" + continue + fi + # Create backport branch git checkout -b "${BACKPORT_BRANCH}" "origin/${TARGET_BRANCH}" @@ -328,6 +336,9 @@ jobs: if [ "${reason}" = "branch-missing" ]; then gh pr comment "${PR_NUMBER}" --body "@${PR_AUTHOR} Backport failed: Branch \`${target}\` does not exist" + elif [ "${reason}" = "already-exists" ]; then + gh pr comment "${PR_NUMBER}" --body "@${PR_AUTHOR} Commit \`${MERGE_COMMIT}\` already exists on branch \`${target}\`. No backport needed." + elif [ "${reason}" = "conflicts" ]; then # Convert comma-separated conflicts back to newlines for display CONFLICTS_LIST=$(echo "${conflicts}" | tr ',' '\n' | sed 's/^/- /') From 234fc3433cac39ad15e236336c4e5f776c7326f1 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Sun, 26 Oct 2025 23:58:29 -0700 Subject: [PATCH 004/115] use prompt id rather than queue index for history reconciliation (#6327) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Changed history reconciliation to use `promptId` instead of `queueIndex` to support cloud environments that don't have queue indices. Refactored into pure functions with expressive naming. ## Changes - Use `promptId` (unique UUID) for reconciliation instead of `queueIndex` (not available in cloud) - Extract `reconcileHistoryWithServer` with helpers: `extractPromptIds`, `isAddedAfter`, `sortNewestFirst` - Added 34 tests covering reconciliation edge cases, sorting, and limits ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6327-use-prompt-id-rather-than-queue-index-for-history-reconciliation-2996d73d3650818e9471dbeb53cc23bb) by [Unito](https://www.unito.io) --- src/stores/queueStore.ts | 77 ++- tests-ui/tests/store/queueStore.test.ts | 682 +++++++++++++++++++++++- 2 files changed, 728 insertions(+), 31 deletions(-) diff --git a/src/stores/queueStore.ts b/src/stores/queueStore.ts index 5cb754ca6..99d8d0eb7 100644 --- a/src/stores/queueStore.ts +++ b/src/stores/queueStore.ts @@ -425,6 +425,47 @@ export class TaskItemImpl { } } +const extractPromptIds = (tasks: TaskItem[]): Set => + new Set(tasks.map((task) => task.prompt[1])) + +const isAddedAfter = (queueIndex: number) => (task: TaskItem) => + task.prompt[0] > queueIndex + +const sortNewestFirst = (a: TaskItemImpl, b: TaskItemImpl) => + b.queueIndex - a.queueIndex + +const toTaskItemImpls = (tasks: TaskItem[]): TaskItemImpl[] => + tasks.map( + (task) => + new TaskItemImpl( + task.taskType, + task.prompt, + 'status' in task ? task.status : undefined, + 'outputs' in task ? task.outputs : undefined + ) + ) + +const reconcileHistoryWithServer = ( + serverHistory: TaskItem[], + clientHistory: TaskItemImpl[], + lastKnownQueueIndex: number, + maxItems: number +): TaskItemImpl[] => { + const serverPromptIds = extractPromptIds(serverHistory) + + const itemsAddedSinceLastSync = toTaskItemImpls( + serverHistory.filter(isAddedAfter(lastKnownQueueIndex)) + ) + + const itemsStillOnServer = clientHistory.filter((item) => + serverPromptIds.has(item.promptId) + ) + + return [...itemsAddedSinceLastSync, ...itemsStillOnServer] + .sort(sortNewestFirst) + .slice(0, maxItems) +} + export const useQueueStore = defineStore('queue', () => { const runningTasks = ref([]) const pendingTasks = ref([]) @@ -459,37 +500,15 @@ export const useQueueStore = defineStore('queue', () => { api.getHistory(maxHistoryItems.value) ]) - const toClassAll = (tasks: TaskItem[]): TaskItemImpl[] => - tasks - .map( - (task: TaskItem) => - new TaskItemImpl( - task.taskType, - task.prompt, - // status and outputs only exist on history tasks - 'status' in task ? task.status : undefined, - 'outputs' in task ? task.outputs : undefined - ) - ) - .sort((a, b) => b.queueIndex - a.queueIndex) + runningTasks.value = toTaskItemImpls(queue.Running).sort(sortNewestFirst) + pendingTasks.value = toTaskItemImpls(queue.Pending).sort(sortNewestFirst) - runningTasks.value = toClassAll(queue.Running) - pendingTasks.value = toClassAll(queue.Pending) - - const allIndex = new Set( - history.History.map((item: TaskItem) => item.prompt[0]) + historyTasks.value = reconcileHistoryWithServer( + history.History, + historyTasks.value, + lastHistoryQueueIndex.value, + maxHistoryItems.value ) - const newHistoryItems = toClassAll( - history.History.filter( - (item) => item.prompt[0] > lastHistoryQueueIndex.value - ) - ) - const existingHistoryItems = historyTasks.value.filter((item) => - allIndex.has(item.queueIndex) - ) - historyTasks.value = [...newHistoryItems, ...existingHistoryItems] - .slice(0, maxHistoryItems.value) - .sort((a, b) => b.queueIndex - a.queueIndex) } finally { isLoading.value = false } diff --git a/tests-ui/tests/store/queueStore.test.ts b/tests-ui/tests/store/queueStore.test.ts index 313673e69..72a398279 100644 --- a/tests-ui/tests/store/queueStore.test.ts +++ b/tests-ui/tests/store/queueStore.test.ts @@ -1,6 +1,85 @@ -import { describe, expect, it } from 'vitest' +import { createPinia, setActivePinia } from 'pinia' +import { beforeEach, describe, expect, it, vi } from 'vitest' -import { TaskItemImpl } from '@/stores/queueStore' +import type { + HistoryTaskItem, + PendingTaskItem, + RunningTaskItem, + TaskOutput, + TaskPrompt, + TaskStatus +} from '@/schemas/apiSchema' +import { api } from '@/scripts/api' +import { TaskItemImpl, useQueueStore } from '@/stores/queueStore' + +// Fixture factories +const createTaskPrompt = ( + queueIndex: number, + promptId: string, + inputs: Record = {}, + extraData: Record = {}, + outputsToExecute: any[] = [] +): TaskPrompt => [queueIndex, promptId, inputs, extraData, outputsToExecute] + +const createTaskStatus = ( + statusStr: 'success' | 'error' = 'success', + messages: any[] = [] +): TaskStatus => ({ + status_str: statusStr, + completed: true, + messages +}) + +const createTaskOutput = ( + nodeId: string = 'node-1', + images: any[] = [] +): TaskOutput => ({ + [nodeId]: { + images + } +}) + +const createRunningTask = ( + queueIndex: number, + promptId: string +): RunningTaskItem => ({ + taskType: 'Running', + prompt: createTaskPrompt(queueIndex, promptId), + remove: { name: 'Cancel', cb: () => {} } +}) + +const createPendingTask = ( + queueIndex: number, + promptId: string +): PendingTaskItem => ({ + taskType: 'Pending', + prompt: createTaskPrompt(queueIndex, promptId) +}) + +const createHistoryTask = ( + queueIndex: number, + promptId: string, + outputs: TaskOutput = createTaskOutput(), + status: TaskStatus = createTaskStatus() +): HistoryTaskItem => ({ + taskType: 'History', + prompt: createTaskPrompt(queueIndex, promptId), + status, + outputs +}) + +// Mock API +vi.mock('@/scripts/api', () => ({ + api: { + getQueue: vi.fn(), + getHistory: vi.fn(), + clearItems: vi.fn(), + deleteItem: vi.fn(), + apiURL: vi.fn((path) => `/api${path}`), + addEventListener: vi.fn(), + removeEventListener: vi.fn() + } +})) describe('TaskItemImpl', () => { it('should remove animated property from outputs during construction', () => { @@ -154,3 +233,602 @@ describe('TaskItemImpl', () => { }) }) }) + +describe('useQueueStore', () => { + let store: ReturnType + + beforeEach(() => { + setActivePinia(createPinia()) + store = useQueueStore() + vi.clearAllMocks() + }) + + const mockGetQueue = vi.mocked(api.getQueue) + const mockGetHistory = vi.mocked(api.getHistory) + const mockClearItems = vi.mocked(api.clearItems) + const mockDeleteItem = vi.mocked(api.deleteItem) + + describe('initial state', () => { + it('should have empty state on initialization', () => { + expect(store.runningTasks).toEqual([]) + expect(store.pendingTasks).toEqual([]) + expect(store.historyTasks).toEqual([]) + expect(store.isLoading).toBe(false) + expect(store.maxHistoryItems).toBe(64) + }) + + it('should have empty computed tasks', () => { + expect(store.tasks).toEqual([]) + expect(store.flatTasks).toEqual([]) + expect(store.hasPendingTasks).toBe(false) + expect(store.lastHistoryQueueIndex).toBe(-1) + }) + }) + + describe('update() - basic functionality', () => { + it('should load running and pending tasks from API', async () => { + const runningTask = createRunningTask(1, 'run-1') + const pendingTask1 = createPendingTask(2, 'pend-1') + const pendingTask2 = createPendingTask(3, 'pend-2') + + mockGetQueue.mockResolvedValue({ + Running: [runningTask], + Pending: [pendingTask1, pendingTask2] + }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.update() + + expect(store.runningTasks).toHaveLength(1) + expect(store.pendingTasks).toHaveLength(2) + expect(store.runningTasks[0].promptId).toBe('run-1') + expect(store.pendingTasks[0].promptId).toBe('pend-2') + expect(store.pendingTasks[1].promptId).toBe('pend-1') + }) + + it('should load history tasks from API', async () => { + const historyTask1 = createHistoryTask(5, 'hist-1') + const historyTask2 = createHistoryTask(4, 'hist-2') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ + History: [historyTask1, historyTask2] + }) + + await store.update() + + expect(store.historyTasks).toHaveLength(2) + expect(store.historyTasks[0].promptId).toBe('hist-1') + expect(store.historyTasks[1].promptId).toBe('hist-2') + }) + + it('should set loading state correctly', async () => { + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [] }) + + expect(store.isLoading).toBe(false) + + const updatePromise = store.update() + expect(store.isLoading).toBe(true) + + await updatePromise + expect(store.isLoading).toBe(false) + }) + + it('should clear loading state even if API fails', async () => { + mockGetQueue.mockRejectedValue(new Error('API error')) + mockGetHistory.mockResolvedValue({ History: [] }) + + await expect(store.update()).rejects.toThrow('API error') + expect(store.isLoading).toBe(false) + }) + }) + + describe('update() - sorting', () => { + it('should sort tasks by queueIndex descending', async () => { + const task1 = createHistoryTask(1, 'hist-1') + const task2 = createHistoryTask(5, 'hist-2') + const task3 = createHistoryTask(3, 'hist-3') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ + History: [task1, task2, task3] + }) + + await store.update() + + expect(store.historyTasks[0].queueIndex).toBe(5) + expect(store.historyTasks[1].queueIndex).toBe(3) + expect(store.historyTasks[2].queueIndex).toBe(1) + }) + + it('should sort pending tasks by queueIndex descending', async () => { + const pend1 = createPendingTask(10, 'pend-1') + const pend2 = createPendingTask(15, 'pend-2') + const pend3 = createPendingTask(12, 'pend-3') + + mockGetQueue.mockResolvedValue({ + Running: [], + Pending: [pend1, pend2, pend3] + }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.update() + + expect(store.pendingTasks[0].queueIndex).toBe(15) + expect(store.pendingTasks[1].queueIndex).toBe(12) + expect(store.pendingTasks[2].queueIndex).toBe(10) + }) + }) + + describe('update() - history reconciliation by promptId', () => { + it('should keep existing history items that are still in server response', async () => { + const hist1 = createHistoryTask(10, 'existing-1') + const hist2 = createHistoryTask(9, 'existing-2') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [hist1, hist2] }) + + await store.update() + expect(store.historyTasks).toHaveLength(2) + + const hist3 = createHistoryTask(11, 'new-1') + mockGetHistory.mockResolvedValue({ + History: [hist3, hist1, hist2] + }) + + await store.update() + + expect(store.historyTasks).toHaveLength(3) + expect(store.historyTasks.map((t) => t.promptId)).toEqual([ + 'new-1', + 'existing-1', + 'existing-2' + ]) + }) + + it('should remove history items no longer in server response', async () => { + const hist1 = createHistoryTask(10, 'remove-me') + const hist2 = createHistoryTask(9, 'keep-me') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [hist1, hist2] }) + + await store.update() + expect(store.historyTasks).toHaveLength(2) + + mockGetHistory.mockResolvedValue({ History: [hist2] }) + + await store.update() + + expect(store.historyTasks).toHaveLength(1) + expect(store.historyTasks[0].promptId).toBe('keep-me') + }) + + it('should add new history items with queueIndex > lastHistoryQueueIndex', async () => { + const hist1 = createHistoryTask(5, 'old-1') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [hist1] }) + + await store.update() + expect(store.lastHistoryQueueIndex).toBe(5) + + const hist2 = createHistoryTask(6, 'new-1') + const hist3 = createHistoryTask(7, 'new-2') + mockGetHistory.mockResolvedValue({ + History: [hist3, hist2, hist1] + }) + + await store.update() + + expect(store.historyTasks).toHaveLength(3) + expect(store.historyTasks.map((t) => t.promptId)).toContain('new-1') + expect(store.historyTasks.map((t) => t.promptId)).toContain('new-2') + }) + + it('should NOT add history items with queueIndex <= lastHistoryQueueIndex', async () => { + const hist1 = createHistoryTask(10, 'existing-1') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [hist1] }) + + await store.update() + + const oldHist = createHistoryTask(5, 'old-task-should-not-appear') + mockGetHistory.mockResolvedValue({ History: [hist1, oldHist] }) + + await store.update() + + expect(store.historyTasks).toHaveLength(1) + expect(store.historyTasks[0].promptId).toBe('existing-1') + }) + + it('should handle complete history replacement', async () => { + const hist1 = createHistoryTask(5, 'old-1') + const hist2 = createHistoryTask(4, 'old-2') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [hist1, hist2] }) + + await store.update() + expect(store.historyTasks).toHaveLength(2) + + const newHist1 = createHistoryTask(10, 'new-1') + const newHist2 = createHistoryTask(9, 'new-2') + mockGetHistory.mockResolvedValue({ + History: [newHist1, newHist2] + }) + + await store.update() + + expect(store.historyTasks).toHaveLength(2) + expect(store.historyTasks.map((t) => t.promptId)).toEqual([ + 'new-1', + 'new-2' + ]) + }) + + it('should handle empty history from server', async () => { + const hist1 = createHistoryTask(5, 'will-be-removed') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [hist1] }) + + await store.update() + expect(store.historyTasks).toHaveLength(1) + + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.update() + + expect(store.historyTasks).toHaveLength(0) + }) + }) + + describe('update() - queue index collision (THE BUG FIX)', () => { + it('should NOT confuse different prompts with same queueIndex', async () => { + const hist1 = createHistoryTask(50, 'prompt-uuid-aaa') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [hist1] }) + + await store.update() + expect(store.historyTasks).toHaveLength(1) + expect(store.historyTasks[0].promptId).toBe('prompt-uuid-aaa') + + const hist2 = createHistoryTask(51, 'prompt-uuid-bbb') + mockGetHistory.mockResolvedValue({ + History: [hist2] + }) + + await store.update() + + expect(store.historyTasks).toHaveLength(1) + expect(store.historyTasks[0].promptId).toBe('prompt-uuid-bbb') + expect(store.historyTasks[0].queueIndex).toBe(51) + }) + + it('should correctly reconcile when queueIndex is reused', async () => { + const hist1 = createHistoryTask(100, 'first-prompt-at-100') + const hist2 = createHistoryTask(99, 'prompt-at-99') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [hist1, hist2] }) + + await store.update() + expect(store.historyTasks).toHaveLength(2) + + const hist3 = createHistoryTask(101, 'second-prompt-at-101') + mockGetHistory.mockResolvedValue({ + History: [hist3, hist2] + }) + + await store.update() + + expect(store.historyTasks).toHaveLength(2) + const promptIds = store.historyTasks.map((t) => t.promptId) + expect(promptIds).toContain('second-prompt-at-101') + expect(promptIds).toContain('prompt-at-99') + expect(promptIds).not.toContain('first-prompt-at-100') + }) + + it('should handle multiple queueIndex collisions simultaneously', async () => { + const hist1 = createHistoryTask(10, 'old-at-10') + const hist2 = createHistoryTask(20, 'old-at-20') + const hist3 = createHistoryTask(30, 'keep-at-30') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ + History: [hist3, hist2, hist1] + }) + + await store.update() + expect(store.historyTasks).toHaveLength(3) + + const newHist1 = createHistoryTask(31, 'new-at-31') + const newHist2 = createHistoryTask(32, 'new-at-32') + mockGetHistory.mockResolvedValue({ + History: [newHist2, newHist1, hist3] + }) + + await store.update() + + expect(store.historyTasks).toHaveLength(3) + const promptIds = store.historyTasks.map((t) => t.promptId) + expect(promptIds).toEqual(['new-at-32', 'new-at-31', 'keep-at-30']) + }) + }) + + describe('update() - maxHistoryItems limit', () => { + it('should enforce maxHistoryItems limit', async () => { + store.maxHistoryItems = 3 + + const tasks = Array.from({ length: 5 }, (_, i) => + createHistoryTask(10 - i, `hist-${i}`) + ) + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: tasks }) + + await store.update() + + expect(store.historyTasks).toHaveLength(3) + expect(store.historyTasks[0].queueIndex).toBe(10) + expect(store.historyTasks[1].queueIndex).toBe(9) + expect(store.historyTasks[2].queueIndex).toBe(8) + }) + + it('should respect maxHistoryItems when combining new and existing', async () => { + store.maxHistoryItems = 5 + + const initial = Array.from({ length: 3 }, (_, i) => + createHistoryTask(10 + i, `existing-${i}`) + ) + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: initial }) + + await store.update() + expect(store.historyTasks).toHaveLength(3) + + const newTasks = Array.from({ length: 4 }, (_, i) => + createHistoryTask(20 + i, `new-${i}`) + ) + mockGetHistory.mockResolvedValue({ + History: [...newTasks, ...initial] + }) + + await store.update() + + expect(store.historyTasks).toHaveLength(5) + expect(store.historyTasks[0].queueIndex).toBe(23) + }) + + it('should handle maxHistoryItems = 0', async () => { + store.maxHistoryItems = 0 + + const tasks = [createHistoryTask(10, 'hist-1')] + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: tasks }) + + await store.update() + + expect(store.historyTasks).toHaveLength(0) + }) + + it('should handle maxHistoryItems = 1', async () => { + store.maxHistoryItems = 1 + + const tasks = [ + createHistoryTask(10, 'hist-1'), + createHistoryTask(9, 'hist-2') + ] + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: tasks }) + + await store.update() + + expect(store.historyTasks).toHaveLength(1) + expect(store.historyTasks[0].queueIndex).toBe(10) + }) + + it('should dynamically adjust when maxHistoryItems changes', async () => { + store.maxHistoryItems = 10 + + const tasks = Array.from({ length: 15 }, (_, i) => + createHistoryTask(20 - i, `hist-${i}`) + ) + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: tasks }) + + await store.update() + expect(store.historyTasks).toHaveLength(10) + + store.maxHistoryItems = 5 + mockGetHistory.mockResolvedValue({ History: tasks }) + + await store.update() + expect(store.historyTasks).toHaveLength(5) + }) + }) + + describe('computed properties', () => { + it('tasks should combine pending, running, and history in correct order', async () => { + const running = createRunningTask(5, 'run-1') + const pending1 = createPendingTask(6, 'pend-1') + const pending2 = createPendingTask(7, 'pend-2') + const hist1 = createHistoryTask(3, 'hist-1') + const hist2 = createHistoryTask(4, 'hist-2') + + mockGetQueue.mockResolvedValue({ + Running: [running], + Pending: [pending1, pending2] + }) + mockGetHistory.mockResolvedValue({ + History: [hist2, hist1] + }) + + await store.update() + + expect(store.tasks).toHaveLength(5) + expect(store.tasks[0].taskType).toBe('Pending') + expect(store.tasks[1].taskType).toBe('Pending') + expect(store.tasks[2].taskType).toBe('Running') + expect(store.tasks[3].taskType).toBe('History') + expect(store.tasks[4].taskType).toBe('History') + }) + + it('hasPendingTasks should be true when pending tasks exist', async () => { + mockGetQueue.mockResolvedValue({ + Running: [], + Pending: [createPendingTask(1, 'pend-1')] + }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.update() + expect(store.hasPendingTasks).toBe(true) + }) + + it('hasPendingTasks should be false when no pending tasks', async () => { + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.update() + expect(store.hasPendingTasks).toBe(false) + }) + + it('lastHistoryQueueIndex should return highest queue index', async () => { + const hist1 = createHistoryTask(10, 'hist-1') + const hist2 = createHistoryTask(25, 'hist-2') + const hist3 = createHistoryTask(15, 'hist-3') + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ + History: [hist1, hist2, hist3] + }) + + await store.update() + expect(store.lastHistoryQueueIndex).toBe(25) + }) + + it('lastHistoryQueueIndex should be -1 when no history', async () => { + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.update() + expect(store.lastHistoryQueueIndex).toBe(-1) + }) + }) + + describe('clear()', () => { + beforeEach(async () => { + mockGetQueue.mockResolvedValue({ + Running: [createRunningTask(1, 'run-1')], + Pending: [createPendingTask(2, 'pend-1')] + }) + mockGetHistory.mockResolvedValue({ + History: [createHistoryTask(3, 'hist-1')] + }) + await store.update() + }) + + it('should clear both queue and history by default', async () => { + mockClearItems.mockResolvedValue(undefined) + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.clear() + + expect(mockClearItems).toHaveBeenCalledTimes(2) + expect(mockClearItems).toHaveBeenCalledWith('queue') + expect(mockClearItems).toHaveBeenCalledWith('history') + expect(store.runningTasks).toHaveLength(0) + expect(store.pendingTasks).toHaveLength(0) + expect(store.historyTasks).toHaveLength(0) + }) + + it('should clear only queue when specified', async () => { + mockClearItems.mockResolvedValue(undefined) + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ + History: [createHistoryTask(3, 'hist-1')] + }) + + await store.clear(['queue']) + + expect(mockClearItems).toHaveBeenCalledTimes(1) + expect(mockClearItems).toHaveBeenCalledWith('queue') + expect(store.historyTasks).toHaveLength(1) + }) + + it('should clear only history when specified', async () => { + mockClearItems.mockResolvedValue(undefined) + mockGetQueue.mockResolvedValue({ + Running: [createRunningTask(1, 'run-1')], + Pending: [createPendingTask(2, 'pend-1')] + }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.clear(['history']) + + expect(mockClearItems).toHaveBeenCalledTimes(1) + expect(mockClearItems).toHaveBeenCalledWith('history') + expect(store.runningTasks).toHaveLength(1) + expect(store.pendingTasks).toHaveLength(1) + }) + + it('should do nothing when empty array passed', async () => { + await store.clear([]) + + expect(mockClearItems).not.toHaveBeenCalled() + }) + }) + + describe('delete()', () => { + it('should delete task from queue', async () => { + const task = new TaskItemImpl('Pending', createTaskPrompt(1, 'pend-1')) + + mockDeleteItem.mockResolvedValue(undefined) + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.delete(task) + + expect(mockDeleteItem).toHaveBeenCalledWith('queue', 'pend-1') + }) + + it('should delete task from history', async () => { + const task = new TaskItemImpl( + 'History', + createTaskPrompt(1, 'hist-1'), + createTaskStatus(), + createTaskOutput() + ) + + mockDeleteItem.mockResolvedValue(undefined) + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.delete(task) + + expect(mockDeleteItem).toHaveBeenCalledWith('history', 'hist-1') + }) + + it('should refresh store after deletion', async () => { + const task = new TaskItemImpl('Pending', createTaskPrompt(1, 'pend-1')) + + mockDeleteItem.mockResolvedValue(undefined) + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue({ History: [] }) + + await store.delete(task) + + expect(mockGetQueue).toHaveBeenCalled() + expect(mockGetHistory).toHaveBeenCalled() + }) + }) +}) From ed49a82c209381e34200de9af8e2ee02c309ba2e Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Mon, 27 Oct 2025 14:24:55 -0700 Subject: [PATCH 005/115] fix subscription panel badge bg color (#6334) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary This should use the dialog bg color instead of menu bg when it is on a dialog. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6334-fix-subscription-panel-badge-bg-color-2996d73d36508171bf5bd2a8dc54f7c3) by [Unito](https://www.unito.io) --- .../cloud/subscription/components/SubscriptionPanel.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/platform/cloud/subscription/components/SubscriptionPanel.vue b/src/platform/cloud/subscription/components/SubscriptionPanel.vue index 2903d5e8b..fa751d47b 100644 --- a/src/platform/cloud/subscription/components/SubscriptionPanel.vue +++ b/src/platform/cloud/subscription/components/SubscriptionPanel.vue @@ -5,7 +5,10 @@

{{ $t('subscription.title') }}

- +
From ddbf2cc720a652a6d6b9ffcad13b24e77c8c12f5 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Mon, 27 Oct 2025 14:25:43 -0700 Subject: [PATCH 006/115] skip system notifications on cloud (#6333) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary This code has no effect but adding it so that when the `!isElectron()` condition is removed, maintainers will remember this extra condition that must still be enforced. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6333-skip-system-notifications-on-cloud-2996d73d3650818b8335d395c86badf3) by [Unito](https://www.unito.io) --- src/platform/updates/common/releaseStore.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/platform/updates/common/releaseStore.ts b/src/platform/updates/common/releaseStore.ts index 294c9476f..3e2849259 100644 --- a/src/platform/updates/common/releaseStore.ts +++ b/src/platform/updates/common/releaseStore.ts @@ -3,6 +3,7 @@ import { defineStore } from 'pinia' import { compare } from 'semver' import { computed, ref } from 'vue' +import { isCloud } from '@/platform/distribution/types' import { useSettingStore } from '@/platform/settings/settingStore' import { useSystemStatsStore } from '@/stores/systemStatsStore' import { isElectron } from '@/utils/envUtil' @@ -81,7 +82,7 @@ export const useReleaseStore = defineStore('release', () => { // Show toast if needed const shouldShowToast = computed(() => { // Only show on desktop version - if (!isElectron()) { + if (!isElectron() || isCloud) { return false } @@ -113,7 +114,7 @@ export const useReleaseStore = defineStore('release', () => { // Show red-dot indicator const shouldShowRedDot = computed(() => { // Only show on desktop version - if (!isElectron()) { + if (!isElectron() || isCloud) { return false } @@ -160,7 +161,7 @@ export const useReleaseStore = defineStore('release', () => { // Show "What's New" popup const shouldShowPopup = computed(() => { // Only show on desktop version - if (!isElectron()) { + if (!isElectron() || isCloud) { return false } From d8657aaee324f3e30eda1618d3f409682287994e Mon Sep 17 00:00:00 2001 From: Alexander Brown Date: Mon, 27 Oct 2025 14:53:52 -0700 Subject: [PATCH 007/115] devex: Add some acronyms (#6335) ## Summary Suggested by @arjansingh, encourage the LLMs to consider more classic practices. --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 0b187fbfc..4866c2dce 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -62,6 +62,11 @@ Key Nx features: ## Project Philosophy +- Follow good software engineering principles + - YAGNI + - AHA + - DRY + - SOLID - Clean, stable public APIs - Domain-driven design - Thousands of users and extensions From d26309c7abba9a0eaa566e498be5d4c986853800 Mon Sep 17 00:00:00 2001 From: Arjan Singh <1598641+arjansingh@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:08:33 -0700 Subject: [PATCH 008/115] feat(historyV2): create sythetic queue priority (#6336) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Create display priority based on execution success timestamps. Next up is displaying in progress prompts in the queue. ## Review Focus @DrJKL and I discussed logic and decided for history, execution success (when the prompt finishes) is the best way to assign priority. This does differ from existing cloud logic which uses execution start time. For prompt progress I intend to create a priority for them based on start time. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6336-feat-historyV2-create-sythetic-queue-priority-2996d73d365081ffa3a0f8071c178066) by [Unito](https://www.unito.io) --- .../comfyui/history/adapters/v2ToV1Adapter.ts | 57 +++-- tests-ui/fixtures/historyFixtures.ts | 13 +- tests-ui/fixtures/historySortingFixtures.ts | 199 ++++++++++++++++++ .../history/adapters/v2ToV1Adapter.test.ts | 72 ++++++- 4 files changed, 318 insertions(+), 23 deletions(-) create mode 100644 tests-ui/fixtures/historySortingFixtures.ts diff --git a/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.ts b/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.ts index 5b0e9f266..bf3cbdcfb 100644 --- a/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.ts +++ b/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.ts @@ -1,10 +1,7 @@ /** * @fileoverview Adapter to convert V2 history format to V1 format * @module platform/remote/comfyui/history/adapters/v2ToV1Adapter - * - * Converts cloud API V2 response format to the V1 format expected by the app. */ - import type { HistoryTaskItem, TaskPrompt } from '../types/historyV1Types' import type { HistoryResponseV2, @@ -13,31 +10,55 @@ import type { TaskPromptV2 } from '../types/historyV2Types' -/** - * Maps V2 prompt format to V1 prompt tuple format. - */ function mapPromptV2toV1( promptV2: TaskPromptV2, - outputs: TaskOutput + outputs: TaskOutput, + syntheticPriority: number ): TaskPrompt { - const outputNodesIds = Object.keys(outputs) - const { priority, prompt_id, extra_data } = promptV2 - return [priority, prompt_id, {}, extra_data, outputNodesIds] + return [ + syntheticPriority, + promptV2.prompt_id, + {}, + promptV2.extra_data, + Object.keys(outputs) + ] +} + +function getExecutionSuccessTimestamp(item: RawHistoryItemV2): number { + return ( + item.status?.messages?.find((m) => m[0] === 'execution_success')?.[1] + ?.timestamp ?? 0 + ) } -/** - * Maps V2 history format to V1 history format. - */ export function mapHistoryV2toHistory( historyV2Response: HistoryResponseV2 ): HistoryTaskItem[] { - return historyV2Response.history.map( - ({ prompt, status, outputs, meta }: RawHistoryItemV2): HistoryTaskItem => ({ + const history = historyV2Response.history + + // Sort by execution_success timestamp, descending (newest first) + history.sort((a, b) => { + return getExecutionSuccessTimestamp(b) - getExecutionSuccessTimestamp(a) + }) + + // Count items with valid timestamps for synthetic priority calculation + const countWithTimestamps = history.filter( + (item) => getExecutionSuccessTimestamp(item) > 0 + ).length + + return history.map((item, index): HistoryTaskItem => { + const { prompt, outputs, status, meta } = item + const timestamp = getExecutionSuccessTimestamp(item) + + // Items with timestamps get priority based on sorted position (highest first) + const syntheticPriority = timestamp > 0 ? countWithTimestamps - index : 0 + + return { taskType: 'History' as const, - prompt: mapPromptV2toV1(prompt, outputs), + prompt: mapPromptV2toV1(prompt, outputs, syntheticPriority), status, outputs, meta - }) - ) + } + }) } diff --git a/tests-ui/fixtures/historyFixtures.ts b/tests-ui/fixtures/historyFixtures.ts index 5ae3ff998..3a930a1ad 100644 --- a/tests-ui/fixtures/historyFixtures.ts +++ b/tests-ui/fixtures/historyFixtures.ts @@ -233,12 +233,17 @@ export const historyV2Fixture: HistoryResponseV2 = { /** * Expected V1 transformation of historyV2Fixture + * Priority is now synthetic based on execution_success timestamp: + * - complete-item-id: has timestamp → priority 1 (only one with timestamp) + * - no-status-id: no status → priority 0 + * - no-meta-id: empty messages → priority 0 + * - multi-output-id: empty messages → priority 0 */ export const expectedV1Fixture: HistoryTaskItem[] = [ { taskType: 'History', prompt: [ - 24, + 1, 'complete-item-id', {}, { @@ -295,7 +300,7 @@ export const expectedV1Fixture: HistoryTaskItem[] = [ { taskType: 'History', prompt: [ - 23, + 0, 'no-status-id', {}, { @@ -319,7 +324,7 @@ export const expectedV1Fixture: HistoryTaskItem[] = [ { taskType: 'History', prompt: [ - 22, + 0, 'no-meta-id', {}, { @@ -342,7 +347,7 @@ export const expectedV1Fixture: HistoryTaskItem[] = [ { taskType: 'History', prompt: [ - 21, + 0, 'multi-output-id', {}, { diff --git a/tests-ui/fixtures/historySortingFixtures.ts b/tests-ui/fixtures/historySortingFixtures.ts new file mode 100644 index 000000000..797aec243 --- /dev/null +++ b/tests-ui/fixtures/historySortingFixtures.ts @@ -0,0 +1,199 @@ +/** + * @fileoverview Test fixtures for history V2 timestamp-based sorting + */ +import type { HistoryResponseV2 } from '@/platform/remote/comfyui/history/types/historyV2Types' + +export const historyV2WithMissingTimestamp: HistoryResponseV2 = { + history: [ + { + prompt_id: 'item-timestamp-1000', + prompt: { + priority: 0, + prompt_id: 'item-timestamp-1000', + extra_data: { + client_id: 'test-client' + } + }, + outputs: { + '1': { + images: [{ filename: 'test1.png', type: 'output', subfolder: '' }] + } + }, + status: { + status_str: 'success', + completed: true, + messages: [ + [ + 'execution_success', + { prompt_id: 'item-timestamp-1000', timestamp: 1000 } + ] + ] + } + }, + { + prompt_id: 'item-timestamp-2000', + prompt: { + priority: 0, + prompt_id: 'item-timestamp-2000', + extra_data: { + client_id: 'test-client' + } + }, + outputs: { + '2': { + images: [{ filename: 'test2.png', type: 'output', subfolder: '' }] + } + }, + status: { + status_str: 'success', + completed: true, + messages: [ + [ + 'execution_success', + { prompt_id: 'item-timestamp-2000', timestamp: 2000 } + ] + ] + } + }, + { + prompt_id: 'item-no-timestamp', + prompt: { + priority: 0, + prompt_id: 'item-no-timestamp', + extra_data: { + client_id: 'test-client' + } + }, + outputs: { + '3': { + images: [{ filename: 'test3.png', type: 'output', subfolder: '' }] + } + }, + status: { + status_str: 'success', + completed: true, + messages: [] + } + } + ] +} + +export const historyV2FiveItemsSorting: HistoryResponseV2 = { + history: [ + { + prompt_id: 'item-timestamp-3000', + prompt: { + priority: 0, + prompt_id: 'item-timestamp-3000', + extra_data: { client_id: 'test-client' } + }, + outputs: { + '1': { + images: [{ filename: 'test1.png', type: 'output', subfolder: '' }] + } + }, + status: { + status_str: 'success', + completed: true, + messages: [ + [ + 'execution_success', + { prompt_id: 'item-timestamp-3000', timestamp: 3000 } + ] + ] + } + }, + { + prompt_id: 'item-timestamp-1000', + prompt: { + priority: 0, + prompt_id: 'item-timestamp-1000', + extra_data: { client_id: 'test-client' } + }, + outputs: { + '2': { + images: [{ filename: 'test2.png', type: 'output', subfolder: '' }] + } + }, + status: { + status_str: 'success', + completed: true, + messages: [ + [ + 'execution_success', + { prompt_id: 'item-timestamp-1000', timestamp: 1000 } + ] + ] + } + }, + { + prompt_id: 'item-timestamp-5000', + prompt: { + priority: 0, + prompt_id: 'item-timestamp-5000', + extra_data: { client_id: 'test-client' } + }, + outputs: { + '3': { + images: [{ filename: 'test3.png', type: 'output', subfolder: '' }] + } + }, + status: { + status_str: 'success', + completed: true, + messages: [ + [ + 'execution_success', + { prompt_id: 'item-timestamp-5000', timestamp: 5000 } + ] + ] + } + }, + { + prompt_id: 'item-timestamp-2000', + prompt: { + priority: 0, + prompt_id: 'item-timestamp-2000', + extra_data: { client_id: 'test-client' } + }, + outputs: { + '4': { + images: [{ filename: 'test4.png', type: 'output', subfolder: '' }] + } + }, + status: { + status_str: 'success', + completed: true, + messages: [ + [ + 'execution_success', + { prompt_id: 'item-timestamp-2000', timestamp: 2000 } + ] + ] + } + }, + { + prompt_id: 'item-timestamp-4000', + prompt: { + priority: 0, + prompt_id: 'item-timestamp-4000', + extra_data: { client_id: 'test-client' } + }, + outputs: { + '5': { + images: [{ filename: 'test5.png', type: 'output', subfolder: '' }] + } + }, + status: { + status_str: 'success', + completed: true, + messages: [ + [ + 'execution_success', + { prompt_id: 'item-timestamp-4000', timestamp: 4000 } + ] + ] + } + } + ] +} diff --git a/tests-ui/tests/platform/remote/comfyui/history/adapters/v2ToV1Adapter.test.ts b/tests-ui/tests/platform/remote/comfyui/history/adapters/v2ToV1Adapter.test.ts index f77a5e158..0d6cef8c2 100644 --- a/tests-ui/tests/platform/remote/comfyui/history/adapters/v2ToV1Adapter.test.ts +++ b/tests-ui/tests/platform/remote/comfyui/history/adapters/v2ToV1Adapter.test.ts @@ -11,6 +11,10 @@ import { expectedV1Fixture, historyV2Fixture } from '@tests-ui/fixtures/historyFixtures' +import { + historyV2FiveItemsSorting, + historyV2WithMissingTimestamp +} from '@tests-ui/fixtures/historySortingFixtures' describe('mapHistoryV2toHistory', () => { describe('fixture validation', () => { @@ -38,7 +42,7 @@ describe('mapHistoryV2toHistory', () => { it('should transform prompt to V1 tuple [priority, id, {}, extra_data, outputNodeIds]', () => { const firstItem = history[0] - expect(firstItem.prompt[0]).toBe(24) + expect(firstItem.prompt[0]).toBe(1) // Synthetic priority based on timestamp expect(firstItem.prompt[1]).toBe('complete-item-id') expect(firstItem.prompt[2]).toEqual({}) // history v2 does not return this data expect(firstItem.prompt[3]).toMatchObject({ client_id: 'test-client' }) @@ -117,4 +121,70 @@ describe('mapHistoryV2toHistory', () => { expect(history[0].prompt[3].client_id).toBeUndefined() }) }) + + describe('timestamp-based priority assignment', () => { + it('assigns priority 0 to items without execution_success timestamp', () => { + const result = mapHistoryV2toHistory(historyV2WithMissingTimestamp) + + expect(result).toHaveLength(3) + + const item1000 = result.find( + (item) => item.prompt[1] === 'item-timestamp-1000' + ) + const item2000 = result.find( + (item) => item.prompt[1] === 'item-timestamp-2000' + ) + const itemNoTimestamp = result.find( + (item) => item.prompt[1] === 'item-no-timestamp' + ) + + expect(item1000).toBeDefined() + expect(item2000).toBeDefined() + expect(itemNoTimestamp).toBeDefined() + if (!item1000 || !item2000 || !itemNoTimestamp) { + throw new Error('Expected items not found in result') + } + + expect(item2000.prompt[0]).toBe(2) + expect(item1000.prompt[0]).toBe(1) + expect(itemNoTimestamp.prompt[0]).toBe(0) + }) + + it('correctly sorts and assigns priorities for multiple items', () => { + const result = mapHistoryV2toHistory(historyV2FiveItemsSorting) + + expect(result).toHaveLength(5) + + const item1000 = result.find( + (item) => item.prompt[1] === 'item-timestamp-1000' + ) + const item2000 = result.find( + (item) => item.prompt[1] === 'item-timestamp-2000' + ) + const item3000 = result.find( + (item) => item.prompt[1] === 'item-timestamp-3000' + ) + const item4000 = result.find( + (item) => item.prompt[1] === 'item-timestamp-4000' + ) + const item5000 = result.find( + (item) => item.prompt[1] === 'item-timestamp-5000' + ) + + expect(item1000).toBeDefined() + expect(item2000).toBeDefined() + expect(item3000).toBeDefined() + expect(item4000).toBeDefined() + expect(item5000).toBeDefined() + if (!item1000 || !item2000 || !item3000 || !item4000 || !item5000) { + throw new Error('Expected items not found in result') + } + + expect(item5000.prompt[0]).toBe(5) + expect(item4000.prompt[0]).toBe(4) + expect(item3000.prompt[0]).toBe(3) + expect(item2000.prompt[0]).toBe(2) + expect(item1000.prompt[0]).toBe(1) + }) + }) }) From d1c9ce5a6627a68c4752c587b92a360bb029bfd0 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Mon, 27 Oct 2025 16:57:00 -0700 Subject: [PATCH 009/115] change some settings for cloud-specific behavior (#6302) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Make some settings dynamic based on whether in cloud or localhost 1. Comfy.Memory.AllowManualUnload (line 18-24) - Type: 'hidden' on cloud, 'boolean' on localhost - Default: false on cloud, true on localhost 2. Comfy.Validation.Workflows (line 25-30) - Default: false on cloud, true on localhost 3. Comfy.Workflow.ShowMissingModelsWarning (line 282-288) - Type: 'hidden' on cloud, 'boolean' on localhost - Default: false on cloud, true on localhost 4. Comfy.ModelLibrary.AutoLoadAll (line 387-394) - Type: 'hidden' on cloud, 'boolean' on localhost 5. Comfy.QueueButton.BatchCountLimit (line 595-603) - Default: 4 on cloud, 100 on localhost 6. Comfy.Toast.DisableReconnectingToast (line 943-949) - Default: true on cloud, false on localhost 7. Comfy.Assets.UseAssetAPI (line 1068-1075) - Default: true on cloud, false on localhost ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6302-change-some-settings-for-cloud-specific-behavior-2986d73d365081169be4ebd11823a7fa) by [Unito](https://www.unito.io) --- src/platform/settings/constants/coreSettings.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/platform/settings/constants/coreSettings.ts b/src/platform/settings/constants/coreSettings.ts index 916d2e8fa..dbb4a2510 100644 --- a/src/platform/settings/constants/coreSettings.ts +++ b/src/platform/settings/constants/coreSettings.ts @@ -1,4 +1,5 @@ import { LinkMarkerShape, LiteGraph } from '@/lib/litegraph/src/litegraph' +import { isCloud } from '@/platform/distribution/types' import { useSettingStore } from '@/platform/settings/settingStore' import type { SettingParams } from '@/platform/settings/types' import type { ColorPalettes } from '@/schemas/colorPaletteSchema' @@ -18,14 +19,14 @@ export const CORE_SETTINGS: SettingParams[] = [ id: 'Comfy.Memory.AllowManualUnload', name: 'Allow manual unload of models and execution cache via user command', type: 'hidden', - defaultValue: true, + defaultValue: isCloud ? false : true, versionAdded: '1.18.0' }, { id: 'Comfy.Validation.Workflows', name: 'Validate workflows', type: 'boolean', - defaultValue: true + defaultValue: isCloud ? false : true }, { id: 'Comfy.NodeSearchBoxImpl', @@ -281,8 +282,8 @@ export const CORE_SETTINGS: SettingParams[] = [ { id: 'Comfy.Workflow.ShowMissingModelsWarning', name: 'Show missing models warning', - type: 'boolean', - defaultValue: true, + type: isCloud ? 'hidden' : 'boolean', + defaultValue: isCloud ? false : true, experimental: true }, { @@ -388,7 +389,7 @@ export const CORE_SETTINGS: SettingParams[] = [ name: 'Automatically load all model folders', tooltip: 'If true, all folders will load as soon as you open the model library (this may cause delays while it loads). If false, root level model folders will only load once you click on them.', - type: 'boolean', + type: isCloud ? 'hidden' : 'boolean', defaultValue: false }, { @@ -597,7 +598,7 @@ export const CORE_SETTINGS: SettingParams[] = [ tooltip: 'The maximum number of tasks added to the queue at one button click', type: 'number', - defaultValue: 100, + defaultValue: isCloud ? 4 : 100, versionAdded: '1.3.5' }, { @@ -943,7 +944,7 @@ export const CORE_SETTINGS: SettingParams[] = [ id: 'Comfy.Toast.DisableReconnectingToast', name: 'Disable toasts when reconnecting or reconnected', type: 'hidden', - defaultValue: false, + defaultValue: isCloud ? true : false, versionAdded: '1.15.12' }, { @@ -1069,7 +1070,7 @@ export const CORE_SETTINGS: SettingParams[] = [ name: 'Use Asset API for model library', type: 'hidden', tooltip: 'Use new Asset API for model browsing', - defaultValue: false, + defaultValue: isCloud ? true : false, experimental: true } ] From 6afdb9529d9528bd8143de9c61893508862c208f Mon Sep 17 00:00:00 2001 From: Alexander Brown Date: Mon, 27 Oct 2025 19:36:19 -0700 Subject: [PATCH 010/115] Fix: Vue-Litegraph conversion bug with Reroutes (#6330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary The private fields triggered an error in intitializing the linkLayoutSync. Turns out that wasn't necessary anymore. > [!NOTE] > Edit: Doing some more investigation, it looks like the slot sync can also be removed? ## Changes - **What**: Converts JS private fields to typescript private, adds some readonly declarations - **What**: Removes the useLinkLayoutSync usage in useVueNodeLifecycle - **What**: Removes the useSlotLayoutSync usage in useVueNodeLifecycle ## Review Focus Was the sync doing something that wouldn't be caught in normal usage/testing? ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6330-Fix-Vue-Litegraph-conversion-bug-with-Reroutes-2996d73d3650819ebb24e4aa2fc51c65) by [Unito](https://www.unito.io) --- .gitattributes | 1 + knip.config.ts | 2 +- src/composables/graph/useVueNodeLifecycle.ts | 29 +- src/lib/litegraph/src/LGraph.ts | 14 +- src/lib/litegraph/src/Reroute.ts | 136 ++++---- src/renderer/core/layout/slots/register.ts | 75 ----- .../core/layout/sync/useLinkLayoutSync.ts | 310 ------------------ .../core/layout/sync/useSlotLayoutSync.ts | 150 --------- .../core/__snapshots__/LGraph.test.ts.snap | 2 + 9 files changed, 82 insertions(+), 637 deletions(-) delete mode 100644 src/renderer/core/layout/slots/register.ts delete mode 100644 src/renderer/core/layout/sync/useLinkLayoutSync.ts delete mode 100644 src/renderer/core/layout/sync/useSlotLayoutSync.ts diff --git a/.gitattributes b/.gitattributes index 0f538ae76..39d7f722c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,6 +7,7 @@ *.json text eol=lf *.mjs text eol=lf *.mts text eol=lf +*.snap text eol=lf *.ts text eol=lf *.vue text eol=lf *.yaml text eol=lf diff --git a/knip.config.ts b/knip.config.ts index 3bc025cad..a77574f97 100644 --- a/knip.config.ts +++ b/knip.config.ts @@ -14,7 +14,7 @@ const config: KnipConfig = { }, 'apps/desktop-ui': { entry: ['src/main.ts', 'src/i18n.ts'], - project: ['src/**/*.{js,ts,vue}', '*.{js,ts,mts}'] + project: ['src/**/*.{js,ts,vue}'] }, 'packages/tailwind-utils': { project: ['src/**/*.{js,ts}'] diff --git a/src/composables/graph/useVueNodeLifecycle.ts b/src/composables/graph/useVueNodeLifecycle.ts index cfcee1d44..2b32e51bf 100644 --- a/src/composables/graph/useVueNodeLifecycle.ts +++ b/src/composables/graph/useVueNodeLifecycle.ts @@ -4,13 +4,11 @@ import { shallowRef, watch } from 'vue' import { useGraphNodeManager } from '@/composables/graph/useGraphNodeManager' import type { GraphNodeManager } from '@/composables/graph/useGraphNodeManager' import { useVueFeatureFlags } from '@/composables/useVueFeatureFlags' -import type { LGraphCanvas, LGraphNode } from '@/lib/litegraph/src/litegraph' +import type { LGraphNode } from '@/lib/litegraph/src/litegraph' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMutations' import { layoutStore } from '@/renderer/core/layout/store/layoutStore' import { useLayoutSync } from '@/renderer/core/layout/sync/useLayoutSync' -import { useLinkLayoutSync } from '@/renderer/core/layout/sync/useLinkLayoutSync' -import { useSlotLayoutSync } from '@/renderer/core/layout/sync/useSlotLayoutSync' import { app as comfyApp } from '@/scripts/app' function useVueNodeLifecycleIndividual() { @@ -21,8 +19,6 @@ function useVueNodeLifecycleIndividual() { const nodeManager = shallowRef(null) const { startSync } = useLayoutSync() - const linkSyncManager = useLinkLayoutSync() - const slotSyncManager = useSlotLayoutSync() const initializeNodeManager = () => { // Use canvas graph if available (handles subgraph contexts), fallback to app graph @@ -62,10 +58,6 @@ function useVueNodeLifecycleIndividual() { // Initialize layout sync (one-way: Layout Store → LiteGraph) startSync(canvasStore.canvas) - - if (comfyApp.canvas) { - linkSyncManager.start(comfyApp.canvas) - } } const disposeNodeManagerAndSyncs = () => { @@ -77,8 +69,6 @@ function useVueNodeLifecycleIndividual() { /* empty */ } nodeManager.value = null - - linkSyncManager.stop() } // Watch for Vue nodes enabled state changes @@ -96,25 +86,14 @@ function useVueNodeLifecycleIndividual() { // Consolidated watch for slot layout sync management watch( - [() => canvasStore.canvas, () => shouldRenderVueNodes.value], - ([canvas, vueMode], [, oldVueMode]) => { + () => shouldRenderVueNodes.value, + (vueMode, oldVueMode) => { const modeChanged = vueMode !== oldVueMode // Clear stale slot layouts when switching modes if (modeChanged) { layoutStore.clearAllSlotLayouts() } - - // Switching to Vue - if (vueMode) { - slotSyncManager.stop() - } - - // Switching to LG - const shouldRun = Boolean(canvas?.graph) && !vueMode - if (shouldRun && canvas) { - slotSyncManager.attemptStart(canvas as LGraphCanvas) - } }, { immediate: true, flush: 'sync' } ) @@ -152,8 +131,6 @@ function useVueNodeLifecycleIndividual() { nodeManager.value.cleanup() nodeManager.value = null } - slotSyncManager.stop() - linkSyncManager.stop() } return { diff --git a/src/lib/litegraph/src/LGraph.ts b/src/lib/litegraph/src/LGraph.ts index b588baa74..4c7b1ff2a 100644 --- a/src/lib/litegraph/src/LGraph.ts +++ b/src/lib/litegraph/src/LGraph.ts @@ -223,15 +223,15 @@ export class LGraph /** Internal only. Not required for serialisation; calculated on deserialise. */ #lastFloatingLinkId: number = 0 - #floatingLinks: Map = new Map() + private readonly floatingLinksInternal: Map = new Map() get floatingLinks(): ReadonlyMap { - return this.#floatingLinks + return this.floatingLinksInternal } - #reroutes = new Map() + private readonly reroutesInternal = new Map() /** All reroutes in this graph. */ public get reroutes(): Map { - return this.#reroutes + return this.reroutesInternal } get rootGraph(): LGraph { @@ -340,7 +340,7 @@ export class LGraph this._links.clear() this.reroutes.clear() - this.#floatingLinks.clear() + this.floatingLinksInternal.clear() this.#lastFloatingLinkId = 0 @@ -1268,7 +1268,7 @@ export class LGraph if (link.id === -1) { link.id = ++this.#lastFloatingLinkId } - this.#floatingLinks.set(link.id, link) + this.floatingLinksInternal.set(link.id, link) const slot = link.target_id !== -1 @@ -1291,7 +1291,7 @@ export class LGraph } removeFloatingLink(link: LLink): void { - this.#floatingLinks.delete(link.id) + this.floatingLinksInternal.delete(link.id) const slot = link.target_id !== -1 diff --git a/src/lib/litegraph/src/Reroute.ts b/src/lib/litegraph/src/Reroute.ts index 348289709..6436df532 100644 --- a/src/lib/litegraph/src/Reroute.ts +++ b/src/lib/litegraph/src/Reroute.ts @@ -51,31 +51,31 @@ export class Reroute } /** The network this reroute belongs to. Contains all valid links and reroutes. */ - #network: WeakRef + private readonly network: WeakRef - #parentId?: RerouteId + private parentIdInternal?: RerouteId public get parentId(): RerouteId | undefined { - return this.#parentId + return this.parentIdInternal } /** Ignores attempts to create an infinite loop. @inheritdoc */ public set parentId(value) { if (value === this.id) return if (this.getReroutes() === null) return - this.#parentId = value + this.parentIdInternal = value } public get parent(): Reroute | undefined { - return this.#network.deref()?.getReroute(this.#parentId) + return this.network.deref()?.getReroute(this.parentIdInternal) } /** This property is only defined on the last reroute of a floating reroute chain (closest to input end). */ floating?: FloatingRerouteSlot - #pos: Point = [0, 0] + private readonly posInternal: Point = [0, 0] /** @inheritdoc */ get pos(): Point { - return this.#pos + return this.posInternal } set pos(value: Point) { @@ -83,14 +83,14 @@ export class Reroute throw new TypeError( 'Reroute.pos is an x,y point, and expects an indexable with at least two values.' ) - this.#pos[0] = value[0] - this.#pos[1] = value[1] + this.posInternal[0] = value[0] + this.posInternal[1] = value[1] } /** @inheritdoc */ get boundingRect(): ReadOnlyRect { const { radius } = Reroute - const [x, y] = this.#pos + const [x, y] = this.posInternal return [x - radius, y - radius, 2 * radius, 2 * radius] } @@ -98,11 +98,11 @@ export class Reroute * Slightly over-sized rectangle, guaranteed to contain the entire surface area for hover detection. * Eliminates most hover positions using an extremely cheap check. */ - get #hoverArea(): ReadOnlyRect { + private get hoverArea(): ReadOnlyRect { const xOffset = 2 * Reroute.slotOffset const yOffset = 2 * Math.max(Reroute.radius, Reroute.slotRadius) - const [x, y] = this.#pos + const [x, y] = this.posInternal return [x - xOffset, y - yOffset, 2 * xOffset, 2 * yOffset] } @@ -149,35 +149,35 @@ export class Reroute * Used to ensure reroute angles are only executed once per frame. * @todo Calculate on change instead. */ - #lastRenderTime: number = -Infinity + private lastRenderTime: number = -Infinity - #inputSlot = new RerouteSlot(this, true) - #outputSlot = new RerouteSlot(this, false) + private readonly inputSlot = new RerouteSlot(this, true) + private readonly outputSlot = new RerouteSlot(this, false) get isSlotHovered(): boolean { return this.isInputHovered || this.isOutputHovered } get isInputHovered(): boolean { - return this.#inputSlot.hovering + return this.inputSlot.hovering } get isOutputHovered(): boolean { - return this.#outputSlot.hovering + return this.outputSlot.hovering } get firstLink(): LLink | undefined { const linkId = this.linkIds.values().next().value return linkId === undefined ? undefined - : this.#network.deref()?.links.get(linkId) + : this.network.deref()?.links.get(linkId) } get firstFloatingLink(): LLink | undefined { const linkId = this.floatingLinkIds.values().next().value return linkId === undefined ? undefined - : this.#network.deref()?.floatingLinks.get(linkId) + : this.network.deref()?.floatingLinks.get(linkId) } /** @inheritdoc */ @@ -205,7 +205,7 @@ export class Reroute linkIds?: Iterable, floatingLinkIds?: Iterable ) { - this.#network = new WeakRef(network) + this.network = new WeakRef(network) this.parentId = parentId if (pos) this.pos = pos this.linkIds = new Set(linkIds) @@ -261,15 +261,15 @@ export class Reroute */ getReroutes(visited = new Set()): Reroute[] | null { // No parentId - last in the chain - if (this.#parentId === undefined) return [this] + if (this.parentIdInternal === undefined) return [this] // Invalid chain - looped if (visited.has(this)) return null visited.add(this) - const parent = this.#network.deref()?.reroutes.get(this.#parentId) + const parent = this.network.deref()?.reroutes.get(this.parentIdInternal) // Invalid parent (or network) - drop silently to recover if (!parent) { - this.#parentId = undefined + this.parentIdInternal = undefined return [this] } @@ -288,14 +288,14 @@ export class Reroute withParentId: RerouteId, visited = new Set() ): Reroute | null | undefined { - if (this.#parentId === withParentId) return this + if (this.parentIdInternal === withParentId) return this if (visited.has(this)) return null visited.add(this) - if (this.#parentId === undefined) return + if (this.parentIdInternal === undefined) return - return this.#network + return this.network .deref() - ?.reroutes.get(this.#parentId) + ?.reroutes.get(this.parentIdInternal) ?.findNextReroute(withParentId, visited) } @@ -309,7 +309,7 @@ export class Reroute const link = this.firstLink ?? this.firstFloatingLink if (!link) return - const node = this.#network.deref()?.getNodeById(link.origin_id) + const node = this.network.deref()?.getNodeById(link.origin_id) if (!node) return return { @@ -325,7 +325,7 @@ export class Reroute findTargetInputs(): | { node: LGraphNode; input: INodeInputSlot; link: LLink }[] | undefined { - const network = this.#network.deref() + const network = this.network.deref() if (!network) return const results: { @@ -363,7 +363,7 @@ export class Reroute * @returns An array of floating links */ getFloatingLinks(from: 'input' | 'output'): LLink[] | undefined { - const floatingLinks = this.#network.deref()?.floatingLinks + const floatingLinks = this.network.deref()?.floatingLinks if (!floatingLinks) return const idProp = from === 'input' ? 'origin_id' : 'target_id' @@ -387,7 +387,7 @@ export class Reroute output: INodeOutputSlot, index: number ) { - const network = this.#network.deref() + const network = this.network.deref() const floatingOutLinks = this.getFloatingLinks('output') if (!floatingOutLinks) throw new Error('[setFloatingLinkOrigin]: Invalid network.') @@ -411,15 +411,15 @@ export class Reroute /** @inheritdoc */ move(deltaX: number, deltaY: number) { - const previousPos = { x: this.#pos[0], y: this.#pos[1] } - this.#pos[0] += deltaX - this.#pos[1] += deltaY + const previousPos = { x: this.posInternal[0], y: this.posInternal[1] } + this.posInternal[0] += deltaX + this.posInternal[1] += deltaY // Update Layout Store with new position layoutMutations.setSource(LayoutSource.Canvas) layoutMutations.moveReroute( this.id, - { x: this.#pos[0], y: this.#pos[1] }, + { x: this.posInternal[0], y: this.posInternal[1] }, previousPos ) } @@ -441,7 +441,7 @@ export class Reroute } removeFloatingLink(linkId: LinkId) { - const network = this.#network.deref() + const network = this.network.deref() if (!network) return const floatingLink = network.floatingLinks.get(linkId) @@ -462,7 +462,7 @@ export class Reroute * @remarks Does not remove the link from the network. */ removeLink(link: LLink) { - const network = this.#network.deref() + const network = this.network.deref() if (!network) return const floatingLink = network.floatingLinks.get(link.id) @@ -474,7 +474,7 @@ export class Reroute } remove() { - const network = this.#network.deref() + const network = this.network.deref() if (!network) return network.removeReroute(this.id) @@ -486,8 +486,8 @@ export class Reroute linkStart: Point ): void { // Ensure we run once per render - if (!(lastRenderTime > this.#lastRenderTime)) return - this.#lastRenderTime = lastRenderTime + if (!(lastRenderTime > this.lastRenderTime)) return + this.lastRenderTime = lastRenderTime const { id, pos: thisPos } = this @@ -509,14 +509,14 @@ export class Reroute sum /= angles.length const originToReroute = Math.atan2( - this.#pos[1] - linkStart[1], - this.#pos[0] - linkStart[0] + this.posInternal[1] - linkStart[1], + this.posInternal[0] - linkStart[0] ) let diff = (originToReroute - sum) * 0.5 if (Math.abs(diff) > Math.PI * 0.5) diff += Math.PI const dist = Math.min( Reroute.maxSplineOffset, - distance(linkStart, this.#pos) * 0.25 + distance(linkStart, this.posInternal) * 0.25 ) // Store results @@ -604,8 +604,8 @@ export class Reroute * @param ctx The canvas context to draw on. */ drawSlots(ctx: CanvasRenderingContext2D): void { - this.#inputSlot.draw(ctx) - this.#outputSlot.draw(ctx) + this.inputSlot.draw(ctx) + this.outputSlot.draw(ctx) } drawHighlight(ctx: CanvasRenderingContext2D, colour: CanvasColour): void { @@ -629,8 +629,8 @@ export class Reroute * @returns `true` if any changes require a redraw. */ updateVisibility(pos: Point): boolean { - const input = this.#inputSlot - const output = this.#outputSlot + const input = this.inputSlot + const output = this.outputSlot input.dirty = false output.dirty = false @@ -642,8 +642,8 @@ export class Reroute const showEither = showInput || showOutput // Check if even in the vicinity - if (showEither && isPointInRect(pos, this.#hoverArea)) { - const outlineOnly = this.#contains(pos) + if (showEither && isPointInRect(pos, this.hoverArea)) { + const outlineOnly = this.contains(pos) if (showInput) input.update(pos, outlineOnly) if (showOutput) output.update(pos, outlineOnly) @@ -656,8 +656,8 @@ export class Reroute /** Prevents rendering of the input and output slots. */ hideSlots() { - this.#inputSlot.hide() - this.#outputSlot.hide() + this.inputSlot.hide() + this.outputSlot.hide() } /** @@ -666,10 +666,10 @@ export class Reroute * @returns `true` if {@link pos} is within the reroute's radius. */ containsPoint(pos: Point): boolean { - return isPointInRect(pos, this.#hoverArea) && this.#contains(pos) + return isPointInRect(pos, this.hoverArea) && this.contains(pos) } - #contains(pos: Point): boolean { + private contains(pos: Point): boolean { return distance(this.pos, pos) <= Reroute.radius } @@ -692,47 +692,47 @@ export class Reroute */ class RerouteSlot { /** The reroute that the slot belongs to. */ - readonly #reroute: Reroute + private readonly reroute: Reroute - readonly #offsetMultiplier: 1 | -1 + private readonly offsetMultiplier: 1 | -1 /** Centre point of this slot. */ get pos(): Point { - const [x, y] = this.#reroute.pos - return [x + Reroute.slotOffset * this.#offsetMultiplier, y] + const [x, y] = this.reroute.pos + return [x + Reroute.slotOffset * this.offsetMultiplier, y] } /** Whether any changes require a redraw. */ dirty: boolean = false - #hovering = false + private hoveringInternal = false /** Whether the pointer is hovering over the slot itself. */ get hovering() { - return this.#hovering + return this.hoveringInternal } set hovering(value) { - if (!Object.is(this.#hovering, value)) { - this.#hovering = value + if (!Object.is(this.hoveringInternal, value)) { + this.hoveringInternal = value this.dirty = true } } - #showOutline = false + private showOutlineInternal = false /** Whether the slot outline / faint background is visible. */ get showOutline() { - return this.#showOutline + return this.showOutlineInternal } set showOutline(value) { - if (!Object.is(this.#showOutline, value)) { - this.#showOutline = value + if (!Object.is(this.showOutlineInternal, value)) { + this.showOutlineInternal = value this.dirty = true } } constructor(reroute: Reroute, isInput: boolean) { - this.#reroute = reroute - this.#offsetMultiplier = isInput ? -1 : 1 + this.reroute = reroute + this.offsetMultiplier = isInput ? -1 : 1 } /** @@ -771,7 +771,7 @@ class RerouteSlot { if (!showOutline) return try { - ctx.fillStyle = hovering ? this.#reroute.colour : 'rgba(127,127,127,0.3)' + ctx.fillStyle = hovering ? this.reroute.colour : 'rgba(127,127,127,0.3)' ctx.strokeStyle = 'rgb(0,0,0,0.5)' ctx.lineWidth = 1 diff --git a/src/renderer/core/layout/slots/register.ts b/src/renderer/core/layout/slots/register.ts deleted file mode 100644 index 747ae4543..000000000 --- a/src/renderer/core/layout/slots/register.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Slot Registration - * - * Handles registration of slot layouts with the layout store for hit testing. - * This module manages the state mutation side of slot layout management, - * while pure calculations are handled separately in SlotCalculations.ts. - */ -import type { Point } from '@/lib/litegraph/src/interfaces' -import { LiteGraph } from '@/lib/litegraph/src/litegraph' -import { - calculateInputSlotPos, - calculateOutputSlotPos -} from '@/renderer/core/canvas/litegraph/slotCalculations' -import type { SlotPositionContext } from '@/renderer/core/canvas/litegraph/slotCalculations' -import { layoutStore } from '@/renderer/core/layout/store/layoutStore' -import type { SlotLayout } from '@/renderer/core/layout/types' - -import { getSlotKey } from './slotIdentifier' - -/** - * Register slot layout with the layout store for hit testing - * @param nodeId The node ID - * @param slotIndex The slot index - * @param isInput Whether this is an input slot - * @param position The slot position in graph coordinates - */ -function registerSlotLayout( - nodeId: string, - slotIndex: number, - isInput: boolean, - position: Point -): void { - const slotKey = getSlotKey(nodeId, slotIndex, isInput) - - // Calculate bounds for the slot using LiteGraph's standard slot height - const slotSize = LiteGraph.NODE_SLOT_HEIGHT - const halfSize = slotSize / 2 - - const slotLayout: SlotLayout = { - nodeId, - index: slotIndex, - type: isInput ? 'input' : 'output', - position: { x: position[0], y: position[1] }, - bounds: { - x: position[0] - halfSize, - y: position[1] - halfSize, - width: slotSize, - height: slotSize - } - } - - layoutStore.updateSlotLayout(slotKey, slotLayout) -} - -/** - * Register all slots for a node - * @param nodeId The node ID - * @param context The slot position context - */ -export function registerNodeSlots( - nodeId: string, - context: SlotPositionContext -): void { - // Register input slots - context.inputs.forEach((_, index) => { - const position = calculateInputSlotPos(context, index) - registerSlotLayout(nodeId, index, true, position) - }) - - // Register output slots - context.outputs.forEach((_, index) => { - const position = calculateOutputSlotPos(context, index) - registerSlotLayout(nodeId, index, false, position) - }) -} diff --git a/src/renderer/core/layout/sync/useLinkLayoutSync.ts b/src/renderer/core/layout/sync/useLinkLayoutSync.ts deleted file mode 100644 index b1cbc5fa0..000000000 --- a/src/renderer/core/layout/sync/useLinkLayoutSync.ts +++ /dev/null @@ -1,310 +0,0 @@ -import { tryOnScopeDispose } from '@vueuse/core' -import { computed, ref, toValue } from 'vue' - -import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas' -import { LLink } from '@/lib/litegraph/src/LLink' -import { Reroute } from '@/lib/litegraph/src/Reroute' -import type { Point } from '@/lib/litegraph/src/interfaces' -import { LinkDirection } from '@/lib/litegraph/src/types/globalEnums' -import { LitegraphLinkAdapter } from '@/renderer/core/canvas/litegraph/litegraphLinkAdapter' -import type { LinkRenderContext } from '@/renderer/core/canvas/litegraph/litegraphLinkAdapter' -import { getSlotPosition } from '@/renderer/core/canvas/litegraph/slotCalculations' -import { layoutStore } from '@/renderer/core/layout/store/layoutStore' -import type { LayoutChange } from '@/renderer/core/layout/types' - -export function useLinkLayoutSync() { - const canvasRef = ref() - const graphRef = computed(() => canvasRef.value?.graph) - const unsubscribeLayoutChange = ref<() => void>() - const adapter = new LitegraphLinkAdapter() - - /** - * Build link render context from canvas properties - */ - function buildLinkRenderContext(): LinkRenderContext { - const canvas = toValue(canvasRef) - if (!canvas) { - throw new Error('Canvas not initialized') - } - - return { - // Canvas settings - renderMode: canvas.links_render_mode, - connectionWidth: canvas.connections_width, - renderBorder: canvas.render_connections_border, - lowQuality: canvas.low_quality, - highQualityRender: canvas.highquality_render, - scale: canvas.ds.scale, - linkMarkerShape: canvas.linkMarkerShape, - renderConnectionArrows: canvas.render_connection_arrows, - - // State - highlightedLinks: new Set(Object.keys(canvas.highlighted_links)), - - // Colors - defaultLinkColor: canvas.default_link_color, - linkTypeColors: (canvas.constructor as any).link_type_colors || {}, - - // Pattern for disabled links - disabledPattern: canvas._pattern - } - } - - /** - * Recompute a single link and all its segments - * - * Note: This logic mirrors LGraphCanvas#renderAllLinkSegments but: - * - Works with offscreen context for event-driven updates - * - No visibility checks (always computes full geometry) - * - No dragging state handling (pure geometry computation) - */ - function recomputeLinkById(linkId: number): void { - const canvas = toValue(canvasRef) - const graph = toValue(graphRef) - if (!graph || !canvas) return - - const link = graph.links.get(linkId) - if (!link || link.id === -1) return // Skip floating/temp links - - // Get source and target nodes - const sourceNode = graph.getNodeById(link.origin_id) - const targetNode = graph.getNodeById(link.target_id) - if (!sourceNode || !targetNode) return - - // Get slots - const sourceSlot = sourceNode.outputs?.[link.origin_slot] - const targetSlot = targetNode.inputs?.[link.target_slot] - if (!sourceSlot || !targetSlot) return - - // Get positions - const startPos = getSlotPosition(sourceNode, link.origin_slot, false) - const endPos = getSlotPosition(targetNode, link.target_slot, true) - - // Get directions - const startDir = sourceSlot.dir || LinkDirection.RIGHT - const endDir = targetSlot.dir || LinkDirection.LEFT - - // Get reroutes for this link - const reroutes = LLink.getReroutes(graph, link) - - // Build render context - const context = buildLinkRenderContext() - - if (reroutes.length > 0) { - // Render segmented link with reroutes - let segmentStartPos = startPos - let segmentStartDir = startDir - - for (let i = 0; i < reroutes.length; i++) { - const reroute = reroutes[i] - - // Calculate reroute angle - reroute.calculateAngle(Date.now(), graph, [ - segmentStartPos[0], - segmentStartPos[1] - ]) - - // Calculate control points - const distance = Math.sqrt( - (reroute.pos[0] - segmentStartPos[0]) ** 2 + - (reroute.pos[1] - segmentStartPos[1]) ** 2 - ) - const dist = Math.min(Reroute.maxSplineOffset, distance * 0.25) - - // Special handling for floating input chain - const isFloatingInputChain = !sourceNode && targetNode - const startControl: Readonly = isFloatingInputChain - ? [0, 0] - : [dist * reroute.cos, dist * reroute.sin] - - // Render segment to this reroute - adapter.renderLinkDirect( - canvas.ctx, - segmentStartPos, - reroute.pos, - link, - true, // skip_border - 0, // flow - null, // color - segmentStartDir, - LinkDirection.CENTER, - context, - { - startControl, - endControl: reroute.controlPoint, - reroute, - disabled: false - } - ) - - // Prepare for next segment - segmentStartPos = reroute.pos - segmentStartDir = LinkDirection.CENTER - } - - // Render final segment from last reroute to target - const lastReroute = reroutes[reroutes.length - 1] - const finalDistance = Math.sqrt( - (endPos[0] - lastReroute.pos[0]) ** 2 + - (endPos[1] - lastReroute.pos[1]) ** 2 - ) - const finalDist = Math.min(Reroute.maxSplineOffset, finalDistance * 0.25) - const finalStartControl: Readonly = [ - finalDist * lastReroute.cos, - finalDist * lastReroute.sin - ] - - adapter.renderLinkDirect( - canvas.ctx, - lastReroute.pos, - endPos, - link, - true, // skip_border - 0, // flow - null, // color - LinkDirection.CENTER, - endDir, - context, - { - startControl: finalStartControl, - disabled: false - } - ) - } else { - // No reroutes - render direct link - adapter.renderLinkDirect( - canvas.ctx, - startPos, - endPos, - link, - true, // skip_border - 0, // flow - null, // color - startDir, - endDir, - context, - { - disabled: false - } - ) - } - } - - /** - * Recompute all links connected to a node - */ - function recomputeLinksForNode(nodeId: number): void { - const graph = toValue(graphRef) - if (!graph) return - - const node = graph.getNodeById(nodeId) - if (!node) return - - const linkIds = new Set() - - // Collect output links - if (node.outputs) { - for (const output of node.outputs) { - if (output.links) { - for (const linkId of output.links) { - linkIds.add(linkId) - } - } - } - } - - // Collect input links - if (node.inputs) { - for (const input of node.inputs) { - if (input.link !== null && input.link !== undefined) { - linkIds.add(input.link) - } - } - } - - // Recompute each link - for (const linkId of linkIds) { - recomputeLinkById(linkId) - } - } - - /** - * Recompute all links associated with a reroute - */ - function recomputeLinksForReroute(rerouteId: number): void { - const graph = toValue(graphRef) - if (!graph) return - - const reroute = graph.reroutes.get(rerouteId) - if (!reroute) return - - // Recompute all links that pass through this reroute - for (const linkId of reroute.linkIds) { - recomputeLinkById(linkId) - } - } - - /** - * Start link layout sync with event-driven functionality - */ - function start(canvasInstance: LGraphCanvas): void { - canvasRef.value = canvasInstance - if (!canvasInstance.graph) return - - // Initial computation for all existing links - for (const link of canvasInstance.graph._links.values()) { - if (link.id !== -1) { - recomputeLinkById(link.id) - } - } - - // Subscribe to layout store changes - unsubscribeLayoutChange.value?.() - unsubscribeLayoutChange.value = layoutStore.onChange( - (change: LayoutChange) => { - switch (change.operation.type) { - case 'moveNode': - case 'resizeNode': - recomputeLinksForNode(parseInt(change.operation.nodeId)) - break - case 'batchUpdateBounds': - for (const nodeId of change.operation.nodeIds) { - recomputeLinksForNode(parseInt(nodeId)) - } - break - case 'createLink': - recomputeLinkById(change.operation.linkId) - break - case 'deleteLink': - // No-op - store already cleaned by existing code - break - case 'createReroute': - case 'deleteReroute': - // Recompute all affected links - if ('linkIds' in change.operation) { - for (const linkId of change.operation.linkIds) { - recomputeLinkById(linkId) - } - } - break - case 'moveReroute': - recomputeLinksForReroute(change.operation.rerouteId) - break - } - } - ) - } - - function stop(): void { - unsubscribeLayoutChange.value?.() - unsubscribeLayoutChange.value = undefined - canvasRef.value = undefined - } - - tryOnScopeDispose(stop) - - return { - start, - stop - } -} diff --git a/src/renderer/core/layout/sync/useSlotLayoutSync.ts b/src/renderer/core/layout/sync/useSlotLayoutSync.ts deleted file mode 100644 index 6d7812dd7..000000000 --- a/src/renderer/core/layout/sync/useSlotLayoutSync.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { tryOnScopeDispose } from '@vueuse/core' -import { ref } from 'vue' - -import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas' -import type { LGraphNode } from '@/lib/litegraph/src/litegraph' -import { LiteGraph } from '@/lib/litegraph/src/litegraph' -import type { SlotPositionContext } from '@/renderer/core/canvas/litegraph/slotCalculations' -import { registerNodeSlots } from '@/renderer/core/layout/slots/register' -import { layoutStore } from '@/renderer/core/layout/store/layoutStore' - -function computeAndRegisterSlots(node: LGraphNode): void { - const nodeId = String(node.id) - const nodeLayout = layoutStore.getNodeLayoutRef(nodeId).value - - // Fallback to live node values if layout not ready - const nodeX = nodeLayout?.position.x ?? node.pos[0] - const nodeY = nodeLayout?.position.y ?? node.pos[1] - const nodeWidth = nodeLayout?.size.width ?? node.size[0] - const nodeHeight = nodeLayout?.size.height ?? node.size[1] - - // Ensure concrete slots & arrange when needed for accurate positions - node._setConcreteSlots() - const collapsed = node.flags.collapsed ?? false - if (!collapsed) { - node.arrange() - } - - const context: SlotPositionContext = { - nodeX, - nodeY, - nodeWidth, - nodeHeight, - collapsed, - collapsedWidth: node._collapsed_width, - slotStartY: node.constructor.slot_start_y, - inputs: node.inputs, - outputs: node.outputs, - widgets: node.widgets - } - - registerNodeSlots(nodeId, context) -} - -export function useSlotLayoutSync() { - const unsubscribeLayoutChange = ref<() => void>() - const restoreHandlers = ref<() => void>() - - /** - * Attempt to start slot layout sync with full event-driven functionality - * @param canvas LiteGraph canvas instance - * @returns true if sync was actually started, false if early-returned - */ - function attemptStart(canvas: LGraphCanvas): boolean { - // When Vue nodes are enabled, slot DOM registers exact positions. - // Skip calculated registration to avoid conflicts. - if (LiteGraph.vueNodesMode) { - return false - } - const graph = canvas?.graph - if (!graph) return false - - // Initial registration for all nodes in the current graph - for (const node of graph.nodes) { - computeAndRegisterSlots(node) - } - - // Layout changes → recompute slots for changed nodes - unsubscribeLayoutChange.value?.() - unsubscribeLayoutChange.value = layoutStore.onChange((change) => { - for (const nodeId of change.nodeIds) { - const node = graph.getNodeById(parseInt(nodeId)) - if (node) { - computeAndRegisterSlots(node) - } - } - }) - - // LiteGraph event hooks - const origNodeAdded = graph.onNodeAdded - const origNodeRemoved = graph.onNodeRemoved - const origTrigger = graph.onTrigger - const origAfterChange = graph.onAfterChange - - graph.onNodeAdded = (node: LGraphNode) => { - computeAndRegisterSlots(node) - if (origNodeAdded) { - origNodeAdded.call(graph, node) - } - } - - graph.onNodeRemoved = (node: LGraphNode) => { - layoutStore.deleteNodeSlotLayouts(String(node.id)) - if (origNodeRemoved) { - origNodeRemoved.call(graph, node) - } - } - - graph.onTrigger = (event) => { - if ( - event.type === 'node:property:changed' && - event.property === 'flags.collapsed' - ) { - const node = graph.getNodeById(parseInt(String(event.nodeId))) - if (node) { - computeAndRegisterSlots(node) - } - } - - // Chain to original handler - origTrigger?.(event) - } - - graph.onAfterChange = (graph: any, node?: any) => { - if (node && node.id) { - computeAndRegisterSlots(node) - } - if (origAfterChange) { - origAfterChange.call(graph, graph, node) - } - } - - // Store cleanup function - restoreHandlers.value = () => { - graph.onNodeAdded = origNodeAdded || undefined - graph.onNodeRemoved = origNodeRemoved || undefined - // Only restore onTrigger if Vue nodes are not active - // Vue node manager sets its own onTrigger handler - if (!LiteGraph.vueNodesMode) { - graph.onTrigger = origTrigger || undefined - } - graph.onAfterChange = origAfterChange || undefined - } - - return true - } - - function stop(): void { - unsubscribeLayoutChange.value?.() - unsubscribeLayoutChange.value = undefined - restoreHandlers.value?.() - restoreHandlers.value = undefined - } - - tryOnScopeDispose(stop) - - return { - attemptStart, - stop - } -} diff --git a/tests-ui/tests/litegraph/core/__snapshots__/LGraph.test.ts.snap b/tests-ui/tests/litegraph/core/__snapshots__/LGraph.test.ts.snap index 18cc5c713..1a92319bb 100644 --- a/tests-ui/tests/litegraph/core/__snapshots__/LGraph.test.ts.snap +++ b/tests-ui/tests/litegraph/core/__snapshots__/LGraph.test.ts.snap @@ -274,6 +274,7 @@ LGraph { "filter": undefined, "fixedtime": 0, "fixedtime_lapse": 0.01, + "floatingLinksInternal": Map {}, "globaltime": 0, "id": "b4e984f1-b421-4d24-b8b4-ff895793af13", "iteration": 0, @@ -284,6 +285,7 @@ LGraph { "nodes_executedAction": [], "nodes_executing": [], "onTrigger": undefined, + "reroutesInternal": Map {}, "revision": 0, "runningtime": 0, "starttime": 0, From b3da6cf1b43b7c8c5cd2390311955782a4db6af9 Mon Sep 17 00:00:00 2001 From: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com> Date: Tue, 28 Oct 2025 04:02:28 +0100 Subject: [PATCH 011/115] Contextmenu extension migration (#5993) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request refactors how context menu items are contributed by extensions in the LiteGraph-based canvas. The legacy monkey-patching approach for adding context menu options is replaced by a new, explicit API (`getCanvasMenuItems` and `getNodeMenuItems`) for extensions. A compatibility layer is added to support legacy extensions and warn developers about deprecated usage. The changes improve maintainability, extension interoperability, and migration to the new context menu system. ### Context Menu System Refactor * Introduced a new API for extensions to contribute context menu items via `getCanvasMenuItems` and `getNodeMenuItems` methods, replacing legacy monkey-patching of `LGraphCanvas.prototype.getCanvasMenuOptions`. Major extension files (`groupNode.ts`, `groupOptions.ts`, `nodeTemplates.ts`) now use this new API. [[1]](diffhunk://#diff-b29f141b89433027e7bb7cde57fad84f9e97ffbe5c58040d3e0fdb7905022917L1779-R1771) [[2]](diffhunk://#diff-91169f3a27ff8974d5c8fc3346bd99c07bdfb5399984484630125fdd647ff02fL232-R239) [[3]](diffhunk://#diff-04c18583d2dbfc013888e4c02fd432c250acbcecdef82bf7f6d9fd888e632a6eL447-R458) * Added a compatibility layer (`legacyMenuCompat` in `contextMenuCompat.ts`) to detect and warn when legacy monkey-patching is used, and to extract legacy-added menu items for backward compatibility. [[1]](diffhunk://#diff-2b724cb107c04e290369fb927e2ae9fad03be9e617a7d4de2487deab89d0d018R2-R45) [[2]](diffhunk://#diff-d3a8284ec16ae3f9512e33abe44ae653ed1aa45c9926485ef6270cc8d2b94ae6R1-R115) ### Extension Migration * Refactored core extensions (`groupNode`, `groupOptions`, and `nodeTemplates`) to implement the new context menu API, moving menu item logic out of monkey-patched methods and into explicit extension methods. [[1]](diffhunk://#diff-b29f141b89433027e7bb7cde57fad84f9e97ffbe5c58040d3e0fdb7905022917L1633-L1683) [[2]](diffhunk://#diff-91169f3a27ff8974d5c8fc3346bd99c07bdfb5399984484630125fdd647ff02fL19-R77) [[3]](diffhunk://#diff-04c18583d2dbfc013888e4c02fd432c250acbcecdef82bf7f6d9fd888e632a6eL366-R373) ### Type and Import Cleanup * Updated imports for context menu types (`IContextMenuValue`) across affected files for consistency with the new API. [[1]](diffhunk://#diff-b29f141b89433027e7bb7cde57fad84f9e97ffbe5c58040d3e0fdb7905022917R4-L7) [[2]](diffhunk://#diff-91169f3a27ff8974d5c8fc3346bd99c07bdfb5399984484630125fdd647ff02fL1-R11) [[3]](diffhunk://#diff-04c18583d2dbfc013888e4c02fd432c250acbcecdef82bf7f6d9fd888e632a6eL2-R6) [[4]](diffhunk://#diff-bde0dce9fe2403685d27b0e94a938c3d72824d02d01d1fd6167a0dddc6e585ddR10) ### Backward Compatibility and Migration Guidance * The compatibility layer logs a deprecation warning to the console when legacy monkey-patching is detected, helping developers migrate to the new API. --- These changes collectively modernize the context menu extension mechanism, improve code clarity, and provide a migration path for legacy extensions. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5993-Contextmenu-extension-migration-2876d73d3650813fae07c1141679637a) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions --- .../right-click-node-chromium-linux.png | Bin 107155 -> 106792 bytes ...right-click-pinned-node-chromium-linux.png | Bin 109110 -> 108939 bytes ...ght-click-unpinned-node-chromium-linux.png | Bin 107155 -> 106792 bytes src/composables/useContextMenuTranslation.ts | 56 ++- src/extensions/core/groupNode.ts | 98 ++--- src/extensions/core/groupOptions.ts | 416 +++++++++--------- src/extensions/core/nodeTemplates.ts | 185 ++++---- src/lib/litegraph/src/LGraphCanvas.ts | 4 +- src/lib/litegraph/src/contextMenuCompat.ts | 148 +++++++ src/lib/litegraph/src/interfaces.ts | 4 +- src/services/extensionService.ts | 20 +- src/services/litegraphService.ts | 1 - .../extensions/contextMenuExtension.test.ts | 55 ++- .../contextMenuExtensionName.test.ts | 71 +++ .../litegraph/core/contextMenuCompat.test.ts | 346 +++++++++++++++ 15 files changed, 1030 insertions(+), 374 deletions(-) create mode 100644 src/lib/litegraph/src/contextMenuCompat.ts create mode 100644 tests-ui/tests/extensions/contextMenuExtensionName.test.ts create mode 100644 tests-ui/tests/litegraph/core/contextMenuCompat.test.ts diff --git a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-chromium-linux.png b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-chromium-linux.png index ac2f2b0661d905a7937182cd9918c93e1019cc69..cffe23ed13e199896e36caeff8ae8baaea88bc5e 100644 GIT binary patch delta 47440 zcmaI8cRZHi`#*fyGwviS*&$g;ky$q?d+$xM$_Np0$t*Jp*&$gWWM@Q3vXf+!k-hhL z4t>7A&+~nr=kT+*Lj`ialDWB`+eLmn+UTT2tR23MKiK{n#NOe=e%20 zbfPg-u^m`8)~B*BtT1eT#M#bWdEMj5;-Wm0ETa4_$-ChbPNxfeU50(<8RTvW@e<12 zl>N!U%Nq4U^6i=Ejue&UKJCpT=Y)i^URyDFcdF=_{ovFkG3_kXxVL#JVlxuAi|(~2 zoELxerMbByS$w;sQwqJ3*xuUOs*~4O($*Mub*oN#=W2`d=g*%VnE0tlGc|H3-$U{rfQh8C?^=2NTQ^LLq2xtMfmTk-aGWjgn_+n=|Q zmmUTQx}9h5&e!B8i#l8MIOW_EiNmG*VU1XD8C zP8m4VYtGHj%SUVF^;L+kcBRRPHf5L;j@EjM*Y=z}dv^Rd(rFyeO!g^4hm08?Fq$Qs zdun!h z4PKhiCX0BbX&)+HVqY9&Wa0$@gD1Q|5W!ctczCNqcg$SbiLq&F&t%zXpYuJ&Ab7~9 zrXnH_4nBW;c$aVYsoSzUr8;>JY;BA5ct5-!w!ucfy~9CDLZZ$S<6(;gVx8OEa9H57 z9-$~762xQ%pDM3w@WTyIGw>9{a2ZIxNgW2)4Dl@=Ym3q75bzh4m8}1OAx1{VK776A(>D6t;=6KVzY-FJg}vcD6e?qy z)h&Qu&t%Swtk+3k)4G~ispZCL^Yim%dTt4R|NZ;76SATM3*dqw}jb-Fl?WG_}?|hxS z`66q0Cipwt#7v=)r#WAe)QzQjZ#2;$+h@6Zg%{a^;G6H2(09Zn{=2~WrkRj*?uf}9 z)-J*`fit%sZyH@6LNj1l5T-0G9&_RiwTEK(RV5|8O{@o=buTvU!p2f-s?Nc}`L>+u z$JoFd>+^Ps?i{QT-SL~!R(WZ5$~~igk@Vm4{K7RG5GcNZhcv%Adr1dYFDdKK_xLO9 z*0K|Dt}b1=RA^EoHgpPy{p)-E5;*)bo~aQL6pZLlp07r^!Y~E+~4oM_NUd@*f=I8hC)vBozm*+YNh99u1R6}D1TfV zEwA2-)Kt`P#?$xY2=IxN+!*9HFqp+5G<$DQ;biXP<0B)}_|dlan&ZePmzj={Z9|h% zn{JdX5L<*E`vfnR?;l=T3F^z!m0tVGKI*f-SY+8UW=dSoshj|x;tUS&FEI9+&o9r- z%L~p?_m{(bnJ=vKnQRVEN@5I7S5CYp&k?=9TsLaI|GU(lR=|WeuB~ooB9!%hPVh~H z99f}ZME3W8;f_T(z^S6EhOa3!uGT?~jP74cEGaJLxpavD_vVu)PrSXo4Gav_)Vf4Q zpZHsEWWIg-rK#!awQDpqG!xg2FJ8RJ5YBn|a<^S+ij?G#gLvlm3-Z0 z8Xj%=gTdIBFDE^(73+HMj0dNsrRnSIh_)^aQR4e`#-TKiJyY@nB|7_4D%^ zvArD{8p_Vj?zpXf<&TpH>|RuCd{&oj+KGzvCA~8vem#Q7V(?W|GSs+_HnOB^4%XV> zSvBGCEIsj>%gKW8VDi}+KXvZfn9Q~NzgAkLk1k6{Jb~ao-(T2r?uwAmHHRVY7==}` zPety@8acwOtgM29U7ei*@Pd^UXPKUsHtxlX7cXDB%p|+7J#aBVXF|?iGI>08w$dmi zK7O}DeEC_^M4F_z8QrT_uacy^t7>bdu3T~9ZW-`9T>ys|7VX1_6$rnDpVqz|9qwBR z4R~)4iwrF?RFqhEvIR_cB-__rW@pD^{o~43?>_2X?l4?+Nwlz07y*nhwfK)6&$$XY$EoduiB%T|U~>d-E)scou_s5fii7Kqer3^{RYkPrhL} zCl}Ww#o*##xrngvpQ)+EUq$SkobODs-Dj!}r);qPnx#>Ojlqfwto!F22;>F#g z{bjFhN+JS+Vff@3PNf%ZQyw4N;;&dUZaEuwetNtK)~ypRBcVEk=sDOo#QVn9)8^QC6;*j1b>i z8XoNJ^_OvYF1xl^K046@Th*xg(c+IB&86}ug8u@3U?cw6zauutsq}hmem)fQyV!~> zLaV5u0ej@8q@?8K<)x{4CMDTWTl=al+QY$!oFgX;c%hT0o!7Usq>!ezvi|dxf|ZsQ zwQ0V0@=|C-#3KW12ZyCAof22Pwid`}`4>j(n02l*ZDO(55eO86?iO5hLN)zX8{6BE zkiGQuUhCv7E-WO$?B@FNL>x!%AK&4JeLDX$9|s3#YHAAB!hOiOr6*Gnt%EI2DYa97 z=n3l?9UYCqS`@uzAwKX#7|xxWpPQpPb0!eW%Cxeuyv$5XyA4@&$z!|hS#U%GV2NisJvC-a?R zzkv61;Z;FPoUn2jD##XK$B@Z96`WkPFw^lA&TLyO-~O0CrI3)&!QtWh`g+Z%9&#(q zvL(W}`ceC)l(6z(;piQ8tz~)}529Er+k}p`wn^(h*REZoC=T@Q)7R82ah_~``}XaR zA3xv|H4p8NeKHD6}OGL^(O9GviD=XVZcqf#_;zOx%-XMh{kDBYp40 zF@cljTh|0}s-&a@B7sVZ#B)r7q}R2Z7*VCB_d4^#?xW$R*4Ea8+t&tNhNl(d_{Y<3 zps-?bZBu8sRNivi4OKY95icq#B2G(7(!EdS+kVf*)T@G6d98Qn5L0K zEr7jZ-hdyYusIcHI>Cmb=y60uMC(hgNM`BU_wV0lW@eU@Xl81RtGCnB(;MXflxx40 z;XLu>d4Y6IK|zOYvbg)wP__GVj%JpEqN1jTMnhvGD?(^?pOlmo{vbmPY3PDt?DyA~ zGv2+M&MT~K$h>0R5f&MFJe}ycV?6~x>3F4)GSz4AZ}n2uJPM)A!%|i@z@$)so4el8 z-roLr8$G6t6kF1jOj+wym4@Avm6bJ#cr=I66Q@nKL~iFr8QrvLMx4Ec5R^b+Oh?X5mbf7-N1dVlxJ_?uKw<5v@CoKu0I zsIEh71Uls+7yY&_@&R*x$`?h>--WM!4UToj^ddV&7gUyXm<@aW2qO{U;mIP7DOx=F z1qDYZx3Tzya;3^`J|r|0-~t{lF1%nBB&^p|;_QWO_Orma+VyYGvuDrPZ$}u_`JAVf zT>Wx}x2^fhmp?NzlNT!t%N>mCe7x`7d)JEIwX?Us#K$-F^4j*JgPqmy-@l8Dc*w9t zecGK)3=a=CEW7_aEbNQB7o0C5N~Z7a?QRA$)qv4AdR48htRTfgJQ(vKN9ySUu1K#t z)*T=1Z;yCIGG`0f|Ktr&gGfUWeObcRqUWvrL2M|k0Kdtnozi}j!Ah5z@N*&<6dT8H zTzqWqT*9P!Q9!`)!Goq$Id!dv4<9~w@BqDXzM^+JHaTV{wwANqG0SHpIzxxoA0~f_n5xW97pv>W-NG%#2N=B3{Mlx2Zj4MTWOu za9qR?6Z@@u|=OZR-o>n zXLR(ql`EB3Kwx=xb~djaK?1s#(c}G*bJbNv10_%2<7An5>Tf7xcZ>;b^@ zS8Y?GGH0>bX=&quv?k9YBMWnLCuVZ5=bvHyF+6;jC4G2NLc%CtXOa(n5@PG6GJmi; zlX|=oES;^DJ2z*SR7-#eUR!NrvATDU-?-`{oXEVqP=QnAnmh=Wo^NW8DEakG4qvZlY>8Lml=$W; zxCv#eop1sGt$?nXR5W4+*&cx%Nx}MKU?8X42C@MppnCtRs;Y(Mi;o$?o6Vt+ay~A5 zZcZn)=l0n)`CiH6XUm-k!j3T^BvI9aJw1W~{D7?1wv9|ubV6nPt1u^Y;P_p)@L?f( zI6vE+0YM->KK>=Avgg)-wQhmY?hj2>`tV!Z^Q&**4BHMATfxCwTV4I^xNqn${@@4} zG7xJHIP(7e1+LU5J>A`_e_pBv1)q$;nKw+h|H?I7N~={(3OO1ZG_NnWf8Kd7DWa69OB6sbFl}RZ6Jnm>G0Mty4zx9a}h*RTuWALgsD}sdKd)6EQ0Pg7M zFe$PiNXgA(sOR@AwKSlCM}tKxJ%WLw9$7pTN@>g`Dhs1u4rE zo?Yv}*d(h22QwXxtM{UZ9nUaxrT0j&#D^Z;$B~Z853T9n&dtpM_TJgub#r$Y&@Xu`VD-Q7LwE&BF*vUq=g|Mo;vsOSgCKN3C%JAMRYWe*0oI?w`z+W z|LxQcw|Wv+0c@puEmcBn{a9AU$;k-_sN927w+_%UL*bn3+>eXFY|$L4PuAoQJfUI} zrKd~T7=&c*l|OvnMO(YCA&_jBx);C-}7(d@rR7O&-P9>|v zAm2w}>ri)-%zEIbq0n{|!PXBeX?L2VzWL43C+qFG+IhIRxbRfe0jgmzU0&s|8BLG( z`T-4PsU%NanSynoYwGFg4X!3JySqCPDiF(WoRFOCJ=?`9u|5v~lAj0V@mwfs`I&DR ztox3ehv!>+dnxlowfFubs0W}jdi5%x92Vfe1+~}iCx2CFO zV7Zo-7C8$dg&uusvbdbszSYKH$svCaV1}c-^2um=j^~Ul+)He0Yop~i(las&8=dHK zN7xI9ooazeXd?eGmdKcf=rRKd@IOS>d}WVaDS6|;2g5{(z?;N}cHwJ1SD$L+ z{1J6nnF+DdmsoiGgm}GhvFiEcgTwDLAvvQ*(($s_OA8q!CZLWxgdA@yAVyk0JNd#q zqWZa&eymk|;tIoLbvp%2LFX+@ZmD0PrI{`lhcP# znH|$K))dna$Z)@Y{eq2GJ1q~dp_U6!Q&d!3-sBuABno}@jF^(Le|{5o_NMGQQB(Uh zFBuC9HlK0N(nnBwLnQT~o?Eu8ws5l}p`G8@B5M?sl$2y_QI4-?{5^2yk0YArWL+>@ zxcrTdP+4Onm-J-shS`xfs!<2_mo>F3MTfWQ)(w~ zoOKn8nCzj-f9y#A>R|w84*i+NbgaH=2WhdS=ESgJlf<=oyku9Cb(dbwc>9jL&9o zxOw=xJ8UKQu-}{FoZ>qnVDINK4W{~7h2Rf$PC zlSP(%jly?Q)c>>ZZK-1yL&^xB#NW@ne)7yGa{I9WpQgsmcz^*C38}xzco-tfCPny; z8zogG2}1snU`d|!Zpi!o`PFC%(m*z0;g6M-kFy!bf^OQ_a377f7r*~Jc2`cx>*Tab zP?}~p?+!Lgm%By#E8&E@NR{x4vnEMa^uBq;I<#H==c1MO8NhWKIgESsQgFrQcPS}M z`xSAWL4D$TfygiR1w69@(^xBGl$^ftDb!w@kioqD6*7zS^TSOgPlr*!LZqqT6A-Lk z8CzLQpZ^b;my%EPYqXZgL(Ltzl>rn;5Mj~oGM!VYB%$l*m2dMRK08o?{bg2DMKfTUljh(NL^5_XEsO zynB}eYqLC3^Z4=O6dTSJBvXS#=1p*PFKbtFa&mboSBXA?upsiXH?<@_)YKT~XnmV{ zxKk%s<%}}IB)vR6hX&|RXtbGerm-=Easx5U*EtYeUX0ryapuK-wUdiHkXP5^VUgEJ zQ>(vl$~Vdp3iRFG-BYJd^}bUcgc=(vA|Tm%R^S5l4yXc9j1dqJcvvorDRcJz zX?>~96Jx}$s-kj>_$)0gd%!!DWFDH(s|?D9hKb(dUj5H8q-11@s;Z8*w$~vX&krt* zn4V!3e!TYQ%a<;z^>_(*fS-Uf*ZS_gBVs7!pPt&fY53*Y4Wan^#6R~55D&Hc_uuRBMudhM ze)3pd8m?Zw70pq%HMsd|JV3YQEIs8Lo1(fA~;n>BBH^Au=*DAcO!4 zw6L%M{lewpL*QSHG&TJ(zoAl4$V7qnoHypea*K$#Z_f2W>aMJ;JZNqVreqI*%66BJ zTJC!O6;{^q`looeBbnrgB{#Zc;9Y!td`qZuXw%y0@!=?(F_>v*isZveM%DS9xx7Ls z>P};qYqnG79YK<)_rLG{g8vpl1(TrQPla)#O4E}>(WCyjKo5EokA53RC&({*50Ri$=0MxJSQPav;Vwe5r%&XUTRrb_t= z;KHpyx*O^jGZ0p;*0ZpGACu62@1%}~gjDCMm2yeqTnIDna5vu@ZVe8q@%p}GNJH#$ z>X&@19y=8+nyer1=cQMMzu_h={M+AO1Yr^t6as|402sGmJI(gDj~$+zdJVJN_<5&^ zm!CdK_}p@^w47uy{H2==1S9NFB{)CI%EP7h{hI=AiKINRbT1 z>@AdZ?(P4D_$xtnBDzSBXIaY<2NDigs4IINPa}y+oI&QehrjaYA84YZ=yBH0z6;im zWrd0z@m0@BPsj4abR=9QbI;7x%7uz_@`NHuQnrKI9O?m3>)>JY#N<|-3{Y%rOATnR zo(pfTufNfsI-+~RjwAs@272kFF03(el(yT8{bEt1kpsdRaoU$JvPl;zO#gEL%&5*I zXnmv8#(bXH>Vp)W+j{gZS6PkB=m-Ur)|OH?eWVz%*=11&>w_8rFJ#%Ce(XfTEZ~x` z(ddy@>nr*a46^%8wEx=E7eEr(j`UyIM^HGz!NT^>>1q^j-$2h zi6ZW9ZuI1YFI%Y@8HYwjmRzl~QkOm^A4-?Pn%@UZNqi8{W4rq7yxH|I8Ex3@n*Vlt zw|jvS=gV%JB`UF($5n zM3(Ke%9E)*BWFfhYU&@lhlnqZ%WG4!ItH#fYMw^He@s|VVBo18|AT{r^o$Hc1B0EY z=2Y*k0bonnsY$0EUhg;^_*^!9XJ-d^j3lA@t0C!duAQyllc~&8hc=<`ETLe|%CbgA zzxMa*a#M@FFaL9t<$pT6s)`}@CWC^%5g`fU)rAKVilD?(KH(RgzI~C@T{NMA=5*2* zs&}ssj?J8}j8^Q&$G`dYu2AIrkOAFMGNitA1jlJvknVOvf$q1O%z}SoWbi6Ocq8bW z4Uti`7lOGbhthh@Y={7G;Srl4hSc0b2yXIp0xnq-{5hdv{lwa3g1(N zcrDKEnLU*J#hV*POO6kJE1U?Y8SikAjFA~M6_pxNhK~s<+@J(p(n$CdPpMZ}xtEP~ zJ2LLRy`_)q4cGBpL`eDs(IANGKY`aAZx&}-w8Ko0CE%Krc?2=chwuCs^stbel_N%h zb-l!zMCRU5wN1jYlgPi%navIa-Pksbn%tkIxZ8kr6a@agg!r3 zejX^MzxdM>>e}y9(epSIjrljxjBq|=$=+x9tI=I6kGQ<2|1E3=DjQnOE{23qloQk| z=cBkGY*06KSoH1d#aaOtkW+W8yN@BoU}v*J{XR`ng53x(GgqdyDFt&d9p)GOFY-UJ_d#Xlb?p^NsMlJk)+SVi+||O z%SNT8-z!x)O@G0z;AdCEi=5m$1an_v(28EBp#^Srml}SSYdQsmwLec|&RvWPm8Gd+ zYMuJ{`_T^pyGIXS9qL!?o&uN-NEY{w9|5w$0hKGaUJe~=K-j$>`RvApe$R-cN9*c^ ztgFtl${Kc;pmD4L98}M}H|F)zeZPLBFJdJ{h1vO(HGk?G4_^#v_u0)9ce7SO=e6z8 z-cS3PBAqO|2c`Bi=;~femE5_M5Q)9Lt?7~5!(y&l**XWe+${G0{yAkYSADeRZ@2iZ zW3gI{$!ALB$cpO+>-x0-qsNE4?zzLZs#$_|Bfpg|$@N)nGI(1%Tf5xZQk;j~TFFBb z6Z4n-td*h3P@%_MVO{oa$jEp$YG;VNe^%qZxV|p#Ugy)UI71g^>u*Ft0=K$Cbs`z0 z1T1^D1plfs?^7;+jodFauuX^!sZ{R#O>^YE@6x(?j#@sN>iHM1#UHwC)cLr9WKb=GdlXt+Zx-FjGYzYEg${=6Gv+%x@BRZ^{K$wfy9!SZ3JyVpLUWkfC>7HL!sCuU333 zTYEQ!!RhPE(oCVH*;i>$H0sWuM_!oX*{khhw8I@C80)LzOc&5d1w~EQ>^!%ETwF5@ zke$N+q5+chPsNr$G{9@Uf31Y~9MgBHL;Eu$YdsXtyOoFo8`AW5`u$|FQ5aSRR)eg9 zrH?zQyAx=qjZNB+>D_L2jxgh@M;FCBD=eE6g2_yWz2%lYUKwsA2q`Z7_B~U$yzJpI ztkGr?u7Wa&OY6IOw#`4blbcpd)TtUxG4zRjADM7IQL7AXi)|1Wd2d{9(;J&%_skCm zd1DHc%Sxt#(;4|_YPr*oc9Mg)9xu&);o2EU)ZXHN3=sXCp2#*SYKz zcA|w|?|1v83{Ma-{eP=s@JU2-up(Q8!3bTU2o8=Q9UU7R8!jscO=vPrWIba^V@f`4 zM~wJ?d=*wR3R%7JO7AF-EIe(B2v|23My*nrXxi=y9g(fIFpv|L3?xM`vCk&E z-rs&w(8pG3#2=%Oth0o6R8ENUb8}}G#k!s%LcjgYmNn)zr#Shnt8 z+-7GYe+s+}6%+1xTB~!o#=Un~13U}w1;j~x(|3qxXk-iUB%gI$R>WX6ayH7mG*s+6 zo_M=fock9Xks&iOU)!qAS~6NW%Mbrj%!#$-{M8xKNS{}Vl{cg*SnrmxxSa{c_^(!v zf9@nj>9=Q&Ke`<|c$yA%H>p!okp}up=u%_||L6P022O~VuE=`&phhX(Gyh$3<(ZIo zwjt^7nqRLDew#0gSKkshKq2!DSdpPR!R-KHhU@`c|9o#POG@K-LMst zJr<;%Z#DE46!j$oVaH6Xw>pm=j1&|7vJr;0U?1@ueZnB%{qabd9(#u^3KccJ1au%N z(Ah9p18Dx)Xhyrbe9Kjn#k6^8?1dA`%C3EqMx8rd44wg(5zSkrCz4Vb=qJAtufvIF! z>eEDauiPOI%NYIO{Qe{wo*xbvxwC>J*oX?!gv#A;M!kLqY@_=w@-E`?CtkU=`f^+( z>_T^UH&Ag$JED_hhZ4yq#F&`Fa>iH{9ud@WlB zf9~h!a)ID=;%n$~)Je!_5Dic>S63yW}+eTEsW&WX& zl(N~692EgVZHu3z*s9d-xt`#%csm+pnt$(Acuu8ew2o&p;R$kAYZ5F2&@a|f7^ zfQk{0R|4%8bo>{@4CM5|75%KpquDgKiceKcynj_}O)1|KnXWHtlh)T`PM=0kd(0O1 zS|q$P-slv4^^lPkgBeSHgo{XoO^TKp@L`DYadDVhtk9c_{i9M~iD)lgcrIy>G-)^G z5^^T6;aIQv!LDW8Y}~%os`c(uW?9$`{BhNqS17rn9vyl$IUA{|y$BT;fif|j8tJ0V zk`x?LUQi}){J?we+&S^rooG5Y&p#=)dPJFns;Q+#S6ln~dp>gC@|d`|$-JyyAG2V4 z{pFdq!x(_%ZKGDvj@%j1v!O+2Aq+lL`5> z3)I|9UJFH^fB0fN!IlIb8bW;%x=B%S|M#TU^$O3d0&oK`Ro&PRyybVxZce-}*>bEC zkqsm>GFm|p6dbahf4OZ0?*{E3OIH}5lA-(%8L28Oi_i4Qyhsl?%3&p=sN`g06B8-n zPEUwE;EMqa^u@wiS63J42zhyuRJ(^9qL0_!niRSh$=tZ%i%rWeEM#uD^|XkLs9yf% z{o%SyZNFz`^E+xY;%#qjriCZ=*JXZVAy}MTKS&IrproWcb!sYgfEeEoXpMLO2CKt! zGVrW{WV*Pt#Lv(F)2_NBk0!)!g}D>x9_|8u{1O^xQc<9xw9V44S)9R^>vqbsi~=- z&A0^w>RkU)jYxU#Z2)xz-juDatrL##nL6i7KD`etqM~|veV~hp`=`mOc#Na*6QcWF!ybp#V9UYnx6qW<`sTruq(nmY6BQ2ImFHp(fxKR&G z)FP3@74mh^uh&~Gxl~h(w6$Xr6Z3TPzy!Y5MBp(^_P=^DV|L5sm)oZyY~{b(U9-;E8jAVMF#mqLAI zgc|Y}+ztuXv_(e;?sAeUT#)&FqTj#>5=95a zPAT5+B!@_V0m$Ay4>l4HPlGw1d^9W-7%P_k{U`V>z*9w8@>Kz+CZu4r7w64SQ>Xq;U#Kc3N?LHmz4Rn!!THcn)uiezdUYWPR) zehESR-3CYfd1Ag56!0HCxP7}NfaHvm$MpxlKYsmsC$Qls320tQoR9!JE2jh*=rg$I zVwu08Y_-d@&t?DlACIO*>WW6&TTVvsv1r633ViC$%`7q+UNgFB(BKb_fSm%zem|i< zjzHAh-wGRa`A{LFMd3s}IXEJhK zyh3FAjoJfaU#MH>>D;DCCfrIYb%#{Oop361}hH2zLNwtf-({+(kmwm~D>oGw1#p!X%`rwiNmpJNnq-)eX)Rxv-g zfO%LxeYA9=cjIfT77@fhGipn^ph?kSIp5u>#|r}5HOoUobq!nY!JmIfL@Sz~HygWI z_Dm6ILB5mwNgv59KM2n5wpl?ei5OdKg&E2R56B?UY^?|5;o&()+N-IlK}c5Nm-IRC zFtQV*6OGX1rmi6C9~~XF4FsE7PEL+pDMK(3F>8_DC)dAdPkK6=L{CLIIL(Xn-fQtV z9{_v=!q}v+->wu8=z#+`HHj$P`Dog}5DsAltj`(UHspkOOBvJlCsx-CoxIZ2jrp0G ze%*7(tN_%GAyCDDZh>EaxHl+5M@}s_9AmfdbzMJz*zap)Dm`sIYk*kkm*!)2Iwdp! zn+CEk@n*(7A~*=Kb-GS+pjZgvuUvigsa0yP)F6K=E_b9euEz5`qh34vCu&?+5g9R} zima>_+c$$heh80Icm2mw3f^#wA`dv~;Fkife20jQo12)D6;vBbx?7wti+CaCK!ixs z;%NcvncJLJmRkyX-K7~!Uf_F4y7s^TybM@u1BgZJF$%`Ae;LBxWn@@xEev?@ZX~;p z#K*=4VIVB6Y;G#6sKhE{!dik#$NBR4a$rGjuAQx|{s%Lhf&i<5urTsK>}dvuT#X#3 zY$J8`(*QQkpXZ|q1-~K?#VfR*EMv|xkOse_$e4?ViT3U$Q9m_s`9DCh${_nqWFbEDs zz%URMJHf~fmN4)s!MTE_0phe1`<>ngB4`VQ_?^$EctTNM4S@md<;piQBXr9ljk0RuRN7WUV`nLL=S9#0@Pg7d!<2^Zz zy)&$|v>QiPc;*^@__%1t;pmxvOC2HJ#BbNVeho=}x;|IV zjJvO|Pn{Zcal$M3zs*p=*X`4F$DdaQiN1q>oLT+2CU|efP4Vab0F38?)$Ta699tAI zm)rW+E`h8%UEVghi@d&X&Ws(OM`(Q{p^&H(B^Uj3o7LjKsIqMt#N;?W!$)BL2?~M= z1}q0a<(Gp{}Pt);0snJj?s>w=!xM%|Z;mKQ|{T%q}g=}n6&3&S337gMEU zU5!FA+yMo}()_r&NdqTp_m}qj3Vi}G34m;%9c9%o5D8Pt(=8l9!G{U*N{#0# z6n(TOd?#LuDiRTCwTeGhb&L93YjfCb5YIr5F&`yWyv9^ar7ZXay)!GVF0Oa4Nq+4;IRoQRog#bQ4W(^XJ2cQ;=k6~<#E z^)7N+&F}w@nZQv6;pe?D{nnt-KkCl2wFnYL9s>NE9ujBHwG~4ixqof4brDxVl~vt_k%ZVKQHfz3#xOw&g$-6iKCrK03zSNetiudM*G5=YeS-GDd^;Ju%7g{45@e@OT1=j$%c6#cf3hyxLt^5=@fvHVOKiQVWPyp zUbEjpL_4zkCURm_G2yQ=p3+51prQR(xKBFn8sI>$U#KXfK0+@o<;n$<8o^RXIyB(8psw_=xm(jTNz|Q1NX%k|nG~!!X=)yjEEX0P{D~;vy?s0O zBNFlt%$S%pqg(H!`Jm_R61wCNWX{9Gv$Ek6WRAi9x8T>!{HGVgj7EU+ZAb~ibm z|Izq3C3Ct_(4y$q-wAVvqudqa+9wx|YA2`LjZh!mJ#W^Vb*~xqjE`N8C{t4ej#4J| zc35%E@Y#s58Qp*t-o1H)5Y-DSYf?8Y-%zJMHk6HidpPI4lf@|@5IG9&Fi}QR+_1A= zTNN>ie&%!$lZ+ZS)}OywEOf28jjcr8heyv7YOdemcS|7n-K36G07tn0O?qV1>cyun z6br3&YSeP-)O9ap(72mI4B^yre987-&YipZ%)EOC^YL-y7aN*qO}JV1$5on8!QU$x zfUYOgvuSF=lH&!{JD6^8Uw$6p*Dha)19d(yk%_6OoFHabi#lB`>E;aiQRgG{6~6q zM98zcAc{7jJO7DE;I?PNmw5w`Lbg}9#rYCymH5ig`TU98Gtr2L4Z#8>+bDxaSskA z76wY-xWR4(ABKmJAa-`B(gg}7b8~YDB2yVdK|w*ZCLXL(Qnk6cq(W3MF**@dBvLPH0k|1J*!tu1iBsI+WONidMiGr=?~~6Y`sLxBU7Qo$pE}+%aDl z-3#i}S1mt(hE)@y^IGvt1AiFsw1HSvt9UrH&>8`QKRBELYjClzS=p%fhw!b7aZ=QHs=8W8Gije7mu<6$6xcXB%80a@Bbx z?CmbaK>h~d;(+4lk)G3vr{(n&ZGiV$JZGQF@&iTqZ)Bac^}ZRU3j+Gp{HD@9(%=*A zJQFur;Iyk9U_fx$Wd)BNnS?g^-M)PWKPN;vIZ7DyoG`|z{k$da!nlpPSbc77kdf2% z`5;vGw4E*LS?a8~mMIXsFv56F2*15k+oMtyuRmu*+Mfd!Pt24p9X~*3=@O)2)ukpw z{8xe(jyit4ecU^_tntJ zC+5Z@sJvi|=>wbCw8mPXOH(8eI3`(&Qjh|98WYIkK0k9 zy=<01S|^33$1a5#BgUAvy%!Xnq!sVM@nO6?)JLT_Hw~~b)%UbQ)}iHt@{B3 z|F&8EeVh+!+^z;ny{@KmHHzcRY)Con|E>j8j<>EyfK?or(2JJ2ec7LASOa``Q8pzS zwtB~*jknh|xl~exRwJIhcs)Yvl^0WMpzWHrA$xQ6a*cYZ$iy?+$z?jDgXuA3aC74MDlX^v@u z(!EvK@4{Ga#%Wo~R>ZBrhAJnf2)k^C(3^i&SDC*Ye@gdTrwR9U=gNgw-EUhWzdM^; zN>d}AOoGe7N~rlEbiUp1Gcxd4!Erri!OS?n_LM)u%{E~v+54MCQ5a>i=#>j@-3#=! zQnqaB+*lipB+Ecg8P%!HOJ}dfU78EYn^&Z7zVJg`EcN%Vfhqy*me)i?*aJ9Kk}B-_ zcqFcr0cTKK3n;3trPq|%d!zfq2f=;S>k#mP580T_h%~8uIQ1>&QbFQdTf0KX?AF&l zB3N|x{F$&$C;_9&r%6Xxf*HRF}r)GYv;wAuOlQ$ zMf?xE+DZ<9nJ_rJJ-00SWcp(+w532X^clbY{Q2|ry(sPGNXlhzb;aAIhfmDnwOFaHr$)3D-@hGqtM{FQ zgQiG%uA|Ldf}x#^pWQvqgg+Vq7%{JSK|}86vY@vS06Bjg!)e-R6G0RjN51oU_x8APgNL8om~A@q`i>C&Rs2D)TLb7HJ7hm~g56jf){)a2>I9Bmzc zd=wG3EnxR+jQTKe|DOIM4eIj@^?`(G*@DzeVIzZF)S-d!G;3U}aF830pz?uf7^p+A zjw*P1qIv9nu3!BSYW#elT|Uo14`NqFzM z-n(~CMWq9ZEBkASlM@rr6$M2o=$P?wals|uxHve*P*Pws!F%k#?P|aUw^Cn1P|qL4 zTgB9FV@gV<;eVOzb|i2I&>;_ECJ4WOLN`2Xbn>80o`;)zOe9x}M+*B0m}xBo1F^4L zvf+`#n@#Uv>wj?^fEU@TMHJQaVPer7pz3jl91BFU5Dz)?#r3q!7&3n=ma7{^C1*Fc z2}IkqP3tI^jvY42H-G|Kk--O}DfpJ5*BrV}#>U2=)$95HQ5`3>b_dHIz&Qm32Kp!w z^l^J`aATn>mT3(HI50n-w0aX$=6%+Sh5mav;&5hZA7GBb<~a)*TV99x;fUD}i<6vo z6oT4zj%)OJHF*`95D^&xNH49cnCy3|B*ME#<{OBeX?3(oSjx+Gzjz>nZ<*9*2R+j8 zyr3U9=5PxdmLIQA7xC^xQ*x+my7*EBI~aB0KjovrEYGsDvp;?metN^{Z%^jUG7b*j zF^z%9HlKC0%<2Wdm?<>CjRKNFMK?<8z*`%xOUNnjFjY9)+C57VlRvvF5|}KBjaTaF ze^`6CH$1C*k!f^xZ=2NT8A2BiEZp~d>wrN`J;n(D?m17$24bULzVug&IqBQh0-omo z)2}T+)(<4?+QE7!v(%G{>}+CI>htFpKcXG1yFO;$KU>l-q%y2`7eeo9ofa^6BefJ1 z??LAx#SvU#p~F4p%LTp651>KV!<&61kc`$Qp#zFvX;ccEouB^zXn#0V6+b#V9l>nB z<7R9;41W6#L2{pYK_b0;9dxycmSRxAsKN;xpd)-FBxK|yWcUAO-y}w_hdr6z^xwd(EKhtR=eTjBP*-^N{MrRGzSL>d+;B_Kd@iW5xBp#XsI9j?k|{h zCE93NfBgFO3Fn{T=3s4U`l zuSBI%0$;9d)1Jo$KLR5jPNa4PF$){4LysXHP%=sA>FV}FN2Es1%AILo0`qmC1s`aZ zks7ZPOM!tw0vPd`m_~GwgDx4A5{NHg&0dc7=qAI|5K2g#^#UJwq0hguc;OXEY}j4T zBUmXh;b@d>25>%)mI_XLl0wp{cD5eq_PtaPRwfrI)Qge*V-kFt97q z8~K0PXmM0Ypj+}kts4K8bJ6c@Z71y=H!%kp&CrKG_N&NJWu9?K04y|S_^jai!C<}f zzxIq?uZN#t8L{Pp))6~9JMNI;RJ`xE>&9;e?bE*YK5Ns?^Jh5}gAL65(r~PLQymu? zd}6JFt@tr1`+xSf=VGO0q4wujz(Ks7Upu#`Ha7lBblUU%rH8h>_fq+vV#Su)g z|2(mth&{o!HW!kjt*-umvGpDBSg!y7j}ekeDv?o2QrSB@l_V+@*(%wic#Mp04Vprd zl@TE!m6feJ8AVovTG&;d!3>zV7S#eBSHBw~qO${i>%2 zM%tV+byHl)kd!%jR>}ra!f)~Vc{(XEkonYAM15k&w?C-M`Q`;-DWi$UcN6G!Q}04N zd4UIlpnx~0@_lBWzgEv`Y4`5l{AcGTNXV;Fd3GwK{?Mp|;F*4vk-aZznE3uWC)jsJ z$2UtuaNT6s3@3SKz?70VhjPkLKl5Xj&``?5@LI`VJL|R{(%E+{gWA#Mf8g*trb~dt zU$-A!`U?~W8vKQF`J%6DD$da;_lA{9?C24k5W9!*yvW zzL5?pOWr8m6vOzK3wji%DtA45!h^66BHi2fMJ|8yXQxGul3fn7pwmmOA?o_+vMo}M zZ%c3fxE)gKq|ZcuSM5Q6vGU8a!dLx7fB$cD5-(`iAHK)sKdSy!Vw6O~0|yw%D5Wx6 z+Y`ZVt(G#r8@(JjnYpanY$Ostc5N7`T(7ro8xj7_)a2fuyY-@2mBLascJ0=!`?Ahv z78ddKHV#fs%C5ayu*mOWB_&62lBP7-%_!jjhv5A>RPJAOi$cyA2CBOPYKJpAWy&Kb z?0EB_{_h*AOg%hlvFj4YR_N~j?pn+3Ucg+VseU86B}UX_8?U#HPolQk9YQ1ZSb=Bo zAC9`rk#WR{hJyh-aGHLGJW3c@HHu0Aue$xi?z6 zSOTBYrgKx| z{InM-3Fi3N1ge*}WeEZlmdn7$@2e0cj~-RpNOi(#2geEM#$kgpuuMndlxxJaKr@dv z+}PNWyWzsKGi@s#C8+mhKQ3pVZ1q0&+hzR8yhMn`_wMekp;fbQ6UG;_Jo?V*7|bn} z)mDqK&`GjH3*Ov(^KJ6cOP34{jY8a<^Sgf(Zy*ji+r7BiUmVt)af?MuI7_#{J=8?E zp*<`*^~E-3riApjTb@fgNLJ6zb${xUg@Mtp>}gSK(AFIaJ*gK+h3h2z*5*x}&acOpfu(#LN-Jar*Fg!XhFg zV|z+eUY*QpQREG(?Q68H4Qk|vW*&JftZZz$$B(xUg$@|?|eb?;nM z!xpltY}(XsL?BFaIUnssRUvl5@%md2p2_EIRNjfhyA?E0s7RHukWGu!NRF`T~5@<$w!>h3t3$;^)j^va%*TNrNGtz?gGJ$8Vf`i z!UTL^z7OJ6(qvlB%>3i$PZ43^d651v?|26(I(&NS=jR6<8L}tp@5IN)|M>C4&yV6y zsD<3Q^D14a|JyeyugQL7JAjptkPY(m@?v0M(AU>DL+DC`G!u=~jxbHHsSoY+5iQIo zCUld$opr*^7!`cJ#d5zM%wsQCX0upRp-8(&V!@v1#XA<*_JUP zyh8C8FvS=*pOE6w`V}qFrPjH7bcvx3hU>4toR#B7hSry}*=!b}&gU}?z@ta^?Ye)B z;7IHc=r;NXaejdl8c5~)t;c0+vX)hH-uCvDX#Z*fZQ+oFR;6#ImOgTtOZG&NO_JD|T;n9HD}s0Ll8 z=O~i`8HBHF<|ex-2ucX*F62LPUfUR--z!P+JBaYAjvev5yu4uPP~TI{^NNa!9_+oE zyNjj--g_?RB0e^y)|&ej-SzYltEA!F$J;K<&tK2Z4l6#iB$lXAu^f>Tf`uC!8w;XB zLgJ1xj5P)M`Fu1Cl>XJh6gt(e2fC^9XSw(Y3N;nh6(GnGi)j1oot*By>)~E?b;q}} za*mzTkFM8P;qg*NU61zuN-%DJfAh)P=0}e{MUvy1t?IWnO563lj{yUNhQuXbamSA9 z`I|nKz4}0*)P-Ag7*P7(e6Y(g5ee5!f&c|Y@~LMpo;|Do5J>B%lJ7nJgizhgq2wji z@yZbb8i`1u?c1-`_FWAKU{ecV;rxp1s(bgWev6-1j6Ev&aIS0_Jv~;cRdA$08|rLV zH@BqA1?Yvipwa~p;Xc~g@!`X_@85mk#Kl=;Zr%k#ZgP@(=+HZv4IAhwekC+p%P4ix zkDBaAqqQLHmW0{^3w7uIvCI?=skblpcw6nJMBt#k78nSB*8rmGK;Pi|YELvko3j5V zdofIp5Mx33`hr+2>AhEqs7jE(iZ0(YPMu2Vd_~8&3MnDYO-<6WvWJp%ArV2IiCQHL zx*(sfUaf$35bP8aADS`5NHVV`R_8r`4o6+_`3ZsI97`mbAu|KgS!`1%@=q{rq{ORO z&{N7DYXt z=<8o}cR%u}jj^?5SxZ}+@rlZ?w<%9d?dP@E&aUUAv>vjrIc~*A=xa_fB4$%J73(ZJ z_PrHSeTum@ZtV9hy^9-GSm?cfzrWRkaTvkE-(@_0d`c5?fGo=@Hj!}qGiUa1c#+_# z7@L{tycDlTr)Pt{3zk*1*O6Q6%pl#Z=4I|EWu~V1IFFj@6sM^w$jj&c+()4kqh+Be zF==}c(zb!)1t*MdyHHu4=dC9H$#VTXq1|dm5re|uZB-Lgd`+4J5o{K8heS7;h3QD%SeZ)WwINCOpb83bO?zf)q4He$ zK51)>hREu>&FA-8I*mBn580od=qGY>f3mYPm_2&Mz$j!~}_;JTWHzC&; z9~b{sLK9y*i(o444*GskEHmUdMJ-lWUurH|HRwe5Q_kSi``OOU!UQiOMU~5w-H#@S z?Q^q0SKc%NFl_iJ)b*>bVpEPNjF2DVwTRRzx5|BZB; zcV|C0nN`J}s(o7E3K8+_gjsWQtlEPV)z89g=Z%fMnf(vz>pPb0Lz0(~wl+SQmv&9l z)zxXnMp7GIChQu*6NpVc$H?*I*%usS*)hADzl`E*sI9${@2~gopP1Grw4~#)V)r<1 zAJ2#Sp*1M;{k?lmY7d~oxS5nxc(i}pIxj=x!sYbp(!`0K#ar2}o11%Yyzv+ud=7v@ zs@!uuv%gjOp~bkFGo~WpAku#GFBOOxduUlKG@(Z<#t+!0Bkzz2H?_5+2#t%^5ec7z zprfAk<{P78ubk#JWWL>Kr&7n(kL%a>+zUVQ^T(De{PPQQbr=T~Dk0Jf(tzCRl(%QHqYfY^W9l}2byLK6Lvzb0N6L^=NQEY7BaX{$(leEHJ z>?#g+4ZfxV-ANg*#6-!9KxJXGpy)vc&dkJAr{xEsDDW^QK9niJ8vG!AK~I4m*YeLS zT|lN_=h(?N`}b$c?~8zL3PE=i}&trah+II)be|FwrFkCN|(g-JsfWo+Dr?NRMohMWa)ZeG6UXkJ9uMi~=4u+hC2Jiz3#7l*E+0dGyJ1(_7a18d8JXMc?6)0- zRnI)!n3|oPKeNZx)mBgMoSvS$sp-kRdq*}MENuQH5jxUv41rJ49)g7oF6b% zS9uzKw0{e$r;)LOu@SSe`DL9<)PT&X+24cqNR7PX$UONTD0L?_2tOJvAuMMEBMOwkS8o0OKHn8jZ*PUCpV^ z)OQwarZ+e{&g7~~J^iv&p{sr*m+&dTuXZ`D9UZ2r#Iffs-vPVIFP?|k2!v|(ZGZn| zp_IJytDi!3+%Q@?bZ>i4-_Z`ubGXdb^x`sSf%(lQg%j=-B zVybDs2z3BTY~HUrvU@3>A9@Qcmg@q^1CI+G*(QWk!2{p!f%B>7LRLn9Wt~13mMgb3c|1Q~fqKCl^;C!ZO?236qTtS^+d(Ypj+X z$l#6`G0Hrj+MwxII4h5Q&FL{gHjDm!5wt5UyufawdYPo@SU%8O6CJf432jI&w53fy zzgmp%8;T>q^dFRx1EY7-e{*aFGcyA1n$gbqt9=1j)}P>qdl|EAxtMAYqI^`uf)>Fj*zHGUO`DU1w;&-9%Umc%sb!IoL z8Bnm(UW|t%vZTapONiq8ddloh-k`p3-}qUXHf|&~BC`Z3ZC6)Aa5Io{0zqdZbPm6* zOBE6wV>8DJ@nNWRsE_p1S{!7G{p=bFj@g=;k;~)D*6DALdf&t-m-q0>f7hXHZ#|o4 zA|flsmbTvazREtNYXOrE3E>OVRPbT-yYS}Kt5d(mzHA8rF8=8BfzLQaS6zMAL%7Is zXVAYejhlD62_a+l`I1-b0U#C76bC$CjE|h(xsJK!P}s=mJ5w*7@1H`vJ=ZN4qbBe^ zW74;{KwY6+yWCWmjx}I9_71q`Ld&f1OEEhm%aEXj*cC|fq%}lFsGf5xuihLn-hH*f*yG15Ym& z9mKWx{CN!0`@z83U%zf`Qds~dJgk&{u+E%7d4d8I|7Q76T~);?erg{YJlR|@k@2O! z=3AxJG%EY+lbx6-itM4=%7oYtZD!>-G4;6S!$-U&MDyikX9I9n0Aaz{d7^m zSM`CRSm+_b&6)UsY$Np5-oXK%seWz{|4W7lr8PlKjP@Q4E!mMHoevR$;o$}@E(ks4 z6+d+aB1e3W3pgElgUA=-+Z*uoL^@0c(&FMFtRQKgdrjH#2334HyNXxQ6Zjy`^r76~ zlCKCT^;G1o(OE|Ol0b$sP_~+Hwq%Uq!~}Xe6o2R@3X~Gt+JLcOlem5TI^PvUlpGpb zX>{U55h7yu2C(P|u7g1UIw{?qVUYaB$-C{0tIbSJC1c*8mxK(-@ywYVB-a7dx4>o= z<+~;P-N$sp(^z$6ge6MFrr~GTh-*yPIZ+IsKD{+W1KBh_2x7qnMf#4K#+frch*g5W zf$CjVQDF`7!1QRB$GLNc`7TLL3T-oeGuz7_zQo3~nN{(98u>U;CLIN$X>0l>Ab6e% z==bn_EvW*D)OPKtyZ7%ScKk3GS9Cqktn|q5nF;VXlj8))NpEz|kXNA!pgZy`JNx18 z30x@XDiPUyHiLO*nBC{Hi>M61X-@w9d10m}d_Zj&>m6;UgPmQ2QZnv_qUTvn&9}I& zt2QZfuUWH)2}XC2E{|>t5lD7wLei@H@zMu{(IM3L0vpl$#-lSFI8WfcQ`(FMaZL01hkU z46~^*{kY$iACIUka zGV`pd-fi#Rr4cA+)h!^ zI4RpZ#l`cJ14JXtItWT~!_DoB^*-z@3h^?!b|mbo@83U=+xXc$;aTf%8z~tXq_Vre zwO=aZCY6%4{M`ENHipik?lHs0Dg@{X^`({;oWXXCt-&xb>ZhRzVB$NXH1z?5VXMy# zqYNMihY_%@LR>(f41wwtFLBRF2Y#jFqN1Wko)G@g?X8fA{Jw;>fZ0<}P-umeV7k#; z0m}LEpiQGABk%hr2I}l}b=himOZx`|z>(Tn;v3C+CnBQqw_tE=?2}_VaidKOR4R%)|#py}P?Rv;V8=Y6q+l>{BR)6wZEDwI_=IvdSW62et$AXgf^T z(O|})EP&hTqg=YydRby9c441C4p`qK`&J2xVU!Irw;Fm4vu*VNkPku>UZ!a6ENvlMx9=6zo9VqZ2~O>j8&H_z>wi zUz~277X`#?m5bvdYPuvAmWcB508UjT+CDf^@4yxQZY47_qR3e$gya(rO>3nba%|)` zNz$!1IOpL(ApO$U$H%4_o{{gv!_rq%@#yd0qI2-zb*B}a_?V=G>4`}`8wUr+rcLmt zkzNa=oA?$*Nl*Q}ML=q!YhvjrFd@aRohZ zmCMvqxh5h8smBoL`sS3adf?)B55hXTX5zR<>@{5IE^MW^4mDPdD;^1C913gh$w|w+ z%%kjbp4O)Kui0 zSVnp})%hcUj!8u{=)l&E?IZBfioK?AE=ID!DQV@Nh88J?HlrnX`C0)J{0_V+;tRtE z4jh0I#HA)m`bzNP?>?0)!GPXsc4wpdOHM8y+jA#0G|!>s2l8`!zJ0p}Ea^ni*)N2e zyiNM?#kFNHx1I7&_I#wSDSMw0LFE^ybBG7L~Zq- zq@_vLZ4XF{!nvg~^KC7Rx1Qr)AvA)yE3f5{(Xf_=hRwwBTb7>>Tc9=v%G|yB4GFb_ zZ0R{GXSDomp)xVo!Jbsw%b{%kq3pfOOlQgHNdqj#?xqq)zQoKRW zAsDA1m+9SVKZr@tKWC#!y}yn zmC`k8pkvZAG5}lJSS&zo=88{?FIQJ$;`7VPDs$f@k!hw@39&bsE}fRPYf*J52s?qm zBNQbM8ttWz>+7%LlDWkyfe>A~6rKT?dn7%sC~CGK#C~1k50~HBsubGc&|WUPU=!;hM2M0Mh}a z|ALQI0b$H{@GY_UR!m5$7w^ngVJVd1K^XCl}6)D&V^Ydq}Z;#bDbf_`< zEO;G9ShWZwR*TH{fynF|90YU3#B>6-RTC5L;-=67uc@6pV?YnFqk_-*p!6A-m#kB} zjlF$zc=$9{qwRhiJvea&cjzVmMs+`E8riN7U85HBBM$8NQMXZ38QlBF}RuT2Z@6n`q}*qcVYXGyBw=8(9D7EbFVG6>~?;hYC#| z#8$%oo21PG2U@;K2{vLp5AZEJwh_77JHvRDyr@9F$>4c%7oqdL6B)_5e*F~sUNW6H zf)}BVtC^XNN-q?{If~|UZPCiT z>?Zr`;m9{fR;PVwbA8e#{Yv@pMg50)kNqOJJ+YFImM!JI0vU5IaRPpW|2g8;Z zIjf7>84QQ%90hr4c+#=hJEfPkj?Fx-Sqo+;=b|7bTiyN@pX7=V-T6JhMu=lOYr#lXoy*oe+zDH7f`(CrWWbF8Haps^O zH8ifFg2NGq=>Fw=F!R8A^W@Q^7f2{+)|R5EZ$y(~WAi93t_vF|JfDmOcW(A7myy`~ z%6%P#%CZ8zlDz3Bk2-hMMXe~LaMW6EEt`}vK!&YNT|B6vjZY39xLlZKTBnR^9JLk< z02!%V4YHgw;YUUvIUD?3L8(&$c>p781YZ~OfoCmneNmE^qV6NhIRK8up^sTUK!}d^ z28AOeYC5UM5QYrt6cM9%{s*Ed2bjZAqr&W-w46@0kR&Zrk1^9Jb2Fx!OsOl3 zkf0H`f}oORAV!ZLw_O-nQCztzv*6C1qu&$HyNOYSB<8r9km`gc&T+ zd|>%F3Vxo%DFj(V=fRT2el$^K^9Tr<~W!-Zd~g ze+FDO9AqFk@xg`BZY!7nwOp+D52j;SE{O#NQ6eUyAsT2P16J`omZgy~fdXVrFl5dc*l>$WRzzBQ3S0QE z^E~nvDEZBO#`j}`PvxSen7*=1Q?-9vS$WpQg_(urL;E5;58V?pSZ$XXRxZ6x3qAs3 zCn5>N@!L0<|%2O?~14^FsH)+P>OI z$-Z}@rKo_vP0XOFK}bC(Frv)NQS^3G%1Ya}S5!t_2?pGT;WeY^Bd~Pw#&Pk6TX_g5 zlV*z!q^V}L#E7j!1gSz#iayw9IIGM^qg28!&Kpb{>TX zvWCwPRiTH+G)`BU3fsU;G%*QM(QL^D*~_$)S;h3ZrQ~ccHx~esn^sXK zEu{{9pP8O_rySn5R74wW-(JSyNz*SpJEk^-XRz`j*~q9G5Zk-x(vJ!n6^d@6c->XL zPXV2dSHeT1yt@P%IDtLkrL=yXPeKp)A*mr-|2n-NFNS-;u0-c8Gie8eBlQ?oOH=_L z`7(7`)CHxoUk%IaCXO2zV9#Q|*|aNnahQUi0eM359-^@XJoT@*Q0g8ya)q9t6dP?n zauH}BGUR~mmfbePCBz%VQKt2?twP-oCVr!g1?1c%#~v;79g<=3SbZpj{xn;*Hg(Y551(_a=PQH`TL zcfVYo<_rjxue(wraYvuFdYwd^bdBYwhr-MHS3%{Rp`X>_P-7k%*>zW1^mswnRT3wh zPKdHz-uK1#9)@xkx5Pw46vF!G(WeBErLy6sJ9FsxLd|_|dx5JAwK|yH}2q&I>ON3*5AJ6=O(Evb38D_dCh^p zcBPMhe5uS%GK7ypQ&jb+XRja5B1`bLl;${4!&1TPr>g}!zNO|kGbm-%^ryvc8h&4r z5U1^xn!NV%+@RFTS>gN2@th^S>uib*wCQ&2nLdzj@&ta2!oorj*7irF6hoTEx{j~D zZ)X2WaQ1DbV9YnIxf@pbR3bM^?Exf%;B9w?0RY9?NheO+`~qa}%Y z59PRTJJD7viYW@U(Z*=@bK;IH;uhTV!S>Y-6aB8EF~CX+qx3^cWq77 zy0&mB*|74KpLn-L2G1tQ!L#KF`V+3pHp-Vg%r|0q{Y`I&JZlo5PVZxBURHP2%sJO4 z6{KWFP{S_}!>?OJFCVMgjuwLg zPUo)o7dRb7+#Or{A>bkV8ywHkvV^llPY_{Ax9IEb;vB($qeMa(!U@|8Z>hV4fZ90_`(tEsS8ki3R=yjTySCXW_i6U5(q8KW$!rY_z9tjQUqB=NSRr zpO5sXs&TV_JxZNrZd~Vm4W}IT@0tkl*B@5W^zTFwo_K%=GDCf~fBzd4oaYrg5h@I9 zNTtCBBM5-ckVMFs1fL}UONh3BWnjir!ZsWp2t2?qARBAjw*3gTbs?i{%F4jLqQVgO z|926z^IrF*RVSe3xVC012pg2Q-Q<}7P6hIYWG7-Bg&Orl(=Ro4W=L9ndBJw_3fSE# zxfE*wwGTu%OQZyo>IQ^B{s~u*8tA}0v9(cv!*VZQp)CAe02%KzHGsfxQ4&4Rz0euyHQZclft$bL=Q+LM?+z6(S}XncVnzKUOy2 z8c^!Q#0=xpgX3sSIkHv_xp{nS*UtutXMaSECb1;ZC$njsOXu0ingd!WN*TQ;q1cIv z03SQOFd71-d=xMGjsCIfyE2+g7BpQC@y{+A)fN+r3)XSInE3aUgh$9cA2b_O0MBYn zS;lvuO=0%G5{xsyc)Xko;K{uSPemi-$3(K~qOCPCLBCgi>KQ%l9>nx#z;)Hp-j4Y$ zNJ9@7A`H>dzQBI7_v)&FT>5xzKv%y3A)}?&?qH?#vjwqP6yy|}F{sUpkxS#BAFbB2 zgMg6daThbz!xVv117?#-?+2pi+}udG$ZOID))TzzT*$UkV!dt%lo@?;_zAWFer^%- z60Pv-%^7K?>D` zv5l+gH_iL8Y#u)uB^)qq6Y-2ruPuILNYojW@2fW`KS2JN(=yk-FZT@hOJwZzKCBo7 zi|Ly86W%yr5DKCLdP_=zq=lqpZpFD8_3Gs)JV7rdQ zpGiC$UiO;&cm6-E)q#SO4gXeJ4LBBqT!EB$qk=o4T_9h2TU~v(%JLua6|`3bDZV^V2 zL`31E<&KBLn{0uC|P)s{#asBVWHZTs#fdPSyN} z4Lyk-0?mE2Nxh!J%qlq)`y_E9EaaDwI$hO;17?qalCI81P7+UEX3pK>HhYJfb1Ck1FI zHkd)Y1ahKOYmT!eVrJY7&iD60l(0`)^zP&{@$kcx;(w!@gIDWuHzvbEbSA^b$shG4 z^#;_J)hs-v13>^1u%xWA8iBPzpEPi9w4+cKZMK-$*~(x(l(bwj z4iOmtgqjGGRWP0l7CHukh2tzbOsE$TdjGDfY5>C($g>vI6Lv~(PSngZ^@(*!*dH1+@w773gLq>F0%_7q^ot5trFVN%5`&fw*IfKG_+Kw0eblO;CM z&XKG3kkc6#78dYPN*8AB0aDGke09cc#=E<#*#jRAiY%;V?9rlX8W8wmWCss7Hzs)D zj}L(t%&D2~>_gSACrcA=4@wC80kLq|>Sx+fL8;o`M$5&XT;{p9g(l$e6>qpwybACg z2ZgPlognE10UD=3%_NdYX2%pIW8*oDPjmvfKirxFA^>|oGA(8xO&pND1u(1#24Vz* zzzIkq!HXclgibvD48$x(?Bt~rLO;jGFt;dW`55MJ(Lr8-GFFyM7_ z8&Jjzh;gy)Ay0c?)(BVR=b69I8);2SivT2WcEu`_GMr>5Y$<3+v07%8JG}ky4D@6E zp8TvTnw`55tbl%{`W|+a5^>77Q}MF=_PjfH?>-NTfONl}I`vhOs8vjyQe%))P=GtH z4#0hRxq8+?7KE)xN@f8mwPE-2_Fk*@P=yVt;Mmotk8cyc^`&t>(%jgZ_3_5R8Z$KD#xs77wRjhN2a%%*sK->K>~Mum)@ zGzbQ#x`dX`fbX_zMVy6}3gV`XuG6A1r92o_920}II})%)SjldAd853;dU}mujMI)I zQmaY`+I3M)L&^7$WdUTuFZM}M zk%=>!V<+Jc`RIQ*)i%{VGq>7&cN{3rEiA;hcX!}!fwL>;b_GNN0Syk!%Iaz;m?6-s z%h1DopEGCPXgPx!#IhMXT^cO|wxQ|cN3er2C2LevRE*3_O&y(`Ymc3t1p=-m$+tAg!=LRw0yUzD}d-59!FdP+d9G+k7TNq_}?fUicA3spX zK-eK(mS7T8T10#$I%oaZN(DVpFtJTa3f@` zp1|FR#qvaGVh8j)psqlYTDzRa#q75w%Y{i=h&pj7friGeh%fvH{#V_JR%^q{f(2`! z-x3Q=D781OU5oX?3w7}ZYp}rR>Aqp1n0ph$(ni~N??zhGZ?dcjvN(D2!OS2|GPav< z{tkix=#S9M0^oOla+RQgz|3G#Jj#o}AhF-VwYi@84g8)Edd2Ie_NyPr$j6Xf93hBt z3Ru0#>33n{5AxZBvIexM_Q8X&?f|`xJSx~u=3jv*hQz%Xz&RE?j3?mE8)7a13i}D} zPF-CclU>}gIiZxIz7!)r`o$CY2v=BngHmK2ewdbe9lJYH98e-5@IS?|?CcGvhAfX! zvl?H&P1b)sKeSs;?!MyrhO*p(Ti7g-$$UIb-%anG)-Zu>70BE#_;R&7f=3c_hLUGj zKURSa!e4FAqPcyNl%Fy(oS>A7vfK2z^8(Lz)nlW|Whlrpl-88_9k^*x9~AokSLckg znB#224nV=CXMHiw8M65~BwCzp@sd_AFKNX}P)&Gd()5W8%_B#MsU`!29Y9y3)ged` zTM6^|Q9%T~X!}OeM;!E!{-3jHaGvIUSr&!G^Df0zj=O_n{&mBAorF$~QH@XQoa$ZH z1l?4YePNp0W^Y_9k&qxSN9&Q<8z59YUhbR9&EJ5EBnXmv_|UDal2h9n{6~n+;yLJo zz<{TqR>m_29RrLWcT%~U?5m@sZ!V<1vwV(j(yg|5h+=v*_LJLHVxTL(InsPWF$iv$ z1g`^rQzd$SGAEg-3JLS>tp^!_WOM@v>rV6qKJsy$4W+zW>tbh?^$`enj_pJT&m&=3 ziTJTr?rz$CqDpL8L3AP{jxkJge*}Ky`?0sPW8#DU10z>)>;R&&mZ{k&WrLaI$Dz$Z z#v-cHrKDSpg9k&ZEVExdJ^31`xDY471N4Twv8u`z>Np4}@$cZrj#0*;VTs5PeEIs$qe+IQY#73= zFJBNwcxV?MdT^NhJBS^&IOcIO;nG8R0loqZQ%-g^sN1K{pM%W)F+HsUA`@=I<$SQ2 zAVLYB%4>!8Yzce^)==}}bxoZRwTk&jcsqf&Zs92{f*Bd-xH-f+Xoex1g1HHUtsTNw0|noS2vuUToXZ*WV2mzSbmKd0`!5eq!cf|fFg*o!XJ#q95H*x!NRpEo z=;>M2AcB!a{m0GC&Cc%r{gZgdTWYGYOms0`n{0*2jI-itUejga|Fo3<3;zQk$v_Sh zMJ$+Dy63WR_u)iCo$-LHfTYe~u*3iC*tP5QAh_0sI))C%;QqxlDZ$0~IjYy{v**r@ zgW3VrMX0TS5QR)o1qfo_4C866X3~$bF}VxB<%%y)qcMVV6KfVi01zql_0I|lyf9Q2 z)ej0-tN>V@P>S(i>0i1^imi+hHRVUow)HzP0}77Mymhri!mO)54G&(U!um)yWU*Y2 zs+-{KWQ;iI3yxilcp&!Uh!;ZpAQA-BbMimzEys@@ExUVj-xiT@%!*H%p+YtaoC8c+ zU7f`X)_7Ow2%eH$K-zPsgIA{lhb$QTI~XIZ#3{p5Hc&M4Jkl;1b_=@EP*Z{S=6^eJ zb@TeRjkbJ&c0KDU#5_%O&FyQ~IIy;GAh;z0*)rOOzAw)R4IjMn;{KGF+e-$$4(7`rj5vsu-B}*%I z0oaM26p~kGSKPvH!2gOT^KaQM{&RL2e;N5p!16_xbi(*AzY8?W$$cMRlPkzti~Nc= z_sm{-$3(|;X%t~fJ6j%SD z7TS_)gq@inlqK^2sVw=rbq&T6+XNyk1_y+Ou-^q30u!()dv^NjLm9{v%rKq?(2Xp@E6C$N+>gs&Fy~ z03n%?3^x8_S(@`7hUiK#1pheYZI$OSxBFd9O);j!hRZZ)*yYG8Dz-x-f~4wXrxkcf zvTeo&XM_rdyq`FIaXJI>L0wQdk^|Hjs41DiEGf%A=sShR0rOw4p>7-E-LoZxYC6#h z$Cxkv05S88}2|!ikv^6mNr23N#av>`xAtCHKw|0PZ z^uomLSnrYD(0Hg_!%hSFwre(6LTuQap7{_stiu;Od+y9&0gfSBf{qS@X(4fpQ0oxT z!M=b96%-g8(KRwAu7F+fSU}}^rPm(TJFQ5GZ7_14m*@Mdv5|Ch;-PQ!@xl&^BEi%1 z#Y-ok5{XNz#!uv1PtS2kRNLFN7CARSC1AT263Y|LS1^6&s7pFn|#c)hTg&f&wqG<|_+Mm#kh9^#F#mG-Vz?0%nUNKZjXhvhb22)Xi)N#u}u!lZ? zfXH0A&fyb!Fa*=KHV$EFY#R9^kmp~=?3TCtSyt8xU_#fgV>d)sg(?VPI?!8R3H~oo z6mg2tV6Cu^srb%j!?AYt>H&;Rycq6!?p(drxv3H_`~J0vOwW0n69pcke+eul{*9I* z2Xe9*_!K$V+tD#2Dd`OGJ{-C5FW%juhuGA8Yo{O!13MQU7KV!snHr+0>-Keg{1{&K z4f}U4!_L>39%QIy8|*4f$FuU}8e60&(<-AJ|` zH6?K%*po*-V zoHJQ1S}wq<_2p*_H?!_jS8o6X-w*Kh1H3ooN@XxK&@SyH)Cd1~PKp09ol=iD+<5(^ z|8}FqdUB#Px>7g;5Qtigqdvg=NmA1O2?nF$%)^qyt1P09{U0D{VpWm8_Mh_)5DDhA ztW|>$VJ{Qv6A0d3e?d)|Tmsw6yB>IWcZS`#XY(YihUgx*lrXGl#W5ZQ)Q7=}kuz5A z1IY&csiBtYsQAo&1GD6#BH{2^(j8&!A4U?vE>AYQ-^(#mlva1B8R52se}l6e(E zyfbKIU?+l{Hf0L5JnAWEY1b?^4vM`;@y$2zd&h?)*E*gkMw;=B-+~*ae^ao z5x7EbZZmK@h_I143>uY=B)$+y(`mIg{2z(mAM`6`hH&fKJUM}rD>!_v)agQV*GarMmuSB*r^@&Tj{3jRs2z3K*6VU0+(7);$nY={5z1J; zfVkSNpn%Ed#TZ)YYC`(s-}M+78rEkAZ$ul3MTYt$Iy3D4{ol~8je9Eg9=0gXe4nn6 zanSiervT)4P)QT*xKk=Bu&KRNt$`o~=Ql3Aom0kLl*sq)^qO5)!t-)x!hkcg)wtcKE^ZqVi$;Do!h&jaGsY2{TW7iT8VPZU&0U!&BmAU|*Bx__H!@XM1M9rR@Jb8AgUhtjTHD_ThVr)r_%MjDx?X8vE2gl3J` z`JVCl=STMHNnD)|LI{j8%G1w1$j`Q89rI}`Wgz86kT4Qpbj5m~LNWak!Ycp&%!RyaJ9Vd-b}2!ga6q2B}O}Pv$8I zl;MLN=|$c3PYOfqOb(lc38Mn*l9`w+EGGs2Hn~i+oE_v^zdi>g4!9w#Xj0zSS!9@c z>^7&QIzJoGp~f{9;E%?}&ZZtS($`ln&71ELB?z=0q!`cT8$yS`K+4HQyz2o1fx{(r zSCe4*J{uZ&lI zetvM!Awng;W_K;B91`>hMk$2_4Ap7`>sKTVEH3yOz3l9at>{MKzD5nT_nz$z_W3XY z0Kf9}E!GlP%S0bD-HXpbDPSl2)7cPUFu(@i!d{npj9_2C-v8>=wojj+)NGu4%fyGL zzWTQvWDp*XcaUi^s|rh+$OvuxN5mGZsi{Fm3P4oH$Vii^CEIrG{BkRR;Mi-Doi>x@ zIR}~WfJr{rLE!42w6f|&qpzQSA_O_XzXnb{!?pGD@&bi(REQm~$-+x0LY5GbTG!rQ z-96ra8c!pgeJF*)84Vzmzq=uNM?esCm)IW2)?9wemaiyilbs;jn%qkE0$yvc?`vpH zKfSf_Gqj~TiRwyl&a&zn8gi~%M}_@bzzDWort!&1{wtW~UauXEr!%WyhpIR5Oi0xT zUxcQhi9@1X6Kb$nV&Od96yzGPHv)uLcixk-jeFI0A))VYHkeBRhOooiM}XgXpvzGt ziN-*doBi4!?A-S5z3lJ5-+q0o)@7jf_hVvg8|FU0qytEg2@f^hDGwi#82ZAC-NY;ztt!~?0FRy|TQSoO zM!U$Iax(s<0t&g4xr=9bO-e5iF_B?!zq@2RcPYwz|> zxGjoatIdbeF<3HNJ8y>F>eqggyHzP9YAvXWInwpicCvN}8FNv&l z*nT6;r${nFn@ym>TBEK=x6_~?&`vlXbM)6F$!|u zRcx&Orkukl-SVF0FMqg*_LkzUO zFUWL(Cgl5fhb4g`b8;_i01?b6pi@>u)Qee0=!{VNKqyf7nFl#Go0bk%kF_`9p@?8T zWouj2H!fC~TUr~B?>v6^@NIEXjJv>>wU&0IR&y)2E#7zW z5`Ips0kTuApGLmbD$W}2h=Z4bpYkwnHD+$2Q2qoHurtvo+wZ_ZkoJ^m$+Y@E8{LW% zLhLb%4i+lQ{VGm+GE2GAJ=GGhcio_e@2^KmPa*0}#EfVXGdQq+(NL;4kH z@~#5I<$9q{aF*Pf$|F@u|NOAo)V~W0*ibP1U5-w@r9SIjRgHe* zJP#_!VIm*BIfT#FILDj>F>d9}o1U>RucQ27F@YG^YiO?ub)r`rY%cE25>ioo3mYX? z{ug@w(5;moL$1+vOCzc<~EmXw=rSBg!-1BE(OFF$M91)(-ox2E}g=2WAdV6|+ zkoaG@;xpah;gauz&Ji**u$|e@VWUJE941a$O0?jOL>AsIE-C^$;*P)u6gk**=V86T zpGNyEvSY`_^I<=baM%kTbUzDTvV#G_VeI_LD3l;Dg};|jEZi)ZCLQY<_oKSASD9e z6cV<#Zzoy0DIHpTE;yTyqV6mE!4{~V6fKAWi>w$@3R0RX$8G69FkowYCg$(~Cxz>* zn!M-l^;&FaTkc|gn*57?-#s!Z?DTtV16dxN;qW&}4N`mZfjGctFqn8~vjIo+AsE5u))&t9hK-(U3ZGZr15X)ODFi6~WM-gJ*cP#97N;W|L2)J9Slg_9sa z{p+|K%Q8C3z1304wo%C=hn`&M9{2pAKxopikZ(YZhJ}|8oC<}K&mW?3mb>D4dV_y_ zpAJJ%U|@z(&LFf4;H0Fq&hsU;M1s=QQLl|%1fq)nlNk^jYH2ll}W@b zyufA4%ac8?J)m5MadX>c)kzZ#^?{J>nSpZ{cw|jj_ia@=`jo0T_dN@`lb484g*9jO zg|W+<7RIh}R|vbO;B|x!d^qKSpUc|mFYmdLfbiXP`#Tc9PX0`49Dw84K_ap;BS?|A z_H{PHy(|FpI6Fv&25Ed`W}u->RtrM7(Z4|9vm zmzf@*??zqm;^9NmIEs9z{Y)t4=f7=N3DImvra~~ST(LG@eKV)lMFxuB{cluxo>di} zKgWL@@=aG5932gJTES9Qgv`4Om^_Gba)+?+aDRWi?JV3JDvL930 z4SbKu_q_n{gZIZ%@ODf{>oSzDh#SI{$HVifgJyFmj7j?w>ml=i0zi`OI-(RVUAhE~ zW5}bI7LU@?@9H1sXTzYf1Ol_vnxB{|NK3mxPU*6K61o=%iBcM8s<6pBdqi- zg#WBa-w3nEtsHgJoO9n_o8?)E8XHw?$vrk*K=_u0{x7J># z$Kag*+WeA#Q^FT+)BAaCbZPnv%^$h>VeEr#cMtovwJZ1x>=OQY_YIXz7YRB>Ry7Pu z2w8`w5iEzMFeP|f?=ecIS+S9JG{osnc|o^tzpt*gG;6exg6#^E-|mE7+;lLSQr$K- zCiYs)vU#uO%3G{AD!QvifA3f(=CkVk)}6)_$YFLmGO03 zD;1X+$i|pu#JF|WM`&0FUD?MEK7962(vN?`ek67zR6%nl8K3y$R#)2try%< zo?5&=ww%D)QFX4- zWGF}fe7DCi2*N&h0af+Q4w4t6__b5;It1n0L;MyDznaqu0MGH271eXW7e7Bg3S1U$ z#s|oo$5+H!vbXl*)&n~dRMAxJBeO9O4cpN0aM(S}P;>U_<|5@O)*a1OSshSS;0PUf zfPPQ^*fG@8R!@`w-9g^f*Yur7Xyw_&!%rt4c751DP=byBJWDY6ljA9>hk_eE+DN_k z7KKO;z~=L1V?{V1RHsn1QvCK)Gb!)SR$Qun!f8?l9UVRUHruln+Y<# zy02a(wNV@8NPxX^t^R0kRi^L$Ce6uC6;C>NtKM z!iBQ3BS*GKMieKPD4~$dY&y=!&gv8md!JPlaY>PtE;F(zyX?x@Eqn8OU%&DC{eJ%T z`rdbZzMt>&e%{afd2()pDhI?EaGR1?zX56F1UrHu9#(j)-1vK69DFQ=5}*qQOV}hE z9% z6a&fd7zHoL#8~zyoZzR8_%vsvs;-U)UPtMeg!`q64c=ETtJ2JyT1T$#2Yhxc4G4rFg>go(EIOiw5X$D zNC4<}xM_O}*84gW25?+k+wZ{IvtSNCw1>9Q^9^kz&=qhnZ{#yDn)o>B84bd3U$D)Y zYXq4bOnYr_Zx0Y*<#2NA^+9&lx`;^~aKM{S)bkJzC>Q(;K^MnjiKi4JUY9^ru~qJn z+w%?{3!K}_^yO$d0Pp}3D1cx!um-Xq0&8Ga*!?&gipWV+Fa)DM_}IWHYy{U@?=7WT z6?35!&}eA>uWAa(si+iuS#b0RFL7N_BWNXQ<<8B{!gG+20@w}JBdm9!a8N@$#_NlH zUgn;J2@mLsb*fQ_O?U%By@A=W2|&>xpR;iuxa(-9!9tNi!GM%uJ6QY7v@I<7ykFt@ z(hJ&qjpp(`K-F+J+~L_%qG$W&e*XTgAKR-?19~uE;^VCsA#4%6;rS2KN3?$`phGyY zH`|=*rLwjm;OE|}M9HN^i+`IW%r8>CasAKT9Z>2ktC};8wt_6PzkV63(3%$xB+@JB z$uqGt-1qxEddZ+4nzk$$Sbdkx)Q=v92q1w>-Fz4guB`-z7x+8##2xBp@ID8>6hka5 zau6arsHXqS18SK_)DD>xOzn0xNWs^<^%CLF@QPy!Ah>jCmgP$Z=}qaJA@lR`W}4Rb zMhs@UagHUAOwF)jUbQ(5&^M3n4V|eccz6`XtyZjWP7fQKd$_rm+~1bjj1R>QUNbhb zbr3(!0Oa z$kN)40W*;sH$a8yUb(%yhgC3#J%RFB4tz7Xw^`>PtdE?J-=X?(y)SbBI;p{$QmCGC#=k01-mOJ#) z`d#C5A18~DNrE|h7)wsNU167bC%SoTq2s6G&yV%S$I=;dq>A2VT&+KLjt&PyCrT;m zpF#@PSw4$mF8+;Msfr(PH=9kBLVR1iN9mQf!v3#$Z&I1ym?CpPZ2|ii%vu8iHlewF z!C(h;w=5WlcBRN?VIw@wHuv-AXaz2{Ws--VKLpy`=-rjR+FEo{o6p8y+b8;Ed~C$axHJQ8Kd>c@V;YSQ{Yc;QnlO- zgOX?cu9A4CjYzKyu8mOj`i|IHIlB9beOnSiX>^x;Z8zrgF3TJiPF;78YIKpi{Qywt zWt4QEXcsSouh0zh!Asf_rOg=5sOXXxX&f};o*vB_j>D$LIG*LI24(@{z!~R3)9db5 z5x?mYwK3$Sf^y-Gt(^EmdFOB*d(^jOkS6d66Y$f6F@8zKpQYB1_AqE4&lVYyk)ul* zvV5ie?9ykbMvN{k=z&k%D?!DA4cGQsR|occx9a6N-wc{Fw$MBA>(V30OyaOv2)5|z z>A8J<^I^`%$yAKQq;K_mHIRa5l2a%cW?G${EZPVS)UvW9=}i#(C0$_>o$Q>8!y7@R z1thDeY{GAvo$n8iwbEq zJMFIe3z53-U-+awE}YDkVY|4Hc=}^&d0X0iCay7rYdeJ6PLD5h!T!@4`jh1!tWt!L zRrXWa!b*#6jDZHka8OG~|UF1A}EH7bst8w~eMn*(dELCKC;stR-M1;zJW+XeDnF-Y|6Bo9vR^0v3H;c0~6q5rH8?|q=?N{3tt`cI89 z?ceUtb0JExkv&4JM0_%Hd5_EKDB;v$`e5qUl?s)EUkE|(caXN@r@IGc*jX%UYus|1 zS~nmE`CXG?{_;EJcC2FG9+fq+gb>5G!mh@@Yb79;-+UuR(J?FQpy5V@5e-+>*yyfW zp!OD#T2C~0P_28$pgK$mqkOz9KUjS#<5>k$gWRb#tmI%H65oU|+6xknX7-6ty53Pf zXEaM-xwY!EvJKg^IM4pCk)x3_3qK%ytN4BG;5-S#dDZL5pT$gEhs1i`8d^3E{1lbW zVvr?M?VGyi=c1(#doE4RA|q5~yR}ZdPQuBjeSahn{DYkJqxNaRV1uqt#k%g_M@qvP zE-`e?Tn^Yz_%ZLXsYABIS0`_oMy{5t3$9mp@H<&wl|ijHVIIG0z}m3T15CV3`|m~u zxsO*5b$3JK{>g3C+OHuR$Y&TEU}kk9(d#CgIJIP$Bhs8Hbn zb*H0UB7Mt`p^h_{Y9dk6A2oG4x{==2q_BYj@V|_+xOt*^d|!9*kz6{%DxJ}J3o{y? zDo0EpK}!{bJowmOa_7ZMj?FuPWEXX5p^SVMyXe8;Ew3>BI92|c?O;3eR5ApchO$nV zJYs3Et&1b-(Gk`p4r?*&C7|%Q5WV}U*GE|!`OG>=G;lmyX}i+=VDyx~ro6)aTk{@x zUbe^_=Wx#~tD>%_JFKX5={DC-$fm%LhiEU&&=h6Kc#T?FFE;1D4dg%HW3JW_#3AFE z+nukAN$ibd?Uk^c7eK@(0m;&PL$22m2^7nJ;ZX`?yFpD75-BW)y!FIwL{|!A-zgt$ z<1)0;#BcRwb5=15T3{9M8T4E>cbRRqS_~bSVw6l>MQt0RSabGFIE~il9Rg6%jfg+#WIuM z!#OHnHW7CkY;4^5*d622LdO_(kLS!4;!PcNHbW5Wn@2}*7;|e^yumwbBS-L?H|9rIaunL$$#Sy*5BLI!?%2Bx?gm#O;q#DQQo{OHs{0>E&|{)I3f|* zi&Y?7FZ~eP7p+?+?ixt1|AVqXuP08ssDbjA=hwr z5mi@@CwTa~lDB0K|CKJ}phgJ@n_FXhz8 zOKbY$J4q9pNfR^Qy>H#=A$z5&KA`6A9I2sJmc4RErd$xIgJN^!Zo+lQ)`$o6{XfEw z%*Qq-8G-I3ZUEqCWMsrIEG&TcDrm2jV>5kc5uuw2yVR1D+(vHuXwMzA#_hky2jYpv z+7qMIGkk}*d+zx^T~KFN)yleybJFh13h~RbOMg=s)G8)e)BDM@J4D{~^&wKtdXar+ z5Pe{glE=hea0&|>>$ED38hR@8^N**vR*UieHDA8CTz0i=DZF*x=@80ihAo(8pJ%vt zhrH~k@zhL|Jhza=M%FodG|{c^4{y3l!Nlt7{8dvH31{WBK@)|F^f%Y*5)a1s#%$bt zGTOEM;6e3tATP?`j<)rU8iB6^E9BaYtGa>t)5%wkt_3s>+R;pIO?Xh1kC!|CVYIN@ z8T+MtjCNVu{3OU#=#xE`b>49&98>3hH$b6yoA z4LMR%S$acCQ*2($7TCe%+JqIH9ZmrfvHNf~LQ_!Kybt^D!X`dHCx;r9eCIc3$*k=9 ztH{LSlz1t{|1Ma4oXPXRv>~6xq48VdBm}VL1}++EPbfCI+0Wz=s?o`^PuZeN#3K#o zq>va@ftzMZt9+7Ovy3rP;i2jUX;01U6B3&Ct4#Zk%54cvGTdd9w2G79>6$gmU@kCK zbn7CmBn|R0CD(Tiiwr3_YZdo3zw6!=2`tR*nqHXaj^bs~Reo`6KR@6n{!tGXkFWUA zzYi0cFZ!aL!`v*q3y4)MxjrW1c}g>ZnoBow%+8~vyzX9I!nHj;Z=0S)RR81U)-I;$ zF*I(dHn3dJQF2M~?5R^Z11^q*6D{Tl*%-=QaAf?}+iRG2h^iGK1F8bVWzB!{Zj#pz z*q|Lge-KV=xqHwMp^ir|qUvOmOQV@L1g4MrrHiK6qK+7vI1yi~q~7_#!gaMG%QDjx z*_QG(hh=Ho__y^~ELom-COd7}aygCf*VJC^kdDo!lJT*Go$0iho#0_1{n}#Z&sCP0 zULB_1dWw^zc|z5(i+MJ%;yf@rGRz>qLY5JIXn0epLpmoIn*~E z1I4Ur?gMo#YU?qjn~wxOZjZLNq%LJxcgIp81P)VF#`X6yva+lyT#VZ>Q)gYM<9`{_ zeMl_6&sg7!ryGz(kdPE%gpEcB)M{Xtc&)wRwyI2!1tY=>vqYXD&vUuZytyW!=NI}# z6*0toCzloxN;~C6a#gaR{AcaOF)EuZ!`fM*C9VJB7HvJIyVdNcJ{95`$)E3d+Uw^J z#3SRSQUp!rHH!KzPLZ~{Jnk%)W$%LEA$}h(%62d^2h_jcx7k|{_D(&`%S^cVdOofqg|nJ<=FGc9tFKmX04D@2F_qW?d;2o^_^K-B7atFo``L4Dr%*PmTNqzLwhp7!$dL^Hb?=3A!<`+Da5I;eZ6q!0LpiiO>B1T8y`pOiMe7^Lprf9H4^MZZ$^B2?g!7K7Yv?niO^#!M^12dz{orSEs`Q_ zknvJy*kE|bM!&(hmL9h+jnLb^Yt{Sana1CEg(eG%i(BYl3(?AgDG~dOjF`XN{M`0T|?+PO8wg!r!cw7U?@kPcqe_Zq; zuwZScJ)D)C-&?8@WzPQNg(XZ%WiOYy>0I3M@DoUA$9j!j)(TbR?ZOq;_<#P0P_*wQDm>H{psT3H#6x_7bSsKf*M4u)- zz9_45D!YadaKF>OqeGH{u=GBqxE^|pN+x}6{WO_!hbO_^Q+jtB%n2_DCG73p$@?L; zT>iClCRU~q%Q+pX+9UC#b4Pg@gE&X{N1<|dMc~=RtU&R8di?ez%*YrXl5XqhFyeK| zTy0Mezh3yHj!N4=`mS+xT|Ktl!a1 zfzey!?55f7TSVw9S_*|Loew&;%8Cl;MC~rX$mrO}h}4+MgUx zt<}H0q9`pnBd?UDAIW3a&Be~fU39$mvKxeOOOwa;H@NCHF8KRbX0VBmM85wSt+U`@ zT%4So9{(7BGAk9yMS)G_!cyQsxWHNB3Tlznsv=l~ReW@PS=R>yoC%wYHZO zgsPxs(x!N8+RZ3mYlSFy^Q)v=)of3DyH4SNIgrX$R(tJI#qlF+FOI5)WA(LX%)2nF iRfxpm8v1(G9rgTkr%!E7sZ~*S!b=zQHH$Dd_x=On;Max# delta 47806 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 O$J3)4>EvqLUiv>a&C;y^ diff --git a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-pinned-node-chromium-linux.png b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-pinned-node-chromium-linux.png index 562ec32e6f0376a8e253d423098d04c39fc28a72..5cd2eacc4857c54ff5557af408b0ad0402f73f3c 100644 GIT binary patch delta 49676 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 z zub}0*Kh$Pe1=zGhO-)$!D>fJMOZK61&un-)IXRJ%k{bH&!wSqzN2B7jlxNrDlt6F1 zyJrBM!t+K%mhFwtccHF6mp0{jBO9CS5n433y6a*W$9+r9w7$EJHB9P@*i*NsE0+9} zgbXnsPnB>Hz3rKVG;6*^n^k7AFjC2-fr2~!M|1R61M7bQ^zpgO>eJI350^U#d2eMc zjZ!1_YFD0Htf6DILPA3Dq{lnD?L4E~+uM7)#6+<)f48piUyge^(s%x-5ymzk&86Ic(iFNiuwXlp7 z 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 z z|1q_3VwP96Q48?df725{^PUZ;hp5d=O2`#5uQ(bzU{%Q+aaP$3Q>6Tf;Z_J6MHaW} z^K(6$zH&aZHQ(;%Qx{yjz(2z>%id0kv@rG4q<(8`&oX~Bn0tbLL(t;mZlc2Z!bnq3 zyF+!#D-tmt!jcV!-F44iKCwxnE*LmVFj!l!UOaqaIC-`EI>~Jh>179H-9}4#E)$m} zGJy^8)`?7poEmAS26s){`0aaP7e-&)>gz~d`m0?#Nw^8WXCT*U~{X+h6Ipk&rKl{tbtRhXt3J3Z9qoTh!au9@lxT_D-7o3>w_BxH>${0*cO53!T2B}Pp5t=E|ka< zdq!-~T4!Ya{_?6RN?$-kmOH(8QB|hy%-(ij!@_<1JIwS~6nL2qss%O^h>uULi+onZ zZ|h2Kl=Qx`Cz=<7MB)$%RJAPj5#~MAj1^={O-fwWsfXbV=xy%F969Gml31KY#6Nr_)eXq^MVDz0%cUXLM4->LjFH)_I4^mAl-)c`gFkad zNnJ^wC!k7$);4#%-m+lW@Zsu%Mnc-4Rqg>SFCDaU(bA%SEi13^_?dq^{psj=zj*Ti zS}&G*4TW>lP~ZWtRyyeJUt0sS5eO#t(QMRl{!oKF8f5e& zFdH{Jh!(4zcnXrlM$WOnopU^*z!;R-!w>o4V6AYrvf}-oA;B^f9gA=t6vEop^XVQs z_`aVueCo$7MQzIX_7t$B@n+d)nzqWN_5S9e;U28W#+bCARJ52L9MNC`U!;#yo!j=1 zhz#41#;{HHez~}!{~B^0U#EX4UrAWl1s(_}ZL13{Ld`~xjT1qj6d4|_G_PKfC#dIr zIV!?63kjr;7^}*XoeMZytx?Mt%AqVn!pV(}4`QRBY5fkKRdl`ht5>?CkdfQk+6pL$ zVR4%nuL^(kx=u1#@O*TGZWCL$ytD;kH$abzo-HPAI1_NY{kt!{fJgQYDVIO{L<=$zTV(mRMCA}G)y>&%8=`Y(Jun{=>jBIJ}yH;;k zXCmdPDDVrpw5T8;JFX}z_) z`7v(={(P4uFjm{*@n{I}zi44)=+0njN<|99 HMt=VfZ3|-b delta 49848 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 diff --git a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-chromium-linux.png b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-chromium-linux.png index ac2f2b0661d905a7937182cd9918c93e1019cc69..cffe23ed13e199896e36caeff8ae8baaea88bc5e 100644 GIT binary patch delta 47440 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 delta 47806 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 O$J3)4>EvqLUiv>a&C;y^ diff --git a/src/composables/useContextMenuTranslation.ts b/src/composables/useContextMenuTranslation.ts index 1fd851420..cfcf5c809 100644 --- a/src/composables/useContextMenuTranslation.ts +++ b/src/composables/useContextMenuTranslation.ts @@ -1,4 +1,5 @@ import { st, te } from '@/i18n' +import { legacyMenuCompat } from '@/lib/litegraph/src/contextMenuCompat' import type { IContextMenuOptions, IContextMenuValue, @@ -6,18 +7,40 @@ import type { IWidget } from '@/lib/litegraph/src/litegraph' import { LGraphCanvas, LiteGraph } from '@/lib/litegraph/src/litegraph' +import { app } from '@/scripts/app' import { normalizeI18nKey } from '@/utils/formatUtil' /** * Add translation for litegraph context menu. */ export const useContextMenuTranslation = () => { - const f = LGraphCanvas.prototype.getCanvasMenuOptions + // Install compatibility layer BEFORE any extensions load + legacyMenuCompat.install(LGraphCanvas.prototype, 'getCanvasMenuOptions') + + const { getCanvasMenuOptions } = LGraphCanvas.prototype const getCanvasCenterMenuOptions = function ( this: LGraphCanvas, - ...args: Parameters + ...args: Parameters ) { - const res = f.apply(this, args) as ReturnType + const res: IContextMenuValue[] = getCanvasMenuOptions.apply(this, args) + + // Add items from new extension API + const newApiItems = app.collectCanvasMenuItems(this) + for (const item of newApiItems) { + res.push(item) + } + + // Add legacy monkey-patched items + const legacyItems = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + this, + ...args + ) + for (const item of legacyItems) { + res.push(item) + } + + // Translate all items for (const item of res) { if (item?.content) { item.content = st(`contextMenu.${item.content}`, item.content) @@ -28,6 +51,33 @@ export const useContextMenuTranslation = () => { LGraphCanvas.prototype.getCanvasMenuOptions = getCanvasCenterMenuOptions + legacyMenuCompat.registerWrapper( + 'getCanvasMenuOptions', + getCanvasCenterMenuOptions, + getCanvasMenuOptions, + LGraphCanvas.prototype + ) + + // Wrap getNodeMenuOptions to add new API items + const nodeMenuFn = LGraphCanvas.prototype.getNodeMenuOptions + const getNodeMenuOptionsWithExtensions = function ( + this: LGraphCanvas, + ...args: Parameters + ) { + const res = nodeMenuFn.apply(this, args) + + // Add items from new extension API + const node = args[0] + const newApiItems = app.collectNodeMenuItems(node) + for (const item of newApiItems) { + res.push(item) + } + + return res + } + + LGraphCanvas.prototype.getNodeMenuOptions = getNodeMenuOptionsWithExtensions + function translateMenus( values: readonly (IContextMenuValue | string | null)[] | undefined, options: IContextMenuOptions diff --git a/src/extensions/core/groupNode.ts b/src/extensions/core/groupNode.ts index 2be2980eb..42408fa0d 100644 --- a/src/extensions/core/groupNode.ts +++ b/src/extensions/core/groupNode.ts @@ -1,10 +1,10 @@ import { PREFIX, SEPARATOR } from '@/constants/groupNodeConstants' import { t } from '@/i18n' import { type NodeId } from '@/lib/litegraph/src/LGraphNode' +import type { IContextMenuValue } from '@/lib/litegraph/src/interfaces' import { type ExecutableLGraphNode, type ExecutionId, - LGraphCanvas, LGraphNode, LiteGraph, SubgraphNode @@ -1630,57 +1630,6 @@ export class GroupNodeHandler { } } -function addConvertToGroupOptions() { - // @ts-expect-error fixme ts strict error - function addConvertOption(options, index) { - const selected = Object.values(app.canvas.selected_nodes ?? {}) - const disabled = - selected.length < 2 || - selected.find((n) => GroupNodeHandler.isGroupNode(n)) - options.splice(index, null, { - content: `Convert to Group Node (Deprecated)`, - disabled, - callback: convertSelectedNodesToGroupNode - }) - } - - // @ts-expect-error fixme ts strict error - function addManageOption(options, index) { - const groups = app.graph.extra?.groupNodes - const disabled = !groups || !Object.keys(groups).length - options.splice(index, null, { - content: `Manage Group Nodes`, - disabled, - callback: () => manageGroupNodes() - }) - } - - // Add to canvas - const getCanvasMenuOptions = LGraphCanvas.prototype.getCanvasMenuOptions - LGraphCanvas.prototype.getCanvasMenuOptions = function () { - // @ts-expect-error fixme ts strict error - const options = getCanvasMenuOptions.apply(this, arguments) - const index = options.findIndex((o) => o?.content === 'Add Group') - const insertAt = index === -1 ? options.length - 1 : index + 2 - addConvertOption(options, insertAt) - addManageOption(options, insertAt + 1) - return options - } - - // Add to nodes - const getNodeMenuOptions = LGraphCanvas.prototype.getNodeMenuOptions - LGraphCanvas.prototype.getNodeMenuOptions = function (node) { - // @ts-expect-error fixme ts strict error - const options = getNodeMenuOptions.apply(this, arguments) - if (!GroupNodeHandler.isGroupNode(node)) { - const index = options.findIndex((o) => o?.content === 'Properties') - const insertAt = index === -1 ? options.length - 1 : index - addConvertOption(options, insertAt) - } - return options - } -} - const replaceLegacySeparators = (nodes: ComfyNode[]): void => { for (const node of nodes) { if (typeof node.type === 'string' && node.type.startsWith('workflow/')) { @@ -1718,6 +1667,9 @@ async function convertSelectedNodesToGroupNode() { return await GroupNodeHandler.fromNodes(nodes) } +const convertDisabled = (selected: LGraphNode[]) => + selected.length < 2 || !!selected.find((n) => GroupNodeHandler.isGroupNode(n)) + function ungroupSelectedGroupNodes() { const nodes = Object.values(app.canvas.selected_nodes ?? {}) for (const node of nodes) { @@ -1776,8 +1728,46 @@ const ext: ComfyExtension = { } } ], - setup() { - addConvertToGroupOptions() + + getCanvasMenuItems(canvas): IContextMenuValue[] { + const items: IContextMenuValue[] = [] + const selected = Object.values(canvas.selected_nodes ?? {}) + const convertEnabled = !convertDisabled(selected) + + items.push({ + content: `Convert to Group Node (Deprecated)`, + disabled: !convertEnabled, + // @ts-expect-error fixme ts strict error - async callback + callback: () => convertSelectedNodesToGroupNode() + }) + + const groups = canvas.graph?.extra?.groupNodes + const manageDisabled = !groups || !Object.keys(groups).length + items.push({ + content: `Manage Group Nodes`, + disabled: manageDisabled, + callback: () => manageGroupNodes() + }) + + return items + }, + + getNodeMenuItems(node): IContextMenuValue[] { + if (GroupNodeHandler.isGroupNode(node)) { + return [] + } + + const selected = Object.values(app.canvas.selected_nodes ?? {}) + const convertEnabled = !convertDisabled(selected) + + return [ + { + content: `Convert to Group Node (Deprecated)`, + disabled: !convertEnabled, + // @ts-expect-error fixme ts strict error - async callback + callback: () => convertSelectedNodesToGroupNode() + } + ] }, async beforeConfigureGraph( graphData: ComfyWorkflowJSON, diff --git a/src/extensions/core/groupOptions.ts b/src/extensions/core/groupOptions.ts index 5d49e0444..7e3240bcf 100644 --- a/src/extensions/core/groupOptions.ts +++ b/src/extensions/core/groupOptions.ts @@ -1,8 +1,14 @@ -import type { Positionable } from '@/lib/litegraph/src/interfaces' -import { LGraphGroup } from '@/lib/litegraph/src/litegraph' -import { LGraphCanvas } from '@/lib/litegraph/src/litegraph' -import type { LGraphNode } from '@/lib/litegraph/src/litegraph' +import type { + IContextMenuValue, + Positionable +} from '@/lib/litegraph/src/interfaces' +import { + LGraphCanvas, + LGraphGroup, + type LGraphNode +} from '@/lib/litegraph/src/litegraph' import { useSettingStore } from '@/platform/settings/settingStore' +import type { ComfyExtension } from '@/types/comfy' import { app } from '../../scripts/app' @@ -16,220 +22,218 @@ function addNodesToGroup(group: LGraphGroup, items: Iterable) { group.resizeTo([...group.children, ...items], padding) } -app.registerExtension({ +const ext: ComfyExtension = { name: 'Comfy.GroupOptions', - setup() { - const orig = LGraphCanvas.prototype.getCanvasMenuOptions - // graph_mouse - LGraphCanvas.prototype.getCanvasMenuOptions = function ( - this: LGraphCanvas - ) { - // @ts-expect-error fixme ts strict error - const options = orig.apply(this, arguments) - // @ts-expect-error fixme ts strict error - const group = this.graph.getGroupOnPos( - this.graph_mouse[0], - this.graph_mouse[1] - ) - if (!group) { - if (this.selectedItems.size > 0) { - options.push({ - content: 'Add Group For Selected Nodes', - callback: () => { - const group = new LGraphGroup() - addNodesToGroup(group, this.selectedItems) - // @ts-expect-error fixme ts strict error - this.graph.add(group) - // @ts-expect-error fixme ts strict error - this.graph.change() - group.recomputeInsideNodes() + getCanvasMenuItems(canvas: LGraphCanvas): IContextMenuValue[] { + const items: IContextMenuValue[] = [] + + // @ts-expect-error fixme ts strict error + const group = canvas.graph.getGroupOnPos( + canvas.graph_mouse[0], + canvas.graph_mouse[1] + ) + + if (!group) { + if (canvas.selectedItems.size > 0) { + items.push({ + content: 'Add Group For Selected Nodes', + callback: () => { + const group = new LGraphGroup() + addNodesToGroup(group, canvas.selectedItems) + // @ts-expect-error fixme ts strict error + canvas.graph.add(group) + // @ts-expect-error fixme ts strict error + canvas.graph.change() + + group.recomputeInsideNodes() + } + }) + } + + return items + } + + // Group nodes aren't recomputed until the group is moved, this ensures the nodes are up-to-date + group.recomputeInsideNodes() + const nodesInGroup = group.nodes + + items.push({ + content: 'Add Selected Nodes To Group', + disabled: !canvas.selectedItems?.size, + callback: () => { + addNodesToGroup(group, canvas.selectedItems) + // @ts-expect-error fixme ts strict error + canvas.graph.change() + } + }) + + // No nodes in group, return default options + if (nodesInGroup.length === 0) { + return items + } else { + // Add a separator between the default options and the group options + // @ts-expect-error fixme ts strict error + items.push(null) + } + + // Check if all nodes are the same mode + let allNodesAreSameMode = true + for (let i = 1; i < nodesInGroup.length; i++) { + if (nodesInGroup[i].mode !== nodesInGroup[0].mode) { + allNodesAreSameMode = false + break + } + } + + items.push({ + content: 'Fit Group To Nodes', + callback: () => { + group.recomputeInsideNodes() + const padding = useSettingStore().get( + 'Comfy.GroupSelectedNodes.Padding' + ) + group.resizeTo(group.children, padding) + // @ts-expect-error fixme ts strict error + canvas.graph.change() + } + }) + + items.push({ + content: 'Select Nodes', + callback: () => { + canvas.selectNodes(nodesInGroup) + // @ts-expect-error fixme ts strict error + canvas.graph.change() + canvas.canvas.focus() + } + }) + + // Modes + // 0: Always + // 1: On Event + // 2: Never + // 3: On Trigger + // 4: Bypass + // If all nodes are the same mode, add a menu option to change the mode + if (allNodesAreSameMode) { + const mode = nodesInGroup[0].mode + switch (mode) { + case 0: + // All nodes are always, option to disable, and bypass + items.push({ + content: 'Set Group Nodes to Never', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 2) + } + } + }) + items.push({ + content: 'Bypass Group Nodes', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 4) + } + } + }) + break + case 2: + // All nodes are never, option to enable, and bypass + items.push({ + content: 'Set Group Nodes to Always', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 0) + } + } + }) + items.push({ + content: 'Bypass Group Nodes', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 4) + } + } + }) + break + case 4: + // All nodes are bypass, option to enable, and disable + items.push({ + content: 'Set Group Nodes to Always', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 0) + } + } + }) + items.push({ + content: 'Set Group Nodes to Never', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 2) + } + } + }) + break + default: + // All nodes are On Trigger or On Event(Or other?), option to disable, set to always, or bypass + items.push({ + content: 'Set Group Nodes to Always', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 0) + } + } + }) + items.push({ + content: 'Set Group Nodes to Never', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 2) + } + } + }) + items.push({ + content: 'Bypass Group Nodes', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 4) + } } }) - } - - return options - } - - // Group nodes aren't recomputed until the group is moved, this ensures the nodes are up-to-date - group.recomputeInsideNodes() - const nodesInGroup = group.nodes - - options.push({ - content: 'Add Selected Nodes To Group', - disabled: !this.selectedItems?.size, - callback: () => { - addNodesToGroup(group, this.selectedItems) - // @ts-expect-error fixme ts strict error - this.graph.change() - } - }) - - // No nodes in group, return default options - if (nodesInGroup.length === 0) { - return options - } else { - // Add a separator between the default options and the group options - // @ts-expect-error fixme ts strict error - options.push(null) - } - - // Check if all nodes are the same mode - let allNodesAreSameMode = true - for (let i = 1; i < nodesInGroup.length; i++) { - if (nodesInGroup[i].mode !== nodesInGroup[0].mode) { - allNodesAreSameMode = false break - } } - - options.push({ - content: 'Fit Group To Nodes', + } else { + // Nodes are not all the same mode, add a menu option to change the mode to always, never, or bypass + items.push({ + content: 'Set Group Nodes to Always', callback: () => { - group.recomputeInsideNodes() - const padding = useSettingStore().get( - 'Comfy.GroupSelectedNodes.Padding' - ) - group.resizeTo(group.children, padding) - // @ts-expect-error fixme ts strict error - this.graph.change() + for (const node of nodesInGroup) { + setNodeMode(node, 0) + } } }) - - options.push({ - content: 'Select Nodes', + items.push({ + content: 'Set Group Nodes to Never', callback: () => { - this.selectNodes(nodesInGroup) - // @ts-expect-error fixme ts strict error - this.graph.change() - this.canvas.focus() + for (const node of nodesInGroup) { + setNodeMode(node, 2) + } } }) - - // Modes - // 0: Always - // 1: On Event - // 2: Never - // 3: On Trigger - // 4: Bypass - // If all nodes are the same mode, add a menu option to change the mode - if (allNodesAreSameMode) { - const mode = nodesInGroup[0].mode - switch (mode) { - case 0: - // All nodes are always, option to disable, and bypass - options.push({ - content: 'Set Group Nodes to Never', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 2) - } - } - }) - options.push({ - content: 'Bypass Group Nodes', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 4) - } - } - }) - break - case 2: - // All nodes are never, option to enable, and bypass - options.push({ - content: 'Set Group Nodes to Always', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 0) - } - } - }) - options.push({ - content: 'Bypass Group Nodes', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 4) - } - } - }) - break - case 4: - // All nodes are bypass, option to enable, and disable - options.push({ - content: 'Set Group Nodes to Always', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 0) - } - } - }) - options.push({ - content: 'Set Group Nodes to Never', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 2) - } - } - }) - break - default: - // All nodes are On Trigger or On Event(Or other?), option to disable, set to always, or bypass - options.push({ - content: 'Set Group Nodes to Always', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 0) - } - } - }) - options.push({ - content: 'Set Group Nodes to Never', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 2) - } - } - }) - options.push({ - content: 'Bypass Group Nodes', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 4) - } - } - }) - break + items.push({ + content: 'Bypass Group Nodes', + callback: () => { + for (const node of nodesInGroup) { + setNodeMode(node, 4) + } } - } else { - // Nodes are not all the same mode, add a menu option to change the mode to always, never, or bypass - options.push({ - content: 'Set Group Nodes to Always', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 0) - } - } - }) - options.push({ - content: 'Set Group Nodes to Never', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 2) - } - } - }) - options.push({ - content: 'Bypass Group Nodes', - callback: () => { - for (const node of nodesInGroup) { - setNodeMode(node, 4) - } - } - }) - } - - return options + }) } + + return items } -}) +} + +app.registerExtension(ext) diff --git a/src/extensions/core/nodeTemplates.ts b/src/extensions/core/nodeTemplates.ts index 528f73a5f..c16ebed72 100644 --- a/src/extensions/core/nodeTemplates.ts +++ b/src/extensions/core/nodeTemplates.ts @@ -1,8 +1,10 @@ import { downloadBlob } from '@/base/common/downloadUtil' import { t } from '@/i18n' -import { LGraphCanvas } from '@/lib/litegraph/src/litegraph' +import type { IContextMenuValue } from '@/lib/litegraph/src/interfaces' +import type { LGraphCanvas } from '@/lib/litegraph/src/litegraph' import { useToastStore } from '@/platform/updates/common/toastStore' import { useDialogService } from '@/services/dialogService' +import type { ComfyExtension } from '@/types/comfy' import { deserialiseAndCreate } from '@/utils/vintageClipboard' import { api } from '../../scripts/api' @@ -328,110 +330,107 @@ class ManageTemplates extends ComfyDialog { } } -app.registerExtension({ +const manage = new ManageTemplates() + +// @ts-expect-error fixme ts strict error +const clipboardAction = async (cb) => { + // We use the clipboard functions but dont want to overwrite the current user clipboard + // Restore it after we've run our callback + const old = localStorage.getItem('litegrapheditor_clipboard') + await cb() + // @ts-expect-error fixme ts strict error + localStorage.setItem('litegrapheditor_clipboard', old) +} + +const ext: ComfyExtension = { name: id, - setup() { - const manage = new ManageTemplates() + + getCanvasMenuItems(_canvas: LGraphCanvas): IContextMenuValue[] { + const items: IContextMenuValue[] = [] // @ts-expect-error fixme ts strict error - const clipboardAction = async (cb) => { - // We use the clipboard functions but dont want to overwrite the current user clipboard - // Restore it after we've run our callback - const old = localStorage.getItem('litegrapheditor_clipboard') - await cb() - // @ts-expect-error fixme ts strict error - localStorage.setItem('litegrapheditor_clipboard', old) - } + items.push(null) + items.push({ + content: `Save Selected as Template`, + disabled: !Object.keys(app.canvas.selected_nodes || {}).length, + callback: async () => { + const name = await useDialogService().prompt({ + title: t('nodeTemplates.saveAsTemplate'), + message: t('nodeTemplates.enterName'), + defaultValue: '' + }) + if (!name?.trim()) return - const orig = LGraphCanvas.prototype.getCanvasMenuOptions - LGraphCanvas.prototype.getCanvasMenuOptions = function () { - // @ts-expect-error fixme ts strict error - const options = orig.apply(this, arguments) + clipboardAction(() => { + app.canvas.copyToClipboard() + let data = localStorage.getItem('litegrapheditor_clipboard') + data = JSON.parse(data || '{}') + const nodeIds = Object.keys(app.canvas.selected_nodes) + for (let i = 0; i < nodeIds.length; i++) { + const node = app.graph.getNodeById(nodeIds[i]) + const nodeData = node?.constructor.nodeData - // @ts-expect-error fixme ts strict error - options.push(null) - options.push({ - content: `Save Selected as Template`, - disabled: !Object.keys(app.canvas.selected_nodes || {}).length, - // @ts-expect-error fixme ts strict error - callback: async () => { - const name = await useDialogService().prompt({ - title: t('nodeTemplates.saveAsTemplate'), - message: t('nodeTemplates.enterName'), - defaultValue: '' - }) - if (!name?.trim()) return - - clipboardAction(() => { - app.canvas.copyToClipboard() - let data = localStorage.getItem('litegrapheditor_clipboard') - // @ts-expect-error fixme ts strict error - data = JSON.parse(data) - const nodeIds = Object.keys(app.canvas.selected_nodes) - for (let i = 0; i < nodeIds.length; i++) { - const node = app.graph.getNodeById(nodeIds[i]) - const nodeData = node?.constructor.nodeData - - let groupData = GroupNodeHandler.getGroupData(node) - if (groupData) { - groupData = groupData.nodeData + let groupData = GroupNodeHandler.getGroupData(node) + if (groupData) { + groupData = groupData.nodeData + // @ts-expect-error + if (!data.groupNodes) { // @ts-expect-error - if (!data.groupNodes) { - // @ts-expect-error - data.groupNodes = {} - } - if (nodeData == null) throw new TypeError('nodeData is not set') - // @ts-expect-error - data.groupNodes[nodeData.name] = groupData - // @ts-expect-error - data.nodes[i].type = nodeData.name + data.groupNodes = {} } + if (nodeData == null) throw new TypeError('nodeData is not set') + // @ts-expect-error + data.groupNodes[nodeData.name] = groupData + // @ts-expect-error + data.nodes[i].type = nodeData.name } + } - manage.templates.push({ - name, - data: JSON.stringify(data) - }) - manage.store() + manage.templates.push({ + name, + data: JSON.stringify(data) + }) + manage.store() + }) + } + }) + + // Map each template to a menu item + const subItems = manage.templates.map((t) => { + return { + content: t.name, + callback: () => { + clipboardAction(async () => { + const data = JSON.parse(t.data) + await GroupNodeConfig.registerFromWorkflow(data.groupNodes, {}) + + // Check for old clipboard format + if (!data.reroutes) { + deserialiseAndCreate(t.data, app.canvas) + } else { + localStorage.setItem('litegrapheditor_clipboard', t.data) + app.canvas.pasteFromClipboard() + } }) } - }) + } + }) - // Map each template to a menu item - const subItems = manage.templates.map((t) => { - return { - content: t.name, - callback: () => { - clipboardAction(async () => { - const data = JSON.parse(t.data) - await GroupNodeConfig.registerFromWorkflow(data.groupNodes, {}) + // @ts-expect-error fixme ts strict error + subItems.push(null, { + content: 'Manage', + callback: () => manage.show() + }) - // Check for old clipboard format - if (!data.reroutes) { - deserialiseAndCreate(t.data, app.canvas) - } else { - localStorage.setItem('litegrapheditor_clipboard', t.data) - app.canvas.pasteFromClipboard() - } - }) - } - } - }) + items.push({ + content: 'Node Templates', + submenu: { + options: subItems + } + }) - // @ts-expect-error fixme ts strict error - subItems.push(null, { - content: 'Manage', - callback: () => manage.show() - }) - - options.push({ - content: 'Node Templates', - submenu: { - options: subItems - } - }) - - return options - } + return items } -}) +} + +app.registerExtension(ext) diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 4bac98402..bae17e74b 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -1262,7 +1262,7 @@ export class LGraphCanvas if (!node) return // TODO: This is a static method, so the below "that" appears broken. - if (v.callback) v.callback.call(this, node, v, e, prev) + if (v.callback) void v.callback.call(this, node, v, e, prev) if (!v.value) return @@ -8042,7 +8042,7 @@ export class LGraphCanvas } } - getCanvasMenuOptions(): IContextMenuValue[] { + getCanvasMenuOptions(): IContextMenuValue[] { let options: IContextMenuValue[] if (this.getMenuOptions) { options = this.getMenuOptions() diff --git a/src/lib/litegraph/src/contextMenuCompat.ts b/src/lib/litegraph/src/contextMenuCompat.ts new file mode 100644 index 000000000..5d2cd09ad --- /dev/null +++ b/src/lib/litegraph/src/contextMenuCompat.ts @@ -0,0 +1,148 @@ +import type { LGraphCanvas } from './LGraphCanvas' +import type { IContextMenuValue } from './interfaces' + +/** + * Simple compatibility layer for legacy getCanvasMenuOptions and getNodeMenuOptions monkey patches. + * To disable legacy support, set ENABLE_LEGACY_SUPPORT = false + */ +const ENABLE_LEGACY_SUPPORT = true + +type ContextMenuValueProvider = (...args: unknown[]) => IContextMenuValue[] + +class LegacyMenuCompat { + private originalMethods = new Map() + private hasWarned = new Set() + private currentExtension: string | null = null + private isExtracting = false + private readonly wrapperMethods = new Map() + private readonly preWrapperMethods = new Map< + string, + ContextMenuValueProvider + >() + private readonly wrapperInstalled = new Map() + + /** + * Set the name of the extension that is currently being set up. + * This allows us to track which extension is monkey-patching. + * @param extensionName The name of the extension + */ + setCurrentExtension(extensionName: string | null) { + this.currentExtension = extensionName + } + + /** + * Register a wrapper method that should NOT be treated as a legacy monkey-patch. + * @param methodName The method name + * @param wrapperFn The wrapper function + * @param preWrapperFn The method that existed before the wrapper + * @param prototype The prototype to verify wrapper installation + */ + registerWrapper( + methodName: keyof LGraphCanvas, + wrapperFn: ContextMenuValueProvider, + preWrapperFn: ContextMenuValueProvider, + prototype?: LGraphCanvas + ) { + this.wrapperMethods.set(methodName, wrapperFn) + this.preWrapperMethods.set(methodName, preWrapperFn) + const isInstalled = prototype && prototype[methodName] === wrapperFn + this.wrapperInstalled.set(methodName, !!isInstalled) + } + + /** + * Install compatibility layer to detect monkey-patching + * @param prototype The prototype to install on + * @param methodName The method name to track + */ + install(prototype: LGraphCanvas, methodName: keyof LGraphCanvas) { + if (!ENABLE_LEGACY_SUPPORT) return + + const originalMethod = prototype[methodName] + this.originalMethods.set(methodName, originalMethod) + + let currentImpl = originalMethod + + Object.defineProperty(prototype, methodName, { + get() { + return currentImpl + }, + set: (newImpl: ContextMenuValueProvider) => { + const fnKey = `${methodName}:${newImpl.toString().slice(0, 100)}` + if (!this.hasWarned.has(fnKey) && this.currentExtension) { + this.hasWarned.add(fnKey) + + console.warn( + `%c[DEPRECATED]%c Monkey-patching ${methodName} is deprecated. (Extension: "${this.currentExtension}")\n` + + `Please use the new context menu API instead.\n\n` + + `See: https://docs.comfy.org/custom-nodes/js/context-menu-migration`, + 'color: orange; font-weight: bold', + 'color: inherit' + ) + } + currentImpl = newImpl + } + }) + } + + /** + * Extract items that were added by legacy monkey patches + * @param methodName The method name that was monkey-patched + * @param context The context to call methods with + * @param args Arguments to pass to the methods + * @returns Array of menu items added by monkey patches + */ + extractLegacyItems( + methodName: keyof LGraphCanvas, + context: LGraphCanvas, + ...args: unknown[] + ): IContextMenuValue[] { + if (!ENABLE_LEGACY_SUPPORT) return [] + if (this.isExtracting) return [] + + const originalMethod = this.originalMethods.get(methodName) + if (!originalMethod) return [] + + try { + this.isExtracting = true + + const originalItems = originalMethod.apply(context, args) as + | IContextMenuValue[] + | undefined + if (!originalItems) return [] + + const currentMethod = context.constructor.prototype[methodName] + if (!currentMethod || currentMethod === originalMethod) return [] + + const registeredWrapper = this.wrapperMethods.get(methodName) + if (registeredWrapper && currentMethod === registeredWrapper) return [] + + const preWrapperMethod = this.preWrapperMethods.get(methodName) + const wrapperWasInstalled = this.wrapperInstalled.get(methodName) + + const shouldSkipWrapper = + preWrapperMethod && + wrapperWasInstalled && + currentMethod !== preWrapperMethod + + const methodToCall = shouldSkipWrapper ? preWrapperMethod : currentMethod + + const patchedItems = methodToCall.apply(context, args) as + | IContextMenuValue[] + | undefined + if (!patchedItems) return [] + + if (patchedItems.length > originalItems.length) { + return patchedItems.slice(originalItems.length) as IContextMenuValue[] + } + + return [] + } catch (e) { + console.error('[Context Menu Compat] Failed to extract legacy items:', e) + return [] + } finally { + this.isExtracting = false + } + } +} + +export const legacyMenuCompat = new LegacyMenuCompat() diff --git a/src/lib/litegraph/src/interfaces.ts b/src/lib/litegraph/src/interfaces.ts index f4b4888b9..3ab56a112 100644 --- a/src/lib/litegraph/src/interfaces.ts +++ b/src/lib/litegraph/src/interfaces.ts @@ -393,7 +393,7 @@ export interface IContextMenuOptions event?: MouseEvent, previous_menu?: ContextMenu, extra?: unknown - ): void | boolean + ): void | boolean | Promise } export interface IContextMenuValue< @@ -416,7 +416,7 @@ export interface IContextMenuValue< event?: MouseEvent, previous_menu?: ContextMenu, extra?: TExtra - ): void | boolean + ): void | boolean | Promise } interface IContextMenuSubmenu diff --git a/src/services/extensionService.ts b/src/services/extensionService.ts index 1e51991d6..4f3f523d3 100644 --- a/src/services/extensionService.ts +++ b/src/services/extensionService.ts @@ -1,5 +1,6 @@ import { useCurrentUser } from '@/composables/auth/useCurrentUser' import { useErrorHandling } from '@/composables/useErrorHandling' +import { legacyMenuCompat } from '@/lib/litegraph/src/contextMenuCompat' import { useSettingStore } from '@/platform/settings/settingStore' import { api } from '@/scripts/api' import { app } from '@/scripts/app' @@ -136,8 +137,25 @@ export const useExtensionService = () => { extensionStore.enabledExtensions.map(async (ext) => { if (method in ext) { try { - return await ext[method](...args, app) + // Set current extension name for legacy compatibility tracking + if (method === 'setup') { + legacyMenuCompat.setCurrentExtension(ext.name) + } + + const result = await ext[method](...args, app) + + // Clear current extension after setup + if (method === 'setup') { + legacyMenuCompat.setCurrentExtension(null) + } + + return result } catch (error) { + // Clear current extension on error too + if (method === 'setup') { + legacyMenuCompat.setCurrentExtension(null) + } + console.error( `Error calling extension '${ext.name}' method '${method}'`, { error }, diff --git a/src/services/litegraphService.ts b/src/services/litegraphService.ts index 9bc35e0b9..3fe45fcea 100644 --- a/src/services/litegraphService.ts +++ b/src/services/litegraphService.ts @@ -658,7 +658,6 @@ export const useLitegraphService = () => { return [ { content: 'Copy Image', - // @ts-expect-error: async callback is not accepted by litegraph callback: async () => { const url = new URL(img.src) url.searchParams.delete('preview') diff --git a/tests-ui/tests/extensions/contextMenuExtension.test.ts b/tests-ui/tests/extensions/contextMenuExtension.test.ts index e6766b0da..5cd9d3664 100644 --- a/tests-ui/tests/extensions/contextMenuExtension.test.ts +++ b/tests-ui/tests/extensions/contextMenuExtension.test.ts @@ -77,9 +77,9 @@ describe('Context Menu Extension API', () => { extensionStore.registerExtension(ext1) extensionStore.registerExtension(ext2) - const items = extensionService + const items: IContextMenuValue[] = extensionService .invokeExtensions('getCanvasMenuItems', mockCanvas) - .flat() as IContextMenuValue[] + .flat() expect(items).toHaveLength(3) expect(items[0]).toMatchObject({ content: 'Canvas Item 1' }) @@ -105,9 +105,9 @@ describe('Context Menu Extension API', () => { extensionStore.registerExtension(extension) - const items = extensionService + const items: IContextMenuValue[] = extensionService .invokeExtensions('getCanvasMenuItems', mockCanvas) - .flat() as IContextMenuValue[] + .flat() expect(items).toHaveLength(3) expect(items[0].content).toBe('Menu with Submenu') @@ -127,13 +127,44 @@ describe('Context Menu Extension API', () => { extensionStore.registerExtension(canvasExtension) extensionStore.registerExtension(extensionWithoutCanvasMenu) - const items = extensionService + const items: IContextMenuValue[] = extensionService .invokeExtensions('getCanvasMenuItems', mockCanvas) - .flat() as IContextMenuValue[] + .flat() expect(items).toHaveLength(1) expect(items[0].content).toBe('Canvas Item 1') }) + + it('should not duplicate menu items when collected multiple times', () => { + const extension = createCanvasMenuExtension('Test Extension', [ + canvasMenuItem1, + canvasMenuItem2 + ]) + + extensionStore.registerExtension(extension) + + // Collect items multiple times (simulating repeated menu opens) + const items1: IContextMenuValue[] = extensionService + .invokeExtensions('getCanvasMenuItems', mockCanvas) + .flat() + + const items2: IContextMenuValue[] = extensionService + .invokeExtensions('getCanvasMenuItems', mockCanvas) + .flat() + + // Both collections should have the same items (no duplication) + expect(items1).toHaveLength(2) + expect(items2).toHaveLength(2) + + // Verify items are unique by checking their content + const contents1 = items1.map((item) => item.content) + const uniqueContents1 = new Set(contents1) + expect(uniqueContents1.size).toBe(contents1.length) + + const contents2 = items2.map((item) => item.content) + const uniqueContents2 = new Set(contents2) + expect(uniqueContents2.size).toBe(contents2.length) + }) }) describe('collectNodeMenuItems', () => { @@ -147,9 +178,9 @@ describe('Context Menu Extension API', () => { extensionStore.registerExtension(ext1) extensionStore.registerExtension(ext2) - const items = extensionService + const items: IContextMenuValue[] = extensionService .invokeExtensions('getNodeMenuItems', mockNode) - .flat() as IContextMenuValue[] + .flat() expect(items).toHaveLength(3) expect(items[0]).toMatchObject({ content: 'Node Item 1' }) @@ -172,9 +203,9 @@ describe('Context Menu Extension API', () => { extensionStore.registerExtension(extension) - const items = extensionService + const items: IContextMenuValue[] = extensionService .invokeExtensions('getNodeMenuItems', mockNode) - .flat() as IContextMenuValue[] + .flat() expect(items[0].content).toBe('Node Menu with Submenu') expect(items[0].submenu?.options).toHaveLength(2) @@ -189,9 +220,9 @@ describe('Context Menu Extension API', () => { extensionStore.registerExtension(nodeExtension) extensionStore.registerExtension(extensionWithoutNodeMenu) - const items = extensionService + const items: IContextMenuValue[] = extensionService .invokeExtensions('getNodeMenuItems', mockNode) - .flat() as IContextMenuValue[] + .flat() expect(items).toHaveLength(1) expect(items[0].content).toBe('Node Item 1') diff --git a/tests-ui/tests/extensions/contextMenuExtensionName.test.ts b/tests-ui/tests/extensions/contextMenuExtensionName.test.ts new file mode 100644 index 000000000..1fb0b5fd5 --- /dev/null +++ b/tests-ui/tests/extensions/contextMenuExtensionName.test.ts @@ -0,0 +1,71 @@ +import { describe, expect, it, vi } from 'vitest' + +import { legacyMenuCompat } from '@/lib/litegraph/src/contextMenuCompat' +import { LGraphCanvas } from '@/lib/litegraph/src/litegraph' + +/** + * Test that demonstrates the extension name appearing in deprecation warnings + */ +describe('Context Menu Extension Name in Warnings', () => { + it('should include extension name in deprecation warning', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) + + // Install compatibility layer + legacyMenuCompat.install(LGraphCanvas.prototype, 'getCanvasMenuOptions') + + // Simulate what happens during extension setup + legacyMenuCompat.setCurrentExtension('MyCustomExtension') + + // Extension monkey-patches the method + const original = LGraphCanvas.prototype.getCanvasMenuOptions + LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) { + const items = (original as any).apply(this, args) + items.push({ content: 'My Custom Menu Item', callback: () => {} }) + return items + } + + // Clear extension (happens after setup completes) + legacyMenuCompat.setCurrentExtension(null) + + // Verify the warning includes the extension name + expect(warnSpy).toHaveBeenCalled() + const warningMessage = warnSpy.mock.calls[0][0] + + expect(warningMessage).toContain('[DEPRECATED]') + expect(warningMessage).toContain('getCanvasMenuOptions') + expect(warningMessage).toContain('"MyCustomExtension"') + + vi.restoreAllMocks() + }) + + it('should include extension name for node menu patches', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}) + + // Install compatibility layer + legacyMenuCompat.install(LGraphCanvas.prototype, 'getNodeMenuOptions') + + // Simulate what happens during extension setup + legacyMenuCompat.setCurrentExtension('AnotherExtension') + + // Extension monkey-patches the method + const original = LGraphCanvas.prototype.getNodeMenuOptions + LGraphCanvas.prototype.getNodeMenuOptions = function (...args: any[]) { + const items = (original as any).apply(this, args) + items.push({ content: 'My Node Menu Item', callback: () => {} }) + return items + } + + // Clear extension (happens after setup completes) + legacyMenuCompat.setCurrentExtension(null) + + // Verify the warning includes extension info + expect(warnSpy).toHaveBeenCalled() + const warningMessage = warnSpy.mock.calls[0][0] + + expect(warningMessage).toContain('[DEPRECATED]') + expect(warningMessage).toContain('getNodeMenuOptions') + expect(warningMessage).toContain('"AnotherExtension"') + + vi.restoreAllMocks() + }) +}) diff --git a/tests-ui/tests/litegraph/core/contextMenuCompat.test.ts b/tests-ui/tests/litegraph/core/contextMenuCompat.test.ts new file mode 100644 index 000000000..623082c68 --- /dev/null +++ b/tests-ui/tests/litegraph/core/contextMenuCompat.test.ts @@ -0,0 +1,346 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +import { legacyMenuCompat } from '@/lib/litegraph/src/contextMenuCompat' +import { LGraphCanvas } from '@/lib/litegraph/src/litegraph' + +describe('contextMenuCompat', () => { + let originalGetCanvasMenuOptions: typeof LGraphCanvas.prototype.getCanvasMenuOptions + let mockCanvas: LGraphCanvas + + beforeEach(() => { + // Save original method + originalGetCanvasMenuOptions = LGraphCanvas.prototype.getCanvasMenuOptions + + // Create mock canvas + mockCanvas = { + constructor: { + prototype: LGraphCanvas.prototype + } + } as unknown as LGraphCanvas + + // Clear console warnings + vi.spyOn(console, 'warn').mockImplementation(() => {}) + }) + + afterEach(() => { + // Restore original method + LGraphCanvas.prototype.getCanvasMenuOptions = originalGetCanvasMenuOptions + vi.restoreAllMocks() + }) + + describe('install', () => { + it('should install compatibility layer on prototype', () => { + const methodName = 'getCanvasMenuOptions' + + // Install compatibility layer + legacyMenuCompat.install(LGraphCanvas.prototype, methodName) + + // The method should still be callable + expect(typeof LGraphCanvas.prototype.getCanvasMenuOptions).toBe( + 'function' + ) + }) + + it('should detect monkey patches and warn', () => { + const methodName = 'getCanvasMenuOptions' + const warnSpy = vi.spyOn(console, 'warn') + + // Install compatibility layer + legacyMenuCompat.install(LGraphCanvas.prototype, methodName) + + // Set current extension before monkey-patching + legacyMenuCompat.setCurrentExtension('Test Extension') + + // Simulate extension monkey-patching + const original = LGraphCanvas.prototype.getCanvasMenuOptions + LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) { + const items = (original as any).apply(this, args) + items.push({ content: 'Custom Item', callback: () => {} }) + return items + } + + // Should have logged a warning with extension name + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining('[DEPRECATED]'), + expect.any(String), + expect.any(String) + ) + expect(warnSpy).toHaveBeenCalledWith( + expect.stringContaining('"Test Extension"'), + expect.any(String), + expect.any(String) + ) + + // Clear extension + legacyMenuCompat.setCurrentExtension(null) + }) + + it('should only warn once per unique function', () => { + const methodName = 'getCanvasMenuOptions' + const warnSpy = vi.spyOn(console, 'warn') + + legacyMenuCompat.install(LGraphCanvas.prototype, methodName) + legacyMenuCompat.setCurrentExtension('test.extension') + + const patchFunction = function (this: LGraphCanvas, ...args: any[]) { + const items = (originalGetCanvasMenuOptions as any).apply(this, args) + items.push({ content: 'Custom', callback: () => {} }) + return items + } + + // Patch twice with same function + LGraphCanvas.prototype.getCanvasMenuOptions = patchFunction + LGraphCanvas.prototype.getCanvasMenuOptions = patchFunction + + // Should only warn once + expect(warnSpy).toHaveBeenCalledTimes(1) + }) + }) + + describe('extractLegacyItems', () => { + beforeEach(() => { + // Setup a mock original method + LGraphCanvas.prototype.getCanvasMenuOptions = function () { + return [ + { content: 'Item 1', callback: () => {} }, + { content: 'Item 2', callback: () => {} } + ] + } + + // Install compatibility layer + legacyMenuCompat.install(LGraphCanvas.prototype, 'getCanvasMenuOptions') + }) + + it('should extract items added by monkey patches', () => { + // Monkey-patch to add items + const original = LGraphCanvas.prototype.getCanvasMenuOptions + LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) { + const items = (original as any).apply(this, args) + items.push({ content: 'Custom Item 1', callback: () => {} }) + items.push({ content: 'Custom Item 2', callback: () => {} }) + return items + } + + // Extract legacy items + const legacyItems = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + + expect(legacyItems).toHaveLength(2) + expect(legacyItems[0]).toMatchObject({ content: 'Custom Item 1' }) + expect(legacyItems[1]).toMatchObject({ content: 'Custom Item 2' }) + }) + + it('should return empty array when no items added', () => { + // No monkey-patching, so no extra items + const legacyItems = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + + expect(legacyItems).toHaveLength(0) + }) + + it('should return empty array when patched method returns same count', () => { + // Monkey-patch that replaces items but keeps same count + LGraphCanvas.prototype.getCanvasMenuOptions = function () { + return [ + { content: 'Replaced 1', callback: () => {} }, + { content: 'Replaced 2', callback: () => {} } + ] + } + + const legacyItems = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + + expect(legacyItems).toHaveLength(0) + }) + + it('should handle errors gracefully', () => { + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + + // Monkey-patch that throws error + LGraphCanvas.prototype.getCanvasMenuOptions = function () { + throw new Error('Test error') + } + + const legacyItems = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + + expect(legacyItems).toHaveLength(0) + expect(errorSpy).toHaveBeenCalledWith( + expect.stringContaining('Failed to extract legacy items'), + expect.any(Error) + ) + }) + }) + + describe('integration', () => { + it('should work with multiple extensions patching', () => { + // Setup base method + LGraphCanvas.prototype.getCanvasMenuOptions = function () { + return [{ content: 'Base Item', callback: () => {} }] + } + + legacyMenuCompat.install(LGraphCanvas.prototype, 'getCanvasMenuOptions') + + // First extension patches + const original1 = LGraphCanvas.prototype.getCanvasMenuOptions + LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) { + const items = (original1 as any).apply(this, args) + items.push({ content: 'Extension 1 Item', callback: () => {} }) + return items + } + + // Second extension patches + const original2 = LGraphCanvas.prototype.getCanvasMenuOptions + LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) { + const items = (original2 as any).apply(this, args) + items.push({ content: 'Extension 2 Item', callback: () => {} }) + return items + } + + // Extract legacy items + const legacyItems = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + + // Should extract both items added by extensions + expect(legacyItems).toHaveLength(2) + expect(legacyItems[0]).toMatchObject({ content: 'Extension 1 Item' }) + expect(legacyItems[1]).toMatchObject({ content: 'Extension 2 Item' }) + }) + + it('should extract legacy items only once even when called multiple times', () => { + // Setup base method + LGraphCanvas.prototype.getCanvasMenuOptions = function () { + return [ + { content: 'Base Item 1', callback: () => {} }, + { content: 'Base Item 2', callback: () => {} } + ] + } + + legacyMenuCompat.install(LGraphCanvas.prototype, 'getCanvasMenuOptions') + + // Simulate legacy extension monkey-patching the prototype + const original = LGraphCanvas.prototype.getCanvasMenuOptions + LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) { + const items = (original as any).apply(this, args) + items.push({ content: 'Legacy Item 1', callback: () => {} }) + items.push({ content: 'Legacy Item 2', callback: () => {} }) + return items + } + + // Extract legacy items multiple times (simulating repeated menu opens) + const legacyItems1 = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + const legacyItems2 = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + const legacyItems3 = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + + // Each extraction should return the same items (no accumulation) + expect(legacyItems1).toHaveLength(2) + expect(legacyItems2).toHaveLength(2) + expect(legacyItems3).toHaveLength(2) + + // Verify items are the expected ones + expect(legacyItems1[0]).toMatchObject({ content: 'Legacy Item 1' }) + expect(legacyItems1[1]).toMatchObject({ content: 'Legacy Item 2' }) + + expect(legacyItems2[0]).toMatchObject({ content: 'Legacy Item 1' }) + expect(legacyItems2[1]).toMatchObject({ content: 'Legacy Item 2' }) + + expect(legacyItems3[0]).toMatchObject({ content: 'Legacy Item 1' }) + expect(legacyItems3[1]).toMatchObject({ content: 'Legacy Item 2' }) + }) + + it('should not extract items from registered wrapper methods', () => { + // Setup base method + LGraphCanvas.prototype.getCanvasMenuOptions = function () { + return [{ content: 'Base Item', callback: () => {} }] + } + + legacyMenuCompat.install(LGraphCanvas.prototype, 'getCanvasMenuOptions') + + // Create a wrapper that adds new API items (simulating useContextMenuTranslation) + const originalMethod = LGraphCanvas.prototype.getCanvasMenuOptions + const wrapperMethod = function (this: LGraphCanvas) { + const items = (originalMethod as any).apply(this, []) + // Add new API items + items.push({ content: 'New API Item 1', callback: () => {} }) + items.push({ content: 'New API Item 2', callback: () => {} }) + return items + } + + // Set the wrapper as the current method + LGraphCanvas.prototype.getCanvasMenuOptions = wrapperMethod + + // Register the wrapper so it's not treated as a legacy patch + legacyMenuCompat.registerWrapper( + 'getCanvasMenuOptions', + wrapperMethod, + originalMethod, + LGraphCanvas.prototype // Wrapper is installed + ) + + // Extract legacy items - should return empty because current method is a registered wrapper + const legacyItems = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + + expect(legacyItems).toHaveLength(0) + }) + + it('should extract legacy items even when a wrapper is registered but not active', () => { + // Setup base method + LGraphCanvas.prototype.getCanvasMenuOptions = function () { + return [{ content: 'Base Item', callback: () => {} }] + } + + legacyMenuCompat.install(LGraphCanvas.prototype, 'getCanvasMenuOptions') + + // Register a wrapper (but don't set it as the current method) + const originalMethod = LGraphCanvas.prototype.getCanvasMenuOptions + const wrapperMethod = function () { + return [{ content: 'Wrapper Item', callback: () => {} }] + } + legacyMenuCompat.registerWrapper( + 'getCanvasMenuOptions', + wrapperMethod, + originalMethod + // NOT passing prototype, so it won't be marked as installed + ) + + // Monkey-patch with a different function (legacy extension) + const original = LGraphCanvas.prototype.getCanvasMenuOptions + LGraphCanvas.prototype.getCanvasMenuOptions = function (...args: any[]) { + const items = (original as any).apply(this, args) + items.push({ content: 'Legacy Item', callback: () => {} }) + return items + } + + // Extract legacy items - should return the legacy item because current method is NOT the wrapper + const legacyItems = legacyMenuCompat.extractLegacyItems( + 'getCanvasMenuOptions', + mockCanvas + ) + + expect(legacyItems).toHaveLength(1) + expect(legacyItems[0]).toMatchObject({ content: 'Legacy Item' }) + }) + }) +}) From efed9344181bebe99e68b674b88df41036977962 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Tue, 28 Oct 2025 08:31:34 -0700 Subject: [PATCH 012/115] remove tailwindcss eslint plugin (#6342) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This plugin does not seem to work well with tw v4. Can revert this PR later. --- the graph is forcing tailwind-api-utils@1.0.3 which tries to import v3 files, or something like that. ``` > @comfyorg/comfyui-frontend@1.31.0 lint:fix /home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31 > eslint src --cache --fix Oops! Something went wrong! :( ESLint: 9.35.0 Error: Error while loading rule 'tailwindcss/enforces-negative-arbitrary-values': Cannot find module '/home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31/node_modules/.pnpm/tailwindcss@4.1.12/node_modules/tailwindcss/dist/lib/setupContextUtils.js' Require stack: - /home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31/node_modules/.pnpm/tailwind-api-utils@1.0.3_tailwindcss@4.1.12/node_modules/tailwind-api-utils/dist/index.cjs - /home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31/node_modules/.pnpm/eslint-plugin-tailwindcss@4.0.0-beta.0_tailwindcss@4.1.12/node_modules/eslint-plugin-tailwindcss/lib/util/customConfig.js - /home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31/node_modules/.pnpm/eslint-plugin-tailwindcss@4.0.0-beta.0_tailwindcss@4.1.12/node_modules/eslint-plugin-tailwindcss/lib/util/tailwindAPI.js - /home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31/node_modules/.pnpm/eslint-plugin-tailwindcss@4.0.0-beta.0_tailwindcss@4.1.12/node_modules/eslint-plugin-tailwindcss/lib/rules/classnames-order.js - /home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31/node_modules/.pnpm/eslint-plugin-tailwindcss@4.0.0-beta.0_tailwindcss@4.1.12/node_modules/eslint-plugin-tailwindcss/lib/index.js Occurred while linting /home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31/src/base/common/downloadUtil.ts at Module._resolveFilename (node:internal/modules/cjs/loader:1410:15) at defaultResolveImpl (node:internal/modules/cjs/loader:1051:19) at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1056:22) at Module._load (node:internal/modules/cjs/loader:1219:37) at TracingChannel.traceSync (node:diagnostics_channel:322:14) at wrapModuleLoad (node:internal/modules/cjs/loader:238:24) at Module.require (node:internal/modules/cjs/loader:1493:12) at require (node:internal/modules/helpers:152:16) at TailwindUtils.loadConfigV3 (/home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31/node_modules/.pnpm/tailwind-api-utils@1.0.3_tailwindcss@4.1.12/node_modules/tailwind-api-utils/dist/index.cjs:429:31) at getTailwindConfig (/home/c_byrne/projects/comfyui-frontend-testing/ComfyUI_frontend-clone-31/node_modules/.pnpm/eslint-plugin-tailwindcss@4.0.0-beta.0_tailwindcss@4.1.12/node_modules/eslint-plugin-tailwindcss/lib/util/tailwindAPI.js:14:11)  ELIFECYCLE  Command failed with exit code 2. ``` --- eslint.config.ts | 9 +------- package.json | 2 -- pnpm-lock.yaml | 50 ++++++--------------------------------------- pnpm-workspace.yaml | 4 +--- 4 files changed, 8 insertions(+), 57 deletions(-) diff --git a/eslint.config.ts b/eslint.config.ts index 2a4d219a9..6681d2126 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -5,7 +5,6 @@ import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescrip import { importX } from 'eslint-plugin-import-x' import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended' import storybook from 'eslint-plugin-storybook' -import tailwind from 'eslint-plugin-tailwindcss' import unusedImports from 'eslint-plugin-unused-imports' import pluginVue from 'eslint-plugin-vue' import { defineConfig } from 'eslint/config' @@ -34,11 +33,7 @@ const settings = { ], noWarnOnMultipleProjects: true }) - ], - tailwindcss: { - config: `${import.meta.dirname}/packages/design-system/src/css/style.css`, - functions: ['cn', 'clsx', 'tw'] - } + ] } as const const commonParserOptions = { @@ -97,7 +92,6 @@ export default defineConfig([ // Difference in typecheck on CI vs Local // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Bad types in the plugin - tailwind.configs['flat/recommended'], pluginVue.configs['flat/recommended'], eslintPluginPrettierRecommended, storybook.configs['flat/recommended'], @@ -129,7 +123,6 @@ export default defineConfig([ 'import-x/no-relative-packages': 'error', 'unused-imports/no-unused-imports': 'error', 'no-console': ['error', { allow: ['warn', 'error'] }], - 'tailwindcss/no-custom-classname': 'off', // TODO: fix 'vue/no-v-html': 'off', // Enforce dark-theme: instead of dark: prefix 'vue/no-restricted-class': ['error', '/^dark:/'], diff --git a/package.json b/package.json index 3513162b0..1ecd06209 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,6 @@ "@storybook/vue3-vite": "catalog:", "@tailwindcss/vite": "catalog:", "@trivago/prettier-plugin-sort-imports": "catalog:", - "@types/eslint-plugin-tailwindcss": "catalog:", "@types/fs-extra": "catalog:", "@types/jsdom": "catalog:", "@types/node": "catalog:", @@ -78,7 +77,6 @@ "eslint-plugin-import-x": "catalog:", "eslint-plugin-prettier": "catalog:", "eslint-plugin-storybook": "catalog:", - "eslint-plugin-tailwindcss": "catalog:", "eslint-plugin-unused-imports": "catalog:", "eslint-plugin-vue": "catalog:", "fs-extra": "^11.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eb38350f7..d42625007 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,9 +87,6 @@ catalogs: '@trivago/prettier-plugin-sort-imports': specifier: ^5.2.0 version: 5.2.2 - '@types/eslint-plugin-tailwindcss': - specifier: ^3.17.0 - version: 3.17.0 '@types/fs-extra': specifier: ^11.0.4 version: 11.0.4 @@ -153,9 +150,6 @@ catalogs: eslint-plugin-storybook: specifier: ^9.1.6 version: 9.1.6 - eslint-plugin-tailwindcss: - specifier: 4.0.0-beta.0 - version: 4.0.0-beta.0 eslint-plugin-unused-imports: specifier: ^4.2.0 version: 4.2.0 @@ -519,9 +513,6 @@ importers: '@trivago/prettier-plugin-sort-imports': specifier: 'catalog:' version: 5.2.2(@vue/compiler-sfc@3.5.13)(prettier@3.6.2) - '@types/eslint-plugin-tailwindcss': - specifier: 'catalog:' - version: 3.17.0 '@types/fs-extra': specifier: 'catalog:' version: 11.0.4 @@ -570,9 +561,6 @@ importers: eslint-plugin-storybook: specifier: 'catalog:' version: 9.1.6(eslint@9.35.0(jiti@2.4.2))(storybook@9.1.6(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)))(typescript@5.9.2) - eslint-plugin-tailwindcss: - specifier: 'catalog:' - version: 4.0.0-beta.0(tailwindcss@4.1.12) eslint-plugin-unused-imports: specifier: 'catalog:' version: 4.2.0(@typescript-eslint/eslint-plugin@8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.35.0(jiti@2.4.2)) @@ -3155,9 +3143,6 @@ packages: '@types/diff-match-patch@1.0.36': resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==} - '@types/eslint-plugin-tailwindcss@3.17.0': - resolution: {integrity: sha512-ucQGf2YIdTcndYcxRU3UdZgmhUHsOlbIF4BaRtl0op+7k2JmqM2i3aXZ6XIcfZgVq1ZKov7VM5c/BR81ukmkyg==} - '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -4700,12 +4685,6 @@ packages: eslint: '>=8' storybook: ^9.1.6 - eslint-plugin-tailwindcss@4.0.0-beta.0: - resolution: {integrity: sha512-WWCajZgQu38Sd67ZCl2W6i3MRzqB0d+H8s4qV9iB6lBJbsDOIpIlj6R1Fj2FXkoWErbo05pZnZYbCGIU9o/DsA==} - engines: {node: '>=18.12.0'} - peerDependencies: - tailwindcss: ^3.4.0 || ^4.0.0 - eslint-plugin-unused-imports@4.2.0: resolution: {integrity: sha512-hLbJ2/wnjKq4kGA9AUaExVFIbNzyxYdVo49QZmKCnhk5pc9wcYRbfgLHvWJ8tnsdcseGhoUAddm9gn/lt+d74w==} peerDependencies: @@ -7163,11 +7142,6 @@ packages: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} - tailwind-api-utils@1.0.3: - resolution: {integrity: sha512-KpzUHkH1ug1sq4394SLJX38ZtpeTiqQ1RVyFTTSY2XuHsNSTWUkRo108KmyyrMWdDbQrLYkSHaNKj/a3bmA4sQ==} - peerDependencies: - tailwindcss: ^3.3.0 || ^4.0.0 || ^4.0.0-beta - tailwind-merge@2.6.0: resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} @@ -7626,6 +7600,9 @@ packages: vue-component-type-helpers@3.1.1: resolution: {integrity: sha512-B0kHv7qX6E7+kdc5nsaqjdGZ1KwNKSUQDWGy7XkTYT7wFsOpkEyaJ1Vq79TjwrrtuLRgizrTV7PPuC4rRQo+vw==} + vue-component-type-helpers@3.1.2: + resolution: {integrity: sha512-ch3/SKBtxdZq18vsEntiGCdSszCRNfhX5QaTxjSacCAXLlNQRXfXo+ANjoQEYJMsJOJy1/vHF6Tkc4s85MS+zw==} + vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} engines: {node: '>=12'} @@ -10308,7 +10285,7 @@ snapshots: storybook: 9.1.6(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) type-fest: 2.19.0 vue: 3.5.13(typescript@5.9.2) - vue-component-type-helpers: 3.1.1 + vue-component-type-helpers: 3.1.2 '@swc/helpers@0.5.17': dependencies: @@ -10613,8 +10590,6 @@ snapshots: '@types/diff-match-patch@1.0.36': {} - '@types/eslint-plugin-tailwindcss@3.17.0': {} - '@types/estree@1.0.5': {} '@types/estree@1.0.8': {} @@ -12380,14 +12355,6 @@ snapshots: - supports-color - typescript - eslint-plugin-tailwindcss@4.0.0-beta.0(tailwindcss@4.1.12): - dependencies: - fast-glob: 3.3.3 - postcss: 8.5.6 - synckit: 0.11.11 - tailwind-api-utils: 1.0.3(tailwindcss@4.1.12) - tailwindcss: 4.1.12 - eslint-plugin-unused-imports@4.2.0(@typescript-eslint/eslint-plugin@8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.35.0(jiti@2.4.2)): dependencies: eslint: 9.35.0(jiti@2.4.2) @@ -15431,13 +15398,6 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - tailwind-api-utils@1.0.3(tailwindcss@4.1.12): - dependencies: - enhanced-resolve: 5.18.3 - jiti: 2.5.1 - local-pkg: 1.1.2 - tailwindcss: 4.1.12 - tailwind-merge@2.6.0: {} tailwindcss-primeui@0.6.1(tailwindcss@4.1.12): @@ -15983,6 +15943,8 @@ snapshots: vue-component-type-helpers@3.1.1: {} + vue-component-type-helpers@3.1.2: {} + vue-demi@0.14.10(vue@3.5.13(typescript@5.9.2)): dependencies: vue: 3.5.13(typescript@5.9.2) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a7e91efdc..a972730cb 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -30,7 +30,6 @@ catalog: '@storybook/vue3-vite': ^9.1.1 '@tailwindcss/vite': ^4.1.12 '@trivago/prettier-plugin-sort-imports': ^5.2.0 - '@types/eslint-plugin-tailwindcss': ^3.17.0 '@types/fs-extra': ^11.0.4 '@types/jsdom': ^21.1.7 '@types/node': ^20.14.8 @@ -52,7 +51,6 @@ catalog: eslint-plugin-import-x: ^4.16.1 eslint-plugin-prettier: ^5.5.4 eslint-plugin-storybook: ^9.1.6 - eslint-plugin-tailwindcss: 4.0.0-beta.0 eslint-plugin-unused-imports: ^4.2.0 eslint-plugin-vue: ^10.4.0 firebase: ^11.6.0 @@ -64,6 +62,7 @@ catalog: knip: ^5.62.0 lint-staged: ^15.2.7 markdown-table: ^3.0.4 + mixpanel-browser: ^2.71.0 nx: 21.4.1 picocolors: ^1.1.1 pinia: ^2.1.7 @@ -99,7 +98,6 @@ catalog: zod: ^3.23.8 zod-to-json-schema: ^3.24.1 zod-validation-error: ^3.3.0 - mixpanel-browser: ^2.71.0 cleanupUnusedCatalogs: true From 0a80a288c00f1ea1fbbafc192ae169e9e1a43378 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Tue, 28 Oct 2025 08:32:16 -0700 Subject: [PATCH 013/115] add title to asset names in model browser (#6338) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show full title when hovering the text. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6338-add-title-to-asset-names-in-model-browser-29a6d73d36508106a1d5ce9c09007b78) by [Unito](https://www.unito.io) --- src/platform/assets/components/AssetCard.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/assets/components/AssetCard.vue b/src/platform/assets/components/AssetCard.vue index dd35b4fc1..3f793529b 100644 --- a/src/platform/assets/components/AssetCard.vue +++ b/src/platform/assets/components/AssetCard.vue @@ -31,6 +31,7 @@ 'dark-theme:text-white' ) " + :title="asset.name" > {{ asset.name }} From b03cf7e11d82d6b1eed3468afee2d14563f66c1f Mon Sep 17 00:00:00 2001 From: Alexander Brown Date: Tue, 28 Oct 2025 12:13:28 -0700 Subject: [PATCH 014/115] Style: Token renaming and style organization (#6337) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Align color names and organize style.css some more ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6337-Style-Token-renaming-and-style-organization-29a6d73d365081b69f25ce1298c67fdc) by [Unito](https://www.unito.io) --- packages/design-system/src/css/style.css | 172 +++++++++-------- packages/tailwind-utils/README.md | 2 +- src/components/common/FormImageUpload.vue | 4 +- .../dialog/content/setting/UsageLogsTable.vue | 2 +- .../dialog/content/setting/UserPanel.vue | 2 +- .../graph/modals/ZoomControlsModal.vue | 2 +- .../graph/selectionToolbox/MenuOptionItem.vue | 2 +- .../graph/selectionToolbox/SubmenuPopover.vue | 6 +- .../selectionToolbox/VerticalDivider.vue | 4 +- .../graph/widgets/ChatHistoryWidget.vue | 4 +- .../graph/widgets/chatHistory/CopyButton.vue | 2 +- .../MultiSelect.accessibility.stories.ts | 42 ++--- src/components/input/MultiSelect.vue | 2 +- .../SingleSelect.accessibility.stories.ts | 58 +++--- src/components/input/SingleSelect.vue | 4 +- src/components/load3d/Load3DControls.vue | 6 +- .../load3d/controls/RecordingControls.vue | 2 +- .../load3d/controls/ViewerControls.vue | 2 +- src/components/topbar/TopbarBadge.test.ts | 4 +- src/components/topbar/TopbarBadge.vue | 6 +- .../widget/layout/BaseModalLayout.vue | 4 +- src/components/widget/nav/NavItem.vue | 4 +- src/core/graph/subgraph/SubgraphNode.vue | 4 +- .../assets/components/AssetBadgeGroup.vue | 8 +- .../components/AssetBrowserModal.stories.ts | 6 +- .../assets/components/AssetCard.stories.ts | 12 +- src/platform/assets/components/AssetCard.vue | 18 +- .../components/AssetFilterBar.stories.ts | 10 +- src/platform/assets/components/AssetGrid.vue | 4 +- .../assets/components/MediaImageTop.vue | 2 +- .../useAssetBrowserDialog.stories.ts | 10 +- .../extensions/vueNodes/VideoPreview.vue | 14 +- .../vueNodes/components/ImagePreview.vue | 10 +- .../vueNodes/components/LivePreview.vue | 6 +- .../widgets/components/WidgetChart.vue | 2 +- .../widgets/components/WidgetRecordAudio.vue | 6 +- .../components/audio/AudioPreviewPlayer.vue | 16 +- src/scripts/ui/menu/menu.css | 177 ------------------ 38 files changed, 235 insertions(+), 406 deletions(-) diff --git a/packages/design-system/src/css/style.css b/packages/design-system/src/css/style.css index 4b559c4b3..21553a439 100644 --- a/packages/design-system/src/css/style.css +++ b/packages/design-system/src/css/style.css @@ -9,29 +9,18 @@ @config '../../tailwind.config.ts'; -@media (prefers-color-scheme: dark) { - :root { - --fg-color: #fff; - --bg-color: #202020; - --content-bg: #4e4e4e; - --content-fg: #fff; - --content-hover-bg: #222; - --content-hover-fg: #fff; - } -} - @theme { --text-xxs: 0.625rem; --text-xxs--line-height: calc(1 / 0.625); - /* Spacing */ - --spacing-xs: 8px; + --text-xxxs: 0.5625rem; + --text-xxxs--line-height: calc(1 / 0.5625); /* Font Families */ --font-inter: 'Inter', sans-serif; /* Palette Colors */ - --color-charcoal-100: #171718; + --color-charcoal-100: #55565e; --color-charcoal-200: #494a50; --color-charcoal-300: #3c3d42; --color-charcoal-400: #313235; @@ -42,43 +31,45 @@ --color-neutral-550: #636363; - --color-stone-100: #828282; - --color-stone-200: #444444; - --color-stone-300: #bbbbbb; + --color-ash-300: #bbbbbb; + --color-ash-500: #828282; + --color-ash-800: #444444; --color-ivory-100: #fdfbfa; --color-ivory-200: #faf9f5; --color-ivory-300: #f0eee6; - --color-gray-100: #f3f3f3; - --color-gray-200: #e9e9e9; - --color-gray-300: #e1e1e1; - --color-gray-400: #d9d9d9; - --color-gray-500: #c5c5c5; - --color-gray-600: #b4b4b4; - --color-gray-700: #a0a0a0; - --color-gray-800: #8a8a8a; + --color-smoke-100: #f3f3f3; + --color-smoke-200: #e9e9e9; + --color-smoke-300: #e1e1e1; + --color-smoke-400: #d9d9d9; + --color-smoke-500: #c5c5c5; + --color-smoke-600: #b4b4b4; + --color-smoke-700: #a0a0a0; + --color-smoke-800: #8a8a8a; --color-sand-100: #e1ded5; --color-sand-200: #d6cfc2; --color-sand-300: #888682; - --color-pure-black: #000000; - --color-pure-white: #ffffff; - --color-slate-100: #9c9eab; --color-slate-200: #9fa2bd; --color-slate-300: #5b5e7d; - --color-brand-yellow: #f0ff41; - --color-brand-blue: #172dd7; + --color-electric-400: #f0ff41; + --color-sapphire-700: #172dd7; + --color-brand-yellow: var(--color-electric-400); + --color-brand-blue: var(--color-sapphire-700); + + --color-azure-400: #31b9f4; + --color-azure-600: #0b8ce9; + + --color-jade-400: #47e469; + --color-jade-600: #00cd72; + + --color-gold-400: #fcbf64; + --color-gold-600: #fd9903; - --color-blue-100: #0b8ce9; - --color-blue-200: #31b9f4; - --color-success-100: #00cd72; - --color-success-200: #47e469; - --color-warning-100: #fd9903; - --color-warning-200: #fcbf64; --color-danger-100: #c02323; --color-danger-200: #d62952; @@ -90,26 +81,24 @@ --color-error: #962a2a; --color-comfy-menu-secondary: var(--comfy-menu-secondary-bg); - --text-xxxs: 0.5625rem; - --text-xxxs--line-height: calc(1 / 0.5625); - --color-blue-selection: rgb(from var(--color-blue-100) r g b / 0.3); - --color-node-hover-100: rgb(from var(--color-charcoal-100) r g b/ 0.15); - --color-node-hover-200: rgb(from var(--color-charcoal-100) r g b/ 0.1); - --color-modal-tag: rgb(from var(--color-gray-400) r g b/ 0.4); + --color-blue-selection: rgb(from var(--color-azure-600) r g b / 0.3); + --color-node-hover-100: rgb(from var(--color-charcoal-800) r g b/ 0.15); + --color-node-hover-200: rgb(from var(--color-charcoal-800) r g b/ 0.1); + --color-modal-tag: rgb(from var(--color-smoke-400) r g b/ 0.4); --color-alpha-charcoal-600-30: color-mix( in srgb, var(--color-charcoal-600) 30%, transparent ); - --color-alpha-stone-100-20: color-mix( + --color-alpha-ash-500-20: color-mix( in srgb, - var(--color-stone-100) 20%, + var(--color-ash-500) 20%, transparent ); - --color-alpha-gray-500-50: color-mix( + --color-alpha-smoke-500-50: color-mix( in srgb, - var(--color-gray-500) 50%, + var(--color-smoke-500) 50%, transparent ); @@ -145,8 +134,8 @@ --content-hover-bg: #adadad; --content-hover-fg: #000; - --button-surface: var(--color-pure-white); - --button-surface-contrast: var(--color-pure-black); + --button-surface: var(--color-white); + --button-surface-contrast: var(--color-black); /* Code styling colors for help menu*/ --code-text-color: rgb(0 122 255 / 1); @@ -157,31 +146,36 @@ --accent-primary: var(--color-charcoal-700); --backdrop: var(--color-white); - --button-hover-surface: var(--color-gray-200); - --button-active-surface: var(--color-gray-400); - --button-icon: var(--color-gray-600); + + --button-hover-surface: var(--color-smoke-200); + --button-active-surface: var(--color-smoke-400); + --button-icon: var(--color-smoke-600); + --dialog-surface: var(--color-neutral-200); - --interface-menu-component-surface-hovered: var(--color-gray-200); - --interface-menu-component-surface-selected: var(--color-gray-400); - --interface-menu-keybind-surface-default: var(--color-gray-500); - --interface-panel-surface: var(--color-pure-white); - --interface-stroke: var(--color-gray-300); - --nav-background: var(--color-pure-white); - --node-border: var(--color-gray-300); - --node-component-border: var(--color-gray-400); - --node-component-disabled: var(--color-alpha-stone-100-20); + + --interface-menu-component-surface-hovered: var(--color-smoke-200); + --interface-menu-component-surface-selected: var(--color-smoke-400); + --interface-menu-keybind-surface-default: var(--color-smoke-500); + --interface-panel-surface: var(--color-white); + --interface-stroke: var(--color-smoke-300); + + --nav-background: var(--color-white); + + --node-border: var(--color-smoke-300); + --node-component-border: var(--color-smoke-400); + --node-component-disabled: var(--color-alpha-ash-500-20); --node-component-executing: var(--color-blue-500); --node-component-header: var(--fg-color); - --node-component-header-icon: var(--color-stone-200); + --node-component-header-icon: var(--color-ash-800); --node-component-header-surface: var(--color-white); --node-component-outline: var(--color-black); - --node-component-ring: rgb(from var(--color-gray-500) r g b / 50%); + --node-component-ring: rgb(from var(--color-smoke-500) r g b / 50%); --node-component-slot-dot-outline-opacity-mult: 1; --node-component-slot-dot-outline-opacity: 5%; --node-component-slot-dot-outline: var(--color-black); - --node-component-slot-text: var(--color-stone-200); - --node-component-surface-highlight: var(--color-stone-100); - --node-component-surface-hovered: var(--color-gray-200); + --node-component-slot-text: var(--color-ash-800); + --node-component-surface-highlight: var(--color-ash-500); + --node-component-surface-hovered: var(--color-smoke-200); --node-component-surface-selected: var(--color-charcoal-200); --node-component-surface: var(--color-white); --node-component-tooltip: var(--color-charcoal-700); @@ -193,40 +187,53 @@ ); --node-component-widget-skeleton-surface: var(--color-zinc-300); --node-divider: var(--color-sand-100); - --node-icon-disabled: var(--color-alpha-gray-500-50); - --node-stroke: var(--color-gray-400); + --node-icon-disabled: var(--color-alpha-smoke-500-50); + --node-stroke: var(--color-smoke-400); --node-stroke-selected: var(--color-accent-primary); --node-stroke-error: var(--color-error); - --node-stroke-executing: var(--color-blue-100); - --text-secondary: var(--color-stone-100); + --node-stroke-executing: var(--color-azure-600); + + --text-secondary: var(--color-ash-500); --text-primary: var(--color-charcoal-700); --input-surface: rgb(0 0 0 / 0.15); } .dark-theme { - --accent-primary: var(--color-pure-white); + --fg-color: #fff; + --bg-color: #202020; + --content-bg: #4e4e4e; + --content-fg: #fff; + --content-hover-bg: #222; + --content-hover-fg: #fff; + + --accent-primary: var(--color-white); --backdrop: var(--color-neutral-900); + --button-surface: var(--color-charcoal-600); - --button-surface-contrast: var(--color-pure-white); + --button-surface-contrast: var(--color-white); --button-hover-surface: var(--color-charcoal-600); --button-active-surface: var(--color-charcoal-600); - --button-icon: var(--color-gray-800); + --button-icon: var(--color-smoke-800); + --dialog-surface: var(--color-neutral-700); + --interface-menu-component-surface-hovered: var(--color-charcoal-400); --interface-menu-component-surface-selected: var(--color-charcoal-300); --interface-menu-keybind-surface-default: var(--color-charcoal-200); - --interface-panel-surface: var(--color-charcoal-100); + --interface-panel-surface: var(--color-charcoal-800); --interface-stroke: var(--color-charcoal-400); - --nav-background: var(--color-charcoal-100); + + --nav-background: var(--color-charcoal-800); + --node-border: var(--color-charcoal-500); - --node-component-border: var(--color-stone-200); + --node-component-border: var(--color-ash-800); --node-component-border-error: var(--color-danger-100); --node-component-border-executing: var(--color-blue-500); --node-component-border-selected: var(--color-charcoal-200); --node-component-header-icon: var(--color-slate-300); --node-component-header-surface: var(--color-charcoal-800); --node-component-outline: var(--color-white); - --node-component-ring: rgb(var(--color-gray-500) / 20%); + --node-component-ring: rgb(var(--color-smoke-500) / 20%); --node-component-slot-dot-outline-opacity: 10%; --node-component-slot-dot-outline: var(--color-white); --node-component-slot-text: var(--color-slate-200); @@ -240,13 +247,15 @@ --node-component-widget-skeleton-surface: var(--color-zinc-800); --node-component-disabled: var(--color-alpha-charcoal-600-30); --node-divider: var(--color-charcoal-500); - --node-icon-disabled: var(--color-alpha-stone-100-20); - --node-stroke: var(--color-stone-200); - --node-stroke-selected: var(--color-pure-white); + --node-icon-disabled: var(--color-alpha-ash-500-20); + --node-stroke: var(--color-ash-800); + --node-stroke-selected: var(--color-white); --node-stroke-error: var(--color-error); - --node-stroke-executing: var(--color-blue-100); + --node-stroke-executing: var(--color-azure-600); + --text-secondary: var(--color-slate-100); - --text-primary: var(--color-pure-white); + --text-primary: var(--color-white); + --input-surface: rgb(130 130 130 / 0.1); } @@ -330,7 +339,6 @@ } } - /* ===================== Scrollbar Utilities (Tailwind) ===================== Usage: Add `scrollbar-custom` class to scrollable containers. The scrollbar styling adapts to light/dark theme automatically. diff --git a/packages/tailwind-utils/README.md b/packages/tailwind-utils/README.md index 5f315600b..35c725e88 100644 --- a/packages/tailwind-utils/README.md +++ b/packages/tailwind-utils/README.md @@ -14,7 +14,7 @@ import { cn } from '@comfyorg/tailwind-utils' // Use with conditional classes (ternary)