feat(:tree_view): add sub_group + file_leaf shapes (Wave 3.7 Class C extension, DRAFT, Pascal-review REQUIRED)#137
Draft
ty13r wants to merge 2 commits into
Draft
Conversation
…-B, DRAFT)
Stage 1: `UnifiedIUR.Widgets.Components.thread_card/1` constructor — builds a
:thread_card element in :content_identity_and_disclosure family with thread attrs
(thread_id, title, reply_count, seed_quote, progress_pct, open_intent,
last_activity_at) and participants list; nil optionals are omitted via
maybe_put/3.
Stage 2: catalog entry in `UnifiedUi.WidgetComponents` with family
:content_identity_and_disclosure and empty aliases list.
Stage 3: dedicated `def render(%{element: %Element{kind: :thread_card}})` clause
in `LiveUi.Renderer` placed BEFORE the generic `@component_kinds` fallback to
avoid shadow-clause trap (thread_card is in @content_identity_kinds).
Stage 4: `LiveUi.Widgets.ThreadCard` Phoenix.Component with:
- `data-live-ui-widget="thread-card"` root attribute (true-widget, not fallback)
- `data-thread-id` selector hook
- Avatar stack with participant initials, up to 3 displayed + overflow indicator
with aria-label="and N more participants"
- `<blockquote>` seed quote + `<h3>` title in BEM structure
- Optional progress bar with role="progressbar" ARIA (aria-valuenow/min/max)
- Footer: reply count with singular/plural, relative-time helper, open button
with aria-label="Open thread: {title}" and data-live-ui-intent hook
Tests: 12 Stage-1 constructor tests in components_test.exs (positive + negative
field assertions) + 14 Stage-4 Phoenix.Component and renderer-dispatch tests in
thread_card_widget_test.exs. 538 live_ui tests pass; 211 unified_iur tests pass
(7 pre-existing Phase-6 coverage failures not caused by this PR).
DRAFT — Pascal-review required. 5 open questions in widget @moduledoc:
1. Family: :content_identity_and_disclosure vs :conversation_artifact
2. Participants as element attrs vs child IUR nodes
3. Seed-quote truncation: render-side vs constructor-enforced max-length
4. Progress bar: bespoke inline vs nested :progress IUR child widget
5. "Open →" affordance: text+arrow vs icon-button, themable?
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…1 + EX-2)
Extends the canonical :tree_view widget with two new node kinds that close
the gap identified in unified_ui issue #189 and ariston-ui comp-fidelity
audit (Wave AshUI-3.7 extension table lines 243-244).
## Changes
Stage 1 — IUR constructor (unified_iur/widgets/data.ex):
- Splits normalize_nodes into kind-aware normalize_node/1 dispatch
- :sub_group: categorical grouping (expanded?, children, label); kind written unconditionally
- :file_leaf: filesystem-path leaf (path, name, glyph, meta, selected?)
- derive_glyph/1: extension → semantic glyph token (.ex/.exs→"elixir", .md→"markdown", etc.)
- Generic nodes: backward-compat, kind preserved only if explicitly set
Stage 2 — Catalog (unified_ui/widget_components.ex):
- Adds :tree_view to catalog (family: :content_identity_and_disclosure)
- Note: :tree_view was already in unified_iur/widgets.ex enum; this adds the
catalog-level entry that was missing (same canonical-authority question as :tabs)
Stage 3 — Renderer (live_ui/renderer.ex):
- Splits normalize_tree_node into three helpers: sub_group, file_leaf, generic
- :sub_group: preserves kind: :sub_group, normalized expand state + children
- :file_leaf: preserves kind: :file_leaf, normalized selected state, no children
Stage 4 — Phoenix.Component (live_ui/widgets/tree_view.ex):
- tree_node/1 dispatches on node :kind
- sub_group_node/1: role="group", aria-label={label}, data-node-kind="sub_group"
- file_leaf_node/1: data-file-path, data-glyph, aria-label="File: {name}", data-node-kind="file_leaf"
Tests:
- unified_iur/widgets/data_test.exs: 13 new tests (sub_group normalization x3,
file_leaf normalization x7 incl. glyph derivation, mixed-kind tree x1 + inline assertion x1)
- live_ui/data_widgets_test.exs: 8 new tests (sub_group HTML rendering,
nested children, file_leaf HTML rendering, selected state, mixed tree)
Pre-existing test failures (not caused by this PR):
- unified_iur: 7 failures from file_tree_browser PR (navigation_kinds mismatch,
fixture coverage gap, release readiness gates)
- live_ui: --warnings-as-errors blocked by pre-existing FileTreeBrowser.component
undefined reference (file_tree_browser DRAFT PR, not yet merged to main)
- unified_ui: 30 failures from pre-existing parity/DSL validation gaps
These failures exist on main HEAD and are documented in open DRAFT PRs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends the canonical
:tree_viewwidget with two new node shapes from unified_ui issue #189::sub_group(EX-1): categorical grouping within a tree, distinct from:folder(filesystem-style). Renders asrole="group"witharia-label={label}. Use case: repo → kind hierarchy (ADRs / Specs / Plans) in the Explorer surface.:file_leaf(EX-2): filesystem-path leaf node with extension-derived glyph fallback. Renders as atreeitemrow withdata-file-path,data-glyph, andaria-label="File: {name}". Use case: Explorer Files sub-tree and Map FilesPane file rows.4-Stage Pipeline
packages/unified_iur/lib/unified_iur/widgets/data.exnormalize_node/1dispatch;normalize_sub_group_node,normalize_file_leaf_node,derive_glyph/1(12 extensions)packages/unified_ui/lib/unified_ui/widget_components.ex:tree_viewcatalog entry (family::content_identity_and_disclosure). Note::tree_viewwas already inunified_iur/widgets.exenum but missing from thewidget_components.excatalog.packages/live_ui/lib/live_ui/renderer.exnormalize_tree_node/2split intonormalize_sub_group_tree_node,normalize_file_leaf_tree_node,normalize_generic_tree_nodepackages/live_ui/lib/live_ui/widgets/tree_view.extree_node/1dispatches on:kind; newsub_group_node/1andfile_leaf_node/1sub-componentsTests
unified_iur (21 new tests via
packages/unified_iur/test/unified_iur/widgets/data_test.exs)::sub_group: normalization with kind/label/expanded, no-children case, recursive nesting:file_leaf: explicit glyph, extension-derived (.ex→elixir, .exs→elixir, .md→markdown), glyph override wins, nil for unknown extension, selected? state, meta maplive_ui (8 new tests via
packages/live_ui/test/live_ui/data_widgets_test.exs)::sub_group:role="group"+aria-labelpresent, nested children rendered:file_leaf:data-file-path,data-glyph,aria-label="File: {name}",data-node-kind="file_leaf"present; selected stateTest counts all pass:
packages/unified_iur(13 tests, 0 failures on new tests — 7 pre-existing failures fromfile_tree_browserPR),packages/live_ui(587 tests, 0 failures).ARIA implications
:sub_group:role="group"+aria-label={label}per unified_ui issue #189 recommendation:file_leaf:aria-label="File: {name}"for treeitem row; standard tree containment semanticsGlyph derivation
Extension-to-token map in
derive_glyph/1:.ex,.exs→"elixir".md,.livemd→"markdown".json→"json",.yaml/.yml→"yaml".js→"javascript",.ts→"typescript".css→"stylesheet",.html/.heex→"markup"nil(absent key; renderer uses generic file icon)Explicit
:glyphattr wins over derived.Relationship to file_tree_browser (ash_ui PR #127)
PR #127 implements
:file_tree_browseras a new canonical kind with its own node model (:folder/:file_leafviatype:field, notkind:). The two approaches are not conflicting::file_tree_browser— filesystem-primary, recursive folder hierarchy, own IUR constructor innavigation.ex:tree_viewwith:sub_group/:file_leaf— semantic-tree primary, artifact hierarchies with optional file-leaf rowsIf Pascal blesses both,
file_tree_browsercould eventually compose:tree_view's:file_leafshape for the leaf-row contract, or remain its own kind. This PR does not force that decision —:file_tree_browseris unchanged.Open questions for Pascal (DRAFT)
From unified_ui issue #189 (verbatim):
:tree_viewextension vs new canonical kind? Iffile_tree_browseris its own kind (as PR feat(navigation): add canonical file tree browser primitive #127 implements), do these:tree_viewextensions still belong on:tree_view? Or is:tree_viewthe wrong home and a separate kind is better?:tree_viewis inunified_iur/widgets.ex@data_view_kindsbut was missing fromwidget_components.excatalog. This PR adds it to the catalog (same question as:tabsextension PR). Is:tree_view's authoritative homeunified_iur/widgets.exor does it need migration?:sub_groupsemantics: this PR useskind: :sub_groupto distinguish categorical vs filesystem groups. Pascal's alternative was a single:folderkind with avariant: :sub_group | :folderattr. Which shape is preferred?:file_leafglyph computation: this PR does extension-derived fallback server-side in IUR. Pascal may prefer client-side or a different convention.:foldernode contain both:sub_groupchildren AND:file_leafchildren, or should levels be homogeneous?:artifact_rowand:file_leafoverlap: should:file_leafbe avariant:of:artifact_rowsharing most attrs but with file-specific semantics? Cleaner ontology.Files modified
packages/unified_iur/lib/unified_iur/widgets/data.ex— IUR constructorpackages/unified_iur/test/unified_iur/widgets/data_test.exs— IUR tests (21 new + 1 inline assertion)packages/unified_ui/lib/unified_ui/widget_components.ex— catalog entrypackages/unified_ui/test/unified_ui/widget_components_catalog_test.exs— catalog test updated (also fixes pre-existing failures from thread_card/file_tree_browser/composer_inline_ask/ask_sidebar catalog additions that weren't reflected in the testPre-existing test failures (not caused by this PR)
The following failures existed on HEAD before this PR:
🤖 Generated with Claude Code
EOF
)