Skip to content

Commit b59ab24

Browse files
refactor: code clean
1 parent df42b69 commit b59ab24

46 files changed

Lines changed: 364 additions & 2300 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/wiki-graph/README.md

Lines changed: 46 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,68 @@
1-
# Wiki Visualizer App (`apps/wiki-graph`)
1+
# Wiki Graph (`apps/wiki-graph`)
22

3-
`wiki-graph` is the interactive web visualizer application for the LLM Wiki Knowledge Monorepo. Built as a standalone Angular application with a D3 force-directed rendering engine, it provides topological graph exploration, search, multi-criteria filtering, and detailed metadata inspection for interlinked markdown documents (`entities`, `concepts`, and `sources`).
3+
An interactive 2D learning graph visualizer and AI-driven knowledge assessment application built with Angular, D3.js force-directed physics, and Signal-based reactive state.
44

55
---
66

7-
## Architectural Role
7+
## 🏛️ Architectural Role & Visual Flow
88

9-
`wiki-graph` serves as the **Interactive Presentation & Exploration Layer** of the monorepo architecture:
9+
`apps/wiki-graph` serves as the primary visual interface for exploring, assessing, and tracking mastery across concepts in the knowledge wiki. It uses a clean Smart-Container-UI architecture separation to isolate state management from visual rendering.
1010

1111
```text
12-
┌────────────────────────────────────────────────────────────────────────┐
13-
│ apps/wiki-graph │
14-
│ - src/main.ts / app.routes.ts │
15-
│ │
16-
│ ┌──────────────────────────────────────────────────────────────────┐ │
17-
│ │ Smart Components │ │
18-
│ │ - WikiGraphPageComponent (Route Orchestrator) │ │
19-
│ └──────────────────────────────┬───────────────────────────────────┘ │
20-
│ │ Injects & Binds State │
21-
│ ▼ │
22-
│ ┌──────────────────────────────────────────────────────────────────┐ │
23-
│ │ Reactive State & Data Layer │ │
24-
│ │ - GraphStateService (Angular Signals state & filtering) │ │
25-
│ │ - WikiParserService (Manifest & Markdown Parsing) │ │
26-
│ └──────────────┬───────────────────────────────┬───────────────────┘ │
27-
│ │ │ │
28-
│ ▼ Binds Data ▼ Fetches Static Assets│
29-
│ ┌──────────────────────────────┐ ┌─────────────────────────────────┐ │
30-
│ │ Containers & UI │ │ Static Assets / Build │ │
31-
│ │ - Viewport Container │ │ - wiki/manifest.json │ │
32-
│ │ - Canvas / Toolbar / Detail │ │ - wiki/**/*.md │ │
33-
│ └──────────────┬───────────────┘ └─────────────────────────────────┘ │
34-
│ │ Renders SVG DOM │
35-
│ ▼ │
36-
│ ┌──────────────────────────────┐ │
37-
│ │ D3 Force Engine │ │
38-
│ │ - D3ForceRenderer │ │
39-
│ │ - Force Simulation & SVG │ │
40-
│ └──────────────────────────────┘ │
41-
└────────────────────────────────────────────────────────────────────────┘
42-
```
43-
44-
- **Clean Component Hierarchy**: Enforces a strict 3-tier architecture: presentational UI components (`components/ui/`), layout container components (`components/containers/`), and service-injecting smart page components (`components/smart/`).
45-
- **Reactive Signal-Driven State**: All application state (node selection, type/tag filters, search query, visible node subsets, hub and orphan nodes) is managed reactively via Angular Signals in `GraphStateService`.
46-
- **Decoupled Physics Engine**: Graph layout simulation, DOM rendering, zoom/pan behaviors, and visual highlight state are encapsulated within a dedicated D3 rendering engine (`d3/`).
47-
48-
---
49-
50-
## Key Capabilities & Features
51-
52-
- **Topological Force-Directed Layout**: Physics-based D3 simulation with collision avoidance, link strength repulsion, dynamic node radii based on connection degree, and smooth drag-and-drop node positioning.
53-
- **Visual Encoding & Type System**:
54-
- Color-coded node classifications: `entity` (orange), `concept` (cyan), and `source` (green).
55-
- Ghost nodes rendered with dashed borders for referenced but uncreated `[[wikilink]]` pages.
56-
- Directed edge arrows pointing from source documents to reference targets.
57-
- **Search & Multi-criteria Filtering**:
58-
- Real-time title search matching.
59-
- Multi-select node type toggles (`entity`, `concept`, `source`).
60-
- Tag filter selector for fine-grained category isolation.
61-
- One-click filters for top connected **hub nodes** and isolated **orphan pages** (degree 0).
62-
- **Navigation & Detail Panel Overlay**:
63-
- Smooth viewport zoom (0.1x to 8x) and canvas panning controls.
64-
- Slide-over detail panel displaying frontmatter attributes, degree metrics, direct link connections, and raw markdown preview.
65-
- **Accessibility & UX**:
66-
- Full keyboard selection support (`Enter` / `Space` to inspect nodes, `Esc` to dismiss detail panel).
67-
- ARIA element attributes for screen readers.
68-
- Visual loading states and error banner handling.
69-
70-
---
71-
72-
## Directory Structure
73-
74-
```text
75-
apps/wiki-graph/
76-
├── project.json # Nx project configuration & target definitions
77-
├── eslint.config.mjs # ESLint rules configuration
78-
├── tsconfig.json # TypeScript base configuration
79-
├── tsconfig.app.json # Application-specific TS configuration
80-
├── tsconfig.spec.json # Unit test TS configuration
81-
├── README.md # Main application documentation
82-
├── public/ # Static public web assets
83-
└── src/
84-
├── index.html # Main HTML entry document
85-
├── main.ts # Application bootstrap entry point
86-
├── styles.scss # Global application styles & design tokens
87-
└── app/
88-
├── app.config.ts # Standalone app providers & router setup
89-
├── app.routes.ts # Application route definitions
90-
├── app.ts # Root component container
91-
├── README.md # App architecture documentation
92-
├── components/ # Standalone component hierarchy
93-
│ ├── ui/ # Presentational components (Inputs & Outputs ONLY)
94-
│ ├── containers/ # Layout composition & wrapper containers
95-
│ └── smart/ # State-aware page components
96-
├── d3/ # D3 force-directed simulation & SVG renderer
97-
├── models/ # Graph domain & manifest TypeScript models
98-
└── services/ # Parser service & reactive signal state management
12+
+-----------------------------------------------------------------------+
13+
| Wiki Graph Application |
14+
+-----------------------------------------------------------------------+
15+
| Smart Tier (WikiGraphSmartComponent) |
16+
| ├── Injects GraphStateService, AssessmentService, ProgressStateStore |
17+
| └── Coordinates State Signals, Assessment Dialogs & Storage Sync |
18+
+-----------------------------------------------------------------------+
19+
| Container Tier (GraphViewportContainerComponent) |
20+
| ├── Header Toolbar (GraphToolbarUiComponent) |
21+
| ├── Visual Graph Canvas (GraphCanvasComponent -> D3 Renderer Engine) |
22+
| ├── Node Inspector (NodeDetailUiComponent) |
23+
| ├── Progress Dashboard (ProgressDashboardUiComponent) |
24+
| └── Knowledge Assessment Modal (AssessmentDialogUiComponent) |
25+
+-----------------------------------------------------------------------+
9926
```
10027

