Force-directed graph view with tag nodes, project clustering, physics tuning
- New /graph route with D3 force simulation (GraphView.vue) - Tag nodes as first-class graph nodes (string IDs "tag:name") — clicking navigates to /notes?tags=name; tags shown by default - Invisible project hub nodes attract project members into clusters - Physics panel with live sliders: repulsion, link distance, link strength, project pull, gravity (forceX/forceY, not forceCenter) - Wikilink edges retain directed arrowheads; tag edges are thin, no arrowhead - Graph nav link in AppHeader; `g` shortcut in App.vue - Backend: build_note_graph() emits tag nodes + note→tag edges instead of O(n²) note→note shared-tag mesh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ from fabledassistant.services.generation_buffer import (
|
||||
)
|
||||
from fabledassistant.services.generation_task import run_assist_generation
|
||||
from fabledassistant.services.notes import (
|
||||
build_note_graph,
|
||||
convert_note_to_task,
|
||||
convert_task_to_note,
|
||||
create_note,
|
||||
@@ -510,3 +511,15 @@ async def get_version_route(note_id: int, version_id: int):
|
||||
if version is None:
|
||||
return not_found("Version")
|
||||
return jsonify(version.to_dict(include_body=True))
|
||||
|
||||
|
||||
# ── Graph route ────────────────────────────────────────────────────────────────
|
||||
|
||||
@notes_bp.route("/graph", methods=["GET"])
|
||||
@login_required
|
||||
async def graph_route():
|
||||
uid = get_current_user_id()
|
||||
project_id = request.args.get("project_id", type=int)
|
||||
shared_tags = request.args.get("shared_tags", "false").lower() == "true"
|
||||
graph = await build_note_graph(uid, project_id=project_id, include_shared_tags=shared_tags)
|
||||
return jsonify(graph)
|
||||
|
||||
Reference in New Issue
Block a user