Skip to content

feat(live_ui): add needs_you_section + blocker_row canonical widgets (Wave 3.7-B)#134

Draft
ty13r wants to merge 2 commits into
mainfrom
claude/widget-needs-you-section-wave-3-7-b
Draft

feat(live_ui): add needs_you_section + blocker_row canonical widgets (Wave 3.7-B)#134
ty13r wants to merge 2 commits into
mainfrom
claude/widget-needs-you-section-wave-3-7-b

Conversation

@ty13r
Copy link
Copy Markdown
Member

@ty13r ty13r commented May 18, 2026

Summary

Two new canonical widgets completing all 4 stages of the pipeline, implementing the needs_you_section attention band and its companion blocker_row row element.

Scope: This PR implements BOTH widgets as separate canonical kinds (Stage 1-4 each), per the spec proposal that treats blocker_row as a first-class row widget rather than a sub-template of needs_you_section.

Widgets added

needs_you_section (family: :workflow_progress_and_status)

An attention band that lists operator-facing blocker rows. Renders a <section> with:

  • Configurable title (default: "Needs you") and empty-state text
  • Ordered list of blocker_row children passed as Element.t() items
  • Overflow "show N more" button when max_visible is exceeded
  • data-live-ui-widget="needs-you-section" marker

blocker_row (family: :row_and_artifact)

A single actionable row inside a needs_you_section. Renders as a <button> with:

  • Actor avatar (initials, decorative)
  • Ask text + scope label body
  • Jump arrow action affordance
  • data-live-ui-widget="blocker-row" + data-row-id + data-severity markers
  • Unique LiveComponent ID via "blocker-row-#{row_id}" fallback (prevents duplicate ID crash when multiple rows render)

4-stage pipeline

Stage File Change
1 - IUR constructor packages/unified_iur/lib/unified_iur/widgets/components.ex :needs_you_section to @workflow_kinds; :blocker_row to @row_artifact_kinds; two constructors
2 - catalog packages/unified_ui/lib/unified_ui/widget_components.ex Two entries appended after :command_palette
3 - renderer clause packages/live_ui/lib/live_ui/renderer.ex Two clauses inserted above @component_kinds generic fallback
4 - component modules packages/live_ui/lib/live_ui/widgets/needs_you_section.ex + blocker_row.ex; navigation.ex New Phoenix.Component modules; both registered in @modules

Tests

  • 17 new UnifiedIUR.Widgets.NeedsYouSectionTest (Stage 1 constructors, kinds, defaults, actor, children)
  • 15 new LiveUi.NeedsYouSectionTest (Stage 4 render: widget markers, empty state, items, overflow, aria-label, severity class, initials, round-trip smoke)
  • 4 updated hardcoded kind-list assertions in components_test.exs, widget_components_catalog_test.exs, fixtures_test.exs

All 46 new/modified tests pass (0 failures). Remaining failures (parity sync, documentation surface cwd, validation tooling) are pre-existing on main and confirmed not introduced by this PR.

Implementation decisions (no Pascal-decision needed)

  • actor uses nil default (not %{}) because merge_attribute/3 silently drops empty maps - test verifies refute Map.has_key?(row.attributes, :actor) when no actor provided
  • blocker_row renderer clause uses "blocker-row-#{row_id_attr}" as fallback ID to keep LiveComponent IDs unique across multiple rows in one section
  • Items in NeedsYouSection.component are received as Element.t() structs from children, rendered via LiveUi.Renderer.render element={item} - not plain maps

Open questions for Pascal review

Q1 - actor struct shape: Currently blocker_row accepts actor: %{initials: "AB", label: "..."}. Should this use the canonical :identity attribute shape from avatar/presence_dot, or keep a flat actor map?

Q2 - overflow strategy: max_visible is modeled as an integer default 5. Implementation uses CSS-only slice + visibility. Should it use JS-driven expand behavior (requires a phx-click event + assigns toggle) or stay CSS-only for the DRAFT?

Q3 - severity token mapping: Currently severity is a string ("info" / "warning" / "error") mapped to a CSS data-attr. Should it map through the canonical tone system (:info / :warning / :danger atoms)?

Q4 - scope_intent atom vs string: scope_intent defaults to "jump_to_blocker" as a string. Should it be an atom like other intent fields?

