mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-22 13:32:11 +00:00
Implements the master plan from PR #11955 on top of PR #11310: - Phase 1: Add @tanstack/vue-query, wire VueQueryPlugin in main.ts with bounded gcTime + retry policy. Module-level singleton via getAppQueryClient() so non-Vue contexts (legacy useRemoteWidget) can reuse the same cache. - Phase 2: Move pure helpers to base/remote/ — itemSchema.ts (getByPath, resolveLabel, mapToDropdownItem, extractItems, buildSearchText), retry.ts (getBackoff, isRetriableError), diagnostics.ts (summarizeError, summarizePayload). Delete fetchRemoteRoute (auth headers now injected inline in useRemoteOptions per existing API-client pattern). - Phase 3: platform/remote/composables/useRemoteOptions.ts wraps TanStack Query with a typed RequestDescriptor and a key factory keyed by client/route/params/{userId, workspaceId} for defense-in-depth partitioning (auth-teardown invariant covers the cache lifecycle). - Phase 4: RemoteCombo/ atom family (Root/Trigger/Content/Search/List/ Item/Empty/Loading/Error/Refresh/LayoutSwitcher) over reka-ui's Combobox primitives. CVA variants in remoteCombo.variants.ts mirror Button.vue conventions (size/variant/border axes). Reka data-attr styling for hover/highlighted/checked. Adapter pattern for spec→prop extraction (specAdapter.ts + comboAdapter.ts). - Phase 5: useRemoteCombo (view layer: schema mapping, search index, auto_select). useRemoteWidget rewritten on getAppQueryClient() — preserves the IWidget mutation contract: first-load defaulting, control_after_refresh override, execution_success auto-refresh toggle. - Phase 6: zComboInputOptionsValidated enforces remote XOR remote_combo to match backend XOR validation. - Phase 7: Tests for new modules (comboAdapter, useRemoteOptions key factory, RichComboWidget atom-level flows, fast-check property test on mapToDropdownItem, XOR schema validation). Pure-helper tests relocated to base/remote/. - Phase 8: A11y minimums on every atom (aria-label/aria-live/aria-busy/ aria-disabled/aria-pressed; sr-only error/empty announcements). - Phase 9: Storybook stories (Default / Loading / Error / Empty / WithSelection / KeyboardA11y) for the atom family. Token-aligned to the design system per master plan §11.2.b. Removed: - src/renderer/extensions/vueNodes/widgets/utils/fetchRemoteRoute.{ts,test.ts} - src/renderer/extensions/vueNodes/widgets/utils/itemSchemaUtils.{ts,test.ts} - src/renderer/extensions/vueNodes/widgets/utils/richComboHelpers.{ts,test.ts} - The auth-scoped Cache API persistence layer in RichComboWidget.vue - The legacy in-memory cacheEntry map in useRemoteWidget.ts Quality gates: pnpm lint, typecheck, knip, build, test:unit (754 files, 10053 tests) all pass.
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import { QueryClient } from '@tanstack/vue-query'
|
|
|
|
import { isRetriableError } from '@/base/remote/retry'
|
|
|
|
const DEFAULT_GC_TIME_MS = 5 * 60_000
|
|
const DEFAULT_RETRY_COUNT = 3
|
|
|
|
let appQueryClient: QueryClient | undefined
|
|
|
|
/**
|
|
* Create the application-wide TanStack Query client.
|
|
*
|
|
* Defaults are tuned for remote-option dropdowns and similar widget data:
|
|
* - `staleTime: 0` so refresh buttons always re-fetch
|
|
* - `gcTime` bounded so a session's footprint stays small (no LRU yet)
|
|
* - `retry` driven by {@link isRetriableError} from `base/remote/retry`
|
|
* - `refetchOnWindowFocus: false` to avoid surprise re-fetches mid-edit
|
|
*
|
|
* QueryClient lifetime is bound to the Vue app instance; auth-state changes
|
|
* tear down the authenticated layout subtree (see master plan §8), so the
|
|
* cache is naturally evicted without manual `queryClient.clear()` calls.
|
|
*/
|
|
export function createAppQueryClient(): QueryClient {
|
|
appQueryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 0,
|
|
gcTime: DEFAULT_GC_TIME_MS,
|
|
retry: (failureCount, error) =>
|
|
failureCount < DEFAULT_RETRY_COUNT && isRetriableError(error),
|
|
refetchOnWindowFocus: false
|
|
}
|
|
}
|
|
})
|
|
return appQueryClient
|
|
}
|
|
|
|
export function getAppQueryClient(): QueryClient {
|
|
if (!appQueryClient) {
|
|
appQueryClient = createAppQueryClient()
|
|
}
|
|
return appQueryClient
|
|
}
|