| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(explorer): add Markdown editor write path (#1349) * feat(explorer): add Markdown editing write path * fix(explorer): address markdown editor review findings * feat(explorer): add Markdown editor write path --------- Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> | 1 个月前 | |
feat(explorer): add deterministic rendering E2E example and test (#1037) (#1041) feat(explorer): add deterministic rendering E2E example and test (#1037) Adds a deterministic Explorer graph baseline and coverage for the full build -> persist -> API -> frontend hydration -> canvas rendering path, so a regression anywhere along that chain shows up in CI instead manually. examples/explorer_deterministic_rendering_example.py builds the canonical 4-node, 3-edge graph (Alice -WORKS_AT-> Acme, Bob -KNOWS-> Alice, Acme -LOCATED_IN-> New York) with ContextGraph.add_node()/ add_edge(), persists it with save_to_file() and reloads it with GraphSession.from_file(), printing the setup prerequisites and the expected node/edge/label checklist for anyone running it by hand. tests/explorer/test_explorer_deterministic_rendering_e2e.py covers graph construction, the serialize/deserialize round trip, GraphSession loading, and the Explorer API's /api/graph/* responses against the exact expected nodes, edges, and labels, plus all three auth modes (unconfigured, API-key required, anonymous opt-in). fix(explorer): address Qodo review findings for deterministic rendering e2e (#1037) - configure SEMANTICA_ALLOW_ANONYMOUS=true and document SEMANTICA_API_KEY as the alternative in the reproduction instructions, so the documented commands don't 503 on a clean checkout - add clean-checkout prerequisites and a visual verification checklist to the example - add edge-label (WORKS_AT, KNOWS, LOCATED_IN), zoom-tier, and hover-interaction coverage to the frontend test - add an explicit auth-enforcement integration test for the deterministic graph endpoints fix(explorer): connect deterministic rendering E2E path The frontend test built its own node/edge objects directly with batchMergeNodes()/batchMergeEdges(), bypassing the real loading path entirely -- it never went through useLoadGraph, never mounted the canvas, and its fixture didn't even carry the same fields the backend actually returns (e.g. no color values), so a break in API hydration, the edge.type -> edgeType mapping, or canvas label rendering could still pass. Adds deterministicExplorerRendering.e2e.ts, which mounts the real Explorer app in Chromium, serves API-shaped /api/graph/nodes and /api/graph/edges responses through route interception, drives the app through its actual useLoadGraph hydration path into a real Sigma canvas, and asserts on captured canvas fillText() calls that WORKS_AT, KNOWS, and LOCATED_IN are genuinely drawn, both after load and after Zoom In. fix(explorer): preserve upstream markdown dependencies ci(explorer): isolate deterministic backend test dependencies Wires the new Python test into ci.yml as its own focused step (it previously only ran manually), installs Playwright's Chromium browser before the frontend suite, and keeps the deterministic backend test's dependency install separate from the rest of the pipeline so it doesn't pull in unrelated optional extras during collection. fix(explorer): remove redundant edge label hydration An earlier commit in this PR added an explicit `label` field to hydrated edge attributes on the theory that it was needed for edge labels to render. Review traced through GraphCanvas.tsx's label resolution (`attrs.edgeType || data.label || ""`, from the earlier #1009 fix already on main) and found that `edgeType` is set unconditionally on every edge during hydration, so it always wins the `||` before `data.label` is ever consulted -- the added field and its plumbing in useLoadGraph.ts and graphStore.ts never did anything. Removed both; reran the real Chromium E2E test against the reverted code and confirmed all three labels still render identically, closing out the question of whether anything else was actually broken. | 1 个月前 | |
feat(explorer): add Markdown editor write path (#1349) * feat(explorer): add Markdown editing write path * fix(explorer): address markdown editor review findings * feat(explorer): add Markdown editor write path --------- Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> | 1 个月前 | |
fix(explorer): label the graph view control "Focus" (#1552) * fix(explorer): label the graph view control "Focus" The control read "Focused" before it was ever activated, which describes a state the selection had already reached rather than the action available. The view mode value, tooltip, enablement and active styling are unchanged. The legend e2e drove this button by its accessible name, so the selector moves with the label; it now also asserts the visible text, the selection-dependent enablement and the active state. Closes #1551 Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(explorer): name the control in the grouped-selection hint, and trim the test "Activate Focused mode" instructed the reader to press a control that no longer carries that name. The surrounding strings describe the mode itself, which is still called focused, so they stay. Drop the label and active-state assertions from the colour-legend test: the getByRole locator already fails when the accessible name is wrong, and the rest belonged to the control's contract rather than to the legend's. Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: Claude Code <noreply@anthropic.com> | 25 天前 | |
fix(explorer): align visible legend with semantic node colors (#1483) Replace the static biomedical category key in Explorer with a live node color legend derived from the active display graph, sharing the canvas's baseColor -> color -> theme fallback resolver. - Preserve original semantic colors on focused display clones via `semanticBaseColor` so interaction styling (selection, path, neighbor highlights) does not bleed into the legend. - Suppress the semantic legend while distance visualization modes are active. - Refactor plugin fallback legend panels to use the shared legend builder with composite (group, color) keys. - Consolidate duplicate `"test:graph-workspace"` scripts in `explorer/package.json`, recovering 26 previously shadowed tests across markdown and explorer capability suites. - Add `tests/graphColorLegend.test.ts` to workspace test runs and wire `test:graph-legend-e2e` into `.github/workflows/ci.yml`. - Closes #1479 | 28 天前 | |
refactor(explorer): split focused view from layout modes (#1599) * refactor(explorer): split focused view from layout modes Keep Focus in the graph view toolbar, but treat it as enterLocalGraph(nodeId) instead of a unary view-mode switch. Layout modes are now only full/grouped. Unavailable grouped/focus reasons are codes with one copy owner, and the segmented control exposes aria-pressed. Closes #1554 * fix(explorer): confirm draft when enterLocalGraph changes node Resolve the target first, then prompt whenever focused mode is entered or the inspector Markdown resource would change. Clear edge/path/search on that same transition so plugin-driven local-graph entry matches focusNode. | 21 天前 | |
feat(explorer): add Semantica Knowledge Explorer UI with full feature set ## Folder & Project - Renamed `semantica-explorer/` → `explorer/` (cleaner path) - Browser tab title: `Semantica Knowledge Explorer` - Brand pill: `SEM` → `SKE` (tooltip: Semantica Knowledge Explorer) - Nav rail label: `Explore` → `Knowledge Explorer` - package.json name: `semantica-knowledge-explorer` - Downgraded Vite 8 → Vite 5 for Node v20.17.0 compatibility ## App Shell - Dynamic per-workspace kicker labels replacing static "Workspace" pill: Graph Studio · Vocabulary Browser · Reasoning Engine · SPARQL Query · Decision Intelligence · Knowledge Audit · Graph Governance ## Enrich Workspace — 2 new tabs ### Entity Resolution tab - Similarity threshold slider (0.50–0.99) - Run Dedup Scan → POST /api/enrich/dedup - Flagged pairs list with colour-coded score bars (red/amber/green) - Expandable inline diff: primary vs duplicate side-by-side - One-click Merge → POST /api/enrich/merge with logEvent dispatch - Dismiss per pair; Clear all button - Merge history sidebar pulled live from Registry store ### Registry tab (Document Registry) - Live chronological audit log of all KG mutations in-session - Colour-coded op-type badges: IMPORT · MERGE · ADD NODE · ADD EDGE · INFER · DELETE · EXPORT · VOCAB - Filter pills to narrow by operation type - Expandable JSON detail rows per entry - Clear log button - Entirely client-side via registryStore (no backend needed) ## Manage Workspace — 2 new tabs ### KG Overview tab - Stats chips: total nodes, edges, graph density - Node type breakdown bar chart (up to 8 types, colour-coded) - Edge type breakdown bar chart from /api/graph/stats - Top-10 most connected nodes ranked by degree - Skeleton loading states + Refresh button ### Ontology Summary tab - Read-only SKOS scheme tree (scheme → top concepts → narrower) - Concept detail panel: labels, notation, description, narrower nav - "Open Full Browser" button deep-links to Vocabulary Browser tab ## Decision Workspace polish - CausalFlowDiagram: vertical node cards connected by relationship pills - Outcome badges: colour-coded (green=approved, red=rejected, amber=deferred) - Live filter input across decision ID, category, and outcome - Animated skeleton loading while list fetches ## Graph Inspector polish - PathFlowViz: clickable node chips connected by edge-type labels; clicking a chip focuses that node in the canvas - Link Prediction button shows spinner while computing - Empty states for path trace and candidate links sections ## Registry dispatch — WebSocket - ADD_NODE events → logEvent("add-node", …) in GraphWorkspace WS handler - ADD_EDGE events → logEvent("add-edge", …) in GraphWorkspace WS handler - Import, Export, Merge already dispatched logEvent on API response ## Graph visibility overhaul ### Edge colours (were nearly transparent, now clearly visible) - edgeBackbone: rgba(…, 0.04) → rgba(…, 0.38) - edgeStructure: rgba(…, 0.009) → rgba(…, 0.28) - edgeInspection: rgba(…, 0.026) → rgba(…, 0.48) - Muted edges: 0.009–0.02 → 0.12–0.26 - Focus edges: 0.16 → 0.42 ### Edge sizes - default minSize: 0.18 → 0.9 (always at least 1 pixel wide) - path minSize: 1.8 → 2.4 - inactive/muted: hide:true → hide:false (dimmed not hidden) ### Node sizes - default sizeMultiplier: 0.72 → 0.92 - default minSize: 0.68 → 3.5 (visible at all zoom levels) - overview nodeScale: 0.66 → 0.88 - nodeTintMix (colour): 0.03 → 0.14 - nodeCoreMix (brightness): 0.52 → 0.72 ### Label budget - overview: 10 → 28 labels - structure: 36 → 60 labels - inspection: 80 → 120 labels ### Sigma settings - renderEdgeLabels: false → true (relationship type on every edge) - edgeLabelSize: — → 10 - labelRenderedSizeThreshold: 4 → 2 - labelDensity: 0.86 → 1.1 - hideLabelsOnMove: true → false (labels stay visible while panning) - hideEdgesOnMove: true → false (edges stay visible while panning) - minCameraRatio: — → 0.04 (prevents zooming inside a node) - maxCameraRatio: — → 8 (graph stays visible when zoomed out) ### Zoom controls - Added Zoom In (+) and Zoom Out (−) buttons to graph toolbar - Smooth animated zoom via camera.animatedZoom / animatedUnzoom (200ms) - Mouse scroll wheel clamped between minCameraRatio and maxCameraRatio Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> | 5 个月前 | |
refactor(explorer): split focused view from layout modes (#1599) * refactor(explorer): split focused view from layout modes Keep Focus in the graph view toolbar, but treat it as enterLocalGraph(nodeId) instead of a unary view-mode switch. Layout modes are now only full/grouped. Unavailable grouped/focus reasons are codes with one copy owner, and the segmented control exposes aria-pressed. Closes #1554 * fix(explorer): confirm draft when enterLocalGraph changes node Resolve the target first, then prompt whenever focused mode is entered or the inspector Markdown resource would change. Clear edge/path/search on that same transition so plugin-driven local-graph entry matches focusNode. | 21 天前 | |
refactor(explorer): split focused view from layout modes (#1599) * refactor(explorer): split focused view from layout modes Keep Focus in the graph view toolbar, but treat it as enterLocalGraph(nodeId) instead of a unary view-mode switch. Layout modes are now only full/grouped. Unavailable grouped/focus reasons are codes with one copy owner, and the segmented control exposes aria-pressed. Closes #1554 * fix(explorer): confirm draft when enterLocalGraph changes node Resolve the target first, then prompt whenever focused mode is entered or the inspector Markdown resource would change. Clear edge/path/search on that same transition so plugin-driven local-graph entry matches focusNode. | 21 天前 | |
feat(explorer): complete ARIA tab pattern for markdown viewer (#1117) (#1196) * feat(explorer): complete ARIA tab pattern for markdown viewer (#1117) The Preview/Source controls exposed role="tablist"/role="tab"/aria-selected but never connected to the content they switch, so assistive technology could not tell which panel the tabs controlled, and the tablist was two separate Tab stops with no arrow-key navigation. Wire the full pattern: - ids from useId(), matching the GraphWorkspace search combobox, so two viewers mounted at once cannot collide on hardcoded ids - aria-controls on both tabs, role="tabpanel" + aria-labelledby on the panel - roving tabindex, so the tablist is a single Tab stop - Arrow Left/Right with wrapping, plus Home/End, all preventDefault'd Two decisions worth recording. Activation is manual (arrows move focus, Enter/Space selects) rather than the automatic activation the APG suggests by default. The APG permits manual activation where switching panels is expensive, and here it is: activating Preview re-runs the whole markdown parse, measured at 385ms for a 1000-row GFM table and 1433ms at 2000 rows while profiling #1118. Automatic activation would freeze the main thread on every arrow keypress. The panel wraps all three render branches, including the empty state, and both tabs point aria-controls at that one id. Only the active view is ever rendered, so per-tab panel ids would leave the inactive tab referencing an element absent from the DOM -- and scoping the panel to the two content branches would dangle the reference for empty nodes. No visible focus style was added: index.css already applies a global :focus-visible ring and tabBtnStyle does not suppress it. Five tests cover the wiring, the empty-state branch, roving tabindex and id uniqueness; each was confirmed to fail against the previous component. Keyboard behaviour is not reachable from the SSR-based suite, so it was verified separately in headless Chromium: Tab enters the tablist on the selected tab, ArrowRight moves focus without activating, Enter and Space activate, ArrowRight wraps, and Home/End work. All 71 tests pass and lint is unchanged. * feat(explorer): complete markdown viewer tab accessibility Complete the Preview/Source ARIA tab pattern with collision-safe IDs, tabpanel wiring, roving tabindex, and manual keyboard activation. Use ref-based focus tracking to prevent keyboard navigation from triggering Markdown re-parsing, and synchronize the roving tabindex after React renders. Add regression coverage for keyboard navigation, wrapping, ARIA labelling, and focus-state invariants. * fix(explorer): move focusedModeRef resource-reset out of render phase The render-phase ref write (focusedModeRef.current = defaultMode inside the activeResourceKey !== resourceKey guard) correctly reset the ref but triggered a react-hooks/refs lint error: refs must not be written during render. Replace with a useLayoutEffect([resourceKey, defaultMode]) that fires synchronously before paint after every resource/defaultMode change. This achieves the same invariant — focusedModeRef is reset before the no-deps tabIndex-correction effect reads it — while satisfying the linter. Lint: npx eslint MarkdownContentViewer.tsx -> 0 errors Tests: npm run test:graph-workspace -> 107/107 pass --------- Co-authored-by: Pravit Ampapathini <pravit.amp@gmail.com> Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> Co-authored-by: Sameer Kadam <sameerkadam@Mac.lan> | 28 天前 | |
feat(explorer): add Markdown editor write path (#1349) * feat(explorer): add Markdown editing write path * fix(explorer): address markdown editor review findings * feat(explorer): add Markdown editor write path --------- Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> | 1 个月前 | |
feat(explorer): add Markdown editor write path (#1349) * feat(explorer): add Markdown editing write path * fix(explorer): address markdown editor review findings * feat(explorer): add Markdown editor write path --------- Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> | 1 个月前 | |
feat(explorer): add Markdown editor write path (#1349) * feat(explorer): add Markdown editing write path * fix(explorer): address markdown editor review findings * feat(explorer): add Markdown editor write path --------- Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> | 1 个月前 | |
fix(explorer): serve entity_type from the ontology graph endpoint (#1438) * fix(explorer): serve entity_type from /api/ontology/graph The node-type classification vocabulary existed twice — once in the backend (_CLASS_TYPES/_PROPERTY_TYPES/_classify_node_type) and once in the Ontology Editor (classifyNodeType/FULL_IRI_PREFIXES). The copies had already drifted: the frontend recognized only compact types (owl:Class) until full IRIs were patched in separately. /graph now returns the server-computed entity_type per node, matching /entity/{uri}, and the editor maps it to its own read-only/editable kinds instead of parsing RDF types. The classification tests move to the backend with it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(explorer): keep graph entity_type inside the response vocabulary Review follow-up: the classifier's "unknown" fallback leaked into the graph response for outward references with unrecognized types; from the requested ontology's perspective such nodes are external reference material. Also extend the classification test to the full compact/ full-IRI matrix (property, ontology, unrecognized external). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(explorer): let /graph and /entity speak one entity_type vocabulary The graph endpoint mapped the classifier's "unknown" to "external", which the editor already does in its default branch — so the mapping changed nothing visible while making the two endpoints report different values for the same node. Emit the classifier verdict verbatim and keep the "external reference material" reading in the editor, where it acts on it. Make entity_type required on OntologyGraphNode: optional turns a producer that forgets into a graph of silently read-only nodes. Pin the agreement with a test that queries both endpoints for the same URIs, fragment-encoded so it cannot pass on the parent ontology instead. | 15 天前 | |
refactor(explorer): own Ontology Hub URL state in one module (#1440) The deep-link protocol introduced in #1278 lived as bare "ontologyTab" / "ontologyEntity" literals in five places across three files, each with its own URLSearchParams plumbing and try/catch. Nothing tied the pieces together: in particular the rule that a selection written under one ontology must be cleared when the active ontology changes — otherwise a reload resolves the stale entity and jumps back to the old ontology — was a comment at one call site with no mechanism behind it. ontologyUrlState.ts now owns the parameter names as private constants and exposes the protocol as intent-named operations, with the write/clear pairing documented where both halves live. Parsing and serialization are pure functions over a search string, so they are covered by tests without a DOM; the window and history.replaceState interaction stays in thin shells. Absent parameters still read as undefined while blank ones read as empty strings, which preserves the differing presence checks the workspace shell and the tab selector each relied on. One behavior change, inherited from all five original call sites: writing the query string dropped any URL fragment, because replaceState with a bare "?..." replaces the whole tail. updateSearch now carries window.location.hash across, which fixes it for every writer at once — this module is the only place that knows how the URL is written, so it is the only place the fix belongs. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 25 天前 | |
refactor: tighten comments across #830 changes for clarity - pluginRegistryPredicates.ts: consolidate 8-line JSDoc to 5 lines, removing redundant detail that restated implementation mechanics already obvious from the code. - GraphWorkspace.tsx: shorten the lastScrubberMsRef comment from 5 lines to 2; trim the handleDiagnosticsChange block comment by removing the 'rather than bailing out' implementation-alternative sentence; tighten the distanceVisual inline comment. - pluginRegistry.temporal.test.mjs: replace 17-line file-level JSDoc with 9 lines focused on the invariant rather than the root-cause narrative (already covered in pluginRegistryPredicates.ts); remove two tsx loader implementation-detail comments; tighten two test-level inline comments. No logic, types, or test assertions changed. All 42 tests pass. | 1 个月前 | |
fix(explorer): keep small Full Graph relationships readable (#1277) * fix(explorer): keep small full graphs readable * perf(explorer): avoid redundant realtime edge sync --------- Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> | 1 个月前 | |
fix(explorer): keep small Full Graph relationships readable (#1277) * fix(explorer): keep small full graphs readable * perf(explorer): avoid redundant realtime edge sync --------- Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> | 1 个月前 | |
fix(explorer): gate temporal requests on graph load (#1003) Explorer was firing temporal requests before the graph even loaded. When the backend is down, /api/graph/nodes fails but the temporal bounds and snapshot effects didn't care , they fired anyway, off in their own corner, ignoring whether the graph actually came up. Every page load with no backend meant three failed requests instead of one, and a scrubber that had nothing to scrub. Added two small predicate functions and gated the temporal effects on them. Basically: don't ask for time-based data until you know the graph itself loaded. An empty graph still counts as loaded, so that case isn't broken. Confirmed with the backend down, before and after: three failing requests down to one. Fixes #982. | 1 个月前 | |
fix(explorer): end the temporal scrubber at now instead of inventing 2030 (#1541) TimelinePanel fell back to a hardcoded 2030-01-01 whenever /api/temporal/bounds reported max: null, then placed the playhead at the midpoint of that fabricated window. session.get_temporal_bounds leaves max open for any graph whose nodes carry valid_from instants and no valid_until, so this was the normal response shape rather than bad data: the header advertised a range no data supported and the workspace's first /api/temporal/snapshot request asked about a time years ahead of the present. The fallback is now a `now` captured once per mount, and defaultTime is that same `now` clamped into the range, so the initial snapshot describes the current state. Three settings tuned for the fictional ~60-year window follow from it: zoomMin drops from a year to a day, the timeAxis/format pinning to 5-year ticks is removed so vis-timeline picks a granularity for the real span, and the fixed 6-month play step becomes span/60 with a one-day floor, which keeps a play-through at roughly 60 frames whether the graph covers months or a decade. The bound and step arithmetic moves into temporalScrubberBounds.ts so it can be asserted directly, alongside the existing temporalLifecycle predicate tests. Closes #1536 Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> | 25 天前 | |
fix(explorer): dedupe temporal snapshot requests and apply latest-wins (#1241) fix(explorer): dedupe temporal snapshot requests and apply latest-wins The temporal snapshot effect fetched /api/temporal/snapshot with no idempotency or ordering guards. Upstream churn (timeline recreation while bounds settle, play ticks resetting the playhead, drag events) could re-request the same `at` repeatedly, and with variable network latency an older position's response could land after a newer one's, overwriting the active-node count, so the chip visibly lagged the scrubber. Add a small stateful guard module (temporalSnapshotGuards.ts) built around a per-position cache, keyed by the debounced timestamp's primitive millisecond value rather than the Date object, so upstream object-identity churn cannot defeat the dedup on its own: - at most one in-flight request per scrubber position, so identical `at` values arriving while a request is pending are dropped instead of firing a fresh fetch, breaking the idle/play polling loop; - successful snapshots are cached per position and re-applied when the scrubber returns to it (play wrap-around, back-scrubbing) without a network round trip; - a response is applied only while the scrubber is still on the position it was requested for, so an out-of-order response can never clobber a newer position's count; - failed, cancelled, or superseded requests release their position so it can be fetched again the next time it's visited, rather than stalling it permanently; - reset() drops all cached and in-flight state when the underlying graph summary changes (reload/retry), since snapshots cached against the previous graph no longer describe anything real. Keyed on the summary query's data identity, which react-query keeps stable (staleTime: Infinity plus structural sharing) unless the graph data itself was replaced, so reset fires exactly on a real reload and not on cosmetic re-renders. The snapshot effect is wired through the guards end to end: begin() returns either a fresh sequence number to fetch under or a cached snapshot to reapply directly; the same shouldApply()/apply() gate handles both the network and cached-reapply paths so they can't drift apart; finish() runs from both the fetch's failure branch and its cleanup function, so a cancelled or failed request is always retryable on the next visit instead of leaving its position stuck in-flight. 16 unit tests cover dedup, independent positions, revisit re-apply, play wrap-around, failure retry, stale-sequence protection (a late response or a late release from a superseded request cannot act on a newer request's position), reset-on-reload, and cache-bound eviction. Closes #1128 | 1 个月前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 25 天前 | ||
| 28 天前 | ||
| 21 天前 | ||
| 5 个月前 | ||
| 21 天前 | ||
| 21 天前 | ||
| 28 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 15 天前 | ||
| 25 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 25 天前 | ||
| 1 个月前 |