From 6048fab23996e2dfd5ee2c3f290a26cb153adcb8 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Thu, 15 Jan 2026 17:24:48 -0800 Subject: [PATCH 01/11] feat: add per-tab workspace authentication infrastructure (#8073) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Add workspace authentication composables and types for per-tab workspace isolation. This infrastructure enables users to work in different workspaces in different browser tabs. ## Changes - **useWorkspaceAuth composable** - workspace token management - Exchange Firebase token for workspace-scoped JWT via `POST /api/auth/token` - Auto-refresh tokens 5 minutes before expiry - Per-tab sessionStorage caching - **useWorkspaceSwitch composable** - workspace switching with unsaved changes confirmation - **WorkspaceWithRole/WorkspaceTokenResponse types** - aligned with backend API - **firebaseAuthStore.getAuthHeader()** - prioritizes workspace tokens over Firebase tokens - **useSessionCookie** - uses Firebase token directly (getIdToken()) since getAuthHeader() now returns workspace token ## Backend Dependency - `POST /api/auth/token` - exchange Firebase token for workspace token - `GET /api/workspaces` - list user's workspaces ## Related - https://github.com/Comfy-Org/ComfyUI_frontend/pull/6295 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8073-feat-add-per-tab-workspace-authentication-infrastructure-2e96d73d3650816c8cf9dae9c330aebb) by [Unito](https://www.unito.io) --------- Co-authored-by: anthropic/claude Co-authored-by: Amp Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com> --- src/composables/auth/useCurrentUser.ts | 4 +- src/composables/useFeatureFlags.ts | 9 +- src/locales/en/main.json | 15 + src/platform/auth/session/useSessionCookie.ts | 88 ++- .../auth/workspace/useWorkspaceAuth.test.ts | 670 ++++++++++++++++++ .../auth/workspace/useWorkspaceSwitch.test.ts | 166 +++++ .../auth/workspace/useWorkspaceSwitch.ts | 49 ++ .../auth/workspace/workspaceConstants.ts | 7 + src/platform/auth/workspace/workspaceTypes.ts | 6 + src/platform/remoteConfig/types.ts | 1 + src/stores/firebaseAuthStore.ts | 40 +- src/stores/workspaceAuthStore.ts | 373 ++++++++++ 12 files changed, 1392 insertions(+), 36 deletions(-) create mode 100644 src/platform/auth/workspace/useWorkspaceAuth.test.ts create mode 100644 src/platform/auth/workspace/useWorkspaceSwitch.test.ts create mode 100644 src/platform/auth/workspace/useWorkspaceSwitch.ts create mode 100644 src/platform/auth/workspace/workspaceConstants.ts create mode 100644 src/platform/auth/workspace/workspaceTypes.ts create mode 100644 src/stores/workspaceAuthStore.ts diff --git a/src/composables/auth/useCurrentUser.ts b/src/composables/auth/useCurrentUser.ts index cc5634cae..b43191fbb 100644 --- a/src/composables/auth/useCurrentUser.ts +++ b/src/composables/auth/useCurrentUser.ts @@ -41,8 +41,8 @@ export const useCurrentUser = () => { whenever(() => authStore.tokenRefreshTrigger, callback) const onUserLogout = (callback: () => void) => { - watch(resolvedUserInfo, (user) => { - if (!user) callback() + watch(resolvedUserInfo, (user, prevUser) => { + if (prevUser && !user) callback() }) } diff --git a/src/composables/useFeatureFlags.ts b/src/composables/useFeatureFlags.ts index 4e7368bc6..136b7ccd1 100644 --- a/src/composables/useFeatureFlags.ts +++ b/src/composables/useFeatureFlags.ts @@ -17,7 +17,8 @@ export enum ServerFeatureFlag { ONBOARDING_SURVEY_ENABLED = 'onboarding_survey_enabled', HUGGINGFACE_MODEL_IMPORT_ENABLED = 'huggingface_model_import_enabled', LINEAR_TOGGLE_ENABLED = 'linear_toggle_enabled', - ASYNC_MODEL_UPLOAD_ENABLED = 'async_model_upload_enabled' + ASYNC_MODEL_UPLOAD_ENABLED = 'async_model_upload_enabled', + TEAM_WORKSPACES_ENABLED = 'team_workspaces_enabled' } /** @@ -92,6 +93,12 @@ export function useFeatureFlags() { false ) ) + }, + get teamWorkspacesEnabled() { + return ( + remoteConfig.value.team_workspaces_enabled ?? + api.getServerFeature(ServerFeatureFlag.TEAM_WORKSPACES_ENABLED, false) + ) } }) diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 9fd1284fd..65189f5b8 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -2592,5 +2592,20 @@ "completed": "Completed", "failed": "Failed" } + }, + "workspace": { + "unsavedChanges": { + "title": "Unsaved Changes", + "message": "You have unsaved changes. Do you want to discard them and switch workspaces?" + } + }, + "workspaceAuth": { + "errors": { + "notAuthenticated": "You must be logged in to access workspaces", + "invalidFirebaseToken": "Authentication failed. Please try logging in again.", + "accessDenied": "You do not have access to this workspace", + "workspaceNotFound": "Workspace not found", + "tokenExchangeFailed": "Failed to authenticate with workspace: {error}" + } } } \ No newline at end of file diff --git a/src/platform/auth/session/useSessionCookie.ts b/src/platform/auth/session/useSessionCookie.ts index 49f6fec46..a919b59eb 100644 --- a/src/platform/auth/session/useSessionCookie.ts +++ b/src/platform/auth/session/useSessionCookie.ts @@ -1,5 +1,6 @@ -import { api } from '@/scripts/api' import { isCloud } from '@/platform/distribution/types' +import { remoteConfig } from '@/platform/remoteConfig/remoteConfig' +import { api } from '@/scripts/api' import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' /** @@ -10,31 +11,59 @@ export const useSessionCookie = () => { /** * Creates or refreshes the session cookie. * Called after login and on token refresh. + * + * When team_workspaces_enabled is true, uses Firebase token directly + * (since getAuthHeader() returns workspace token which shouldn't be used for session creation). + * When disabled, uses getAuthHeader() for backward compatibility. */ const createSession = async (): Promise => { if (!isCloud) return - const authStore = useFirebaseAuthStore() - const authHeader = await authStore.getAuthHeader() + try { + const authStore = useFirebaseAuthStore() - if (!authHeader) { - throw new Error('No auth header available for session creation') - } + let authHeader: Record - const response = await fetch(api.apiURL('/auth/session'), { - method: 'POST', - credentials: 'include', - headers: { - ...authHeader, - 'Content-Type': 'application/json' + if (remoteConfig.value.team_workspaces_enabled) { + const firebaseToken = await authStore.getIdToken() + if (!firebaseToken) { + console.warn( + 'Failed to create session cookie:', + 'No Firebase token available for session creation' + ) + return + } + authHeader = { Authorization: `Bearer ${firebaseToken}` } + } else { + const header = await authStore.getAuthHeader() + if (!header) { + console.warn( + 'Failed to create session cookie:', + 'No auth header available for session creation' + ) + return + } + authHeader = header } - }) - if (!response.ok) { - const errorData = await response.json().catch(() => ({})) - throw new Error( - `Failed to create session: ${errorData.message || response.statusText}` - ) + const response = await fetch(api.apiURL('/auth/session'), { + method: 'POST', + credentials: 'include', + headers: { + ...authHeader, + 'Content-Type': 'application/json' + } + }) + + if (!response.ok) { + const errorData = await response.json().catch(() => ({})) + console.warn( + 'Failed to create session cookie:', + errorData.message || response.statusText + ) + } + } catch (error) { + console.warn('Failed to create session cookie:', error) } } @@ -45,16 +74,21 @@ export const useSessionCookie = () => { const deleteSession = async (): Promise => { if (!isCloud) return - const response = await fetch(api.apiURL('/auth/session'), { - method: 'DELETE', - credentials: 'include' - }) + try { + const response = await fetch(api.apiURL('/auth/session'), { + method: 'DELETE', + credentials: 'include' + }) - if (!response.ok) { - const errorData = await response.json().catch(() => ({})) - throw new Error( - `Failed to delete session: ${errorData.message || response.statusText}` - ) + if (!response.ok) { + const errorData = await response.json().catch(() => ({})) + console.warn( + 'Failed to delete session cookie:', + errorData.message || response.statusText + ) + } + } catch (error) { + console.warn('Failed to delete session cookie:', error) } } diff --git a/src/platform/auth/workspace/useWorkspaceAuth.test.ts b/src/platform/auth/workspace/useWorkspaceAuth.test.ts new file mode 100644 index 000000000..68f5a198c --- /dev/null +++ b/src/platform/auth/workspace/useWorkspaceAuth.test.ts @@ -0,0 +1,670 @@ +import { createPinia, setActivePinia, storeToRefs } from 'pinia' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +import { + useWorkspaceAuthStore, + WorkspaceAuthError +} from '@/stores/workspaceAuthStore' + +import { WORKSPACE_STORAGE_KEYS } from './workspaceConstants' + +const mockGetIdToken = vi.fn() + +vi.mock('@/stores/firebaseAuthStore', () => ({ + useFirebaseAuthStore: () => ({ + getIdToken: mockGetIdToken + }) +})) + +vi.mock('@/scripts/api', () => ({ + api: { + apiURL: (route: string) => `https://api.example.com/api${route}` + } +})) + +vi.mock('@/i18n', () => ({ + t: (key: string) => key +})) + +const mockRemoteConfig = vi.hoisted(() => ({ + value: { + team_workspaces_enabled: true + } +})) + +vi.mock('@/platform/remoteConfig/remoteConfig', () => ({ + remoteConfig: mockRemoteConfig +})) + +const mockWorkspace = { + id: 'workspace-123', + name: 'Test Workspace', + type: 'team' as const +} + +const mockWorkspaceWithRole = { + ...mockWorkspace, + role: 'owner' as const +} + +const mockTokenResponse = { + token: 'workspace-token-abc', + expires_at: new Date(Date.now() + 3600 * 1000).toISOString(), + workspace: mockWorkspace, + role: 'owner' as const, + permissions: ['owner:*'] +} + +describe('useWorkspaceAuthStore', () => { + beforeEach(() => { + setActivePinia(createPinia()) + vi.clearAllMocks() + vi.useFakeTimers() + sessionStorage.clear() + }) + + afterEach(() => { + vi.useRealTimers() + }) + + describe('initial state', () => { + it('has correct initial state values', () => { + const store = useWorkspaceAuthStore() + const { + currentWorkspace, + workspaceToken, + isAuthenticated, + isLoading, + error + } = storeToRefs(store) + + expect(currentWorkspace.value).toBeNull() + expect(workspaceToken.value).toBeNull() + expect(isAuthenticated.value).toBe(false) + expect(isLoading.value).toBe(false) + expect(error.value).toBeNull() + }) + }) + + describe('initializeFromSession', () => { + it('returns true and populates state when valid session data exists', () => { + const futureExpiry = Date.now() + 3600 * 1000 + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE, + JSON.stringify(mockWorkspaceWithRole) + ) + sessionStorage.setItem(WORKSPACE_STORAGE_KEYS.TOKEN, 'valid-token') + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.EXPIRES_AT, + futureExpiry.toString() + ) + + const store = useWorkspaceAuthStore() + const { currentWorkspace, workspaceToken } = storeToRefs(store) + + const result = store.initializeFromSession() + + expect(result).toBe(true) + expect(currentWorkspace.value).toEqual(mockWorkspaceWithRole) + expect(workspaceToken.value).toBe('valid-token') + }) + + it('returns false when sessionStorage is empty', () => { + const store = useWorkspaceAuthStore() + + const result = store.initializeFromSession() + + expect(result).toBe(false) + }) + + it('returns false and clears storage when token is expired', () => { + const pastExpiry = Date.now() - 1000 + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE, + JSON.stringify(mockWorkspaceWithRole) + ) + sessionStorage.setItem(WORKSPACE_STORAGE_KEYS.TOKEN, 'expired-token') + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.EXPIRES_AT, + pastExpiry.toString() + ) + + const store = useWorkspaceAuthStore() + + const result = store.initializeFromSession() + + expect(result).toBe(false) + expect( + sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE) + ).toBeNull() + expect(sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.TOKEN)).toBeNull() + expect( + sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.EXPIRES_AT) + ).toBeNull() + }) + + it('returns false and clears storage when data is malformed', () => { + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE, + 'invalid-json{' + ) + sessionStorage.setItem(WORKSPACE_STORAGE_KEYS.TOKEN, 'some-token') + sessionStorage.setItem(WORKSPACE_STORAGE_KEYS.EXPIRES_AT, 'not-a-number') + + const store = useWorkspaceAuthStore() + + const result = store.initializeFromSession() + + expect(result).toBe(false) + expect( + sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE) + ).toBeNull() + expect(sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.TOKEN)).toBeNull() + expect( + sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.EXPIRES_AT) + ).toBeNull() + }) + + it('returns false when partial session data exists (missing token)', () => { + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE, + JSON.stringify(mockWorkspaceWithRole) + ) + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.EXPIRES_AT, + (Date.now() + 3600 * 1000).toString() + ) + + const store = useWorkspaceAuthStore() + + const result = store.initializeFromSession() + + expect(result).toBe(false) + }) + }) + + describe('switchWorkspace', () => { + it('successfully exchanges Firebase token for workspace token', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockTokenResponse) + }) + ) + + const store = useWorkspaceAuthStore() + const { currentWorkspace, workspaceToken, isAuthenticated } = + storeToRefs(store) + + await store.switchWorkspace('workspace-123') + + expect(currentWorkspace.value).toEqual(mockWorkspaceWithRole) + expect(workspaceToken.value).toBe('workspace-token-abc') + expect(isAuthenticated.value).toBe(true) + }) + + it('stores workspace data in sessionStorage', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockTokenResponse) + }) + ) + + const store = useWorkspaceAuthStore() + + await store.switchWorkspace('workspace-123') + + expect( + sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE) + ).toBe(JSON.stringify(mockWorkspaceWithRole)) + expect(sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.TOKEN)).toBe( + 'workspace-token-abc' + ) + expect( + sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.EXPIRES_AT) + ).toBeTruthy() + }) + + it('sets isLoading to true during operation', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + let resolveResponse: (value: unknown) => void + const responsePromise = new Promise((resolve) => { + resolveResponse = resolve + }) + vi.stubGlobal('fetch', vi.fn().mockReturnValue(responsePromise)) + + const store = useWorkspaceAuthStore() + const { isLoading } = storeToRefs(store) + + const switchPromise = store.switchWorkspace('workspace-123') + expect(isLoading.value).toBe(true) + + resolveResponse!({ + ok: true, + json: () => Promise.resolve(mockTokenResponse) + }) + await switchPromise + + expect(isLoading.value).toBe(false) + }) + + it('throws WorkspaceAuthError with code NOT_AUTHENTICATED when Firebase token unavailable', async () => { + mockGetIdToken.mockResolvedValue(undefined) + + const store = useWorkspaceAuthStore() + const { error } = storeToRefs(store) + + await expect(store.switchWorkspace('workspace-123')).rejects.toThrow( + WorkspaceAuthError + ) + + expect(error.value).toBeInstanceOf(WorkspaceAuthError) + expect((error.value as WorkspaceAuthError).code).toBe('NOT_AUTHENTICATED') + }) + + it('throws WorkspaceAuthError with code ACCESS_DENIED on 403 response', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: false, + status: 403, + statusText: 'Forbidden', + json: () => Promise.resolve({ message: 'Access denied' }) + }) + ) + + const store = useWorkspaceAuthStore() + const { error } = storeToRefs(store) + + await expect(store.switchWorkspace('workspace-123')).rejects.toThrow( + WorkspaceAuthError + ) + + expect(error.value).toBeInstanceOf(WorkspaceAuthError) + expect((error.value as WorkspaceAuthError).code).toBe('ACCESS_DENIED') + }) + + it('throws WorkspaceAuthError with code WORKSPACE_NOT_FOUND on 404 response', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: false, + status: 404, + statusText: 'Not Found', + json: () => Promise.resolve({ message: 'Workspace not found' }) + }) + ) + + const store = useWorkspaceAuthStore() + const { error } = storeToRefs(store) + + await expect(store.switchWorkspace('workspace-123')).rejects.toThrow( + WorkspaceAuthError + ) + + expect(error.value).toBeInstanceOf(WorkspaceAuthError) + expect((error.value as WorkspaceAuthError).code).toBe( + 'WORKSPACE_NOT_FOUND' + ) + }) + + it('throws WorkspaceAuthError with code INVALID_FIREBASE_TOKEN on 401 response', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: false, + status: 401, + statusText: 'Unauthorized', + json: () => Promise.resolve({ message: 'Invalid token' }) + }) + ) + + const store = useWorkspaceAuthStore() + const { error } = storeToRefs(store) + + await expect(store.switchWorkspace('workspace-123')).rejects.toThrow( + WorkspaceAuthError + ) + + expect(error.value).toBeInstanceOf(WorkspaceAuthError) + expect((error.value as WorkspaceAuthError).code).toBe( + 'INVALID_FIREBASE_TOKEN' + ) + }) + + it('throws WorkspaceAuthError with code TOKEN_EXCHANGE_FAILED on other errors', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: false, + status: 500, + statusText: 'Internal Server Error', + json: () => Promise.resolve({ message: 'Server error' }) + }) + ) + + const store = useWorkspaceAuthStore() + const { error } = storeToRefs(store) + + await expect(store.switchWorkspace('workspace-123')).rejects.toThrow( + WorkspaceAuthError + ) + + expect(error.value).toBeInstanceOf(WorkspaceAuthError) + expect((error.value as WorkspaceAuthError).code).toBe( + 'TOKEN_EXCHANGE_FAILED' + ) + }) + + it('sends correct request to API', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + const mockFetch = vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockTokenResponse) + }) + vi.stubGlobal('fetch', mockFetch) + + const store = useWorkspaceAuthStore() + + await store.switchWorkspace('workspace-123') + + expect(mockFetch).toHaveBeenCalledWith( + 'https://api.example.com/api/auth/token', + { + method: 'POST', + headers: { + Authorization: 'Bearer firebase-token-xyz', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ workspace_id: 'workspace-123' }) + } + ) + }) + }) + + describe('clearWorkspaceContext', () => { + it('clears all state refs', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockTokenResponse) + }) + ) + + const store = useWorkspaceAuthStore() + const { currentWorkspace, workspaceToken, error, isAuthenticated } = + storeToRefs(store) + + await store.switchWorkspace('workspace-123') + expect(isAuthenticated.value).toBe(true) + + store.clearWorkspaceContext() + + expect(currentWorkspace.value).toBeNull() + expect(workspaceToken.value).toBeNull() + expect(error.value).toBeNull() + expect(isAuthenticated.value).toBe(false) + }) + + it('clears sessionStorage', async () => { + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE, + JSON.stringify(mockWorkspaceWithRole) + ) + sessionStorage.setItem(WORKSPACE_STORAGE_KEYS.TOKEN, 'some-token') + sessionStorage.setItem(WORKSPACE_STORAGE_KEYS.EXPIRES_AT, '12345') + + const store = useWorkspaceAuthStore() + + store.clearWorkspaceContext() + + expect( + sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE) + ).toBeNull() + expect(sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.TOKEN)).toBeNull() + expect( + sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.EXPIRES_AT) + ).toBeNull() + }) + }) + + describe('getWorkspaceAuthHeader', () => { + it('returns null when no workspace token', () => { + const store = useWorkspaceAuthStore() + + const header = store.getWorkspaceAuthHeader() + + expect(header).toBeNull() + }) + + it('returns proper Authorization header when workspace token exists', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockTokenResponse) + }) + ) + + const store = useWorkspaceAuthStore() + + await store.switchWorkspace('workspace-123') + const header = store.getWorkspaceAuthHeader() + + expect(header).toEqual({ + Authorization: 'Bearer workspace-token-abc' + }) + }) + }) + + describe('token refresh scheduling', () => { + it('schedules token refresh 5 minutes before expiry', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + const expiresInMs = 3600 * 1000 + const tokenResponseWithFutureExpiry = { + ...mockTokenResponse, + expires_at: new Date(Date.now() + expiresInMs).toISOString() + } + const mockFetch = vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(tokenResponseWithFutureExpiry) + }) + vi.stubGlobal('fetch', mockFetch) + + const store = useWorkspaceAuthStore() + + await store.switchWorkspace('workspace-123') + + expect(mockFetch).toHaveBeenCalledTimes(1) + + const refreshBufferMs = 5 * 60 * 1000 + const refreshDelay = expiresInMs - refreshBufferMs + + vi.advanceTimersByTime(refreshDelay - 1) + expect(mockFetch).toHaveBeenCalledTimes(1) + + await vi.advanceTimersByTimeAsync(1) + + expect(mockFetch).toHaveBeenCalledTimes(2) + }) + + it('clears context when refresh fails with ACCESS_DENIED', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + const expiresInMs = 3600 * 1000 + const tokenResponseWithFutureExpiry = { + ...mockTokenResponse, + expires_at: new Date(Date.now() + expiresInMs).toISOString() + } + const mockFetch = vi + .fn() + .mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve(tokenResponseWithFutureExpiry) + }) + .mockResolvedValueOnce({ + ok: false, + status: 403, + statusText: 'Forbidden', + json: () => Promise.resolve({ message: 'Access denied' }) + }) + vi.stubGlobal('fetch', mockFetch) + + const store = useWorkspaceAuthStore() + const { currentWorkspace, workspaceToken } = storeToRefs(store) + + await store.switchWorkspace('workspace-123') + expect(workspaceToken.value).toBe('workspace-token-abc') + + const refreshBufferMs = 5 * 60 * 1000 + const refreshDelay = expiresInMs - refreshBufferMs + + vi.advanceTimersByTime(refreshDelay) + await vi.waitFor(() => { + expect(currentWorkspace.value).toBeNull() + }) + + expect(workspaceToken.value).toBeNull() + }) + }) + + describe('refreshToken', () => { + it('does nothing when no current workspace', async () => { + const mockFetch = vi.fn() + vi.stubGlobal('fetch', mockFetch) + + const store = useWorkspaceAuthStore() + + await store.refreshToken() + + expect(mockFetch).not.toHaveBeenCalled() + }) + + it('refreshes token for current workspace', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + const mockFetch = vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockTokenResponse) + }) + vi.stubGlobal('fetch', mockFetch) + + const store = useWorkspaceAuthStore() + const { workspaceToken } = storeToRefs(store) + + await store.switchWorkspace('workspace-123') + expect(mockFetch).toHaveBeenCalledTimes(1) + + mockFetch.mockResolvedValue({ + ok: true, + json: () => + Promise.resolve({ + ...mockTokenResponse, + token: 'refreshed-token' + }) + }) + + await store.refreshToken() + expect(mockFetch).toHaveBeenCalledTimes(2) + expect(workspaceToken.value).toBe('refreshed-token') + }) + }) + + describe('isAuthenticated computed', () => { + it('returns true when both workspace and token are present', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockTokenResponse) + }) + ) + + const store = useWorkspaceAuthStore() + const { isAuthenticated } = storeToRefs(store) + + await store.switchWorkspace('workspace-123') + + expect(isAuthenticated.value).toBe(true) + }) + + it('returns false when workspace is null', () => { + const store = useWorkspaceAuthStore() + const { isAuthenticated } = storeToRefs(store) + + expect(isAuthenticated.value).toBe(false) + }) + + it('returns false when currentWorkspace is set but workspaceToken is null', async () => { + mockGetIdToken.mockResolvedValue(null) + + const store = useWorkspaceAuthStore() + const { currentWorkspace, workspaceToken, isAuthenticated } = + storeToRefs(store) + + currentWorkspace.value = mockWorkspaceWithRole + workspaceToken.value = null + + expect(isAuthenticated.value).toBe(false) + }) + }) + + describe('feature flag disabled', () => { + beforeEach(() => { + mockRemoteConfig.value.team_workspaces_enabled = false + }) + + afterEach(() => { + mockRemoteConfig.value.team_workspaces_enabled = true + }) + + it('initializeFromSession returns false when flag disabled', () => { + const futureExpiry = Date.now() + 3600 * 1000 + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE, + JSON.stringify(mockWorkspaceWithRole) + ) + sessionStorage.setItem(WORKSPACE_STORAGE_KEYS.TOKEN, 'valid-token') + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.EXPIRES_AT, + futureExpiry.toString() + ) + + const store = useWorkspaceAuthStore() + const { currentWorkspace, workspaceToken } = storeToRefs(store) + + const result = store.initializeFromSession() + + expect(result).toBe(false) + expect(currentWorkspace.value).toBeNull() + expect(workspaceToken.value).toBeNull() + }) + + it('switchWorkspace is a no-op when flag disabled', async () => { + mockGetIdToken.mockResolvedValue('firebase-token-xyz') + const mockFetch = vi.fn() + vi.stubGlobal('fetch', mockFetch) + + const store = useWorkspaceAuthStore() + const { currentWorkspace, workspaceToken, isLoading } = storeToRefs(store) + + await store.switchWorkspace('workspace-123') + + expect(mockFetch).not.toHaveBeenCalled() + expect(currentWorkspace.value).toBeNull() + expect(workspaceToken.value).toBeNull() + expect(isLoading.value).toBe(false) + }) + }) +}) diff --git a/src/platform/auth/workspace/useWorkspaceSwitch.test.ts b/src/platform/auth/workspace/useWorkspaceSwitch.test.ts new file mode 100644 index 000000000..ae71937b2 --- /dev/null +++ b/src/platform/auth/workspace/useWorkspaceSwitch.test.ts @@ -0,0 +1,166 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +import { useWorkspaceSwitch } from '@/platform/auth/workspace/useWorkspaceSwitch' +import type { WorkspaceWithRole } from '@/platform/auth/workspace/workspaceTypes' + +const mockSwitchWorkspace = vi.hoisted(() => vi.fn()) +const mockCurrentWorkspace = vi.hoisted(() => ({ + value: null as WorkspaceWithRole | null +})) + +vi.mock('@/stores/workspaceAuthStore', () => ({ + useWorkspaceAuthStore: () => ({ + switchWorkspace: mockSwitchWorkspace + }) +})) + +vi.mock('pinia', () => ({ + storeToRefs: () => ({ + currentWorkspace: mockCurrentWorkspace + }) +})) + +const mockModifiedWorkflows = vi.hoisted( + () => [] as Array<{ isModified: boolean }> +) + +vi.mock('@/platform/workflow/management/stores/workflowStore', () => ({ + useWorkflowStore: () => ({ + get modifiedWorkflows() { + return mockModifiedWorkflows + } + }) +})) + +const mockConfirm = vi.hoisted(() => vi.fn()) + +vi.mock('@/services/dialogService', () => ({ + useDialogService: () => ({ + confirm: mockConfirm + }) +})) + +vi.mock('vue-i18n', () => ({ + useI18n: () => ({ + t: (key: string) => key + }) +})) + +const mockReload = vi.fn() + +describe('useWorkspaceSwitch', () => { + beforeEach(() => { + vi.clearAllMocks() + mockCurrentWorkspace.value = { + id: 'workspace-1', + name: 'Test Workspace', + type: 'personal', + role: 'owner' + } + mockModifiedWorkflows.length = 0 + vi.stubGlobal('location', { reload: mockReload }) + }) + + afterEach(() => { + vi.unstubAllGlobals() + }) + + describe('hasUnsavedChanges', () => { + it('returns true when there are modified workflows', () => { + mockModifiedWorkflows.push({ isModified: true }) + const { hasUnsavedChanges } = useWorkspaceSwitch() + + expect(hasUnsavedChanges()).toBe(true) + }) + + it('returns true when multiple workflows are modified', () => { + mockModifiedWorkflows.push({ isModified: true }, { isModified: true }) + const { hasUnsavedChanges } = useWorkspaceSwitch() + + expect(hasUnsavedChanges()).toBe(true) + }) + + it('returns false when no workflows are modified', () => { + mockModifiedWorkflows.length = 0 + const { hasUnsavedChanges } = useWorkspaceSwitch() + + expect(hasUnsavedChanges()).toBe(false) + }) + }) + + describe('switchWithConfirmation', () => { + it('returns true immediately if switching to the same workspace', async () => { + const { switchWithConfirmation } = useWorkspaceSwitch() + + const result = await switchWithConfirmation('workspace-1') + + expect(result).toBe(true) + expect(mockSwitchWorkspace).not.toHaveBeenCalled() + expect(mockConfirm).not.toHaveBeenCalled() + }) + + it('switches directly without dialog when no unsaved changes', async () => { + mockModifiedWorkflows.length = 0 + mockSwitchWorkspace.mockResolvedValue(undefined) + const { switchWithConfirmation } = useWorkspaceSwitch() + + const result = await switchWithConfirmation('workspace-2') + + expect(result).toBe(true) + expect(mockConfirm).not.toHaveBeenCalled() + expect(mockSwitchWorkspace).toHaveBeenCalledWith('workspace-2') + expect(mockReload).toHaveBeenCalled() + }) + + it('shows confirmation dialog when there are unsaved changes', async () => { + mockModifiedWorkflows.push({ isModified: true }) + mockConfirm.mockResolvedValue(true) + mockSwitchWorkspace.mockResolvedValue(undefined) + const { switchWithConfirmation } = useWorkspaceSwitch() + + await switchWithConfirmation('workspace-2') + + expect(mockConfirm).toHaveBeenCalledWith({ + title: 'workspace.unsavedChanges.title', + message: 'workspace.unsavedChanges.message', + type: 'dirtyClose' + }) + }) + + it('returns false if user cancels the confirmation dialog', async () => { + mockModifiedWorkflows.push({ isModified: true }) + mockConfirm.mockResolvedValue(false) + const { switchWithConfirmation } = useWorkspaceSwitch() + + const result = await switchWithConfirmation('workspace-2') + + expect(result).toBe(false) + expect(mockSwitchWorkspace).not.toHaveBeenCalled() + expect(mockReload).not.toHaveBeenCalled() + }) + + it('calls switchWorkspace and reloads page after user confirms', async () => { + mockModifiedWorkflows.push({ isModified: true }) + mockConfirm.mockResolvedValue(true) + mockSwitchWorkspace.mockResolvedValue(undefined) + const { switchWithConfirmation } = useWorkspaceSwitch() + + const result = await switchWithConfirmation('workspace-2') + + expect(result).toBe(true) + expect(mockSwitchWorkspace).toHaveBeenCalledWith('workspace-2') + expect(mockReload).toHaveBeenCalled() + }) + + it('returns false if switchWorkspace throws an error', async () => { + mockModifiedWorkflows.length = 0 + mockSwitchWorkspace.mockRejectedValue(new Error('Switch failed')) + const { switchWithConfirmation } = useWorkspaceSwitch() + + const result = await switchWithConfirmation('workspace-2') + + expect(result).toBe(false) + expect(mockReload).not.toHaveBeenCalled() + }) + }) +}) diff --git a/src/platform/auth/workspace/useWorkspaceSwitch.ts b/src/platform/auth/workspace/useWorkspaceSwitch.ts new file mode 100644 index 000000000..6fb970d7f --- /dev/null +++ b/src/platform/auth/workspace/useWorkspaceSwitch.ts @@ -0,0 +1,49 @@ +import { storeToRefs } from 'pinia' +import { useI18n } from 'vue-i18n' + +import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore' +import { useDialogService } from '@/services/dialogService' +import { useWorkspaceAuthStore } from '@/stores/workspaceAuthStore' + +export function useWorkspaceSwitch() { + const { t } = useI18n() + const workspaceAuthStore = useWorkspaceAuthStore() + const { currentWorkspace } = storeToRefs(workspaceAuthStore) + const workflowStore = useWorkflowStore() + const dialogService = useDialogService() + + function hasUnsavedChanges(): boolean { + return workflowStore.modifiedWorkflows.length > 0 + } + + async function switchWithConfirmation(workspaceId: string): Promise { + if (currentWorkspace.value?.id === workspaceId) { + return true + } + + if (hasUnsavedChanges()) { + const confirmed = await dialogService.confirm({ + title: t('workspace.unsavedChanges.title'), + message: t('workspace.unsavedChanges.message'), + type: 'dirtyClose' + }) + + if (!confirmed) { + return false + } + } + + try { + await workspaceAuthStore.switchWorkspace(workspaceId) + window.location.reload() + return true + } catch { + return false + } + } + + return { + hasUnsavedChanges, + switchWithConfirmation + } +} diff --git a/src/platform/auth/workspace/workspaceConstants.ts b/src/platform/auth/workspace/workspaceConstants.ts new file mode 100644 index 000000000..cc28d1f47 --- /dev/null +++ b/src/platform/auth/workspace/workspaceConstants.ts @@ -0,0 +1,7 @@ +export const WORKSPACE_STORAGE_KEYS = { + CURRENT_WORKSPACE: 'Comfy.Workspace.Current', + TOKEN: 'Comfy.Workspace.Token', + EXPIRES_AT: 'Comfy.Workspace.ExpiresAt' +} as const + +export const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000 diff --git a/src/platform/auth/workspace/workspaceTypes.ts b/src/platform/auth/workspace/workspaceTypes.ts new file mode 100644 index 000000000..30774aef3 --- /dev/null +++ b/src/platform/auth/workspace/workspaceTypes.ts @@ -0,0 +1,6 @@ +export interface WorkspaceWithRole { + id: string + name: string + type: 'personal' | 'team' + role: 'owner' | 'member' +} diff --git a/src/platform/remoteConfig/types.ts b/src/platform/remoteConfig/types.ts index 7de4c2da2..7b8b1721c 100644 --- a/src/platform/remoteConfig/types.ts +++ b/src/platform/remoteConfig/types.ts @@ -42,4 +42,5 @@ export type RemoteConfig = { huggingface_model_import_enabled?: boolean linear_toggle_enabled?: boolean async_model_upload_enabled?: boolean + team_workspaces_enabled?: boolean } diff --git a/src/stores/firebaseAuthStore.ts b/src/stores/firebaseAuthStore.ts index 9f3039887..baa1840a8 100644 --- a/src/stores/firebaseAuthStore.ts +++ b/src/stores/firebaseAuthStore.ts @@ -23,7 +23,9 @@ import { useFirebaseAuth } from 'vuefire' import { getComfyApiBaseUrl } from '@/config/comfyApi' import { t } from '@/i18n' +import { WORKSPACE_STORAGE_KEYS } from '@/platform/auth/workspace/workspaceConstants' import { isCloud } from '@/platform/distribution/types' +import { remoteConfig } from '@/platform/remoteConfig/remoteConfig' import { useTelemetry } from '@/platform/telemetry' import { useDialogService } from '@/services/dialogService' import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore' @@ -107,6 +109,15 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => { isInitialized.value = true if (user === null) { lastTokenUserId.value = null + + // Clear workspace sessionStorage on logout to prevent stale tokens + try { + sessionStorage.removeItem(WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE) + sessionStorage.removeItem(WORKSPACE_STORAGE_KEYS.TOKEN) + sessionStorage.removeItem(WORKSPACE_STORAGE_KEYS.EXPIRES_AT) + } catch { + // Ignore sessionStorage errors (e.g., in private browsing mode) + } } // Reset balance when auth state changes @@ -152,16 +163,34 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => { /** * Retrieves the appropriate authentication header for API requests. * Checks for authentication in the following order: - * 1. Firebase authentication token (if user is logged in) - * 2. API key (if stored in the browser's credential manager) + * 1. Workspace token (if team_workspaces_enabled and user has active workspace context) + * 2. Firebase authentication token (if user is logged in) + * 3. API key (if stored in the browser's credential manager) * * @returns {Promise} - * - A LoggedInAuthHeader with Bearer token if Firebase authenticated + * - A LoggedInAuthHeader with Bearer token (workspace or Firebase) * - An ApiKeyAuthHeader with X-API-KEY if API key exists - * - null if neither authentication method is available + * - null if no authentication method is available */ const getAuthHeader = async (): Promise => { - // If available, set header with JWT used to identify the user to Firebase service + if (remoteConfig.value.team_workspaces_enabled) { + const workspaceToken = sessionStorage.getItem( + WORKSPACE_STORAGE_KEYS.TOKEN + ) + const expiresAt = sessionStorage.getItem( + WORKSPACE_STORAGE_KEYS.EXPIRES_AT + ) + + if (workspaceToken && expiresAt) { + const expiryTime = parseInt(expiresAt, 10) + if (Date.now() < expiryTime) { + return { + Authorization: `Bearer ${workspaceToken}` + } + } + } + } + const token = await getIdToken() if (token) { return { @@ -169,7 +198,6 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => { } } - // If not authenticated with Firebase, try falling back to API key if available return useApiKeyAuthStore().getAuthHeader() } diff --git a/src/stores/workspaceAuthStore.ts b/src/stores/workspaceAuthStore.ts new file mode 100644 index 000000000..33e57fdea --- /dev/null +++ b/src/stores/workspaceAuthStore.ts @@ -0,0 +1,373 @@ +import { defineStore } from 'pinia' +import { computed, ref, shallowRef } from 'vue' +import { z } from 'zod' +import { fromZodError } from 'zod-validation-error' + +import { t } from '@/i18n' +import { + TOKEN_REFRESH_BUFFER_MS, + WORKSPACE_STORAGE_KEYS +} from '@/platform/auth/workspace/workspaceConstants' +import { remoteConfig } from '@/platform/remoteConfig/remoteConfig' +import { api } from '@/scripts/api' +import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' +import type { AuthHeader } from '@/types/authTypes' +import type { WorkspaceWithRole } from '@/platform/auth/workspace/workspaceTypes' + +const WorkspaceWithRoleSchema = z.object({ + id: z.string(), + name: z.string(), + type: z.enum(['personal', 'team']), + role: z.enum(['owner', 'member']) +}) + +const WorkspaceTokenResponseSchema = z.object({ + token: z.string(), + expires_at: z.string(), + workspace: z.object({ + id: z.string(), + name: z.string(), + type: z.enum(['personal', 'team']) + }), + role: z.enum(['owner', 'member']), + permissions: z.array(z.string()) +}) + +export class WorkspaceAuthError extends Error { + constructor( + message: string, + public readonly code?: string + ) { + super(message) + this.name = 'WorkspaceAuthError' + } +} + +export const useWorkspaceAuthStore = defineStore('workspaceAuth', () => { + // State + const currentWorkspace = shallowRef(null) + const workspaceToken = ref(null) + const isLoading = ref(false) + const error = ref(null) + + // Timer state + let refreshTimerId: ReturnType | null = null + + // Request ID to prevent stale refresh operations from overwriting newer workspace contexts + let refreshRequestId = 0 + + // Getters + const isAuthenticated = computed( + () => currentWorkspace.value !== null && workspaceToken.value !== null + ) + + // Private helpers + function stopRefreshTimer(): void { + if (refreshTimerId !== null) { + clearTimeout(refreshTimerId) + refreshTimerId = null + } + } + + function scheduleTokenRefresh(expiresAt: number): void { + stopRefreshTimer() + const now = Date.now() + const refreshAt = expiresAt - TOKEN_REFRESH_BUFFER_MS + const delay = Math.max(0, refreshAt - now) + + refreshTimerId = setTimeout(() => { + void refreshToken() + }, delay) + } + + function persistToSession( + workspace: WorkspaceWithRole, + token: string, + expiresAt: number + ): void { + try { + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE, + JSON.stringify(workspace) + ) + sessionStorage.setItem(WORKSPACE_STORAGE_KEYS.TOKEN, token) + sessionStorage.setItem( + WORKSPACE_STORAGE_KEYS.EXPIRES_AT, + expiresAt.toString() + ) + } catch { + console.warn('Failed to persist workspace context to sessionStorage') + } + } + + function clearSessionStorage(): void { + try { + sessionStorage.removeItem(WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE) + sessionStorage.removeItem(WORKSPACE_STORAGE_KEYS.TOKEN) + sessionStorage.removeItem(WORKSPACE_STORAGE_KEYS.EXPIRES_AT) + } catch { + console.warn('Failed to clear workspace context from sessionStorage') + } + } + + // Actions + function init(): void { + initializeFromSession() + } + + function destroy(): void { + stopRefreshTimer() + } + + function initializeFromSession(): boolean { + if (!remoteConfig.value.team_workspaces_enabled) { + return false + } + + try { + const workspaceJson = sessionStorage.getItem( + WORKSPACE_STORAGE_KEYS.CURRENT_WORKSPACE + ) + const token = sessionStorage.getItem(WORKSPACE_STORAGE_KEYS.TOKEN) + const expiresAtStr = sessionStorage.getItem( + WORKSPACE_STORAGE_KEYS.EXPIRES_AT + ) + + if (!workspaceJson || !token || !expiresAtStr) { + return false + } + + const expiresAt = parseInt(expiresAtStr, 10) + if (isNaN(expiresAt) || expiresAt <= Date.now()) { + clearSessionStorage() + return false + } + + const parsedWorkspace = JSON.parse(workspaceJson) + const parseResult = WorkspaceWithRoleSchema.safeParse(parsedWorkspace) + + if (!parseResult.success) { + clearSessionStorage() + return false + } + + currentWorkspace.value = parseResult.data + workspaceToken.value = token + error.value = null + + scheduleTokenRefresh(expiresAt) + return true + } catch { + clearSessionStorage() + return false + } + } + + async function switchWorkspace(workspaceId: string): Promise { + if (!remoteConfig.value.team_workspaces_enabled) { + return + } + + // Only increment request ID when switching to a different workspace + // This invalidates stale refresh operations for the old workspace + // but allows refresh operations for the same workspace to complete + if (currentWorkspace.value?.id !== workspaceId) { + refreshRequestId++ + } + + isLoading.value = true + error.value = null + + try { + const firebaseAuthStore = useFirebaseAuthStore() + const firebaseToken = await firebaseAuthStore.getIdToken() + if (!firebaseToken) { + throw new WorkspaceAuthError( + t('workspaceAuth.errors.notAuthenticated'), + 'NOT_AUTHENTICATED' + ) + } + + const response = await fetch(api.apiURL('/auth/token'), { + method: 'POST', + headers: { + Authorization: `Bearer ${firebaseToken}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ workspace_id: workspaceId }) + }) + + if (!response.ok) { + const errorData = await response.json().catch(() => ({})) + const message = errorData.message || response.statusText + + if (response.status === 401) { + throw new WorkspaceAuthError( + t('workspaceAuth.errors.invalidFirebaseToken'), + 'INVALID_FIREBASE_TOKEN' + ) + } + if (response.status === 403) { + throw new WorkspaceAuthError( + t('workspaceAuth.errors.accessDenied'), + 'ACCESS_DENIED' + ) + } + if (response.status === 404) { + throw new WorkspaceAuthError( + t('workspaceAuth.errors.workspaceNotFound'), + 'WORKSPACE_NOT_FOUND' + ) + } + + throw new WorkspaceAuthError( + t('workspaceAuth.errors.tokenExchangeFailed', { error: message }), + 'TOKEN_EXCHANGE_FAILED' + ) + } + + const rawData = await response.json() + const parseResult = WorkspaceTokenResponseSchema.safeParse(rawData) + + if (!parseResult.success) { + throw new WorkspaceAuthError( + t('workspaceAuth.errors.tokenExchangeFailed', { + error: fromZodError(parseResult.error).message + }), + 'TOKEN_EXCHANGE_FAILED' + ) + } + + const data = parseResult.data + const expiresAt = new Date(data.expires_at).getTime() + + if (isNaN(expiresAt)) { + throw new WorkspaceAuthError( + t('workspaceAuth.errors.tokenExchangeFailed', { + error: 'Invalid expiry timestamp' + }), + 'TOKEN_EXCHANGE_FAILED' + ) + } + + const workspaceWithRole: WorkspaceWithRole = { + ...data.workspace, + role: data.role + } + + currentWorkspace.value = workspaceWithRole + workspaceToken.value = data.token + + persistToSession(workspaceWithRole, data.token, expiresAt) + scheduleTokenRefresh(expiresAt) + } catch (err) { + error.value = err instanceof Error ? err : new Error(String(err)) + throw error.value + } finally { + isLoading.value = false + } + } + + async function refreshToken(): Promise { + if (!currentWorkspace.value) { + return + } + + const workspaceId = currentWorkspace.value.id + // Capture the current request ID to detect if workspace context changed during refresh + const capturedRequestId = refreshRequestId + const maxRetries = 3 + const baseDelayMs = 1000 + + for (let attempt = 0; attempt <= maxRetries; attempt++) { + // Check if workspace context changed since refresh started (user switched workspaces) + if (capturedRequestId !== refreshRequestId) { + console.warn( + 'Aborting stale token refresh: workspace context changed during refresh' + ) + return + } + + try { + await switchWorkspace(workspaceId) + return + } catch (err) { + const isAuthError = err instanceof WorkspaceAuthError + + const isPermanentError = + isAuthError && + (err.code === 'ACCESS_DENIED' || + err.code === 'WORKSPACE_NOT_FOUND' || + err.code === 'INVALID_FIREBASE_TOKEN' || + err.code === 'NOT_AUTHENTICATED') + + if (isPermanentError) { + // Only clear context if this refresh is still for the current workspace + if (capturedRequestId === refreshRequestId) { + console.error('Workspace access revoked or auth invalid:', err) + clearWorkspaceContext() + } + return + } + + const isTransientError = + isAuthError && err.code === 'TOKEN_EXCHANGE_FAILED' + + if (isTransientError && attempt < maxRetries) { + const delay = baseDelayMs * Math.pow(2, attempt) + console.warn( + `Token refresh failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${delay}ms:`, + err + ) + await new Promise((resolve) => setTimeout(resolve, delay)) + continue + } + + // Only clear context if this refresh is still for the current workspace + if (capturedRequestId === refreshRequestId) { + console.error('Failed to refresh workspace token after retries:', err) + clearWorkspaceContext() + } + } + } + } + + function getWorkspaceAuthHeader(): AuthHeader | null { + if (!workspaceToken.value) { + return null + } + return { + Authorization: `Bearer ${workspaceToken.value}` + } + } + + function clearWorkspaceContext(): void { + // Increment request ID to invalidate any in-flight stale refresh operations + refreshRequestId++ + stopRefreshTimer() + currentWorkspace.value = null + workspaceToken.value = null + error.value = null + clearSessionStorage() + } + + return { + // State + currentWorkspace, + workspaceToken, + isLoading, + error, + + // Getters + isAuthenticated, + + // Actions + init, + destroy, + initializeFromSession, + switchWorkspace, + refreshToken, + getWorkspaceAuthHeader, + clearWorkspaceContext + } +}) From 089295606aa9f92a43e48d14b64e32e3c3d1bc8b Mon Sep 17 00:00:00 2001 From: Comfy Org PR Bot Date: Fri, 16 Jan 2026 11:14:27 +0900 Subject: [PATCH 02/11] 1.38.3 (#8085) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch version increment to 1.38.3 **Base branch:** `main` ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8085-1-38-3-2ea6d73d365081779d52dea9c48371a7) by [Unito](https://www.unito.io) --------- Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com> Co-authored-by: github-actions Co-authored-by: Alexander Brown --- package.json | 2 +- src/locales/ar/main.json | 16 ++++++++++++++++ src/locales/es/main.json | 16 ++++++++++++++++ src/locales/fa/main.json | 16 ++++++++++++++++ src/locales/fr/main.json | 16 ++++++++++++++++ src/locales/ja/main.json | 16 ++++++++++++++++ src/locales/ko/main.json | 16 ++++++++++++++++ src/locales/pt-BR/main.json | 16 ++++++++++++++++ src/locales/ru/main.json | 16 ++++++++++++++++ src/locales/tr/main.json | 16 ++++++++++++++++ src/locales/zh-TW/main.json | 16 ++++++++++++++++ src/locales/zh/main.json | 16 ++++++++++++++++ 12 files changed, 177 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a2105ad9a..a4db1d77d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@comfyorg/comfyui-frontend", "private": true, - "version": "1.38.2", + "version": "1.38.3", "type": "module", "repository": "https://github.com/Comfy-Org/ComfyUI_frontend", "homepage": "https://comfy.org", diff --git a/src/locales/ar/main.json b/src/locales/ar/main.json index 31f41da4c..e3d369349 100644 --- a/src/locales/ar/main.json +++ b/src/locales/ar/main.json @@ -848,6 +848,7 @@ "releaseTitle": "إصدار {package} {version}", "reloadToApplyChanges": "أعد التحميل لتطبيق التغييرات", "removeImage": "إزالة الصورة", + "removeTag": "إزالة الوسم", "removeVideo": "إزالة الفيديو", "rename": "إعادة تسمية", "reportIssue": "إرسال تقرير", @@ -2575,6 +2576,21 @@ "exportWorkflow": "تصدير سير العمل", "saveWorkflow": "حفظ سير العمل" }, + "workspace": { + "unsavedChanges": { + "message": "لديك تغييرات غير محفوظة. هل تريد تجاهلها والانتقال إلى مساحة عمل أخرى؟", + "title": "تغييرات غير محفوظة" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "ليس لديك صلاحية الوصول إلى هذه مساحة العمل", + "invalidFirebaseToken": "فشل التحقق من الهوية. يرجى محاولة تسجيل الدخول مرة أخرى.", + "notAuthenticated": "يجب تسجيل الدخول للوصول إلى مساحات العمل", + "tokenExchangeFailed": "فشل التحقق من مساحة العمل: {error}", + "workspaceNotFound": "لم يتم العثور على مساحة العمل" + } + }, "zoomControls": { "hideMinimap": "إخفاء الخريطة المصغرة", "label": "عناصر التحكم في التكبير", diff --git a/src/locales/es/main.json b/src/locales/es/main.json index 311d8c349..cd59b5bf8 100644 --- a/src/locales/es/main.json +++ b/src/locales/es/main.json @@ -848,6 +848,7 @@ "releaseTitle": "Lanzamiento de {package} {version}", "reloadToApplyChanges": "Recargar para aplicar cambios", "removeImage": "Eliminar imagen", + "removeTag": "Eliminar etiqueta", "removeVideo": "Eliminar video", "rename": "Renombrar", "reportIssue": "Enviar informe", @@ -2575,6 +2576,21 @@ "exportWorkflow": "Exportar flujo de trabajo", "saveWorkflow": "Guardar flujo de trabajo" }, + "workspace": { + "unsavedChanges": { + "message": "Tienes cambios no guardados. ¿Quieres descartarlos y cambiar de espacio de trabajo?", + "title": "Cambios no guardados" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "No tienes acceso a este espacio de trabajo", + "invalidFirebaseToken": "La autenticación ha fallado. Por favor, intenta iniciar sesión de nuevo.", + "notAuthenticated": "Debes iniciar sesión para acceder a los espacios de trabajo", + "tokenExchangeFailed": "No se pudo autenticar con el espacio de trabajo: {error}", + "workspaceNotFound": "Espacio de trabajo no encontrado" + } + }, "zoomControls": { "hideMinimap": "Ocultar minimapa", "label": "Controles de zoom", diff --git a/src/locales/fa/main.json b/src/locales/fa/main.json index 1f8ead99e..d4c673259 100644 --- a/src/locales/fa/main.json +++ b/src/locales/fa/main.json @@ -848,6 +848,7 @@ "releaseTitle": "انتشار {package} نسخه {version}", "reloadToApplyChanges": "برای اعمال تغییرات بارگذاری مجدد کنید", "removeImage": "حذف تصویر", + "removeTag": "حذف برچسب", "removeVideo": "حذف ویدیو", "rename": "تغییر نام", "reportIssue": "ارسال گزارش", @@ -2586,6 +2587,21 @@ "exportWorkflow": "خروجی گرفتن از workflow", "saveWorkflow": "ذخیره workflow" }, + "workspace": { + "unsavedChanges": { + "message": "شما تغییرات ذخیره‌نشده دارید. آیا می‌خواهید آن‌ها را رها کرده و فضای کاری را تغییر دهید؟", + "title": "تغییرات ذخیره‌نشده" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "شما به این فضای کاری دسترسی ندارید.", + "invalidFirebaseToken": "احراز هویت ناموفق بود. لطفاً دوباره وارد شوید.", + "notAuthenticated": "برای دسترسی به فضاهای کاری باید وارد شوید.", + "tokenExchangeFailed": "احراز هویت با فضای کاری ناموفق بود: {error}", + "workspaceNotFound": "فضای کاری پیدا نشد." + } + }, "zoomControls": { "hideMinimap": "مخفی‌سازی نقشه کوچک", "label": "کنترل‌های بزرگ‌نمایی", diff --git a/src/locales/fr/main.json b/src/locales/fr/main.json index 7f504cd59..014f2ea0e 100644 --- a/src/locales/fr/main.json +++ b/src/locales/fr/main.json @@ -848,6 +848,7 @@ "releaseTitle": "Publication de {package} {version}", "reloadToApplyChanges": "Recharger pour appliquer les modifications", "removeImage": "Supprimer l'image", + "removeTag": "Supprimer le tag", "removeVideo": "Supprimer la vidéo", "rename": "Renommer", "reportIssue": "Envoyer le rapport", @@ -2575,6 +2576,21 @@ "exportWorkflow": "Exporter le flux de travail", "saveWorkflow": "Enregistrer le flux de travail" }, + "workspace": { + "unsavedChanges": { + "message": "Vous avez des modifications non enregistrées. Voulez-vous les abandonner et changer d’espace de travail ?", + "title": "Modifications non enregistrées" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "Vous n’avez pas accès à cet espace de travail", + "invalidFirebaseToken": "Échec de l’authentification. Veuillez vous reconnecter.", + "notAuthenticated": "Vous devez être connecté pour accéder aux espaces de travail", + "tokenExchangeFailed": "Échec de l’authentification avec l’espace de travail : {error}", + "workspaceNotFound": "Espace de travail introuvable" + } + }, "zoomControls": { "hideMinimap": "Masquer la mini-carte", "label": "Contrôles de zoom", diff --git a/src/locales/ja/main.json b/src/locales/ja/main.json index 961d07085..7791475f5 100644 --- a/src/locales/ja/main.json +++ b/src/locales/ja/main.json @@ -848,6 +848,7 @@ "releaseTitle": "{package} {version} リリース", "reloadToApplyChanges": "変更を適用するには再読み込みしてください", "removeImage": "画像を削除", + "removeTag": "タグを削除", "removeVideo": "ビデオを削除", "rename": "名前を変更", "reportIssue": "報告する", @@ -2575,6 +2576,21 @@ "exportWorkflow": "ワークフローをエクスポート", "saveWorkflow": "ワークフローを保存" }, + "workspace": { + "unsavedChanges": { + "message": "未保存の変更があります。破棄してワークスペースを切り替えますか?", + "title": "未保存の変更" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "このワークスペースへのアクセス権がありません", + "invalidFirebaseToken": "認証に失敗しました。もう一度ログインしてください。", + "notAuthenticated": "ワークスペースにアクセスするにはログインが必要です", + "tokenExchangeFailed": "ワークスペースの認証に失敗しました: {error}", + "workspaceNotFound": "ワークスペースが見つかりません" + } + }, "zoomControls": { "hideMinimap": "ミニマップを非表示", "label": "ズームコントロール", diff --git a/src/locales/ko/main.json b/src/locales/ko/main.json index bc65475fd..60b2f9711 100644 --- a/src/locales/ko/main.json +++ b/src/locales/ko/main.json @@ -848,6 +848,7 @@ "releaseTitle": "{package} {version} 릴리스", "reloadToApplyChanges": "변경 사항을 적용하려면 새로 고침하세요.", "removeImage": "이미지 제거", + "removeTag": "태그 제거", "removeVideo": "비디오 제거", "rename": "이름 바꾸기", "reportIssue": "보고서 보내기", @@ -2575,6 +2576,21 @@ "exportWorkflow": "워크플로 내보내기", "saveWorkflow": "워크플로 저장" }, + "workspace": { + "unsavedChanges": { + "message": "저장되지 않은 변경 사항이 있습니다. 변경 사항을 취소하고 워크스페이스를 전환하시겠습니까?", + "title": "저장되지 않은 변경 사항" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "이 워크스페이스에 접근할 수 없습니다.", + "invalidFirebaseToken": "인증에 실패했습니다. 다시 로그인해 주세요.", + "notAuthenticated": "워크스페이스에 접근하려면 로그인해야 합니다.", + "tokenExchangeFailed": "워크스페이스 인증에 실패했습니다: {error}", + "workspaceNotFound": "워크스페이스를 찾을 수 없습니다." + } + }, "zoomControls": { "hideMinimap": "미니맵 숨기기", "label": "줌 컨트롤", diff --git a/src/locales/pt-BR/main.json b/src/locales/pt-BR/main.json index 868420df3..160f525f5 100644 --- a/src/locales/pt-BR/main.json +++ b/src/locales/pt-BR/main.json @@ -848,6 +848,7 @@ "releaseTitle": "Lançamento {package} {version}", "reloadToApplyChanges": "Recarregue para aplicar as alterações", "removeImage": "Remover imagem", + "removeTag": "Remover tag", "removeVideo": "Remover vídeo", "rename": "Renomear", "reportIssue": "Enviar relatório", @@ -2586,6 +2587,21 @@ "exportWorkflow": "Exportar Fluxo de Trabalho", "saveWorkflow": "Salvar fluxo de trabalho" }, + "workspace": { + "unsavedChanges": { + "message": "Você tem alterações não salvas. Deseja descartá-las e trocar de espaço de trabalho?", + "title": "Alterações não salvas" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "Você não tem acesso a este espaço de trabalho", + "invalidFirebaseToken": "Falha na autenticação. Por favor, tente fazer login novamente.", + "notAuthenticated": "Você precisa estar logado para acessar os espaços de trabalho", + "tokenExchangeFailed": "Falha ao autenticar com o espaço de trabalho: {error}", + "workspaceNotFound": "Espaço de trabalho não encontrado" + } + }, "zoomControls": { "hideMinimap": "Ocultar Minimapa", "label": "Controles de Zoom", diff --git a/src/locales/ru/main.json b/src/locales/ru/main.json index 7c00dda65..60155d334 100644 --- a/src/locales/ru/main.json +++ b/src/locales/ru/main.json @@ -848,6 +848,7 @@ "releaseTitle": "Релиз {package} {version}", "reloadToApplyChanges": "Перезагрузите, чтобы применить изменения", "removeImage": "Удалить изображение", + "removeTag": "Удалить тег", "removeVideo": "Удалить видео", "rename": "Переименовать", "reportIssue": "Отправить отчёт", @@ -2575,6 +2576,21 @@ "exportWorkflow": "Экспорт рабочего процесса", "saveWorkflow": "Сохранить рабочий процесс" }, + "workspace": { + "unsavedChanges": { + "message": "У вас есть несохранённые изменения. Хотите их отменить и переключиться на другое рабочее пространство?", + "title": "Несохранённые изменения" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "У вас нет доступа к этому рабочему пространству", + "invalidFirebaseToken": "Ошибка аутентификации. Пожалуйста, попробуйте войти снова.", + "notAuthenticated": "Вы должны войти в систему, чтобы получить доступ к рабочим пространствам", + "tokenExchangeFailed": "Не удалось выполнить аутентификацию с рабочим пространством: {error}", + "workspaceNotFound": "Рабочее пространство не найдено" + } + }, "zoomControls": { "hideMinimap": "Скрыть миникарту", "label": "Управление масштабом", diff --git a/src/locales/tr/main.json b/src/locales/tr/main.json index 8b3019adc..870cee220 100644 --- a/src/locales/tr/main.json +++ b/src/locales/tr/main.json @@ -848,6 +848,7 @@ "releaseTitle": "{package} {version} Sürümü", "reloadToApplyChanges": "Değişiklikleri uygulamak için yeniden yükleyin", "removeImage": "Görüntüyü kaldır", + "removeTag": "Etiketi kaldır", "removeVideo": "Videoyu kaldır", "rename": "Yeniden Adlandır", "reportIssue": "Rapor Gönder", @@ -2575,6 +2576,21 @@ "exportWorkflow": "İş Akışını Dışa Aktar", "saveWorkflow": "İş akışını kaydet" }, + "workspace": { + "unsavedChanges": { + "message": "Kaydedilmemiş değişiklikleriniz var. Bunları iptal edip çalışma alanlarını değiştirmek istiyor musunuz?", + "title": "Kaydedilmemiş Değişiklikler" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "Bu çalışma alanına erişiminiz yok", + "invalidFirebaseToken": "Kimlik doğrulama başarısız oldu. Lütfen tekrar giriş yapmayı deneyin.", + "notAuthenticated": "Çalışma alanlarına erişmek için giriş yapmalısınız", + "tokenExchangeFailed": "Çalışma alanı ile kimlik doğrulama başarısız oldu: {error}", + "workspaceNotFound": "Çalışma alanı bulunamadı" + } + }, "zoomControls": { "hideMinimap": "Mini Haritayı Gizle", "label": "Yakınlaştırma Kontrolleri", diff --git a/src/locales/zh-TW/main.json b/src/locales/zh-TW/main.json index c84d96a7f..0a148681a 100644 --- a/src/locales/zh-TW/main.json +++ b/src/locales/zh-TW/main.json @@ -848,6 +848,7 @@ "releaseTitle": "{package} {version} 版本發佈", "reloadToApplyChanges": "重新載入以套用變更", "removeImage": "移除圖片", + "removeTag": "移除標籤", "removeVideo": "移除影片", "rename": "重新命名", "reportIssue": "送出回報", @@ -2575,6 +2576,21 @@ "exportWorkflow": "匯出工作流程", "saveWorkflow": "儲存工作流程" }, + "workspace": { + "unsavedChanges": { + "message": "您有未儲存的變更。是否要捨棄這些變更並切換工作區?", + "title": "未儲存的變更" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "您沒有存取此工作區的權限", + "invalidFirebaseToken": "驗證失敗。請重新登入。", + "notAuthenticated": "您必須登入才能存取工作區", + "tokenExchangeFailed": "與工作區驗證失敗:{error}", + "workspaceNotFound": "找不到工作區" + } + }, "zoomControls": { "hideMinimap": "隱藏小地圖", "label": "縮放控制", diff --git a/src/locales/zh/main.json b/src/locales/zh/main.json index 689a2e1ff..1108b1702 100644 --- a/src/locales/zh/main.json +++ b/src/locales/zh/main.json @@ -848,6 +848,7 @@ "releaseTitle": "{package} {version} 发布", "reloadToApplyChanges": "重新加载以应用更改", "removeImage": "移除图片", + "removeTag": "移除标签", "removeVideo": "移除视频", "rename": "重命名", "reportIssue": "发送报告", @@ -2586,6 +2587,21 @@ "exportWorkflow": "导出工作流", "saveWorkflow": "保存工作流" }, + "workspace": { + "unsavedChanges": { + "message": "您有未保存的更改。是否要放弃这些更改并切换工作区?", + "title": "未保存的更改" + } + }, + "workspaceAuth": { + "errors": { + "accessDenied": "您无权访问此工作区", + "invalidFirebaseToken": "身份验证失败。请重新登录。", + "notAuthenticated": "您必须登录才能访问工作区", + "tokenExchangeFailed": "与工作区认证失败:{error}", + "workspaceNotFound": "未找到工作区" + } + }, "zoomControls": { "hideMinimap": "隐藏小地图", "label": "缩放控制", From c0a649ef439c20d6807fdb6355a543f3213a78f3 Mon Sep 17 00:00:00 2001 From: ric-yu Date: Thu, 15 Jan 2026 20:11:22 -0800 Subject: [PATCH 03/11] refactor: encapsulate error extraction in TaskItemImpl getters (#7650) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Add `errorMessage` and `executionError` getters to `TaskItemImpl` that extract error info from status messages - Update `useJobErrorReporting` composable to use these getters instead of standalone function - Remove the standalone `extractExecutionError` function This encapsulates error extraction within `TaskItemImpl`, preparing for the Jobs API migration where the underlying data format will change but the getter interface will remain stable. ## Test plan - [x] All existing tests pass - [x] New tests added for `TaskItemImpl.errorMessage` and `TaskItemImpl.executionError` getters - [x] TypeScript, lint, and knip checks pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7650-refactor-encapsulate-error-extraction-in-TaskItemImpl-getters-2ce6d73d365081caae33dcc7e1e07720) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Co-authored-by: Christian Byrne --- browser_tests/fixtures/ComfyPage.ts | 8 - src/components/queue/QueueProgressOverlay.vue | 2 +- .../queue/job/JobDetailsPopover.stories.ts | 132 ++--- src/components/queue/job/JobGroupsList.vue | 2 +- .../queue/job/useJobErrorReporting.test.ts | 223 +++---- .../queue/job/useJobErrorReporting.ts | 41 +- .../sidebar/tabs/AssetsSidebarTab.vue | 114 ++-- src/composables/queue/useJobList.test.ts | 10 +- src/composables/queue/useJobList.ts | 2 +- src/composables/queue/useJobMenu.test.ts | 103 +++- src/composables/queue/useJobMenu.ts | 114 ++-- .../queue/useResultGallery.test.ts | 134 +++-- src/composables/queue/useResultGallery.ts | 49 +- .../assets/composables/media/assetMappers.ts | 1 - .../history/__fixtures__/historyFixtures.ts | 380 ------------ .../history/adapters/v2ToV1Adapter.test.ts | 434 -------------- .../comfyui/history/adapters/v2ToV1Adapter.ts | 74 --- .../history/fetchers/fetchHistoryV1.test.ts | 52 -- .../history/fetchers/fetchHistoryV1.ts | 51 -- .../history/fetchers/fetchHistoryV2.test.ts | 41 -- .../history/fetchers/fetchHistoryV2.ts | 42 -- src/platform/remote/comfyui/history/index.ts | 29 - .../comfyui/history/reconciliation.test.ts | 335 ----------- .../remote/comfyui/history/reconciliation.ts | 122 ---- .../comfyui/history/types/historyV1Types.ts | 15 - .../comfyui/history/types/historyV2Types.ts | 46 -- .../remote/comfyui/history/types/index.ts | 9 - .../remote/comfyui/jobs/fetchJobs.test.ts | 10 +- src/platform/remote/comfyui/jobs/fetchJobs.ts | 4 +- src/platform/remote/comfyui/jobs/jobTypes.ts | 17 +- .../cloud/getWorkflowFromHistory.test.ts | 124 ++-- .../workflow/cloud/getWorkflowFromHistory.ts | 21 - src/platform/workflow/cloud/index.ts | 10 - .../workflow/utils/workflowExtractionUtil.ts | 22 +- src/schemas/apiSchema.ts | 135 +---- src/scripts/api.ts | 118 ++-- src/scripts/ui.ts | 34 +- src/services/dialogService.ts | 15 +- src/services/jobOutputCache.test.ts | 278 +++++++++ src/services/jobOutputCache.ts | 103 ++++ src/stores/assetsStore.test.ts | 225 +++----- src/stores/assetsStore.ts | 34 +- src/stores/executionStore.ts | 6 +- src/stores/queueStore.loadWorkflow.test.ts | 159 ++--- src/stores/queueStore.test.ts | 545 +++++++++--------- src/stores/queueStore.ts | 292 +++++----- 46 files changed, 1650 insertions(+), 3067 deletions(-) delete mode 100644 src/platform/remote/comfyui/history/__fixtures__/historyFixtures.ts delete mode 100644 src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.test.ts delete mode 100644 src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.ts delete mode 100644 src/platform/remote/comfyui/history/fetchers/fetchHistoryV1.test.ts delete mode 100644 src/platform/remote/comfyui/history/fetchers/fetchHistoryV1.ts delete mode 100644 src/platform/remote/comfyui/history/fetchers/fetchHistoryV2.test.ts delete mode 100644 src/platform/remote/comfyui/history/fetchers/fetchHistoryV2.ts delete mode 100644 src/platform/remote/comfyui/history/index.ts delete mode 100644 src/platform/remote/comfyui/history/reconciliation.test.ts delete mode 100644 src/platform/remote/comfyui/history/reconciliation.ts delete mode 100644 src/platform/remote/comfyui/history/types/historyV1Types.ts delete mode 100644 src/platform/remote/comfyui/history/types/historyV2Types.ts delete mode 100644 src/platform/remote/comfyui/history/types/index.ts delete mode 100644 src/platform/workflow/cloud/getWorkflowFromHistory.ts delete mode 100644 src/platform/workflow/cloud/index.ts create mode 100644 src/services/jobOutputCache.test.ts create mode 100644 src/services/jobOutputCache.ts diff --git a/browser_tests/fixtures/ComfyPage.ts b/browser_tests/fixtures/ComfyPage.ts index 2f51533ce..fe439af20 100644 --- a/browser_tests/fixtures/ComfyPage.ts +++ b/browser_tests/fixtures/ComfyPage.ts @@ -21,7 +21,6 @@ import { import { Topbar } from './components/Topbar' import type { Position, Size } from './types' import { NodeReference, SubgraphSlotReference } from './utils/litegraphUtils' -import TaskHistory from './utils/taskHistory' dotenv.config() @@ -146,8 +145,6 @@ class ConfirmDialog { } export class ComfyPage { - private _history: TaskHistory | null = null - public readonly url: string // All canvas position operations are based on default view of canvas. public readonly canvas: Locator @@ -301,11 +298,6 @@ export class ComfyPage { } } - setupHistory(): TaskHistory { - this._history ??= new TaskHistory(this) - return this._history - } - async setup({ clearStorage = true, mockReleases = true diff --git a/src/components/queue/QueueProgressOverlay.vue b/src/components/queue/QueueProgressOverlay.vue index 78efb7a78..d6b3edcd8 100644 --- a/src/components/queue/QueueProgressOverlay.vue +++ b/src/components/queue/QueueProgressOverlay.vue @@ -262,7 +262,7 @@ const focusAssetInSidebar = async (item: JobListItem) => { const inspectJobAsset = wrapWithErrorHandlingAsync( async (item: JobListItem) => { - openResultGallery(item) + await openResultGallery(item) await focusAssetInSidebar(item) } ) diff --git a/src/components/queue/job/JobDetailsPopover.stories.ts b/src/components/queue/job/JobDetailsPopover.stories.ts index 2343a8fa2..9b79c99e5 100644 --- a/src/components/queue/job/JobDetailsPopover.stories.ts +++ b/src/components/queue/job/JobDetailsPopover.stories.ts @@ -1,6 +1,9 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite' -import type { TaskStatus } from '@/schemas/apiSchema' +import type { + JobListItem, + JobStatus +} from '@/platform/remote/comfyui/jobs/jobTypes' import { useExecutionStore } from '@/stores/executionStore' import { TaskItemImpl, useQueueStore } from '@/stores/queueStore' @@ -37,91 +40,86 @@ function resetStores() { exec.nodeProgressStatesByPrompt = {} } +function makeTask( + id: string, + priority: number, + fields: Partial & { status: JobStatus; create_time: number } +): TaskItemImpl { + const job: JobListItem = { + id, + priority, + last_state_update: null, + update_time: fields.create_time, + ...fields + } + return new TaskItemImpl(job) +} + function makePendingTask( id: string, - index: number, - createTimeMs?: number + priority: number, + createTimeMs: number ): TaskItemImpl { - const extraData = { - client_id: 'c1', - ...(typeof createTimeMs === 'number' ? { create_time: createTimeMs } : {}) - } - return new TaskItemImpl('Pending', [index, id, {}, extraData, []]) + return makeTask(id, priority, { + status: 'pending', + create_time: createTimeMs + }) } function makeRunningTask( id: string, - index: number, - createTimeMs?: number + priority: number, + createTimeMs: number ): TaskItemImpl { - const extraData = { - client_id: 'c1', - ...(typeof createTimeMs === 'number' ? { create_time: createTimeMs } : {}) - } - return new TaskItemImpl('Running', [index, id, {}, extraData, []]) + return makeTask(id, priority, { + status: 'in_progress', + create_time: createTimeMs + }) } function makeRunningTaskWithStart( id: string, - index: number, + priority: number, startedSecondsAgo: number ): TaskItemImpl { const start = Date.now() - startedSecondsAgo * 1000 - const status: TaskStatus = { - status_str: 'success', - completed: false, - messages: [['execution_start', { prompt_id: id, timestamp: start } as any]] - } - return new TaskItemImpl( - 'Running', - [index, id, {}, { client_id: 'c1', create_time: start - 5000 }, []], - status - ) + return makeTask(id, priority, { + status: 'in_progress', + create_time: start - 5000, + update_time: start + }) } function makeHistoryTask( id: string, - index: number, + priority: number, durationSec: number, ok: boolean, errorMessage?: string ): TaskItemImpl { - const start = Date.now() - durationSec * 1000 - 1000 - const end = start + durationSec * 1000 - const messages: TaskStatus['messages'] = ok - ? [ - ['execution_start', { prompt_id: id, timestamp: start } as any], - ['execution_success', { prompt_id: id, timestamp: end } as any] - ] - : [ - ['execution_start', { prompt_id: id, timestamp: start } as any], - [ - 'execution_error', - { - prompt_id: id, - timestamp: end, - node_id: '1', - node_type: 'Node', - executed: [], - exception_message: - errorMessage || 'Demo error: Node failed during execution', - exception_type: 'RuntimeError', - traceback: [], - current_inputs: {}, - current_outputs: {} - } as any - ] - ] - const status: TaskStatus = { - status_str: ok ? 'success' : 'error', - completed: true, - messages - } - return new TaskItemImpl( - 'History', - [index, id, {}, { client_id: 'c1', create_time: start }, []], - status - ) + const now = Date.now() + const executionEndTime = now + const executionStartTime = now - durationSec * 1000 + return makeTask(id, priority, { + status: ok ? 'completed' : 'failed', + create_time: executionStartTime - 5000, + update_time: now, + execution_start_time: executionStartTime, + execution_end_time: executionEndTime, + execution_error: errorMessage + ? { + prompt_id: id, + timestamp: now, + node_id: '1', + node_type: 'ExampleNode', + exception_message: errorMessage, + exception_type: 'RuntimeError', + traceback: [], + current_inputs: {}, + current_outputs: {} + } + : undefined + }) } export const Queued: Story = { @@ -140,8 +138,12 @@ export const Queued: Story = { makePendingTask(jobId, queueIndex, Date.now() - 90_000) ] // Add some other pending jobs to give context - queue.pendingTasks.push(makePendingTask('job-older-1', 100)) - queue.pendingTasks.push(makePendingTask('job-older-2', 101)) + queue.pendingTasks.push( + makePendingTask('job-older-1', 100, Date.now() - 60_000) + ) + queue.pendingTasks.push( + makePendingTask('job-older-2', 101, Date.now() - 30_000) + ) // Queued at (in metadata on prompt[4]) diff --git a/src/components/queue/job/JobGroupsList.vue b/src/components/queue/job/JobGroupsList.vue index 482016d34..3a7c6d6af 100644 --- a/src/components/queue/job/JobGroupsList.vue +++ b/src/components/queue/job/JobGroupsList.vue @@ -12,7 +12,7 @@ v-for="ji in group.items" :key="ji.id" :job-id="ji.id" - :workflow-id="ji.taskRef?.workflow?.id" + :workflow-id="ji.taskRef?.workflowId" :state="ji.state" :title="ji.title" :right-text="ji.meta" diff --git a/src/components/queue/job/useJobErrorReporting.test.ts b/src/components/queue/job/useJobErrorReporting.test.ts index abd444dbe..1d1fc6ef0 100644 --- a/src/components/queue/job/useJobErrorReporting.test.ts +++ b/src/components/queue/job/useJobErrorReporting.test.ts @@ -2,116 +2,49 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { computed, ref } from 'vue' import type { ComputedRef } from 'vue' -import type { ExecutionErrorWsMessage } from '@/schemas/apiSchema' import type { TaskItemImpl } from '@/stores/queueStore' -import type { - JobErrorDialogService, - UseJobErrorReportingOptions -} from '@/components/queue/job/useJobErrorReporting' -import * as jobErrorReporting from '@/components/queue/job/useJobErrorReporting' +import type { JobErrorDialogService } from '@/components/queue/job/useJobErrorReporting' +import { useJobErrorReporting } from '@/components/queue/job/useJobErrorReporting' +import type { ExecutionError } from '@/platform/remote/comfyui/jobs/jobTypes' -const createExecutionErrorMessage = ( - overrides: Partial = {} -): ExecutionErrorWsMessage => ({ - prompt_id: 'prompt', - timestamp: 100, - node_id: 'node-1', - node_type: 'KSampler', - executed: [], - exception_message: 'default failure', - exception_type: 'RuntimeError', - traceback: ['Trace line'], - current_inputs: {}, - current_outputs: {}, - ...overrides -}) - -const createTaskWithMessages = ( - messages: Array<[string, unknown]> | undefined = [] +const createTaskWithError = ( + promptId: string, + errorMessage?: string, + executionError?: ExecutionError, + createTime?: number ): TaskItemImpl => ({ - status: { - status_str: 'error', - completed: false, - messages - } - }) as TaskItemImpl - -describe('extractExecutionError', () => { - it('returns null when task has no execution error messages', () => { - expect(jobErrorReporting.extractExecutionError(null)).toBeNull() - expect( - jobErrorReporting.extractExecutionError({ - status: undefined - } as TaskItemImpl) - ).toBeNull() - expect( - jobErrorReporting.extractExecutionError({ - status: { - status_str: 'error', - completed: false, - messages: {} as unknown as Array<[string, unknown]> - } - } as TaskItemImpl) - ).toBeNull() - expect( - jobErrorReporting.extractExecutionError(createTaskWithMessages([])) - ).toBeNull() - expect( - jobErrorReporting.extractExecutionError( - createTaskWithMessages([ - ['execution_start', { prompt_id: 'prompt', timestamp: 1 }] - ] as Array<[string, unknown]>) - ) - ).toBeNull() - }) - - it('returns detail and message for execution_error entries', () => { - const detail = createExecutionErrorMessage({ exception_message: 'Kaboom' }) - const result = jobErrorReporting.extractExecutionError( - createTaskWithMessages([ - ['execution_success', { prompt_id: 'prompt', timestamp: 2 }], - ['execution_error', detail] - ] as Array<[string, unknown]>) - ) - expect(result).toEqual({ - detail, - message: 'Kaboom' - }) - }) - - it('falls back to an empty message when the tuple lacks detail', () => { - const result = jobErrorReporting.extractExecutionError( - createTaskWithMessages([ - ['execution_error'] as unknown as [string, ExecutionErrorWsMessage] - ]) - ) - expect(result).toEqual({ detail: undefined, message: '' }) - }) -}) + promptId, + errorMessage, + executionError, + createTime: createTime ?? Date.now() + }) as Partial as TaskItemImpl describe('useJobErrorReporting', () => { let taskState = ref(null) let taskForJob: ComputedRef - let copyToClipboard: UseJobErrorReportingOptions['copyToClipboard'] - let showExecutionErrorDialog: JobErrorDialogService['showExecutionErrorDialog'] - let showErrorDialog: JobErrorDialogService['showErrorDialog'] + let copyToClipboard: ReturnType + let showErrorDialog: ReturnType + let showExecutionErrorDialog: ReturnType let dialog: JobErrorDialogService - let composable: ReturnType + let composable: ReturnType beforeEach(() => { + vi.clearAllMocks() taskState = ref(null) taskForJob = computed(() => taskState.value) copyToClipboard = vi.fn() - showExecutionErrorDialog = vi.fn() showErrorDialog = vi.fn() + showExecutionErrorDialog = vi.fn() dialog = { - showExecutionErrorDialog, - showErrorDialog - } - composable = jobErrorReporting.useJobErrorReporting({ + showErrorDialog, + showExecutionErrorDialog + } as unknown as JobErrorDialogService + composable = useJobErrorReporting({ taskForJob, - copyToClipboard, + copyToClipboard: copyToClipboard as ( + value: string + ) => void | Promise, dialog }) }) @@ -121,73 +54,87 @@ describe('useJobErrorReporting', () => { }) it('exposes a computed message that reflects the current task error', () => { - taskState.value = createTaskWithMessages([ - [ - 'execution_error', - createExecutionErrorMessage({ exception_message: 'First failure' }) - ] - ]) + taskState.value = createTaskWithError('job-1', 'First failure') expect(composable.errorMessageValue.value).toBe('First failure') - taskState.value = createTaskWithMessages([ - [ - 'execution_error', - createExecutionErrorMessage({ exception_message: 'Second failure' }) - ] - ]) + taskState.value = createTaskWithError('job-2', 'Second failure') expect(composable.errorMessageValue.value).toBe('Second failure') }) + it('returns empty string when no error message', () => { + taskState.value = createTaskWithError('job-1') + expect(composable.errorMessageValue.value).toBe('') + }) + + it('returns empty string when task is null', () => { + taskState.value = null + expect(composable.errorMessageValue.value).toBe('') + }) + it('only calls the copy handler when a message exists', () => { - taskState.value = createTaskWithMessages([ - [ - 'execution_error', - createExecutionErrorMessage({ exception_message: 'Clipboard failure' }) - ] - ]) + taskState.value = createTaskWithError('job-1', 'Clipboard failure') composable.copyErrorMessage() expect(copyToClipboard).toHaveBeenCalledTimes(1) expect(copyToClipboard).toHaveBeenCalledWith('Clipboard failure') - vi.mocked(copyToClipboard).mockClear() - taskState.value = createTaskWithMessages([]) + copyToClipboard.mockClear() + taskState.value = createTaskWithError('job-2') composable.copyErrorMessage() expect(copyToClipboard).not.toHaveBeenCalled() }) - it('prefers the detailed execution dialog when detail is available', () => { - const detail = createExecutionErrorMessage({ - exception_message: 'Detailed failure' - }) - taskState.value = createTaskWithMessages([['execution_error', detail]]) + it('shows simple error dialog when only errorMessage present', () => { + taskState.value = createTaskWithError('job-1', 'Queue job error') composable.reportJobError() - expect(showExecutionErrorDialog).toHaveBeenCalledTimes(1) - expect(showExecutionErrorDialog).toHaveBeenCalledWith(detail) - expect(showErrorDialog).not.toHaveBeenCalled() - }) - it('shows a fallback dialog when only a message is available', () => { - const message = 'Queue job error' - taskState.value = createTaskWithMessages([]) - const valueSpy = vi - .spyOn(composable.errorMessageValue, 'value', 'get') - .mockReturnValue(message) - - expect(composable.errorMessageValue.value).toBe(message) - composable.reportJobError() - expect(showExecutionErrorDialog).not.toHaveBeenCalled() expect(showErrorDialog).toHaveBeenCalledTimes(1) - const [errorArg, optionsArg] = vi.mocked(showErrorDialog).mock.calls[0] + const [errorArg, optionsArg] = showErrorDialog.mock.calls[0] expect(errorArg).toBeInstanceOf(Error) - expect(errorArg.message).toBe(message) + expect(errorArg.message).toBe('Queue job error') expect(optionsArg).toEqual({ reportType: 'queueJobError' }) - valueSpy.mockRestore() + expect(showExecutionErrorDialog).not.toHaveBeenCalled() }) - it('does nothing when no error could be extracted', () => { - taskState.value = createTaskWithMessages([]) + it('does nothing when no task exists', () => { + taskState.value = null composable.reportJobError() - expect(showExecutionErrorDialog).not.toHaveBeenCalled() expect(showErrorDialog).not.toHaveBeenCalled() + expect(showExecutionErrorDialog).not.toHaveBeenCalled() + }) + + it('shows rich error dialog when execution_error available on task', () => { + const executionError: ExecutionError = { + prompt_id: 'job-1', + timestamp: 12345, + node_id: '5', + node_type: 'KSampler', + executed: ['1', '2'], + exception_message: 'CUDA out of memory', + exception_type: 'RuntimeError', + traceback: ['line 1', 'line 2'], + current_inputs: {}, + current_outputs: {} + } + taskState.value = createTaskWithError( + 'job-1', + 'CUDA out of memory', + executionError, + 12345 + ) + + composable.reportJobError() + + expect(showExecutionErrorDialog).toHaveBeenCalledTimes(1) + expect(showExecutionErrorDialog).toHaveBeenCalledWith(executionError) + expect(showErrorDialog).not.toHaveBeenCalled() + }) + + it('does nothing when no error message and no execution_error', () => { + taskState.value = createTaskWithError('job-1') + + composable.reportJobError() + + expect(showErrorDialog).not.toHaveBeenCalled() + expect(showExecutionErrorDialog).not.toHaveBeenCalled() }) }) diff --git a/src/components/queue/job/useJobErrorReporting.ts b/src/components/queue/job/useJobErrorReporting.ts index afc0baf3e..b008238a6 100644 --- a/src/components/queue/job/useJobErrorReporting.ts +++ b/src/components/queue/job/useJobErrorReporting.ts @@ -1,13 +1,13 @@ import { computed } from 'vue' import type { ComputedRef } from 'vue' -import type { ExecutionErrorWsMessage } from '@/schemas/apiSchema' +import type { ExecutionErrorDialogInput } from '@/services/dialogService' import type { TaskItemImpl } from '@/stores/queueStore' type CopyHandler = (value: string) => void | Promise export type JobErrorDialogService = { - showExecutionErrorDialog: (error: ExecutionErrorWsMessage) => void + showExecutionErrorDialog: (executionError: ExecutionErrorDialogInput) => void showErrorDialog: ( error: Error, options?: { @@ -17,30 +17,7 @@ export type JobErrorDialogService = { ) => void } -type JobExecutionError = { - detail?: ExecutionErrorWsMessage - message: string -} - -export const extractExecutionError = ( - task: TaskItemImpl | null -): JobExecutionError | null => { - const status = (task as TaskItemImpl | null)?.status - const messages = (status as { messages?: unknown[] } | undefined)?.messages - if (!Array.isArray(messages) || !messages.length) return null - const record = messages.find((entry: unknown) => { - return Array.isArray(entry) && entry[0] === 'execution_error' - }) as [string, ExecutionErrorWsMessage?] | undefined - if (!record) return null - const detail = record[1] - const message = String(detail?.exception_message ?? '') - return { - detail, - message - } -} - -export type UseJobErrorReportingOptions = { +type UseJobErrorReportingOptions = { taskForJob: ComputedRef copyToClipboard: CopyHandler dialog: JobErrorDialogService @@ -51,10 +28,7 @@ export const useJobErrorReporting = ({ copyToClipboard, dialog }: UseJobErrorReportingOptions) => { - const errorMessageValue = computed(() => { - const error = extractExecutionError(taskForJob.value) - return error?.message ?? '' - }) + const errorMessageValue = computed(() => taskForJob.value?.errorMessage ?? '') const copyErrorMessage = () => { if (errorMessageValue.value) { @@ -63,11 +37,12 @@ export const useJobErrorReporting = ({ } const reportJobError = () => { - const error = extractExecutionError(taskForJob.value) - if (error?.detail) { - dialog.showExecutionErrorDialog(error.detail) + const executionError = taskForJob.value?.executionError + if (executionError) { + dialog.showExecutionErrorDialog(executionError) return } + if (errorMessageValue.value) { dialog.showErrorDialog(new Error(errorMessageValue.value), { reportType: 'queueJobError' diff --git a/src/components/sidebar/tabs/AssetsSidebarTab.vue b/src/components/sidebar/tabs/AssetsSidebarTab.vue index 015badfed..341d41019 100644 --- a/src/components/sidebar/tabs/AssetsSidebarTab.vue +++ b/src/components/sidebar/tabs/AssetsSidebarTab.vue @@ -240,12 +240,19 @@ import type { AssetItem } from '@/platform/assets/schemas/assetSchema' import type { MediaKind } from '@/platform/assets/schemas/mediaAssetSchema' import { isCloud } from '@/platform/distribution/types' import { useSettingStore } from '@/platform/settings/settingStore' +import { getJobDetail } from '@/services/jobOutputCache' import { useCommandStore } from '@/stores/commandStore' import { useDialogStore } from '@/stores/dialogStore' import { ResultItemImpl, useQueueStore } from '@/stores/queueStore' import { formatDuration, getMediaTypeFromFilename } from '@/utils/formatUtil' import { cn } from '@/utils/tailwindUtil' +interface JobOutputItem { + filename: string + subfolder: string + type: string +} + const { t, n } = useI18n() const commandStore = useCommandStore() const queueStore = useQueueStore() @@ -492,6 +499,35 @@ function handleContextMenuHide() { }) } +const handleBulkDownload = (assets: AssetItem[]) => { + downloadMultipleAssets(assets) + clearSelection() +} + +const handleBulkDelete = async (assets: AssetItem[]) => { + await deleteMultipleAssets(assets) + clearSelection() +} + +const handleClearQueue = async () => { + await commandStore.execute('Comfy.ClearPendingTasks') +} + +const handleBulkAddToWorkflow = async (assets: AssetItem[]) => { + await addMultipleToWorkflow(assets) + clearSelection() +} + +const handleBulkOpenWorkflow = async (assets: AssetItem[]) => { + await openMultipleWorkflows(assets) + clearSelection() +} + +const handleBulkExportWorkflow = async (assets: AssetItem[]) => { + await exportMultipleWorkflows(assets) + clearSelection() +} + const handleZoomClick = (asset: AssetItem) => { const mediaType = getMediaTypeFromFilename(asset.name) @@ -519,16 +555,16 @@ const handleZoomClick = (asset: AssetItem) => { } } -const enterFolderView = (asset: AssetItem) => { +const enterFolderView = async (asset: AssetItem) => { const metadata = getOutputAssetMetadata(asset.user_metadata) if (!metadata) { console.warn('Invalid output asset metadata') return } - const { promptId, allOutputs, executionTimeInSeconds } = metadata + const { promptId, allOutputs, executionTimeInSeconds, outputCount } = metadata - if (!promptId || !Array.isArray(allOutputs) || allOutputs.length === 0) { + if (!promptId) { console.warn('Missing required folder view data') return } @@ -536,7 +572,48 @@ const enterFolderView = (asset: AssetItem) => { folderPromptId.value = promptId folderExecutionTime.value = executionTimeInSeconds - folderAssets.value = allOutputs.map((output) => ({ + // Determine which outputs to display + let outputsToDisplay = allOutputs ?? [] + + // If outputCount indicates more outputs than we have, fetch full outputs + const needsFullOutputs = + typeof outputCount === 'number' && + outputCount > 1 && + outputsToDisplay.length < outputCount + + if (needsFullOutputs) { + try { + const jobDetail = await getJobDetail(promptId) + if (jobDetail?.outputs) { + // Convert job outputs to ResultItemImpl array + outputsToDisplay = Object.entries(jobDetail.outputs).flatMap( + ([nodeId, nodeOutputs]) => + Object.entries(nodeOutputs).flatMap(([mediaType, items]) => + (items as JobOutputItem[]) + .map( + (item) => + new ResultItemImpl({ + ...item, + nodeId, + mediaType + }) + ) + .filter((r) => r.supportsPreview) + ) + ) + } + } catch (error) { + console.error('Failed to fetch job detail for folder view:', error) + outputsToDisplay = [] + } + } + + if (outputsToDisplay.length === 0) { + console.warn('No outputs available for folder view') + return + } + + folderAssets.value = outputsToDisplay.map((output) => ({ id: `${output.nodeId}-${output.filename}`, name: output.filename, size: 0, @@ -609,35 +686,6 @@ const handleDeleteSelected = async () => { clearSelection() } -const handleBulkDownload = (assets: AssetItem[]) => { - downloadMultipleAssets(assets) - clearSelection() -} - -const handleBulkDelete = async (assets: AssetItem[]) => { - await deleteMultipleAssets(assets) - clearSelection() -} - -const handleBulkAddToWorkflow = async (assets: AssetItem[]) => { - await addMultipleToWorkflow(assets) - clearSelection() -} - -const handleBulkOpenWorkflow = async (assets: AssetItem[]) => { - await openMultipleWorkflows(assets) - clearSelection() -} - -const handleBulkExportWorkflow = async (assets: AssetItem[]) => { - await exportMultipleWorkflows(assets) - clearSelection() -} - -const handleClearQueue = async () => { - await commandStore.execute('Comfy.ClearPendingTasks') -} - const handleApproachEnd = useDebounceFn(async () => { if ( activeTab.value === 'output' && diff --git a/src/composables/queue/useJobList.test.ts b/src/composables/queue/useJobList.test.ts index 2e453bcf1..a2a061f78 100644 --- a/src/composables/queue/useJobList.test.ts +++ b/src/composables/queue/useJobList.test.ts @@ -16,7 +16,7 @@ type TestTask = { executionTime?: number executionEndTimestamp?: number createTime?: number - workflow?: { id?: string } + workflowId?: string } const translations: Record = { @@ -161,7 +161,7 @@ const createTask = ( executionTime: overrides.executionTime, executionEndTimestamp: overrides.executionEndTimestamp, createTime: overrides.createTime, - workflow: overrides.workflow + workflowId: overrides.workflowId }) const mountUseJobList = () => { @@ -305,7 +305,7 @@ describe('useJobList', () => { expect(vi.getTimerCount()).toBe(0) }) - it('sorts all tasks by queue index descending', async () => { + it('sorts all tasks by priority descending', async () => { queueStoreMock.pendingTasks = [ createTask({ promptId: 'p', queueIndex: 1, mockState: 'pending' }) ] @@ -360,13 +360,13 @@ describe('useJobList', () => { promptId: 'wf-1', queueIndex: 2, mockState: 'pending', - workflow: { id: 'workflow-1' } + workflowId: 'workflow-1' }), createTask({ promptId: 'wf-2', queueIndex: 1, mockState: 'pending', - workflow: { id: 'workflow-2' } + workflowId: 'workflow-2' }) ] diff --git a/src/composables/queue/useJobList.ts b/src/composables/queue/useJobList.ts index 1acac786d..b745a7103 100644 --- a/src/composables/queue/useJobList.ts +++ b/src/composables/queue/useJobList.ts @@ -238,7 +238,7 @@ export function useJobList() { const activeId = workflowStore.activeWorkflow?.activeState?.id if (!activeId) return [] entries = entries.filter(({ task }) => { - const wid = task.workflow?.id + const wid = task.workflowId return !!wid && wid === activeId }) } diff --git a/src/composables/queue/useJobMenu.test.ts b/src/composables/queue/useJobMenu.test.ts index 0d8a4359d..1b339d09c 100644 --- a/src/composables/queue/useJobMenu.test.ts +++ b/src/composables/queue/useJobMenu.test.ts @@ -73,6 +73,7 @@ vi.mock('@/scripts/utils', () => ({ })) const dialogServiceMock = { + showErrorDialog: vi.fn(), showExecutionErrorDialog: vi.fn(), prompt: vi.fn() } @@ -103,6 +104,11 @@ vi.mock('@/stores/queueStore', () => ({ useQueueStore: () => queueStoreMock })) +const getJobWorkflowMock = vi.fn() +vi.mock('@/services/jobOutputCache', () => ({ + getJobWorkflow: (...args: any[]) => getJobWorkflowMock(...args) +})) + const createAnnotatedPathMock = vi.fn() vi.mock('@/utils/createAnnotatedPath', () => ({ createAnnotatedPath: (...args: any[]) => createAnnotatedPathMock(...args) @@ -132,9 +138,7 @@ const createJobItem = ( title: overrides.title ?? 'Test job', meta: overrides.meta ?? 'meta', state: overrides.state ?? 'completed', - taskRef: overrides.taskRef as Partial | undefined as - | TaskItemImpl - | undefined, + taskRef: overrides.taskRef as TaskItemImpl | undefined, iconName: overrides.iconName, iconImageUrl: overrides.iconImageUrl, showClear: overrides.showClear, @@ -181,6 +185,8 @@ describe('useJobMenu', () => { LoadVideo: { id: 'LoadVideo' }, LoadAudio: { id: 'LoadAudio' } } + // Default: no workflow available via lazy loading + getJobWorkflowMock.mockResolvedValue(undefined) }) const setCurrentItem = (item: JobListItem | null) => { @@ -190,10 +196,13 @@ describe('useJobMenu', () => { it('opens workflow when workflow data exists', async () => { const { openJobWorkflow } = mountJobMenu() const workflow = { nodes: [] } - setCurrentItem(createJobItem({ id: '55', taskRef: { workflow } })) + // Mock lazy loading via fetchJobDetail + extractWorkflow + getJobWorkflowMock.mockResolvedValue(workflow) + setCurrentItem(createJobItem({ id: '55' })) await openJobWorkflow() + expect(getJobWorkflowMock).toHaveBeenCalledWith('55') expect(workflowStoreMock.createTemporary).toHaveBeenCalledWith( 'Job 55.json', workflow @@ -268,11 +277,10 @@ describe('useJobMenu', () => { it('copies error message from failed job entry', async () => { const { jobMenuEntries } = mountJobMenu() - const error = { exception_message: 'boom' } setCurrentItem( createJobItem({ state: 'failed', - taskRef: { status: { messages: [['execution_error', error]] } } as any + taskRef: { errorMessage: 'Something went wrong' } as any }) ) @@ -280,31 +288,75 @@ describe('useJobMenu', () => { const entry = findActionEntry(jobMenuEntries.value, 'copy-error') await entry?.onClick?.() - expect(copyToClipboardMock).toHaveBeenCalledWith('boom') + expect(copyToClipboardMock).toHaveBeenCalledWith('Something went wrong') }) - it('reports error via dialog when entry triggered', async () => { + it('reports error via rich dialog when execution_error available', async () => { + const executionError = { + prompt_id: 'job-1', + timestamp: 12345, + node_id: '5', + node_type: 'KSampler', + executed: ['1', '2'], + exception_message: 'CUDA out of memory', + exception_type: 'RuntimeError', + traceback: ['line 1', 'line 2'], + current_inputs: {}, + current_outputs: {} + } const { jobMenuEntries } = mountJobMenu() - const error = { exception_message: 'bad', extra: 1 } setCurrentItem( createJobItem({ state: 'failed', - taskRef: { status: { messages: [['execution_error', error]] } } as any + taskRef: { + errorMessage: 'CUDA out of memory', + executionError, + createTime: 12345 + } as any }) ) await nextTick() const entry = findActionEntry(jobMenuEntries.value, 'report-error') - void entry?.onClick?.() + await entry?.onClick?.() + expect(dialogServiceMock.showExecutionErrorDialog).toHaveBeenCalledTimes(1) expect(dialogServiceMock.showExecutionErrorDialog).toHaveBeenCalledWith( - error + executionError ) + expect(dialogServiceMock.showErrorDialog).not.toHaveBeenCalled() + }) + + it('falls back to simple error dialog when no execution_error', async () => { + const { jobMenuEntries } = mountJobMenu() + setCurrentItem( + createJobItem({ + state: 'failed', + taskRef: { errorMessage: 'Job failed with error' } as any + }) + ) + + await nextTick() + const entry = findActionEntry(jobMenuEntries.value, 'report-error') + await entry?.onClick?.() + + expect(dialogServiceMock.showExecutionErrorDialog).not.toHaveBeenCalled() + expect(dialogServiceMock.showErrorDialog).toHaveBeenCalledTimes(1) + const [errorArg, optionsArg] = + dialogServiceMock.showErrorDialog.mock.calls[0] + expect(errorArg).toBeInstanceOf(Error) + expect(errorArg.message).toBe('Job failed with error') + expect(optionsArg).toEqual({ reportType: 'queueJobError' }) }) it('ignores error actions when message missing', async () => { const { jobMenuEntries } = mountJobMenu() - setCurrentItem(createJobItem({ state: 'failed', taskRef: { status: {} } })) + setCurrentItem( + createJobItem({ + state: 'failed', + taskRef: { errorMessage: undefined } as any + }) + ) await nextTick() const copyEntry = findActionEntry(jobMenuEntries.value, 'copy-error') @@ -313,6 +365,7 @@ describe('useJobMenu', () => { await reportEntry?.onClick?.() expect(copyToClipboardMock).not.toHaveBeenCalled() + expect(dialogServiceMock.showErrorDialog).not.toHaveBeenCalled() expect(dialogServiceMock.showExecutionErrorDialog).not.toHaveBeenCalled() }) @@ -488,12 +541,13 @@ describe('useJobMenu', () => { }) it('exports workflow with default filename when prompting disabled', async () => { + const workflow = { foo: 'bar' } + getJobWorkflowMock.mockResolvedValue(workflow) const { jobMenuEntries } = mountJobMenu() setCurrentItem( createJobItem({ id: '7', - state: 'completed', - taskRef: { workflow: { foo: 'bar' } } + state: 'completed' }) ) @@ -513,11 +567,11 @@ describe('useJobMenu', () => { it('prompts for filename when setting enabled', async () => { settingStoreMock.get.mockReturnValue(true) dialogServiceMock.prompt.mockResolvedValue('custom-name') + getJobWorkflowMock.mockResolvedValue({}) const { jobMenuEntries } = mountJobMenu() setCurrentItem( createJobItem({ - state: 'completed', - taskRef: { workflow: {} } + state: 'completed' }) ) @@ -537,12 +591,12 @@ describe('useJobMenu', () => { it('keeps existing json extension when exporting workflow', async () => { settingStoreMock.get.mockReturnValue(true) dialogServiceMock.prompt.mockResolvedValue('existing.json') + getJobWorkflowMock.mockResolvedValue({ foo: 'bar' }) const { jobMenuEntries } = mountJobMenu() setCurrentItem( createJobItem({ id: '42', - state: 'completed', - taskRef: { workflow: { foo: 'bar' } } + state: 'completed' }) ) @@ -558,11 +612,11 @@ describe('useJobMenu', () => { it('abandons export when prompt cancelled', async () => { settingStoreMock.get.mockReturnValue(true) dialogServiceMock.prompt.mockResolvedValue('') + getJobWorkflowMock.mockResolvedValue({}) const { jobMenuEntries } = mountJobMenu() setCurrentItem( createJobItem({ - state: 'completed', - taskRef: { workflow: {} } + state: 'completed' }) ) @@ -682,7 +736,12 @@ describe('useJobMenu', () => { it('returns failed menu entries with error actions', async () => { const { jobMenuEntries } = mountJobMenu() - setCurrentItem(createJobItem({ state: 'failed', taskRef: { status: {} } })) + setCurrentItem( + createJobItem({ + state: 'failed', + taskRef: { errorMessage: 'Some error' } as any + }) + ) await nextTick() expect(jobMenuEntries.value.map((entry) => entry.key)).toEqual([ diff --git a/src/composables/queue/useJobMenu.ts b/src/composables/queue/useJobMenu.ts index 6392e22eb..b4208304e 100644 --- a/src/composables/queue/useJobMenu.ts +++ b/src/composables/queue/useJobMenu.ts @@ -9,15 +9,11 @@ import { useMediaAssetActions } from '@/platform/assets/composables/useMediaAsse import { useSettingStore } from '@/platform/settings/settingStore' import { useWorkflowService } from '@/platform/workflow/core/services/workflowService' import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore' -import type { - ExecutionErrorWsMessage, - ResultItem, - ResultItemType, - TaskStatus -} from '@/schemas/apiSchema' +import type { ResultItem, ResultItemType } from '@/schemas/apiSchema' import { api } from '@/scripts/api' import { downloadBlob } from '@/scripts/utils' import { useDialogService } from '@/services/dialogService' +import { getJobWorkflow } from '@/services/jobOutputCache' import { useLitegraphService } from '@/services/litegraphService' import { useNodeDefStore } from '@/stores/nodeDefStore' import { useQueueStore } from '@/stores/queueStore' @@ -59,7 +55,7 @@ export function useJobMenu( const openJobWorkflow = async (item?: JobListItem | null) => { const target = resolveItem(item) if (!target) return - const data = target.taskRef?.workflow + const data = await getJobWorkflow(target.id) if (!data) return const filename = `Job ${target.id}.json` const temp = workflowStore.createTemporary(filename, data) @@ -83,37 +79,39 @@ export function useJobMenu( await queueStore.update() } - const findExecutionError = ( - messages: TaskStatus['messages'] | undefined - ): ExecutionErrorWsMessage | undefined => { - const errMessage = messages?.find((m) => m[0] === 'execution_error') - if (errMessage && errMessage[0] === 'execution_error') { - return errMessage[1] - } - return undefined - } - const copyErrorMessage = async (item?: JobListItem | null) => { const target = resolveItem(item) - if (!target) return - const err = findExecutionError(target.taskRef?.status?.messages) - const message = err?.exception_message - if (message) await copyToClipboard(String(message)) + const message = target?.taskRef?.errorMessage + if (message) await copyToClipboard(message) } const reportError = (item?: JobListItem | null) => { const target = resolveItem(item) if (!target) return - const err = findExecutionError(target.taskRef?.status?.messages) - if (err) useDialogService().showExecutionErrorDialog(err) + + // Use execution_error from list response if available + const executionError = target.taskRef?.executionError + + if (executionError) { + useDialogService().showExecutionErrorDialog(executionError) + return + } + + // Fall back to simple error dialog + const message = target.taskRef?.errorMessage + if (message) { + useDialogService().showErrorDialog(new Error(message), { + reportType: 'queueJobError' + }) + } } // This is very magical only because it matches the respective backend implementation // There is or will be a better way to do this - const addOutputLoaderNode = async (item?: JobListItem | null) => { - const target = resolveItem(item) - if (!target) return - const result: ResultItemImpl | undefined = target.taskRef?.previewOutput + const addOutputLoaderNode = async () => { + const item = currentMenuItem() + if (!item) return + const result: ResultItemImpl | undefined = item.taskRef?.previewOutput if (!result) return let nodeType: 'LoadImage' | 'LoadVideo' | 'LoadAudio' | null = null @@ -161,10 +159,10 @@ export function useJobMenu( /** * Trigger a download of the job's previewable output asset. */ - const downloadPreviewAsset = (item?: JobListItem | null) => { - const target = resolveItem(item) - if (!target) return - const result: ResultItemImpl | undefined = target.taskRef?.previewOutput + const downloadPreviewAsset = () => { + const item = currentMenuItem() + if (!item) return + const result: ResultItemImpl | undefined = item.taskRef?.previewOutput if (!result) return downloadFile(result.url) } @@ -172,14 +170,14 @@ export function useJobMenu( /** * Export the workflow JSON attached to the job. */ - const exportJobWorkflow = async (item?: JobListItem | null) => { - const target = resolveItem(item) - if (!target) return - const data = target.taskRef?.workflow + const exportJobWorkflow = async () => { + const item = currentMenuItem() + if (!item) return + const data = await getJobWorkflow(item.id) if (!data) return const settingStore = useSettingStore() - let filename = `Job ${target.id}.json` + let filename = `Job ${item.id}.json` if (settingStore.get('Comfy.PromptFilename')) { const input = await useDialogService().prompt({ @@ -196,10 +194,10 @@ export function useJobMenu( downloadBlob(filename, blob) } - const deleteJobAsset = async (item?: JobListItem | null) => { - const target = resolveItem(item) - if (!target) return - const task = target.taskRef as TaskItemImpl | undefined + const deleteJobAsset = async () => { + const item = currentMenuItem() + if (!item) return + const task = item.taskRef as TaskItemImpl | undefined const preview = task?.previewOutput if (!task || !preview) return @@ -210,8 +208,8 @@ export function useJobMenu( } } - const removeFailedJob = async (item?: JobListItem | null) => { - const task = resolveItem(item)?.taskRef as TaskItemImpl | undefined + const removeFailedJob = async () => { + const task = currentMenuItem()?.taskRef as TaskItemImpl | undefined if (!task) return await queueStore.delete(task) } @@ -242,8 +240,8 @@ export function useJobMenu( icon: 'icon-[lucide--zoom-in]', onClick: onInspectAsset ? () => { - const current = resolveItem() - if (current) onInspectAsset(current) + const item = currentMenuItem() + if (item) onInspectAsset(item) } : undefined }, @@ -254,33 +252,33 @@ export function useJobMenu( 'Add to current workflow' ), icon: 'icon-[comfy--node]', - onClick: () => addOutputLoaderNode(resolveItem()) + onClick: addOutputLoaderNode }, { key: 'download', label: st('queue.jobMenu.download', 'Download'), icon: 'icon-[lucide--download]', - onClick: () => downloadPreviewAsset(resolveItem()) + onClick: downloadPreviewAsset }, { kind: 'divider', key: 'd1' }, { key: 'open-workflow', label: jobMenuOpenWorkflowLabel.value, icon: 'icon-[comfy--workflow]', - onClick: () => openJobWorkflow(resolveItem()) + onClick: openJobWorkflow }, { key: 'export-workflow', label: st('queue.jobMenu.exportWorkflow', 'Export workflow'), icon: 'icon-[comfy--file-output]', - onClick: () => exportJobWorkflow(resolveItem()) + onClick: exportJobWorkflow }, { kind: 'divider', key: 'd2' }, { key: 'copy-id', label: jobMenuCopyJobIdLabel.value, icon: 'icon-[lucide--copy]', - onClick: () => copyJobId(resolveItem()) + onClick: copyJobId }, { kind: 'divider', key: 'd3' }, ...(hasDeletableAsset @@ -289,7 +287,7 @@ export function useJobMenu( key: 'delete', label: st('queue.jobMenu.deleteAsset', 'Delete asset'), icon: 'icon-[lucide--trash-2]', - onClick: () => deleteJobAsset(resolveItem()) + onClick: deleteJobAsset } ] : []) @@ -301,33 +299,33 @@ export function useJobMenu( key: 'open-workflow', label: jobMenuOpenWorkflowFailedLabel.value, icon: 'icon-[comfy--workflow]', - onClick: () => openJobWorkflow(resolveItem()) + onClick: openJobWorkflow }, { kind: 'divider', key: 'd1' }, { key: 'copy-id', label: jobMenuCopyJobIdLabel.value, icon: 'icon-[lucide--copy]', - onClick: () => copyJobId(resolveItem()) + onClick: copyJobId }, { key: 'copy-error', label: st('queue.jobMenu.copyErrorMessage', 'Copy error message'), icon: 'icon-[lucide--copy]', - onClick: () => copyErrorMessage(resolveItem()) + onClick: copyErrorMessage }, { key: 'report-error', label: st('queue.jobMenu.reportError', 'Report error'), icon: 'icon-[lucide--message-circle-warning]', - onClick: () => reportError(resolveItem()) + onClick: reportError }, { kind: 'divider', key: 'd2' }, { key: 'delete', label: st('queue.jobMenu.removeJob', 'Remove job'), icon: 'icon-[lucide--circle-minus]', - onClick: () => removeFailedJob(resolveItem()) + onClick: removeFailedJob } ] } @@ -336,21 +334,21 @@ export function useJobMenu( key: 'open-workflow', label: jobMenuOpenWorkflowLabel.value, icon: 'icon-[comfy--workflow]', - onClick: () => openJobWorkflow(resolveItem()) + onClick: openJobWorkflow }, { kind: 'divider', key: 'd1' }, { key: 'copy-id', label: jobMenuCopyJobIdLabel.value, icon: 'icon-[lucide--copy]', - onClick: () => copyJobId(resolveItem()) + onClick: copyJobId }, { kind: 'divider', key: 'd2' }, { key: 'cancel-job', label: jobMenuCancelLabel.value, icon: 'icon-[lucide--x]', - onClick: () => cancelJob(resolveItem()) + onClick: cancelJob } ] }) diff --git a/src/composables/queue/useResultGallery.test.ts b/src/composables/queue/useResultGallery.test.ts index 21ab1462e..8b8522a79 100644 --- a/src/composables/queue/useResultGallery.test.ts +++ b/src/composables/queue/useResultGallery.test.ts @@ -1,35 +1,74 @@ -import { describe, it, expect } from 'vitest' +import { createPinia, setActivePinia } from 'pinia' +import { beforeEach, describe, expect, it } from 'vitest' import { useResultGallery } from '@/composables/queue/useResultGallery' -import type { JobListItem } from '@/composables/queue/useJobList' +import type { JobListItem as JobListViewItem } from '@/composables/queue/useJobList' +import type { JobListItem } from '@/platform/remote/comfyui/jobs/jobTypes' +import { ResultItemImpl, TaskItemImpl } from '@/stores/queueStore' -type PreviewLike = { url: string; supportsPreview: boolean } +const createResultItem = ( + url: string, + supportsPreview = true +): ResultItemImpl => { + const item = new ResultItemImpl({ + filename: url, + subfolder: '', + type: 'output', + nodeId: 'node-1', + mediaType: supportsPreview ? 'images' : 'unknown' + }) + // Override url getter for test matching + Object.defineProperty(item, 'url', { get: () => url }) + Object.defineProperty(item, 'supportsPreview', { get: () => supportsPreview }) + return item +} -const createPreview = (url: string, supportsPreview = true): PreviewLike => ({ - url, - supportsPreview +const createMockJob = (id: string, outputsCount = 1): JobListItem => ({ + id, + status: 'completed', + create_time: Date.now(), + preview_output: null, + outputs_count: outputsCount, + priority: 0 }) -const createTask = (preview?: PreviewLike) => ({ - previewOutput: preview -}) +const createTask = ( + preview?: ResultItemImpl, + allOutputs?: ResultItemImpl[], + outputsCount = 1 +): TaskItemImpl => { + const job = createMockJob( + `task-${Math.random().toString(36).slice(2)}`, + outputsCount + ) + const flatOutputs = allOutputs ?? (preview ? [preview] : []) + return new TaskItemImpl(job, {}, flatOutputs) +} -const createJobItem = (id: string, preview?: PreviewLike): JobListItem => +const createJobViewItem = ( + id: string, + taskRef?: TaskItemImpl +): JobListViewItem => ({ id, title: `Job ${id}`, meta: '', state: 'completed', showClear: false, - taskRef: preview ? { previewOutput: preview } : undefined - }) as JobListItem + taskRef + }) as JobListViewItem describe('useResultGallery', () => { - it('collects only previewable outputs and preserves their order', () => { - const previewable = [createPreview('p-1'), createPreview('p-2')] + beforeEach(() => { + setActivePinia(createPinia()) + }) + + it('collects only previewable outputs and preserves their order', async () => { + const previewable = [createResultItem('p-1'), createResultItem('p-2')] + const nonPreviewable = createResultItem('skip-me', false) const tasks = [ createTask(previewable[0]), - createTask({ url: 'skip-me', supportsPreview: false }), + createTask(nonPreviewable), createTask(previewable[1]), createTask() ] @@ -38,28 +77,28 @@ describe('useResultGallery', () => { () => tasks ) - onViewItem(createJobItem('job-1', previewable[0])) + await onViewItem(createJobViewItem('job-1', tasks[0])) - expect(galleryItems.value).toEqual(previewable) + expect(galleryItems.value).toEqual([previewable[0]]) expect(galleryActiveIndex.value).toBe(0) }) - it('does not change state when there are no previewable tasks', () => { + it('does not change state when there are no previewable tasks', async () => { const { galleryItems, galleryActiveIndex, onViewItem } = useResultGallery( () => [] ) - onViewItem(createJobItem('job-missing')) + await onViewItem(createJobViewItem('job-missing')) expect(galleryItems.value).toEqual([]) expect(galleryActiveIndex.value).toBe(-1) }) - it('activates the index that matches the viewed preview URL', () => { + it('activates the index that matches the viewed preview URL', async () => { const previewable = [ - createPreview('p-1'), - createPreview('p-2'), - createPreview('p-3') + createResultItem('p-1'), + createResultItem('p-2'), + createResultItem('p-3') ] const tasks = previewable.map((preview) => createTask(preview)) @@ -67,37 +106,66 @@ describe('useResultGallery', () => { () => tasks ) - onViewItem(createJobItem('job-2', createPreview('p-2'))) + await onViewItem(createJobViewItem('job-2', tasks[1])) - expect(galleryItems.value).toEqual(previewable) - expect(galleryActiveIndex.value).toBe(1) + expect(galleryItems.value).toEqual([previewable[1]]) + expect(galleryActiveIndex.value).toBe(0) }) - it('defaults to the first entry when the clicked job lacks a preview', () => { - const previewable = [createPreview('p-1'), createPreview('p-2')] + it('defaults to the first entry when the clicked job lacks a preview', async () => { + const previewable = [createResultItem('p-1'), createResultItem('p-2')] const tasks = previewable.map((preview) => createTask(preview)) const { galleryItems, galleryActiveIndex, onViewItem } = useResultGallery( () => tasks ) - onViewItem(createJobItem('job-no-preview')) + await onViewItem(createJobViewItem('job-no-preview')) expect(galleryItems.value).toEqual(previewable) expect(galleryActiveIndex.value).toBe(0) }) - it('defaults to the first entry when no gallery item matches the preview URL', () => { - const previewable = [createPreview('p-1'), createPreview('p-2')] + it('defaults to the first entry when no gallery item matches the preview URL', async () => { + const previewable = [createResultItem('p-1'), createResultItem('p-2')] const tasks = previewable.map((preview) => createTask(preview)) const { galleryItems, galleryActiveIndex, onViewItem } = useResultGallery( () => tasks ) - onViewItem(createJobItem('job-mismatch', createPreview('missing'))) + const taskWithMismatchedPreview = createTask(createResultItem('missing')) + await onViewItem( + createJobViewItem('job-mismatch', taskWithMismatchedPreview) + ) - expect(galleryItems.value).toEqual(previewable) + expect(galleryItems.value).toEqual([createResultItem('missing')]) + expect(galleryActiveIndex.value).toBe(0) + }) + + it('loads full outputs when task has only preview outputs', async () => { + const previewOutput = createResultItem('preview-1') + const fullOutputs = [ + createResultItem('full-1'), + createResultItem('full-2'), + createResultItem('full-3') + ] + + // Create a task with outputsCount > 1 to trigger lazy loading + const job = createMockJob('task-1', 3) + const task = new TaskItemImpl(job, {}, [previewOutput]) + + // Mock loadFullOutputs to return full outputs + const loadedTask = new TaskItemImpl(job, {}, fullOutputs) + task.loadFullOutputs = async () => loadedTask + + const { galleryItems, galleryActiveIndex, onViewItem } = useResultGallery( + () => [task] + ) + + await onViewItem(createJobViewItem('job-1', task)) + + expect(galleryItems.value).toEqual(fullOutputs) expect(galleryActiveIndex.value).toBe(0) }) }) diff --git a/src/composables/queue/useResultGallery.ts b/src/composables/queue/useResultGallery.ts index e86ff54d4..44c6a607d 100644 --- a/src/composables/queue/useResultGallery.ts +++ b/src/composables/queue/useResultGallery.ts @@ -1,39 +1,42 @@ import { ref, shallowRef } from 'vue' import type { JobListItem } from '@/composables/queue/useJobList' - -/** Minimal preview item interface for gallery filtering. */ -interface PreviewItem { - url: string - supportsPreview: boolean -} - -/** Minimal task interface for gallery preview. */ -interface TaskWithPreview { - previewOutput?: T -} +import { findActiveIndex, getOutputsForTask } from '@/services/jobOutputCache' +import type { ResultItemImpl, TaskItemImpl } from '@/stores/queueStore' /** * Manages result gallery state and activation for queue items. */ -export function useResultGallery( - getFilteredTasks: () => TaskWithPreview[] -) { +export function useResultGallery(getFilteredTasks: () => TaskItemImpl[]) { const galleryActiveIndex = ref(-1) - const galleryItems = shallowRef([]) + const galleryItems = shallowRef([]) - const onViewItem = (item: JobListItem) => { - const items: T[] = getFilteredTasks().flatMap((t) => { - const preview = t.previewOutput - return preview && preview.supportsPreview ? [preview] : [] - }) + async function onViewItem(item: JobListItem) { + const tasks = getFilteredTasks() + if (!tasks.length) return + + const targetTask = item.taskRef + const targetOutputs = targetTask + ? await getOutputsForTask(targetTask) + : null + + // Request was superseded by a newer one + if (targetOutputs === null && targetTask) return + + // Use target's outputs if available, otherwise fall back to all previews + const items = targetOutputs?.length + ? targetOutputs + : tasks + .map((t) => t.previewOutput) + .filter((o): o is ResultItemImpl => !!o) if (!items.length) return galleryItems.value = items - const activeUrl: string | undefined = item.taskRef?.previewOutput?.url - const idx = activeUrl ? items.findIndex((o) => o.url === activeUrl) : 0 - galleryActiveIndex.value = idx >= 0 ? idx : 0 + galleryActiveIndex.value = findActiveIndex( + items, + item.taskRef?.previewOutput?.url + ) } return { diff --git a/src/platform/assets/composables/media/assetMappers.ts b/src/platform/assets/composables/media/assetMappers.ts index c03b277bd..863dc9877 100644 --- a/src/platform/assets/composables/media/assetMappers.ts +++ b/src/platform/assets/composables/media/assetMappers.ts @@ -32,7 +32,6 @@ export function mapTaskOutputToAssetItem( subfolder: output.subfolder, executionTimeInSeconds: taskItem.executionTimeInSeconds, format: output.format, - workflow: taskItem.workflow, create_time: taskItem.createTime } diff --git a/src/platform/remote/comfyui/history/__fixtures__/historyFixtures.ts b/src/platform/remote/comfyui/history/__fixtures__/historyFixtures.ts deleted file mode 100644 index 3a930a1ad..000000000 --- a/src/platform/remote/comfyui/history/__fixtures__/historyFixtures.ts +++ /dev/null @@ -1,380 +0,0 @@ -/** - * @fileoverview Test fixtures for history tests. - */ -import type { HistoryResponseV2 } from '@/platform/remote/comfyui/history/types/historyV2Types' -import type { HistoryTaskItem } from '@/schemas/apiSchema' - -/** - * V1 API raw response format (object with prompt IDs as keys) - */ -export const historyV1RawResponse: Record< - string, - Omit -> = { - 'complete-item-id': { - prompt: [ - 24, - 'complete-item-id', - {}, - { - client_id: 'test-client', - extra_pnginfo: { - workflow: { - id: '44f0c9f9-b5a7-48de-99fc-7e80c1570241', - revision: 0, - last_node_id: 9, - last_link_id: 9, - nodes: [], - links: [], - groups: [], - config: {}, - extra: {}, - version: 0.4 - } - } - }, - ['9'] - ], - outputs: { - '9': { - images: [ - { - filename: 'test.png', - subfolder: '', - type: 'output' - } - ] - } - }, - status: { - status_str: 'success', - completed: true, - messages: [ - [ - 'execution_start', - { prompt_id: 'complete-item-id', timestamp: 1234567890 } - ], - [ - 'execution_success', - { prompt_id: 'complete-item-id', timestamp: 1234567900 } - ] - ] - }, - meta: { - '9': { - node_id: '9', - display_node: '9' - } - } - }, - 'no-status-id': { - prompt: [ - 23, - 'no-status-id', - {}, - { - client_id: 'inference' - }, - ['10'] - ], - outputs: { - '10': { - images: [] - } - }, - status: undefined, - meta: { - '10': { - node_id: '10', - display_node: '10' - } - } - } -} - -/** - * V2 response with multiple edge cases: - * - Item 0: Complete with all fields - * - Item 1: Missing optional status field - * - Item 2: Missing optional meta field - * - Item 3: Multiple output nodes - */ -export const historyV2Fixture: HistoryResponseV2 = { - history: [ - { - prompt_id: 'complete-item-id', - prompt: { - priority: 24, - prompt_id: 'complete-item-id', - extra_data: { - client_id: 'test-client', - extra_pnginfo: { - workflow: { - id: '44f0c9f9-b5a7-48de-99fc-7e80c1570241', - revision: 0, - last_node_id: 9, - last_link_id: 9, - nodes: [], - links: [], - groups: [], - config: {}, - extra: {}, - version: 0.4 - } - } - } - }, - outputs: { - '9': { - images: [ - { - filename: 'test.png', - subfolder: '', - type: 'output' - } - ] - } - }, - status: { - status_str: 'success', - completed: true, - messages: [ - [ - 'execution_start', - { prompt_id: 'complete-item-id', timestamp: 1234567890 } - ], - [ - 'execution_success', - { prompt_id: 'complete-item-id', timestamp: 1234567900 } - ] - ] - }, - meta: { - '9': { - node_id: '9', - display_node: '9' - } - } - }, - { - prompt_id: 'no-status-id', - prompt: { - priority: 23, - prompt_id: 'no-status-id', - extra_data: { - client_id: 'inference' - } - }, - outputs: { - '10': { - images: [] - } - }, - meta: { - '10': { - node_id: '10', - display_node: '10' - } - } - }, - { - prompt_id: 'no-meta-id', - prompt: { - priority: 22, - prompt_id: 'no-meta-id', - extra_data: { - client_id: 'web-ui' - } - }, - outputs: { - '11': { - audio: [] - } - }, - status: { - status_str: 'error', - completed: false, - messages: [] - } - }, - { - prompt_id: 'multi-output-id', - prompt: { - priority: 21, - prompt_id: 'multi-output-id', - extra_data: { - client_id: 'batch-processor' - } - }, - outputs: { - '3': { - images: [{ filename: 'img1.png', type: 'output', subfolder: '' }] - }, - '9': { - images: [{ filename: 'img2.png', type: 'output', subfolder: '' }] - }, - '12': { - video: [{ filename: 'video.mp4', type: 'output', subfolder: '' }] - } - }, - status: { - status_str: 'success', - completed: true, - messages: [] - }, - meta: { - '3': { node_id: '3', display_node: '3' }, - '9': { node_id: '9', display_node: '9' }, - '12': { node_id: '12', display_node: '12' } - } - } - ] -} - -/** - * 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: [ - 1, - 'complete-item-id', - {}, - { - client_id: 'test-client', - extra_pnginfo: { - workflow: { - id: '44f0c9f9-b5a7-48de-99fc-7e80c1570241', - revision: 0, - last_node_id: 9, - last_link_id: 9, - nodes: [], - links: [], - groups: [], - config: {}, - extra: {}, - version: 0.4 - } - } - }, - ['9'] - ], - outputs: { - '9': { - images: [ - { - filename: 'test.png', - subfolder: '', - type: 'output' - } - ] - } - }, - status: { - status_str: 'success', - completed: true, - messages: [ - [ - 'execution_start', - { prompt_id: 'complete-item-id', timestamp: 1234567890 } - ], - [ - 'execution_success', - { prompt_id: 'complete-item-id', timestamp: 1234567900 } - ] - ] - }, - meta: { - '9': { - node_id: '9', - display_node: '9' - } - } - }, - { - taskType: 'History', - prompt: [ - 0, - 'no-status-id', - {}, - { - client_id: 'inference' - }, - ['10'] - ], - outputs: { - '10': { - images: [] - } - }, - status: undefined, - meta: { - '10': { - node_id: '10', - display_node: '10' - } - } - }, - { - taskType: 'History', - prompt: [ - 0, - 'no-meta-id', - {}, - { - client_id: 'web-ui' - }, - ['11'] - ], - outputs: { - '11': { - audio: [] - } - }, - status: { - status_str: 'error', - completed: false, - messages: [] - }, - meta: undefined - }, - { - taskType: 'History', - prompt: [ - 0, - 'multi-output-id', - {}, - { - client_id: 'batch-processor' - }, - ['3', '9', '12'] - ], - outputs: { - '3': { - images: [{ filename: 'img1.png', type: 'output', subfolder: '' }] - }, - '9': { - images: [{ filename: 'img2.png', type: 'output', subfolder: '' }] - }, - '12': { - video: [{ filename: 'video.mp4', type: 'output', subfolder: '' }] - } - }, - status: { - status_str: 'success', - completed: true, - messages: [] - }, - meta: { - '3': { node_id: '3', display_node: '3' }, - '9': { node_id: '9', display_node: '9' }, - '12': { node_id: '12', display_node: '12' } - } - } -] diff --git a/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.test.ts b/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.test.ts deleted file mode 100644 index e9dff7d38..000000000 --- a/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.test.ts +++ /dev/null @@ -1,434 +0,0 @@ -/** - * @fileoverview Unit tests for V2 to V1 history adapter. - */ -import { describe, expect, it } from 'vitest' - -import { mapHistoryV2toHistory } from '@/platform/remote/comfyui/history/adapters/v2ToV1Adapter' -import { zRawHistoryItemV2 } from '@/platform/remote/comfyui/history/types/historyV2Types' -import type { HistoryResponseV2 } from '@/platform/remote/comfyui/history/types/historyV2Types' - -import { - expectedV1Fixture, - historyV2Fixture -} from '@/platform/remote/comfyui/history/__fixtures__/historyFixtures' -import type { HistoryTaskItem } from '@/platform/remote/comfyui/history/types/historyV1Types' - -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: [] - } - } - ] -} - -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 } - ] - ] - } - } - ] -} - -const historyV2MultipleNoTimestamp: HistoryResponseV2 = { - history: [ - { - prompt_id: 'item-no-timestamp-1', - prompt: { - priority: 0, - prompt_id: 'item-no-timestamp-1', - extra_data: { client_id: 'test-client' } - }, - outputs: { - '1': { - images: [{ filename: 'test1.png', type: 'output', subfolder: '' }] - } - }, - status: { - status_str: 'success', - completed: true, - messages: [] - } - }, - { - prompt_id: 'item-no-timestamp-2', - prompt: { - priority: 0, - prompt_id: 'item-no-timestamp-2', - extra_data: { client_id: 'test-client' } - }, - outputs: { - '2': { - images: [{ filename: 'test2.png', type: 'output', subfolder: '' }] - } - }, - status: { - status_str: 'success', - completed: true, - messages: [] - } - }, - { - prompt_id: 'item-no-timestamp-3', - prompt: { - priority: 0, - prompt_id: 'item-no-timestamp-3', - extra_data: { client_id: 'test-client' } - }, - outputs: { - '3': { - images: [{ filename: 'test3.png', type: 'output', subfolder: '' }] - } - }, - status: { - status_str: 'success', - completed: true, - messages: [] - } - } - ] -} - -function findResultByPromptId( - result: HistoryTaskItem[], - promptId: string -): HistoryTaskItem { - const item = result.find((item) => item.prompt[1] === promptId) - if (!item) { - throw new Error(`Expected item with promptId ${promptId} not found`) - } - return item -} - -describe('mapHistoryV2toHistory', () => { - describe('fixture validation', () => { - it('should have valid fixture data', () => { - // Validate all items in the fixture to ensure test data is correct - historyV2Fixture.history.forEach((item: unknown) => { - expect(() => zRawHistoryItemV2.parse(item)).not.toThrow() - }) - }) - }) - - describe('given a complete V2 history response with edge cases', () => { - const history = mapHistoryV2toHistory(historyV2Fixture) - - it('should transform all items to V1 format with correct structure', () => { - expect(history).toEqual(expectedV1Fixture) - }) - - it('should add taskType "History" to all items', () => { - history.forEach((item) => { - expect(item.taskType).toBe('History') - }) - }) - - it('should transform prompt to V1 tuple [priority, id, {}, extra_data, outputNodeIds]', () => { - const firstItem = history[0] - - 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' }) - expect(firstItem.prompt[4]).toEqual(['9']) - }) - - it('should handle missing optional status field', () => { - expect(history[1].prompt[1]).toBe('no-status-id') - expect(history[1].status).toBeUndefined() - }) - - it('should handle missing optional meta field', () => { - expect(history[2].prompt[1]).toBe('no-meta-id') - expect(history[2].meta).toBeUndefined() - }) - - it('should derive output node IDs from outputs object keys', () => { - const multiOutputItem = history[3] - - expect(multiOutputItem.prompt[4]).toEqual( - expect.arrayContaining(['3', '9', '12']) - ) - expect(multiOutputItem.prompt[4]).toHaveLength(3) - }) - }) - - describe('given empty history array', () => { - it('should return empty array', () => { - const emptyResponse: HistoryResponseV2 = { history: [] } - const history = mapHistoryV2toHistory(emptyResponse) - - expect(history).toEqual([]) - }) - }) - - describe('given empty outputs object', () => { - it('should return empty array for output node IDs', () => { - const v2Response: HistoryResponseV2 = { - history: [ - { - prompt_id: 'test-id', - prompt: { - priority: 0, - prompt_id: 'test-id', - extra_data: { client_id: 'test' } - }, - outputs: {} - } - ] - } - - const history = mapHistoryV2toHistory(v2Response) - - expect(history[0].prompt[4]).toEqual([]) - }) - }) - - describe('given missing client_id', () => { - it('should accept history items without client_id', () => { - const v2Response: HistoryResponseV2 = { - history: [ - { - prompt_id: 'test-id', - prompt: { - priority: 0, - prompt_id: 'test-id', - extra_data: {} - }, - outputs: {} - } - ] - } - - const history = mapHistoryV2toHistory(v2Response) - - 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 = findResultByPromptId(result, 'item-timestamp-1000') - const item2000 = findResultByPromptId(result, 'item-timestamp-2000') - const itemNoTimestamp = findResultByPromptId(result, 'item-no-timestamp') - - 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 = findResultByPromptId(result, 'item-timestamp-1000') - const item2000 = findResultByPromptId(result, 'item-timestamp-2000') - const item3000 = findResultByPromptId(result, 'item-timestamp-3000') - const item4000 = findResultByPromptId(result, 'item-timestamp-4000') - const item5000 = findResultByPromptId(result, 'item-timestamp-5000') - - 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) - }) - - it('assigns priority 0 to all items when multiple items lack timestamps', () => { - const result = mapHistoryV2toHistory(historyV2MultipleNoTimestamp) - - expect(result).toHaveLength(3) - - const item1 = findResultByPromptId(result, 'item-no-timestamp-1') - const item2 = findResultByPromptId(result, 'item-no-timestamp-2') - const item3 = findResultByPromptId(result, 'item-no-timestamp-3') - - expect(item1.prompt[0]).toBe(0) - expect(item2.prompt[0]).toBe(0) - expect(item3.prompt[0]).toBe(0) - }) - }) -}) diff --git a/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.ts b/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.ts deleted file mode 100644 index fcb46eda7..000000000 --- a/src/platform/remote/comfyui/history/adapters/v2ToV1Adapter.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @fileoverview Adapter to convert V2 history format to V1 format - * @module platform/remote/comfyui/history/adapters/v2ToV1Adapter - */ -import type { HistoryTaskItem, TaskPrompt } from '../types/historyV1Types' -import type { - HistoryResponseV2, - RawHistoryItemV2, - TaskOutput, - TaskPromptV2 -} from '../types/historyV2Types' - -function mapPromptV2toV1( - promptV2: TaskPromptV2, - outputs: TaskOutput, - syntheticPriority: number, - createTime?: number -): TaskPrompt { - const extraData = { - ...(promptV2.extra_data ?? {}), - ...(typeof createTime === 'number' ? { create_time: createTime } : {}) - } - return [ - syntheticPriority, - promptV2.prompt_id, - {}, - extraData, - Object.keys(outputs) - ] -} - -function getExecutionSuccessTimestamp(item: RawHistoryItemV2): number { - return ( - item.status?.messages?.find((m) => m[0] === 'execution_success')?.[1] - ?.timestamp ?? 0 - ) -} - -export function mapHistoryV2toHistory( - historyV2Response: HistoryResponseV2 -): HistoryTaskItem[] { - const { history } = historyV2Response - - // 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, - syntheticPriority, - item.create_time - ), - status, - outputs, - meta - } - }) -} diff --git a/src/platform/remote/comfyui/history/fetchers/fetchHistoryV1.test.ts b/src/platform/remote/comfyui/history/fetchers/fetchHistoryV1.test.ts deleted file mode 100644 index b2fa1cfa2..000000000 --- a/src/platform/remote/comfyui/history/fetchers/fetchHistoryV1.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @fileoverview Unit tests for V1 history fetcher. - */ -import { describe, expect, it, vi } from 'vitest' - -import { fetchHistoryV1 } from '@/platform/remote/comfyui/history/fetchers/fetchHistoryV1' - -import { historyV1RawResponse } from '@/platform/remote/comfyui/history/__fixtures__/historyFixtures' - -describe('fetchHistoryV1', () => { - const mockFetchApi = vi.fn().mockResolvedValue({ - json: async () => historyV1RawResponse - }) - - it('should fetch from /history endpoint with default max_items', async () => { - await fetchHistoryV1(mockFetchApi) - - expect(mockFetchApi).toHaveBeenCalledWith('/history?max_items=200') - }) - - it('should fetch with custom max_items parameter', async () => { - await fetchHistoryV1(mockFetchApi, 50) - - expect(mockFetchApi).toHaveBeenCalledWith('/history?max_items=50') - }) - - it('should transform object response to array with taskType and preserve fields', async () => { - const result = await fetchHistoryV1(mockFetchApi) - - expect(result.History).toHaveLength(2) - result.History.forEach((item) => { - expect(item.taskType).toBe('History') - }) - expect(result.History[0]).toMatchObject({ - taskType: 'History', - prompt: [24, 'complete-item-id', {}, expect.any(Object), ['9']], - outputs: expect.any(Object), - status: expect.any(Object), - meta: expect.any(Object) - }) - }) - - it('should handle empty response object', async () => { - const emptyMock = vi.fn().mockResolvedValue({ - json: async () => ({}) - }) - - const result = await fetchHistoryV1(emptyMock) - - expect(result.History).toEqual([]) - }) -}) diff --git a/src/platform/remote/comfyui/history/fetchers/fetchHistoryV1.ts b/src/platform/remote/comfyui/history/fetchers/fetchHistoryV1.ts deleted file mode 100644 index 6d566d035..000000000 --- a/src/platform/remote/comfyui/history/fetchers/fetchHistoryV1.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @fileoverview V1 History Fetcher - Desktop/localhost API - * @module platform/remote/comfyui/history/fetchers/fetchHistoryV1 - * - * Fetches history directly from V1 API endpoint. - * Used by desktop and localhost distributions. - */ - -import type { - HistoryTaskItem, - HistoryV1Response -} from '../types/historyV1Types' - -/** - * Fetches history from V1 API endpoint - * @param api - API instance with fetchApi method - * @param maxItems - Maximum number of history items to fetch - * @param offset - Offset for pagination (must be non-negative integer) - * @returns Promise resolving to V1 history response - * @throws Error if offset is invalid (negative or non-integer) - */ -export async function fetchHistoryV1( - fetchApi: (url: string) => Promise, - maxItems: number = 200, - offset?: number -): Promise { - // Validate offset parameter - if (offset !== undefined && (offset < 0 || !Number.isInteger(offset))) { - throw new Error( - `Invalid offset parameter: ${offset}. Must be a non-negative integer.` - ) - } - - const params = new URLSearchParams({ max_items: maxItems.toString() }) - if (offset !== undefined) { - params.set('offset', offset.toString()) - } - const url = `/history?${params.toString()}` - const res = await fetchApi(url) - const json: Record< - string, - Omit - > = await res.json() - - return { - History: Object.values(json).map((item) => ({ - ...item, - taskType: 'History' - })) - } -} diff --git a/src/platform/remote/comfyui/history/fetchers/fetchHistoryV2.test.ts b/src/platform/remote/comfyui/history/fetchers/fetchHistoryV2.test.ts deleted file mode 100644 index fd8aa8bbd..000000000 --- a/src/platform/remote/comfyui/history/fetchers/fetchHistoryV2.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @fileoverview Unit tests for V2 history fetcher. - */ -import { describe, expect, it, vi } from 'vitest' - -import { fetchHistoryV2 } from '@/platform/remote/comfyui/history/fetchers/fetchHistoryV2' - -import { - expectedV1Fixture, - historyV2Fixture -} from '@/platform/remote/comfyui/history/__fixtures__/historyFixtures' - -describe('fetchHistoryV2', () => { - const mockFetchApi = vi.fn().mockResolvedValue({ - json: async () => historyV2Fixture - }) - - it('should fetch from /history_v2 endpoint with default max_items', async () => { - await fetchHistoryV2(mockFetchApi) - - expect(mockFetchApi).toHaveBeenCalledWith('/history_v2?max_items=200') - }) - - it('should fetch with custom max_items parameter', async () => { - await fetchHistoryV2(mockFetchApi, 50) - - expect(mockFetchApi).toHaveBeenCalledWith('/history_v2?max_items=50') - }) - - it('should adapt V2 response to V1-compatible format', async () => { - const result = await fetchHistoryV2(mockFetchApi) - - expect(result.History).toEqual(expectedV1Fixture) - expect(result).toHaveProperty('History') - expect(Array.isArray(result.History)).toBe(true) - result.History.forEach((item) => { - expect(item.taskType).toBe('History') - expect(item.prompt).toHaveLength(5) - }) - }) -}) diff --git a/src/platform/remote/comfyui/history/fetchers/fetchHistoryV2.ts b/src/platform/remote/comfyui/history/fetchers/fetchHistoryV2.ts deleted file mode 100644 index dfe86ece1..000000000 --- a/src/platform/remote/comfyui/history/fetchers/fetchHistoryV2.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @fileoverview V2 History Fetcher - Cloud API with adapter - * @module platform/remote/comfyui/history/fetchers/fetchHistoryV2 - * - * Fetches history from V2 API endpoint and converts to V1 format. - * Used exclusively by cloud distribution. - */ - -import { mapHistoryV2toHistory } from '../adapters/v2ToV1Adapter' -import type { HistoryV1Response } from '../types/historyV1Types' -import type { HistoryResponseV2 } from '../types/historyV2Types' - -/** - * Fetches history from V2 API endpoint and adapts to V1 format - * @param fetchApi - API instance with fetchApi method - * @param maxItems - Maximum number of history items to fetch - * @param offset - Offset for pagination (must be non-negative integer) - * @returns Promise resolving to V1 history response (adapted from V2) - * @throws Error if offset is invalid (negative or non-integer) - */ -export async function fetchHistoryV2( - fetchApi: (url: string) => Promise, - maxItems: number = 200, - offset?: number -): Promise { - // Validate offset parameter - if (offset !== undefined && (offset < 0 || !Number.isInteger(offset))) { - throw new Error( - `Invalid offset parameter: ${offset}. Must be a non-negative integer.` - ) - } - - const params = new URLSearchParams({ max_items: maxItems.toString() }) - if (offset !== undefined) { - params.set('offset', offset.toString()) - } - const url = `/history_v2?${params.toString()}` - const res = await fetchApi(url) - const rawData: HistoryResponseV2 = await res.json() - const adaptedHistory = mapHistoryV2toHistory(rawData) - return { History: adaptedHistory } -} diff --git a/src/platform/remote/comfyui/history/index.ts b/src/platform/remote/comfyui/history/index.ts deleted file mode 100644 index fc96225e4..000000000 --- a/src/platform/remote/comfyui/history/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @fileoverview History API module - Distribution-aware exports - * @module platform/remote/comfyui/history - * - * This module provides a unified history fetching interface that automatically - * uses the correct implementation based on build-time distribution constant. - * - * - Cloud builds: Uses V2 API with adapter (tree-shakes V1 fetcher) - * - Desktop/localhost builds: Uses V1 API directly (tree-shakes V2 fetcher + adapter) - * - * The rest of the application only needs to import from this module and use - * V1 types - all distribution-specific details are encapsulated here. - */ - -import { isCloud } from '@/platform/distribution/types' -import { fetchHistoryV1 } from './fetchers/fetchHistoryV1' -import { fetchHistoryV2 } from './fetchers/fetchHistoryV2' - -/** - * Fetches history using the appropriate API for the current distribution. - * Build-time constant enables dead code elimination - only one implementation - * will be included in the final bundle. - */ -export const fetchHistory = isCloud ? fetchHistoryV2 : fetchHistoryV1 - -/** - * Export only V1 types publicly - consumers don't need to know about V2 - */ -export type * from './types' diff --git a/src/platform/remote/comfyui/history/reconciliation.test.ts b/src/platform/remote/comfyui/history/reconciliation.test.ts deleted file mode 100644 index d7ada5971..000000000 --- a/src/platform/remote/comfyui/history/reconciliation.test.ts +++ /dev/null @@ -1,335 +0,0 @@ -/** - * @fileoverview Tests for history reconciliation (V1 and V2) - */ -import { beforeEach, describe, expect, it, vi } from 'vitest' - -import { reconcileHistory } from '@/platform/remote/comfyui/history/reconciliation' -import type { TaskItem } from '@/schemas/apiSchema' - -// Mock distribution types -vi.mock('@/platform/distribution/types', () => ({ - isCloud: false, - isDesktop: true -})) - -function createHistoryItem(promptId: string, queueIndex = 0): TaskItem { - return { - taskType: 'History', - prompt: [queueIndex, promptId, {}, {}, []], - status: { status_str: 'success', completed: true, messages: [] }, - outputs: {} - } -} - -function getAllPromptIds(result: TaskItem[]): string[] { - return result.map((item) => item.prompt[1]) -} - -describe('reconcileHistory (V1)', () => { - beforeEach(async () => { - const distTypes = await import('@/platform/distribution/types') - vi.mocked(distTypes).isCloud = false - }) - - describe('when filtering by queueIndex', () => { - it('should retain items with queueIndex greater than lastKnownQueueIndex', () => { - const serverHistory = [ - createHistoryItem('new-1', 11), - createHistoryItem('new-2', 10), - createHistoryItem('old', 5) - ] - const clientHistory = [createHistoryItem('old', 5)] - - const result = reconcileHistory(serverHistory, clientHistory, 10, 9) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(3) - expect(promptIds).toContain('new-1') - expect(promptIds).toContain('new-2') - expect(promptIds).toContain('old') - }) - - it('should evict items with queueIndex less than or equal to lastKnownQueueIndex', () => { - const serverHistory = [ - createHistoryItem('new', 11), - createHistoryItem('existing', 10), - createHistoryItem('old-should-not-appear', 5) - ] - const clientHistory = [createHistoryItem('existing', 10)] - - const result = reconcileHistory(serverHistory, clientHistory, 10, 10) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(2) - expect(promptIds).toContain('new') - expect(promptIds).toContain('existing') - expect(promptIds).not.toContain('old-should-not-appear') - }) - - it('should retain all server items when lastKnownQueueIndex is undefined', () => { - const serverHistory = [ - createHistoryItem('item-1', 5), - createHistoryItem('item-2', 4) - ] - - const result = reconcileHistory(serverHistory, [], 10, undefined) - - expect(result).toHaveLength(2) - expect(result[0].prompt[1]).toBe('item-1') - expect(result[1].prompt[1]).toBe('item-2') - }) - }) - - describe('when reconciling with existing client items', () => { - it('should retain client items that still exist on server', () => { - const serverHistory = [ - createHistoryItem('new', 11), - createHistoryItem('existing-1', 9), - createHistoryItem('existing-2', 8) - ] - const clientHistory = [ - createHistoryItem('existing-1', 9), - createHistoryItem('existing-2', 8) - ] - - const result = reconcileHistory(serverHistory, clientHistory, 10, 10) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(3) - expect(promptIds).toContain('new') - expect(promptIds).toContain('existing-1') - expect(promptIds).toContain('existing-2') - }) - - it('should evict client items that no longer exist on server', () => { - const serverHistory = [ - createHistoryItem('new', 11), - createHistoryItem('keep', 9) - ] - const clientHistory = [ - createHistoryItem('keep', 9), - createHistoryItem('removed-from-server', 8) - ] - - const result = reconcileHistory(serverHistory, clientHistory, 10, 10) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(2) - expect(promptIds).toContain('new') - expect(promptIds).toContain('keep') - expect(promptIds).not.toContain('removed-from-server') - }) - }) - - describe('when limiting the result count', () => { - it('should respect the maxItems constraint', () => { - const serverHistory = Array.from({ length: 10 }, (_, i) => - createHistoryItem(`item-${i}`, 20 + i) - ) - - const result = reconcileHistory(serverHistory, [], 5, 15) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(5) - }) - - it('should evict lowest priority items when exceeding capacity', () => { - const serverHistory = [ - createHistoryItem('new-1', 13), - createHistoryItem('new-2', 12), - createHistoryItem('new-3', 11), - createHistoryItem('existing', 9) - ] - const clientHistory = [createHistoryItem('existing', 9)] - - const result = reconcileHistory(serverHistory, clientHistory, 2, 10) - - expect(result).toHaveLength(2) - expect(result[0].prompt[1]).toBe('new-1') - expect(result[1].prompt[1]).toBe('new-2') - }) - }) - - describe('when handling empty collections', () => { - it('should return all server items when client history is empty', () => { - const serverHistory = [ - createHistoryItem('item-1', 10), - createHistoryItem('item-2', 9) - ] - - const result = reconcileHistory(serverHistory, [], 10, 8) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(2) - }) - - it('should return empty result when server history is empty', () => { - const clientHistory = [createHistoryItem('item-1', 5)] - - const result = reconcileHistory([], clientHistory, 10, 5) - - expect(result).toHaveLength(0) - }) - - it('should return empty result when both collections are empty', () => { - const result = reconcileHistory([], [], 10, undefined) - - expect(result).toHaveLength(0) - }) - }) -}) - -describe('reconcileHistory (V2/Cloud)', () => { - beforeEach(async () => { - const distTypes = await import('@/platform/distribution/types') - vi.mocked(distTypes).isCloud = true - }) - - describe('when adding new items from server', () => { - it('should retain items with promptIds not present in client history', () => { - const serverHistory = [ - createHistoryItem('new-item'), - createHistoryItem('existing-item') - ] - const clientHistory = [createHistoryItem('existing-item')] - - const result = reconcileHistory(serverHistory, clientHistory, 10) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(2) - expect(promptIds).toContain('new-item') - expect(promptIds).toContain('existing-item') - }) - - it('should respect priority ordering when retaining multiple new items', () => { - const serverHistory = [ - createHistoryItem('new-1'), - createHistoryItem('new-2'), - createHistoryItem('existing') - ] - const clientHistory = [createHistoryItem('existing')] - - const result = reconcileHistory(serverHistory, clientHistory, 10) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(3) - expect(promptIds).toContain('new-1') - expect(promptIds).toContain('new-2') - expect(promptIds).toContain('existing') - }) - }) - - describe('when reconciling with existing client items', () => { - it('should retain client items that still exist on server', () => { - const serverHistory = [ - createHistoryItem('item-1'), - createHistoryItem('item-2') - ] - const clientHistory = [ - createHistoryItem('item-1'), - createHistoryItem('item-2') - ] - - const result = reconcileHistory(serverHistory, clientHistory, 10) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(2) - expect(promptIds).toContain('item-1') - expect(promptIds).toContain('item-2') - }) - - it('should evict client items that no longer exist on server', () => { - const serverHistory = [createHistoryItem('item-1')] - const clientHistory = [ - createHistoryItem('item-1'), - createHistoryItem('old-item') - ] - - const result = reconcileHistory(serverHistory, clientHistory, 10) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(1) - expect(promptIds).toContain('item-1') - expect(promptIds).not.toContain('old-item') - }) - }) - - describe('when detecting new items by promptId', () => { - it('should retain new items regardless of queueIndex values', () => { - const serverHistory = [ - createHistoryItem('existing', 100), - createHistoryItem('new-item', 50) - ] - const clientHistory = [createHistoryItem('existing', 100)] - - const result = reconcileHistory(serverHistory, clientHistory, 10) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toContain('new-item') - expect(promptIds).toContain('existing') - }) - }) - - describe('when limiting the result count', () => { - it('should respect the maxItems constraint', () => { - const serverHistory = Array.from({ length: 10 }, (_, i) => - createHistoryItem(`server-${i}`) - ) - const clientHistory = Array.from({ length: 5 }, (_, i) => - createHistoryItem(`client-${i}`) - ) - - const result = reconcileHistory(serverHistory, clientHistory, 5) - - const promptIds = getAllPromptIds(result) - expect(promptIds).toHaveLength(5) - }) - - it('should evict lowest priority items when exceeding capacity', () => { - const serverHistory = [ - createHistoryItem('new-1'), - createHistoryItem('new-2'), - createHistoryItem('existing') - ] - const clientHistory = [createHistoryItem('existing')] - - const result = reconcileHistory(serverHistory, clientHistory, 2) - - expect(result).toHaveLength(2) - expect(result[0].prompt[1]).toBe('new-1') - expect(result[1].prompt[1]).toBe('new-2') - }) - }) - - describe('when handling empty collections', () => { - it('should return all server items when client history is empty', () => { - const serverHistory = [ - createHistoryItem('item-1'), - createHistoryItem('item-2') - ] - - const result = reconcileHistory(serverHistory, [], 10) - - expect(result).toHaveLength(2) - expect(result[0].prompt[1]).toBe('item-1') - expect(result[1].prompt[1]).toBe('item-2') - }) - - it('should return empty result when server history is empty', () => { - const clientHistory = [ - createHistoryItem('item-1'), - createHistoryItem('item-2') - ] - - const result = reconcileHistory([], clientHistory, 10) - - expect(result).toHaveLength(0) - }) - - it('should return empty result when both collections are empty', () => { - const result = reconcileHistory([], [], 10) - - expect(result).toHaveLength(0) - }) - }) -}) diff --git a/src/platform/remote/comfyui/history/reconciliation.ts b/src/platform/remote/comfyui/history/reconciliation.ts deleted file mode 100644 index aaf445775..000000000 --- a/src/platform/remote/comfyui/history/reconciliation.ts +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @fileoverview History reconciliation for V1 and V2 APIs - * @module platform/remote/comfyui/history/reconciliation - * - * Returns list of items that should be displayed, sorted by queueIndex (newest first). - * Caller is responsible for mapping to their own class instances. - * - * V1: QueueIndex-based filtering for stable monotonic indices - * V2: PromptId-based merging for synthetic priorities (V2 assigns synthetic - * priorities after timestamp sorting, so new items may have lower priority - * than existing items) - */ -import { isCloud } from '@/platform/distribution/types' -import type { TaskItem } from '@/schemas/apiSchema' - -/** - * V1 reconciliation: QueueIndex-based filtering works because V1 has stable, - * monotonically increasing queue indices. - * - * Sort order: Sorts serverHistory by queueIndex descending (newest first) to ensure - * consistent ordering. JavaScript .filter() maintains iteration order, so filtered - * results remain sorted. clientHistory is assumed already sorted from previous update. - * - * @returns All items to display, sorted by queueIndex descending (newest first) - */ -function reconcileHistoryV1( - serverHistory: TaskItem[], - clientHistory: TaskItem[], - maxItems: number, - lastKnownQueueIndex: number | undefined -): TaskItem[] { - const sortedServerHistory = serverHistory.sort( - (a, b) => b.prompt[0] - a.prompt[0] - ) - - const serverPromptIds = new Set( - sortedServerHistory.map((item) => item.prompt[1]) - ) - - // If undefined, treat as initial sync (all items are new) - const itemsAddedSinceLastSync = - lastKnownQueueIndex === undefined - ? sortedServerHistory - : sortedServerHistory.filter( - (item) => item.prompt[0] > lastKnownQueueIndex - ) - - const clientItemsStillOnServer = clientHistory.filter((item) => - serverPromptIds.has(item.prompt[1]) - ) - - // Merge new and reused items, sort by queueIndex descending, limit to maxItems - return [...itemsAddedSinceLastSync, ...clientItemsStillOnServer] - .sort((a, b) => b.prompt[0] - a.prompt[0]) - .slice(0, maxItems) -} - -/** - * V2 reconciliation: PromptId-based merging because V2 assigns synthetic - * priorities after sorting by timestamp. - * - * Sort order: Sorts serverHistory by queueIndex descending (newest first) to ensure - * consistent ordering. JavaScript .filter() maintains iteration order, so filtered - * results remain sorted. clientHistory is assumed already sorted from previous update. - * - * @returns All items to display, sorted by queueIndex descending (newest first) - */ -function reconcileHistoryV2( - serverHistory: TaskItem[], - clientHistory: TaskItem[], - maxItems: number -): TaskItem[] { - const sortedServerHistory = serverHistory.sort( - (a, b) => b.prompt[0] - a.prompt[0] - ) - - const serverPromptIds = new Set( - sortedServerHistory.map((item) => item.prompt[1]) - ) - const clientPromptIds = new Set(clientHistory.map((item) => item.prompt[1])) - - const newItems = sortedServerHistory.filter( - (item) => !clientPromptIds.has(item.prompt[1]) - ) - - const clientItemsStillOnServer = clientHistory.filter((item) => - serverPromptIds.has(item.prompt[1]) - ) - - // Merge new and reused items, sort by queueIndex descending, limit to maxItems - return [...newItems, ...clientItemsStillOnServer] - .sort((a, b) => b.prompt[0] - a.prompt[0]) - .slice(0, maxItems) -} - -/** - * Reconciles server history with client history. - * Automatically uses V1 (queueIndex-based) or V2 (promptId-based) algorithm based on - * distribution type. - * - * @param serverHistory - Server's current history items - * @param clientHistory - Client's existing history items - * @param maxItems - Maximum number of items to return - * @param lastKnownQueueIndex - Last queue index seen (V1 only, optional for V2) - * @returns All items that should be displayed, sorted by queueIndex descending - */ -export function reconcileHistory( - serverHistory: TaskItem[], - clientHistory: TaskItem[], - maxItems: number, - lastKnownQueueIndex?: number -): TaskItem[] { - if (isCloud) { - return reconcileHistoryV2(serverHistory, clientHistory, maxItems) - } - return reconcileHistoryV1( - serverHistory, - clientHistory, - maxItems, - lastKnownQueueIndex - ) -} diff --git a/src/platform/remote/comfyui/history/types/historyV1Types.ts b/src/platform/remote/comfyui/history/types/historyV1Types.ts deleted file mode 100644 index f7bff7a84..000000000 --- a/src/platform/remote/comfyui/history/types/historyV1Types.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @fileoverview History V1 types - Public interface used throughout the app - * @module platform/remote/comfyui/history/types/historyV1Types - * - * These types represent the V1 history format that the application expects. - * Both desktop (direct V1 API) and cloud (V2 API + adapter) return data in this format. - */ - -import type { HistoryTaskItem, TaskPrompt } from '@/schemas/apiSchema' - -export interface HistoryV1Response { - History: HistoryTaskItem[] -} - -export type { HistoryTaskItem, TaskPrompt } diff --git a/src/platform/remote/comfyui/history/types/historyV2Types.ts b/src/platform/remote/comfyui/history/types/historyV2Types.ts deleted file mode 100644 index 08580edb9..000000000 --- a/src/platform/remote/comfyui/history/types/historyV2Types.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @fileoverview History V2 types and schemas - Internal cloud API format - * @module platform/remote/comfyui/history/types/historyV2Types - * - * These types and schemas represent the V2 history format returned by the cloud API. - * They are only used internally and are converted to V1 format via adapter. - * - * IMPORTANT: These types should NOT be used outside this history module. - */ - -import { z } from 'zod' - -import { - zExtraData, - zPromptId, - zQueueIndex, - zStatus, - zTaskMeta, - zTaskOutput -} from '@/schemas/apiSchema' - -const zTaskPromptV2 = z.object({ - priority: zQueueIndex, - prompt_id: zPromptId, - extra_data: zExtraData -}) - -const zRawHistoryItemV2 = z.object({ - prompt_id: zPromptId, - prompt: zTaskPromptV2, - status: zStatus.optional(), - outputs: zTaskOutput, - meta: zTaskMeta.optional(), - create_time: z.number().int().optional() -}) - -const zHistoryResponseV2 = z.object({ - history: z.array(zRawHistoryItemV2) -}) - -export type TaskPromptV2 = z.infer -export type RawHistoryItemV2 = z.infer -export type HistoryResponseV2 = z.infer -export type TaskOutput = z.infer - -export { zRawHistoryItemV2 } diff --git a/src/platform/remote/comfyui/history/types/index.ts b/src/platform/remote/comfyui/history/types/index.ts deleted file mode 100644 index d49f66ffe..000000000 --- a/src/platform/remote/comfyui/history/types/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @fileoverview Public history types export - * @module platform/remote/comfyui/history/types - * - * Only V1 types are exported publicly - the rest of the app - * should never need to know about V2 types or implementation details. - */ - -export type * from './historyV1Types' diff --git a/src/platform/remote/comfyui/jobs/fetchJobs.test.ts b/src/platform/remote/comfyui/jobs/fetchJobs.test.ts index 56f7fdef6..ec32cb3b3 100644 --- a/src/platform/remote/comfyui/jobs/fetchJobs.test.ts +++ b/src/platform/remote/comfyui/jobs/fetchJobs.test.ts @@ -16,17 +16,13 @@ type JobsListResponse = z.infer function createMockJob( id: string, - status: 'pending' | 'in_progress' | 'completed' = 'completed', + status: 'pending' | 'in_progress' | 'completed' | 'failed' = 'completed', overrides: Partial = {} ): RawJobListItem { return { id, status, create_time: Date.now(), - execution_start_time: null, - execution_end_time: null, - preview_output: null, - outputs_count: 0, ...overrides } } @@ -63,7 +59,7 @@ describe('fetchJobs', () => { const result = await fetchHistory(mockFetch) expect(mockFetch).toHaveBeenCalledWith( - '/jobs?status=completed&limit=200&offset=0' + '/jobs?status=completed,failed,cancelled&limit=200&offset=0' ) expect(result).toHaveLength(2) expect(result[0].id).toBe('job1') @@ -113,7 +109,7 @@ describe('fetchJobs', () => { const result = await fetchHistory(mockFetch, 200, 5) expect(mockFetch).toHaveBeenCalledWith( - '/jobs?status=completed&limit=200&offset=5' + '/jobs?status=completed,failed,cancelled&limit=200&offset=5' ) // Priority base is total - offset = 10 - 5 = 5 expect(result[0].priority).toBe(5) // (total - offset) - 0 diff --git a/src/platform/remote/comfyui/jobs/fetchJobs.ts b/src/platform/remote/comfyui/jobs/fetchJobs.ts index f5facceff..defaed16c 100644 --- a/src/platform/remote/comfyui/jobs/fetchJobs.ts +++ b/src/platform/remote/comfyui/jobs/fetchJobs.ts @@ -68,7 +68,7 @@ function assignPriority( } /** - * Fetches history (completed jobs) + * Fetches history (terminal state jobs: completed, failed, cancelled) * Assigns synthetic priority starting from total (lower than queue jobs). */ export async function fetchHistory( @@ -78,7 +78,7 @@ export async function fetchHistory( ): Promise { const { jobs, total } = await fetchJobsRaw( fetchApi, - ['completed'], + ['completed', 'failed', 'cancelled'], maxItems, offset ) diff --git a/src/platform/remote/comfyui/jobs/jobTypes.ts b/src/platform/remote/comfyui/jobs/jobTypes.ts index 855348309..48e2bfbc4 100644 --- a/src/platform/remote/comfyui/jobs/jobTypes.ts +++ b/src/platform/remote/comfyui/jobs/jobTypes.ts @@ -21,12 +21,15 @@ const zJobStatus = z.enum([ const zPreviewOutput = z.object({ filename: z.string(), subfolder: z.string(), - type: resultItemType + type: resultItemType, + nodeId: z.string(), + mediaType: z.string() }) /** - * Execution error details for error jobs. - * Contains the same structure as ExecutionErrorWsMessage from WebSocket. + * Execution error from Jobs API. + * Similar to ExecutionErrorWsMessage but with optional prompt_id/timestamp/executed + * since these may not be present in stored errors or infrastructure-generated errors. */ const zExecutionError = z .object({ @@ -43,6 +46,8 @@ const zExecutionError = z }) .passthrough() +export type ExecutionError = z.infer + /** * Raw job from API - uses passthrough to allow extra fields */ @@ -105,3 +110,9 @@ export type RawJobListItem = z.infer /** Job list item with priority always set (server-provided or synthetic) */ export type JobListItem = RawJobListItem & { priority: number } export type JobDetail = z.infer + +/** Task type used in the API (queue vs history endpoints) */ +export type APITaskType = 'queue' | 'history' + +/** Internal task type derived from job status for UI display */ +export type TaskType = 'Running' | 'Pending' | 'History' diff --git a/src/platform/workflow/cloud/getWorkflowFromHistory.test.ts b/src/platform/workflow/cloud/getWorkflowFromHistory.test.ts index fede0e864..8102a711c 100644 --- a/src/platform/workflow/cloud/getWorkflowFromHistory.test.ts +++ b/src/platform/workflow/cloud/getWorkflowFromHistory.test.ts @@ -1,11 +1,13 @@ import { describe, expect, it, vi } from 'vitest' +import type { JobDetail } from '@/platform/remote/comfyui/jobs/jobTypes' import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema' -import { getWorkflowFromHistory } from '@/platform/workflow/cloud/getWorkflowFromHistory' +import { + extractWorkflow, + fetchJobDetail +} from '@/platform/remote/comfyui/jobs/fetchJobs' const mockWorkflow: ComfyWorkflowJSON = { - id: 'test-workflow-id', - revision: 0, last_node_id: 5, last_link_id: 3, nodes: [], @@ -16,75 +18,63 @@ const mockWorkflow: ComfyWorkflowJSON = { version: 0.4 } -const mockHistoryResponse = { - 'test-prompt-id': { - prompt: { - priority: 1, - prompt_id: 'test-prompt-id', - extra_data: { - client_id: 'test-client', - extra_pnginfo: { - workflow: mockWorkflow - } +// Jobs API detail response structure (matches actual /jobs/{id} response) +// workflow is nested at: workflow.extra_data.extra_pnginfo.workflow +const mockJobDetailResponse: JobDetail = { + id: 'test-prompt-id', + status: 'completed', + create_time: 1234567890, + update_time: 1234567900, + workflow: { + extra_data: { + extra_pnginfo: { + workflow: mockWorkflow } - }, - outputs: {}, - status: { - status_str: 'success', - completed: true, - messages: [] + } + }, + outputs: { + '20': { + images: [ + { filename: 'test.png', subfolder: '', type: 'output' }, + { filename: 'test2.png', subfolder: '', type: 'output' } + ] } } } -describe('getWorkflowFromHistory', () => { - it('should fetch workflow from /history_v2/{prompt_id} endpoint', async () => { +describe('fetchJobDetail', () => { + it('should fetch job detail from /jobs/{prompt_id} endpoint', async () => { const mockFetchApi = vi.fn().mockResolvedValue({ - json: async () => mockHistoryResponse + ok: true, + json: async () => mockJobDetailResponse }) - await getWorkflowFromHistory(mockFetchApi, 'test-prompt-id') + await fetchJobDetail(mockFetchApi, 'test-prompt-id') - expect(mockFetchApi).toHaveBeenCalledWith('/history_v2/test-prompt-id') + expect(mockFetchApi).toHaveBeenCalledWith('/jobs/test-prompt-id') }) - it('should extract and return workflow from response', async () => { + it('should return job detail with workflow and outputs', async () => { const mockFetchApi = vi.fn().mockResolvedValue({ - json: async () => mockHistoryResponse + ok: true, + json: async () => mockJobDetailResponse }) - const result = await getWorkflowFromHistory(mockFetchApi, 'test-prompt-id') + const result = await fetchJobDetail(mockFetchApi, 'test-prompt-id') - expect(result).toEqual(mockWorkflow) + expect(result).toBeDefined() + expect(result?.id).toBe('test-prompt-id') + expect(result?.outputs).toEqual(mockJobDetailResponse.outputs) + expect(result?.workflow).toBeDefined() }) - it('should return undefined when prompt_id not found in response', async () => { + it('should return undefined when job not found (non-OK response)', async () => { const mockFetchApi = vi.fn().mockResolvedValue({ - json: async () => ({}) + ok: false, + status: 404 }) - const result = await getWorkflowFromHistory(mockFetchApi, 'nonexistent-id') - - expect(result).toBeUndefined() - }) - - it('should return undefined when workflow is missing from extra_pnginfo', async () => { - const mockFetchApi = vi.fn().mockResolvedValue({ - json: async () => ({ - 'test-prompt-id': { - prompt: { - priority: 1, - prompt_id: 'test-prompt-id', - extra_data: { - client_id: 'test-client' - } - }, - outputs: {} - } - }) - }) - - const result = await getWorkflowFromHistory(mockFetchApi, 'test-prompt-id') + const result = await fetchJobDetail(mockFetchApi, 'nonexistent-id') expect(result).toBeUndefined() }) @@ -92,19 +82,45 @@ describe('getWorkflowFromHistory', () => { it('should handle fetch errors gracefully', async () => { const mockFetchApi = vi.fn().mockRejectedValue(new Error('Network error')) - const result = await getWorkflowFromHistory(mockFetchApi, 'test-prompt-id') + const result = await fetchJobDetail(mockFetchApi, 'test-prompt-id') expect(result).toBeUndefined() }) it('should handle malformed JSON responses', async () => { const mockFetchApi = vi.fn().mockResolvedValue({ + ok: true, json: async () => { throw new Error('Invalid JSON') } }) - const result = await getWorkflowFromHistory(mockFetchApi, 'test-prompt-id') + const result = await fetchJobDetail(mockFetchApi, 'test-prompt-id') + + expect(result).toBeUndefined() + }) +}) + +describe('extractWorkflow', () => { + it('should extract workflow from job detail', async () => { + const result = await extractWorkflow(mockJobDetailResponse) + + expect(result).toEqual(mockWorkflow) + }) + + it('should return undefined when job is undefined', async () => { + const result = await extractWorkflow(undefined) + + expect(result).toBeUndefined() + }) + + it('should return undefined when workflow is missing', async () => { + const jobWithoutWorkflow: JobDetail = { + ...mockJobDetailResponse, + workflow: {} + } + + const result = await extractWorkflow(jobWithoutWorkflow) expect(result).toBeUndefined() }) diff --git a/src/platform/workflow/cloud/getWorkflowFromHistory.ts b/src/platform/workflow/cloud/getWorkflowFromHistory.ts deleted file mode 100644 index 8c9027e30..000000000 --- a/src/platform/workflow/cloud/getWorkflowFromHistory.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema' -import type { PromptId } from '@/schemas/apiSchema' - -export async function getWorkflowFromHistory( - fetchApi: (url: string) => Promise, - promptId: PromptId -): Promise { - try { - const res = await fetchApi(`/history_v2/${promptId}`) - const json = await res.json() - - const historyItem = json[promptId] - if (!historyItem) return undefined - - const workflow = historyItem.prompt?.extra_data?.extra_pnginfo?.workflow - return workflow ?? undefined - } catch (error) { - console.error(`Failed to fetch workflow for prompt ${promptId}:`, error) - return undefined - } -} diff --git a/src/platform/workflow/cloud/index.ts b/src/platform/workflow/cloud/index.ts deleted file mode 100644 index 1f5422402..000000000 --- a/src/platform/workflow/cloud/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Cloud: Fetches workflow by prompt_id. Desktop: Returns undefined (workflows already in history). - */ -import { isCloud } from '@/platform/distribution/types' - -import { getWorkflowFromHistory as cloudImpl } from './getWorkflowFromHistory' - -export const getWorkflowFromHistory = isCloud - ? cloudImpl - : async () => undefined diff --git a/src/platform/workflow/utils/workflowExtractionUtil.ts b/src/platform/workflow/utils/workflowExtractionUtil.ts index 88a17af5d..f7f812d58 100644 --- a/src/platform/workflow/utils/workflowExtractionUtil.ts +++ b/src/platform/workflow/utils/workflowExtractionUtil.ts @@ -8,17 +8,18 @@ import type { AssetItem } from '@/platform/assets/schemas/assetSchema' import { getOutputAssetMetadata } from '@/platform/assets/schemas/assetMetadataSchema' import { getAssetUrl } from '@/platform/assets/utils/assetUrlUtil' import { getWorkflowDataFromFile } from '@/scripts/metadata/parser' +import { getJobWorkflow } from '@/services/jobOutputCache' /** - * Extract workflow from AssetItem (async - may need file fetch) - * Tries metadata first (for output assets), then falls back to extracting from file - * This supports both output assets (with embedded metadata) and input assets (PNG with workflow) + * Extract workflow from AssetItem using jobs API + * For output assets: uses jobs API (getJobWorkflow) + * For input assets: extracts from file metadata * * @param asset The asset item to extract workflow from * @returns WorkflowSource with workflow and generated filename * * @example - * const asset = { name: 'output.png', user_metadata: { workflow: {...} } } + * const asset = { name: 'output.png', user_metadata: { promptId: '123' } } * const { workflow, filename } = await extractWorkflowFromAsset(asset) */ export async function extractWorkflowFromAsset(asset: AssetItem): Promise<{ @@ -27,17 +28,14 @@ export async function extractWorkflowFromAsset(asset: AssetItem): Promise<{ }> { const baseFilename = asset.name.replace(/\.[^/.]+$/, '.json') - // Strategy 1: Try metadata first (for output assets) + // For output assets: use jobs API (with caching and validation) const metadata = getOutputAssetMetadata(asset.user_metadata) - if (metadata?.workflow) { - return { - workflow: metadata.workflow as ComfyWorkflowJSON, - filename: baseFilename - } + if (metadata?.promptId) { + const workflow = await getJobWorkflow(metadata.promptId) + return { workflow: workflow ?? null, filename: baseFilename } } - // Strategy 2: Try extracting from file (for input assets with embedded workflow) - // This supports PNG, WEBP, FLAC, and other formats with metadata + // For input assets: extract from file metadata (PNG/WEBP/FLAC with embedded workflow) try { const fileUrl = getAssetUrl(asset) const response = await fetch(fileUrl) diff --git a/src/schemas/apiSchema.ts b/src/schemas/apiSchema.ts index 1d2d5e80b..64b0b5208 100644 --- a/src/schemas/apiSchema.ts +++ b/src/schemas/apiSchema.ts @@ -1,18 +1,14 @@ import { z } from 'zod' import { LinkMarkerShape } from '@/lib/litegraph/src/litegraph' -import { - zComfyWorkflow, - zNodeId -} from '@/platform/workflow/validation/schemas/workflowSchema' +import { zNodeId } from '@/platform/workflow/validation/schemas/workflowSchema' import { colorPalettesSchema } from '@/schemas/colorPaletteSchema' import { zKeybinding } from '@/schemas/keyBindingSchema' import { NodeBadgeMode } from '@/types/nodeSource' import { LinkReleaseTriggerAction } from '@/types/searchBoxTypes' const zNodeType = z.string() -export const zQueueIndex = z.number() -export const zPromptId = z.string() +const zPromptId = z.string() export type PromptId = z.infer export const resultItemType = z.enum(['input', 'output', 'temp']) export type ResultItemType = z.infer @@ -173,136 +169,9 @@ export type AssetDownloadWsMessage = z.infer export type NotificationWsMessage = z.infer -const zPromptInputItem = z.object({ - inputs: z.record(z.string(), z.any()), - class_type: zNodeType -}) - -const zPromptInputs = z.record(zPromptInputItem) - -const zExtraPngInfo = z - .object({ - workflow: zComfyWorkflow - }) - .passthrough() - -export const zExtraData = z - .object({ - /** extra_pnginfo can be missing is backend execution gets a validation error. */ - extra_pnginfo: zExtraPngInfo.optional(), - client_id: z.string().optional(), - // Cloud/Adapters: creation time in milliseconds when available - create_time: z.number().int().optional() - }) - // Allow backend/adapters/extensions to add arbitrary metadata - .passthrough() -const zOutputsToExecute = z.array(zNodeId) - -const zExecutionStartMessage = z.tuple([ - z.literal('execution_start'), - zExecutionStartWsMessage -]) - -const zExecutionSuccessMessage = z.tuple([ - z.literal('execution_success'), - zExecutionSuccessWsMessage -]) - -const zExecutionCachedMessage = z.tuple([ - z.literal('execution_cached'), - zExecutionCachedWsMessage -]) - -const zExecutionInterruptedMessage = z.tuple([ - z.literal('execution_interrupted'), - zExecutionInterruptedWsMessage -]) - -const zExecutionErrorMessage = z.tuple([ - z.literal('execution_error'), - zExecutionErrorWsMessage -]) - -const zStatusMessage = z.union([ - zExecutionStartMessage, - zExecutionSuccessMessage, - zExecutionCachedMessage, - zExecutionInterruptedMessage, - zExecutionErrorMessage -]) - -export const zStatus = z.object({ - status_str: z.enum(['success', 'error']), - completed: z.boolean(), - messages: z.array(zStatusMessage) -}) - -const zTaskPrompt = z.tuple([ - zQueueIndex, - zPromptId, - zPromptInputs, - zExtraData, - zOutputsToExecute -]) - -const zRunningTaskItem = z.object({ - taskType: z.literal('Running'), - prompt: zTaskPrompt, - // @Deprecated - remove: z.object({ - name: z.literal('Cancel'), - cb: z.function() - }) -}) - -const zPendingTaskItem = z.object({ - taskType: z.literal('Pending'), - prompt: zTaskPrompt -}) - export const zTaskOutput = z.record(zNodeId, zOutputs) - -const zNodeOutputsMeta = z.object({ - node_id: zNodeId, - display_node: zNodeId, - prompt_id: zPromptId.optional(), - read_node_id: zNodeId.optional() -}) - -export const zTaskMeta = z.record(zNodeId, zNodeOutputsMeta) - -const zHistoryTaskItem = z.object({ - taskType: z.literal('History'), - prompt: zTaskPrompt, - status: zStatus.optional(), - outputs: zTaskOutput, - meta: zTaskMeta.optional() -}) - -const zTaskItem = z.union([ - zRunningTaskItem, - zPendingTaskItem, - zHistoryTaskItem -]) - -const zTaskType = z.union([ - z.literal('Running'), - z.literal('Pending'), - z.literal('History') -]) - -export type TaskType = z.infer -export type TaskPrompt = z.infer -export type TaskStatus = z.infer export type TaskOutput = z.infer -// `/queue` -export type RunningTaskItem = z.infer -export type PendingTaskItem = z.infer -// `/history` -export type HistoryTaskItem = z.infer -export type TaskItem = z.infer - const zEmbeddingsResponse = z.array(z.string()) const zExtensionsResponse = z.array(z.string()) const zError = z.object({ diff --git a/src/scripts/api.ts b/src/scripts/api.ts index 822773c0d..67f98826e 100644 --- a/src/scripts/api.ts +++ b/src/scripts/api.ts @@ -10,6 +10,7 @@ import type { } from '@/platform/assets/schemas/assetSchema' import { isCloud } from '@/platform/distribution/types' import { useToastStore } from '@/platform/updates/common/toastStore' +import type { IFuseOptions } from 'fuse.js' import { type TemplateInfo, type WorkflowTemplates @@ -31,16 +32,13 @@ import type { ExecutionSuccessWsMessage, ExtensionsResponse, FeatureFlagsWsMessage, - HistoryTaskItem, LogsRawResponse, LogsWsMessage, NotificationWsMessage, - PendingTaskItem, ProgressStateWsMessage, ProgressTextWsMessage, ProgressWsMessage, PromptResponse, - RunningTaskItem, Settings, StatusWsMessage, StatusWsMessageStatus, @@ -49,12 +47,19 @@ import type { UserDataFullInfo, PreviewMethod } from '@/schemas/apiSchema' +import type { + JobDetail, + JobListItem +} from '@/platform/remote/comfyui/jobs/jobTypes' import type { ComfyNodeDef } from '@/schemas/nodeDefSchema' import type { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' import type { AuthHeader } from '@/types/authTypes' import type { NodeExecutionId } from '@/types/nodeIdentification' -import { fetchHistory } from '@/platform/remote/comfyui/history' -import type { IFuseOptions } from 'fuse.js' +import { + fetchHistory, + fetchJobDetail, + fetchQueue +} from '@/platform/remote/comfyui/jobs/fetchJobs' interface QueuePromptRequestBody { client_id: string @@ -670,7 +675,6 @@ export class ComfyApi extends EventTarget { case 'logs': case 'b_preview': case 'notification': - case 'asset_download': this.dispatchCustomEvent(msg.type, msg.data) break case 'feature_flags': @@ -893,53 +897,13 @@ export class ComfyApi extends EventTarget { * @returns The currently running and queued items */ async getQueue(): Promise<{ - Running: RunningTaskItem[] - Pending: PendingTaskItem[] + Running: JobListItem[] + Pending: JobListItem[] }> { try { - const res = await this.fetchApi('/queue') - const data = await res.json() - // Normalize queue tuple shape across backends: - // - Backend (V1): [idx, prompt_id, inputs, extra_data(object), outputs_to_execute(array)] - // - Cloud: [idx, prompt_id, inputs, outputs_to_execute(array), metadata(object{create_time})] - const normalizeQueuePrompt = (prompt: any): any => { - if (!Array.isArray(prompt)) return prompt - // Ensure 5-tuple - const p = prompt.slice(0, 5) - const fourth = p[3] - const fifth = p[4] - // Cloud shape: 4th is array, 5th is metadata object - if ( - Array.isArray(fourth) && - fifth && - typeof fifth === 'object' && - !Array.isArray(fifth) - ) { - const meta: any = fifth - const extraData = { ...meta } - return [p[0], p[1], p[2], extraData, fourth] - } - // V1 shape already: return as-is - return p - } - return { - // Running action uses a different endpoint for cancelling - Running: data.queue_running.map((prompt: any) => { - const np = normalizeQueuePrompt(prompt) - return { - taskType: 'Running', - prompt: np, - // prompt[1] is the prompt id - remove: { name: 'Cancel', cb: () => api.interrupt(np[1]) } - } - }), - Pending: data.queue_pending.map((prompt: any) => ({ - taskType: 'Pending', - prompt: normalizeQueuePrompt(prompt) - })) - } + return await fetchQueue(this.fetchApi.bind(this)) } catch (error) { - console.error(error) + console.error('Failed to fetch queue:', error) return { Running: [], Pending: [] } } } @@ -951,7 +915,7 @@ export class ComfyApi extends EventTarget { async getHistory( max_items: number = 200, options?: { offset?: number } - ): Promise<{ History: HistoryTaskItem[] }> { + ): Promise { try { return await fetchHistory( this.fetchApi.bind(this), @@ -960,10 +924,19 @@ export class ComfyApi extends EventTarget { ) } catch (error) { console.error(error) - return { History: [] } + return [] } } + /** + * Gets detailed job info including outputs and workflow + * @param jobId The job/prompt ID + * @returns Full job details or undefined if not found + */ + async getJobDetail(jobId: string): Promise { + return fetchJobDetail(this.fetchApi.bind(this), jobId) + } + /** * Gets system & device stats * @returns System stats such as python version, OS, per device info @@ -1273,29 +1246,6 @@ export class ComfyApi extends EventTarget { } } - /** - * Gets the Fuse options from the server. - * - * @returns The Fuse options, or null if not found or invalid - */ - async getFuseOptions(): Promise | null> { - try { - const res = await axios.get( - this.fileURL('/templates/fuse_options.json'), - { - headers: { - 'Content-Type': 'application/json' - } - } - ) - const contentType = res.headers['content-type'] - return contentType?.includes('application/json') ? res.data : null - } catch (error) { - console.error('Error loading fuse options:', error) - return null - } - } - /** * Gets the custom nodes i18n data from the server. * @@ -1331,6 +1281,24 @@ export class ComfyApi extends EventTarget { getServerFeatures(): Record { return { ...this.serverFeatureFlags } } + + async getFuseOptions(): Promise | null> { + try { + const res = await axios.get( + this.fileURL('/templates/fuse_options.json'), + { + headers: { + 'Content-Type': 'application/json' + } + } + ) + const contentType = res.headers['content-type'] + return contentType?.includes('application/json') ? res.data : null + } catch (error) { + console.error('Error loading fuse options:', error) + return null + } + } } export const api = new ComfyApi() diff --git a/src/scripts/ui.ts b/src/scripts/ui.ts index 6a428c974..9a0f9d5cc 100644 --- a/src/scripts/ui.ts +++ b/src/scripts/ui.ts @@ -1,6 +1,6 @@ import { useSettingStore } from '@/platform/settings/settingStore' import { WORKFLOW_ACCEPT_STRING } from '@/platform/workflow/core/types/formats' -import { type StatusWsMessageStatus, type TaskItem } from '@/schemas/apiSchema' +import { type StatusWsMessageStatus } from '@/schemas/apiSchema' import { useDialogService } from '@/services/dialogService' import { isCloud } from '@/platform/distribution/types' import { useTelemetry } from '@/platform/telemetry' @@ -33,6 +33,17 @@ type Props = { type Children = Element[] | Element | string | string[] +/** + * @deprecated Legacy queue item structure from old history API. + * Will be removed when ComfyList is migrated to Jobs API. + */ +interface LegacyQueueItem { + prompt: [unknown, string, unknown, { extra_pnginfo: { workflow: unknown } }] + outputs?: Record + meta?: Record + remove?: { name: string; cb: () => Promise | void } +} + type ElementType = K extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[K] : HTMLElement @@ -259,29 +270,28 @@ class ComfyList { $el('div.comfy-list-items', [ // @ts-expect-error fixme ts strict error ...(this.#reverse ? items[section].reverse() : items[section]).map( - (item: TaskItem) => { + (item: LegacyQueueItem) => { // Allow items to specify a custom remove action (e.g. for interrupt current prompt) - const removeAction = - 'remove' in item - ? item.remove - : { - name: 'Delete', - cb: () => api.deleteItem(this.#type, item.prompt[1]) - } + const removeAction = item.remove ?? { + name: 'Delete', + cb: () => api.deleteItem(this.#type, item.prompt[1]) + } return $el('div', { textContent: item.prompt[0] + ': ' }, [ $el('button', { textContent: 'Load', onclick: async () => { await app.loadGraphData( - // @ts-expect-error fixme ts strict error - item.prompt[3].extra_pnginfo.workflow, + item.prompt[3].extra_pnginfo.workflow as Parameters< + typeof app.loadGraphData + >[0], true, false ) - if ('outputs' in item) { + if ('outputs' in item && item.outputs) { app.nodeOutputs = {} for (const [key, value] of Object.entries(item.outputs)) { const realKey = item['meta']?.[key]?.display_node ?? key + // @ts-expect-error fixme ts strict error app.nodeOutputs[realKey] = value } } diff --git a/src/services/dialogService.ts b/src/services/dialogService.ts index 8629e2dd8..50b0223ce 100644 --- a/src/services/dialogService.ts +++ b/src/services/dialogService.ts @@ -19,7 +19,6 @@ import { useTelemetry } from '@/platform/telemetry' import { isCloud } from '@/platform/distribution/types' import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription' import SettingDialogContent from '@/platform/settings/components/SettingDialogContent.vue' -import type { ExecutionErrorWsMessage } from '@/schemas/apiSchema' import { useDialogStore } from '@/stores/dialogStore' import type { DialogComponentProps, @@ -45,6 +44,18 @@ export type ConfirmationDialogType = | 'dirtyClose' | 'reinstall' +/** + * Minimal interface for execution error dialogs. + * Satisfied by both ExecutionErrorWsMessage (WebSocket) and ExecutionError (Jobs API). + */ +export interface ExecutionErrorDialogInput { + exception_type: string + exception_message: string + node_id: string | number + node_type: string + traceback: string[] +} + export const useDialogService = () => { const dialogStore = useDialogStore() @@ -115,7 +126,7 @@ export const useDialogService = () => { }) } - function showExecutionErrorDialog(executionError: ExecutionErrorWsMessage) { + function showExecutionErrorDialog(executionError: ExecutionErrorDialogInput) { const props: ComponentAttrs = { error: { exceptionType: executionError.exception_type, diff --git a/src/services/jobOutputCache.test.ts b/src/services/jobOutputCache.test.ts new file mode 100644 index 000000000..38e47e973 --- /dev/null +++ b/src/services/jobOutputCache.test.ts @@ -0,0 +1,278 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +import type { + JobDetail, + JobListItem +} from '@/platform/remote/comfyui/jobs/jobTypes' +import { ResultItemImpl, TaskItemImpl } from '@/stores/queueStore' + +vi.mock('@/platform/remote/comfyui/jobs/fetchJobs', () => ({ + fetchJobDetail: vi.fn(), + extractWorkflow: vi.fn() +})) + +function createResultItem(url: string, supportsPreview = true): ResultItemImpl { + const item = new ResultItemImpl({ + filename: url, + subfolder: '', + type: 'output', + nodeId: 'node-1', + mediaType: supportsPreview ? 'images' : 'unknown' + }) + Object.defineProperty(item, 'url', { get: () => url }) + Object.defineProperty(item, 'supportsPreview', { get: () => supportsPreview }) + return item +} + +function createMockJob(id: string, outputsCount = 1): JobListItem { + return { + id, + status: 'completed', + create_time: Date.now(), + preview_output: null, + outputs_count: outputsCount, + priority: 0 + } +} + +function createTask( + preview?: ResultItemImpl, + allOutputs?: ResultItemImpl[], + outputsCount = 1 +): TaskItemImpl { + const job = createMockJob( + `task-${Math.random().toString(36).slice(2)}`, + outputsCount + ) + const flatOutputs = allOutputs ?? (preview ? [preview] : []) + return new TaskItemImpl(job, {}, flatOutputs) +} + +describe('jobOutputCache', () => { + beforeEach(() => { + vi.resetModules() + vi.clearAllMocks() + }) + + describe('findActiveIndex', () => { + it('returns index of matching URL', async () => { + const { findActiveIndex } = await import('@/services/jobOutputCache') + const items = [ + createResultItem('a'), + createResultItem('b'), + createResultItem('c') + ] + + expect(findActiveIndex(items, 'b')).toBe(1) + }) + + it('returns 0 when URL not found', async () => { + const { findActiveIndex } = await import('@/services/jobOutputCache') + const items = [createResultItem('a'), createResultItem('b')] + + expect(findActiveIndex(items, 'missing')).toBe(0) + }) + + it('returns 0 when URL is undefined', async () => { + const { findActiveIndex } = await import('@/services/jobOutputCache') + const items = [createResultItem('a'), createResultItem('b')] + + expect(findActiveIndex(items, undefined)).toBe(0) + }) + }) + + describe('getOutputsForTask', () => { + it('returns previewable outputs directly when no lazy load needed', async () => { + const { getOutputsForTask } = await import('@/services/jobOutputCache') + const outputs = [createResultItem('p-1'), createResultItem('p-2')] + const task = createTask(undefined, outputs, 1) + + const result = await getOutputsForTask(task) + + expect(result).toEqual(outputs) + }) + + it('lazy loads when outputsCount > 1', async () => { + const { getOutputsForTask } = await import('@/services/jobOutputCache') + const previewOutput = createResultItem('preview') + const fullOutputs = [ + createResultItem('full-1'), + createResultItem('full-2') + ] + + const job = createMockJob('task-1', 3) + const task = new TaskItemImpl(job, {}, [previewOutput]) + const loadedTask = new TaskItemImpl(job, {}, fullOutputs) + task.loadFullOutputs = vi.fn().mockResolvedValue(loadedTask) + + const result = await getOutputsForTask(task) + + expect(result).toEqual(fullOutputs) + expect(task.loadFullOutputs).toHaveBeenCalled() + }) + + it('caches loaded tasks', async () => { + const { getOutputsForTask } = await import('@/services/jobOutputCache') + const fullOutputs = [createResultItem('full-1')] + + const job = createMockJob('task-1', 3) + const task = new TaskItemImpl(job, {}, [createResultItem('preview')]) + const loadedTask = new TaskItemImpl(job, {}, fullOutputs) + task.loadFullOutputs = vi.fn().mockResolvedValue(loadedTask) + + // First call should load + await getOutputsForTask(task) + expect(task.loadFullOutputs).toHaveBeenCalledTimes(1) + + // Second call should use cache + await getOutputsForTask(task) + expect(task.loadFullOutputs).toHaveBeenCalledTimes(1) + }) + + it('falls back to preview outputs on load error', async () => { + const { getOutputsForTask } = await import('@/services/jobOutputCache') + const previewOutput = createResultItem('preview') + + const job = createMockJob('task-1', 3) + const task = new TaskItemImpl(job, {}, [previewOutput]) + task.loadFullOutputs = vi + .fn() + .mockRejectedValue(new Error('Network error')) + + const result = await getOutputsForTask(task) + + expect(result).toEqual([previewOutput]) + }) + + it('returns null when request is superseded', async () => { + const { getOutputsForTask } = await import('@/services/jobOutputCache') + const job1 = createMockJob('task-1', 3) + const job2 = createMockJob('task-2', 3) + + const task1 = new TaskItemImpl(job1, {}, [createResultItem('preview-1')]) + const task2 = new TaskItemImpl(job2, {}, [createResultItem('preview-2')]) + + const loadedTask1 = new TaskItemImpl(job1, {}, [ + createResultItem('full-1') + ]) + const loadedTask2 = new TaskItemImpl(job2, {}, [ + createResultItem('full-2') + ]) + + // Task1 loads slowly, task2 loads quickly + task1.loadFullOutputs = vi.fn().mockImplementation( + () => + new Promise((resolve) => { + setTimeout(() => resolve(loadedTask1), 50) + }) + ) + task2.loadFullOutputs = vi.fn().mockResolvedValue(loadedTask2) + + // Start task1, then immediately start task2 + const promise1 = getOutputsForTask(task1) + const promise2 = getOutputsForTask(task2) + + const [result1, result2] = await Promise.all([promise1, promise2]) + + // Task2 should succeed, task1 should return null (superseded) + expect(result1).toBeNull() + expect(result2).toEqual([createResultItem('full-2')]) + }) + }) + + describe('getJobDetail', () => { + it('fetches and caches job detail', async () => { + const { getJobDetail } = await import('@/services/jobOutputCache') + const { fetchJobDetail } = + await import('@/platform/remote/comfyui/jobs/fetchJobs') + + const mockDetail: JobDetail = { + id: 'job-1', + status: 'completed', + create_time: Date.now(), + priority: 0, + outputs: {} + } + vi.mocked(fetchJobDetail).mockResolvedValue(mockDetail) + + const result = await getJobDetail('job-1') + + expect(result).toEqual(mockDetail) + expect(fetchJobDetail).toHaveBeenCalledWith(expect.any(Function), 'job-1') + }) + + it('returns cached job detail on subsequent calls', async () => { + const { getJobDetail } = await import('@/services/jobOutputCache') + const { fetchJobDetail } = + await import('@/platform/remote/comfyui/jobs/fetchJobs') + + const mockDetail: JobDetail = { + id: 'job-2', + status: 'completed', + create_time: Date.now(), + priority: 0, + outputs: {} + } + vi.mocked(fetchJobDetail).mockResolvedValue(mockDetail) + + // First call + await getJobDetail('job-2') + expect(fetchJobDetail).toHaveBeenCalledTimes(1) + + // Second call should use cache + const result = await getJobDetail('job-2') + expect(result).toEqual(mockDetail) + expect(fetchJobDetail).toHaveBeenCalledTimes(1) + }) + + it('returns undefined on fetch error', async () => { + const { getJobDetail } = await import('@/services/jobOutputCache') + const { fetchJobDetail } = + await import('@/platform/remote/comfyui/jobs/fetchJobs') + + vi.mocked(fetchJobDetail).mockRejectedValue(new Error('Network error')) + + const result = await getJobDetail('job-error') + + expect(result).toBeUndefined() + }) + }) + + describe('getJobWorkflow', () => { + it('fetches job detail and extracts workflow', async () => { + const { getJobWorkflow } = await import('@/services/jobOutputCache') + const { fetchJobDetail, extractWorkflow } = + await import('@/platform/remote/comfyui/jobs/fetchJobs') + + const mockDetail: JobDetail = { + id: 'job-wf', + status: 'completed', + create_time: Date.now(), + priority: 0, + outputs: {} + } + const mockWorkflow = { version: 1 } + + vi.mocked(fetchJobDetail).mockResolvedValue(mockDetail) + vi.mocked(extractWorkflow).mockResolvedValue(mockWorkflow as any) + + const result = await getJobWorkflow('job-wf') + + expect(result).toEqual(mockWorkflow) + expect(extractWorkflow).toHaveBeenCalledWith(mockDetail) + }) + + it('returns undefined when job detail not found', async () => { + const { getJobWorkflow } = await import('@/services/jobOutputCache') + const { fetchJobDetail, extractWorkflow } = + await import('@/platform/remote/comfyui/jobs/fetchJobs') + + vi.mocked(fetchJobDetail).mockResolvedValue(undefined) + vi.mocked(extractWorkflow).mockResolvedValue(undefined) + + const result = await getJobWorkflow('missing') + + expect(result).toBeUndefined() + }) + }) +}) diff --git a/src/services/jobOutputCache.ts b/src/services/jobOutputCache.ts new file mode 100644 index 000000000..72722afd9 --- /dev/null +++ b/src/services/jobOutputCache.ts @@ -0,0 +1,103 @@ +/** + * @fileoverview Job output cache for caching and managing job data + * @module services/jobOutputCache + * + * Centralizes job output and detail caching with LRU eviction. + * Provides helpers for working with previewable outputs and workflows. + */ + +import QuickLRU from '@alloc/quick-lru' + +import type { JobDetail } from '@/platform/remote/comfyui/jobs/jobTypes' +import { extractWorkflow } from '@/platform/remote/comfyui/jobs/fetchJobs' +import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema' +import { api } from '@/scripts/api' +import { ResultItemImpl } from '@/stores/queueStore' +import type { TaskItemImpl } from '@/stores/queueStore' + +const MAX_TASK_CACHE_SIZE = 50 +const MAX_JOB_DETAIL_CACHE_SIZE = 50 + +const taskCache = new QuickLRU({ + maxSize: MAX_TASK_CACHE_SIZE +}) +const jobDetailCache = new QuickLRU({ + maxSize: MAX_JOB_DETAIL_CACHE_SIZE +}) + +// Track latest request to dedupe stale responses +let latestTaskRequestId: string | null = null + +// ===== Task Output Caching ===== + +export function findActiveIndex( + items: readonly ResultItemImpl[], + url?: string +): number { + return ResultItemImpl.findByUrl(items, url) +} + +/** + * Gets previewable outputs for a task, with lazy loading, caching, and request deduping. + * Returns null if a newer request superseded this one while loading. + */ +export async function getOutputsForTask( + task: TaskItemImpl +): Promise { + const requestId = String(task.promptId) + latestTaskRequestId = requestId + + const outputsCount = task.outputsCount ?? 0 + const needsLazyLoad = outputsCount > 1 + + if (!needsLazyLoad) { + return [...task.previewableOutputs] + } + + const cached = taskCache.get(requestId) + if (cached) { + return [...cached.previewableOutputs] + } + + try { + const loadedTask = await task.loadFullOutputs() + + // Check if request was superseded while loading + if (latestTaskRequestId !== requestId) { + return null + } + + taskCache.set(requestId, loadedTask) + return [...loadedTask.previewableOutputs] + } catch (error) { + console.warn('Failed to load full outputs, using preview:', error) + return [...task.previewableOutputs] + } +} + +// ===== Job Detail Caching ===== + +export async function getJobDetail( + jobId: string +): Promise { + const cached = jobDetailCache.get(jobId) + if (cached) return cached + + try { + const detail = await api.getJobDetail(jobId) + if (detail) { + jobDetailCache.set(jobId, detail) + } + return detail + } catch (error) { + console.warn('Failed to fetch job detail:', error) + return undefined + } +} + +export async function getJobWorkflow( + jobId: string +): Promise { + const detail = await getJobDetail(jobId) + return await extractWorkflow(detail) +} diff --git a/src/stores/assetsStore.test.ts b/src/stores/assetsStore.test.ts index 1905a0177..576c40d7e 100644 --- a/src/stores/assetsStore.test.ts +++ b/src/stores/assetsStore.test.ts @@ -3,12 +3,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { useAssetsStore } from '@/stores/assetsStore' import { api } from '@/scripts/api' -import type { - HistoryTaskItem, - TaskPrompt, - TaskStatus, - TaskOutput -} from '@/schemas/apiSchema' +import type { JobListItem } from '@/platform/remote/comfyui/jobs/jobTypes' // Mock the api module vi.mock('@/scripts/api', () => ({ @@ -53,26 +48,25 @@ vi.mock('@/stores/queueStore', () => ({ url: string } | undefined + public promptId: string - constructor( - public taskType: string, - public prompt: TaskPrompt, - public status: TaskStatus | undefined, - public outputs: TaskOutput - ) { - this.flatOutputs = this.outputs - ? [ - { - supportsPreview: true, - filename: 'test.png', - subfolder: '', - type: 'output', - url: 'http://test.com/test.png' - } - ] - : [] + constructor(public job: JobListItem) { + this.promptId = job.id + this.flatOutputs = [ + { + supportsPreview: true, + filename: 'test.png', + subfolder: '', + type: 'output', + url: 'http://test.com/test.png' + } + ] this.previewOutput = this.flatOutputs[0] } + + get previewableOutputs() { + return this.flatOutputs.filter((o) => o.supportsPreview) + } } })) @@ -82,17 +76,17 @@ vi.mock('@/platform/assets/composables/media/assetMappers', () => ({ id: `${type}-${index}`, name, size: 0, - created_at: new Date(Date.now() - index * 1000).toISOString(), // Unique timestamps + created_at: new Date(Date.now() - index * 1000).toISOString(), tags: [type], preview_url: `http://test.com/${name}` })), mapTaskOutputToAssetItem: vi.fn((task, output) => { - const index = parseInt(task.prompt[1].split('_')[1]) || 0 + const index = parseInt(task.promptId.split('_')[1]) || 0 return { - id: task.prompt[1], // Use promptId as asset ID + id: task.promptId, name: output.filename, size: 0, - created_at: new Date(Date.now() - index * 1000).toISOString(), // Unique timestamps + created_at: new Date(Date.now() - index * 1000).toISOString(), tags: ['output'], preview_url: output.url, user_metadata: {} @@ -103,43 +97,20 @@ vi.mock('@/platform/assets/composables/media/assetMappers', () => ({ describe('assetsStore - Refactored (Option A)', () => { let store: ReturnType - // Helper function to create mock history items - const createMockHistoryItem = (index: number): HistoryTaskItem => ({ - taskType: 'History' as const, - prompt: [ - 1000 + index, // queueIndex - `prompt_${index}`, // promptId - {}, // promptInputs - { - extra_pnginfo: { - workflow: { - last_node_id: 1, - last_link_id: 1, - nodes: [], - links: [], - groups: [], - config: {}, - version: 1 - } - } - }, // extraData - [] // outputsToExecute - ], - status: { - status_str: 'success' as const, - completed: true, - messages: [] - }, - outputs: { - '1': { - images: [ - { - filename: `output_${index}.png`, - subfolder: '', - type: 'output' as const - } - ] - } + // Helper function to create mock job items + const createMockJobItem = (index: number): JobListItem => ({ + id: `prompt_${index}`, + status: 'completed', + create_time: 1000 + index, + update_time: 1000 + index, + last_state_update: 1000 + index, + priority: 1000 + index, + preview_output: { + filename: `output_${index}.png`, + subfolder: '', + type: 'output', + nodeId: 'node_1', + mediaType: 'images' } }) @@ -152,11 +123,9 @@ describe('assetsStore - Refactored (Option A)', () => { describe('Initial Load', () => { it('should load initial history items', async () => { const mockHistory = Array.from({ length: 10 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValue({ - History: mockHistory - }) + vi.mocked(api.getHistory).mockResolvedValue(mockHistory) await store.updateHistory() @@ -169,11 +138,9 @@ describe('assetsStore - Refactored (Option A)', () => { it('should set hasMoreHistory to true when batch is full', async () => { const mockHistory = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValue({ - History: mockHistory - }) + vi.mocked(api.getHistory).mockResolvedValue(mockHistory) await store.updateHistory() @@ -197,11 +164,9 @@ describe('assetsStore - Refactored (Option A)', () => { it('should accumulate items when loading more', async () => { // First batch - full BATCH_SIZE const firstBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: firstBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(firstBatch) await store.updateHistory() expect(store.historyAssets).toHaveLength(200) @@ -209,11 +174,9 @@ describe('assetsStore - Refactored (Option A)', () => { // Second batch - different items const secondBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(200 + i) + createMockJobItem(200 + i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: secondBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(secondBatch) await store.loadMoreHistory() @@ -225,24 +188,20 @@ describe('assetsStore - Refactored (Option A)', () => { it('should prevent duplicate items during pagination', async () => { // First batch - full BATCH_SIZE const firstBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: firstBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(firstBatch) await store.updateHistory() expect(store.historyAssets).toHaveLength(200) // Second batch with some duplicates const secondBatch = [ - createMockHistoryItem(2), // Duplicate - createMockHistoryItem(5), // Duplicate - ...Array.from({ length: 198 }, (_, i) => createMockHistoryItem(200 + i)) // New + createMockJobItem(2), // Duplicate + createMockJobItem(5), // Duplicate + ...Array.from({ length: 198 }, (_, i) => createMockJobItem(200 + i)) // New ] - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: secondBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(secondBatch) await store.loadMoreHistory() @@ -258,11 +217,9 @@ describe('assetsStore - Refactored (Option A)', () => { it('should stop loading when no more items', async () => { // First batch - less than BATCH_SIZE const firstBatch = Array.from({ length: 50 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: firstBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(firstBatch) await store.updateHistory() expect(store.hasMoreHistory).toBe(false) @@ -277,11 +234,9 @@ describe('assetsStore - Refactored (Option A)', () => { it('should handle race conditions with concurrent loads', async () => { // Setup initial state with full batch const initialBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: initialBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(initialBatch) await store.updateHistory() expect(store.hasMoreHistory).toBe(true) @@ -289,12 +244,10 @@ describe('assetsStore - Refactored (Option A)', () => { vi.mocked(api.getHistory).mockClear() // Setup slow API response - let resolveLoadMore: (value: { History: HistoryTaskItem[] }) => void - const loadMorePromise = new Promise<{ History: HistoryTaskItem[] }>( - (resolve) => { - resolveLoadMore = resolve - } - ) + let resolveLoadMore: (value: JobListItem[]) => void + const loadMorePromise = new Promise((resolve) => { + resolveLoadMore = resolve + }) vi.mocked(api.getHistory).mockReturnValueOnce(loadMorePromise) // Start first loadMore @@ -305,9 +258,9 @@ describe('assetsStore - Refactored (Option A)', () => { // Resolve const secondBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(200 + i) + createMockJobItem(200 + i) ) - resolveLoadMore!({ History: secondBatch }) + resolveLoadMore!(secondBatch) await Promise.all([firstLoad, secondLoad]) @@ -320,21 +273,17 @@ describe('assetsStore - Refactored (Option A)', () => { // Initial load const firstBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: firstBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(firstBatch) await store.updateHistory() // Load additional batches for (let batch = 1; batch < BATCH_COUNT; batch++) { const items = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(batch * 200 + i) + createMockJobItem(batch * 200 + i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: items - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(items) await store.loadMoreHistory() } @@ -347,21 +296,17 @@ describe('assetsStore - Refactored (Option A)', () => { it('should maintain date sorting after pagination', async () => { // First batch const firstBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: firstBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(firstBatch) await store.updateHistory() // Second batch const secondBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(200 + i) + createMockJobItem(200 + i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: secondBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(secondBatch) await store.loadMoreHistory() @@ -378,11 +323,9 @@ describe('assetsStore - Refactored (Option A)', () => { it('should preserve existing data when loadMore fails', async () => { // First successful load - full batch const firstBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: firstBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(firstBatch) await store.updateHistory() expect(store.historyAssets).toHaveLength(200) @@ -402,11 +345,9 @@ describe('assetsStore - Refactored (Option A)', () => { it('should clear error state on successful retry', async () => { // First load succeeds const firstBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: firstBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(firstBatch) await store.updateHistory() @@ -419,11 +360,9 @@ describe('assetsStore - Refactored (Option A)', () => { // Third load succeeds const thirdBatch = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(200 + i) + createMockJobItem(200 + i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: thirdBatch - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(thirdBatch) await store.loadMoreHistory() @@ -450,11 +389,9 @@ describe('assetsStore - Refactored (Option A)', () => { for (let batch = 0; batch < batches; batch++) { const items = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(batch * 200 + i) + createMockJobItem(batch * 200 + i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: items - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(items) if (batch === 0) { await store.updateHistory() @@ -476,11 +413,9 @@ describe('assetsStore - Refactored (Option A)', () => { // Load items beyond limit for (let batch = 0; batch < 6; batch++) { const items = Array.from({ length: 200 }, (_, i) => - createMockHistoryItem(batch * 200 + i) + createMockJobItem(batch * 200 + i) ) - vi.mocked(api.getHistory).mockResolvedValueOnce({ - History: items - }) + vi.mocked(api.getHistory).mockResolvedValueOnce(items) if (batch === 0) { await store.updateHistory() @@ -503,11 +438,9 @@ describe('assetsStore - Refactored (Option A)', () => { describe('jobDetailView Support', () => { it('should include outputCount and allOutputs in user_metadata', async () => { const mockHistory = Array.from({ length: 5 }, (_, i) => - createMockHistoryItem(i) + createMockJobItem(i) ) - vi.mocked(api.getHistory).mockResolvedValue({ - History: mockHistory - }) + vi.mocked(api.getHistory).mockResolvedValue(mockHistory) await store.updateHistory() diff --git a/src/stores/assetsStore.ts b/src/stores/assetsStore.ts index 56efe3daa..a387aea7d 100644 --- a/src/stores/assetsStore.ts +++ b/src/stores/assetsStore.ts @@ -9,7 +9,7 @@ import { import type { AssetItem } from '@/platform/assets/schemas/assetSchema' import { assetService } from '@/platform/assets/services/assetService' import { isCloud } from '@/platform/distribution/types' -import type { TaskItem } from '@/schemas/apiSchema' +import type { JobListItem } from '@/platform/remote/comfyui/jobs/jobTypes' import { api } from '@/scripts/api' import { TaskItemImpl } from './queueStore' @@ -48,27 +48,18 @@ async function fetchInputFilesFromCloud(): Promise { } /** - * Convert history task items to asset items + * Convert history job items to asset items */ -function mapHistoryToAssets(historyItems: TaskItem[]): AssetItem[] { +function mapHistoryToAssets(historyItems: JobListItem[]): AssetItem[] { const assetItems: AssetItem[] = [] - for (const item of historyItems) { - // Type guard for HistoryTaskItem which has status and outputs - if (item.taskType !== 'History') { + for (const job of historyItems) { + // Only process completed jobs with preview output + if (job.status !== 'completed' || !job.preview_output) { continue } - if (!item.outputs || !item.status || item.status?.status_str === 'error') { - continue - } - - const task = new TaskItemImpl( - 'History', - item.prompt, - item.status, - item.outputs - ) + const task = new TaskItemImpl(job) if (!task.previewOutput) { continue @@ -76,11 +67,10 @@ function mapHistoryToAssets(historyItems: TaskItem[]): AssetItem[] { const assetItem = mapTaskOutputToAssetItem(task, task.previewOutput) - const supportedOutputs = task.flatOutputs.filter((o) => o.supportsPreview) assetItem.user_metadata = { ...assetItem.user_metadata, - outputCount: supportedOutputs.length, - allOutputs: supportedOutputs + outputCount: job.outputs_count, + allOutputs: task.previewableOutputs } assetItems.push(assetItem) @@ -143,8 +133,8 @@ export const useAssetsStore = defineStore('assets', () => { offset: historyOffset.value }) - // Convert TaskItems to AssetItems - const newAssets = mapHistoryToAssets(history.History) + // Convert JobListItems to AssetItems + const newAssets = mapHistoryToAssets(history) if (loadMore) { // Filter out duplicates and insert in sorted order @@ -176,7 +166,7 @@ export const useAssetsStore = defineStore('assets', () => { // Update pagination state historyOffset.value += BATCH_SIZE - hasMoreHistory.value = history.History.length === BATCH_SIZE + hasMoreHistory.value = history.length === BATCH_SIZE if (allHistoryItems.value.length > MAX_HISTORY_ITEMS) { const removed = allHistoryItems.value.slice(MAX_HISTORY_ITEMS) diff --git a/src/stores/executionStore.ts b/src/stores/executionStore.ts index b9f89c29a..429adb807 100644 --- a/src/stores/executionStore.ts +++ b/src/stores/executionStore.ts @@ -396,10 +396,8 @@ export const useExecutionStore = defineStore('execution', () => { error: e.detail.exception_message }) } - const pid = e.detail?.prompt_id - // Clear initialization for errored prompt if present - if (e.detail?.prompt_id) clearInitializationByPromptId(e.detail.prompt_id) - resetExecutionState(pid) + clearInitializationByPromptId(e.detail.prompt_id) + resetExecutionState(e.detail.prompt_id) } /** diff --git a/src/stores/queueStore.loadWorkflow.test.ts b/src/stores/queueStore.loadWorkflow.test.ts index 3ff57f593..8b9ae30a5 100644 --- a/src/stores/queueStore.loadWorkflow.test.ts +++ b/src/stores/queueStore.loadWorkflow.test.ts @@ -1,14 +1,14 @@ import { createPinia, setActivePinia } from 'pinia' import { beforeEach, describe, expect, it, vi } from 'vitest' -import type { ComfyApp } from '@/scripts/app' +import type { + JobDetail, + JobListItem +} from '@/platform/remote/comfyui/jobs/jobTypes' import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema' +import type { ComfyApp } from '@/scripts/app' import { TaskItemImpl } from '@/stores/queueStore' -import * as getWorkflowModule from '@/platform/workflow/cloud' - -vi.mock('@/platform/distribution/types', () => ({ - isCloud: true -})) +import * as jobOutputCache from '@/services/jobOutputCache' vi.mock('@/services/extensionService', () => ({ useExtensionService: vi.fn(() => ({ @@ -17,8 +17,6 @@ vi.mock('@/services/extensionService', () => ({ })) const mockWorkflow: ComfyWorkflowJSON = { - id: 'test-workflow-id', - revision: 0, last_node_id: 5, last_link_id: 3, nodes: [], @@ -29,53 +27,46 @@ const mockWorkflow: ComfyWorkflowJSON = { version: 0.4 } -const createHistoryTaskWithWorkflow = (): TaskItemImpl => { - return new TaskItemImpl( - 'History', - [ - 0, // queueIndex - 'test-prompt-id', // promptId - {}, // promptInputs - { - client_id: 'test-client', - extra_pnginfo: { - workflow: mockWorkflow - } - }, - [] // outputsToExecute - ], - { - status_str: 'success', - completed: true, - messages: [] - }, - {} // outputs - ) +// Mock job detail response (matches actual /jobs/{id} API response structure) +// workflow is nested at: workflow.extra_data.extra_pnginfo.workflow +const mockJobDetail = { + id: 'test-prompt-id', + status: 'completed' as const, + create_time: Date.now(), + update_time: Date.now(), + workflow: { + extra_data: { + extra_pnginfo: { + workflow: mockWorkflow + } + } + }, + outputs: { + '1': { images: [{ filename: 'test.png', subfolder: '', type: 'output' }] } + } } -const createHistoryTaskWithoutWorkflow = (): TaskItemImpl => { - return new TaskItemImpl( - 'History', - [ - 0, - 'test-prompt-id', - {}, - { - client_id: 'test-client' - // No extra_pnginfo.workflow - }, - [] - ], - { - status_str: 'success', - completed: true, - messages: [] - }, - {} - ) +function createHistoryJob(id: string): JobListItem { + const now = Date.now() + return { + id, + status: 'completed', + create_time: now, + priority: now + } } -describe('TaskItemImpl.loadWorkflow - cloud history workflow fetching', () => { +function createRunningJob(id: string): JobListItem { + const now = Date.now() + return { + id, + status: 'in_progress', + create_time: now, + priority: now + } +} + +describe('TaskItemImpl.loadWorkflow - workflow fetching', () => { let mockApp: ComfyApp let mockFetchApi: ReturnType @@ -91,85 +82,57 @@ describe('TaskItemImpl.loadWorkflow - cloud history workflow fetching', () => { fetchApi: mockFetchApi } } as unknown as ComfyApp - - vi.spyOn(getWorkflowModule, 'getWorkflowFromHistory') }) - it('should load workflow directly when workflow is in extra_pnginfo', async () => { - const task = createHistoryTaskWithWorkflow() + it('should fetch workflow from API for history tasks', async () => { + const job = createHistoryJob('test-prompt-id') + const task = new TaskItemImpl(job) - await task.loadWorkflow(mockApp) - - expect(mockApp.loadGraphData).toHaveBeenCalledWith(mockWorkflow) - expect(mockFetchApi).not.toHaveBeenCalled() - }) - - it('should fetch workflow from cloud when workflow is missing from history task', async () => { - const task = createHistoryTaskWithoutWorkflow() - - // Mock getWorkflowFromHistory to return workflow - vi.spyOn(getWorkflowModule, 'getWorkflowFromHistory').mockResolvedValue( - mockWorkflow + vi.spyOn(jobOutputCache, 'getJobDetail').mockResolvedValue( + mockJobDetail as JobDetail ) await task.loadWorkflow(mockApp) - expect(getWorkflowModule.getWorkflowFromHistory).toHaveBeenCalledWith( - expect.any(Function), - 'test-prompt-id' - ) + expect(jobOutputCache.getJobDetail).toHaveBeenCalledWith('test-prompt-id') expect(mockApp.loadGraphData).toHaveBeenCalledWith(mockWorkflow) }) it('should not load workflow when fetch returns undefined', async () => { - const task = createHistoryTaskWithoutWorkflow() + const job = createHistoryJob('test-prompt-id') + const task = new TaskItemImpl(job) - vi.spyOn(getWorkflowModule, 'getWorkflowFromHistory').mockResolvedValue( - undefined - ) + vi.spyOn(jobOutputCache, 'getJobDetail').mockResolvedValue(undefined) await task.loadWorkflow(mockApp) - expect(getWorkflowModule.getWorkflowFromHistory).toHaveBeenCalled() + expect(jobOutputCache.getJobDetail).toHaveBeenCalled() expect(mockApp.loadGraphData).not.toHaveBeenCalled() }) it('should only fetch for history tasks, not running tasks', async () => { - const runningTask = new TaskItemImpl( - 'Running', - [ - 0, - 'test-prompt-id', - {}, - { - client_id: 'test-client' - }, - [] - ], - undefined, - {} - ) + const job = createRunningJob('test-prompt-id') + const runningTask = new TaskItemImpl(job) - vi.spyOn(getWorkflowModule, 'getWorkflowFromHistory').mockResolvedValue( - mockWorkflow + vi.spyOn(jobOutputCache, 'getJobDetail').mockResolvedValue( + mockJobDetail as JobDetail ) await runningTask.loadWorkflow(mockApp) - expect(getWorkflowModule.getWorkflowFromHistory).not.toHaveBeenCalled() + expect(jobOutputCache.getJobDetail).not.toHaveBeenCalled() expect(mockApp.loadGraphData).not.toHaveBeenCalled() }) it('should handle fetch errors gracefully by returning undefined', async () => { - const task = createHistoryTaskWithoutWorkflow() + const job = createHistoryJob('test-prompt-id') + const task = new TaskItemImpl(job) - vi.spyOn(getWorkflowModule, 'getWorkflowFromHistory').mockResolvedValue( - undefined - ) + vi.spyOn(jobOutputCache, 'getJobDetail').mockResolvedValue(undefined) await task.loadWorkflow(mockApp) - expect(getWorkflowModule.getWorkflowFromHistory).toHaveBeenCalled() + expect(jobOutputCache.getJobDetail).toHaveBeenCalled() expect(mockApp.loadGraphData).not.toHaveBeenCalled() }) }) diff --git a/src/stores/queueStore.test.ts b/src/stores/queueStore.test.ts index e01ec5afd..063658b2f 100644 --- a/src/stores/queueStore.test.ts +++ b/src/stores/queueStore.test.ts @@ -1,34 +1,39 @@ import { createPinia, setActivePinia } from 'pinia' import { beforeEach, describe, expect, it, vi } from 'vitest' -import type { - HistoryTaskItem, - PendingTaskItem, - RunningTaskItem, - TaskOutput, - TaskPrompt, - TaskStatus -} from '@/schemas/apiSchema' +import type { JobListItem } from '@/platform/remote/comfyui/jobs/jobTypes' +import type { TaskOutput } 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] +// Fixture factory for JobListItem +function createJob( + id: string, + status: JobListItem['status'], + createTime: number = Date.now(), + priority?: number +): JobListItem { + return { + id, + status, + create_time: createTime, + update_time: createTime, + last_state_update: createTime, + priority: priority ?? createTime + } +} -const createTaskStatus = ( - statusStr: 'success' | 'error' = 'success', - messages: any[] = [] -): TaskStatus => ({ - status_str: statusStr, - completed: true, - messages -}) +function createRunningJob(createTime: number, id: string): JobListItem { + return createJob(id, 'in_progress', createTime) +} + +function createPendingJob(createTime: number, id: string): JobListItem { + return createJob(id, 'pending', createTime) +} + +function createHistoryJob(createTime: number, id: string): JobListItem { + return createJob(id, 'completed', createTime) +} const createTaskOutput = ( nodeId: string = 'node-1', @@ -39,35 +44,6 @@ const createTaskOutput = ( } }) -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: { @@ -83,17 +59,13 @@ vi.mock('@/scripts/api', () => ({ describe('TaskItemImpl', () => { it('should remove animated property from outputs during construction', () => { - const taskItem = new TaskItemImpl( - 'History', - [0, 'prompt-id', {}, { client_id: 'client-id' }, []], - { status_str: 'success', messages: [], completed: true }, - { - 'node-1': { - images: [{ filename: 'test.png', type: 'output', subfolder: '' }], - animated: [false] - } + const job = createHistoryJob(0, 'prompt-id') + const taskItem = new TaskItemImpl(job, { + 'node-1': { + images: [{ filename: 'test.png', type: 'output', subfolder: '' }], + animated: [false] } - ) + }) // Check that animated property was removed expect('animated' in taskItem.outputs['node-1']).toBe(false) @@ -103,90 +75,72 @@ describe('TaskItemImpl', () => { }) it('should handle outputs without animated property', () => { - const taskItem = new TaskItemImpl( - 'History', - [0, 'prompt-id', {}, { client_id: 'client-id' }, []], - { status_str: 'success', messages: [], completed: true }, - { - 'node-1': { - images: [{ filename: 'test.png', type: 'output', subfolder: '' }] - } + const job = createHistoryJob(0, 'prompt-id') + const taskItem = new TaskItemImpl(job, { + 'node-1': { + images: [{ filename: 'test.png', type: 'output', subfolder: '' }] } - ) + }) expect(taskItem.outputs['node-1'].images).toBeDefined() expect(taskItem.outputs['node-1'].images?.[0]?.filename).toBe('test.png') }) it('should recognize webm video from core', () => { - const taskItem = new TaskItemImpl( - 'History', - [0, 'prompt-id', {}, { client_id: 'client-id' }, []], - { status_str: 'success', messages: [], completed: true }, - { - 'node-1': { - video: [{ filename: 'test.webm', type: 'output', subfolder: '' }] - } + const job = createHistoryJob(0, 'prompt-id') + const taskItem = new TaskItemImpl(job, { + 'node-1': { + video: [{ filename: 'test.webm', type: 'output', subfolder: '' }] } - ) + }) const output = taskItem.flatOutputs[0] expect(output.htmlVideoType).toBe('video/webm') expect(output.isVideo).toBe(true) - expect(output.isWebm).toBe(true) expect(output.isVhsFormat).toBe(false) expect(output.isImage).toBe(false) }) // https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite/blob/0a75c7958fe320efcb052f1d9f8451fd20c730a8/videohelpersuite/nodes.py#L578-L590 it('should recognize webm video from VHS', () => { - const taskItem = new TaskItemImpl( - 'History', - [0, 'prompt-id', {}, { client_id: 'client-id' }, []], - { status_str: 'success', messages: [], completed: true }, - { - 'node-1': { - gifs: [ - { - filename: 'test.webm', - type: 'output', - subfolder: '', - format: 'video/webm', - frame_rate: 30 - } - ] - } + const job = createHistoryJob(0, 'prompt-id') + const taskItem = new TaskItemImpl(job, { + 'node-1': { + gifs: [ + { + filename: 'test.webm', + type: 'output', + subfolder: '', + format: 'video/webm', + frame_rate: 30 + } + ] } - ) + }) const output = taskItem.flatOutputs[0] expect(output.htmlVideoType).toBe('video/webm') expect(output.isVideo).toBe(true) - expect(output.isWebm).toBe(true) expect(output.isVhsFormat).toBe(true) expect(output.isImage).toBe(false) }) it('should recognize mp4 video from core', () => { - const taskItem = new TaskItemImpl( - 'History', - [0, 'prompt-id', {}, { client_id: 'client-id' }, []], - { status_str: 'success', messages: [], completed: true }, - { - 'node-1': { - images: [ - { - filename: 'test.mp4', - type: 'output', - subfolder: '' - } - ], - animated: [true] - } + const job = createHistoryJob(0, 'prompt-id') + const taskItem = new TaskItemImpl(job, { + 'node-1': { + images: [ + { + filename: 'test.mp4', + type: 'output', + subfolder: '' + } + ], + animated: [true] } - ) + }) const output = taskItem.flatOutputs[0] @@ -205,22 +159,18 @@ describe('TaskItemImpl', () => { audioFormats.forEach(({ extension, mimeType }) => { it(`should recognize ${extension} audio`, () => { - const taskItem = new TaskItemImpl( - 'History', - [0, 'prompt-id', {}, { client_id: 'client-id' }, []], - { status_str: 'success', messages: [], completed: true }, - { - 'node-1': { - audio: [ - { - filename: `test.${extension}`, - type: 'output', - subfolder: '' - } - ] - } + const job = createHistoryJob(0, 'prompt-id') + const taskItem = new TaskItemImpl(job, { + 'node-1': { + audio: [ + { + filename: `test.${extension}`, + type: 'output', + subfolder: '' + } + ] } - ) + }) const output = taskItem.flatOutputs[0] @@ -232,6 +182,58 @@ describe('TaskItemImpl', () => { }) }) }) + + describe('error extraction getters', () => { + it('errorMessage returns undefined when no execution_error', () => { + const job = createHistoryJob(0, 'prompt-id') + const taskItem = new TaskItemImpl(job) + expect(taskItem.errorMessage).toBeUndefined() + }) + + it('errorMessage returns the exception_message from execution_error', () => { + const job: JobListItem = { + ...createHistoryJob(0, 'prompt-id'), + status: 'failed', + execution_error: { + node_id: 'node-1', + node_type: 'KSampler', + exception_message: 'GPU out of memory', + exception_type: 'RuntimeError', + traceback: ['line 1', 'line 2'], + current_inputs: {}, + current_outputs: {} + } + } + const taskItem = new TaskItemImpl(job) + expect(taskItem.errorMessage).toBe('GPU out of memory') + }) + + it('executionError returns undefined when no execution_error', () => { + const job = createHistoryJob(0, 'prompt-id') + const taskItem = new TaskItemImpl(job) + expect(taskItem.executionError).toBeUndefined() + }) + + it('executionError returns the full error object from execution_error', () => { + const errorDetail = { + node_id: 'node-1', + node_type: 'KSampler', + executed: ['node-0'], + exception_message: 'Invalid dimensions', + exception_type: 'ValueError', + traceback: ['traceback line'], + current_inputs: { input1: 'value' }, + current_outputs: {} + } + const job: JobListItem = { + ...createHistoryJob(0, 'prompt-id'), + status: 'failed', + execution_error: errorDetail + } + const taskItem = new TaskItemImpl(job) + expect(taskItem.executionError).toEqual(errorDetail) + }) + }) }) describe('useQueueStore', () => { @@ -267,15 +269,16 @@ describe('useQueueStore', () => { 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') + const runningJob = createRunningJob(1, 'run-1') + const pendingJob1 = createPendingJob(2, 'pend-1') + const pendingJob2 = createPendingJob(3, 'pend-2') + // API returns pre-sorted data (newest first) mockGetQueue.mockResolvedValue({ - Running: [runningTask], - Pending: [pendingTask1, pendingTask2] + Running: [runningJob], + Pending: [pendingJob2, pendingJob1] // Pre-sorted by create_time desc }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) await store.update() @@ -287,13 +290,11 @@ describe('useQueueStore', () => { }) it('should load history tasks from API', async () => { - const historyTask1 = createHistoryTask(5, 'hist-1') - const historyTask2 = createHistoryTask(4, 'hist-2') + const historyJob1 = createHistoryJob(5, 'hist-1') + const historyJob2 = createHistoryJob(4, 'hist-2') mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ - History: [historyTask1, historyTask2] - }) + mockGetHistory.mockResolvedValue([historyJob1, historyJob2]) await store.update() @@ -304,7 +305,7 @@ describe('useQueueStore', () => { it('should set loading state correctly', async () => { mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) expect(store.isLoading).toBe(false) @@ -317,7 +318,7 @@ describe('useQueueStore', () => { it('should clear loading state even if API fails', async () => { mockGetQueue.mockRejectedValue(new Error('API error')) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) await expect(store.update()).rejects.toThrow('API error') expect(store.isLoading).toBe(false) @@ -326,14 +327,12 @@ describe('useQueueStore', () => { 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') + const job1 = createHistoryJob(1, 'hist-1') + const job2 = createHistoryJob(5, 'hist-2') + const job3 = createHistoryJob(3, 'hist-3') mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ - History: [task1, task2, task3] - }) + mockGetHistory.mockResolvedValue([job1, job2, job3]) await store.update() @@ -342,16 +341,17 @@ describe('useQueueStore', () => { 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') + it('should preserve API sort order for pending tasks', async () => { + const pend1 = createPendingJob(10, 'pend-1') + const pend2 = createPendingJob(15, 'pend-2') + const pend3 = createPendingJob(12, 'pend-3') + // API returns pre-sorted data (newest first) mockGetQueue.mockResolvedValue({ Running: [], - Pending: [pend1, pend2, pend3] + Pending: [pend2, pend3, pend1] // Pre-sorted by create_time desc }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) await store.update() @@ -363,19 +363,17 @@ describe('useQueueStore', () => { 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') + const hist1 = createHistoryJob(50, 'prompt-uuid-aaa') mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [hist1] }) + mockGetHistory.mockResolvedValue([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] - }) + const hist2 = createHistoryJob(51, 'prompt-uuid-bbb') + mockGetHistory.mockResolvedValue([hist2]) await store.update() @@ -385,19 +383,17 @@ describe('useQueueStore', () => { }) it('should correctly reconcile when queueIndex is reused', async () => { - const hist1 = createHistoryTask(100, 'first-prompt-at-100') - const hist2 = createHistoryTask(99, 'prompt-at-99') + const hist1 = createHistoryJob(100, 'first-prompt-at-100') + const hist2 = createHistoryJob(99, 'prompt-at-99') mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [hist1, hist2] }) + mockGetHistory.mockResolvedValue([hist1, hist2]) await store.update() expect(store.historyTasks).toHaveLength(2) - const hist3 = createHistoryTask(101, 'second-prompt-at-101') - mockGetHistory.mockResolvedValue({ - History: [hist3, hist2] - }) + const hist3 = createHistoryJob(101, 'second-prompt-at-101') + mockGetHistory.mockResolvedValue([hist3, hist2]) await store.update() @@ -409,23 +405,19 @@ describe('useQueueStore', () => { }) 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') + const hist1 = createHistoryJob(10, 'old-at-10') + const hist2 = createHistoryJob(20, 'old-at-20') + const hist3 = createHistoryJob(30, 'keep-at-30') mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ - History: [hist3, hist2, hist1] - }) + mockGetHistory.mockResolvedValue([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] - }) + const newHist1 = createHistoryJob(31, 'new-at-31') + const newHist2 = createHistoryJob(32, 'new-at-32') + mockGetHistory.mockResolvedValue([newHist2, newHist1, hist3]) await store.update() @@ -437,19 +429,17 @@ describe('useQueueStore', () => { describe('update() - history reconciliation', () => { it('should keep existing items still on server (by promptId)', async () => { - const hist1 = createHistoryTask(10, 'existing-1') - const hist2 = createHistoryTask(9, 'existing-2') + const hist1 = createHistoryJob(10, 'existing-1') + const hist2 = createHistoryJob(9, 'existing-2') mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [hist1, hist2] }) + mockGetHistory.mockResolvedValue([hist1, hist2]) await store.update() expect(store.historyTasks).toHaveLength(2) - const hist3 = createHistoryTask(11, 'new-1') - mockGetHistory.mockResolvedValue({ - History: [hist3, hist1, hist2] - }) + const hist3 = createHistoryJob(11, 'new-1') + mockGetHistory.mockResolvedValue([hist3, hist1, hist2]) await store.update() @@ -460,16 +450,16 @@ describe('useQueueStore', () => { }) it('should remove items no longer on server', async () => { - const hist1 = createHistoryTask(10, 'remove-me') - const hist2 = createHistoryTask(9, 'keep-me') + const hist1 = createHistoryJob(10, 'remove-me') + const hist2 = createHistoryJob(9, 'keep-me') mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [hist1, hist2] }) + mockGetHistory.mockResolvedValue([hist1, hist2]) await store.update() expect(store.historyTasks).toHaveLength(2) - mockGetHistory.mockResolvedValue({ History: [hist2] }) + mockGetHistory.mockResolvedValue([hist2]) await store.update() @@ -478,18 +468,16 @@ describe('useQueueStore', () => { }) it('should add new items from server', async () => { - const hist1 = createHistoryTask(5, 'old-1') + const hist1 = createHistoryJob(5, 'old-1') mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [hist1] }) + mockGetHistory.mockResolvedValue([hist1]) await store.update() - const hist2 = createHistoryTask(6, 'new-1') - const hist3 = createHistoryTask(7, 'new-2') - mockGetHistory.mockResolvedValue({ - History: [hist3, hist2, hist1] - }) + const hist2 = createHistoryJob(6, 'new-1') + const hist3 = createHistoryJob(7, 'new-2') + mockGetHistory.mockResolvedValue([hist3, hist2, hist1]) await store.update() @@ -497,18 +485,69 @@ describe('useQueueStore', () => { expect(store.historyTasks.map((t) => t.promptId)).toContain('new-1') expect(store.historyTasks.map((t) => t.promptId)).toContain('new-2') }) + + it('should recreate TaskItemImpl when outputs_count changes', async () => { + // Initial load without outputs_count + const jobWithoutOutputsCount = createHistoryJob(10, 'job-1') + delete (jobWithoutOutputsCount as any).outputs_count + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue([jobWithoutOutputsCount]) + + await store.update() + expect(store.historyTasks).toHaveLength(1) + const initialTask = store.historyTasks[0] + expect(initialTask.outputsCount).toBeUndefined() + + // Second load with outputs_count now populated + const jobWithOutputsCount = { + ...createHistoryJob(10, 'job-1'), + outputs_count: 2 + } + mockGetHistory.mockResolvedValue([jobWithOutputsCount]) + + await store.update() + + // Should have recreated the TaskItemImpl with new outputs_count + expect(store.historyTasks).toHaveLength(1) + const updatedTask = store.historyTasks[0] + expect(updatedTask.outputsCount).toBe(2) + // Should be a different instance + expect(updatedTask).not.toBe(initialTask) + }) + + it('should reuse TaskItemImpl when outputs_count unchanged', async () => { + const job = { + ...createHistoryJob(10, 'job-1'), + outputs_count: 2 + } + + mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) + mockGetHistory.mockResolvedValue([job]) + + await store.update() + const initialTask = store.historyTasks[0] + + // Same job with same outputs_count + mockGetHistory.mockResolvedValue([{ ...job }]) + + await store.update() + + // Should reuse the same instance + expect(store.historyTasks[0]).toBe(initialTask) + }) }) 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}`) + const jobs = Array.from({ length: 5 }, (_, i) => + createHistoryJob(10 - i, `hist-${i}`) ) mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: tasks }) + mockGetHistory.mockResolvedValue(jobs) await store.update() @@ -522,21 +561,19 @@ describe('useQueueStore', () => { store.maxHistoryItems = 5 const initial = Array.from({ length: 3 }, (_, i) => - createHistoryTask(10 + i, `existing-${i}`) + createHistoryJob(10 + i, `existing-${i}`) ) mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: initial }) + mockGetHistory.mockResolvedValue(initial) await store.update() expect(store.historyTasks).toHaveLength(3) - const newTasks = Array.from({ length: 4 }, (_, i) => - createHistoryTask(20 + i, `new-${i}`) + const newJobs = Array.from({ length: 4 }, (_, i) => + createHistoryJob(20 + i, `new-${i}`) ) - mockGetHistory.mockResolvedValue({ - History: [...newTasks, ...initial] - }) + mockGetHistory.mockResolvedValue([...newJobs, ...initial]) await store.update() @@ -547,10 +584,10 @@ describe('useQueueStore', () => { it('should handle maxHistoryItems = 0', async () => { store.maxHistoryItems = 0 - const tasks = [createHistoryTask(10, 'hist-1')] + const jobs = [createHistoryJob(10, 'hist-1')] mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: tasks }) + mockGetHistory.mockResolvedValue(jobs) await store.update() @@ -560,13 +597,13 @@ describe('useQueueStore', () => { it('should handle maxHistoryItems = 1', async () => { store.maxHistoryItems = 1 - const tasks = [ - createHistoryTask(10, 'hist-1'), - createHistoryTask(9, 'hist-2') + const jobs = [ + createHistoryJob(10, 'hist-1'), + createHistoryJob(9, 'hist-2') ] mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: tasks }) + mockGetHistory.mockResolvedValue(jobs) await store.update() @@ -577,18 +614,18 @@ describe('useQueueStore', () => { it('should dynamically adjust when maxHistoryItems changes', async () => { store.maxHistoryItems = 10 - const tasks = Array.from({ length: 15 }, (_, i) => - createHistoryTask(20 - i, `hist-${i}`) + const jobs = Array.from({ length: 15 }, (_, i) => + createHistoryJob(20 - i, `hist-${i}`) ) mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: tasks }) + mockGetHistory.mockResolvedValue(jobs) await store.update() expect(store.historyTasks).toHaveLength(10) store.maxHistoryItems = 5 - mockGetHistory.mockResolvedValue({ History: tasks }) + mockGetHistory.mockResolvedValue(jobs) await store.update() expect(store.historyTasks).toHaveLength(5) @@ -597,19 +634,17 @@ describe('useQueueStore', () => { 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') + const running = createRunningJob(5, 'run-1') + const pending1 = createPendingJob(6, 'pend-1') + const pending2 = createPendingJob(7, 'pend-2') + const hist1 = createHistoryJob(3, 'hist-1') + const hist2 = createHistoryJob(4, 'hist-2') mockGetQueue.mockResolvedValue({ Running: [running], Pending: [pending1, pending2] }) - mockGetHistory.mockResolvedValue({ - History: [hist2, hist1] - }) + mockGetHistory.mockResolvedValue([hist2, hist1]) await store.update() @@ -624,9 +659,9 @@ describe('useQueueStore', () => { it('hasPendingTasks should be true when pending tasks exist', async () => { mockGetQueue.mockResolvedValue({ Running: [], - Pending: [createPendingTask(1, 'pend-1')] + Pending: [createPendingJob(1, 'pend-1')] }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) await store.update() expect(store.hasPendingTasks).toBe(true) @@ -634,21 +669,19 @@ describe('useQueueStore', () => { it('hasPendingTasks should be false when no pending tasks', async () => { mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) 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') + const hist1 = createHistoryJob(10, 'hist-1') + const hist2 = createHistoryJob(25, 'hist-2') + const hist3 = createHistoryJob(15, 'hist-3') mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ - History: [hist1, hist2, hist3] - }) + mockGetHistory.mockResolvedValue([hist1, hist2, hist3]) await store.update() expect(store.lastHistoryQueueIndex).toBe(25) @@ -656,7 +689,7 @@ describe('useQueueStore', () => { it('lastHistoryQueueIndex should be -1 when no history', async () => { mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) await store.update() expect(store.lastHistoryQueueIndex).toBe(-1) @@ -666,19 +699,17 @@ describe('useQueueStore', () => { describe('clear()', () => { beforeEach(async () => { mockGetQueue.mockResolvedValue({ - Running: [createRunningTask(1, 'run-1')], - Pending: [createPendingTask(2, 'pend-1')] - }) - mockGetHistory.mockResolvedValue({ - History: [createHistoryTask(3, 'hist-1')] + Running: [createRunningJob(1, 'run-1')], + Pending: [createPendingJob(2, 'pend-1')] }) + mockGetHistory.mockResolvedValue([createHistoryJob(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: [] }) + mockGetHistory.mockResolvedValue([]) await store.clear() @@ -693,9 +724,7 @@ describe('useQueueStore', () => { it('should clear only queue when specified', async () => { mockClearItems.mockResolvedValue(undefined) mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ - History: [createHistoryTask(3, 'hist-1')] - }) + mockGetHistory.mockResolvedValue([createHistoryJob(3, 'hist-1')]) await store.clear(['queue']) @@ -707,10 +736,10 @@ describe('useQueueStore', () => { it('should clear only history when specified', async () => { mockClearItems.mockResolvedValue(undefined) mockGetQueue.mockResolvedValue({ - Running: [createRunningTask(1, 'run-1')], - Pending: [createPendingTask(2, 'pend-1')] + Running: [createRunningJob(1, 'run-1')], + Pending: [createPendingJob(2, 'pend-1')] }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) await store.clear(['history']) @@ -729,11 +758,12 @@ describe('useQueueStore', () => { describe('delete()', () => { it('should delete task from queue', async () => { - const task = new TaskItemImpl('Pending', createTaskPrompt(1, 'pend-1')) + const job = createPendingJob(1, 'pend-1') + const task = new TaskItemImpl(job) mockDeleteItem.mockResolvedValue(undefined) mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) await store.delete(task) @@ -741,16 +771,12 @@ describe('useQueueStore', () => { }) it('should delete task from history', async () => { - const task = new TaskItemImpl( - 'History', - createTaskPrompt(1, 'hist-1'), - createTaskStatus(), - createTaskOutput() - ) + const job = createHistoryJob(1, 'hist-1') + const task = new TaskItemImpl(job, createTaskOutput()) mockDeleteItem.mockResolvedValue(undefined) mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) await store.delete(task) @@ -758,11 +784,12 @@ describe('useQueueStore', () => { }) it('should refresh store after deletion', async () => { - const task = new TaskItemImpl('Pending', createTaskPrompt(1, 'pend-1')) + const job = createPendingJob(1, 'pend-1') + const task = new TaskItemImpl(job) mockDeleteItem.mockResolvedValue(undefined) mockGetQueue.mockResolvedValue({ Running: [], Pending: [] }) - mockGetHistory.mockResolvedValue({ History: [] }) + mockGetHistory.mockResolvedValue([]) await store.delete(task) diff --git a/src/stores/queueStore.ts b/src/stores/queueStore.ts index 7571ad280..1c72e27d8 100644 --- a/src/stores/queueStore.ts +++ b/src/stores/queueStore.ts @@ -2,34 +2,27 @@ import _ from 'es-toolkit/compat' import { defineStore } from 'pinia' import { computed, ref, shallowRef, toRaw, toValue } from 'vue' -import { isCloud } from '@/platform/distribution/types' -import { reconcileHistory } from '@/platform/remote/comfyui/history/reconciliation' -import { useSettingStore } from '@/platform/settings/settingStore' -import { getWorkflowFromHistory } from '@/platform/workflow/cloud' +import { extractWorkflow } from '@/platform/remote/comfyui/jobs/fetchJobs' import type { - ComfyWorkflowJSON, - NodeId -} from '@/platform/workflow/validation/schemas/workflowSchema' + APITaskType, + JobListItem, + TaskType +} from '@/platform/remote/comfyui/jobs/jobTypes' +import type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema' import type { - HistoryTaskItem, ResultItem, StatusWsMessageStatus, - TaskItem, - TaskOutput, - TaskPrompt, - TaskStatus, - TaskType + TaskOutput } from '@/schemas/apiSchema' import { api } from '@/scripts/api' import type { ComfyApp } from '@/scripts/app' import { useExtensionService } from '@/services/extensionService' +import { getJobDetail } from '@/services/jobOutputCache' import { useNodeOutputStore } from '@/stores/imagePreviewStore' import { useExecutionStore } from '@/stores/executionStore' +import { useSettingStore } from '@/platform/settings/settingStore' import { getMediaTypeFromFilename } from '@/utils/formatUtil' -// Task type used in the API. -type APITaskType = 'queue' | 'history' - enum TaskItemDisplayStatus { Running = 'Running', Pending = 'Pending', @@ -212,32 +205,44 @@ export class ResultItemImpl { get supportsPreview(): boolean { return this.isImage || this.isVideo || this.isAudio || this.is3D } + + static filterPreviewable( + outputs: readonly ResultItemImpl[] + ): ResultItemImpl[] { + return outputs.filter((o) => o.supportsPreview) + } + + static findByUrl(items: readonly ResultItemImpl[], url?: string): number { + if (!url) return 0 + const idx = items.findIndex((o) => o.url === url) + return idx >= 0 ? idx : 0 + } } export class TaskItemImpl { - readonly taskType: TaskType - readonly prompt: TaskPrompt - readonly status?: TaskStatus + readonly job: JobListItem readonly outputs: TaskOutput readonly flatOutputs: ReadonlyArray constructor( - taskType: TaskType, - prompt: TaskPrompt, - status?: TaskStatus, + job: JobListItem, outputs?: TaskOutput, flatOutputs?: ReadonlyArray ) { - this.taskType = taskType - this.prompt = prompt - this.status = status + this.job = job + // If no outputs provided but job has preview_output, create synthetic outputs + // using the real nodeId and mediaType from the backend response + const effectiveOutputs = + outputs ?? + (job.preview_output + ? { + [job.preview_output.nodeId]: { + [job.preview_output.mediaType]: [job.preview_output] + } + } + : {}) // Remove animated outputs from the outputs object - // outputs.animated is an array of boolean values that indicates if the images - // array in the result are animated or not. - // The queueStore does not use this information. - // It is part of the legacy API response. We should redesign the backend API. - // https://github.com/Comfy-Org/ComfyUI_frontend/issues/2739 - this.outputs = _.mapValues(outputs ?? {}, (nodeOutputs) => + this.outputs = _.mapValues(effectiveOutputs, (nodeOutputs) => _.omit(nodeOutputs, 'animated') ) this.flatOutputs = flatOutputs ?? this.calculateFlatOutputs() @@ -261,15 +266,31 @@ export class TaskItemImpl { ) } + /** All outputs that support preview (images, videos, audio, 3D) */ + get previewableOutputs(): readonly ResultItemImpl[] { + return ResultItemImpl.filterPreviewable(this.flatOutputs) + } + get previewOutput(): ResultItemImpl | undefined { + const previewable = this.previewableOutputs + // Prefer saved media files over the temp previews return ( - this.flatOutputs.find( - // Prefer saved media files over the temp previews - (output) => output.type === 'output' && output.supportsPreview - ) ?? this.flatOutputs.find((output) => output.supportsPreview) + previewable.find((output) => output.type === 'output') ?? previewable[0] ) } + // Derive taskType from job status + get taskType(): TaskType { + switch (this.job.status) { + case 'in_progress': + return 'Running' + case 'pending': + return 'Pending' + default: + return 'History' + } + } + get apiTaskType(): APITaskType { switch (this.taskType) { case 'Running': @@ -285,61 +306,42 @@ export class TaskItemImpl { } get queueIndex() { - return this.prompt[0] + return this.job.priority } get promptId() { - return this.prompt[1] + return this.job.id } - get promptInputs() { - return this.prompt[2] + get outputsCount(): number | undefined { + return this.job.outputs_count ?? undefined } - get extraData() { - return this.prompt[3] + get status() { + return this.job.status } - get outputsToExecute() { - return this.prompt[4] + get errorMessage(): string | undefined { + return this.job.execution_error?.exception_message ?? undefined } - get extraPngInfo() { - return this.extraData.extra_pnginfo + get executionError() { + return this.job.execution_error ?? undefined } - get clientId() { - return this.extraData.client_id + get workflowId(): string | undefined { + return this.job.workflow_id ?? undefined } - get workflow(): ComfyWorkflowJSON | undefined { - return this.extraPngInfo?.workflow + get createTime(): number { + return this.job.create_time } - get messages() { - return this.status?.messages || [] - } - - /** - * Server-provided creation time in milliseconds, when available. - * - * Sources: - * - Queue: 5th tuple element may be a metadata object with { create_time }. - * - History (Cloud V2): Adapter injects create_time into prompt[3].extra_data. - */ - get createTime(): number | undefined { - const extra = (this.extraData as any) || {} - const fromExtra = - typeof extra.create_time === 'number' ? extra.create_time : undefined - if (typeof fromExtra === 'number') return fromExtra - - return undefined - } - - get interrupted() { - return _.some( - this.messages, - (message) => message[0] === 'execution_interrupted' + get interrupted(): boolean { + return ( + this.job.status === 'failed' && + this.job.execution_error?.exception_type === + 'InterruptProcessingException' ) } @@ -352,42 +354,26 @@ export class TaskItemImpl { } get displayStatus(): TaskItemDisplayStatus { - switch (this.taskType) { - case 'Running': + switch (this.job.status) { + case 'in_progress': return TaskItemDisplayStatus.Running - case 'Pending': + case 'pending': return TaskItemDisplayStatus.Pending - case 'History': - if (this.interrupted) return TaskItemDisplayStatus.Cancelled - - switch (this.status!.status_str) { - case 'success': - return TaskItemDisplayStatus.Completed - case 'error': - return TaskItemDisplayStatus.Failed - } + case 'completed': + return TaskItemDisplayStatus.Completed + case 'failed': + return TaskItemDisplayStatus.Failed + case 'cancelled': + return TaskItemDisplayStatus.Cancelled } } get executionStartTimestamp() { - const message = this.messages.find( - (message) => message[0] === 'execution_start' - ) - return message ? message[1].timestamp : undefined + return this.job.execution_start_time ?? undefined } get executionEndTimestamp() { - const messages = this.messages.filter((message) => - [ - 'execution_success', - 'execution_interrupted', - 'execution_error' - ].includes(message[0]) - ) - if (!messages.length) { - return undefined - } - return _.max(messages.map((message) => message[1].timestamp)) + return this.job.execution_end_time ?? undefined } get executionTime() { @@ -403,28 +389,48 @@ export class TaskItemImpl { : undefined } - public async loadWorkflow(app: ComfyApp) { - let workflowData = this.workflow + /** + * Loads full outputs for tasks that only have preview data + * Returns a new TaskItemImpl with full outputs and execution status + */ + public async loadFullOutputs(): Promise { + // Only load for history tasks (caller checks outputsCount > 1) + if (!this.isHistory) { + return this + } + const jobDetail = await getJobDetail(this.promptId) - if (isCloud && !workflowData && this.isHistory) { - workflowData = await getWorkflowFromHistory( - (url) => app.api.fetchApi(url), - this.promptId - ) + if (!jobDetail?.outputs) { + return this } + // Create new TaskItemImpl with full outputs + return new TaskItemImpl(this.job, jobDetail.outputs) + } + + public async loadWorkflow(app: ComfyApp) { + if (!this.isHistory) { + return + } + + // Single fetch for both workflow and outputs (with caching) + const jobDetail = await getJobDetail(this.promptId) + + const workflowData = await extractWorkflow(jobDetail) if (!workflowData) { return } await app.loadGraphData(toRaw(workflowData)) - if (!this.outputs) { + // Use full outputs from job detail, or fall back to existing outputs + const outputsToLoad = jobDetail?.outputs ?? this.outputs + if (!outputsToLoad) { return } const nodeOutputsStore = useNodeOutputStore() - const rawOutputs = toRaw(this.outputs) + const rawOutputs = toRaw(outputsToLoad) for (const nodeExecutionId in rawOutputs) { nodeOutputsStore.setNodeOutputsByExecutionId( nodeExecutionId, @@ -445,15 +451,10 @@ export class TaskItemImpl { return this.flatOutputs.map( (output: ResultItemImpl, i: number) => new TaskItemImpl( - this.taskType, - [ - this.queueIndex, - `${this.promptId}-${i}`, - this.promptInputs, - this.extraData, - this.outputsToExecute - ], - this.status, + { + ...this.job, + id: `${this.promptId}-${i}` + }, { [output.nodeId]: { [output.mediaType]: [output] @@ -463,32 +464,8 @@ export class TaskItemImpl { ) ) } - - public toTaskItem(): TaskItem { - const item: HistoryTaskItem = { - taskType: 'History', - prompt: this.prompt, - status: this.status!, - outputs: this.outputs - } - return item - } } -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 - ) - ) - export const useQueueStore = defineStore('queue', () => { // Use shallowRef because TaskItemImpl instances are immutable and arrays are // replaced entirely (not mutated), so deep reactivity would waste performance @@ -525,8 +502,9 @@ export const useQueueStore = defineStore('queue', () => { api.getHistory(maxHistoryItems.value) ]) - runningTasks.value = toTaskItemImpls(queue.Running).sort(sortNewestFirst) - pendingTasks.value = toTaskItemImpls(queue.Pending).sort(sortNewestFirst) + // API returns pre-sorted data (sort_by=create_time&order=desc) + runningTasks.value = queue.Running.map((job) => new TaskItemImpl(job)) + pendingTasks.value = queue.Pending.map((job) => new TaskItemImpl(job)) const currentHistory = toValue(historyTasks) @@ -534,7 +512,7 @@ export const useQueueStore = defineStore('queue', () => { const executionStore = useExecutionStore() appearedTasks.forEach((task) => { const promptIdString = String(task.promptId) - const workflowId = task.workflow?.id + const workflowId = task.workflowId if (workflowId && promptIdString) { executionStore.registerPromptWorkflowIdMapping( promptIdString, @@ -543,22 +521,26 @@ export const useQueueStore = defineStore('queue', () => { } }) - const items = reconcileHistory( - history.History, - currentHistory.map((impl) => impl.toTaskItem()), - toValue(maxHistoryItems), - toValue(lastHistoryQueueIndex) - ) + // Sort by create_time descending and limit to maxItems + const sortedHistory = [...history] + .sort((a, b) => b.create_time - a.create_time) + .slice(0, toValue(maxHistoryItems)) // Reuse existing TaskItemImpl instances or create new + // Must recreate if outputs_count changed (e.g., API started returning it) const existingByPromptId = new Map( currentHistory.map((impl) => [impl.promptId, impl]) ) - historyTasks.value = items.map( - (item) => - existingByPromptId.get(item.prompt[1]) ?? toTaskItemImpls([item])[0] - ) + historyTasks.value = sortedHistory.map((job) => { + const existing = existingByPromptId.get(job.id) + if (!existing) return new TaskItemImpl(job) + // Recreate if outputs_count changed to ensure lazy loading works + if (existing.outputsCount !== (job.outputs_count ?? undefined)) { + return new TaskItemImpl(job) + } + return existing + }) } finally { isLoading.value = false } From a6b6857e372863844ca47933e9b2bd01edc6f15a Mon Sep 17 00:00:00 2001 From: AustinMroz Date: Thu, 15 Jan 2026 20:36:39 -0800 Subject: [PATCH 04/11] Fix copypasted primitives inside subgraphs (#8094) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copying a subgraph which contains primitive nodes would cause the primitives to fail to initialize. This was caused because they did not have their `onGraphConfigured` and `onAfterGraphConfigured` callbacks applied. There's already a copy of `forEachNode` in `@/utils/graphTraversalUtil.ts`, but the method is small and I want to avoid litegraph referencing outside code. See also #6606, where a similar fix was needed ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8094-Fix-copypasted-primitives-inside-subgraphs-2ea6d73d365081f189f1ea4c9248f5ed) by [Unito](https://www.unito.io) --- src/lib/litegraph/src/LGraphCanvas.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 7dee812fc..3129324e3 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -8,6 +8,7 @@ import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMuta import { layoutStore } from '@/renderer/core/layout/store/layoutStore' import { LayoutSource } from '@/renderer/core/layout/types' import { removeNodeTitleHeight } from '@/renderer/core/layout/utils/nodeSizeUtil' +import { forEachNode } from '@/utils/graphTraversalUtil' import { CanvasPointer } from './CanvasPointer' import type { ContextMenu } from './ContextMenu' @@ -4057,6 +4058,8 @@ export class LGraphCanvas implements CustomEventDispatcher layoutStore.batchUpdateNodeBounds(newPositions) this.selectItems(created) + forEachNode(graph, (n) => n.onGraphConfigured?.()) + forEachNode(graph, (n) => n.onAfterGraphConfigured?.()) graph.afterChange() this.emitAfterChange() From 6714b958c71bdc060255c35c42f69e4d77475fbc Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Thu, 15 Jan 2026 22:12:37 -0800 Subject: [PATCH 05/11] chore: remove dead browser test fixture after Jobs API migration (#8099) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Removes which is dead code left over from the Jobs API migration. ## Details This fixture file: - References legacy and types that were removed in the Jobs API migration - Is not referenced anywhere in the codebase - Cannot be used since the types it imports no longer exist ## Related PRs Follow-up cleanup to the Jobs API migration: - #7169 - Add Jobs API infrastructure (PR 1 of 3) - #7170 - Migrate to Jobs API (PR 2 of 3) - #7650 - Encapsulate error extraction in TaskItemImpl getters ## Testing - ✅ Typecheck passes - ✅ No references to this file in the codebase - ✅ File imports types that no longer exist (cannot be used) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8099-chore-remove-dead-browser-test-fixture-after-Jobs-API-migration-2ea6d73d36508172be89c9c5a74b33ee) by [Unito](https://www.unito.io) --- browser_tests/fixtures/utils/taskHistory.ts | 164 -------------------- 1 file changed, 164 deletions(-) delete mode 100644 browser_tests/fixtures/utils/taskHistory.ts diff --git a/browser_tests/fixtures/utils/taskHistory.ts b/browser_tests/fixtures/utils/taskHistory.ts deleted file mode 100644 index 01dfb1a4a..000000000 --- a/browser_tests/fixtures/utils/taskHistory.ts +++ /dev/null @@ -1,164 +0,0 @@ -import type { Request, Route } from '@playwright/test' -import _ from 'es-toolkit/compat' -import fs from 'fs' -import path from 'path' -import { v4 as uuidv4 } from 'uuid' - -import type { - HistoryTaskItem, - TaskItem, - TaskOutput -} from '../../../src/schemas/apiSchema' -import type { ComfyPage } from '../ComfyPage' - -/** keyof TaskOutput[string] */ -type OutputFileType = 'images' | 'audio' | 'animated' - -const DEFAULT_IMAGE = 'example.webp' - -const getFilenameParam = (request: Request) => { - const url = new URL(request.url()) - return url.searchParams.get('filename') || DEFAULT_IMAGE -} - -const getContentType = (filename: string, fileType: OutputFileType) => { - const subtype = path.extname(filename).slice(1) - switch (fileType) { - case 'images': - return `image/${subtype}` - case 'audio': - return `audio/${subtype}` - case 'animated': - return `video/${subtype}` - } -} - -const setQueueIndex = (task: TaskItem) => { - task.prompt[0] = TaskHistory.queueIndex++ -} - -const setPromptId = (task: TaskItem) => { - task.prompt[1] = uuidv4() -} - -export default class TaskHistory { - static queueIndex = 0 - static readonly defaultTask: Readonly = { - prompt: [0, 'prompt-id', {}, { client_id: uuidv4() }, []], - outputs: {}, - status: { - status_str: 'success', - completed: true, - messages: [] - }, - taskType: 'History' - } - private tasks: HistoryTaskItem[] = [] - private outputContentTypes: Map = new Map() - - constructor(readonly comfyPage: ComfyPage) {} - - private loadAsset: (filename: string) => Buffer = _.memoize( - (filename: string) => { - const filePath = this.comfyPage.assetPath(filename) - return fs.readFileSync(filePath) - } - ) - - private async handleGetHistory(route: Route) { - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify(this.tasks) - }) - } - - private async handleGetView(route: Route) { - const fileName = getFilenameParam(route.request()) - if (!this.outputContentTypes.has(fileName)) { - return route.continue() - } - - const asset = this.loadAsset(fileName) - return route.fulfill({ - status: 200, - contentType: this.outputContentTypes.get(fileName), - body: asset, - headers: { - 'Cache-Control': 'public, max-age=31536000', - 'Content-Length': asset.byteLength.toString() - } - }) - } - - async setupRoutes() { - return this.comfyPage.page.route( - /.*\/api\/(view|history)(\?.*)?$/, - async (route) => { - const request = route.request() - const method = request.method() - - const isViewReq = request.url().includes('view') && method === 'GET' - if (isViewReq) return this.handleGetView(route) - - const isHistoryPath = request.url().includes('history') - const isGetHistoryReq = isHistoryPath && method === 'GET' - if (isGetHistoryReq) return this.handleGetHistory(route) - - const isClearReq = - method === 'POST' && - isHistoryPath && - request.postDataJSON()?.clear === true - if (isClearReq) return this.clearTasks() - - return route.continue() - } - ) - } - - private createOutputs( - filenames: string[], - filetype: OutputFileType - ): TaskOutput { - return filenames.reduce((outputs, filename, i) => { - const nodeId = `${i + 1}` - outputs[nodeId] = { - [filetype]: [{ filename, subfolder: '', type: 'output' }] - } - const contentType = getContentType(filename, filetype) - this.outputContentTypes.set(filename, contentType) - return outputs - }, {}) - } - - private addTask(task: HistoryTaskItem) { - setPromptId(task) - setQueueIndex(task) - this.tasks.unshift(task) // Tasks are added to the front of the queue - } - - clearTasks(): this { - this.tasks = [] - return this - } - - withTask( - outputFilenames: string[], - outputFiletype: OutputFileType = 'images', - overrides: Partial = {} - ): this { - this.addTask({ - ...TaskHistory.defaultTask, - outputs: this.createOutputs(outputFilenames, outputFiletype), - ...overrides - }) - return this - } - - /** Repeats the last task in the task history a specified number of times. */ - repeat(n: number): this { - for (let i = 0; i < n; i++) - this.addTask(structuredClone(this.tasks.at(0)) as HistoryTaskItem) - return this - } -} From ddac3dca1df3d9f89778db3236ad0dab1708a8ba Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Thu, 15 Jan 2026 23:00:09 -0800 Subject: [PATCH 06/11] Allow users to drag actionbar over tabs (#8068) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary A common bit of feedback is that users want to be able to drag the actionbar into the very top of their window. Currently the actionbar is clamped to not allow it to overlap the tabs, this update removes that restriction & fixes padding for the top menu section when the UI elements are hidden within it adding additional gaps. ## Changes - Remove clamping on actionbar position - Fix padding on top menu section ## Screenshots (if applicable) Before: image After: image Actionbar over tabs: image ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8068-Allow-users-to-drag-actionbar-over-tabs-2e96d73d365081708491f3c54968df3a) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions --- ...e-default-workflow-mobile-chrome-linux.png | Bin 30353 -> 30548 bytes ...obile-empty-canvas-mobile-chrome-linux.png | Bin 18007 -> 18212 bytes ...le-settings-dialog-mobile-chrome-linux.png | Bin 17882 -> 17882 bytes ...s-paned-with-touch-mobile-chrome-linux.png | Bin 25603 -> 25810 bytes ...e-moved-node-touch-mobile-chrome-linux.png | Bin 27083 -> 27277 bytes ...colors-light-all-colors-chromium-linux.png | Bin 141102 -> 141090 bytes src/components/actionbar/ComfyActionbar.vue | 12 ++---------- src/components/topbar/ActionBarButtons.vue | 2 +- 8 files changed, 3 insertions(+), 11 deletions(-) diff --git a/browser_tests/tests/mobileBaseline.spec.ts-snapshots/mobile-default-workflow-mobile-chrome-linux.png b/browser_tests/tests/mobileBaseline.spec.ts-snapshots/mobile-default-workflow-mobile-chrome-linux.png index b983d8214552394ba328b2eac3ddb0b50272d18f..c21094f81326996240e08d900a854a0fc2322e1f 100644 GIT binary patch literal 30548 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 diff --git a/browser_tests/tests/mobileBaseline.spec.ts-snapshots/mobile-empty-canvas-mobile-chrome-linux.png b/browser_tests/tests/mobileBaseline.spec.ts-snapshots/mobile-empty-canvas-mobile-chrome-linux.png index 886d3404cf0802cb6c8d799ad93b415e5574746f..1c9232428d72bcec997b5c4b5e44f97f377e1cb8 100644 GIT binary patch literal 18212 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 literal 18007 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űt9VA9uYk@3bla|k}4d&uJlhVx6a9sMrBj+v^ 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 TJh1B%00000NkvXXu0mjfrNdB2 delta 685 zcmV;e0#g0jivik;0kC^IO*upJvbOa{n3eTV85rVea_q%BJ4c8@P=tv!G<9e_%h<*llBHLXMZ^hyp9R#3HT+C2S4M?KN{u?cMRHe)dohz1CFeY3L8y)*Du;S{G3;lWjX7 z5Whz!7d{SOYvVD%s%CFd0F#|N8hIOl4@6mK+~{adXn0KLye2#k6#d((n4}Si!u!mkf!`lyG%Begx6$ z>*=i{H-2mL;(T-l%eMN-(9G)I{_jM76-8oA?5g6dgNw07mTwuBuroBZ#*;QY78LqY z8I>se-gHAV+k1OPrN-Y9`Bjr(JR}j0%Cz{w(7epOePdD{Ul#>Xla)LlJ>Iz`imjoE zrLnDR$x7blZ#6V-J^Rj%&y>$s5WP;)g(@jF^5Kd3DGx7;f+@trT2||VxF$sHy&pOg z*Q1m1JRg55=_2D>T2wh-D^-c~M<*8veJI4lmUydidRp3plZ#%AYZh1mrynF1*M68- zk`CU$7>+6F>Mc|%Ba1SallS%(mX}=YMVYC`!J>CPeK?O}Lkb^)Ce*n)3}a#w4ZGCozBT|36Xqlbk*70gaQ3 zJ{t)gtN9)BP0#!WldnED57(Ff^E7`o_TQn!^grK;v-Cb$0R$qWPIj|VKy?KaQPCOs T7Wuyp00000NkvXXu0mjf8oX86 diff --git a/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png b/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png index 7bfad824dd14e95edf9b01cf5e27d86a77559736..b509651cfcb7ad768c87e1c8c62d5ee19680a2e8 100644 GIT binary patch literal 25810 zcmd43bySr7x;H+Gf(nR&fPjDkk`mGl64D^uAl*H5sR)RaNOz}%bb~a~Fv9>tgVZ3+ z(D8oVarQoE?S0N~t>3%eb^dzR;+Yxmx$oXVs&)hW?Y3YCw8_UdNbCb_6S>BQz&o%1N`1;#~Q~j!`p{cBypEo%y zcGF<8`fe~hFjR`OHk3;C@Zrx4p1XLI5!cWMyyBRUr-Hq-kOx$z1duxqEAB!*-kG`u z5&LL+6Y@-q`^LKm&ypdcpS~zSo=W`XWe+hH29e058_*E93aj>yca4mUP&R^sf_X~m z+Y1XnZkb%1?1=|`v@U+aY5Aa8F?^6#F{Pj-h}-h&2SPrXo0*O6dso&+bWA*o&RfgNks@A; zfyA5|ipkuu25VoQiPtqAV)?`J!egEmso~zen~7^am^65Dy4OQVACOc=$z}bh86xY5 ztW;yPv#X>KeZl=GMB?@9*EpirUbgAm@In|=!0q?r?d{2OlP=?z%mqn`*;0{t)3AIc zj;%Ks;r45T$*s;SvX~J5tZ}WAtIKn4hdDi6T^@^}-)CoM=uMs!K9?ZG@z%8ac#-<$ z`SG{nVnN@tfnkyB0Xqi=hwEPINE|XE4FdzGU%gQs!FZaQnytI-2k=_2Us17=l9E-p zuAwz{(_Tlvr>?J#sT&0RubQwZJbrX_J!fP@ZI-nb78ESFRYN!My&egn8(cSaeC(p4 zqN+MF#gqASs9%Rk%gSbXkiMkyIX~K}qJ3dY-`sStHVoSb*F~$4^lNG9$-{>-JM=s} z@!sx@?mI_&dzpuxSEt@cvz?}cp^R70%9{33B3FCIKYrYhpZbw=DROzpLCTtanwIXd zw0C+yT&#C0ZDbS`72_w>+> z?1KV{WNkTVM<7_3n7q3_6K+miw^#cLgG(6}J`ckm>FiAKvM#|L8M8=p{-R4E?4zZp zcQKgEqi)3oT_5@M=}w~j(Q)hb<@ru)HuJZlA_LEr74cxd{N9DRSvl5bPPgB@;vL>z zFAs|l#oCwsteXsBS=kOb`T4NE^>s^ReK)qH(=Y=A17|On-^DHD+nGA2!@0HL^kF*@ z8-%=ofbLZrrwyVQT(|Jm2`O@T{_3cf!$MItl?~jSX<>bR{jGsSj&v_np+&my(9BHA z>+C1w)IybyF;fcSqc73X;!+sv)w#L3PBv-&SM?TYo~wq}Uf}ztLgTwzmC}VJ zu?_uBTgzI`bS|fKrw{g)=?c(N*=q7rW%7!Oc{RiDZeZZx;Lx)aw)LK5o}K=RjvSvC zP(Sy-I-tZHp|%ug-Pm8Dw|~aX9mn8p2e*?^Q1IRVNoQ%B;3Y2=Nzp$%oS#)uQL)o< zZomIa#-V8sGv2sJc|29XUFh;KeZ3ssl0o}pbx`-wz1zO_Rvg5{6Sebxq0?bV-nO<^ zD=TJI@|RNf&jX)wDS>0v6G5IoM7$Ne6h^Ao6G@p*JKea`BBvlI*WVpC8bUzV6HcZy zTww*H-F_B)pFHa^DTn#MTDpJc)iy5yZP*ShA1`<8c;0^)3F}TP)S(Yb*guQ*KHk=^ zFuhxnFQ1Q-i!#1=qrmOJrZO``eny1BMyVQya9(vq3Eh#LO} zFSLL(z!bSh%g8ThnAQzCG&d{F0=&{h)Y}wH1rEid^hT-Zysg(JyAwk z?W8j^jVPHeh&-Kk@NPL>O(x;U)6|^!j;JnQ3&6qyU)}%eFh9SqzuyWc*+3-RLX|p{ zA9|rn2|vl2;o)pr^Z#;XSf^2RltgKoVQ^YGEG*uVE?@(6Zbbi-+mv;HDrNGx0-D>{?1C5_U3lHX{aqJJI3G3ja%af$=;%b@p5&{axIH7-89C?k z*DZoxhj+-&vz4rDSc9&5VZrlocuaR%9T%NaS{7Z_BAx85@ya(+JN>M!yuN3gZmjjm2e4Gz=XqFX(;T9BK{h#%Kd9{;D=J7XcdVj< z9W%qfmv$jEh?Hx!1!EoWf5v!!pkP$y#*Z$JxZiI_lHoHm-TZ!~tfHFicgWepZb0sY zy$=YWZuH)p@@8Ect$LAw?ak>7b!K6-Z78L7zck#|VFDNnT6-!fon%O&6389*({zTo zwyIz)wg^=enojIGUMVM_rb#++qH+DvS+Yo1e4DzYNr}>Syn}RN))zu>KdNBQ*rTX6 z--|3|b(*Z|3N_A@wPoieZ`J5fuQ`q>uD?;B*56>=La>eaqN`HFn{<@X@`4i+lPdhP zGeOkuGmNYLpA8|k)d=0|X_SI*eRnt%_;1S@} zYm~Xn9{d<~2DR>I=De+L6Q&?vTx<)D{5KnGRDa*2dwdv>XPJ?e5>%PG#F~*6V@pV# zLa)Ni)$VqCzR}I)7Wr4%8xq-FtGa@4Ncml^q&`{M6P}w%xk9m!8$T{pb#!b^Y|0v@^@sCqnA7A32m1SDwezcd z6UKyW-%pR+=AH`(moFiK>LDBIYph#6Z@w~lqOML@Uq98=bsJ~9cE1AO#RZ@xXE#ue z(c9B*ZcqF6@#~lFt5*TPe?O6vy*E8KCQjwV#a_Y1$@$RrYC?=LKAw~F7kt8k5pQ+Z2s~!? zEJH`}sDguN^e<-;a(HQ3zQ34{!PzdONPD>dPyT2HsAX997+DNI64y56bE&DZF=Ldp z){ zMNd^#yrfJqOleen{r#aM^6r*wFtuLEmTacwBK?!u6;Iot_FUG0xy-CAczb(AIBrnV zCT#+I^uATCor8(FeO~mtH&Oze90cnJ&io_xS@M~gPwY|IifWpg$`12=eMsqv>-k@- z{-<>Ar|~s}kAC@|EDA6aIVsRl6UbpUi`&_ymOFj3GqqlrBtcyf$Bx)rt&x;Kx5G#U z)Vw?m#Is+|5GsB=X!5u1_K23v<;S7DkG^MBOWsH8C4F$1|8Bz$DjL(BTBamSX0<{AbnK z$VkR=Db?ww;dPfw(?$T^ocV~j6LX$P&wW*w5K;x!rd?DF1IN0ObH1+9h#53p!OhJL z?1?@H4^v8XYrA`TYEK>{%15v`kN=$uSZmAYb>FV4c3tM&u9=p|&3#@JoS{3>G4hz; zHf*lB@jk^&PYgyLSdkWCO0Ci*bfhv18Xw;74bom=or6t`+5>gGln!tnZRf{2nT ze)DQc7JzdV=GvpB9o#o|0Sr5(E5&~5_6{uEdw1{Pyy+z@cXE38@F9;wH~S?U507rS zaaZrdMbeJf0K^<>GchveA-cOlWGOez6`%rB8X8?_Ce+dum5bZvW3FSnPy z$DXS}<1V*GkHKyBF;{Z0ad2Mf-K1INF4pu~P0XM7J)S?ztf;E8-C}CG)!R33ND~#q zO;-2)E>6tEcpTllk=I)bo8$Ag%fnNzwfP+tjH0@_1Py*ZKH(HyotA>WTiB|dANVOVU2T(`n%b;a>Tx_I?cY}hYVV}I&r_+Xg^abCeT@&xB@%5_b3kEol7-sMIi za{q&oKk}`m?c5S(MMF|TiGPhV_F?iN4h$SBbN}78^K}0!Np0;ZU5DnM4S0arfE6f1 zb$ynDtaJ6HKXrUJ@?0B!DfGRjoPzts?=$pzS?ejSkWj#fkR%RV_9nudUlJq=>?gEt{he~JA3s&t0xVrG1f?_)ZywTeL`um zcQG$tyJ*g`n}Vlj7l688F}_57EBkJr%lYg*QXxj7YM_gNSUxbGHU9aGv6txJjk9KQ zb{gpH@%(dI+QBrA30S|XdQx26QTlb$^=k6<*&%G$+QvrPJv+d#xGVHJflbU#4uw!x zQ)6q+%(1x=Vydd}#4q#@4D0r)-g))5L}4E_a!2jJ&g%P5?*Yb%5x!bHznJgGv&99o z9qDtHrU*rzaLm!Iv#^}o=PlVZaS=S+En0C8?dC1i;O^h_FbDVVI25BAipDm{(hf+@ z3t&HfR?P|dgiQAG@|->G`nc9>#%&Og$a0JIvY;i8{d#q=V26_Y=$BV{r-I+@?F74l?5ZT7yJk=jULQla}tZRg7m!g;QUh`0|g zPO*#67lfCQ+(aKfe3+S;QFAXG&6#*>+=qETm^7}aJEB{k3v-Zqb$hCHrjQZStNCeJ z=M0PGs5iCYMM-G|8~TtRp)DCgY%N<+XBJpo%DdN8C77-Y2$yp>he$}cJbhZJ&$X6a zt_Fq$DoF6CM0KQUET*7;z9c6IzgC4r-sW>O%Nw>pp*@TMZ)JRC3T4I(frNy8-dTX% z;S;@t&bqp~=+Usr$;n0c%8JGX;eMn!4E(?Go$dM7^o_(t{XcXSp=I07hN7=aIiZK*Tg9F8*EW{cc3XS}TfuL#txnSY$m@1z zpGB6Gl(8_^6SP6s<~*#QPm2y6sjP&8dEdM7D1x^L|rABcD^ouI}e zohF`U8G5L4s3J-L4z#PZ0t6Py-F;_naGO%NnaykZn??x^E^bMg!<*LW5dA%6O?4la zO+yyHtBlU}IrsMEEqlYSJ}>u^gE#2R518<=gBNnI?cBfr?5^D?%c_qSnMG)B6wh{M zdN|{z%I!%MLd|Ba@6pD;;&>=ulKC>v&jvwn8m@X|`F@+dIV3cal6N;v{JF(YS}MCM z@`zjjwBD{)0i@|k+@C_jO=iDnEGr-o2++hdW^)lH8X80d+==ov&<%F$mn39l-{$SE z>{iLgnp6wE^ut)Ml1|R)svfZ&het#N8qV*2$P5W|8HsVD%t9sb_&POFl==x+cCEn& z2Abz4>GRCt3$cbTEkmq#b;pfWC`l*kPfl*}^InaJW4mq7w53R~R06uHbcsnDbxj zNp&RMh0GGl4WMk2@}43zh{{=bPNG)zfTSVO&*9m=F6B+Sjttz*3E8e6Zqe8|=OPlw7H?p5u z^_wZ+nFnnY{7+~?8HJKbNv#js1<2)R9ywYwjjIzq|Lse+h7@M1{js~|HhG3)l)5D3 zWrmzGwBPcdfA&@o_i*~`{$N9szOj+T3Pp@_RzI!j47KB&2uW20<|Aw>Dp~tEHA9&_ ziB>{+2Sd+m)OB->Nl(peqg&HeZ7ZdKn|!rjU(C;I&z)I7SBhM(l*v!5yUcE z!EIdAiZ!MV+ps7d1Lj4pPO{6&SXJHZxoR?LpKt1*LSR&+7ZG7$^z`%@!-94Lv&;+| zziN?A#WPqc^Qa{YJPqPpc8r(d@;07BpL<6N<_E4D%lEnlK9v|yQ{GRxUad~Qj)ATd zh!cEk;V@v3+2|v9_b$F-I)u4&LYir|sHjNi``bms>;1K|t7Az|Pfr~$e)1d_cbCel zs+lU!11!o5O~zPu{l+JRXykQsgV7}`>E`*N)swwn2-Qay$JvnyL^vs_`X{#W@$u8I zH^BZ6$TEb_CEybQ#YKWAXc&~-Xkq@^`oN}t^x0jOu$h_Wib{4)irh3+_}xqN1nwrH zM8I+3=?ZPvbrA06#-Dkk>(fn=p2Oj{Z+t&L^>V7c+CROJbxF?<*SWsf`FL6X;u4C1 zc}rVcTT(&~ej+~J>i-m%wY#U*k@0sJ$-z*n0K)jdv$VwTTIsmP84**BTeb#-4iaIX z$sac`)(6KRs-_aAIIZ$8n6`EgYMe@0XNic2_V^}htJl6t|K)sIVTK30rku#gMliT*o^L!FYJ;r@zkfS&UD)bxsH%DZSn2{6I`Sui^facs zCAxdX7WJ8(4Y!^T0djv74@O6xQeb3ZVKF_H9upQ8rX(`Hmt&OI^fhKbv=mjZYoFUa zTf?QuM;HPpGo;dE%b;uUJa{c8mXe%2og)LoiCuHUCFc+Oz#t^F)kg^Z92j~Yc3{Ud znqOP}?ZwL4TIA!GA0o_(%5vg*yF!UQ(;%~%mX^z2i#Q7gF|Y0g3bL_T_QjBNb#?ik z9V#d&)H^P|@YDSm20mnv7TFM<5%Ouon#Gx?;XWo*K(ovsGtNo$2Sh-?+xn#|e}eUj z^QAs}Qw_SGNhMj-f6J?WH%&9ppPOW3nM%DVl>^e8i6B59hlht}XHf~v8Z$<7@rE3t ztEJ6K44prA$4Yv68zlaDivzcEyn@pFjd72bNGl$Jd8~$1GM-Y7tsDe`k7Q%BQdYpB zq@c70A?+}%J8@R6x;+6_1-nY++Wz+T4;%06>jS@>L(wXi1{ya$c1&ui=uV?-GiJ`t zF1(tdEVSM9r9tmGx+&$pDXwdaC1-g>g^FgX zz&!!$&<#|WzffwQ``WMCXZ^z5?B%8-u=<9EwbdHe3a?zfmewlxf9%Yo#symcu`=&J z?#_KzK+np-`SmdgmjSsn4eFxWe#JSl;+4ep$MdF?i0Xj#0|&sPntWEV!sWrr%yt^_ zuzd5gvr{cAm{m{HFS|-IJ3lmPAjbza)?Ae=34)lLv46p|I&9^oxLllH=iP?JE4GS zZD~o-9|;@#nz+p}dplK>nRDC+(y|7-`w<*pYuT^XOV1b2I;f&P*|ceEPrpen%zJ$t z{76VjXi50@Gwl49*Lmynu8+AkIQ)|Uc`|$}=qgNIEoN=iJU))QI^m1Laa3Vp{Rb{L z8g2K1Jj4)sg*)S;vlF^^@Zs6>ZLj2Qc095+sDFKfr>R+<6Xh<2GezQAnVOYMRJa|n z-ZdG&=t;U~xEzkyL}hs;6APo-B`b6}T9VT*x(+A-a?6L%p6>3_s;Y$dZx^ER?7o** zmH}?Q#O{Kha(hQ2l0Qm;D_m4Zb&yoRecLSeIp@>diz9wteUAqa{@{qd(S=$qTT43= zIc8dQHm6*nT^e1M%mQ>wazyb01Q>S|#KkelLkr5vmb()so8!B;@1|>o zJ5Vinx#?jPWo1?6^J~BAm*Y zrq-4tJe(0Og|1OSoYmo>WV2&3OFiP*_2IGIVoIAE1z6E2Y&A6-otc)cW^~S2jeoEf z>o?q>hB4(rZr9vBEp#A-z+5Mss=lkpiu$|S`G!%hT}N=Z2%OL#b1)*mw(fmfGc`we ztuXT7u~s<$x=4sTAU+={uE}dpT8I_w{Y?cD5@0ycS0w?MW64 z;`)0mW;$?n8#d~PkX!jZ6#2_UY!B{_G#Au<_i}EO@$J>S{r>jTTPUe%-IuD)hgQ=>nn!EB0MN0uy4rO*Id;v_q2cdbKy2)6gR2~E^h*eYqNfU5P@9DZLF%GDrN<*+TTR)kA zKvI8P{P73OnyRX+k2koAyh)Ep-he@4WryLTKGL+s>MmX>UmZkQa+ znB$nF2kqmbI$qe#->SB7-)LU&i0bdnXSjGH7?bhw?N@&NlFc0hd;c4z!qQTp*)PlU z?O5$CNrKy@TVtC^m-i)!*Xbtg;Q)4z-Wm(Nr2Zc3xT?ODw^j*|t_)lK9?26D5@KND zuyJ$e#j+><1{=mB`PkUl!-iVBX#*{-UI@ek#+ZEb=2@A+m~ z0hAl>3vdjCKo)WjrX+&rzJC3>{*)Zo6^{g8wz+<9xo3K6N|}y@i!1yF#PZd*@?GEa zBcQ}8B(V8)etK9_uM4b;Xw^O)>xYVvy3`LCp^P~A6get;_-ar0AkbwwAd=AZMR z;=$7-BisD-tID`*e^pn7ZDn^cJv)(I8(u%iwbP4Ph3(PGak8iwLUs%zmY-w>R%X4 z{>#UBE;ip;<^Ri79JD9DHQ-(4cYnoz`s~lJ8i*mv`r+UCRQ~ZX2kqVu|9b8yR|9$4 znj8mQw?C-B39nTKu(945NLWmn+S^kAqGNS6uN)9LbhNYvtrUZQNl*Gh65Xi}>0{0XWsRGfjcU}Pwl0mt2pZ&XxlH4~S{tZ8A4Gk$9nmsvcy2k42 zPO7TZFd;v5*D8M^k$ruANxIvxdIIl_?$S5hx%5R{TiI{Z?z}&8I-a_s?hKMHfrz<4$IIJQShK7cKMMh3R z0XF$mNXQqKHy9LjEO@&*3B1Z1%EsygFNpdz?J%LCu5R^6Ie4hQpM&r8KI|cn`>?>z zT6F@}aR+tqTr#jm+O+Bt6SaMPg?M<>#4Xns%1wIw(Bl&-g)tkSq-ogSP)Gl?%+-3K zVVBWI8z|PM6Ui9(m2uTeltDF3XymokL4(RXhq!*>EB(SoR@dABTUl9I3Qo(BP}Y_a zV=GzN&-VjDxCAT$zY(L;vfG;1iY=jxH9%SFdOt(o9>npN7%gm zTfvkP--k5c`Jd&l0qh+~wu!_)11N!b?$$y3%ZYky**`7%CF>K2*Ta95*1vN~fwzUe zE#>eBUx^J|#A={PsS9yTR_RH+F*rGgRR6+om2)hf12r8*AmVO7pdaTdt*$OSziEoB z?(7WzsYD0v`uh6QlarBl;8gn4c928ZJZx;cM@Me1uDND`Vo^y+Ny*9mgvy%sU_k?= z_3&YoNq3kqFe3rMl8lrzfryP&k1Szx;LoiQ8jr1+lGq@?$Ioh6?TyL~2?>G6X1`Vi zPhV0+PwzJ%sV**j7!v67S@at^`9pygPpxiZz{~s?Y~wX;O}hx$`qM^~>+_GAfeonb zKhLcs0+yJRq{0SZ`Q_F5vj!%j(1~L0t(_gZSXuBvToDvPabLcON&=r!GN+Zwn~@*S z#Ko$A(n8jsS6K(uH#WlTfb_e~!lgAZI0#5%7z|dX->7KUq+MyQm@Yin-o6wvbX^93LlSqv%T0A^=QWJ2pmbS+V2v(GJbV#fB6jOMe_LjP=V0rhS@P5%qN=#Iq z{;Z>g19^v4QW1h5%x}+$RJbeYj&bu0c9ScqZVcSIN{ivs^K&dr%++7No+d!viIh}q z04ogii~VR;U=f#Qson~UPCEl5qpXa~9vYqd%n_XHWR0nq=;-rV_jv&U0T?~+EEqE{ z7#Kz;%_mA{aUdB1U{HrhjJ5jvlcLP~mOmA}1sroG8osPr8sFVR_vShR%v;2%Ejv5A zPQ7z(b#<)uV1Y6>jS~ ze{I}qO0MIl_3`%h+Z!7jGrw;vZEcAwMW?4L;TFK*YUAe6r)6Lfud0gq%U5%YuCGtj zvIWuv;&Eb-pI-~;a8yyf1yLV$l>$}(tE>xN20yjs_rGedb24H0s%Aq)MO9zv+0hXU z9!3Geu;Eb~1eos*rXGRO4F(+W7{+Kyfd{b^(FykQZSatQjw0{5cT0ygR+a?x21~Bi zkal`%>g>}q#^;!j5$zKejDPkwN>AJDyS>x{hoKIW`_Br=5xc6;b+f9$Vlk_%^3-*iF7Ja&{O5@+ouyI zIrbL7&Gs{zj_}^?*;r{BSe^p<_?S4f3tHRIu-X?}(A(P&YEVeWOx4lRQCeCW3Wchx zbIn#)R$}9lr^Lm@rKHHaOGP{x%~wkQrdb9=Ihek?do5`Dz&%7vOw0j!$88m>aO1{} z+qZ86bJW_lj<)vgTZgsZzrTqEFG&^l4Qkv3Rj{>XXJr*)d-I)}t8j8b{_5%~DS?Y> zb-xmlJqM!4r9N^%fgGgk8#2nliR@(&o=sy~>D0hJD_wPPB^g!hEE zmwBeaRp7-7+wQQ9BC14rw+)qBFw%eO*Z1rVc+CcZL-X?TlHnaN*QQ6`;Q&8s);t8SQwyZa{c-$n&#lmJ|=NHB<}?(q3D|;$uM8dF|E$0j6U&!vWxZ zcJ!zM6Yz>q8ylN`2m~rM?WU@%{BRc7UsyrSdNSb3HP+QRN*xw``&JJ?Au`vF8z5BJ zjmCwA1wb^Xr0Aiku&{z9Ly16RD@5evznvnOpBgLh}YXe~Z+}quK3xRBnwsEO|^ZmzX2x!pN;dDbiJ^56DZMY#TYZ)1j zJq_LbA~y#QkA*wy{9VWhcd9SnO*+ey)R!JLv_L^PvPC0bMc*BFXe6nb_)qi z>pF7h_)kj(6(NmbYBtKbZ&XC~avS5>%_^(H$5vf)TP%VaR00}Q+znB(h7--j1qC_N z%Gs}#BO@6MYqPVLf$b&{!8xS8hzb;V)cdmTIE4^Rh1b>*wXh;h5 zSyPe;Y4I-T+#H zGpPX1q=N&iiODj#fLmT}?w(IC;L5RZ?wEqI+VJ77Z}c81?--Cb2&avRjy5qedIl!7 z(po-^hew@-nOVOnd)hQCN{o&!|L_p{w`P!YgJ2mFBr1=8nks((A17|IHx>?%vFY)a`(y_DrL81`}~}BD;QL3;E-pz<=8y zc79ae!5S+Y1R^wIy$!~%tL6GzIy#HQ;%5vDeEj@Lx;r~NB5y@A3JVj@y8G(mwTW2` z##%ORL4*v}dfFwaMlVhe#Kgobr{HiXa5VxWojl*Fki%R6R9ex*yIhOY=VTWc13@D_ zvg9}(o1UBV1Hb^VTTu6|&nq`>T!Io56BlPfDZqZQNE_{&O&gq_;%A07^Xjit;X z!wfX>5Q(p`u?ia|=H{=LWe01)cmNCK)D+*}x+`cT0O#2!B4weVLv5_DOJmp9dk)qf z@9t(iE4rV$d=t{FvDT9e+VV{dtVtwtv?4oOTu~7S@Ac*7FK1J^Y|K6DR|DS^my`fO z@-+Q14y0Lot&G?nFn=TxQY)5!wdN5>N_JH}dHk5ysQnfPhidp%A%+LA9{xcnM2^jl zb_=AFe?}-wRo}IBhrM?|dOU$x5nInYJiv3YB-Z)BeSA~)PT4)z@!3B#NgeIKLI3|b ztB|$LbBqt<5!}CSp!xX?D8DUQJ=P}^KmN7=w&?>vFY5n~bi@CKG5>F`=KuF9TyQ>! z-TEKR8EoKQ@3trG@&9yTQ+AS)N1lST_J_3I2&f>uPd@tV{meviuJQ=Km!Y{&!aczg!KRmuV?U@+kEC1~@B-km#`u zPlyB+1{Zr`n8xQW<8jO)TNV08#pnVR`acFEW!ABg=^L{oSyyf^A-|3hJTrHea)ND#vMNM#-dD_?#2Y! zESPXIB!g$fjQjcX=e}Uz4o(2$7c1a51_o@`hV=jN1I>{<$^mvizjgr)6)?&S3>$MC z9E4#25+x<;Y9;6@&si`g(Cm~Huf(Sd3 zOpL5~Pm44X-nnPQjr-$2erJ@{&Law{tEQ%zNMDG{pqisjn_vmHI7qtBl$zBZG* zZ6kQ67m|T(8LMzFFsq<|o`yz?24A@+90B%aTACSSA;~wpBYl0JZ6;WLk~$jP7mXjQ znXU3ZP6L~xLee3`Jv^qpJuO-xGn0CM-`UxvlC9v@2->lEH_p@ZT#n|ez|W9-w?Eun z5dMK~*QMur`O?+Rt#l646QS2!Sb^CS6;yjik15k{-O#>2-{G%_bF#qg$ zrzay{oO`xoW%|vt1oX#A)C&g$WG|Fq4v!p4i)( z+gY2B*Q+dM9Km}i{hL7Th7eFXy1IHVyqCcb`315BrXOOGljT_VL3-21B)Q&YO=UXz z70<+Fck-cEvtvl7*3dal?7JJ;%rCaeB(}?n#+q1S>jMWzj9eHQ@0Cej4nZxt!$`nF z@8alK2i;f#@=o2Rk+zmrv0lCN@5z^7cW=F{aR-7Bv?^-)Dl?cOYb!hq2iO*oNMS>d z#Zzjj2%oFdwV7EE*IDV;)T_sr97dn-gtHpFAQA#8t7tlDqS}by0!MTmwp@1K#)ZUWapTDPFJpP-nIplzt~sTxrJ5 zo4{TcN(5+&SR}cjezO;|kWeZD*wBEx^$2)7tE;PXUws4KMwi(JO3O#07RK4 zkmuu;kTgCQjmzrOvok-C*i*v*?%=C~^lRgh)Mv?6VjJQl5_=LNRiZYQ@9ka5HNX!1FAc5!jJ2ZA}y$hW%-ZSaDb7GJE|OAzIp zzVj5#k((?hZ;LVocO%w5H3dW{$-yWS6Z^0c%mlc|EDd?Et(=AC%*}M*v984xqB-r5 zYN%|Xz0PRP?b4QO@!%vkD9<=*_>b2oFY@`c}NcLJjR|NB37zmv;J*-X5@8; z7BTs>A}^8!t)XU9pk!)fw6XA3sb`|)Vjo*qm#k1tc3DD?0gX)r`Dkn}hIp{5X2j@+p@0yE;DW*f!bguJn4j8*x3*pb zf3^8Qg3MsFVn16*R^5V}UIQbfFeBLYMQ41eqYn zzw!%LdmgNQ_;8c|*Urj{43pK1#0YCA?@!_3AT@jeJlzUH)MsB{9|{Y#Lx&|L126+^ zXHJ-e;?h1f=x-u?DG3QBXTKo~C?v;#Y&!3~qfc6z)fh_5+Twez@%C*-cc@;=#UhYT zk2aQvg=A@?fsWU*+a3z~6>yRssCnzwIX*)#SQ;&LhPbQ_fbeAZ;t^twb@`b{>kk+# z;1y4>TlCQS_j*os8Q0@cDM|srA~2OTHGz*jIpNh2pREOH&u20lKq##@vF2E@AaM3Xiv0fS6CW-v05#VjyAE+0mMdQHk29V#$c88V2SQssA#x>0Z?@0 z;;G<0XYueqWk~NZw~xpD+lO~^@->wpk!6Tk==11&Xm`0%g)7x3!(-G2d<8eU;0-7x&!Y1 zdM9cC5`+GTY4#N|H2C3ujgkU0e<>&+!TjySSb`dvAY!xWVCyiUFl&i>yj)QX3I1A2A@JsWn@9U%o7W6g) zhawOfD=RBSjUdA*RSR-hoO2RV>tiquHOZ<(5G}!gEWDcjvl$Jx%DDoQDRh^GpZ^R@ z8*5$mR6v})n-iV31uWe6T6Yj`QZ>}pWty$te5;`mcP5L4<&8|R!Uc5i2(u;+B>@2} z>@X)N$oooddXje%$wx#8f)#|{%6Pb{!Q1-=2S+B;rtz5Rf9=mS$y+I?hvqVNNqU-@ zbyc-!=m0W5W3Q-cFc0WSU@lKiYN2C6UIB5E^%ArxIWiE%ODI$&Zm2(hGSm8!|19h5 zjHHs{Xm7*);$*v5uBV>s{d;j*LAH4I(6|+6ZAG`Ux#mqdxqI;AY%dQD^S;q+0hbC@ z-51aE6))WOmXvkUV`H6vuPcUY0;+ws?%_c%H4})^s~P>nWWxVX3gBrHLFBe22{ z5t+v&^D_g#nL$Ws))w%($RfJBIyFAtUwxd?m)yc4vi^WV$kp0msbn2sb~?J_sO&rz z@00rK`6dOvE;|>#eVW{`%*@W|dncfA8sEkFB4drU_#oXQ=mW{9YzevRMXO!-r@?iwz=jdaXU;P z36XjEkT_ELT8`GH7bH2(r&;ksWZvvLhBtF@!k^Q1QA}Rj$RBnws1jEwjsh7M0KvzP zKT-HXW5I}0RWv)hIAB#%$N{Qxu}<|@BA}$UK}5gE%7yMbbBKvceM8&|{Ma)W_9&!t zMn6hx1}u5<(44bu`T%@~`8#(W&mir~^aYeUWL8%-ikG2|!ur0x9l%4oI+QA2k{=WE zh}65NFsh>a21hhVkyBDq>eTyR-$;?ida7ky&MUlaJ^4L^E@CIM+?F!^DlU%O$w@OP z(lSZd&df||8Z1VZf?v8TXN7!prtMxCEgx}a7^si)!swr}!Nry&*yw*Vyk3x{0n!3=T zbwQ}nPi;Q0sVPB+jPr?sUQAib+|XQoaaCQlP-C6Ph@FfTOnlvArZBqor62SUXCNeg zh{pE2df)b{!zP#O=g(t#oUi?+G9f%Yk?G<+3u;V*1I*`GII_}pbA4AhwDKwO(WyGx z%0v96=lap{XOTrA@kLf~0O=Lsa;^eD1=oZdgJ>CW7Kw&ujGE+2Nv7HxcwL;7j@w*S zcx=Fkhbe~!2YH#B(KAy3Q>R1{@ozyy&s z@l{l8sLCrkH;ew``{=+eccIpMqR#CU{TL@HUDc&l&9goHl?@r>P>jc3k5s^3BMpcl?NMeQ5poDr zUO~ak-26F=;~$gZU(j?7hTOmo0%?AA-2aF5&EOGDzyDv=of^{ND_6&%;o+ihu|*m+ zM_n$c&Fd3cfj~hXI&sF!W!YrF^Q||%2j$j1yxLM8!B7_Jd@_O%TQO_bJzuJ4P^Ika zlNBn}E4#{dy%$JDCtx?hx7OzE;6})UDnR0kD14N@zT19 zh7ahO2E3vcGnd^BK6wHdAA*3Jl_(xMyhjThP!H~JmDQA;i7BY6y4a94f@=O%dKg&_ zD8I1%ePdK7?_{H;k4b92MS8{l(td?;+WF5R*=DybpJjaV{C*it1?nFj1Q2MD9&Muw zoqg|!6N+hTD}~Zv??Y+{_4Q>;e0tdt*Fr4W%t8(F9j7`v)Jka6!?s2SvhR~)4l9M4kDL%Eh+oih`H-&uW?Lf zzr82JsmtdZyO&T1lAWvC(anjKndJpDlQI7XHv)*|x4b-dt`#B}!#^tIZ`h$~kTxV| zZ-Cg|*=^!)W9?J{c>93gF}$*p0|PQbZdb{`$~r$V00l&lu(0qS!x0!qpjU$5K#4fh z2EVU^edi8P%NjBQTr_}R;dpyC{|!C(r}|29ea zd-Ha87yta2QTZ2?JKXlXWoBJ@t)0vPQpu| z+6~r%^B58aZ(ET9PBKwT`?)4TGi26}8{)?H7kkxA?=gaD>3R_3T)wcK9}9~=Wy*zH zZrE?POldQq@LJCaU5`h&llAoVf#MAkO28V>UqZt6bYyI-;xsNVkCq>JgdUJuv&^>m znk@VJqWCd4QlnrC-W5^*b+%Q_!<^xuESQ9j5`~G8I8sV!X#&?*QcybCdU;52z z9i)_!%d3>;zx+ z=)HHONta$jmlirw1S#`z?#$e|Ywnsge?XF*ti8YN@AtmXv)iTzbHC*_5(Jc4uGRuh z{(UT%h)Qhs^;{?TH2BfSC%VqB$^Ei_&i0j-7O7>uhzXaEs#GW2;mx71bwNQ!qr`~R z5X&CC4>n?wx(~VErza;HUVa$Z-;d}GGFrxUNJOTk4W8j!PH0C7k-o{*-_OsFQep5i zJigL(*^vHN{jq9#azcEtw*{l1%0vp=HG?B!*C37HLKCnV(ZyDW|%>fAW&*GpIP^S7#t=*NFS!R9PPnWE@7N?03|?m;!9 zMoYfx=^)Je6x4kAjm|!;|MKL6JXr&w99W0ehz7ENFyY@h$NqT@U#;>Z=cTu++l189!IgS($lY^& z5+y?a__S~(K`u_*hH8^WC;b}aw1S<317xFjUS&Ox00UkF(blOcXyN%M%l&J*ggz~b zR-g2)ou|#QoKi0pz6`Ot)@WwuUu%EoRmz%65Y<;PZamh5tlrLnKMZA4Z4dZOjGmiY zec^z3iW!{Ic^B%X)~h}%z4c4Esrvbc3*b^4ctSt`K9+EXEAfU9E4HW3R$t%7Ne%xx z7q^5js;`eDvw~OIJdlb^JiTV<&4yBk=+ zsK4LV-5pr+^O}RgyrM5f35cL?m6R}h;-rGNP;tU{pz~%{XDExQP;*MS4ae~0y1B6K zAs4Meis8qDk4Cmy+fh~ZEn_CZDmxF^t=5}8F8Me~pX=QP--i%*n zw3C}#j(eRnedORZE{y7Qc2(jJdp9Zv{KQyy_Y+`X;_y5>yDk}&^Z?2y@su6otAIio z(x!|(V*nHQm4W@W!C^n5l(@Kuq6+2UR%Y2a^NDwhWKe>I?T(hZI&-voSqCeR_R_+- zsqHFOSkG>8E6&%qc11xf6wU8>WK~F@#eQx)y z;a$(&%FBK6QKY3+QkIqSnUtzzf#k00pg%*gqb7-el#L4JL^pYV^B z1bDO#GmHM#$uqN8g{pi#lPC9C6Oj#a6JERvHa zFJH3#GO_FIE8QRRB|s{C=jt9ix&_<$I;LL5l$UEP=kd_mw63KUg+9U2H2l{rATKaj z?18RQ8efxTz4v(r8XcMZhzW`lwa))(VVQy4v9GKqaUV*rJ*Dgq=@G=PYj9@fx~C;> z7|xyG($8phR zB$^(y2e5Z()z3P+OHVGP%uy(l;HdS?5gCqAjEtCGV ztbV^Nqu<&we7hROZ_@IqCQ8i9O8Df-X+>w3e6oV{oUegZ&wgE2OF~15LAY_mAwTF51_xHC$^iIZ|O&7jD9H zi0h}zu}!l@Mc-zQC(_59MHEicn{1uDnG4hRi_T9y`FXw+`J8lpOvj6fxx8bA z^=(<(`17j_cBY?7XaT02pVC zyht~-Ze%u|-60-iH^$<;E-w^!Q|}vo`#uYHw&FfsoLVw60nS#sGPl_W??=heO3LvU zUygqc{C0Lmpa=|%U2{{e9sFH;rV2Y*_@NsVG;dEzGc&El#k+jU{2c66)}_rGa!MF0 zmY%XuFI6^0+rjsT-XYl#Rq02Ar@BIz<;|cdhLj7x-~z+9<_pEU{vg${XIkJZP>^q| zIo%saz5kts!5SosTR*j+m344F6{;vXkw^*n*-po0?-ob}gOU{@FBst{OLh4IE$+Ed zpIRq6C#Typ*fo`dv*3v_G*h0$>FPuWYw?93>t$@3w}!i0y$ioT(^N|2F$&3NNz64c z#)z0sjI85!42u*KfyWx7w{1J-gw#~qtc#ymNyW)|YKgZSxQr8%L>@1%44%rgw9??oo|b-QNWF=!CzorIM)dSl-6eKFuwxL1Do6|k~Sn{H87xu3L1Ao zMozwot%x=-+gtPln2T!R8JQZvurlBXUvz)}Zt23%iRn*WAwKjrFieDIs;Mn&t+6dn z7N4II6aH~$ro`IXW?OKnam2o+E*o4=wYqb99h&-oswi+EvfibvkjF&H`THZVg70q< z(^wlBJ-WwJjloD%pp^87FHv%GYVrG)${ z@2Efc#=~Qj+a))Tk~n7+AfVIH(fRDmL63syVtjo^9%aA^vyo%3GJd_R!74uEOVDjD zkSz+&753@q$v8p=@-LJ!Zf$$rJG^vQ*Jk={srBG3CDfR51kJ>P37OEMpdcw(!@KEc zZ_HoYRaAn3VeV&aQ{hqQW_I-0=U_g2n}kI) z-E|W^E34DCNZU@b{kCaDwnkhydUJlQ!@;zpgPyQm5S~Cac%Qds3xSw&=4qP8_nK>5 zS+T*;kB;CmzA!0BTC&gRL*t_^IKB+sV`A#YtT0MgjPNyaP8ebLZfy{nq&B`fG-o02 z*=g_`XiTdA)cu0CIs6-;;&mM&?2vB!-_hai^j_cisl?1ws?4joA zb>$JOtrgw$00^_Sg-J?E3Qk!7#*G>7B~YwyrKgVd2Ev zA(0Hurp8|cDpyzyJNg7%R#I_FAt5$>9TpcQH|#x={hKN!~7n!;XaRg7LON_mRTE&}ZQ}NN-c01*d6;xD^3UW1$ z%lBSpriSLM2M=NHqxxdA6w9kgggT}s=(S_`Ba|A9T zPGk;+7jw>FO2vgS;qjHWm)pE$6a)K>=XFCvD!+u)0qX@iyu!ccv7pYnf072LfFs-7 zZ}3eyF+FkbE*F0wz4U6S`L9+Q?Q>JAL=4(Ti=GwEG*z~mHJFigxIvNbuG*OzF5e%V zkvLKeeMstjvM+6eQZtUPsG#0>%=bXDbzy9*vRqbl2JiglPcLTi2f^WTDJ3H!ysDHB zd44Qw2$fej7$Et>B84Xh_46BM8k4jxLL<733^%tfCYy@9+oTNic7sxgmxtr)Zi4>9 z5>D0{5BWz$X*&CS!CN>CDVLxBCEO6Ip2a>U5+EN%t1u&G-p6vMA_heKXeK~$5>%}7@?=z1M*!^h%Szbuth%_E&0<{b1%F2}eVE$ios5eD(Qgs@^u2A_A9n z5G1?I?2J_S&C6}_3~t-k+c?}J$t19P0%hM72O=0s( z-4u_byDrHoQdD|e)ZLdZrC#Y;kYTXY^i(#6qO@j~ZuQ%i}48EDpY`t@Q-4 zUWcW4Dw|hy#JL3OxG#IRHrdL_HEjL(5fdHVBFAhN^5C^$U%04dkrwatl+DZxD(G1U z=fud=nKw73tH&{!e>*<@TkO|H?&qY0eEls4y+AdM9bgl+R&1(i&1hNAo{Sz+7Itvp zd#W?toz~o+rkkutWm&TSm;&*-K*VoolP-cvAmnRRNu)DTc{v*yl@2SDWwi@7;E1=a z138j|+9o8Pj)-r72kx{9KFQ9{ALx6-<1`7px!`9(xbEt8OLb#FF38I>p~CIv>iWr# zILpdFFzhK;h2hTClnTD(OhuJ{eqf&rl*Zp9gKgfYo zx)q+pKkoQaHR-{|VQHC4Uf%RhFFA!%(_9*hgmvb&C%I*;TZ0!&leVkrfsIpNIsMGg zZEgkxQmu}>(bNP=3?@=-ulKL)Dy>g^ogD0IwEl>-bH`uB?p5x0 zJB<-_MV~t+pXUyS4JUBrt-Fj*PM!cibmkttsAwyoiAnC=YfhC+ec}LYlvvw@{wX;C zBY-o4)D?(2uAI~3HtCHt;}IWeUeQNV85FXt!Ok)4)FzQv+$(d24YkX-7Vr5dE_6Lh zTG~5;85p&u)!E%U@00P?NGfcrGbR9f>EZEPlIHColCc8)I(n7l&nk%}-@}TEjx&=7 z*Bs@wwc!Ynf<&wIHC`uN`IpS$Yd9PZ$VHt0H&W-~YESt@X+=vO zYV!{S62#{>Hlh<7CQfug+pEJIb95BUpxJ3u3dEn~4GrG*>V+|pE%E489}PA2xP$~X zRmViOt=C%Z0JsE7$AP&g?=`5`6qj^`ETAK=*Il8*u(U@o}yYK}t%0F@t4d5kfv`7L5TV-eomG93y&!A;)Z#XAazp zgSfM*N}up}w1<0QG@ETMUH7XjbOgq?-zQ!>$a- z&IB<<2k0YnQ|4;Fky=V3YaJ`%ZCeeB!6pSoEPiap^9G;`h&`718tjE2RSMKtpH%VtyLY| zk^6#RT@*ihXo>(dumNXs1zi4bLe0dh%?|>(A$;{5fq(1r|9>@f9p{oUHd)}Z|N?*Sf@WxqdkFQFkn_F9E zUt3#S$HtC8Yz{hPJPs>C-rfy>`6|d#o&uTtF2*{==GU&i;kS@XACQTIttAeZ@a4<1 z+Qg_R;JGYw-FsSFQCytL6$M6F07nPp=9C;gJw2%DF~Z@&pFcnUo5Y-{w5CEVWCKio zx^gQg#~iSysz`NpZlLs^LSH50YIR+sqod8u^MG-sq@=_`85kI#x3kdNAf}h??GyAk zvfCIQ<^Xi{+U6!;;yTKQfyPmYHAz#tRr9~&wdvQ>vsVP!-^?Uml_{V|p^}6?24}zC zfs$xuC*bSelo-^!fC8Aq>%>^FA`!T?7>mt%rjU&PLX&~Bp&U1CY-*YUf&`@K!b0o% zcJp7?pHp1f^tY-kX`en7f2yRX2PuHDKg9ySU?pH-0r@Oo=8?qma^K#`sUjnT1P)LQ zrKPpSb{S3<&xICzBp9}RIlOx}1aM;IS2@1qv=x|mXGnE_x3#*brmn732fQkc5)!_k z1e;|{$cWTc3{&vK`QEu@41t`Pan1f%Spk2>z^p1#DCfA;5j;PiI$37wkU2UE3ZDqG zzfN5)E-t|MKUL^)t<&G02_q{j+29P|Zy0*TGXrO0(roe+eKVm5I9TYl(12PIZC;E( zsWWcGoKK!1{2>TGfV2XG#cI`P3BCWtrlCQ>C#9jO>9Qoj*?vz0x48Jyr1znJ+h-_v zQi4vou?`JX4$>T`KB)>qDNy(VD6faBtKH9*^=8292`f5ub$44#mS%E3Vu^kY@E#dS z!s8v`W@^hD5VP3I)%+`{kB%-HDmUVrzK{is6CNHOz^UTy<`y89-j`T4;BN6sY1lvU z^9}H2LW(FZK;&H}^x)PK zoYY3{AN~h1Is^1X0A1poHL|tURaI>Rm1h~&@!OJYcpqYRwZTI+{_*sTf1PCi-M}B( ztG7e7*4tVCCoo?7t$vr~U)~yocaRVA|0hX0(oiPN)pHBt9=DBP6@YWa=VV5Rr0E^^ zON%2b2>xkcQ2p5w|I!zv#+EloR(5h*LEryxqXPie#iE7GV0Z_5m&6dr<>jRXZ3YAa fA-Gyfu0w7*$s4~YxC=-r2t-<3UaU|=@8f>}-@x+XwDP8=VX3>N}{;7dw~C_y0C0w9p; zD@Q~0+YrcIh@{9{71zW+(>Sg~;xpLWMen<6k7izSG8w#%)q7WX?H&G&>zO*ZaQ#iD z82XN-AJX=f!_rTmhJ4Wz#;g5Y#M1JR^k<02mM&9qT|H9lp1rpA56#J~Ef#k*-n=Mw zjY2b1Gj+_~a!=5=Z}0nKzW9aw^5MCaD1ZgI`}jQ(g{DfpZNaPt778dv`wPo@y%iWq)lw7t9E-q6QAB>7(Ng`#lS&UozH^xiM;!JZs zik0uJFl!(!A7DWk2h17Hem7ugm)jN;6eRGv$a#64!(;_hcwItAkG5ug4$vc5I0QNQ z`FtLSQ(=M^?KV&=tJ5*#Fnp@VT6%gP{)`o6h=-}EtJiNgx}&xE565!T)1OUztrF#R zwificIP}ZBA82(8@d8+XsL9mgy3ikkD0I zUF&h=?&hY5$=CPMul}=9KKq#O&2f~v-udM01$s;H8y#6}>7`k+o7#p+>C|3?yg-pb zL!)ZmV|oS#RyMW_E@|e2975E<&c-GtJP$@aGXQ?$V(o)$+aPV$E%|{kyZ5 z7v+5dr`;11H1zZyOPx^(oafC*FM;#@A$ft5FZcV~+rPV8+TiyOnkCzR*M7`mKI9*2MMNP7i$nt3Mr^e=W}99DXjl3x4jy&V$J)z#eqOPK79SzAf=m>C|9 z6wCOtvBA&J&jp>?oeyG0XcX-tQF;pkwZl&^7pGK@ydA?iERD%PZ$^&_#9X7dIiIG4w?uB6<#TdDMY*<&QUD=v$ zZPs&7*1=&#B+p! zoee((ca{h&Epb8i>fGV?hzMbEtW{)IR@Mir(L$e#akG^3Ho=*xS`V)2teq`z5&Iig zQZBcGnCn!$4$BTbcNgg_&j(&UP~NAHh=_o1u$lKi0Z$t!ZTXtjJI7l9vs$0Km6Ur9 zHkJ!(^#Oa*tmBdtars?x@-E_9PIOr&3?^_e9Kp^h!w*|%lV4m}QC8H{9Os(#WHaep zNOoH$+}E(wS0FN2AGNWsOcW?Djf;rb6TCbjDSw3g@afa_uC6Zg zI84}-6z*Hg;y>vSltaZvOGE%geHi8DQnYs02SIn{-7p zP6>xnaKB?=cm6XbFL*9F0sE*Ur;IwT7Mqxl$pe@j8wS8(sDox%0j*4nv#}$ zoZKU+k(T4McfCC4S7N7&!4H!Z&3=G)kdl%aZ^6@HnV^L8JdSE$tI$D^R{bAGVbCn!G7Zq`eI;gxUuQ>a%f zm0&aW^KG0gyPdGHa0Cs%2vzUHn_3-S$3Dk%Z7JTEfJsKLSh|6nfQI+i_ zLRM+kr)P`rbe~xlH~Z;(OP&62cR~*IYFrJ`!*u(Gu#aY#?+jX{FJHb~1uF<$`AvM( zk$ul-=}qs+-b#-8JR03enHCflmTl&CIBrJ5tS3|G+4Qw=jYwi)s$erDbbUZsIVG~p z^Jtnt%z0v*jU&}|>Km+xjchwztgXnnjh~M%heLdWu9f_JJoN}s^%Xt0QGVG1arYxA z4sh3Ie=p3R%3Oao-$vyV%VxIO@EK=>ASX{!qC$2-%F&vMmX`O~yuGdMV|@Q148O-= zzX7h-PdKPJlQ@KrmAr_fl&pftNT;rO6NK=Xy?>v`Y2xK&mGRde!UV#LTQOIm_6==cJ2V zQBiTD<}KOWM6n5dOWy9WmNs}eO63gHFWJUduU=JsSina5uHJ&I2OrH|8jR$Q5Zj>; zx`Ln_1V3V1i@vsx>&{n?6(|;zn3M$P6~h_~#vz+eW12)-sayCiAJGmCWu)0+?j{4= z;Irb_I=m*tdvKZ~oL!Zyrqn4SBJ$cM)tesQTDQ_()FxQ6-D9&D;e|ttaqLezew^K< zU{I4qms5~QXhynhs7#nMvJ9alH=2kj_~j_%;(@)|Vi!XE7gXC8owkFkXsM~SLL3Rl zZ+H$UWK2xCK&IdR9{{`mg#QM)2sBt7)|jxpBzp=d^Y>OT*BxnVzo#`lg82Sg1wE(4 zgEXb~^4a5_u1}Re#fdy{+R_`B*LmzwmrDqwk%57bi?-gE%%!NOQRc>RGOb=8r1RYM z;l+rm6E{Wm+G>@iDy8!;XgWJQ%#^s+hZKRaPU+8F1=ZyoL;m0mHA}9U#y_ zYGr8^QH_-da!6@dQ1R1Z71Gy0<(6i4%TK?uM^?o!_t-xj%@o>DHBVXvGFP{4I z=S0H78D}**BRH&()!VDeQwsXCP0N1DjdpIie4Og)>TSer%u%ue0crO*;yb0Jj=8Rf z>pu)}}AW&28`LVPax3*nYBF&O@8irdVf>$ZCnmz z$ssP~@%C&t<>{k`ny**yyBR;fIRvfWFuwjg{GpbH#vAU+_ylbjj3ym5n^Z9|3aylC zpYZV`roS&NY{_MDA$I)d>F;o#xau4GHMT|H+v9{TDMm*|NJvQf!wR>Apj+3zWpAP; z5#jHiFHN)Q{_@(#RTkIhzo86`N%Z7>ZTB-I#7k1r@Kn1>@h{NW9(J0jQTCUPW#nUy zxGA5)!;3_o8BVX%sdvf>n)|FDUdmN{Wg;Pe$g+xM@8IC+i5dE(oRE?DY~U^t(J7~# z^9FGzhgs*FfM(rim5RE$Lt`^kTKxRsMFB-0KavQDM>5~Peg1G1MLw*8D!s(1^GGgt zxF(-678n@#*_Yj`^4pzY*rYxA%O{k60}XLF-x-&Qt6ssmX4zS>v7!?eKn5Uq8` z!;{9cxvc*oc)qqZwWL3xuJHY`0S8*HHS9gq@hhiRUu{*^(rWz<{-pJDWvn(a{nPqi zU!0|R`^+;O%=(AZ20Ql9Vmwy6(0iv_mrhBs*J}px=je+PIJ5f%KHf1TP!E=7j&3U(A4noeN)3$`g4MM@Uh5KiF z%sANCC9sIZV9>8xtD2Sao3Nxd{^;a)tvtZ{?RFB%HSn8jC@wzU5=Pz0r-Vn-0vXy8 zoiY*77Qn@Xg64V?7Y2Ye0OPW8tmon4(Lb43h}X6aYQibIACr@k-n;i=BHU#>C7_I;9~!-N@4Ki@*Mb$=-5qZs@vZSCdvlLqh>JQKkJ7?z(_` zZj&VOTgD;yQd*@NGYewwX-)2@NOHl8hAEEJmupIxtR5`0%K=8~xa38GCXp0alRSLl3^k1?#?sao6H|%d&PKW zPN{}>l3jXdYuxtq+)lErP>4LIlKlMq)#&1m_Vz2H%0$mRTV~_o?=fW0*^?qzKXS0| zveq8{JfGaju*PD!J1#u@-p!jgpM}Rh3#iss8f?iUvwKy%u(aE%$b7D)t{7|gdwNV4 z`d$aq;xi{$P%C`0mC1hKZv45_LQ=l3yF=c{vIUcAmg2RXZO^$KvLvbqUrUj|Pv z(fg7XLD%rz=MJN13$CAOV3L_`rQDL%=z0N$s#Eyt;q z1Mxv#HA)WlBuBB#UMpcXbHdqj27y2%dqiq5=+(NbdU;K!3H#&Yw{%u#%O#nTDR9=^ zVf=$rcsypj-&w)$6LM@6(A9r}wNfKTfAVK>c~m_QPdU=1pyn%v`8YdE8{%;nalY+n z|i19L1e63?)}Otkhgyc!0B}2^f|(w6?>YApGOUrquyQ zZO=WJeU_}<&*|+sH&W);ls`+0DFpcTTSHcv>oKqR`9FUOh-brR1$5Bsq9Z$HWBO=) zhQB)Je0RoUi>)ACURGG#xXtmmbobW$xmG(2(5#iL7(JyKekb%WfS#&csje3Q-)nGL z5F|xLF7_t=7<7cs0_rs+dr6mKQM!lgLTf(p8N3Nk}Di_&(qf%jEXF+|Vj^tehYVPnI~aXXka<@LmY1|MHcf+I8nX z(JNU&?~flp0!-0aJ#0Q`@tQ^SyToAj#rdrG9}KpdOnLNjH7^z2#v6w2WIEZBH#rKhFYwS zJt%^YL(irufxSw=R+pJrm4kl8|9^rdWPE4?K zc2-Elb31$uk>#S;jp5pTBVB~Z&3r?b=$(@kbv)^_AHv8ujZ=Pk*OEQtxQY2%(9EMM zQ(-SBi;n4AF#e-9<)JtHpWwog;-V-7nkQCcXl^(4LD&q+aiZERr7&!3O_>%jg(lsE zZ{C+7vcYk_7V)w`B~hydTwU+*x4C^y3i%nq?c4A|C|P&LPi%s|pGSwWk-5@J3OWxel%5rVUyryGt(7rpC1?;d?cW0*&e*{|N%@Lz(SBzk%7c=jWP?ua< zO%V(KSxob+Kst538`RO6;jFcfd6hhl8(VH;`)TLaBb#JI*5|xg0=*Ns&P=RF2E0h7 zC+BHiok2g@((m%(mP{UYgwxK>ZO8tzaB-5&nOgD6Vi@desQn-zBeUNAxA1U9Yn`ng zn8gqb?wlbdEv;I=Ro$kzzK)#O8d8w#9066YpuKV$&V571gkj2Tm#zHhl3s8#vMJSn z6`^6Iq(8)Wv#6~2n^X1EFt5i@+u1P%(x0pPceIR`RYwzzMQQRr7e_Ydon9L|0Hf_%pIs`G2V7BlTol)TzFlP@Q% zGh5;MNC46BAnd9tRyHyPoNDvAn0-_lf=!I~?3tA9w34pmj!69j88cLw z&%vc0pp$K&s_I>K>B}d+Nz)N@LPz@4pUT z`J7JuK02E9+1l9XAx_dj+T^UYSH)NsJE9fYk16lnQ&dop2zk4ti@)NhU4gAI`|2#h zKQBlrE;&{V#=&PMnhAYvFnT!+YL98NbC_ZnhS_xw6Xqkqvm0I)E_xYP7@6s~67cqy z^mtOU8Y(X<%2`!al~Jc+wa*8$KzezaUsJ=!$e%=nYC8pYlP$)Ts!UkKlCb+mC><+`BhtS^p3V2Q##7 zMOKc}Q?@Uy5KxO}C@L@81od{a?_a-=`m9IVyj2!jnqGC$CGRg5hh$Vyumg zji)D4LW6^Y!vsfn7Y$$)KO*Px3ec6>wpkO?h_qW7FO+N|1MC`nXI|3K#Iv@KjM(fh zu3-Wls=wls%QZwMCp#|%a+-boNON44u&O*Usv5n!wDs;(6DoR2SYC7?Gc z(AOD3+6y@j2(FQ-XVcRYP|ogs#l(b075Z3Oc4kSh>}bEB@GJ?qpO%!G#$pWX2wLSv zRr~5K3})f&uZ*^3Q*oTZTZWema&4@Kr>UE)ChPt@t96}5u9M%~t~o2|5F#bbP})qq z=Ey8MbYbM=#6c+$5E%H!J_s%|`uoY?2M)Rj*Z-X;@duyL$>=(NCT#JLXlv6emBg;@i8)h?Abhj1HThdkEz~ zC+Chto%{9zPs+bm^pc*Fn!D!c1vK^!4(2M;`o(H%M90MBKF(fP&bDK#ti%TjlWV}K z96XN+d6e>UlJ3`#X1$O>Cr9ABpq+@R|QI*I{5qh`y6lj zBqzo+6!cSGM(GvgqPM$4VH0@;Q5?FHLWpA-N3U;HMT%l6R`AlYuWkLZM|{wgiMRW& zx_f%?@$s_;$!wDqN#*e85Owe0zh@X|Ak7<+PLKbw{)e49>n!$pR77&wE=BIa-p98J z*mt(G^|OEcXe21_&d=)_9^XlKW*PbXE7I}Lo}pE} z4W{YosJOrZD|@SmE;lW$I%X(2I=Y)(V4a*NXzRrB`rJG^IsQlHpZb=-kD~V zXO$ydvvLM>M?+mwlm3L{J~{LkuA7xhrnQE86?&7Thpp6Vs&p&;Y^%4>fr6AHs(n^m zbcLk7)RDXHa|O0K`uelIZz!V54u0urYUNefsq;FGWLsi6WfdraH*X0Rhd#xMOjr4x zRbV@WGCSXINW1ohqfhB;)x2)!YZ3y8m&g{MTpOdo6N=Oobk7FO$WsUE8zjEp=>&gz zA>^~kR2d_rZMtUEJ0~`0jv6L}bS?6(9`5zbKfGtO-(KSZ56{@RnIVGh>f66&uF>@0 zYg8?{z2~9|Ub|EpesHPuu@{dts0DbgrKP3TJ|)G)#gpYwhgpZ)kp8D3#Q~ozmO39e zJ3D)F65vyox$TiO6G67q6gl18-IZR8is?zp%G&ryL!n!9O~SP`d=U{_tPtN&^GI13 z4CY8qM5L^xWoc;mR<{l4I%?&BhGtr`vapyyAbjR#=1K3+0kpssEGKE>fC$mQt_SA1 z1n;#h?g`I+irFvUge`uxegEH=}BB|ECtd2af!&kDqC1 zXozU#9&+1fB9S3^dF#Lwhd(lbLgmFbRmwA4iKj`3iC;q?kAa`4qO0q*+&%tL7W=)4 zNlR-h&zm>-I+f{5(Zn*9m6dlOzBr8CwVAF}UZ-XC^*$=Ys#V%5DvpPLxRDE=+}zw; zw&rnfKz_wI_iAzjNP(G)HeuCNQ6a{H^g|G&GycEH#?I0Z$4v)~35I%amU&!+>Ck~b zaG^p{0!S*}KQk2nNoxPMs0BFZgbg}o7YgcUhI+1S-FR&}E4D91b$6IsYV07Z!v8Uf z@vlAx{5PskmA!v`i<)iIf48%NZgY@+|0n-*qT@e(Ok>Tqzzv6_6JgyQf48}w*US_S zN!4k@PA&DsdyUsp2?w+|fhza)%a@9ZikyO&E^t$bpi|#WuZ{v^f@x3u+T7fL<-LN! zyu7fWAh1nm=CldGVy5#&0OR|G|r>X9*Br!HxG3<>jQ)GgS{JEiH6(Jhil5 zVL^TutdGC9urM?<>|i`vN7YwVRsH;_U_(wzOH1}eURpXM!)$YNvlLcS11@FaHArdR z`gp15i9Ok++Du4TnEIqI=0gxEvywKDE-DS1xb8qwb#?n-;Ii6p(1?q--6m?yhQZ)A z-;yV2<$0++1>^XN*NaP~PeEB5!9v zOm4YUEGa=hp1C2zRC9A?U0relc`nV1_w5xQ7V3`YrQs@_r6Moxufe}}yf0N^Afe|{ zFpbb*GP4nn(s}#Hp*A&=uJ^HdcBzRjd^0W$p^}PF;s0JW_>L1?1H#9A$1SA#=16vG zYSEyEX061M#*rY)KEdg`kZNI4QkQcTCeanPUEbaCO0 zjeQ@Po}b?hlruJnuiRko8SKVQY)C5g8x-lk4)@sAg55^_S|)UAp#mrP4hpZ0MwDGg9|5@4XE?CRN50|zG$!R`FV)yU|X(^AfW zioU*lI58qPisbHHA$nOE znH(EYMh38GpT)*S0)#2K$TnbK(yKw0xA;gVt79Q6+jFu<>Ivdc=jRUg_IG6 zqlXXkwUC{IgYPO$_g57`@&WH)?Xiz12dPZr&!0a*V(9kH4ak`je}eg9!Y7N_I(?8f z(HvsoEeBzjimIykxHzTPHq%v%yu1m2CAVg3Dtmk7T()4ZZOqNh6_QAM3-SvK)ooKb znRSpkS#@d?7ueu9|J7mpk^CEGzyow>$Skh=VsRTm z8fs=qzH7<8iauNdL=l(Q*Xc=u)@+@edPedT!^71dLWINtCQD6C{r&s*>gsB4 zu4R>#u`$to))$P7jNIIDo1tVJ#rpN$0PW=EX=6U{JFhHZf8zdmmu2Y*H4$sc2&# z?e9YTTSk$8iS(S+z zH$2M9g-s=6e<|KzJqRRJtZnUOK*i8mPE=$}OtzX<)-O=Z<%itnXlPnx?g`(42zjvA z=D!8kV_HjFn+>e+Kh9Q?dFqPXI>P*#7+)y>44a3cvTG>v(O+(LlY%M%B(lPuuxFtJ(wBbSPh*O z;7Jr01jnJKreS|$2?Ls1VcXxXd%K3KN8*k!~fSRwo63TmkYHC_o?n&tAaH;H( zk(C{CD;^L9dfphfRK)!40YV`mlUyh~)wVasv_+;fWqT_vjo{rA+ z7R{`pT#ZVtYU4rUHTP=;y4s;tPMy*OuUok3L3Xz4Qb(V(Do^tD2T%!;ac%vlsMFtc zTF)~*A5l~3c%UNhxwe)iGr(Z;KS7ESCuaIruhyLRR|kd{i~~_NP^izJu@5j7q=Q<8 z`y9bd`~6KpGf||3tUhmfD!?QBBu-gh{!Ri^IjL!Bhjyw#B6o=%KpQa`nLD6Hy;UC< z3Hg=8>%s!@WomE%VUT|r5*}Ulb0H*EKN^mF!5_8m=TOopl0GYcXSk_mo70Z=4t(@M z=}o7W6i^&jkO_9Rb~;$qf9v-*U25$h|E-Y9f4dI+ixBhQs?uKL>D_Lpzo5^uA6HY2 zUANQb*T0x$_dk(OrXuIbu`7rXPYeu%_qEzr^6~PX0DL zxNV@`XRdoy0WA9Kmk=*6Z}OzJmKJEe7BjY%|GjPo@{FwZ?_-04==&T*KyKJ!L5!WN zR+s4Cv4>X`ZgcE|pzlxvIEh8pQwuovo!gJ*fB$|N!SRBcT3lS*VcpBi3kQFfi<47v zT7%_?m7edccv+SfvU*S@K*DrCfP^8Iih@F>3&0*_m<$0fu2CS%*2x|fOxWIXGN>gT z2Az&K!?<;9)o}3>EDhNw%JdL0g6w!2E z?KcGI0f8t_;NzR3^I~O7SiaG}U4le9fx=NPz{Zwm^7>w9G01#^w}m6jA^_b6(9p{Z zi;v=#%3snkOw+Xq zjqJYbek31$cK<^Qu)6*?!2Z|u@rrqCDh5ico!0LOD+++W^CA=K^R(38xvJ*mCF=n` z-^k&1?LVjZ|5IE3i-8{0RK@`GZSr?0|2JJ|&V8-|+nFme9dR6kyXig$fmD6|XNUbi zb+i7RKUDAdKXShP8s`X!7lX=ABRb5pG#J!uQ@d#@b$Ta4UsZl$ zU3PyPmoJ0Gmz2fSxzD#^D@{Gf4W9n11Q`Vuz zaMb-PeIOK#yYL@|EdJH@fSvHVh4|QWMYD96YaabOkV%L5zmI4Ar!@fw#NXhbqTHip zKVyW$-%f{--W$mN)Bk^H9RF9s(Em4IlJsOQ<}=$}%B5!M5p8PF^;T~JXb<$c|4sD* zy|a>UckqrrihOn2r#H|tJigA^_AR&u9t>!y+dw)}5qI+2`Ns&+zdGH2tM)}1Wj zEa?~<8=IM_Tf*$`JM!{Y1AR15WPWd@kFCex-&9Hq!dTKxG#azrv^Ozs@cY-bcrzl% z{>_PQSY~GC<;77(^g8HgF^t-lMn=URM~|=cf!?-+oQ5*Twfk&rB{q{~QIY$9;^ORE zfg1@lf^L}}*$09k8j20kQc~B}R@K#1RaMkfMC@5>)wqUNR-PbqtAhdqHRYF=H#Zg+ zC&tENV`7q0QfLcgqdMN(w~Rc62$3(czmP3>1X8mOc=SnT%FfQc9TC|8i))0Ln7^Oj zqS8@`^x4o7DNqUQ627)7HncQm`2Z-?r9Wghyfpd}xtrWs)w!5GJhH!hNr-yzAb;)2 z6D(ibR7K8?rQP)O^xwaqgiDA}a%m~6sKkD^OE@6;__pa4Jv~Cdp26yu8#iQHYRGwL zruGyj6UXPaD?G)agp21P&*}FixVx*Xqo=1a^}f&%5PY>)=GFkM+@zuHT)IW$ivvO7 zL9>S2+s6h5mL^8Ju3ox{TD0*?x%_=xkx+4n_Y3QbwbIJwoU)3Bf~sl*) z2QtJ7$=JVH0IxYVW%iddr=7ih{AV8U`BBaA65IJoA+0tQTw7#TxBxXH@S z?zQ?p7(5B4H)G3!2Qn_SDQQ#{Y3VL%4*%<(UJG1Q6f%pUrw5O*@yxaX}v=`5*1u z@k47Qvr%|45_ibmQqtzR%!A`9H%8h&tE!?=S*#o-WSpM1qM~yLIkT~c05>{d_Sb;h z6T|EeovHDwejFVaH=e7S*BU}@Wovt}UU!1=9iGqWZ8zz#-1PP zC>3xshU5j8Hd|X-3c$=2dgP@$V%FQreaEP16^yUNvzpk0g9m03f5gXk+MIwZ0*(W~ zzIHqFEnxaXOEY3B$kEa94G6G7>nS_ByHz||!Kjh^XY8ANV0p&bhd8j;xx-2%%aUT2Sk)^15&uRx2No7BY3`VEF|O`6NBnc69$DuTC+9P z4DGf-<8>43rq*vYveLAqbTw(-y?0|9$97eeoSva@I1-J48Q>;KWy8==NluO{kj<_p?g}zJ)86Feg0+-UAAB;dAM>8gjT&U#hU-F5zf&?zr#Me!wm7ULo0=MqmdE>gRU~axT z*W@2%Y*SFDzxlMR%z3JD_To@|$?9~cjmq4_alfaym^CmnCx?E@DL>7>@k13NV_8Y1 z`J(@4Ws_KUXy6+KUENk_GCGMoXcB$T|SA&YkxI7y82*yJC)GW$ViD- z-fO-&pnTRlfy6vB5jzw6&cp9NeiQ?j+;EbPRHA6AeaOuo3su@l`_^o z6VAA}xMZVf)HQ0|54xD^YploZEuYaH$!85KW%%iPpDZnQ5M6m>4t@Nyqo=A?5HJm* zcYt*B@bK9m5Ldw}w{5vN-?}vDk9eBE{%%e9k;smSV5yLm`A1tMxy<{qpN5V%Y*2`0 zY&k0jr()FLp1!>>hiqobb{g~*Q0&hhj=JrQu)%??o;PR%#NrfDD2!Te}mL3U_z zSQufsCv-b-n!I(8jjLRNJSszPt|x&@yG}y2$)8YON=mEFvvR^6;n0?5z@eh^skY!K z?@$AYg855d9y~MWvbaV)Fw!pEB&MJqI`C=qa{%4f9QfV?Fu2C}#5Sa`5bAoo6vt+! z=wPwfuE;JSLO<)iE{k?x5nau(mDhcN-m(h`I@NdU882DMkw&^~2`ovu6NeBfUaoIW zR~OX99v{0-a37Qn4sP;R`d2|MnSWqsUiq9R<|klcyV{-_-JkXuTC>y2yH%6nNqqDv zs*62$y7$zi-z;@HlX7ZoD5|TzjL#Hx6X=F)Dhle<&z~=h6)iw(4@mG|3}DOi6@`Y% z1BDuyn(9k%;^A5`Bt<3-%g~y7Y-DWAtW$A(IC+_we9x=hqG4<-b7Unwz2Wm`F6f2d zV`+JjX+#KleMn$n`lhNjbJ(-B#g2%p`C5GSfoU+a3(msi?5zHVC_-ar^&{5l>A~L8 zW9kSFppJpb>Y%H6+D|w4qCB)q&F>xjHa8s1lmsKI=WE%pxx=y<=7pz%^}nX4L*5el zJ4cL~7ge&$zI8j=X+u$P+b@EE_DrRNnWra3LE7dd=79MH9fiOdxr!5-3L zcDo95SVX(_pOxE8w$`@q?+0fmyK6bgL9EDhd9J*=i__UKbAFCc^Bxz_L%>+G0tISh z#OrjU7085k+GQB;M}${{f*^LCn2^8*%oP?d??u=YAZ%|nBm}jpnn_6Xw z=u6^n{Sv4p1dx{`!)UfVhl@cdoAV!_J}C425KS>e`X8U*XI>id+?k#0O-f8O=Syh) z0e5P0O(kUmb~=z1kfcqu?Zw5rK(=^kriENO+_=G$D#pzG`t|SKrCTFKw4;Zoesz%X z;fP}R(Oj{`>EXtm-`;>)>Cvr{QBDKV?mdL@xBFaD0v^Ex669>L`^kd+u>K*n+0EPL z{zD7+uV`Zzh90POoDQxq5NvRH;LEZHg2B&AtA*Z z1r-$;(bFR;4KNVzv^jyfPXK|a#+N04`gJw%9uw0xodmk|hYvfTTT2PDlL)x&65I0I ze2z99k5V%xVc{i{fLOrI-jtD_(rpD3~6d<0Zp2I z%XVxVe;Uj_^}7;Lrb)~9DUb}90(5^B6_72FWQr+2V;TYNbf}>k7zW^`z^yw6ba))vMv79C~^q3T548i1DB1|!JGHcypp zOiavdjP+F_)%Dc!t7gW=x<^N!a&ZaUc-RV-K7m?y_jE;$svxy;RdgcN)zoCxt+G^G zT5ehvN)1^{$;twQ6YQ?4?$zKYl9}wep59C;3l`)fkQ~E<@=$Z16EZTIR8f72=Q%Mb z-w4_xF+G8ff}JBOo}DzeNX^ozv6o#Pa`9K?ozn1_JFPe6D-Nd<~_pni{}UJeK>VOJM@_b9p{W zavvsj0{CR??G0(t#sjfnke6KD zX;VKvK7QSz0=t_39v1-_$XSs7HJ=-XD}(7jcxmZNX0GQi-Ur*u8rW(4DUb-4=$?KM z&~lE!X%!LA6$oT~xzj5vSpU>!;}CNY#GVMgZv&4!-pbGjipzSk%mx6fVRtDYd=_QL zlhIj`y=KF`b7y~dH$4hmvc?Wa$R}!&poIm5A3=&EdQpI^>u{IM+}8F1sf$x{`|{cl z2?=MZtfFG*1eOKgF6O;I(vOJuji=*XIyr`$CpG~Tr zH()e_fP;YQn0X{bPZ!L}%IbaYe$Wu{qj&!JeEp1xCa z<)FrDSLsrbdq;`8rx=U_RDJ|9=}3C?1oO>RW$;`%_t;IRf^%|87^UTtr%IfsQ=%C> zXwK#brlz{R&#}b9lJyk6dnlVMfAsT1mWK&4K3pYNXzL$uG45LK(~h>6lESU5RJ2@o zupi9gP~~S%_?toVEs1XdA9a4Fl z^Rfc{%&8ERgQKGnzkg7k$5sF0rY|)xH_w?8i*QgA3yY(m^zyqVG&#XzCR)9H?g;7U z=HQ5mi;I$J`!C}|Xt(h%>wZ}KH^GAdN5;1f;>Gj#-+cL}U=wf2bBgL^5fscrsO9R6 zkCOJm5trxm8;c>8+>eyjw$vv?IIjtzZr=DBn)2HJw3P=|!PGhMd=l?L%x&m;& z;{`qaL8ehHI%X6Q@Wel*SU8*?Vn(n28!0!pM|V;=X1Jp^AfQ|-aL>m2&q}xM!S*MP zS+7&3%cQB(K^}e_ag=1l<76)ANSL5!yPd2aWVN`+*lb3w;@+bVfu904mAHTs!JJ>P z;putKThHd^t+!n1;GYv?W^3C67NDQwSZ-=h7g2E(;&dY8fqj#pFy|#B(^}kuEQqr_p@`SF(LeEvZ*7G|t8tzldiLqA zQ5l11)q|y_mf?V+5+^0_+%8AnCQB_#CM|qN5lK<*=a?24HIH0O1R_z)7wBNCfnsrg zHm57nnp*P^rN|GSj!Sr)qlafl%6fV~?78aJXsO>ic@u%)Ox5b*4nGqjIfz6M0CltX z)>8f}B#dr6&!2O19B`IjJ8E(01gz?^cOVzCM!_wG2SyS{M@PY5!vf=Qi)b{DajT=&w}1ff<14_YA?ugp z1i=PqZ{oO7(eYrGT_Yrwxv0c}^Y!<|#Y{MYIOu?%@03fI2>}b#Uf5XBSJdnD5{~?_ zOOK8W4BGAN3`BmHH8gzQ8vIDucuqX*ajg@5^x8v^C%6@okZ`mJ#}hn1KKS}|R#4$H zHZZ?ET4<@x1FF|IXQ1P|E8r8jJkRAv+H$=`DOdj1C9UFR0duC{w0`N;2tr-1N4B_D z7_HbMfcF{80n!Qx9&TI`2iZCybKB`ERws*HDKj*UqGE7$3z;xr{f>ve~6@{x^rLDfk zOS^1N-MRG;(M=Q3+}_o-h4K=#bAh+~-r`#P{ZT*mF&-{iTC{8d*k0$Y8DZJ5+}u}7 z@r>GKW$uZHpFh7}6JmCvr?DTH&khcewX}>!oKQY|QIBAe5^iD)7wTwMu;h`cZ!FtF|jo*|~Y9iq%}y!dgk-D=W$ds9jzx9^$_KpsN`o!Kh?YT2| z=B_zw)_h}SE%-p*{l0tuf4}E>WokpoXw(|T*X2lacQSL0h>|YI@8e%{UP;L1;|s~< zJM-7CynENB5kEg~m!HG}4Zd{v?IYIN3AZ*K1)o|OE9tWD&8+=U^}Qvpx$?wDDnkmk|IrTe(kgu>-mu1US^D=z`p)(@6LZK?)ul=9Q1WW znzVLy3YJt<^t4Z}C?*5mje{gwUtC_AoiP>6r@gb7%Of{DGzBtSB^7z=8`>KFNJljEBFNtge z`3Lg?BgJ=U{R%qK!;X1F^_3Pr(Uz(~rPY>rmcQbhU$%lhEt&R;EsZ61<~~pmz07hwYU0fmzTOjBg&FW=!L=w-VOinTp1L4dat6Q+gA!c zhz_p1Ii(1ee2LXGpZZhR=9{ZcPQy=4|^5ovZf%7r9sNY5b1|wQ6lCz+*&~~i!?fNt2HaGZ4i(W6nC)G5Xap1tO zsPwAO9u4y!p!0@GN(@d<>3F>~Lw$0pp)GIvxGO+(XOXK(=|$VNr&xfqA>oLSiici;^N@Y5dhjX zy<1zbQQvrNe(V`1ZNXZ7SEz)fWQ~~d2m8XtFg+_P$se7a&eN<-GQc+EiFo2gC4e>{nw;jicN|$ zQ{zjCEjZlGds25@=2&7g3bL-tcprQ&|KSi2z))O#x2)LZBx-R+0Wnt~s2mzCAt5o) zy;gTw(XBFlxL!B<&eW7H8>)`}ZXKOA?L5yAo7MySp(Bjlv#258|v9(ez78o-FAi z5V_{E(0|O_z9Zs_$lBepz?PI`?f?Y_(j&hDXExRpc3*Pr&XmQxjEt!U@8;#pJ==}^ zUnk_(*5uniw&Y~Xf9?@2tC7U53Og3bWD5x4iZT}wt)IRm2C2evIJSDJvQ2Mpl)a&e zxp4vFgaf0poz6M#7jW0zBWL>KDn`?HJ=y!!Q|_c=&~ay_*TNZDD#juArYfI5>!3MSEYItP{w2oI0Y z*HqmT8=N0&om>9l;G)eVI>Nbf$|3${@}~#77EOC-*u&1FscGEMcrxWiRU6bCv!5CS z*;;n8?di4V9-LX7e&%9m4!+XBq4CBBC01ko!+B~-D;E=Srf04HAsW2M`Gr-0oH@{j@+Wi%P~s2-dV*WhzFyWtOzW8l9@E5lrAd z?Mdj)M++^1jl4|V!+bGj@5~EIp<-gzO^EvP^34;Pqon(l@;=C;cQQyJ~p3Q`albu zQMogf@cA-c{%<7!84r%|&D3T3IU@40w9ltwfNfSI|uAhcKO-t-F8 zt-1+V#56sRW7XCXDhRAv%s(CW^i}JD4;+8#A+!`%x%++ngK`wykna9!Oh919?CA5d z)ieYSM}Y#f!uZRlJ6`@75r1 zYL{F6VK32QFIP=v)ZsM>o&Kpp@^p1hYX@I!NQ+XE)oRGB&C;7MUY?>%5nL6O zcZ{pBbSdvmwRn5j9#344xGhLuS^mAEki??$1E@~W zOdQvUn7DY*Rw0y~6cvs}!OHIO$W8Q5hs^h1V2GOAIx-W7VtG70Wl*T9bwtod`j%;m zj*ewy6s`~gGw35ob&?z!<><-Bj*oIbvI6C&5IhoJ;2nhg(EVYXd5om3=ksD|#NaNf z>6ENQ=efmnyXeB_n;3yYO~{9>>2EB~mny9IJ4)7GZ$8NrnZ71nr9YieBaZXI785&* zkuZ>dnXH~MfZ|hUmWyhh^WcsQPGagfI7WNeMK-SVkK`1u^nuZ6f9C1g_IT~FM?5;- z$wphx>(nOfo@A{rE&_6C!12e+moKZT@MQ8D0=C2+B^;q*!~Uo6Z4@d)N~-SXyrb7g z4>EqbI5I(E`9$3JxR`#P@ea4W+d9)gsbKP*9&xhjqQdn@Hi(1Pfm0*nN%5)&Plshs zCJf%r?2xggY5LI-&S!Sn7DP^!8GTFD)YP}Oudc_hN2=s>$`R2H^DKfVKS$bDF7O&+ z&LSk*n{>1bkzGRjViMiXwm5xDEOB;PiRmc1AEsM^V~tR0tgN74%VeEHxo9sJ3MQ9c zd6>ttBP!WqN|4PdJK37sGD3gql;YrEF84bj-63)W6DCK(B<$guK2b~b*E9I}^^f_3 z1y9w9mrr>-$EHL@M;NaWWzhW(&E(zP^~?g!pLRNlv$ptc#)WZbKmnm6uTVvrZI3W5 zQ&ew638?6$x0u{SvLnEW=j4E(U}h?@f0x}pD%W21XpeHwp>Ky8@-i{zJeO?G$8w~1 zJi8I~i)`c4G~h)sOfoeie9+C|@esd;LLzl~#qq09_p_&+Fy5gn6Or$G`&g6{PfnDr zgGdl(4!XQ@2ZOO5*pX-pLNsSA<0RaPKKYjW1M)dE6x%K_g zc-E|t-{|StA=4S7su0K$k(E zP5y3GCbO;j(AHkxN~){&D@3pWX9LX4w<*iLcO&n`URp{@FJEqt(wzXFQ+h_}LO*Jl z=@0AKSudx4@37q8MJUn~`{>2xy>NOA9Ssj4j3X3hf*Rs>pMEfXr)X8?b zBw#UdKjx%HPGUFu)hjI{qw~=6EI!R!)e@c2F0BE(&&?Zse0D|OUKxG@H{ZTU$emxD zu;yiDW3ls~J0jdj?p>6kAGyx~fxrVP7ZQ~yNzu`aSgeDwmR6v)&f*(CSB@~6#?T<2 zhsAf>F|RC$x2l;qH7gSzp|+%GXZm%eS)QOA?vAzU8;!Z2)?HrpDoD&N&^jVAvo;8c zJyU0$34iwRv8icxdb#^jMM#)+bVLM)sNGq6Ui%S%p02F82&RJe{ijcAk0r~k9%ZBu z>h}%d@b^i+`RNRjVBS(KVVJlYc%`BOW;)(I8GL`LtgfZyowZg?Rm=AjM%_BBEW)|g zbl5Coez3YSp0VA?pr(4DD19cs_5H+IjyqoEC$X|Z;+V$wz7>m&>n-!FppnrDCR>Bg zMGewumbWV^;YCF{9Mr;Ob9T$?%*{4u*E4_pQMLwe(c zGIoXsAeT=HLIWgfyx2djBXwtYH`C7s)S$RuS-lADyZZZ@M=R3I8QR|2>1c1S{|!jB zC>w1t7LDQL01K`20o3n{^|`%#l=c^(QONtLAkSZXa@A+Kt}zd@C{VmO=W~uBN^Ie9 z;j7IE`pLKD3yR4Ffo+`aW4e+P1cLnD*Pa^9!d(NLROZ%5$y|v7rNqI zcDuW~#Fh5a(>Oyz2_3QOYFFurhX5664ydNAuCi2mN~E#$d&`P6;VM3X@H!`_^EDDZ zd%FgQ>lqw;bHez&aY->E~`i&YuUO zgryC=TXN2T?bhxS;&;KLD$wo@gS4fNookfDwmyl$^P^Py!p;dg;QR`r&V{gDR?zHT z<7&A;=%6gQ7rsVuB4P<;%(N2gpk*P%8j(-}LD0j_c{9w|yK|GfNF;}eN%STG^!tUn z_<4t|G;2^HYKYfH89?Ru)&jl{9JIXh{YMo{)re5+H^+pih_ z=t4<}>s2b*vvTWFoajqdB)mJyzNCi~KgxJxwC0&T$yc+?y78K*H!p*%J_m+caUTrs zKkFck;{;posTXgJvh}z)1v5rlDD8euPRbpE-kg$qeti5A29Gbmc2Z?E?lif;WE?|! z`2!Q_=?l{cx@cgu(X&fjl1)Au&0;z zipDqu-1qc!G+@nEQk?jF^HDAT+2Mz-$dd*G>gUk14FFz`=v(d{)F%^~t^C%7NzwUL z)znLxm;bY3{lDXkza5zUzZ%Y~=={P-q?=nzv@{jsVee`l0LDOZ|1n)$Lo6VCKne@M z=k$Eim=0p$o@OqXO%J*v7Tf`Uz-QLQ4{q${<{V~#003%Ed0>kN1SSZ%9UUE)XJ;QS z7betzp>`9Jkk4`7<^Zrah-|PpzJ3MhBEO(u_!=<21KH?Z(~5VfFMWLo27B=I00{cG zub+bCsi+|CzuqIDg!PS&jU56+tCp4)&&`|Q$qs|T&?{d*>PX>AO2Em+(aFio!{dHp zQet8h2Q;b1@t4>Dj{-%vv5^r_i1SlZqpj`u`0+)@r$R?#5SKA~InT5N5$0lFT zHgNoQ?~UgTS=r;|GAIb{F)BBMgB8pa0KU@PEa&<@HT4%HI=CZcX*ZV$Zeh=!(V0o! zzn|Tq?{{F&&IYzCOhN#S9SHy!52%R};;5-Mut>>}&`=mJX&x%^=JuVUf+_JQiop;F z1)#UXq9H6LBDcEom3@GM09XWq#M#|Iz2K@skj2xdH^%uvrsn|M4WNHmH@vh2>@cZS ziWC`;g@elh#{JurG}Sj{tc$3)_#YiZ01HB1Pg?{3aaY2Q7q~Kjj+mV$2GgKv`5;fK z!WX=aKw4KI_6i`Fxd4X<9)DniaET`rKs`fB4Fp0%DikXiS_cyl$OnF9O2S_l?~p>(~K)XQ^J;;(^+#()`m=FfImAGswUF zX%JIURnY*z@^9DoFG3+FBVDJ*RF`V7cc;n!JF>7_n=f(B^Fd>-h*iq0&&*RVjV=aUmcoDosE|nuzq?l&bXJoAi$K8c=D10wTTF(2H~kO#wlA2dR-x zLWj^o0{3ODz4keKf9HJnj{CX=CYz>RW@%yR(YM;4N<~H0nZXzuK@)L~eBiu71bOcJSpo7u`X>YACY>26B5B3Uei~QD;$6FuGf+@7*&a%&F)@h0X_VhrWj)f`*2Z&BWbY^4`b633 z?*NkG;$l}ji;bsGd$me^A3e$v!&~$A=*o>0#q1oloTs9ab{9LL=eVR70r;Fl$J_o0 z|J@&CW15P|ys@IIpC3vbt6>6K9AS#UMm~8UHVLCc;1zarn`1sC`7nK;5(sB-<7_?5g ziIkNUVrpuNlu^;|9CzgFqop;`N#kSp>uWv=l@xG|gogi3MsxGo4>F^S<}uSqRyG!v zZ2NpYur3{Hd5XAIvF(wOll@hZoo{%ChK9SlyXpRCQVI&hh_PXq+?ob@yhy8T{CIL< zVZkayB4iHrIf9(y5i4u>f_3|cwZ3G&k)-_mO!RJlihx9q%Svw|xAm9!cuPCG`#8y< zpdf7CbTib)*!Tf#fRJrw=$X%YNiF`3Pre6Z6K9x-mcWoB(=dF7&GSjibhT6R%_Hon zno@syi}A@`r>tDh#>U242rLrQLFG8y5h-?dyzt{=y5~Y@R@NhiPkDK(glvt2wT|f{ zc}o7^1H;3^iGDX{Xf;^x{Qj;ahU@K)Wuc;^1Z&l3(dQv5DvHLPpRA_Scw4>j^Lr=x z$ZIvVmO0YOR8Fp^$>#{W<#8^9pw-ffXKOyjwvmYC9B7q3Rvob2ni23#N1M}#`g+RB zK4CrIbo9q9MJuJG8tm=u(L&KfwEoz4wNTNs<3$icA8rqJcYpD=nZmb13MmQvj1M89 zjY~;!K0s-h>k?B7a`W=mR97Fc`JeRgA$%3|#>d8*FesMOqjT}7@BZ+3BR{W=UrsA4 z9%z#_wG!Rxy%1Wz9Cq24bzf3b6L5L_1PACOi=Z`&S`PYGF{AH z6yY~socQcne`|pCc(G2NQo8qEmqt~(*!jr-ScDA0*N~&D&{J0hg>Wv*e&3ZuOTW|U zReO7TYwqsZS&;`1j5nv;*qYG8bdkcC1_Um`->2XOde+01#`n!!cWlu;Hp2?j&VH3_ zX-==zbx%J((apf^&&}yD7|iEr3s%O#(+o~4Q6Ne2Lg7mkoy>4WOUwBe`j3$`B7)xN zgu5&>{)^#!8=IRvel?Yr1A;5$y=NEVPay+$i9T0tf;6sP9ih(JgZ+#J3U1pe!<;XL}0ty zq>K?Gt$FEZ+m!>NT2K#rA5rHers^}Rm@sBcEE0(vJw#5FrH6(R{GjI{Ph?jYqxIb} z8cRwt){e3?iv*OS&_yK$j^vVF44};J&F_ zVMb7rC!a?ILz%QHE7Ul$tIh}s2xw?(ayF^xt9~dd&0KUvli$B@XKGpmZ-&8^!QL7z zu!ID=#M@;V31NIn;T@x+^5xC3VzFIjzVC(uX-+zngv*9#eK0Oe3T}UZ~J>;p$*2*;n&x9nu7fNgLL6J$0sMd zeffA&IBFEtu(Q2=_#WNZ=%@{LXVfQ4lK=+cVRCkME;DLTWU&r^bYKUz*_Y^Ox<`+! z%$;`2W|?fNnW^ZoA*$C22r^$}QE*udAH^B=xGtm{Ev7M(BA^~N%F4=~p2x|KXLS7h zff(qWK5mRV$hZujU@(o-Sl9dEn4#XAYyRok*%GG*@2(fx=Evn*%iGK28}oxgFf*f1 zxeil#jB?-QQOlLj?4;szu<{}JLCW*N&}WkeRj+&v)x*}}dv=0QjL7ypxq;*&G5kAFA7*tqB^c{mb$u}n#DxvJ;H z6k=kCrKQK=w87FD)~DUwVRd!d%NLbLHRJ=v10B;c@%44v$=n+0;pTMw6hGxrjng6n z%5-a{e(@t)a{`B{H?%3nI?r_A^l;PXXx1OM!Z)CB>~twQ zGEXs8+<&@YD07oOM&{a$4S(E$m|D{4*w{$A)0zEzka_7Se*PaV zC*0!2_d5mLP>&B}eWB2kTkx2eJKpiDX+G{lSyJe(77R)bgFnn)+tD=SB;sw0iXM*J zZgh!{qNeuA#UEYnA>ekG#xopU)%shdEFS^}MltKHUszn_Sx zs9`6`OFI4a@sd1G4H}~nu%D3$lu&$8f}-N$jlJcb(aTwMkYc(ypKU}>d|AfZ2G8B$ z?*Z39o_`Su3ZL<#9U5hB-KEVp~7oES<#>^2g=v(y#c zD#XT}t9Wgy03kyyICfC=MU{bt78$}QgnU> zWcGZKqqwOw%`o_F!>MdkSaaS~b0(Hbp==r9;BpqLSq$4Q+?#%82j3;PnTp5iA5Ifn!|Z+tI_m`tcq5voR6`A_4HYUjE4t_`zo2XaQt)I zfwqx`2S$Dr%wvy->tG$};sdk_2Y$pER4Cax8a=H|e=~F5u4#qBqIM&hQHQLq@Avu`?ax*$EZai)!cO@=&Dv455zfHZlf5k)eu8Y57e|x*SxsEMc zs-~{4jsQQu2IvswV0{`I_V%3k5EF4D%TP)2NW(cljo9VzaNrHctgIhDUU#!2fXtSZ6uk1ot6g|hkR445m7}7{={}5N=6VvtPPzZm4OSgq0;|^0 zFgH&&CW654LSL7Z*nws{*7noWWOWMxtL23ST^+-@%=Q=Jms}gVyPX*=wU+sYmerH)?9BJ!__N|5niC93%9ZZ_zoQ?x25)W8{)$q@mEC$+X>_x5h% z&z8UoTfcwTc~Sy1cX>E+=f@}71T{Zr!6#Z;MxE#k_nb)nYtliY$67uEbN4iF5DCH* z7_yBq%kk9mW{+>nUAuOTjm^l%r?a=0iadV9u%v{O#n!e!z1df$;T87Wl-p0-oPFqh z`|y`31fcQG}i7k@~kk=ds!>{zD}>Imd`| zKRMG|j)FSclU!>QlvK%2S*vTJ3f?W6I2;?Pi#NbhSFMmUIzNTf4fdK>?m1)aM0Xpv z%aS?1Q&LhAk;~sdxNcn=+|4lNKA5Xu8?;eVP*9J1Cs23()BvMxZx4!ls+jT`3-SwF zq4TP4xu7}_Fu9l+`*G?xwqTnTjPIs#y`y)rE@(unlaMS+*~nDcr!EPUZr9=_hxHAwV=Dh zRP46xljb9h+mzv>Cng5Dupi$Hr1m<+&J2Egj`(cj0=`4TY7=hIiazh7x8ZI&Ua(cm z?ah#Qp6Vd-UBvX*&iR|VZo=PKfRmHgd=S}GpiroMcM z1~WsMp@NA)+xYm(kPI!gz$0DzUqAa4{Bj+1bOfq-O-%Z6jqdga2CM6n-`WhKqM|4R zLQ};2(g{+?X&gN zp=_CT+b?-U+e29Z*OhOOD7v)RXXbuA+( ztPt+q790+Cvd7G~Np8nE;qY~4*~4wb0MU!-#y8dVF@hb*8=ECa|Gdgd7JFq)&7{va zWu82Fl0aj#r#3ZZMrSlPsjij;KTXYHEn7{&3HW{&O9{vd+|J?L|57aFgcKts6)Iy7 zEg@ZxO7q#8tVNtLLJPo%=BDqiYjuu0;{1F?ZU+jTTufNU-+--fB!RZf zVOFO{-#%eu%ZsI<*&<=nJ6wt`$_kcZ)vx>Ydzbs^6Vza4+d#`s))WTJ#c!Jf${P15 zS^W=Nl&mWI%|}YsgSeU|fBh0Z$L^!8?Co(Il>;_27SlEMZf*vgS6_s47IXJGeqkh| zesJ6=Hpj&DbE?KZ`s2qU`SHWUX~&u>Zdw87803q|;|kX|w8uX~nxsXN8aLU>(^(HG zIN4ke)2(2iQ}uPub)nY5dj)F0KkuBJzd^4Lz}tTC3~+146P@-ct;E$(@>$t`VQ|1U z1t@v$N`1xALaFkOu4e&}7sX^)MWW_!YFqdDl2h=sC+g$1hz z6eS{h#SIyZ=rZ1*G% z2HWGxi+ifmO$2Qp6|h>%*E+OF$00k;NIpj2I7-8qlyO8RUr!jBzt34QFiN(xiocv^ zmUJ)Kv`#?W?;bOb2tNF zq{hRkqTYP<++5X$&@Uh2yo7g+pNRN3KRKXWzdU+B12O$j0>A8RWu1y|*kT}Y9noW? zlN1|!Q0Cus+Ck-izS9;-Nkx@d&hd?HeBnonB6(&Fz1updPYHkI&xuRhH+9312{qBz zg}5(|`RP>_>+>_1Q^TKb=#WJ#aU~9?lPxR)4LR;|s?hGVqSfxjG@5{rGT8YrI)K zHv0FJk2-dOr4he>?_->no0`G$a(Wuc{nI*`^RB8nKJU=PAoJI)qG1H*Q9UW%#3sS) z#>msY;VE$43oTy0zedE8Uimd?+t{kL1v#eY7&{aCyrm57&0va67+Q#GUkqhaW-s8) zCbHfAVs2wAuOP3%CR6FvGd^K-?xH?A2w)RV(`-l6hmRh$c6Q2~#84_cBFLSVpOX2s z$2lMNi1ZyJ&OM@ioZe(eh|XwgQe7{}%YA!VyH+=->iB|zNmYoUzJ@-aLX3R1F!fFJHa{Bl=|*vmAN*QUufvkZB@53C9UDp`w)w z#(AG)hCfko=^Gem$J<5|@Kco+lx7LD2A`=2t#`1UbJV)KqG|I_=|`<7&yv$m*?fI| zk{a<$Xlc%TG7omK6z=Lo-jer_@=|x-71z2(8clnTcIRiC2X|_X)RHbaHhMa8{ebAPHe`LPG46+XV&e9_JJ(m<<1mKOLf z2?wnhQ@IOq($11WZQ0An(9?z2nE1LgjnLHTx3Kg2b>nEY!IGA+8k&dbU;36`-AQG3 zmqa|D{UC)62aT~XCxB3pWVe@;Ds8EDH!2( zoZRc~VI#iJSJ^xl>_N#dJ&M{5A1h>!h* z*vIHdZ?werdb) z?S!CIRaGOXh0ZYP=Xa>6;**n$G*PSTr+H#HB*@mTe?)?XsbCfq)IDIX&b&=ZDktaP zG{adft68i))I5&P^f9daY^IW%hq6_uLVVZ%L-cCOl&nIvc|pV6le((u?~KBj6W0EB z654rJJ{hLDp+anZ=G+LW9Bph??sIc*V=Y2cKL$8Tb`1IOK3u#pzkk;8T!>QnX=r#! zowtS?{SQ){=GSKp%Q)NfqXt$zUVB8%vXcK<&wN`*>^cAtuw@=|&z?R##?hYrBnoey z@JJ<t3mQN`Rw3O7Dj++8CGouW+BjC|$F1NMxw&3yv)FcTmiYu-n_+j7^WvK72Bk zlBKvdAa-8meSiWuwu*x)D;7NxiAJvtnNlL0I<8I1CuFtb>Et!n?%&uHIiOEjFOp`k zEtx%A5@{AQXz{ysep^g5zyeJ6(r5Zp`&6_u6G^q=QxZv@sPuT2+iK9T$J z;|HDerwr4?LY4x05bkt4SF9xQTyJ$})bQ$fdbYPIp*P#4LHmaO1-z`uWbn|aC zU+^)apPw`vx=U7|x|MRtmBL1ZhmTKBSGS|H(+&PZeQavs^^``fRN=5+*DXpd-pz_5 z`@4wKCj@;As0z0sk&LC)Q*El{6H#NyQvLc~boAt}rPo6m2#u-wnylOo>5tER5Dc3W zipWwh2uxXIJH)4^Qmi8sXvlfU3AY81$5tK0I9467McA9~qy=tBK5v`U2(C z@Wn|=Clg%aIdJS^a4Wu*i`=AHxzrUB&FagHQPlSOX$(0X2m#q zZ_ap->({i<*fp1`-aR93^7=)~*-CD1YRh5cchrY4baW?t@>UNvsqHK?73!;az8>(Z5c%u@36NkYbjiE zLQV6f_}M>sBD)QzhrM!$rzRVI*F47BcXV=^l#rzAy}R6x9(sITJ|_P*vJy$ovldtt zkbcA9Bpl0a!sW6w0uAm+$Y)tyUY7Hps;n4JoPRcZHT5|w_p&b}b9E#%Fk&B>kfmg4 zxji`bC|Z`-|K*VXsA+Q>O~wA2>Fe+_gAkQyQI9@fMn)|LPPAolZZ7;QdrQTh=0}3b z(eUCD`{@LEU89M2E>J0PQ{DnY?y!4}jkxQC?S7#RX&u@tujvxt@wJggnihi428F6w zllBi)EnBKO*5%RrB6Vkcu5XW9_HE+H1APX%e!v=w)ldAte^9!oa;mUU!swkt7h|!q zqNw;RHg=gv5)a`!_`T~#b#qNkxr(0%e6&i?rFK+y6i@;Pg2HG?a0vp z-3r+?k9Ib!LowCu8c&Ad?EGo*@od& zQ}mANtg=??tpAH*>-F@iw7C-M;8T#4qS6A-6C7-DtvGm$5%gebr;kISXg|DI&{6xyY`YDe*FBs)Z3~{WRRYg<^kUzf-J zS=rgFPkXJuV%;s~h4mmeCClt=92``Ic~4JINyu*kYTs#Do1eNxufnW6F;U0GMNV7$ zS66f%IpnRex4D`Ps`~x=*5Ke^(7!9Qgm$!&(2BO+*-r!P>gcauRj=FdWuILy2qk4? zhd{ogn_{iNA|jfh%n4wG!W^tyT3dJBS=C4vaEW_gP*W4val&gqrLU{o4S`%4VM%Un z6$hdQ6TkzHdQUZa5mIxXZaSue#-zEZ$W~nZ@>NpACrVAg4_ZJV@7+X`WiPiCvb2qqViQ>*t7IcnA@Nd{aG8 zNi@{eDKkFf;`(?Avi1V89yI;ymwW=dsIV}0s(L*$6MD2Q_PmeD!^0y~G7C;2mhJ!u zW*`cXClPHvOQf*2seGm&=-l)Mx|4VloAvDiDCZxImB#ct7M7KX`C%pV^%0GYjX61w zNk}4PXrVc{IC^?|Z+y}auX$;e3p76rKCEr?wm$xj5{R?xTs2?pRc~EQP4|WNSJg+) zo;-njk!n4FKr)G3`n#K5Aw*kv+ofEg8r|-&r-VfU&~egmC*QOzf}kVj*~DT2!Rh@yiyK3X=s(Z;1E=_ zDCLIo@cuu7mw)?&KbaG+dFr>|xXi!44S2=$18Xo3%V)Xx4Tr6b{EKAfpPvx*y`pP; z+#Luafd0W|eR|4_&tay{SK!?x$R8G8?UDpsqyb^ZeQyYpo4c~KWQGrU@ac6$*W_g4 zj`9v zFu}tNrGhPD_!cz0{IA3^s?jjqZyBAP9S{&eXS6ljpag|Nt*r~Dc!A#J-o1M|Iyy1r zXJ=6n%g7X*?jn63bnJ*%4xN=gGDD9tS_3hY0prZzdudfTkzm*!}a;z8j;U5|YiY<12zt~^ttE{Lnfk3EVzg={- zwnhSFkuMTP#uH~@X2#9U%?^1R!Ty{VoC;hIo3LOvVEOR%76g;T0fOazw!SQ(f^EzTPr~x5OCZ-z72TwzZKa(k5_^a z@-3yjbl9{$!fS7Ra(ku~K>Ce{h`4+AZtwHsQNQaCbgj}AfWkz6#LUT@c}TPSjwQ(& z6Ziv6hKq|U+{a?dRORTD(i9|Qf@gnLQh8V@TsV1UAf1eyybh>M&}dhSKW07qub)$A zkz{OEPlag@2<=1ujt*NTHuUaprg2tKxoPL08PlFmC7J%ggKyK*$;`U8iHV6I;WYl7 zob>8V7>apcUhY%{^kZ%(d*(Ky;4U@{@g*}TrQM;RDDVX$m3$zWnyqsRfIE*`Wf==P zEtokw-)05!vItq`y#7?7P6)&m6f)4qGADr9!~euwOpRy-$aFX#Kd#HneAfz?jf+9L zprAm#3XBb}q8X$l(X^aq>|pzB$(HRh7#SIP%PTZ>q^q9ykB`^n=JE;&oesl#T<_b1 zqzz`J%F0R~Q~@J%0@w=?G$I`k$d+`Odvtm_TR6w^^73vTH%ihgCN_5L*Dp^n;(@Ja zJ(3F`;dITZU%!;6!*sPT>S0qw=|Yt7x*XuP?YCCmWY;-@N%UKpTvUF$y50y8G6i8yXlG zn48ms4=dh>3hL=m0iB1eWD}ch*&|DS(W(-$#=F?u+IE`SkDVZrW6z^ zB67AWcK*7~g8}m4N{h%H)~5#WmCtwf2X}1Rz5;=p!QaMcV|8pLa3Q#yW zIJg~})7Y58Ea(c7NW#Bn$t=nYtBA0$1tm74IK=F2s32s`0^9M#$REe!j~P)Cp*85Ss`88B9IC1^@8jk27^Iyf@$iT^U7x-Jz!LOLsst zr!q(AJ_27|XxDw@{Z+!_5r8e^*7a~)d|lF(!*7F`5+@@)@oZc_K3$g&2PesH3{6qh z(V;N<*0^)y8z{qIu@9Eu3tX+%nV=;rE3d3H-P7xxG%@tNCd=Wk<@x6@qEyP#&2W9W z8G5>xhfR|QTtL;O4shD(9l}5o3eG?=5tkLBhS@+#u&TB5*O0BP4zo5#$GeL}paGbT zs7=0*#*9QWDsf7sM}Yf~LA47&pxt>TTN@klDR8Z~=jP^o-y!-T;Qd({c6_@hS1xk? z)n%zaJb9hG&7(s@yDsD(ZEYuZK^+|(OG`1Poe{hBX}3eorm6}aK78nFR@7|hJumL7 zKjQ^jBm%MRco2*DK($6ek@)$uvKFI~5E)rKfN?=c!t(M)Mu5x@y)}CZv||bidq?{R z2NXi?cDlNPEsx*i4ZV=*mc&rF_7ZC02&PB!)Q|8Dj+#5PLArP^r=wKDvRsmW%$ctG zP41vO_v_cM0K#qyiQLHpaMbJ9nZDfuYzlI6LQV^h{ZZT7v^Q@WJ35wG^1e2#Q;E4~ z!VZ_G31Gn-57htIa45)&WV^2l~LygkRJoL*ZVNB=5((*Ek+{vBbFJDYRRo;>` z8soh)!kBDjmAb&p#->#ttScS!VRfLBONt~y_m!8IS0QZFBuj-6yg5Qw9kj>!jz8|; z_^(qpGw}1*Wn{23Fa&ogeWs9~Tta~YydXd1oL!}AXio}x9{#<8Sx5*p#0kN*8d{($ zh-A}ma2I*<#HQmDvilL`V?mE+ahD)gCSUEciYKeAU0%NYK_$sfeg* zY1O)K3JN-RrVk%;$IcxnUxlFWZ?ZkjlPz0xjgj;{4%2-lB_(A8bGv?#;sdIa`KhRE zb3Z)1=w_?Co?{I0t12qK(4?lOQb3-|tTiXqG;cEa&F>BlHVX&{P$H&#dOp$)6_u4~ z8N&2w6UZE%{x$y{{DfyIrc9+UoQ*>ETVH8t@KArHVmE#cu;LdlGHs%glc%$!2sIq( zQ^0)hw$7VN+e^q7b}>E=16_;nqdI31Xq3ik5Y_MT8`o~!x3jX+uCj7^^X4-O1Ll~) zMF2Rjy`jN<{3t|APQJFf3aaQ<2V~-9L20RBgZr!m32TCwzn_*X~rLDW(zIh_{Tg$51|GV`!|pd+(^=gf{8DuiR7rDg+0kKwMG ze$}_xS={gM5@1nDZTM7_nL?oOC&|MjBgkU|NlE{+80i%@qvn)^gr5*dRR*1Fch@z8 zScN-&$$XBlArKEWBclOEDji+jCu|fBZw0PEAQ)vs!gyNgMaFRo1XS~4h>-nr>Rg|k zAO!O3MK0P{52?&|jEg-Ce=nq}KAZle!-9y=b%rU(MQ-E8;yZyh3R{q!P1i7+C-G-e zm{bRYUV3m)Q28{q$jk&81Wvp?vb-_}r{f6ZwuawM zLYx2juHL1;u>gavOWfiH1QTuRVF=j8;3-xOvRs&)%3n!tLg%j}cY(Ml=RV8}3%lM6 zdP0Ye>3iMtJ8$1YIvicV>cdF}azQ5D&jU9(O9n-Ck;a5}k?{ls1Xye3&scW_Zq5L^ z%Wt>ZE13lZ62+F)+L)8sL%@Ng1G!kN-jPV?hY!YKrtu)Lttkp8U%!6+SS?L~$c63F zb0S$;+2i-lvN!)MGh#|ocmJ#}e|O!yJTpT><<-@9{~W>U`~M!n&@s)Ud!{Zcdy?E;CTyy7RoNlivpfNQYA{ zBazHzi#0VhSS%L6_CNp&+EI7F-5=X`CW=m)nVa*ttjODZT3%YZJ~=l!+CDw))1NX4 z)D)Hw$dlf_J^PWLg@;ZE;T)6Wv#WF1avI@4n1h~HYeCpkRgIF1_p*k z+d_Lo{`B75@PF&wynPK+LQ1Qv-2ljdhfkD|*AvIO?#p|E!3=H1@Dbhv<-)*gabIz< z&En4UszK4@V;zA_#*Zv=p*5K+@1yZwitmsg4(!u_4!LBMM>S0~pvBF;j@ zu_9Wt*VD5)_9PH=d_>eb@=DaE_U*NU582z}{=Vv&wXYI8us4(7%G9z%c*IMphfxMMwW@h%y z+}~sftG%FiArOg-mD{lHu_CP#bFYIWA0%jsJa-tvq&25QPjbad8}Q&Zl1ORs!QE{A&! zBp*GX{-QRW2LId^LXys5Du@TM3Zab67IKfY) zb#!)dVR`m!rDs$#s}o460s5oM^z^AsOH+C}EwPH*+I=#}nu@28DMIw*tJ3PU0w}xl z^EhCqu$r8mEy>9E3WrY(4}VGPPvWVB>*Bs0{Q(K?S?P! zCc^(M=g$EpzZU^1DJeiH&-tTI;Ar#Iyfu*E?99(*TJ72nkRyADP*H*Uf$HYr=H8j# z>9vyrjQ;i`Nd_9deemqrjU$~)kX!Q- zis{h9#L&DvGA^2bf>+Z6gq8*YO1fjKt(+p){sgZI$Hz4V)h)q~FI4cK$$d1o5O@K? ztWRP;P(a>V?d0Nvgdus|Kp%3GY;N%)8Q1N6?9Bv-(n2eV4(LUn>mT1?{QH}<{|km> zQ&vzw@NY2Erd;1ixgZ2m{sMf|nzH48Yo+?X4@LNwYx_TskNunTto1({`pi=9i&rrw zXQhB8xL^umJ5qVr$z{wA2`mu^!fenS}^fPfGEFrJGuWJ%-t$CBdGWkA4R1ACI^7=#y{;U09o(h z;n)HS_jF&Mefx)7xw#g=f&&inF#Tz_cW?mR`Cc!``v>u+?das4+qXF_dJ_mp8Lr^t z!obT}aFpHV0jD2AZydUKoc0vQwTsD-x52rxJGuE^U|RLLcJwH$Pk*RBB1+jj(Z zg%5XnWC$Zv9VmH`{R0!BD?LR zRlpHaZP6FGYO=VFLVf&5*exqZNeOdZt5tB~(SWcA@=|`u9sd*?8{QP47H_HM=l2~z z3m?P668^z243>*6_cBDg@3$7HchUsL0QaCj@Vj#RDfJ*qbXJ-3Cky2x<1JWr_99Tm0eKL}pXb=smbu=auN0b8_0+OG zh43LqZw)6$K?&E?yhkDMR{CSXqO@&yx2&3483$dh_kqoIFkJQW&H0AlA9Hb**4E67 z>^noABiu>DiIviXt%q~29a}rVVAAOd0IEcS?t_Je<^1fZw(K#(oqH>-_HLi(KVn;Vz0a6)KwN7}o3_lgeort~D`%L0bdP~iTC;#L29}jFgY6D;5Z!hh%~!!;4orjZ zQBzajyH{w6$HrE6!3+W}r!o{@rj2 zu3%)J^64%b?YkJ>B8DCmr=Bj>KWPWTT?%pmvk_KonYS938-?DL=Jt+`p{b5c7udp! z%>r;ET5KmuQ~7rutJRJ{>dzR#6%0S$XggD7ECOwoqBA^~jzHVvTe!7Nx~ z^27Q1Weofbn5~cYdf4_i3!HY(PS2SERqKiz7CS#t!oX_~dEwy)fdr&A4zq>uisIs@ z?Cc+|k$SBpBCcGy0;rFHRH0R1f&IG+ArcEq61(xn}I*S zn(i)Jh+0aHs${{)B)Q%4hODerB5F|h8{4;^FE_&gZZJyr63v z8}b2~j*Yt=s4>Ja28=J%{9jve4n7AcDWhYct#)lZ0IElX_d2U?MwBznn4UeC$^?*Jy4?s0Etk;eIB*K9JMUR6Tt>LwiD`1euQZmdYL1K%||6w zx6)+`VA6zQKy4pI7vc|$-xucZYFwiY@i%}e7x>j=WMq(t9>2BujT*}V*3fODPZSle z*kVLuUffYaN8Ym{W*y9a9S}-HEf^D#VL$0y^iEAz_Z}6Mki!f=rgZC9d310hh~Ha4 zt8x89Qj*P-@nFUa*PAZ;E3Ce!K#+&}xhfnvP zpL+shGA4l5Pe3qpN5n`p07EJ?U@*`EzZuE2PnUAMPWIxXx%f#tG& zauQ^ncO9Xg%m)Wk_GR-=@7q)k@~Z$qV02tfhK-*;fek^^Xi^(eF2Au!Ju1DNujRSi z9eYTtItIMBK)wVdnYlG-9$Wm^HRa^wsKv^rY{x{C37+9RXkRpRL6}0HwQo`jrof#) z-6Nurm*DI~qE?^zKK*>P(o!T!K9beOYHj-Zxkskjd@-@%~`F(29c^8*FtrBOGQxby= zi3I+p+DaTpgW}HaZer*`mdEVsC8q zG%>u%-f2s ziIjY-K_4MTE$-9&7dGk*VD;AbQ1LTYIucE)< zkpk%!Qm>Ds*U7ZwQ%!j}j7|qlt?Ba$(7QOc+_oK$*?NH1gj994X{UQnO2 zNncPfamDa^lkz(PY1$P~9praHHrn+(Otju0p7Xx&$jbHs1Q1aMwHc{v9_UB7APWE0 z6I~_Q2uqF(x8cNxvu z>)~*q4@!xPI|L8^(ACiaPehTt;9~)Y0uVJnT5)#cMVA4ft+2amI%H&y_M9)1N(fpnQ<~Nl{S|lu#>;58>eefK$H* z2si7-O&-W|A56`KcLAizSS8?%xAndd#qBZ(iUZAW_S39BAUFpw69i+S26FMKPeG}6 z`THAl^p78>2z#lT%Ylpf+zf1CYKth8rnYttyrR7P^>hvNg8yQfozb^8#fLmv+$6O! zH&2ZQ$f0xR>qm@?e3oQK6%|>iLg%pqpeQOWr3nfWu$kV+4T>krYih?#KPVZ|E>t(v z1Rh?+bt)=UcaPktXl(OjOkyI%&70t18aZ(1>6%R&K1#ZG?_N}K;6b7i1>G_u9e+2A z*pl8hQJ)w{ICx`hjG&XL=}c{Kt1R2uc}Pl=AeSiB!>MEY!tb!uKul9JCVxxjWUq1N zlSD|(y(LSVr}UkXTc1J&B-i)%IB(ES6&@A<_X&s|S|8x-7ZNfj2hDPC@==ER6CCKa zVrvz1hyenByekB`nVghVcnMFY&;qEFmy1BI+x(SQmR{DLg$GZl6rS#xpz>_2* z?(?`!whj0n{19WxJLX+oj8N%LNS3>N`7|(y*biMEKY_!l7#il<6ns_6IdXyn72W8l zEf^0gYnsP&vp;8LACE%S@S{sgHs4>}S5sBJSmK4~H1{!t*ssYS67>w6&R2LoQd0Sg zP`INLDENkNo0{HGJ1?rPhGjgko#>~1e7oqwrM9s{faAub#Z`F>41^MJsO3I0OEm$$ z2T=WaI5?o#-Minvf0yToy-0v6yip+AG=YXom){%Bga=V6EPl%Jq?bb2v&vaP(#&;u zj9*QS>uhwix7Z{7Lwg|qn3f9uY@HwdQ@hVKvxacj;NWOGdur`Yir>EQm6bSRDqheW zhv+I%P*89mK91#OKY5#|At@;dp6*jJQ)yY2shHaa_IdzN_Q<_zCg-tR7@`xhdMd=u zJ~}tYEO64gb1V7;|Hh4HRSG&f@1_W?g{LRjl&2l!WS6H$-g+CP`sS)=9~(PvL(Gvi zB}FIR;Y2Rf?}4HS43ny)*1x~~1kd^y9QbyJuX3QPYqH)&OIMeY>ptL_*o%1?X#FyI z`+x0Lo}$AWokSiw|NdEpE>g7?8Hps|QW5=*U-%lcmAb1j@i{yzeh~APQf<#RagHfV0dKjXI1kodi-g{4&(T6m|DAA(#F$hK< zWt2I$XP@^y`}9k>o@nz@4m0=^Zi_T562WqEG#QkX6j7hc2-(iMp-Rn zo{mRah_scJmvFj1*H_+#pI3Ysp}$HoFP(h%wzu;-A}}!F9IRVMEZ*uHs3icbhn6Dg z*QKzxwC|XvM{jCsw^~}fFGoq>+kbCim-}>et2IzOhHNf zF2}lRnnLQiZr@I1QOxVmij9@;Z`u7B=Oh38w9ugs^ac@ zuCA^$lr%*bsobenn0$_Qjq3IW_X>=amHDz*3u;@kZ#F3!g@N{ynMuP-=e2r6ilp9J z;nLDOu$`&ELT$6^-MOU{3nZ_|+~nN%3B5WBYF2umqfaKD`s2Uk0}Kq3^FAm1NWcH1 z=@oocs+@EOYZLMBl6QkliirqAW?GthY-CdTWcW6RB_SD#_qe=T~ITSlzrvW>QW)^kg7b&|?V6D8y{H+SETAe2f~IDnGq z&tK!{Bh>(V&9i=_*7o+ggzb7no@(t(y&EdGd9V>hAEo>kIsaczx(?b`HK2I@K^F7sYP zl8^V^Uhf&Lkzon9VPG2&77@`$a79a@NgGg?!lF-F_PUcC1{SwkIc3f|h+@t&pDUA@ zwOZeqOGqT*uD8ofUx3WJExmBD<#j2xcXC=?UZ}R5@Dk_kJtJ6Te*eaKOm_DCR>#L6 zPEXNgrCnuZn2YN?^1?d<1!CJ=vRcsh73nIkw?J?7ilM`5PgjPoE|yq6FD9Vf6FK-O-41?a z0azKF{J6?NF920vYk{wjlewn-qF#gU4FlCm6YbHO9aY>V7MFWGu1oD+fsNf!;wZx; z{8C6wi~v8sMZG*b$lJgsynPP!KPKtxCyJ1L1#e$plAcjoid!@@{r_DFk82s@jQjb^ z&mIm3MX%7jjpM?LREt$cD9qqs{5c3y47hFS=>cOA+NyK@%NK=9kQX^3H$?Ngc>8VAcwwcc~UBL*neCVI$^FE5sei%U!3)bW}D^zi^#VVEQ$A%S!M+9N(! zushnX0|XitpAI!!T3P_Qmlp#1bfEJ+Z0*`hsi6HL*>Pp63FzBuiV1Fej#tbfeev}T z-Y|p5l$6zaP*AGhr(C|>YMhRYsiL5ysVb>l@Or1CGo7nd(p+9#S~>|Cqi4VG2OvLj zhJe{GL1oZ*CdlsHfB?n#!aD~C-{n!rW1pQ4Ae!n~Ekw#$39(B3g;t z9Hmvy(aP*z$IHFR$x7flfg^P&4f{j(0?^u?Y)<*QP#40C#bO5oy1Kig>ZOeXF3djg zAgmnn4Kjr6vwnDm8=0tlyU&rDnK?A%v8vU2LViVCTb=SsIqi*C|EdL0?rc$Gesw+d zKg7d^rW9u!xA*n{y$w!Ns^;dm%m%B>>d|QbBSDa@1dDi|3oZl_X9a;IbByDM$K~hA zzI(14e9s!lc6~LPeZMKthTHMW>pA#XK3ED!fSRxvRhE_MRvOkhqua3_prCmLvaSoI z!!ii@0O_3yf1=rr+}{=k>gt082a0B-%d!HUt{7YeP&4QMx#35Cju0PNG3m8=3Ui65;VNO3V$kLeeu`(iop1r? zkXRQqUki)@P-wI-*i@NwngEQ^j9zebOy+uqYqSB=8O%(%dln*Od<7nBW)%Yu#yu}O=HDyrj zMa+?rI8I74CRLwL5~G*HB7- zK{6BqM>Y6Dx|171l+WCX?(y6Elw%jz65IE?{7?pyT zUWF5BZjx3w9{lKxW0patHJX9@h%(rcOLaE5Jdzy^q-Wmp*WdHdre#m_HZ;uO7a*Pd zKB~Fqle)Qi>g^456{)ZmaJ}|CX_VVS8oh!YSHRlZ?CVqX^o)^m=A5q2G=M@YYQHY` z58g)~d*P3PB+mOk_9c{;*RWVtJ%jiDTyw_O)_n0ZvmS{_Nm*r)VO1`DAA8Ky3sCqO zU`yNERrCVYIsd;)%lLcKr_FSAI~T(42wtLLxz5JsY;T?DA#pm;Hi*GvEnVXu72 z^Epi(tI5iX!|yri!(f^d^z>F+J;Yt+zM>5XOs=ClYUp66V`BYYT1npGD{mTiPa+H> zahkxgz@e&A-qRTmc$&rS#8nhx@ZNny^JLe6C{*1`yNCShNx;uu=9LBdx#jmdCN*`% zyd=;4hzQ9gTr9$!fU5T46A8~eO;7WB)-RR+y^+K!J!>}NY^7F!4AAt{dKXRYWH>Zh z&n-}tUlP7yj*Q%qhB89KIV-E->ZUDgducIV?isTyaA$a9P4;YM)>Ew3vgQbGk=6rA zTUR5er{hyxzi^9VV@^oxx@OPB4wWt(N171?=^J0~M@{vkDQWDy{L?9BKb<+=+*n@| z|Jswd$87ejp{}^T1(mp=J3*U^C;e=kY);;$9BxyIy)nY=FoEJD z-97qMrw{kF`ifTb=lW^8%{HwpEy*qpZqCsq-9HWLDh#+a(j4cqRgpXBGg$q11#BfWh5DGMbL{ZnJdm9+61#=g>Vax%Tns6W9USyAjaG_&tw?te&R z41P0xc@;J}lx$#fQq`aPcv7ewo|53lCND!>(lt2ZpO)PaO#`&)~#wI2ZYU)U^ zdOucoy7*t@GzRml?v3TgdQZk&-keW5JlYx&A`rZ*0_%~_J!_l&T4F~=-u$iUyrGMw z&D|pXyv%4@TA9D%D{`&TvV$S~QMJ|9cbYw#(z9q8qoA>klM~uuq_%1O0;sXy6%k<; zd5MWrf(e^FP}eT$7q?s#mGcc7PlZn(Fx_?i0nR&TM^D2)Rn#Mxh-$&K*4&UEZw)Yo zae0OKsU3I6ZgUpLT;QCwltVOQdv+6adG`8(XK*#Kf`M(*(+!1%^J^t!7ei7|5%QYD zABTrxBJX=8y95dnbS4{aBVRbID&X@t0uO`*mzJ#VovfKYx z{e6hP!Q$b&%PTI1WmzqcA`%l)Q|&Wv%vjkB>Js(S`KsPytXQO`<@t>onz;phElm~k z$`LJfjEGhK)KmuIL0{c+h`^KaX#wr=%_Gi3>heH7{!{biY#jP{x*@YYa*v+gKR&T% zJ#?I=?0OoWpZ6HPsX!Z^k1VlIY29Gu8;MOy+@cPMV7Z3VOE=c7867#Aks9z~1eqpx z9Bwr?)NVrXVrhHE4=84$p+ik=WC=GI9QjCexCi$~onkl51J&q*-Q+bBP$%XT&&3J=NtI=fG@NI&fB!E`S~6@o5fGoE5p<=;-@#;>e94UNUD=lzY-Fm zb;wVZ;5b^1m{5txX^Z5TM%tU8=An95HPoFP9ZQPq>z6C#zBX_6W-rE8RQT)Y+zV7g z%iNHS@Urz+A`cCrov!{<_U#)RID>cL_ADmAE(DlbU)0wjIkSZ68Gi2DJJ@QEd0^YG zo3&;uzEOc07=Sx98b^QYvJ2uL$%0usNS>ISXPf@jR$N(rnfR4h# z7N>&)_Uj`7DyofXVH<#_EP)PqmsLeik0y)yi7%nhj!E3g!-vQoc$mf#*b~!!sU$^N zwO7-j$+Gip3eXhD6LwdtCC8#yp~cYT_>A?%_1mttA3y3lIe8)NDmi~J&`+ZqawdZ2 zKY+U}adez$0Q;>=o?o7BFVlgG=*_(7PjY8r`J0`MH*LI#DX!Ebz`@8!Q0{>_Iy$9T z=&ApBYD(uio7;rR(*z@!t+|cb)=>5Ur2Kgl!4=LS+}Cb|)k=nlw<9It@5(hZYb6AG zlFCZo;1}Zg9ea9)9w_*$*PP&I=Jw>@tvpC1sUBBUu)wT~nga5lJU0zkuQZuh>hXOy zUxIqBa$9pZL7&pE!F0^Z-2BF0e=V=C3t3?SO|%!v3&Tn>0Se z%kl7ryj$g_BR}8AzyKCfWrf57+utj~eP*ZR_a^OleFEJ?==`=b5=;JI(Z^Ctj0t?F zi-TR0cQ_Fdm-~_}6eVki#232IPEHX>4GH)MluYsrk=maf5IZtl=*IIf3gPxyL@do~{T}IS76s*Hn{7u-aZ+gj z)_Kx9Q*t?3E*>d|{Y<>Ojc_(@%D2|q+V*l_g{kEn2oDATiUP3T z^xLtu#z?!XO~QTWsvJrvbPEMPJYFD+J~^WG^}}ssq&pMtSXESGN~_uBhNEuWuW*@p zj4S(_JZ5(@A=X*vduiaKp~Iby17hPizp5(Zup$B>AS_oYHw^@6XK;mEe#zW7O4~pq{3qhrLztiW)(0+ z@dei7wOLsF6Q^@VOlz|WmS0$Rwk4cB^J+h;#Mm2Tj6Z6npzJ$g=GD|n{CHC7;zGQ# zyL(P*td-YODIowq$On zUMe+RWw*$CWhP5hd9&EuaOhkNMlmxnJDCmX&~G2X{5FROK6Ei7n? zil$b!G9qP~*WwsYcZsAH*opJAxIPA9ygb+8e7rWg@&IDJJJcojnxfWrUz=8*I8PiN{tq>2f1d08+p!@~`==RldH z#UGhIs;^6YUZb&R=~-F(W`4uCRZ;aMCWc*kY#*V*!2V|Bgzq%Y=cFcx?7%kLnVvm! zX^_S4K7MI4IS$z@B1KYrj^Ocp30)E>qe)DtWaZ|t6MnDu>$x63dBrmMq1nRg+Yz*V zef&r6FVz(D`V9YUlWv>)7e7yS^G$ZFkEe^y_HSFzeG)1oCo}L_UD@sm!XsNLAPR9u z@ojdF+prsVW@bkE+zJkN`15w`+Dzb0z%7H^81N|-7INRc`w5gF>gz|pe}5B0Z)0r@ zJf9%uTvTYfI@3x5tjBPr3DjUTsI?gG=Xc`nF4|<#9R5K5zL074-?!%O(P236esWP# zLXRicsR*|cr-RHSZEQ^UH#a-Gx@PI9#`E6lz}#I)?Np3f_7fFVF4-YJK3qye_Q>~< zVo#kQ5DMbi9Dz>Go7u4?DTYs;m^x{q)-@-_$Cst4RxN}W7-|<6W%%C^@$5|3HC20r z^z<)Hj1OGhQV|S0FBcXNe@RXzm5=7-)-yPlY{DXcobgrHE2bS<>!q#e3{=V?uC(-{ zTt|gnmQp&KrX1>*Q~xv8mpfAS_9hX!Kp$=1{;i~ofzDk>M#dZToD<>_G(m44;qG2= z2AoI6+|U~Pv99EllEQw}kUub9UcM?Td9czISX@z3_M2e+v#ZN0W2Ert`=l?frw8{< z1?wK~y$GgcU%P!YYmY-_mbky9p%L90 zBXMtHc2MmUQ(>-k} zZ@Wwj_mF_654dQ6!+b+XLke@FXCIf55iIe$L1j<7 z0Vp#5TM3q#iHY~~-I`jU?i2~Wi{5`V(@NjKscg)7xA4AJ_ z&e~qOPoGL_D9)+_p72qcCa5VTXzmt(7f_b`qtGe~HW1sNc>o8aE7m6emfquo#;}Si zjvh*|D}1Gsk)I32`T^HA*`-H-MVTgO^P(N}^=&NXpL6T`eQ8N*HPiptCpPYLbGpW| zj)XB^WMO&>f6bdjz;Ku7u`qgNo{C_T-oL*KCM7H{&n;oA?)JryRyOq>*3n#f>@WJX z=obOcVB%F-m6ZjUp(VRV$Ne4pTs&rqk&tZPInzsZ3yX`OBQlWFcjGgeEaZ9yp74q^@FWT1V+*kt^2D=QhqKvV_P=5?Ja zju*^Vl2TIoul}uD9NszgOr4fLjN05tIR>(^0H$i~LS0UhIOAflM9y)O{a+e z{_x-g437v4q5f1|Z3A(o&6LFVL`gA7c6e?Pspn5|aP?N`^YqnwAs+Y z90!a+4!Ry_G=L2t2*^QIRJ2mIA<_3y$Yg2R#__Q+u(JEFK5X+=2yN~pSD>{8(3XS4 z#=^q<;$n#RoEKk)xc$J)>0aIY_kW%4g6wBlESsQ^kP{qUQWmeq`SA+m%8#K08R=1& zLGqK;)%TjgYM|5j8OX|e0V8?t%YAb{(DIBc{HTVnV(e{HX$?3j)JOrSCKD|!Eyx9| zYynO)JvB8IaGH)60ao;Mytux<1}wv``+lUvf9WOW=S%;KN*XBD{ig{jXPods3c9pz zpUml>%&)j;i)Va8gZF+f)ky8RMcFct+WK$U0YbBM%;E5r_4Sxe7DzTNSzQ_^c=Kp5 zxtN>xPfnhZWBK{O4$S1kVlZ z%2ZT4)zvTM<>f*9+$>-$D?Qy~p{;d3-!|Tn)s>cf|z-P52Xm&-~quL%fW3x->Hf2Y`Vu^p!CKWu63pYA_hg z=;$a&|3pP~g9<+o5{tBD1%pSxD+9_?y7pjb19(|GU(f-6ZHni1adBDEX217}mxm{; zYHM>d`?KrH*mFHSPHxkw&z9t7Ss58M0A~dY2{33NP9z1wTg7gG50wl!mS!Q#Edomi zs7-%@MFN)VA2%?x#Msz4+2ZZH^O3b6E(78v=a&;T#d`sFU=OEOR;4W}0>Evajh==^ zH<`nmPu)e;Iv^F=t3KHcCGv7bDxh<`(u7bH7c4NRy!J-PdAv@z^ z&`dx&+S>kF!1L{cl>PVzfDQv18pJ}Mab9QaVtoXHTtm))6^jiC@wT($71Vv)PXzH- zSv@H*A?FNd0DEAd0s#?p;Pu8i#@^Bt*w>Sro_;LhzJ%nrP(td!4_k&K*z}b%J0aSL8s|vE;+fh zKVLgWNH#KR&0HIx| z0|hZ>J^raWml-hN=H&PoD6nPk0&=%*$oQqJt3jou43o(BX=yNH<9i;8Z#A+5;Xe5mP zEv2ynL>Ksp_a9mO|Fleo*-H{(vQG_ZOahJE?aSFbcQKyvF=?<{4WQ$#GU+_<>OBp3 rM52X2NTge0xF84wa_MXrNCqKUPII2qqAvu$fjm*xdQ|!FMezRu!i0o@ literal 27083 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 diff --git a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png index a7ebfdac8236caecd428c9a5d7c99352ea30c669..64ae5e68bbb8617dcfe0d05072b8b70ce1945e45 100644 GIT binary patch delta 135878 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

%N`Tpar~3*e*P^uXV5{uT%h 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 MNh?YfN$C6jFMX*apa1{> delta 135844 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

xByUG#X>9%SwilC8cd7G`FI3u_yjk`Ed5%73J# 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 diff --git a/src/components/actionbar/ComfyActionbar.vue b/src/components/actionbar/ComfyActionbar.vue index 1d24e4838..5ea860852 100644 --- a/src/components/actionbar/ComfyActionbar.vue +++ b/src/components/actionbar/ComfyActionbar.vue @@ -1,5 +1,5 @@