Q5 - family placement: needs_you_section is in :workflow_progress_and_status. Would :layer_shell_and_callout be more appropriate given it is typically a persistent overlay strip?

Q6 - blocker_row as separate kind: The spec proposal suggests two separate widgets. This PR implements that. Pascal should confirm whether blocker_row should remain a standalone IUR kind or be collapsed into a template slot of needs_you_section.

Pre-flight grep results

All four stages were fully absent on main before authoring:

  • git grep -n "kind: :needs_you_section" - 0 results
  • git grep -n "kind: :blocker_row" - 0 results
  • git grep -n "NeedsYouSection" - 0 results
  • git grep -n "BlockerRow" - 0 results

Generated with Claude Sonnet 4.6 - Wave AshUI-3.7-B sub-agent dispatch

ty13r and others added 2 commits May 18, 2026 02:16
…(Wave 3.7-B, DRAFT)

Two new canonical widgets implementing the full 4-stage pipeline
(IUR constructor → unified_ui catalog → live_ui renderer clause →
Phoenix.Component module).

needs_you_section (workflow_progress_and_status family):
- Attention band listing operator-facing blockers
- Renders a scrollable list of blocker_row children with title, empty
  state, and overflow "show N more" button
- Accepts :title, :empty_state_text, :max_visible opts; children are
  blocker_row Elements

blocker_row (row_and_artifact family):
- Single actionable row: actor avatar + ask text + scope label + jump arrow
- Unique LiveComponent IDs via "blocker-row-#{row_id}" fallback to prevent
  duplicate-ID crash when multiple rows render in one section
- :actor attribute uses nil default (not %{}) because merge_attribute drops
  empty maps silently

Stage 1: UnifiedIUR.Widgets.Components — :needs_you_section added to
  @workflow_kinds, :blocker_row added to @row_artifact_kinds; constructors
  with normalize_opts + maybe_put + build_component
Stage 2: UnifiedUi.WidgetComponents catalog — two entries appended
Stage 3: LiveUi.Renderer — dedicated clauses inserted above @component_kinds
  generic fallback
Stage 4: LiveUi.Widgets.{NeedsYouSection,BlockerRow} Phoenix.Component
  modules; both registered in LiveUi.Widgets.Navigation @modules

Tests: 32 new tests (17 unified_iur constructor, 15 live_ui render);
  4 hardcoded catalog tests updated to include new kinds.

Open questions for Pascal review:
  Q1: avatar in blocker_row — use :actor struct or :initials/:label opt?
  Q2: scroll/overflow strategy — CSS-only clamp or max_visible JS?
  Q3: severity tokens — map to :warning/:error/:info or keep as string?
  Q4: scope_intent atom vs string?
  Q5: needs_you_section family — :workflow or :layer_callout?
  Q6: blocker_row — separate kind vs sub-element of needs_you_section?
    (implemented here as separate top-level widget per spec proposal)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Apply registry-threading discipline per the updated widget skill
(project-ariston PR #62 + memory entry [[new-canonical-widget-needs-
registry-threading]]). Mirrors Pascal's a902750 (PresenceDot) pattern.

Touch points (delta): widgets aggregation + both adapters + multi-layer
tests — for both kinds.

- widgets.ex: add :workflow + :row_and_artifact to @type family + families/0;
  add workflow_modules/0 + row_and_artifact_modules/0; wire into modules/0
- widgets/workflow.ex: new per-family aggregation module (NeedsYouSection)
- widgets/row_and_artifact.ex: new per-family aggregation module (BlockerRow)
- widgets/navigation.ex: remove NeedsYouSection + BlockerRow (moved to
  correct per-family modules)
- iur_adapter.ex: add base_attributes/2 clauses for :needs_you_section
  (:workflow_progress_and_status family, :section attrs) and :blocker_row
  (:row_and_artifact family, :blocker + :actor attrs)
- live_ui_adapter.ex: add generate_heex/2 fallback clauses for both kinds
- needs_you_section_test.exs: family-exposure tests for both kinds
- renderer_test.exs: renderer clause tests for needs_you_section (with items
  + empty state) and blocker_row
- phase_31_canonical_conversion_test.exs: both kinds added to @component_samples
- phase_31_runtime_adapter_test.exs: adapter dispatch tests for both kinds

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant