FN-6493: update lazy view inventory guard

Keep the lazy-loaded dashboard inventory aligned with AppModals imports.\n\n- Document SettingsModal and WorkflowNodeEditor alongside other lazy-loaded dashboard views.\n- Update the dashboard guide inventory count and modal lazy-load note.\n- Extend the docs guard test to scan AppModals lazy imports and assert the 22-view inventory.\n\nFiles changed:\n AGENTS.md                                          |  6 ++--\n docs/dashboard-guide.md                            |  5 ++-\n .../app/__tests__/lazy-loaded-views-docs.test.ts   | 40 +++++++++++++++++++---\n 3 files changed, 43 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-6493

Fusion-Task-Lineage: d2b4de05-fb3c-4965-921e-4f8551e3e96a
This commit is contained in:
gsxdsm
2026-06-16 18:22:28 -07:00
parent 802fecb245
commit 7852c34a9f
3 changed files with 43 additions and 8 deletions

View File

@@ -215,8 +215,8 @@ Scoped exception (FN-5819): shared-branch-group members (`branchContext.assignme
### Lazy-Loaded Heavy Views
These 20 views are lazy-loaded via `React.lazy()` with `<Suspense fallback={null}>`.
Keep this AGENTS inventory in sync with App lazy imports and `packages/dashboard/app/__tests__/lazy-loaded-views-docs.test.ts`.
These 22 views are lazy-loaded via `React.lazy()` with `<Suspense fallback={null}>`.
Keep this AGENTS inventory in sync with App lazy imports, AppModals lazy modal imports (`SettingsModal`, `WorkflowNodeEditor`, `SetupWizardModal`), and `packages/dashboard/app/__tests__/lazy-loaded-views-docs.test.ts`.
- `AgentsView`
- `NodesView`
@@ -235,6 +235,8 @@ Keep this AGENTS inventory in sync with App lazy imports and `packages/dashboard
- `StashRecoveryView`
- `PullRequestView`
- `SetupWizardModal`
- `SettingsModal`
- `WorkflowNodeEditor`
- `PluginManager`
- `PiExtensionsManager`
- `AgentDetailView`

View File

@@ -1232,7 +1232,7 @@ Manage project and global secrets directly inside **Settings → Project → Sec
### Lazy-Loaded Heavy Views
These 19 views are lazy-loaded via `React.lazy()` with `<Suspense fallback={null}>`. `prefetchLazyViews()` warms chunks once on mount via `requestIdleCallback`. **Do not make these eager.**
These 22 views are lazy-loaded via `React.lazy()` with `<Suspense fallback={null}>`. `prefetchLazyViews()` warms App-level chunks once on mount via `requestIdleCallback`; AppModals lazy modal imports (`SettingsModal`, `WorkflowNodeEditor`, `SetupWizardModal`) are part of the same inventory. **Do not make these eager.**
- `AgentsView`
- `NodesView`
@@ -1249,7 +1249,10 @@ These 19 views are lazy-loaded via `React.lazy()` with `<Suspense fallback={null
- `TodoView`
- `GoalsView`
- `StashRecoveryView`
- `PullRequestView`
- `SetupWizardModal`
- `SettingsModal`
- `WorkflowNodeEditor`
- `PluginManager`
- `PiExtensionsManager`
- `AgentDetailView`

View File

@@ -20,6 +20,8 @@ const EXPECTED_DOCUMENTED_VIEWS = new Set([
"StashRecoveryView",
"PullRequestView",
"SetupWizardModal",
"SettingsModal",
"WorkflowNodeEditor",
"PluginManager",
"PiExtensionsManager",
"AgentDetailView",
@@ -44,6 +46,16 @@ const EXPECTED_APP_LEVEL_VIEWS = new Set([
"PullRequestView",
]);
/*
* FNXC:DashboardLazyViews 2026-06-16-17:40:
* AppModals lazy-loads top-level heavy modals outside App.tsx, so the docs guard must scan that source site too; otherwise SettingsModal and WorkflowNodeEditor can drift out of the canonical inventory while tests stay green.
*/
const EXPECTED_APP_MODALS_LAZY_VIEWS = new Set([
"SetupWizardModal",
"SettingsModal",
"WorkflowNodeEditor",
]);
function extractLazyLoadedSection(agentsDoc: string): string {
const match = agentsDoc.match(/### Lazy-Loaded Heavy Views[\s\S]*?(?=\n### |\n---|$)/);
if (!match) {
@@ -59,9 +71,12 @@ function extractBacktickedNamesFromBullets(section: string): string[] {
.flatMap((line) => [...line.matchAll(/`([^`]+)`/g)].map((m) => m[1]));
}
function extractConstLazyViews(source: string): string[] {
return [...source.matchAll(/const\s+(\w+)\s*=\s*lazy\(/g)].map((m) => m[1]);
}
function extractAppLazyViews(appSource: string): Set<string> {
const matches = [...appSource.matchAll(/const\s+(\w+)\s*=\s*lazy\(/g)].map((m) => m[1]);
const normalized = matches
const normalized = extractConstLazyViews(appSource)
.map((name) => {
if (name === "_TodoView") {
return "TodoView";
@@ -75,22 +90,29 @@ function extractAppLazyViews(appSource: string): Set<string> {
return new Set(normalized);
}
function extractAppModalsLazyViews(appModalsSource: string): Set<string> {
return new Set(extractConstLazyViews(appModalsSource));
}
describe("AGENTS lazy-loaded views inventory", () => {
it("documents the App-level lazy views accurately and keeps the curated 20-view list in sync", () => {
it("documents the App-level and AppModals lazy views accurately and keeps the curated 22-view list in sync", () => {
const agentsDoc = readFileSync(resolve(__dirname, "../../../../AGENTS.md"), "utf-8");
const appSource = readFileSync(resolve(__dirname, "../App.tsx"), "utf-8");
const appModalsSource = readFileSync(resolve(__dirname, "../components/AppModals.tsx"), "utf-8");
const section = extractLazyLoadedSection(agentsDoc);
const countMatch = section.match(/These\s+(\d+)\s+views\s+are lazy-loaded/);
expect(countMatch).toBeTruthy();
expect(Number(countMatch?.[1])).toBe(20);
expect(Number(countMatch?.[1])).toBe(22);
const documentedViews = extractBacktickedNamesFromBullets(section);
expect(new Set(documentedViews)).toEqual(EXPECTED_DOCUMENTED_VIEWS);
expect(documentedViews).toHaveLength(20);
expect(documentedViews).toHaveLength(22);
expect(section).toContain("`ResearchView`");
expect(section).toContain("`TodoView`");
expect(section).toContain("`SettingsModal`");
expect(section).toContain("`WorkflowNodeEditor`");
expect((section.match(/`AgentDetailView`/g) ?? []).length).toBe(1);
const appLevelViews = extractAppLazyViews(appSource);
@@ -99,5 +121,13 @@ describe("AGENTS lazy-loaded views inventory", () => {
for (const view of appLevelViews) {
expect(EXPECTED_DOCUMENTED_VIEWS.has(view)).toBe(true);
}
const appModalsLazyViews = extractAppModalsLazyViews(appModalsSource);
expect(appModalsLazyViews).toEqual(EXPECTED_APP_MODALS_LAZY_VIEWS);
for (const view of appModalsLazyViews) {
expect(EXPECTED_DOCUMENTED_VIEWS.has(view)).toBe(true);
expect(section).toContain(`\`${view}\``);
}
});
});