Files
projax/web/templates/project_chip.tmpl
mAi 13923aadb6 feat(views): Phase 5i slice A — project filter dim + descendants toggle
m's Q5 pick (2026-05-26): project scope on every Views-supporting page,
with descendants exposed as an explicit on/off chip toggle rather than
always-on. Slice A ships the smallest standalone piece of the Views
system; slices B–E (view_type URL param, kanban, saved-views schema,
defaults) follow on the same branch.

TreeFilter grows two fields:
- ProjectPath: scoped item's primary path; "" = no filter.
- IncludeDescendants: default true; flipped via ?project_descendants=0.

Matching extends to path-prefix across `it.Paths` when ProjectPath is
set; equality-only when IncludeDescendants is off. Multi-parent items
pass when ANY of their paths qualifies.

Picker is a shared partial (templates/project_chip.tmpl) that every
Views-supporting filter strip includes (tree, dashboard, timeline,
calendar). Two states: <select> picker when no project is set; active
chip with × clear + descendants on/off chip when scoped. Hidden
inputs added to each form so non-picker chip clicks preserve the
project state. Graph and admin tools are NOT Views consumers (per
design.md / docs/plans/views-system.md §5) and stay untouched.

Test-source edits (per the 5c sharpened rule):
- dashboard_test.go, public_listing_test.go, timeline_test.go: row
  membership assertions tightened from `Contains(body, slug)` to
  `Contains(body, href="/i/path")`. The picker now renders every
  item's primary path inside a <select>, so coarse slug substring
  matches falsely passed across filtered-out picker options. Behaviour
  preserved (filtered rows still don't render); the impl-detail
  assertion moved to the row link.

New tests: TestProjectFilterIncludesDescendants,
TestProjectFilterDescendantsOff, TestParseTreeFilterProjectFields,
TestTreeFilterProjectRoundTrip, TestSetProjectAndToggleHelpers,
TestProjectFilterScopesTreeToDescendants (end-to-end via /).
2026-05-26 13:27:37 +02:00

59 lines
2.7 KiB
Cheetah
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{{/*
Phase 5i Slice A — shared project-scope chip + picker.
Rendered inside the tagbar on every Views-supporting page (tree, dashboard,
timeline, calendar). Two visual states:
ProjectPath == "" → <select> picker with all items by primary path
ProjectPath != "" → active chip with × clear + descendants on/off toggle
Each caller passes a top-level page-data map with:
Filter — TreeFilter
Projects — []ParentOption (sorted by path)
BasePath — page route, e.g. "/", "/dashboard", "/timeline", "/calendar"
ProjectChipTarget — HTMX target selector, e.g. "#tree-section"
m's Q5 pick (2026-05-26): descendants toggle is on by default but exposed
explicitly on the chip, not always-on.
*/}}
{{define "view-project-chip"}}
<div class="chip-row project-chip-row">
<span class="muted">project:</span>
{{if .Filter.ProjectPath}}
{{$cleared := (.Filter.SetProject "").URLOn .BasePath}}
{{$toggled := .Filter.ToggleIncludeDescendants.URLOn .BasePath}}
<span class="proj-chip chip-on" title="Scoped to {{.Filter.ProjectPath}}">
<span class="proj-name">{{.Filter.ProjectPath}}</span>
<a class="proj-clear"
href="{{$cleared}}"
hx-get="{{$cleared}}" hx-target="{{.ProjectChipTarget}}" hx-swap="outerHTML" hx-push-url="true"
title="Clear project scope">×</a>
</span>
<a class="proj-desc-chip {{if .Filter.IncludeDescendants}}chip-on{{end}}"
href="{{$toggled}}"
hx-get="{{$toggled}}" hx-target="{{.ProjectChipTarget}}" hx-swap="outerHTML" hx-push-url="true"
title="Include descendants of {{.Filter.ProjectPath}} in scope">
descendants {{if .Filter.IncludeDescendants}}on{{else}}off{{end}}
</a>
{{else}}
<form class="proj-picker"
hx-get="{{.BasePath}}"
hx-target="{{.ProjectChipTarget}}"
hx-swap="outerHTML"
hx-trigger="change from:select"
hx-push-url="true">
{{if .Filter.Q}}<input type="hidden" name="q" value="{{.Filter.Q}}">{{end}}
{{if .Filter.Tags}}<input type="hidden" name="tag" value="{{join "," .Filter.Tags}}">{{end}}
{{if .Filter.Management}}<input type="hidden" name="mgmt" value="{{join "," .Filter.Management}}">{{end}}
{{if ne (join "," .Filter.Status) "active"}}<input type="hidden" name="status" value="{{join "," .Filter.Status}}">{{end}}
{{if .Filter.HasLinks}}<input type="hidden" name="has" value="{{join "," .Filter.HasLinks}}">{{end}}
{{if .Filter.ShowArchived}}<input type="hidden" name="show-archived" value="1">{{end}}
<select name="project" autocomplete="off">
<option value="">— any —</option>
{{range .Projects}}<option value="{{.Path}}">{{.Path}}</option>{{end}}
</select>
</form>
{{end}}
</div>
{{end}}