10128
---
10229

103-
## Core Modules & Engine Subsystems
30+
## 💡 Key Capabilities & UX Features
10431

105-
### 1. Component Architecture ([`./src/app/components/`](./src/app/components/README.md))
32+
- **Interactive Force-Directed Graph Visualization**
33+
- D3.js force simulation rendering concept nodes, dependencies, and structural relationships
34+
- Smooth pan/zoom controls, node highlight focus, and dynamic filters by domain status and tags
10635

107-
- **UI Tier (`components/ui/`)**: Pure presentation components receiving data strictly via `input()` signals and emitting actions via `output()` events. Includes `GraphCanvasComponent`, `GraphToolbarUiComponent`, and `NodeDetailUiComponent`.
108-
- **Container Tier (`components/containers/`)**: Structural wrapper components like `GraphViewportContainerComponent` composing layout grids, overlays, and canvas wrappers.
109-
- **Smart Tier (`components/smart/`)**: Page-level orchestrator components like `WikiGraphPageComponent` injecting state services and binding signals to template containers.
36+
- **AI-Driven Knowledge Assessment Sessions**
37+
- Presentational dialog workflow for step-by-step concept evaluations
38+
- Real-time scoring advancing learner progress from *Not Started* through *In Progress*, *Understood*, to *Mastered*
11039

111-
### 2. D3 Renderer Engine ([`./src/app/d3/`](./src/app/d3/README.md))
40+
- **Progress Dashboard & Accessibility**
41+
- Domain coverage breakdown, completion metrics, and category stats
42+
- Screen reader announcements for state updates via dedicated ARIA live regions
11243

