Skip to content

Commit e97650c

Browse files
committed
spec: add tasks
1 parent 326903f commit e97650c

File tree

1 file changed

+287
-0
lines changed

1 file changed

+287
-0
lines changed
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# Tasks: SPARQL CONSTRUCT Graph Visualization
2+
3+
**Feature**: `001-construct-graph-viz`
4+
**Branch**: `001-construct-graph-viz`
5+
**Input**: Design documents from `/specs/001-construct-graph-viz/`
6+
7+
**Tests**: Tests are NOT explicitly requested in the specification. Manual browser testing per constitution principle IV.
8+
9+
**Organization**: Tasks are grouped by user story (P1-P5) to enable independent implementation and testing of each story.
10+
11+
## Format: `- [ ] [ID] [P?] [Story?] Description`
12+
13+
- **[P]**: Can run in parallel (different files, no dependencies)
14+
- **[Story]**: User story label (US1, US2, etc.) - included for user story phases only
15+
- All paths are absolute from repository root
16+
17+
## Phase 1: Setup (Shared Infrastructure)
18+
19+
**Purpose**: Project initialization and build configuration
20+
21+
- [ ] T001 Initialize package.json with dependencies: vis-network ^9.1.9, @zazuko/yasgui ^4.x (peerDependency), esbuild (devDependency)
22+
- [ ] T002 [P] Create .eslintrc.js with ES2018+ rules for code quality validation
23+
- [ ] T003 [P] Create .prettierrc with formatting rules (2-space indent, single quotes, no trailing commas)
24+
- [ ] T004 Create esbuild.config.js to bundle src/index.js → dist/yasgui-graph-plugin.min.js (UMD format, global `GraphPlugin`)
25+
- [ ] T005 [P] Create src/ directory structure: GraphPlugin.js, parsers.js, transformers.js, prefixUtils.js, colorUtils.js, networkConfig.js, index.js
26+
- [ ] T006 [P] Create example/ directory with index.html and queries.js for manual testing
27+
28+
---
29+
30+
## Phase 2: Foundational (Blocking Prerequisites)
31+
32+
**Purpose**: Core utilities and base plugin structure that ALL user stories depend on
33+
34+
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
35+
36+
- [ ] T007 [P] Implement extractPrefixes(yasrResults) in src/prefixUtils.js to extract namespace mappings from SPARQL results metadata
37+
- [ ] T008 [P] Implement applyPrefix(uri, prefixMap) in src/prefixUtils.js to convert full URI to prefixed form (e.g., http://example.org/Person → ex:Person)
38+
- [ ] T009 [P] Implement truncateLabel(text, maxLength=50) in src/prefixUtils.js to truncate long labels with ellipsis while preserving full value
39+
- [ ] T010 [P] Implement getNodeColor(node, triples) in src/colorUtils.js to determine color: #FFFF00 (blank nodes), #808080 (literals), #00FF00 (rdf:type objects), #0000FF (other URIs)
40+
- [ ] T011 [P] Implement getDefaultNetworkOptions() in src/networkConfig.js returning vis-network config: physics enabled with 200 max iterations, interactions (drag/zoom/pan/hover), autoResize, 100% width/height
41+
- [ ] T012 Create GraphPlugin class skeleton in src/GraphPlugin.js with constructor(yasr), priority=20, label='Graph', and placeholder methods: canHandleResults(), draw(), getIcon()
42+
- [ ] T013 Implement GraphPlugin.canHandleResults() to detect CONSTRUCT results by checking for subject/predicate/object variables in this.yasr.results
43+
- [ ] T014 Implement GraphPlugin.getIcon() to return Font Awesome icon element (fa-project-diagram) for YASR tab
44+
- [ ] T015 Export GraphPlugin and auto-register with Yasgui.Yasr.registerPlugin('graph', GraphPlugin) in src/index.js (UMD compatibility)
45+
46+
**Checkpoint**: Foundation ready - plugin skeleton complete, utilities available, user story implementation can now begin
47+
48+
---
49+
50+
## Phase 3: User Story 1 - View Basic Graph Structure (Priority: P1) 🎯 MVP
51+
52+
**Goal**: Parse CONSTRUCT results and render interactive graph with nodes (subjects/objects) and edges (predicates) using automatic layout
53+
54+
**Independent Test**: Execute any CONSTRUCT query with connected triples, verify nodes appear with correct labels and colors, edges connect properly, automatic spacing works for disconnected components, prefixes applied to labels
55+
56+
### Implementation for User Story 1
57+
58+
- [ ] T016 [P] [US1] Implement parseConstructResults(yasrResults) in src/parsers.js to extract RDFTriple[] from bindings format (subject/predicate/object with type/value/datatype)
59+
- [ ] T017 [P] [US1] Implement createNodeMap(triples) helper in src/transformers.js to deduplicate subjects/objects into Map<string, GraphNode> with id, uri, label, color, type, fullValue
60+
- [ ] T018 [P] [US1] Implement createEdgesArray(triples, nodeMap) helper in src/transformers.js to create GraphEdge[] with from/to node IDs, predicate label, arrows:'to'
61+
- [ ] T019 [US1] Implement triplesToGraph(triples, prefixMap) in src/transformers.js orchestrating createNodeMap() and createEdgesArray() to return {nodes: GraphNode[], edges: GraphEdge[]}
62+
- [ ] T020 [US1] Implement GraphPlugin.draw() method: clear this.yasr.resultsEl, parse triples via parseConstructResults(), extract prefixes via extractPrefixes(), transform via triplesToGraph()
63+
- [ ] T021 [US1] In GraphPlugin.draw(), create container div with 100% width/height, append to this.yasr.resultsEl
64+
- [ ] T022 [US1] In GraphPlugin.draw(), create vis.DataSet for nodes and edges, instantiate vis.Network with container, data, and options from getDefaultNetworkOptions()
65+
- [ ] T023 [US1] In GraphPlugin.draw(), handle stabilizationIterationsDone event to disable physics after layout completes (performance optimization per constitution)
66+
- [ ] T024 [US1] In GraphPlugin.draw(), add error handling to display empty state message if zero triples, or error message if parsing fails
67+
- [ ] T025 [US1] Handle blank nodes in createNodeMap(): detect _:b* identifiers, assign yellow color #FFFF00, generate label "_:b1" etc.
68+
- [ ] T026 [US1] Handle multiple predicates between same nodes in createEdgesArray(): create separate edge for each predicate, vis-network will curve them automatically
69+
- [ ] T027 [US1] Apply prefix abbreviation to node labels in createNodeMap() using applyPrefix(), truncate long labels using truncateLabel()
70+
- [ ] T028 [US1] Apply prefix abbreviation to edge labels in createEdgesArray() using applyPrefix()
71+
72+
**Checkpoint**: User Story 1 complete - basic graph visualization working with correct colors, labels, and layout
73+
74+
---
75+
76+
## Phase 4: User Story 2 - Navigate and Explore Graph (Priority: P2)
77+
78+
**Goal**: Enable zoom (mouse wheel), pan (drag background), and "zoom to extents" control for exploring different parts of the graph
79+
80+
**Independent Test**: Render any graph from US1, verify mouse wheel zooms in/out centered on cursor, click-drag pans viewport smoothly, "fit to view" centers entire graph, graph remains responsive and fills YASR container
81+
82+
### Implementation for User Story 2
83+
84+
- [ ] T029 [US2] Verify vis-network zoom interaction: mouse wheel scrolling already works via getDefaultNetworkOptions() interaction.zoomView:true (no code changes needed)
85+
- [ ] T030 [US2] Verify vis-network pan interaction: background drag already works via getDefaultNetworkOptions() interaction.dragView:true (no code changes needed)
86+
- [ ] T031 [US2] Add "zoom to extents" button to container in GraphPlugin.draw(): create button element with onclick calling this.network.fit()
87+
- [ ] T032 [US2] Style "zoom to extents" button with CSS: position absolute top-right corner, padding, border, background, hover state
88+
- [ ] T033 [US2] Verify responsive layout: confirm getDefaultNetworkOptions() includes autoResize:true and width/height:'100%' (already configured in T011)
89+
- [ ] T034 [US2] Test smooth rendering during interactions: verify FR-018 (<200ms response) by observing zoom/pan operations in example/index.html
90+
91+
**Checkpoint**: User Story 2 complete - navigation controls working, smooth interactions verified
92+
93+
---
94+
95+
## Phase 5: User Story 3 - Reorganize Layout (Priority: P3)
96+
97+
**Goal**: Allow users to drag individual nodes to new positions with edges updating in real-time and positions persisting during zoom/pan
98+
99+
**Independent Test**: Render any graph, drag nodes to new positions, verify edges follow smoothly, zoom/pan maintains relative positions, no automatic snapping occurs
100+
101+
### Implementation for User Story 3
102+
103+
- [ ] T035 [US3] Verify vis-network node dragging: already enabled via getDefaultNetworkOptions() interaction.dragNodes:true (no code changes needed)
104+
- [ ] T036 [US3] Verify edge updates during drag: vis-network automatically updates edges in real-time (built-in behavior, no code changes needed)
105+
- [ ] T037 [US3] Verify position persistence: vis-network maintains node positions in DataSet during zoom/pan (built-in behavior, no code changes needed)
106+
- [ ] T038 [US3] Test manual positioning: verify no snapping or collision prevention in example/index.html (FR-019 requirement)
107+
108+
**Checkpoint**: User Story 3 complete - manual node positioning working as expected
109+
110+
---
111+
112+
## Phase 6: User Story 4 - Inspect Node and Edge Details (Priority: P4)
113+
114+
**Goal**: Show tooltips on hover (300ms delay) with full URI/literal details including datatypes for nodes and predicate URIs for edges
115+
116+
**Independent Test**: Render graph with URIs and literals, hover over nodes and edges, verify tooltips appear after 300ms showing full prefixed URI/literal with datatype/predicate, tooltips disappear on mouse leave
117+
118+
### Implementation for User Story 4
119+
120+
- [ ] T039 [P] [US4] Add title attribute to nodes in createNodeMap() in src/transformers.js: for URIs show full prefixed URI, for literals show value with datatype (e.g., "123"^^xsd:integer), for blank nodes show identifier
121+
- [ ] T040 [P] [US4] Add title attribute to edges in createEdgesArray() in src/transformers.js: show full prefixed predicate URI
122+
- [ ] T041 [US4] Configure tooltip delay in getDefaultNetworkOptions() in src/networkConfig.js: add tooltipDelay property set to 300ms for nodes and edges
123+
- [ ] T042 [US4] Verify tooltip behavior in example/index.html: confirm 300ms delay before showing, auto-hide on mouse leave (vis-network built-in behavior)
124+
125+
**Checkpoint**: User Story 4 complete - tooltips working with correct information and timing
126+
127+
---
128+
129+
## Phase 7: User Story 5 - Export Visualization (Priority: P5)
130+
131+
**Goal**: Provide "save as image" control to export visible viewport content at current zoom/pan level as PNG file with readable labels
132+
133+
**Independent Test**: Render and navigate to specific view, click export button, verify downloaded PNG matches current viewport exactly (not entire graph), image has sufficient resolution for readable labels
134+
135+
### Implementation for User Story 5
136+
137+
- [ ] T043 [US5] Add "save as image" button to container in GraphPlugin.draw(): create button element next to "zoom to extents" button
138+
- [ ] T044 [US5] Implement GraphPlugin.download(filename) method: get canvas element from this.network.canvas.frame.canvas
139+
- [ ] T045 [US5] In GraphPlugin.download(), use canvas.toBlob() to export PNG of current viewport (not full graph), trigger browser download with filename
140+
- [ ] T046 [US5] Wire "save as image" button onclick to call this.download('graph-export') in GraphPlugin.draw()
141+
- [ ] T047 [US5] Style "save as image" button with CSS: position absolute top-right, left of "zoom to extents", consistent styling
142+
- [ ] T048 [US5] Test export in example/index.html: zoom/pan to specific view, export, verify PNG shows only visible viewport at current zoom level
143+
144+
**Checkpoint**: User Story 5 complete - image export working for viewport content
145+
146+
---
147+
148+
## Phase 8: Polish & Cross-Cutting Concerns
149+
150+
**Purpose**: Edge cases, error handling, performance optimization, and final documentation
151+
152+
- [ ] T049 [P] Handle empty results edge case: enhance GraphPlugin.draw() empty state message to match FR-029 "No graph data to visualize"
153+
- [ ] T050 [P] Handle single triple edge case: verify graph renders two nodes with one edge centered in viewport
154+
- [ ] T051 [P] Handle self-referencing triples: verify vis-network renders loop edges correctly (built-in support)
155+
- [ ] T052 [P] Handle very long URIs: ensure truncateLabel() in prefixUtils.js truncates with ellipsis at 50 chars (already implemented in T009)
156+
- [ ] T053 [P] Handle very long literals: ensure truncateLabel() in prefixUtils.js truncates with ellipsis at 50 chars (already implemented in T009)
157+
- [ ] T054 [P] Handle duplicate triples deduplication: verify createEdgesArray() in transformers.js only creates one edge per unique subject-predicate-object (Map/Set based)
158+
- [ ] T055 Add performance warning for large graphs: in GraphPlugin.draw(), if triples.length > 1000, log console warning about potential slowness
159+
- [ ] T056 Handle browser resize: verify vis-network autoResize option handles window resize automatically (configured in T011)
160+
- [ ] T057 Add CSS styling for plugin container in src/GraphPlugin.js: container height 600px or 100% of parent, overflow hidden, position relative
161+
- [ ] T058 Create example/queries.js with sample CONSTRUCT queries: basic graph, ontology visualization, DBpedia example, large graph (100+ triples)
162+
- [ ] T059 Create example/index.html with YASGUI instance, plugin registration, endpoint configuration, and query examples
163+
- [ ] T060 Update README.md with installation instructions, usage examples, configuration options, and link to quickstart.md
164+
- [ ] T061 Build dist/yasgui-graph-plugin.min.js using esbuild: run build script, verify UMD bundle, test global GraphPlugin export
165+
- [ ] T062 Manual browser testing in Chrome: execute all example queries, verify all 5 user stories work correctly
166+
- [ ] T063 Manual browser testing in Firefox: execute all example queries, verify all 5 user stories work correctly
167+
- [ ] T064 Manual browser testing in Safari: execute all example queries, verify all 5 user stories work correctly
168+
- [ ] T065 Manual browser testing in Edge: execute all example queries, verify all 5 user stories work correctly
169+
170+
**Checkpoint**: All edge cases handled, performance optimized, manual testing complete across all browsers
171+
172+
---
173+
174+
## Implementation Strategy
175+
176+
### MVP Scope (Recommended First Delivery)
177+
178+
**Phase 1 + Phase 2 + Phase 3 (User Story 1)** = Minimal viable graph visualization
179+
180+
This provides:
181+
- ✅ Basic graph rendering with automatic layout
182+
- ✅ Color-coded nodes (literals/blank nodes/URIs/types)
183+
- ✅ Prefixed labels
184+
- ✅ Edge connections with predicates
185+
- ✅ Plugin registration with YASR
186+
187+
**Delivery**: Can be released as v0.1.0 after completing T001-T028
188+
189+
### Incremental Additions
190+
191+
- **v0.2.0**: Add Phase 4 (User Story 2 - Navigation) for zoom/pan controls
192+
- **v0.3.0**: Add Phase 5 (User Story 3 - Reorganize) for node dragging
193+
- **v0.4.0**: Add Phase 6 (User Story 4 - Tooltips) for detail inspection
194+
- **v0.5.0**: Add Phase 7 (User Story 5 - Export) for image export
195+
- **v1.0.0**: Complete Phase 8 (Polish) for production readiness
196+
197+
### Parallel Execution Opportunities
198+
199+
**Within Setup Phase (Phase 1)**:
200+
- T002 (eslint), T003 (prettier), T005 (directories), T006 (examples) can run in parallel after T001
201+
202+
**Within Foundational Phase (Phase 2)**:
203+
- T007-T011 (all utility functions) can run in parallel independently
204+
- T012-T015 (plugin skeleton) must run sequentially
205+
206+
**Within User Story 1 (Phase 3)**:
207+
- T016-T018 (parsers/transformers helpers) can run in parallel
208+
- T025-T028 (edge case handlers) can run in parallel after T016-T024 complete
209+
210+
**Within User Story 4 (Phase 6)**:
211+
- T039-T040 (tooltip content) can run in parallel
212+
213+
**Within Polish Phase (Phase 8)**:
214+
- T049-T054 (edge case handlers) can run in parallel
215+
- T062-T065 (browser testing) can run in parallel
216+
217+
**Example Parallel Execution for User Story 1**:
218+
```
219+
┌─ T016 [parsers.js] ────┐
220+
├─ T017 [transformers.js] ┼─→ T019 → T020-T024 (draw() implementation) → T027-T028
221+
└─ T018 [transformers.js] ┘ ↑
222+
223+
┌─ T025 (blank nodes) ─────────┤
224+
├─ T026 (multi predicates) ────┤
225+
└─ T027-T028 (labels) ─────────┘
226+
```
227+
228+
---
229+
230+
## Dependencies (User Story Completion Order)
231+
232+
```
233+
Phase 1 (Setup)
234+
235+
Phase 2 (Foundational) ← BLOCKING: Must complete before any user story
236+
237+
Phase 3 (US1: View Graph) ← MVP: Core visualization
238+
239+
Phase 4 (US2: Navigate) ← Depends on US1 (need graph to navigate)
240+
241+
Phase 5 (US3: Reorganize) ← Depends on US1 (need nodes to drag)
242+
243+
Phase 6 (US4: Tooltips) ← Depends on US1 (need elements to hover)
244+
245+
Phase 7 (US5: Export) ← Depends on US1, US2 (need viewport to export)
246+
247+
Phase 8 (Polish) ← Final integration and testing
248+
```
249+
250+
**Critical Path**: T001 → T007-T015 (foundational) → T016-T028 (US1) → T029-T048 (US2-US5) → T049-T065 (polish)
251+
252+
**No circular dependencies**: Each user story builds on US1 but stories are otherwise independent
253+
254+
---
255+
256+
## Task Summary
257+
258+
- **Total Tasks**: 65
259+
- **Phase 1 (Setup)**: 6 tasks
260+
- **Phase 2 (Foundational)**: 9 tasks (BLOCKING)
261+
- **Phase 3 (US1 - View)**: 13 tasks (MVP)
262+
- **Phase 4 (US2 - Navigate)**: 6 tasks
263+
- **Phase 5 (US3 - Reorganize)**: 4 tasks
264+
- **Phase 6 (US4 - Tooltips)**: 4 tasks
265+
- **Phase 7 (US5 - Export)**: 6 tasks
266+
- **Phase 8 (Polish)**: 17 tasks
267+
268+
**Parallel Opportunities**: 22 tasks marked [P] can run in parallel (34% of total)
269+
270+
**Independent Test Criteria**:
271+
- US1: Execute CONSTRUCT query, verify graph renders with correct colors/labels/layout
272+
- US2: Zoom/pan/fit controls work smoothly on any graph
273+
- US3: Drag nodes, positions persist during navigation
274+
- US4: Hover shows tooltips after 300ms with full details
275+
- US5: Export button downloads PNG of visible viewport
276+
277+
**Format Validation**: ✅ All tasks follow checklist format `- [ ] [ID] [P?] [Story?] Description with file path`
278+
279+
---
280+
281+
## Notes
282+
283+
- **No tests**: Manual browser testing per constitution principle IV (Browser Compatibility)
284+
- **vis-network features**: Many US2/US3 requirements already provided by vis-network built-in functionality (zoom, pan, drag, tooltips), tasks verify configuration
285+
- **Incremental delivery**: Each user story phase is independently testable and deliverable
286+
- **MVP focus**: Phase 1 + 2 + 3 (T001-T028) provides minimal viable product
287+
- **Constitution compliance**: All tasks align with 5 constitution principles (plugin-first, quality, flexibility, compatibility, documentation)

0 commit comments

Comments
 (0)