From 20da521e0b79dcfca6e2515f531f393a7771072c Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Thu, 1 Oct 2026 22:16:25 -0400 Subject: [PATCH 1/5] feat(webv2): restore the What's New notes and point docs at the v7 site Add a lightbulb to the app menu footer, between Settings and Documentation, that opens a small What's New dialog listing the `whatsNew.items` catalog entries with links to the release notes and the docs. The dialog also opens once per server version for each account, after preferences load and the alpha notice is acknowledged; dismissing it records `whatsNewSeenVersion` in the account's workbench preferences. The server version is held in the What's New store rather than the query cache: the gate mounts above the router, and account transitions clear that cache without remounting it. Initial focus lands on the dialog panel so the automatic showing does not draw a keyboard focus ring on the first link. The documentation links now go to https://invoke-ai.github.io/InvokeAI-7/. Keep the new boot modules in the route-shared chunk so startup requests stay at baseline, and re-record the build baseline for the three modules the startup graph now contains. Co-Authored-By: Claude Opus 5.5 --- .../performance/architecture-baseline.json | 34 ++-- .../frontend/webv2/public/locales/en.json | 15 ++ .../frontend/webv2/scripts/mock-backend.mjs | 13 +- .../scripts/run-accessibility-journeys.mjs | 6 +- invokeai/frontend/webv2/src/app/App.tsx | 17 ++ invokeai/frontend/webv2/src/app/router.tsx | 3 + .../src/platform/i18n/translationKeys.test.ts | 5 + .../webv2/src/platform/runtime/appMetadata.ts | 8 + .../webv2/src/platform/ui/VendoredIcon.tsx | 10 + .../src/workbench/launchpad/HelpMenu.tsx | 4 +- .../webv2/src/workbench/settings/contracts.ts | 2 + .../webv2/src/workbench/settings/store.ts | 5 + .../shell/WhatsNewDialog.browser.test.tsx | 177 ++++++++++++++++++ ...hatsNewDialog.lateVersion.browser.test.tsx | 120 ++++++++++++ .../src/workbench/shell/WhatsNewDialog.tsx | 129 +++++++++++++ .../src/workbench/shell/topbar/AppMenu.tsx | 16 +- .../webv2/src/workbench/shell/useWhatsNew.ts | 29 +++ .../src/workbench/shell/whatsNewStore.ts | 62 ++++++ invokeai/frontend/webv2/vite.config.mts | 4 + 19 files changed, 633 insertions(+), 26 deletions(-) create mode 100644 invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.browser.test.tsx create mode 100644 invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.lateVersion.browser.test.tsx create mode 100644 invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.tsx create mode 100644 invokeai/frontend/webv2/src/workbench/shell/useWhatsNew.ts create mode 100644 invokeai/frontend/webv2/src/workbench/shell/whatsNewStore.ts diff --git a/invokeai/frontend/webv2/performance/architecture-baseline.json b/invokeai/frontend/webv2/performance/architecture-baseline.json index 5dc3c67c054..b429ad38677 100644 --- a/invokeai/frontend/webv2/performance/architecture-baseline.json +++ b/invokeai/frontend/webv2/performance/architecture-baseline.json @@ -2,15 +2,15 @@ "build": { "launchpad": { "baseline": { - "brotliBytes": 893586, + "brotliBytes": 783834, "cssRawBytes": 2159, "fontRawBytes": 219480, - "gzipBytes": 892942, - "imageRawBytes": 156376, - "initialRawBytes": 2118609, - "largestAssetRawBytes": 749035, + "gzipBytes": 783016, + "imageRawBytes": 44398, + "initialRawBytes": 2012114, + "largestAssetRawBytes": 749225, "otherAssetRawBytes": 0, - "ownedRawBytes": 93082, + "ownedRawBytes": 94155, "requestCount": 36, "scriptRequestCount": 20, "sourceOwners": [ @@ -197,6 +197,7 @@ "source:src/platform/react/useMountEffect.ts", "source:src/platform/react/usePreservedScrollOffset.ts", "source:src/platform/react/useZodForm.ts", + "source:src/platform/runtime/appMetadata.ts", "source:src/platform/search/dateTokens.ts", "source:src/platform/state/accountLifecycle.ts", "source:src/platform/state/externalStore.ts", @@ -325,7 +326,9 @@ "source:src/workbench/settings/launchpad.tsx", "source:src/workbench/settings/settingsDialogStore.ts", "source:src/workbench/settings/settingsSearchShortcut.ts", - "source:src/workbench/settings/store.ts" + "source:src/workbench/settings/store.ts", + "source:src/workbench/shell/useWhatsNew.ts", + "source:src/workbench/shell/whatsNewStore.ts" ] }, "owner": "app", @@ -334,15 +337,15 @@ }, "editor": { "baseline": { - "brotliBytes": 1243382, + "brotliBytes": 1139046, "cssRawBytes": 2159, "fontRawBytes": 219480, - "gzipBytes": 1237668, - "imageRawBytes": 156376, - "initialRawBytes": 3203516, - "largestAssetRawBytes": 749035, + "gzipBytes": 1132999, + "imageRawBytes": 44398, + "initialRawBytes": 3111181, + "largestAssetRawBytes": 749225, "otherAssetRawBytes": 0, - "ownedRawBytes": 144128, + "ownedRawBytes": 143824, "requestCount": 74, "scriptRequestCount": 58, "sourceOwners": [ @@ -715,6 +718,7 @@ "source:src/platform/react/useMountEffect.ts", "source:src/platform/react/usePreservedScrollOffset.ts", "source:src/platform/react/useZodForm.ts", + "source:src/platform/runtime/appMetadata.ts", "source:src/platform/search/dateTokens.ts", "source:src/platform/state/accountLifecycle.ts", "source:src/platform/state/compareAndSwapRollback.ts", @@ -1000,6 +1004,8 @@ "source:src/workbench/shell/topbar/useLayoutDrift.ts", "source:src/workbench/shell/topbar/useTopbarShortcut.ts", "source:src/workbench/shell/useMountedInstanceIds.ts", + "source:src/workbench/shell/useWhatsNew.ts", + "source:src/workbench/shell/whatsNewStore.ts", "source:src/workbench/useNotify.ts", "source:src/workbench/useOpenWorkbenchWidget.ts", "source:src/workbench/widget-frame/FloatingWidgetLayer.tsx", @@ -1066,7 +1072,7 @@ "source": "src/app/WorkbenchApp.tsx" } }, - "capturedAt": "2026-09-29", + "capturedAt": "2026-10-02", "developmentInvalidation": { "platformUiBarrel": { "specifier": "@platform/ui", diff --git a/invokeai/frontend/webv2/public/locales/en.json b/invokeai/frontend/webv2/public/locales/en.json index 025608e4354..9ef045e5eb9 100644 --- a/invokeai/frontend/webv2/public/locales/en.json +++ b/invokeai/frontend/webv2/public/locales/en.json @@ -4593,5 +4593,20 @@ "estimate": "{{count, number}} selected · {{images}}, {{videos}}, about {{size}}", "available": "{{images}}, {{videos}} unused · about {{size}} reclaimable" } + }, + "whatsNew": { + "items": [ + "Complete frontend facelift with flexible UI widgets.", + "Projects that help keep your work organized.", + "Powerful new Canvas features.", + "Video models: Wan-2.2, MiniMax H3, LTX-2.5.", + "Search galleries by content or image similarity.", + "An interactive image map that groups your gallery by theme and autotags images.", + "Smaller and faster models.", + "And much more!" + ], + "readReleaseNotes": "Read Release Notes", + "readTheDocs": "Read the Docs", + "whatsNewInInvoke": "What's New in Invoke" } } diff --git a/invokeai/frontend/webv2/scripts/mock-backend.mjs b/invokeai/frontend/webv2/scripts/mock-backend.mjs index c6e0cb1726d..c95441e8ef9 100644 --- a/invokeai/frontend/webv2/scripts/mock-backend.mjs +++ b/invokeai/frontend/webv2/scripts/mock-backend.mjs @@ -97,6 +97,8 @@ const STARTER_MODEL = { type: 'main', }; +const MOCK_APP_VERSION = 'fixture'; + const STARTER_MODELS_RESPONSE = { starter_bundles: { 'sd-1': { models: [STARTER_MODEL], name: 'Stable Diffusion 1.5' }, @@ -113,8 +115,13 @@ const createState = (profile) => { return { boards: new Map(fixture.boards.map((board) => [board.board_id, clone(board)])), - // Dismiss the alpha notice so journeys start on the requested page. - clientState: new Map([['webv2:workbench-settings', JSON.stringify({ alphaNoticeAcknowledged: true })]]), + // Dismiss the alpha notice and What's New notes so journeys start on the requested page. + clientState: new Map([ + [ + 'webv2:workbench-settings', + JSON.stringify({ alphaNoticeAcknowledged: true, whatsNewSeenVersion: MOCK_APP_VERSION }), + ], + ]), images: new Map(fixture.images.map((image) => [image.image_name, clone(image)])), models: new Map(fixture.models.map((model) => [model.key, clone(model)])), mutationClock: 0, @@ -867,7 +874,7 @@ export const startMockBackend = async (port, { profile = 'empty' } = {}) => { } if (method === 'GET' && path === '/api/v1/app/version') { - return json(200, { version: 'fixture' }); + return json(200, { version: MOCK_APP_VERSION }); } if (method === 'GET' && path === '/api/v1/app/generation_device_options') { diff --git a/invokeai/frontend/webv2/scripts/run-accessibility-journeys.mjs b/invokeai/frontend/webv2/scripts/run-accessibility-journeys.mjs index 6b6852a452b..1a02e31ba2b 100644 --- a/invokeai/frontend/webv2/scripts/run-accessibility-journeys.mjs +++ b/invokeai/frontend/webv2/scripts/run-accessibility-journeys.mjs @@ -534,16 +534,18 @@ const runTopbarMenuJourney = async (browser) => { const appMenu = page.getByRole('menu', { exact: true, name: 'Open menu' }); const commandPaletteItem = page.getByRole('menuitem', { name: /^Command palette/ }); const settingsItem = appMenu.getByRole('menuitem', { name: /^Settings(?: \(.+\))?$/ }); + const whatsNewItem = page.getByRole('menuitem', { exact: true, name: "What's New in Invoke" }); const documentationItem = page.getByRole('menuitem', { exact: true, name: 'Documentation' }); const discordItem = page.getByRole('menuitem', { exact: true, name: 'Discord' }); await commandPaletteItem.waitFor(); await settingsItem.waitFor(); + await whatsNewItem.waitFor(); await documentationItem.waitFor(); await discordItem.waitFor(); const footerMetrics = await appMenu.evaluate((menu) => { const menuBounds = menu.getBoundingClientRect(); - const footerItems = [...menu.querySelectorAll('[role="menuitem"]')].slice(-4); + const footerItems = [...menu.querySelectorAll('[role="menuitem"]')].slice(-5); return { itemsFit: footerItems.every((item) => { @@ -567,7 +569,7 @@ const runTopbarMenuJourney = async (browser) => { await appMenu.press('End'); assert.equal(await appMenu.getAttribute('aria-activedescendant'), await discordItem.getAttribute('id')); - for (const item of [documentationItem, settingsItem, commandPaletteItem]) { + for (const item of [documentationItem, whatsNewItem, settingsItem, commandPaletteItem]) { await appMenu.press('ArrowUp'); assert.equal(await appMenu.getAttribute('aria-activedescendant'), await item.getAttribute('id')); } diff --git a/invokeai/frontend/webv2/src/app/App.tsx b/invokeai/frontend/webv2/src/app/App.tsx index 3d3016dd630..9513e3daefb 100644 --- a/invokeai/frontend/webv2/src/app/App.tsx +++ b/invokeai/frontend/webv2/src/app/App.tsx @@ -4,6 +4,7 @@ import { AppToaster } from '@platform/ui/toaster'; import { RouterProvider } from '@tanstack/react-router'; import { system } from '@theme/system'; import { useWorkbenchSettingsSelector } from '@workbench/settings/store'; +import { useWhatsNew } from '@workbench/shell/useWhatsNew'; import { lazy, Suspense } from 'react'; import { FeatureHintsAdapterProvider } from './FeatureHintsProvider'; @@ -28,6 +29,21 @@ const AlphaNoticeGate = () => { ) : null; }; +const WhatsNewDialog = lazy(() => + import('@workbench/shell/WhatsNewDialog').then((module) => ({ default: module.WhatsNewDialog })) +); + +/** Load the What's New notes when a new version has not been seen yet, or when the app menu asks for them. */ +const WhatsNewGate = () => { + const { isOpen } = useWhatsNew(); + + return isOpen ? ( + + + + ) : null; +}; + export const App = () => ( @@ -35,6 +51,7 @@ export const App = () => ( + diff --git a/invokeai/frontend/webv2/src/app/router.tsx b/invokeai/frontend/webv2/src/app/router.tsx index e8cd8215540..2d2b4acd503 100644 --- a/invokeai/frontend/webv2/src/app/router.tsx +++ b/invokeai/frontend/webv2/src/app/router.tsx @@ -30,6 +30,7 @@ import { Launchpad } from '@workbench/launchpad/Launchpad'; import { ProjectFileOptionsProvider } from '@workbench/projects/components/ProjectFileOptionsProvider'; import { peekOpenProjectIds, type WorkbenchSearch } from '@workbench/projects/session'; import { loadWorkbenchSettings } from '@workbench/settings/store'; +import { loadAppVersion } from '@workbench/shell/whatsNewStore'; import { Fragment } from 'react'; import { SocketHubRuntime } from './SocketHubRuntime'; @@ -100,6 +101,8 @@ const authenticatedRoute = createRoute({ } } + // What's New compares this with the account's last-seen version; it never holds up the route. + void loadAppVersion(); await loadWorkbenchSettings(); }, component: AuthenticatedLayout, diff --git a/invokeai/frontend/webv2/src/platform/i18n/translationKeys.test.ts b/invokeai/frontend/webv2/src/platform/i18n/translationKeys.test.ts index f649b8dc3e6..186a015985a 100644 --- a/invokeai/frontend/webv2/src/platform/i18n/translationKeys.test.ts +++ b/invokeai/frontend/webv2/src/platform/i18n/translationKeys.test.ts @@ -29,6 +29,11 @@ const flattenCatalog = (value: unknown, prefix = '', keys = new Set()): const path = prefix ? `${prefix}.${segment}` : segment; if (typeof child === 'object' && child !== null) { + // An array is read whole with `t('x', { returnObjects: true })`, so its own path is a key too. + if (Array.isArray(child)) { + keys.add(path); + } + flattenCatalog(child, path, keys); continue; } diff --git a/invokeai/frontend/webv2/src/platform/runtime/appMetadata.ts b/invokeai/frontend/webv2/src/platform/runtime/appMetadata.ts index 717f5cd11e2..9b54abb5192 100644 --- a/invokeai/frontend/webv2/src/platform/runtime/appMetadata.ts +++ b/invokeai/frontend/webv2/src/platform/runtime/appMetadata.ts @@ -1,2 +1,10 @@ /** Build-time application metadata with no domain dependencies. */ export const APP_VERSION = '7.0'; + +export const DOCS_URL = 'https://invoke-ai.github.io/InvokeAI-7/'; + +/** Release notes for a server version string (`7.0.0`, `7.0.0-rc1`), or the release list when it is unknown. */ +export const getReleaseNotesUrl = (version: string | null): string => + version + ? `https://github.com/invoke-ai/InvokeAI/releases/tag/v${version}` + : 'https://github.com/invoke-ai/InvokeAI/releases'; diff --git a/invokeai/frontend/webv2/src/platform/ui/VendoredIcon.tsx b/invokeai/frontend/webv2/src/platform/ui/VendoredIcon.tsx index bfd7c10303f..7f5d5dfb4c3 100644 --- a/invokeai/frontend/webv2/src/platform/ui/VendoredIcon.tsx +++ b/invokeai/frontend/webv2/src/platform/ui/VendoredIcon.tsx @@ -102,3 +102,13 @@ export const GradientIcon = createVendoredIcon({ title: 'Gradient', viewBox: '0 0 32 32', }); + +export const LightbulbFilamentIcon = createVendoredIcon({ + origin: 'Phosphor Icons, bold weight (MIT)', + paths: [ + 'M180,232a12,12,0,0,1-12,12H88a12,12,0,0,1,0-24h80A12,12,0,0,1,180,232Zm40-128a92.47,92.47,0,0,1-37,73.73,7.81,7.81,0,0,0-3,6.27,20,20,0,0,1-20,20H96a20,20,0,0,1-20-20v-.23a7.76,7.76,0,0,0-3.25-6.2,91.36,91.36,0,0,1-36.75-73C35.73,54.69,76,13.2,125.79,12A92,92,0,0,1,220,104Zm-24,0a68,68,0,0,0-69.65-68C89.56,36.89,59.8,67.56,60,104.39a67.52,67.52,0,0,0,27.18,54h0A32.14,32.14,0,0,1,99.77,180H116V149L87.51,120.49a12,12,0,0,1,17-17L128,127l23.51-23.51a12,12,0,0,1,17,17L140,149v31h16.25a31.89,31.89,0,0,1,12.41-21.49A67.45,67.45,0,0,0,196,104Z', + ], + slug: 'lightbulb-filament', + title: 'Lightbulb', + viewBox: '0 0 256 256', +}); diff --git a/invokeai/frontend/webv2/src/workbench/launchpad/HelpMenu.tsx b/invokeai/frontend/webv2/src/workbench/launchpad/HelpMenu.tsx index f4880879939..7f01c2b21d4 100644 --- a/invokeai/frontend/webv2/src/workbench/launchpad/HelpMenu.tsx +++ b/invokeai/frontend/webv2/src/workbench/launchpad/HelpMenu.tsx @@ -1,7 +1,7 @@ import type { ElementType } from 'react'; import { chakra, HStack, Icon, Menu, Portal, Text } from '@chakra-ui/react'; -import { APP_VERSION } from '@platform/runtime/appMetadata'; +import { APP_VERSION, DOCS_URL } from '@platform/runtime/appMetadata'; import { Button } from '@platform/ui/Button'; import { MenuContent } from '@platform/ui/Menu'; import { DiscordIcon, GithubIcon } from '@platform/ui/VendoredIcon'; @@ -22,7 +22,7 @@ interface HelpLink { const GUIDES: HelpLink[] = [ { - href: 'https://invoke-ai.github.io/InvokeAI/', + href: DOCS_URL, icon: BookOpenTextIcon, labelKey: 'launchpad.help.documentation', value: 'documentation', diff --git a/invokeai/frontend/webv2/src/workbench/settings/contracts.ts b/invokeai/frontend/webv2/src/workbench/settings/contracts.ts index 6bb72cb54a7..e2b0cafe7b8 100644 --- a/invokeai/frontend/webv2/src/workbench/settings/contracts.ts +++ b/invokeai/frontend/webv2/src/workbench/settings/contracts.ts @@ -45,6 +45,8 @@ export interface StoredGeneratePreset { export interface WorkbenchPreferences { /** The alpha-build notice was dismissed; shown once per account until then. */ alphaNoticeAcknowledged: boolean; + /** Server version whose What's New notes were last dismissed; a different version shows them once. */ + whatsNewSeenVersion: string | null; themeId: WorkbenchThemeId; reduceMotion: boolean; showFocusRegionHighlight: boolean; diff --git a/invokeai/frontend/webv2/src/workbench/settings/store.ts b/invokeai/frontend/webv2/src/workbench/settings/store.ts index 6c1fb92e258..eeed16f05cc 100644 --- a/invokeai/frontend/webv2/src/workbench/settings/store.ts +++ b/invokeai/frontend/webv2/src/workbench/settings/store.ts @@ -67,6 +67,7 @@ export const DEFAULT_PREFERENCES: WorkbenchPreferences = { showPromptSyntaxHighlighting: true, showFocusRegionHighlight: true, themeId: DEFAULT_THEME_ID, + whatsNewSeenVersion: null, workflowEdgeStyle: 'curved', workflowEdgesBehindNodes: false, workflowGroupNodesByCategory: true, @@ -348,6 +349,10 @@ export const normalizeWorkbenchPreferences = (preferences?: WorkbenchPreferences ? preferences.showPromptSyntaxHighlighting : DEFAULT_PREFERENCES.showPromptSyntaxHighlighting, themeId: resolveWorkbenchThemeId(preferences?.themeId) ?? DEFAULT_PREFERENCES.themeId, + whatsNewSeenVersion: + typeof preferences?.whatsNewSeenVersion === 'string' + ? preferences.whatsNewSeenVersion + : DEFAULT_PREFERENCES.whatsNewSeenVersion, workflowEdgeStyle: preferences?.workflowEdgeStyle === 'square' || preferences?.workflowEdgeStyle === 'straight' ? 'square' diff --git a/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.browser.test.tsx b/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.browser.test.tsx new file mode 100644 index 00000000000..5bce28a715e --- /dev/null +++ b/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.browser.test.tsx @@ -0,0 +1,177 @@ +import { ChakraProvider } from '@chakra-ui/react'; +import { accountLifecycle } from '@platform/state/accountLifecycle'; +import { system } from '@theme/system'; +import { isHotkeyModalLayerActive } from '@workbench/hotkeys/modalLayer'; +import { createInstance } from 'i18next'; +import { act } from 'react'; +import { createRoot, type Root } from 'react-dom/client'; +import { I18nextProvider, initReactI18next } from 'react-i18next'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { page } from 'vitest/browser'; + +import { WhatsNewDialog } from './WhatsNewDialog'; +import * as store from './whatsNewStore'; + +type Snapshot = { + preferences: { alphaNoticeAcknowledged: boolean; whatsNewSeenVersion: string | null }; + status: 'idle' | 'ready'; +}; + +const settings = vi.hoisted(() => ({ + snapshot: { + preferences: { alphaNoticeAcknowledged: true, whatsNewSeenVersion: null }, + status: 'idle', + } as Snapshot, + listeners: new Set<() => void>(), + patchWorkbenchPreferences: vi.fn(), +})); + +vi.mock('@workbench/settings/store', async () => { + const { useSyncExternalStore } = await import('react'); + + return { + patchWorkbenchPreferences: settings.patchWorkbenchPreferences, + useWorkbenchSettingsSelector: (selector: (snapshot: Snapshot) => unknown) => + useSyncExternalStore( + (listener) => { + settings.listeners.add(listener); + return () => settings.listeners.delete(listener); + }, + () => selector(settings.snapshot) + ), + }; +}); + +vi.mock('@platform/transport/http', () => ({ + apiFetchJson: vi.fn((path: string) => + path === '/api/v1/app/version' + ? Promise.resolve({ version: '7.0.0-rc1' }) + : Promise.reject(new Error(`unexpected request ${path}`)) + ), +})); + +const catalog = (await fetch('/locales/en.json').then((response) => response.json())) as { + whatsNew: { items: string[] }; +}; +// An emphasized item exercises the `` markup the shipped catalog may use. +catalog.whatsNew.items = [...catalog.whatsNew.items, 'Try the new thing today.']; + +const i18n = createInstance(); +await i18n.use(initReactI18next).init({ + lng: 'en', + resources: { en: { translation: catalog } }, + interpolation: { escapeValue: false }, +}); + +(globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + +const setSnapshot = (next: Snapshot) => + act(() => { + settings.snapshot = next; + settings.listeners.forEach((listener) => listener()); + }); + +const ready = (preferences: Snapshot['preferences']): Snapshot => ({ preferences, status: 'ready' }); + +const title = () => i18n.t('whatsNew.whatsNewInInvoke'); + +describe('WhatsNewDialog', () => { + let host: HTMLDivElement; + let root: Root; + + beforeEach(async () => { + settings.patchWorkbenchPreferences.mockReset(); + settings.snapshot = { preferences: { alphaNoticeAcknowledged: true, whatsNewSeenVersion: null }, status: 'idle' }; + // An account switch drops the previous test's request and dismissal; the version is not account data. + accountLifecycle.invalidate(); + host = document.createElement('div'); + document.body.append(host); + root = createRoot(host); + await act(() => + root.render( + + + + + + ) + ); + }); + + afterEach(async () => { + await act(() => root.unmount()); + host.remove(); + }); + + it('shows once for an unseen version after preferences load, then records the version on dismissal', async () => { + await act(() => store.loadAppVersion()); + // Not before the account's preferences are known: an account that saw these notes must not see them flash. + expect(document.querySelector('[role="dialog"]')).toBeNull(); + + await setSnapshot(ready({ alphaNoticeAcknowledged: true, whatsNewSeenVersion: '6.14.2' })); + await expect.element(page.getByRole('dialog', { name: title() })).toBeVisible(); + await expect.element(page.getByText('v7.0.0-rc1')).toBeVisible(); + // An automatic open has no click behind it, so focus on a link would draw its keyboard ring; start on the panel. + await expect.element(page.getByRole('dialog', { name: title() })).toHaveFocus(); + expect(isHotkeyModalLayerActive()).toBe(true); + + const items = i18n.t('whatsNew.items', { returnObjects: true }) as string[]; + expect(page.getByRole('listitem').elements()).toHaveLength(items.length); + // Item text with `:` and `.` renders verbatim. + await expect.element(page.getByText('Video models: Wan-2.2, MiniMax H3, LTX-2.5.')).toBeVisible(); + const emphasis = page.getByText('the new thing', { exact: true }).element(); + expect(emphasis.tagName).toBe('SPAN'); + expect(emphasis.parentElement?.textContent).toBe('Try the new thing today.'); + + expect(page.getByRole('link', { name: i18n.t('whatsNew.readReleaseNotes') }).element()).toHaveAttribute( + 'href', + 'https://github.com/invoke-ai/InvokeAI/releases/tag/v7.0.0-rc1' + ); + expect(page.getByRole('link', { name: i18n.t('whatsNew.readTheDocs') }).element()).toHaveAttribute( + 'href', + 'https://invoke-ai.github.io/InvokeAI-7/' + ); + + await page.getByRole('button', { name: /close/i }).click(); + expect(settings.patchWorkbenchPreferences).toHaveBeenCalledExactlyOnceWith({ whatsNewSeenVersion: '7.0.0-rc1' }); + + await setSnapshot(ready({ alphaNoticeAcknowledged: true, whatsNewSeenVersion: '7.0.0-rc1' })); + await expect.element(page.getByRole('dialog')).not.toBeInTheDocument(); + expect(isHotkeyModalLayerActive()).toBe(false); + }); + + it('waits for the alpha notice to be dismissed first', async () => { + await act(() => store.loadAppVersion()); + await setSnapshot(ready({ alphaNoticeAcknowledged: false, whatsNewSeenVersion: null })); + await expect.element(page.getByText('v7.0.0-rc1')).not.toBeInTheDocument(); + expect(document.querySelector('[role="dialog"]')).toBeNull(); + + await setSnapshot(ready({ alphaNoticeAcknowledged: true, whatsNewSeenVersion: null })); + await expect.element(page.getByRole('dialog', { name: title() })).toBeVisible(); + }); + + it('stays closed for a seen version until the app menu opens it, and reopening writes nothing', async () => { + await act(() => store.loadAppVersion()); + await setSnapshot(ready({ alphaNoticeAcknowledged: true, whatsNewSeenVersion: '7.0.0-rc1' })); + expect(document.querySelector('[role="dialog"]')).toBeNull(); + + await act(() => store.openWhatsNew()); + await expect.element(page.getByRole('dialog', { name: title() })).toBeVisible(); + + await page.getByRole('button', { name: /close/i }).click(); + await expect.element(page.getByRole('dialog')).not.toBeInTheDocument(); + expect(settings.patchWorkbenchPreferences).not.toHaveBeenCalled(); + }); + + it('shows an unseen version again for the next account after one dismissed it', async () => { + await act(() => store.loadAppVersion()); + await setSnapshot(ready({ alphaNoticeAcknowledged: true, whatsNewSeenVersion: null })); + await page.getByRole('button', { name: /close/i }).click(); + await expect.element(page.getByRole('dialog')).not.toBeInTheDocument(); + + await act(() => { + accountLifecycle.invalidate(); + }); + await expect.element(page.getByRole('dialog', { name: title() })).toBeVisible(); + }); +}); diff --git a/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.lateVersion.browser.test.tsx b/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.lateVersion.browser.test.tsx new file mode 100644 index 00000000000..2e258373630 --- /dev/null +++ b/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.lateVersion.browser.test.tsx @@ -0,0 +1,120 @@ +import { ChakraProvider } from '@chakra-ui/react'; +import { system } from '@theme/system'; +import { createInstance } from 'i18next'; +import { act } from 'react'; +import { createRoot, type Root } from 'react-dom/client'; +import { I18nextProvider, initReactI18next } from 'react-i18next'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { page } from 'vitest/browser'; + +import { WhatsNewDialog } from './WhatsNewDialog'; +import * as store from './whatsNewStore'; + +type Snapshot = { + preferences: { alphaNoticeAcknowledged: boolean; whatsNewSeenVersion: string | null }; + status: 'idle' | 'ready'; +}; + +const settings = vi.hoisted(() => ({ + snapshot: { + preferences: { alphaNoticeAcknowledged: true, whatsNewSeenVersion: null }, + status: 'idle', + } as Snapshot, + listeners: new Set<() => void>(), + patchWorkbenchPreferences: vi.fn(), +})); + +vi.mock('@workbench/settings/store', async () => { + const { useSyncExternalStore } = await import('react'); + + return { + patchWorkbenchPreferences: settings.patchWorkbenchPreferences, + useWorkbenchSettingsSelector: (selector: (snapshot: Snapshot) => unknown) => + useSyncExternalStore( + (listener) => { + settings.listeners.add(listener); + return () => settings.listeners.delete(listener); + }, + () => selector(settings.snapshot) + ), + }; +}); + +const http = vi.hoisted(() => ({ resolveVersion: (_value: { version: string }) => {} })); + +// The version read stays pending until the test resolves it. +vi.mock('@platform/transport/http', () => ({ + apiFetchJson: vi.fn((path: string) => + path === '/api/v1/app/version' + ? new Promise((resolve) => { + http.resolveVersion = resolve; + }) + : Promise.reject(new Error(`unexpected request ${path}`)) + ), +})); + +const catalog = (await fetch('/locales/en.json').then((response) => response.json())) as Record; + +const i18n = createInstance(); +await i18n.use(initReactI18next).init({ + lng: 'en', + resources: { en: { translation: catalog } }, + interpolation: { escapeValue: false }, +}); + +(globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + +const setSnapshot = (next: Snapshot) => + act(() => { + settings.snapshot = next; + settings.listeners.forEach((listener) => listener()); + }); + +const ready = (preferences: Snapshot['preferences']): Snapshot => ({ preferences, status: 'ready' }); + +const title = () => i18n.t('whatsNew.whatsNewInInvoke'); + +/** Its own file: the store keeps the version for the page's lifetime, and this case needs it still unknown. */ +describe('WhatsNewDialog with a slow version read', () => { + let host: HTMLDivElement; + let root: Root; + + beforeEach(async () => { + host = document.createElement('div'); + document.body.append(host); + root = createRoot(host); + await act(() => + root.render( + + + + + + ) + ); + }); + + afterEach(async () => { + await act(() => root.unmount()); + host.remove(); + }); + + it('does not reopen notes closed by hand when the version arrives late', async () => { + await setSnapshot(ready({ alphaNoticeAcknowledged: true, whatsNewSeenVersion: '6.14.2' })); + + // The boot read is still pending when the menu opens the notes. + void store.loadAppVersion(); + await act(() => store.openWhatsNew()); + await expect.element(page.getByRole('dialog', { name: title() })).toBeVisible(); + await page.getByRole('button', { name: /close/i }).click(); + await expect.element(page.getByRole('dialog')).not.toBeInTheDocument(); + + await act(async () => { + http.resolveVersion({ version: '7.0.0-rc1' }); + await store.loadAppVersion(); + }); + expect(store.getWhatsNewSnapshot().version).toBe('7.0.0-rc1'); + await expect.element(page.getByRole('dialog')).not.toBeInTheDocument(); + expect(settings.patchWorkbenchPreferences).not.toHaveBeenCalled(); + }); +}); diff --git a/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.tsx b/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.tsx new file mode 100644 index 00000000000..8f2748e726c --- /dev/null +++ b/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.tsx @@ -0,0 +1,129 @@ +import { Dialog, HStack, Link, List, Portal, Stack, Text } from '@chakra-ui/react'; +import { useMountEffect } from '@platform/react/useMountEffect'; +import { DOCS_URL, getReleaseNotesUrl } from '@platform/runtime/appMetadata'; +import { CloseButton } from '@platform/ui'; +import { InvokeMark } from '@platform/ui/InvokeMark'; +import { registerHotkeyModalLayer } from '@workbench/hotkeys/modalLayer'; +import { patchWorkbenchPreferences } from '@workbench/settings/store'; +import { useCallback, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { useWhatsNew } from './useWhatsNew'; +import { dismissWhatsNew } from './whatsNewStore'; + +const EMPHASIS = /(.*?)<\/StrongComponent>/; + +const readItems = (value: unknown): string[] => + Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : []; + +/** Items may emphasize a phrase with `…`; split captures land on odd indexes. */ +const WhatsNewItem = ({ text }: { text: string }) => + text.split(EMPHASIS).map((part, index) => + index % 2 === 1 ? ( + + {part} + + ) : ( + part + ) + ); + +/** Mounted only while the notes are open: workbench hotkeys stay quiet under them, as under the other dialogs. */ +const WhatsNewModalLayer = () => { + useMountEffect(() => registerHotkeyModalLayer('whats-new')); + + return null; +}; + +export const WhatsNewDialog = () => { + const { t } = useTranslation(); + const { isOpen, isUnseen, version } = useWhatsNew(); + const items = readItems(t('whatsNew.items', { returnObjects: true })); + const contentRef = useRef(null); + // Start on the panel, not the first link: focus that opens without a click (the automatic showing) counts as + // keyboard focus and would ring the link. Tab still reaches the links, and Escape still closes. + const getInitialFocusEl = useCallback(() => contentRef.current, []); + + const handleOpenChange = useCallback( + (event: { open: boolean }) => { + if (event.open) { + return; + } + + dismissWhatsNew(); + + // Unseen implies loaded preferences; patching before they load would persist defaults over saved choices. + if (isUnseen) { + void patchWorkbenchPreferences({ whatsNewSeenVersion: version }); + } + }, + [isUnseen, version] + ); + + return ( + + {isOpen ? : null} + + + + + + + + {t('whatsNew.whatsNewInInvoke')} + {version ? ( + + v{version} + + ) : null} + + + + + + {items.map((item, index) => ( + // The catalog order is fixed for a build, so the index is a stable key. + + + + ))} + + + + {t('whatsNew.readReleaseNotes')} + + + {t('whatsNew.readTheDocs')} + + + + + + + + + + + + ); +}; diff --git a/invokeai/frontend/webv2/src/workbench/shell/topbar/AppMenu.tsx b/invokeai/frontend/webv2/src/workbench/shell/topbar/AppMenu.tsx index 67f8841bdb2..65ece9c981a 100644 --- a/invokeai/frontend/webv2/src/workbench/shell/topbar/AppMenu.tsx +++ b/invokeai/frontend/webv2/src/workbench/shell/topbar/AppMenu.tsx @@ -1,16 +1,17 @@ import { Badge, Box, chakra, HStack, Icon, Menu, Portal, Text } from '@chakra-ui/react'; import { AccountMenuSection, useCapabilities, useHasAccountSection } from '@features/identity'; import { getQueueSummary } from '@features/queue/contracts'; -import { APP_VERSION } from '@platform/runtime/appMetadata'; +import { APP_VERSION, DOCS_URL } from '@platform/runtime/appMetadata'; import { IconButton } from '@platform/ui/Button'; import { InvokeMark } from '@platform/ui/InvokeMark'; import { MenuContent } from '@platform/ui/Menu'; import { Tooltip } from '@platform/ui/Tooltip'; -import { DiscordIcon } from '@platform/ui/VendoredIcon'; +import { DiscordIcon, LightbulbFilamentIcon } from '@platform/ui/VendoredIcon'; import { useNavigate } from '@tanstack/react-router'; import { OPEN_COMMAND_PALETTE_HOTKEY } from '@workbench/hotkeys/catalog'; import { openCommandPalette } from '@workbench/palette/paletteStore'; import { openWorkbenchSettings } from '@workbench/settings/settingsDialogStore'; +import { openWhatsNew } from '@workbench/shell/whatsNewStore'; import { useOpenWorkbenchWidget } from '@workbench/useOpenWorkbenchWidget'; import { useActiveProjectId, useActiveProjectSelector } from '@workbench/WorkbenchContext'; import { @@ -23,7 +24,6 @@ import { SearchIcon, SettingsIcon, TypeIcon, - type LucideIcon, } from 'lucide-react'; import { useCallback, type ElementType } from 'react'; import { useTranslation } from 'react-i18next'; @@ -31,7 +31,6 @@ import { useTranslation } from 'react-i18next'; import { useTopbarShortcut } from './useTopbarShortcut'; const MENU_POSITIONING = { placement: 'bottom-start' } as const; -const DOCS_URL = 'https://invoke-ai.github.io/InvokeAI/'; const DISCORD_URL = 'https://discord.gg/ZmtBAhwWhy'; export const AppMenu = () => { @@ -121,6 +120,12 @@ export const AppMenu = () => { + void; value: string; diff --git a/invokeai/frontend/webv2/src/workbench/shell/useWhatsNew.ts b/invokeai/frontend/webv2/src/workbench/shell/useWhatsNew.ts new file mode 100644 index 00000000000..84c71c4b8f6 --- /dev/null +++ b/invokeai/frontend/webv2/src/workbench/shell/useWhatsNew.ts @@ -0,0 +1,29 @@ +import { useWorkbenchSettingsSelector } from '@workbench/settings/store'; + +import { useWhatsNewSnapshot } from './whatsNewStore'; + +export interface WhatsNewState { + isOpen: boolean; + /** Whether this showing is the automatic one for a version the account has not dismissed yet. */ + isUnseen: boolean; + /** The server version, or null while unknown. */ + version: string | null; +} + +/** + * Show the notes once per server version for each account, after its preferences are known and the alpha + * notice is out of the way, and whenever the app menu asks for them. + */ +export const useWhatsNew = (): WhatsNewState => { + const { isDismissed, isRequested, version } = useWhatsNewSnapshot(); + const isUnseen = useWorkbenchSettingsSelector( + (snapshot) => + !isDismissed && + version !== null && + snapshot.status === 'ready' && + snapshot.preferences.alphaNoticeAcknowledged && + snapshot.preferences.whatsNewSeenVersion !== version + ); + + return { isOpen: isRequested || isUnseen, isUnseen, version }; +}; diff --git a/invokeai/frontend/webv2/src/workbench/shell/whatsNewStore.ts b/invokeai/frontend/webv2/src/workbench/shell/whatsNewStore.ts new file mode 100644 index 00000000000..180ecadc89c --- /dev/null +++ b/invokeai/frontend/webv2/src/workbench/shell/whatsNewStore.ts @@ -0,0 +1,62 @@ +import { createLogger } from '@platform/logging/logger'; +import { registerAccountOwnedResource } from '@platform/state/accountLifecycle'; +import { createExternalStore } from '@platform/state/externalStore'; +import { apiFetchJson } from '@platform/transport/http'; + +const logger = createLogger({ area: 'whats-new', namespace: 'app' }); + +export interface WhatsNewSnapshot { + /** + * Closed during this page load. A version that arrives after a manual close must not reopen the notes the user + * just dismissed; the next load still shows an unseen version. + */ + isDismissed: boolean; + /** Opened from the app menu; the automatic first-run showing is derived from preferences instead. */ + isRequested: boolean; + /** + * The server version, or null while unknown. Held here rather than in the query cache: the gate lives above + * the router, and account transitions clear that cache without remounting it. + */ + version: string | null; +} + +const store = createExternalStore({ isDismissed: false, isRequested: false, version: null }); + +let versionLoad: Promise | null = null; + +// The server version is not account data; only the request to show the notes follows the account. +registerAccountOwnedResource({ + clear: () => store.patchSnapshot({ isDismissed: false, isRequested: false }), + name: 'whats-new', +}); + +/** The version only changes across a server restart, so one successful read per page load is enough. */ +export const loadAppVersion = (): Promise => { + if (store.getSnapshot().version !== null) { + return Promise.resolve(); + } + + versionLoad ??= apiFetchJson<{ version: string }>('/api/v1/app/version') + .then((response) => store.patchSnapshot({ version: response.version })) + .catch((error: unknown) => { + // The notes stay closed until a later load succeeds; nothing else depends on them. + logger.warn({ error, message: 'Failed to load the app version', name: 'app.whats-new.version-failed' }); + }) + .finally(() => { + versionLoad = null; + }); + + return versionLoad; +}; + +export const openWhatsNew = (): void => { + store.patchSnapshot({ isRequested: true }); + // A failed boot read leaves the version out of the header and links; try again while the notes are open. + void loadAppVersion(); +}; + +export const dismissWhatsNew = (): void => store.patchSnapshot({ isDismissed: true, isRequested: false }); + +export const getWhatsNewSnapshot = (): WhatsNewSnapshot => store.getSnapshot(); + +export const useWhatsNewSnapshot = (): WhatsNewSnapshot => store.useSnapshot(); diff --git a/invokeai/frontend/webv2/vite.config.mts b/invokeai/frontend/webv2/vite.config.mts index e92fb1d44fa..375c8198004 100644 --- a/invokeai/frontend/webv2/vite.config.mts +++ b/invokeai/frontend/webv2/vite.config.mts @@ -40,6 +40,10 @@ const ROUTE_SHARED_MODULES = [ '/platform/ui/settings/contracts.ts', '/platform/core/concurrency.ts', '/platform/query/client.ts', + // The What's New gate mounts at boot; the app menu and the lazy dialog share these with it. + '/platform/runtime/appMetadata.ts', + '/workbench/shell/useWhatsNew.ts', + '/workbench/shell/whatsNewStore.ts', '/platform/time/serverTimestamp.ts', '/platform/transport/connectionStore.ts', '/platform/transport/socketHub.ts', From 1d6c832da62a1ddf155f9f52f2fa3b251ba133e6 Mon Sep 17 00:00:00 2001 From: Lincoln Stein Date: Thu, 1 Oct 2026 22:25:14 -0400 Subject: [PATCH 2/5] feat(webv2): open What's New from the launchpad and add Home to the app menu The launchpad has no app menu, so its rail footer gets a What's New action with the same lightbulb, between Preferences and Help. The editor's Invoke menu gains a Home item, with the launchpad's house icon, above Manage. Co-Authored-By: Claude Opus 5.5 --- .../src/workbench/launchpad/LaunchpadNav.tsx | 21 ++++++++++++++++++- .../src/workbench/shell/topbar/AppMenu.tsx | 9 ++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/invokeai/frontend/webv2/src/workbench/launchpad/LaunchpadNav.tsx b/invokeai/frontend/webv2/src/workbench/launchpad/LaunchpadNav.tsx index 9d1a5e49557..98a95bbb0fc 100644 --- a/invokeai/frontend/webv2/src/workbench/launchpad/LaunchpadNav.tsx +++ b/invokeai/frontend/webv2/src/workbench/launchpad/LaunchpadNav.tsx @@ -3,7 +3,9 @@ import type { LucideIcon } from 'lucide-react'; import { Icon, Stack, Text } from '@chakra-ui/react'; import { Button } from '@platform/ui/Button'; +import { LightbulbFilamentIcon } from '@platform/ui/VendoredIcon'; import { Link } from '@tanstack/react-router'; +import { openWhatsNew } from '@workbench/shell/whatsNewStore'; import { useId, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -19,7 +21,7 @@ const FOOTER_MARGIN_TOP = { md: 'auto' } as const; /** * Sections are routes, so the rail is route links in visual order: Workspace, the open projects, Manage, then the - * footer (Preferences). Tab and reading order follow what the rail shows. + * footer (Preferences, then the What's New and Help actions). Tab and reading order follow what the rail shows. */ export type LaunchpadNavGroupId = 'workspace' | 'manage' | 'footer'; @@ -68,6 +70,22 @@ const NavLink = ({ isActive, item }: { isActive: boolean; item: LaunchpadNavItem ); +const WHATS_NEW_JUSTIFY = { justifyContent: 'start' } as const; + +/** An action, not a route: styled like the Help trigger beneath it rather than as a rail link. */ +const WhatsNewButton = () => { + const { t } = useTranslation(); + + return ( + + ); +}; + const NavGroup = ({ activeId, group, @@ -131,6 +149,7 @@ export const LaunchpadNav = ({ activeId, items }: { activeId: string; items: Lau {footerItems.map((item) => ( ))} + diff --git a/invokeai/frontend/webv2/src/workbench/shell/topbar/AppMenu.tsx b/invokeai/frontend/webv2/src/workbench/shell/topbar/AppMenu.tsx index 65ece9c981a..2628db703bf 100644 --- a/invokeai/frontend/webv2/src/workbench/shell/topbar/AppMenu.tsx +++ b/invokeai/frontend/webv2/src/workbench/shell/topbar/AppMenu.tsx @@ -20,6 +20,7 @@ import { BoxIcon, ChevronDownIcon, FolderIcon, + HouseIcon, ListOrderedIcon, SearchIcon, SettingsIcon, @@ -42,6 +43,9 @@ export const AppMenu = () => { const openWorkbenchWidget = useOpenWorkbenchWidget(); const queuedCount = useActiveProjectSelector((project) => getQueueSummary(project.queue.items).total); + const openHome = useCallback(() => { + void navigate({ to: '/' }); + }, [navigate]); const openProjects = useCallback(() => { void navigate({ to: '/projects' }); }, [navigate]); @@ -76,6 +80,11 @@ export const AppMenu = () => { + + + {t('launchpad.sections.home')} + + {t('topbar.appMenu.manage')} From 6a6e44d79f405eaa444d525884a7d51487302843 Mon Sep 17 00:00:00 2001 From: Josh Corbett Date: Thu, 1 Oct 2026 20:52:25 -0600 Subject: [PATCH 3/5] feat(webv2): redesign the What's New dialog around the v7 highlights Widen the dialog and lead with the v7 logo, title and version badge. Headline features show as icon cards from `whatsNew.highlights`, with the remaining notes listed beneath and the docs and release notes as footer buttons. --- .../frontend/webv2/public/locales/en.json | 32 +++- .../frontend/webv2/src/assets/V7Logo.webp | Bin 0 -> 113414 bytes .../shell/WhatsNewDialog.browser.test.tsx | 22 +-- .../src/workbench/shell/WhatsNewDialog.tsx | 165 +++++++++++------- 4 files changed, 145 insertions(+), 74 deletions(-) create mode 100644 invokeai/frontend/webv2/src/assets/V7Logo.webp diff --git a/invokeai/frontend/webv2/public/locales/en.json b/invokeai/frontend/webv2/public/locales/en.json index 9ef045e5eb9..d1a64e162da 100644 --- a/invokeai/frontend/webv2/public/locales/en.json +++ b/invokeai/frontend/webv2/public/locales/en.json @@ -4595,14 +4595,36 @@ } }, "whatsNew": { + "alsoNew": "Also in this release", + "highlights": { + "canvas": { + "description": "A new engine with layer groups, blend modes, pressure-sensitive brushes, text, and PSD export.", + "title": "Rebuilt Canvas" + }, + "interface": { + "description": "One workbench of widgets you can arrange, pop out into windows, or reach from the command palette.", + "title": "Redesigned interface" + }, + "models": { + "description": "New video models like Wan-2.2, MiniMax H3, and LTX-2.5, plus larger Anima models.", + "title": "Expanded model support" + }, + "projects": { + "description": "Autosaving projects keep your canvas, settings, and workflows together, and export as .invk files.", + "title": "Projects" + } + }, "items": [ - "Complete frontend facelift with flexible UI widgets.", - "Projects that help keep your work organized.", - "Powerful new Canvas features.", - "Video models: Wan-2.2, MiniMax H3, LTX-2.5.", + "Generation settings presets.", + "For-loop workflows.", "Search galleries by content or image similarity.", "An interactive image map that groups your gallery by theme and autotags images.", - "Smaller and faster models.", + "Dynamic prompts, wildcards, and prompt templates.", + "Smaller, faster models with FP8, NVFP4, and int8 quantization.", + "Full color theming system with 6 presets.", + "Multi-GPU support.", + "Interactive intermediates manager.", + "Full tablet support.", "And much more!" ], "readReleaseNotes": "Read Release Notes", diff --git a/invokeai/frontend/webv2/src/assets/V7Logo.webp b/invokeai/frontend/webv2/src/assets/V7Logo.webp new file mode 100644 index 0000000000000000000000000000000000000000..e9353f3e5dff9f0bc79c2bbd0718855462a85939 GIT binary patch literal 113414 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

wBjh@!5|3L^o^aoBa` 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 ({ })); const catalog = (await fetch('/locales/en.json').then((response) => response.json())) as { - whatsNew: { items: string[] }; + whatsNew: { highlights: Record; items: string[] }; }; -// An emphasized item exercises the `` markup the shipped catalog may use. -catalog.whatsNew.items = [...catalog.whatsNew.items, 'Try the new thing today.']; const i18n = createInstance(); await i18n.use(initReactI18next).init({ @@ -115,13 +113,17 @@ describe('WhatsNewDialog', () => { await expect.element(page.getByRole('dialog', { name: title() })).toHaveFocus(); expect(isHotkeyModalLayerActive()).toBe(true); - const items = i18n.t('whatsNew.items', { returnObjects: true }) as string[]; - expect(page.getByRole('listitem').elements()).toHaveLength(items.length); - // Item text with `:` and `.` renders verbatim. - await expect.element(page.getByText('Video models: Wan-2.2, MiniMax H3, LTX-2.5.')).toBeVisible(); - const emphasis = page.getByText('the new thing', { exact: true }).element(); - expect(emphasis.tagName).toBe('SPAN'); - expect(emphasis.parentElement?.textContent).toBe('Try the new thing today.'); + // Every catalogued highlight renders with its title, and the smaller notes list beneath them. + for (const { description, title } of Object.values(catalog.whatsNew.highlights)) { + await expect.element(page.getByText(title, { exact: true })).toBeVisible(); + await expect.element(page.getByText(description, { exact: true })).toBeVisible(); + } + expect( + page + .getByRole('listitem') + .elements() + .map((item) => item.textContent) + ).toEqual(catalog.whatsNew.items); expect(page.getByRole('link', { name: i18n.t('whatsNew.readReleaseNotes') }).element()).toHaveAttribute( 'href', diff --git a/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.tsx b/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.tsx index 8f2748e726c..522d741a3a2 100644 --- a/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.tsx +++ b/invokeai/frontend/webv2/src/workbench/shell/WhatsNewDialog.tsx @@ -1,33 +1,46 @@ -import { Dialog, HStack, Link, List, Portal, Stack, Text } from '@chakra-ui/react'; +import type { LucideIcon } from 'lucide-react'; + +import v7LogoUrl from '@assets/V7Logo.webp'; +import { Badge, Box, Dialog, Flex, Grid, Image, Link, List, Portal, Stack, Text, VStack } from '@chakra-ui/react'; import { useMountEffect } from '@platform/react/useMountEffect'; import { DOCS_URL, getReleaseNotesUrl } from '@platform/runtime/appMetadata'; -import { CloseButton } from '@platform/ui'; -import { InvokeMark } from '@platform/ui/InvokeMark'; +import { Button, CloseButton } from '@platform/ui'; import { registerHotkeyModalLayer } from '@workbench/hotkeys/modalLayer'; import { patchWorkbenchPreferences } from '@workbench/settings/store'; +import { BookOpenIcon, BoxesIcon, BrushIcon, FolderIcon, PanelsTopLeftIcon, ScrollTextIcon } from 'lucide-react'; import { useCallback, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { useWhatsNew } from './useWhatsNew'; import { dismissWhatsNew } from './whatsNewStore'; -const EMPHASIS = /(.*?)<\/StrongComponent>/; +/** Headline features get an icon and a title; the `whatsNew.items` catalog lists the smaller notes beneath them. */ +const HIGHLIGHTS: readonly { descriptionKey: string; icon: LucideIcon; titleKey: string }[] = [ + { + descriptionKey: 'whatsNew.highlights.interface.description', + icon: PanelsTopLeftIcon, + titleKey: 'whatsNew.highlights.interface.title', + }, + { + descriptionKey: 'whatsNew.highlights.projects.description', + icon: FolderIcon, + titleKey: 'whatsNew.highlights.projects.title', + }, + { + descriptionKey: 'whatsNew.highlights.canvas.description', + icon: BrushIcon, + titleKey: 'whatsNew.highlights.canvas.title', + }, + { + descriptionKey: 'whatsNew.highlights.models.description', + icon: BoxesIcon, + titleKey: 'whatsNew.highlights.models.title', + }, +]; const readItems = (value: unknown): string[] => Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : []; -/** Items may emphasize a phrase with `…`; split captures land on odd indexes. */ -const WhatsNewItem = ({ text }: { text: string }) => - text.split(EMPHASIS).map((part, index) => - index % 2 === 1 ? ( - - {part} - - ) : ( - part - ) - ); - /** Mounted only while the notes are open: workbench hotkeys stay quiet under them, as under the other dialogs. */ const WhatsNewModalLayer = () => { useMountEffect(() => registerHotkeyModalLayer('whats-new')); @@ -65,59 +78,93 @@ export const WhatsNewDialog = () => { initialFocusEl={getInitialFocusEl} open={isOpen} placement="center" - size="xs" + scrollBehavior="inside" + size="lg" onOpenChange={handleOpenChange} > {isOpen ? : null} - - - - - {t('whatsNew.whatsNewInInvoke')} - {version ? ( - - v{version} - - ) : null} - + + + + + + {t('whatsNew.whatsNewInInvoke')} + {version ? ( + + v{version} + + ) : null} + + - - - - {items.map((item, index) => ( - // The catalog order is fixed for a build, so the index is a stable key. - - - + + + + {HIGHLIGHTS.map(({ descriptionKey, icon: HighlightIcon, titleKey }) => ( + + + + + + + {t(titleKey)} + + + {t(descriptionKey)} + + + ))} - - - - {t('whatsNew.readReleaseNotes')} - - - {t('whatsNew.readTheDocs')} - - + + {items.length > 0 ? ( + + + {t('whatsNew.alsoNew')} + + + {items.map((item, index) => ( + // The catalog order is fixed for a build, so the index is a stable key. + {item} + ))} + + + ) : null} + + + + From 9ed7e29c1e718cfbc2dc13ca557b32fa803628e5 Mon Sep 17 00:00:00 2001 From: Josh Corbett Date: Thu, 1 Oct 2026 21:09:04 -0600 Subject: [PATCH 4/5] fix(webv2): read the app version from the Python package at build time Replace the hard-coded `7.0` with `__version__` from invokeai_version.py, injected by Vite; the build fails if the file is missing or unparseable. The Docker web stage mirrors the repository layout so the file is available. --- docker/Dockerfile | 6 ++++-- .../docs/development/Process/release-process.mdx | 3 ++- .../webv2/src/platform/runtime/appMetadata.ts | 2 +- invokeai/frontend/webv2/src/vite-env.d.ts | 5 +++++ invokeai/frontend/webv2/vite.config.mts | 16 ++++++++++++++++ 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index f04a840b556..6be57bd8089 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -7,10 +7,12 @@ ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN corepack use pnpm@10.x && corepack enable -WORKDIR /build +# Mirror the repository layout: the webv2 build reads the release version from invokeai/version. +WORKDIR /build/invokeai/frontend/webv2 COPY invokeai/frontend/webv2/ ./ RUN --mount=type=cache,target=/pnpm/store \ pnpm install --frozen-lockfile +COPY invokeai/version/invokeai_version.py /build/invokeai/version/ RUN pnpm exec vite build FROM web-builder AS legacy-web-builder @@ -100,7 +102,7 @@ ENTRYPOINT ["/opt/invokeai/docker-entrypoint.sh"] CMD ["invokeai-web"] # --link requires buldkit w/ dockerfile syntax 1.4, does not work with podman -COPY --link --from=web-builder /build/dist ${INVOKEAI_SRC}/invokeai/frontend/webv2/dist +COPY --link --from=web-builder /build/invokeai/frontend/webv2/dist ${INVOKEAI_SRC}/invokeai/frontend/webv2/dist COPY --link --from=legacy-web-builder /legacy-build/dist ${INVOKEAI_SRC}/invokeai/frontend/webv1/dist # add sources last to minimize image changes on code changes diff --git a/docs/src/content/docs/development/Process/release-process.mdx b/docs/src/content/docs/development/Process/release-process.mdx index 2764f4b101e..c6b22730fbc 100644 --- a/docs/src/content/docs/development/Process/release-process.mdx +++ b/docs/src/content/docs/development/Process/release-process.mdx @@ -21,7 +21,8 @@ The launcher uses GitHub as the source of truth for available releases. Make a developer call-out for PRs to merge. Merge and test things out. Create a branch with a name like user/chore/vX.X.X-prep and bump the version by editing -`invokeai/version/invokeai_version.py` and commit locally. +`invokeai/version/invokeai_version.py` and commit locally. The web UI reads its version from the same file when it is +built, so there is no separate frontend version to update. ## Release Workflow diff --git a/invokeai/frontend/webv2/src/platform/runtime/appMetadata.ts b/invokeai/frontend/webv2/src/platform/runtime/appMetadata.ts index 9b54abb5192..125211580c0 100644 --- a/invokeai/frontend/webv2/src/platform/runtime/appMetadata.ts +++ b/invokeai/frontend/webv2/src/platform/runtime/appMetadata.ts @@ -1,5 +1,5 @@ /** Build-time application metadata with no domain dependencies. */ -export const APP_VERSION = '7.0'; +export const APP_VERSION = import.meta.env.APP_VERSION; export const DOCS_URL = 'https://invoke-ai.github.io/InvokeAI-7/'; diff --git a/invokeai/frontend/webv2/src/vite-env.d.ts b/invokeai/frontend/webv2/src/vite-env.d.ts index feb9fa84f7e..3a070d8e825 100644 --- a/invokeai/frontend/webv2/src/vite-env.d.ts +++ b/invokeai/frontend/webv2/src/vite-env.d.ts @@ -2,3 +2,8 @@ /** Rewrites canvas pixel goldens instead of comparing them; set by `test:browser:update-goldens`. */ declare const __CANVAS_GOLDEN_UPDATE__: boolean; + +interface ImportMetaEnv { + /** The release version from `invokeai/version/invokeai_version.py`, injected by `vite.config.mts`. */ + readonly APP_VERSION: string; +} diff --git a/invokeai/frontend/webv2/vite.config.mts b/invokeai/frontend/webv2/vite.config.mts index 375c8198004..9d55e5489b0 100644 --- a/invokeai/frontend/webv2/vite.config.mts +++ b/invokeai/frontend/webv2/vite.config.mts @@ -1,5 +1,6 @@ import babel from '@rolldown/plugin-babel'; import react, { reactCompilerPreset } from '@vitejs/plugin-react'; +import { readFileSync } from 'node:fs'; import { fileURLToPath, URL } from 'node:url'; import { defineConfig } from 'vite'; @@ -17,6 +18,19 @@ const ALLOWED_HOSTS = process.env.INVOKEAI_DEV_HOSTS?.split(',') .filter(Boolean); const PROJECT_ROOT = fileURLToPath(new URL('.', import.meta.url)); +// The Python package owns the release version, and the release workflow checks it against the tag. Fail the build +// rather than ship a guessed version if the file moves or its format changes. +const VERSION_FILE = fileURLToPath(new URL('../../version/invokeai_version.py', import.meta.url)); +const readAppVersion = (): string => { + const version = /^__version__\s*=\s*["']([^"']+)["']/m.exec(readFileSync(VERSION_FILE, 'utf8'))?.[1]; + + if (!version) { + throw new Error(`No __version__ assignment found in ${VERSION_FILE}.`); + } + + return version; +}; + // Group eager dependencies shared by both routes to avoid extra chunk requests. const ROUTE_SHARED_MODULES = [ '/features/fonts/data/keys.ts', @@ -318,6 +332,8 @@ const getLegacyChunkName = (id: string): string | null => { export default defineConfig({ define: { + // An env define, not a global: Vitest browser mode re-encodes string globals, wrapping them in quotes. + 'import.meta.env.APP_VERSION': JSON.stringify(readAppVersion()), // Use a boolean: Vitest browser mode treats string defines as truthy string literals. __CANVAS_GOLDEN_UPDATE__: false, }, From 27d8400d7010adbc44393effaece8e3f828b04bb Mon Sep 17 00:00:00 2001 From: Josh Corbett Date: Thu, 1 Oct 2026 21:51:36 -0600 Subject: [PATCH 5/5] chore(webv2): re-record the browser baseline for the What's New boot modules appMetadata, whatsNewStore and useWhatsNew now load at startup: startup scripts grow by 4.8 KB on the launchpad and 7.5 KB in the editor, with no new requests. --- .../webv2/performance/browser-baseline.json | 248 +++++++++--------- 1 file changed, 130 insertions(+), 118 deletions(-) diff --git a/invokeai/frontend/webv2/performance/browser-baseline.json b/invokeai/frontend/webv2/performance/browser-baseline.json index 20420c48665..b997a8f89be 100644 --- a/invokeai/frontend/webv2/performance/browser-baseline.json +++ b/invokeai/frontend/webv2/performance/browser-baseline.json @@ -1,6 +1,6 @@ { "browserExecutable": "/home/toast/.cache/ms-playwright/chromium-1243/chrome-linux64/chrome", - "capturedAt": "2026-10-01", + "capturedAt": "2026-10-02", "routes": [ { "activatedResourceBaseline": { @@ -14,13 +14,13 @@ "scriptRequestCount": 0, "totalRawBytes": 0 }, - "domContentLoadedMedianMs": 128, + "domContentLoadedMedianMs": 128.09999999776483, "id": "launchpad", "layoutAckMedianMs": 0, "layoutReturnSwitchMedianMs": 0, "layoutSwitchMedianMs": 0, - "loadMedianMs": 128.09999999776483, - "longestTaskMaxMs": 81, + "loadMedianMs": 128.19999999925494, + "longestTaskMaxMs": 82, "owner": "app", "projectSwitchMedianMs": 0, "readyMark": "invokeai:ready:launchpad", @@ -29,14 +29,14 @@ "cssRawBytes": 2159, "fontRawBytes": 23664, "imageRawBytes": 0, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 31, - "scriptRawBytes": 1806891, + "scriptRawBytes": 1811680, "scriptRequestCount": 27, - "totalRawBytes": 2017245 + "totalRawBytes": 2023258 }, - "routeReadyMedianMs": 266.29999999701977, + "routeReadyMedianMs": 266.8999999985099, "scriptSourceOwnerSet": "launchpad-static", "stateProfile": "empty" }, @@ -52,13 +52,13 @@ "scriptRequestCount": 0, "totalRawBytes": 0 }, - "domContentLoadedMedianMs": 125, + "domContentLoadedMedianMs": 125.39999999850988, "id": "launchpad", "layoutAckMedianMs": 0, "layoutReturnSwitchMedianMs": 0, "layoutSwitchMedianMs": 0, - "loadMedianMs": 125.09999999776483, - "longestTaskMaxMs": 80, + "loadMedianMs": 125.59999999776483, + "longestTaskMaxMs": 79, "owner": "app", "projectSwitchMedianMs": 0, "readyMark": "invokeai:ready:launchpad", @@ -67,14 +67,14 @@ "cssRawBytes": 2159, "fontRawBytes": 23664, "imageRawBytes": 0, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 31, - "scriptRawBytes": 1806891, + "scriptRawBytes": 1811680, "scriptRequestCount": 27, - "totalRawBytes": 2017245 + "totalRawBytes": 2023258 }, - "routeReadyMedianMs": 275.6000000014901, + "routeReadyMedianMs": 274.5999999977648, "scriptSourceOwnerSet": "launchpad-static", "stateProfile": "representative" }, @@ -90,29 +90,29 @@ "scriptRequestCount": 0, "totalRawBytes": 0 }, - "domContentLoadedMedianMs": 129.30000000074506, + "domContentLoadedMedianMs": 125.69999999925494, "id": "editor-minimal", "layoutAckMedianMs": 0, "layoutReturnSwitchMedianMs": 0, "layoutSwitchMedianMs": 0, - "loadMedianMs": 129.5, - "longestTaskMaxMs": 160, + "loadMedianMs": 125.89999999850988, + "longestTaskMaxMs": 169, "owner": "workbench", - "projectSwitchMedianMs": 36.80000000074506, + "projectSwitchMedianMs": 35.900000002235174, "readyMark": "invokeai:ready:widget:center:preview", "remediationTicket": "deepen-widget-registry-loading", "resourceBaseline": { "cssRawBytes": 2159, "fontRawBytes": 23664, - "imageRawBytes": 156376, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "imageRawBytes": 44398, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 89, - "scriptRawBytes": 3900320, + "scriptRawBytes": 3907818, "scriptRequestCount": 84, - "totalRawBytes": 4267050 + "totalRawBytes": 4163794 }, - "routeReadyMedianMs": 424.0999999977648, + "routeReadyMedianMs": 420.80000000074506, "scriptSourceOwnerSet": "editor-minimal-static", "stateProfile": "empty" }, @@ -128,29 +128,29 @@ "scriptRequestCount": 0, "totalRawBytes": 0 }, - "domContentLoadedMedianMs": 125.60000000149012, + "domContentLoadedMedianMs": 130.30000000074506, "id": "editor-minimal", "layoutAckMedianMs": 0, "layoutReturnSwitchMedianMs": 0, "layoutSwitchMedianMs": 0, - "loadMedianMs": 125.80000000074506, - "longestTaskMaxMs": 162, + "loadMedianMs": 130.30000000074506, + "longestTaskMaxMs": 165, "owner": "workbench", - "projectSwitchMedianMs": 39.80000000074506, + "projectSwitchMedianMs": 43.400000002235174, "readyMark": "invokeai:ready:widget:center:preview", "remediationTicket": "deepen-widget-registry-loading", "resourceBaseline": { "cssRawBytes": 2159, "fontRawBytes": 23664, - "imageRawBytes": 156376, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "imageRawBytes": 44398, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 89, - "scriptRawBytes": 3900320, + "scriptRawBytes": 3907818, "scriptRequestCount": 84, - "totalRawBytes": 4267050 + "totalRawBytes": 4163794 }, - "routeReadyMedianMs": 429.80000000074506, + "routeReadyMedianMs": 446.5, "scriptSourceOwnerSet": "editor-minimal-static", "stateProfile": "representative" }, @@ -159,20 +159,20 @@ "cssRawBytes": 0, "fontRawBytes": 0, "imageRawBytes": 0, - "largestAssetRawBytes": 310063, + "largestAssetRawBytes": 310062, "otherRawBytes": 0, "requestCount": 9, - "scriptRawBytes": 507630, + "scriptRawBytes": 507632, "scriptRequestCount": 9, - "totalRawBytes": 507630 + "totalRawBytes": 507632 }, - "domContentLoadedMedianMs": 128.30000000074506, + "domContentLoadedMedianMs": 128.60000000149012, "id": "editor-canvas", - "layoutAckMedianMs": 2.800000000745058, - "layoutReturnSwitchMedianMs": 44.400000002235174, - "layoutSwitchMedianMs": 86.89999999850988, - "loadMedianMs": 128.5, - "longestTaskMaxMs": 160, + "layoutAckMedianMs": 2.5, + "layoutReturnSwitchMedianMs": 46, + "layoutSwitchMedianMs": 84.89999999850988, + "loadMedianMs": 128.69999999925494, + "longestTaskMaxMs": 163, "owner": "canvas", "projectSwitchMedianMs": 0, "readyMark": "invokeai:ready:widget:center:canvas", @@ -180,15 +180,15 @@ "resourceBaseline": { "cssRawBytes": 2159, "fontRawBytes": 23664, - "imageRawBytes": 156376, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "imageRawBytes": 44398, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 98, - "scriptRawBytes": 4407950, + "scriptRawBytes": 4415450, "scriptRequestCount": 93, - "totalRawBytes": 4774680 + "totalRawBytes": 4671426 }, - "routeReadyMedianMs": 1163.800000000745, + "routeReadyMedianMs": 1157.2999999970198, "scriptSourceOwnerSet": "editor-canvas-static", "stateProfile": "empty" }, @@ -197,20 +197,20 @@ "cssRawBytes": 0, "fontRawBytes": 0, "imageRawBytes": 0, - "largestAssetRawBytes": 310063, + "largestAssetRawBytes": 310062, "otherRawBytes": 0, "requestCount": 9, - "scriptRawBytes": 507630, + "scriptRawBytes": 507632, "scriptRequestCount": 9, - "totalRawBytes": 507630 + "totalRawBytes": 507632 }, - "domContentLoadedMedianMs": 129.79999999701977, + "domContentLoadedMedianMs": 128.60000000149012, "id": "editor-canvas", - "layoutAckMedianMs": 2.300000000745058, - "layoutReturnSwitchMedianMs": 52.5, - "layoutSwitchMedianMs": 88, - "loadMedianMs": 129.89999999850988, - "longestTaskMaxMs": 199, + "layoutAckMedianMs": 2.599999997764826, + "layoutReturnSwitchMedianMs": 43.70000000298023, + "layoutSwitchMedianMs": 85.80000000074506, + "loadMedianMs": 128.69999999925494, + "longestTaskMaxMs": 203, "owner": "canvas", "projectSwitchMedianMs": 0, "readyMark": "invokeai:ready:widget:center:canvas", @@ -218,15 +218,15 @@ "resourceBaseline": { "cssRawBytes": 2159, "fontRawBytes": 23664, - "imageRawBytes": 156376, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "imageRawBytes": 44398, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 98, - "scriptRawBytes": 4407950, + "scriptRawBytes": 4415450, "scriptRequestCount": 93, - "totalRawBytes": 4774680 + "totalRawBytes": 4671426 }, - "routeReadyMedianMs": 1132.9000000022352, + "routeReadyMedianMs": 1128.199999999255, "scriptSourceOwnerSet": "editor-canvas-static", "stateProfile": "representative" }, @@ -235,20 +235,20 @@ "cssRawBytes": 15413, "fontRawBytes": 0, "imageRawBytes": 0, - "largestAssetRawBytes": 181637, + "largestAssetRawBytes": 181629, "otherRawBytes": 0, "requestCount": 7, - "scriptRawBytes": 415221, + "scriptRawBytes": 415216, "scriptRequestCount": 6, - "totalRawBytes": 430634 + "totalRawBytes": 430629 }, - "domContentLoadedMedianMs": 126.40000000223517, + "domContentLoadedMedianMs": 128.30000000074506, "id": "editor-workflow", - "layoutAckMedianMs": 2.5, - "layoutReturnSwitchMedianMs": 34.100000001490116, - "layoutSwitchMedianMs": 92.19999999925494, - "loadMedianMs": 126.5, - "longestTaskMaxMs": 167, + "layoutAckMedianMs": 2.400000002235174, + "layoutReturnSwitchMedianMs": 35.399999998509884, + "layoutSwitchMedianMs": 97.70000000298023, + "loadMedianMs": 128.40000000223517, + "longestTaskMaxMs": 160, "owner": "workflow", "projectSwitchMedianMs": 0, "readyMark": "invokeai:ready:widget:center:workflow", @@ -256,15 +256,15 @@ "resourceBaseline": { "cssRawBytes": 17572, "fontRawBytes": 23664, - "imageRawBytes": 156376, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "imageRawBytes": 44398, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 96, - "scriptRawBytes": 4315541, + "scriptRawBytes": 4323034, "scriptRequestCount": 90, - "totalRawBytes": 4697684 + "totalRawBytes": 4594423 }, - "routeReadyMedianMs": 1172.300000000745, + "routeReadyMedianMs": 1174.5, "scriptSourceOwnerSet": "editor-workflow-static", "stateProfile": "empty" }, @@ -273,20 +273,20 @@ "cssRawBytes": 15413, "fontRawBytes": 0, "imageRawBytes": 0, - "largestAssetRawBytes": 181637, + "largestAssetRawBytes": 181629, "otherRawBytes": 0, "requestCount": 7, - "scriptRawBytes": 415221, + "scriptRawBytes": 415216, "scriptRequestCount": 6, - "totalRawBytes": 430634 + "totalRawBytes": 430629 }, - "domContentLoadedMedianMs": 126.80000000074506, + "domContentLoadedMedianMs": 132.90000000223517, "id": "editor-workflow", - "layoutAckMedianMs": 2.699999999254942, - "layoutReturnSwitchMedianMs": 43.80000000074506, - "layoutSwitchMedianMs": 162.80000000074506, - "loadMedianMs": 126.89999999850988, - "longestTaskMaxMs": 435, + "layoutAckMedianMs": 2.400000002235174, + "layoutReturnSwitchMedianMs": 45.5, + "layoutSwitchMedianMs": 157.80000000074506, + "loadMedianMs": 133, + "longestTaskMaxMs": 428, "owner": "workflow", "projectSwitchMedianMs": 0, "readyMark": "invokeai:ready:widget:center:workflow", @@ -294,15 +294,15 @@ "resourceBaseline": { "cssRawBytes": 17572, "fontRawBytes": 23664, - "imageRawBytes": 156376, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "imageRawBytes": 44398, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 96, - "scriptRawBytes": 4315541, + "scriptRawBytes": 4323034, "scriptRequestCount": 90, - "totalRawBytes": 4697684 + "totalRawBytes": 4594423 }, - "routeReadyMedianMs": 1196.7000000029802, + "routeReadyMedianMs": 1201.0999999977648, "scriptSourceOwnerSet": "editor-workflow-static", "stateProfile": "representative" }, @@ -318,13 +318,13 @@ "scriptRequestCount": 0, "totalRawBytes": 0 }, - "domContentLoadedMedianMs": 132.69999999925494, + "domContentLoadedMedianMs": 127.19999999925494, "id": "editor-gallery", "layoutAckMedianMs": 0, "layoutReturnSwitchMedianMs": 0, - "layoutSwitchMedianMs": 35.80000000074506, - "loadMedianMs": 132.80000000074506, - "longestTaskMaxMs": 174, + "layoutSwitchMedianMs": 36.100000001490116, + "loadMedianMs": 127.39999999850988, + "longestTaskMaxMs": 169, "owner": "gallery", "projectSwitchMedianMs": 0, "readyMark": "invokeai:ready:widget:center:gallery", @@ -332,15 +332,15 @@ "resourceBaseline": { "cssRawBytes": 2159, "fontRawBytes": 23664, - "imageRawBytes": 156376, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "imageRawBytes": 44398, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 89, - "scriptRawBytes": 3900320, + "scriptRawBytes": 3907818, "scriptRequestCount": 84, - "totalRawBytes": 4267050 + "totalRawBytes": 4163794 }, - "routeReadyMedianMs": 1390.300000000745, + "routeReadyMedianMs": 1376.300000000745, "scriptSourceOwnerSet": "editor-minimal-static", "stateProfile": "empty" }, @@ -356,13 +356,13 @@ "scriptRequestCount": 0, "totalRawBytes": 0 }, - "domContentLoadedMedianMs": 128.80000000074506, + "domContentLoadedMedianMs": 127.69999999925494, "id": "editor-gallery", "layoutAckMedianMs": 0, "layoutReturnSwitchMedianMs": 0, - "layoutSwitchMedianMs": 46.69999999925494, - "loadMedianMs": 129, - "longestTaskMaxMs": 159, + "layoutSwitchMedianMs": 44.79999999701977, + "loadMedianMs": 127.79999999701977, + "longestTaskMaxMs": 163, "owner": "gallery", "projectSwitchMedianMs": 0, "readyMark": "invokeai:ready:widget:center:gallery", @@ -370,15 +370,15 @@ "resourceBaseline": { "cssRawBytes": 2159, "fontRawBytes": 23664, - "imageRawBytes": 156376, - "largestAssetRawBytes": 749035, - "otherRawBytes": 184531, + "imageRawBytes": 44398, + "largestAssetRawBytes": 749225, + "otherRawBytes": 185755, "requestCount": 89, - "scriptRawBytes": 3900320, + "scriptRawBytes": 3907818, "scriptRequestCount": 84, - "totalRawBytes": 4267050 + "totalRawBytes": 4163794 }, - "routeReadyMedianMs": 1363.699999999255, + "routeReadyMedianMs": 1351.3999999985099, "scriptSourceOwnerSet": "editor-minimal-static", "stateProfile": "representative" } @@ -608,6 +608,7 @@ "source:src/platform/react/useMountEffect.ts", "source:src/platform/react/usePreservedScrollOffset.ts", "source:src/platform/react/useZodForm.ts", + "source:src/platform/runtime/appMetadata.ts", "source:src/platform/search/dateTokens.ts", "source:src/platform/state/accountLifecycle.ts", "source:src/platform/state/externalStore.ts", @@ -737,7 +738,9 @@ "source:src/workbench/settings/launchpad.tsx", "source:src/workbench/settings/settingsDialogStore.ts", "source:src/workbench/settings/settingsSearchShortcut.ts", - "source:src/workbench/settings/store.ts" + "source:src/workbench/settings/store.ts", + "source:src/workbench/shell/useWhatsNew.ts", + "source:src/workbench/shell/whatsNewStore.ts" ], "editor-minimal-static": [ "package:@ark-ui/react", @@ -1252,6 +1255,7 @@ "source:src/platform/react/useMountEffect.ts", "source:src/platform/react/usePreservedScrollOffset.ts", "source:src/platform/react/useZodForm.ts", + "source:src/platform/runtime/appMetadata.ts", "source:src/platform/search/dateTokens.ts", "source:src/platform/state/accountLifecycle.ts", "source:src/platform/state/compareAndSwapRollback.ts", @@ -1703,6 +1707,8 @@ "source:src/workbench/shell/topbar/useLayoutDrift.ts", "source:src/workbench/shell/topbar/useTopbarShortcut.ts", "source:src/workbench/shell/useMountedInstanceIds.ts", + "source:src/workbench/shell/useWhatsNew.ts", + "source:src/workbench/shell/whatsNewStore.ts", "source:src/workbench/useNotify.ts", "source:src/workbench/useOpenWorkbenchWidget.ts", "source:src/workbench/widget-frame/FloatingWidgetLayer.tsx", @@ -2323,6 +2329,7 @@ "source:src/platform/react/useMountEffect.ts", "source:src/platform/react/usePreservedScrollOffset.ts", "source:src/platform/react/useZodForm.ts", + "source:src/platform/runtime/appMetadata.ts", "source:src/platform/search/dateTokens.ts", "source:src/platform/state/accountLifecycle.ts", "source:src/platform/state/compareAndSwapRollback.ts", @@ -2785,6 +2792,8 @@ "source:src/workbench/shell/topbar/useLayoutDrift.ts", "source:src/workbench/shell/topbar/useTopbarShortcut.ts", "source:src/workbench/shell/useMountedInstanceIds.ts", + "source:src/workbench/shell/useWhatsNew.ts", + "source:src/workbench/shell/whatsNewStore.ts", "source:src/workbench/useCanvasProjectMutationDispatch.ts", "source:src/workbench/useNotify.ts", "source:src/workbench/useOpenWorkbenchWidget.ts", @@ -3613,6 +3622,7 @@ "source:src/platform/react/useMountEffect.ts", "source:src/platform/react/usePreservedScrollOffset.ts", "source:src/platform/react/useZodForm.ts", + "source:src/platform/runtime/appMetadata.ts", "source:src/platform/search/dateTokens.ts", "source:src/platform/state/accountLifecycle.ts", "source:src/platform/state/compareAndSwapRollback.ts", @@ -4064,6 +4074,8 @@ "source:src/workbench/shell/topbar/useLayoutDrift.ts", "source:src/workbench/shell/topbar/useTopbarShortcut.ts", "source:src/workbench/shell/useMountedInstanceIds.ts", + "source:src/workbench/shell/useWhatsNew.ts", + "source:src/workbench/shell/whatsNewStore.ts", "source:src/workbench/useNotify.ts", "source:src/workbench/useOpenWorkbenchWidget.ts", "source:src/workbench/widget-frame/FloatingWidgetLayer.tsx",