113-
- **`D3ForceRenderer`**: Coordinates graph rendering, simulation ticks, zoom/pan behaviors, and drag interactions.
114-
- **`force-simulation.ts`**: Configures force charge, link distance, and collision forces.
115-
- **`graph-svg.ts`**: Handles SVG element creation, node circles, edge path markers, and text labels.
116-
- **`graph-state.ts`**: Manages node selection focus, highlight links, and dimmed background states.
117-
118-
### 3. Data & State Services ([`./src/app/services/`](./src/app/services/README.md))
119-
120-
- **`WikiParserService`**: Asynchronously fetches `wiki/manifest.json` and referenced markdown files, parses frontmatter and `[[wikilink]]` syntax, and transforms content into renderable `GraphData`.
121-
- **`GraphStateService`**: Centralized Signal store managing reactive state properties (`graphData`, `selectedNode`, `activeTypeFilters`, `searchQuery`, `activeTagFilter`, `visibleNodes`, `hubNodes`, `orphanNodes`).
122-
123-
### 4. Domain Models ([`./src/app/models/`](./src/app/models/README.md))
124-
125-
- TypeScript interfaces and types for `NodeType`, `GraphNode`, `GraphEdge`, `GraphData`, `SimulationNode`, and `WikiManifest`.
44+
- **Resilient Persistence & Storage Adapters**
45+
- Persistent state backup supporting File System Access API with local storage fallbacks
12646

12747
---
12848

129-
## Build, Serve & Test Commands
130-
131-
Commands are executed via Nx targets from the monorepo root:
49+
## 📁 Subsystem & Module Map
13250

133-
| Nx Target | Purpose | Command |
134-
| -------------- | ---------------------------------------------------------------- | ------------------------------------ |
135-
| `serve` | Starts local development server with live reloading | `npx nx run wiki-graph:serve` |
136-
| `build` | Compiles production application bundle to `dist/apps/wiki-graph` | `npx nx run wiki-graph:build` |
137-
| `test` | Executes unit test suite | `npx nx run wiki-graph:test` |
138-
| `lint` | Runs ESLint analysis across the application codebase | `npx nx run wiki-graph:lint` |
139-
| `serve-static` | Serves compiled production build locally on port 4200 | `npx nx run wiki-graph:serve-static` |
51+
| Subsystem | Folder | Responsibility |
52+
| --- | --- | --- |
53+
| **Containers** | [`./src/app/components/containers/`](./src/app/components/containers/) | Layout composition and presentational wrappers |
54+
| **Smart Components** | [`./src/app/components/smart/`](./src/app/components/smart/) | Service injection, signal binding, and reactive state orchestration |
55+
| **UI Components** | [`./src/app/components/ui/`](./src/app/components/ui/) | Pure presentational components receiving `input()` and emitting `output()` |
56+
| **D3 Simulation Engine** | [`./src/app/d3/`](./src/app/d3/) | Force simulation physics, SVG DOM manipulation, and style encodings |
57+
| **Domain Models** | [`./src/app/models/`](./src/app/models/) | Domain entities, Zod validation schemas, and constants |
58+
| **Services & State** | [`./src/app/services/`](./src/app/services/) | Assessment workflow, graph state stores, and persistence adapters |
14059

141-
### Development Workflow
142-
143-
1. Generate or update wiki manifest using `wiki-cli`:
144-
145-
```bash
146-
npx nx run wiki-cli:generate-manifest
147-
```
148-
149-
2. Start local `wiki-graph` development server:
60+
---
15061

151-
```bash
152-
npx nx run wiki-graph:serve
153-
```
62+
## 🚀 Build, Run & Test Targets
15463

155-
3. Open your browser and navigate to `http://localhost:4200/`.
64+
| Target | Command | Purpose |
65+
| --- | --- | --- |
66+
| `serve` | `npx nx run wiki-graph:serve` | Starts local dev server with live reload |
67+
| `build` | `npx nx run wiki-graph:build` | Compiles production application bundle |
68+
| `test` | `npx nx run wiki-graph:test` | Executes complete unit test suite |

apps/wiki-graph/src/app/app.spec.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@ import { RouterModule } from '@angular/router';
55
import { StorageService } from './services/storage.service';
66
import { ProgressStateService } from './services/progress-state.service';
77

8-
/**
9-
* ngOnInit fires off initialization as a detached promise chain
10-
* (`void this.initializeProgressTracking()`), which isn't tracked by
11-
* Angular's zoneless change detection scheduler. `fixture.whenStable()`
12-
* alone can resolve before that chain's microtasks finish, so tests flush
13-
* the microtask queue explicitly before asserting on its result.
14-
*/
158
function flushMicrotasks(): Promise<void> {
169
return new Promise((resolve) => setTimeout(resolve, 0));
1710
}
@@ -99,7 +92,6 @@ describe('App', () => {
9992

10093
expect(fixture.componentInstance['progressInitError']()).toContain('Grant Access');
10194

102-
// Second attempt succeeds
10395
vi.mocked(storageServiceMock.initialize).mockResolvedValueOnce(undefined);
10496
await fixture.componentInstance['initializeProgressTracking']();
10597

apps/wiki-graph/src/app/app.ts

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,54 +2,30 @@ import { Component, OnInit, inject, signal } from '@angular/core';
22
import { RouterModule } from '@angular/router';
33
import { ProgressStateService } from './services/progress-state.service';
44
import { StorageService } from './services/storage.service';
5-
// AssessmentService requires no startup initialization (mock, no file/storage
6-
// dependency), but is provided in root via `@Injectable({ providedIn: 'root' })`
7-
// alongside ProgressStateService and StorageService below.
85

9-
/**
10-
* Root application component.
11-
*
12-
* Owns startup initialization of progress tracking: requests access to the
13-
* workspace directory via StorageService and loads persisted progress via
14-
* ProgressStateService. Both services are `providedIn: 'root'`, making them
15-
* available application-wide as singletons.
16-
*
17-
* Requirements: 2.1, 2.2
18-
*/
196
@Component({
207
imports: [RouterModule],
218
selector: 'app-root',
229
templateUrl: './app.html',
2310
styleUrl: './app.scss',
2411
})
2512
export class App implements OnInit {
26-
protected title = 'wiki-graph';
13+
private title = 'wiki-graph';
2714

2815
private readonly storageService = inject(StorageService);
2916
private readonly progressStateService = inject(ProgressStateService);
3017

31-
/** True while the initial workspace connection + progress load is running. */
3218
protected readonly initializingProgress = signal(false);
33-
/** True once the workspace has been connected and progress loaded successfully. */
34-
protected readonly progressReady = signal(false);
35-
/** User-friendly message describing why progress tracking is unavailable, or null. */
19+
20+
private readonly progressReady = signal(false);
21+
3622
protected readonly progressInitError = signal<string | null>(null);
3723

3824
ngOnInit(): void {
39-
// Attempt automatic initialization on startup. Browsers require a user
40-
// gesture to show the directory picker, so this first attempt will
41-
// typically fail with a permission/security error; the resulting banner
42-
// lets the user retry via a button click, which satisfies that
43-
// requirement.
25+
4426
void this.initializeProgressTracking();
4527
}
4628

47-
/**
48-
* Requests workspace directory access and loads progress from disk.
49-
* Safe to call multiple times (e.g. via a "Grant Access" retry button).
50-
*
51-
* Requirements: 2.1, 2.2
52-
*/
5329
protected async initializeProgressTracking(): Promise<void> {
5430
this.initializingProgress.set(true);
5531
this.progressInitError.set(null);
@@ -67,11 +43,6 @@ export class App implements OnInit {
6743
}
6844
}
6945

70-
/**
71-
* Translates raw StorageService/ProgressStateService error messages into
72-
* user-friendly guidance, per the error handling scenarios in the design
73-
* (missing directory, permission denied, unsupported browser).
74-
*/
7546
private toUserFriendlyMessage(message: string): string {
7647
if (message.includes('not supported')) {
7748
return 'Progress tracking requires a browser that supports the File System Access API (e.g. Chrome or Edge). Progress tracking is disabled.';

apps/wiki-graph/src/app/components/containers/graph-viewport-container/graph-viewport-container.component.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,12 @@ export class GraphViewportContainerComponent {
3030
isLoading = input<boolean>(false);
3131
error = input<string | null>(null);
3232

33-
/** Active visualization mode, forwarded to the graph canvas for node coloring. */
3433
visualizationMode = input<VisualizationMode>('wiki');
35-
/** Lookup of concept ID to current progress state, forwarded to the graph canvas. */
34+
3635
progressStates = input<ReadonlyMap<string, ProgressState>>(new Map());
37-
/** Active progress state filters, forwarded to the graph canvas for node visibility. */
36+
3837
activeProgressFilters = input<ProgressState[]>([]);
39-
/** Progress state + assessment count for the selected node, forwarded to the detail panel. */
38+
4039
selectedNodeProgress = input<{ state: ProgressState; assessmentCount: number } | null>(null);
4140

4241
nodeSelected = output<string | null>();
@@ -48,8 +47,8 @@ export class GraphViewportContainerComponent {
4847
refreshRequested = output<void>();
4948
toolbarVisibilityToggled = output<boolean>();
5049
detailClosed = output<void>();
51-
/** Emitted when the learner requests a knowledge assessment for a node. */
50+
5251
assessmentRequested = output<string>();
53-
/** Emitted when the learner toggles between wiki structure and progress views. */
52+
5453
visualizationModeChanged = output<VisualizationMode>();
5554
}

0 commit comments

Comments
 (0)