m's bug (verbatim from /views): "we cant edit views yet. and the filters on custom views dont seem to work. No apply button and no instant apply" Two distinct gaps, both surgically fixed. ## Gap 1 — edit UI missing Slice D shipped POST /views/<id> (update) but no GET form to drive it. The index page had delete + redirect-open links only. Fix: - New handleViewEdit serves GET /views/<id>/edit with the form pre-filled from the persisted row. - New templates/view_edit.tmpl mirrors the create form, selecting the current values on each <select>, populating each <input value="">. - filterJSONToQuery rebuilds the URL-query representation of filter_json so the `filter_query` text input round-trips on edit. - /views index row gets an "edit" link next to delete. - Route registered before the catch-all GET /views/ so the more specific pattern wins. handleViewRedirect also defensively forwards /edit suffix in case routing falls through. ## Gap 2 — URL chips clobbered by saved-view filter applySavedView did `*filter = filterFromJSONPayload(payload)` — wholesale replace. URL chip params parsed earlier in handleTree were thrown away. Compounded by chip URLs not preserving `?view=<id>`, so even if the overlay had worked, chip clicks would have stripped the saved view. Fix: - TreeFilter grows a `ViewID` field that round-trips through ParseTreeFilter + QueryString. Not a "filter dimension" in the matching sense (Matches ignores it); just a URL anchor that every chip URL emits forward. - applySavedView builds the saved filter, then overlayURLFields() selectively replaces any dimension the user set via URL chip on top (q/tag/mgmt/status/has/show-archived/public/project/project_descendants). - view_type: URL wins when explicitly set, saved value otherwise. - Drift is transient — URL bookmarkable as a "narrowed saved view" without auto-saving back to the row. To persist, user opens /edit. ## Tests - TestViewEditFlow — GET /<id>/edit pre-fills name + filter_query; POST /<id> updates name + view_type + filter_json round-trip in DB. - TestSavedViewPageFilterApply — seed two items + an empty saved view; /?view=<id> shows both; /?view=<id>&tag=work shows only the work one. Also asserts chip URLs contain view=<id> so navigation stays in the saved view. Out of scope (per brief): - No schema changes. - No view sharing / multi-user. - HTMX modal save UI deferred — the existing inline edit page is the surgical fix m's bug actually needs.
43 lines
1.9 KiB
Cheetah
43 lines
1.9 KiB
Cheetah
{{define "content"}}
|
|
<h1>Edit view</h1>
|
|
<p class="muted"><a href="/views">← back to views</a></p>
|
|
|
|
<section class="views-create">
|
|
<form method="post" action="/views/{{.View.ID}}">
|
|
<label>Name <input type="text" name="name" required maxlength="80" value="{{.View.Name}}"></label>
|
|
<label>Description <input type="text" name="description" maxlength="200" value="{{.View.Description}}"></label>
|
|
<label>View type
|
|
<select name="view_type" required>
|
|
{{$cur := .View.ViewType}}
|
|
{{range .AllViewTypes}}<option value="{{.}}"{{if eq . $cur}} selected{{end}}>{{.}}</option>{{end}}
|
|
</select>
|
|
</label>
|
|
<label>Default for
|
|
<select name="is_default_for">
|
|
{{$d := deref .View.IsDefaultFor}}
|
|
{{range .DefaultForOptions}}<option value="{{.}}"{{if eq . $d}} selected{{end}}>{{if eq . ""}}—{{else}}{{.}}{{end}}</option>{{end}}
|
|
</select>
|
|
</label>
|
|
<label>Group by
|
|
<select name="group_by">
|
|
{{$g := deref .View.GroupBy}}
|
|
{{range .GroupByOptions}}<option value="{{.}}"{{if eq . $g}} selected{{end}}>{{if eq . ""}}—{{else}}{{.}}{{end}}</option>{{end}}
|
|
</select>
|
|
</label>
|
|
<label>Sort field <input type="text" name="sort_field" placeholder="title / updated_at / start_time" maxlength="40" value="{{deref .View.SortField}}"></label>
|
|
<label>Sort dir
|
|
<select name="sort_dir">
|
|
{{$sd := deref .View.SortDir}}
|
|
{{range .SortDirOptions}}<option value="{{.}}"{{if eq . $sd}} selected{{end}}>{{if eq . ""}}—{{else}}{{.}}{{end}}</option>{{end}}
|
|
</select>
|
|
</label>
|
|
<label><input type="checkbox" name="pinned" value="1"{{if .View.Pinned}} checked{{end}}> Pinned</label>
|
|
<label>Filter (URL query form)
|
|
<input type="text" name="filter_query" placeholder="tag=work&mgmt=mai" value="{{.FilterQuery}}">
|
|
</label>
|
|
<button type="submit">Save changes</button>
|
|
<a class="muted" href="/views">cancel</a>
|
|
</form>
|
|
</section>
|
|
{{end}}
|