Problem
Relationship type grouping already exists for legend organization, but there's no way to use it for filtering. Users want to create different graph views focused on specific relationship categories:
- One embed: "show only Social relationships" (allies, enemies, friends)
- Another: "show only Family relationships" (parents, children, siblings)
- Another: "show only Bond relationships" (spouses, romantic partners)
Without this, users have to repeatedly toggle the global type filter, or maintain separate vaults, to get a focused view. This is particularly useful in TTRPG worldbuilding and narrative-heavy vaults where a note has many relationship categories and a given embed (a faction page, a family tree callout) only cares about one of them.
Solution
Add a groups: option to code blocks, using the same group field that already drives legend clustering:
relations
size: small
groups: "Social, Bond"
- OR logic across multiple groups:
groups: ["Social", "Bond"] or groups: "Social, Bond"
- Strict match — an edge is shown only when its type's group is in the requested set. Ungrouped types are excluded once
groups: is set, same as any type whose group isn't requested.
- Composes with the existing global type filter, which is applied first
- Fully opt-in: blocks without
groups: render exactly as before
Implementation
filterGraphByGroups() in graph.ts — pure function, filters edges by type→group lookup, keeps the center/highlight node even if filtering would otherwise isolate it
groups: parsed from code-block YAML (comma-separated string or array) via a new resolveGroups() helper in codeblock.ts, threaded through parseOptions() into the render path
- Addressed maintainer feedback from review:
- Bug:
parseOptions built groups but never returned it, so the option never reached rendering. Fixed, plus added a genuine parseOptions() round-trip test — which required upgrading the test suite's parseYaml mock from a stub that always returned {} to a small real parser, since nothing could otherwise exercise the actual parsing path.
- Behavior: switched from "ungrouped types always shown" to strict matching. Updated the
group field's doc comment in types.ts (no longer "purely cosmetic") and the Settings panel's help text/tooltip.
- Docs: added
groups to the README options table, rebased onto current main (0.25.0).
Expected Files to Modify
| File |
Planned Changes |
Type |
src/graph.ts |
+60 |
filterGraphByGroups() |
src/codeblock.ts |
+41 |
groups: option, resolveGroups(), render-path wiring |
src/types.ts |
+12/-4 |
group field doc update |
src/settings.ts |
+9/-3 |
Help text + tooltip update |
README.md |
+4 |
Options table + known-limitation note |
tests/filter-graph-groups.test.ts |
+262 |
Filter logic coverage |
tests/parse-options-groups.test.ts |
+47 |
Parsing round-trip coverage |
tests/mocks/obsidian.ts |
+38 |
Real parseYaml mock (was a {} stub) |
| Total |
~460 lines |
8 files |
Backward Compatibility
Fully backward compatible for existing usage — groups: is opt-in, and blocks that don't set it are unaffected. The one behavior decision worth flagging for review: groups: filtering excludes ungrouped types (strict match), rather than always showing them. This only affects blocks that explicitly set groups:.
Known Limitation (found in manual testing) — tracked as #28
With scope: local / scope: connected, the note neighborhood is currently walked using every relationship type before groups: (or the existing global type filter) hides anything — so a note reachable only through a now-hidden type can still surface if it has its own edges of a visible type, rendering as a seemingly disconnected extra node/cluster. This predates this PR (the same pattern exists for the global type filter) but is far more visible with groups:, since a whole category can be hidden at once. Filed as #28; a fix (computing hop-distance over the already-filtered edge set) is in progress separately, since it touches shared graph-building code beyond this feature.
Use Case
- Focus on social relationships:
groups: ["Social"]
- Family tree view:
groups: ["Family", "Genealogy"]
- Romantic connections:
groups: ["Bond"]
- Professional network:
groups: ["Mentor", "Professional"]
Problem
Relationship type grouping already exists for legend organization, but there's no way to use it for filtering. Users want to create different graph views focused on specific relationship categories:
Without this, users have to repeatedly toggle the global type filter, or maintain separate vaults, to get a focused view. This is particularly useful in TTRPG worldbuilding and narrative-heavy vaults where a note has many relationship categories and a given embed (a faction page, a family tree callout) only cares about one of them.
Solution
Add a
groups:option to code blocks, using the samegroupfield that already drives legend clustering:groups: ["Social", "Bond"]orgroups: "Social, Bond"groups:is set, same as any type whose group isn't requested.groups:render exactly as beforeImplementation
filterGraphByGroups()ingraph.ts— pure function, filters edges by type→group lookup, keeps the center/highlight node even if filtering would otherwise isolate itgroups:parsed from code-block YAML (comma-separated string or array) via a newresolveGroups()helper incodeblock.ts, threaded throughparseOptions()into the render pathparseOptionsbuiltgroupsbut never returned it, so the option never reached rendering. Fixed, plus added a genuineparseOptions()round-trip test — which required upgrading the test suite'sparseYamlmock from a stub that always returned{}to a small real parser, since nothing could otherwise exercise the actual parsing path.groupfield's doc comment intypes.ts(no longer "purely cosmetic") and the Settings panel's help text/tooltip.groupsto the README options table, rebased onto currentmain(0.25.0).Expected Files to Modify
src/graph.tsfilterGraphByGroups()src/codeblock.tsgroups:option,resolveGroups(), render-path wiringsrc/types.tsgroupfield doc updatesrc/settings.tsREADME.mdtests/filter-graph-groups.test.tstests/parse-options-groups.test.tstests/mocks/obsidian.tsparseYamlmock (was a{}stub)Backward Compatibility
Fully backward compatible for existing usage —
groups:is opt-in, and blocks that don't set it are unaffected. The one behavior decision worth flagging for review:groups:filtering excludes ungrouped types (strict match), rather than always showing them. This only affects blocks that explicitly setgroups:.Known Limitation (found in manual testing) — tracked as #28
With
scope: local/scope: connected, the note neighborhood is currently walked using every relationship type beforegroups:(or the existing global type filter) hides anything — so a note reachable only through a now-hidden type can still surface if it has its own edges of a visible type, rendering as a seemingly disconnected extra node/cluster. This predates this PR (the same pattern exists for the global type filter) but is far more visible withgroups:, since a whole category can be hidden at once. Filed as #28; a fix (computing hop-distance over the already-filtered edge set) is in progress separately, since it touches shared graph-building code beyond this feature.Use Case
groups: ["Social"]groups: ["Family", "Genealogy"]groups: ["Bond"]groups: ["Mentor", "Professional"]