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:
@@ -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`
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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}\``);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user