vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Standardize filter rows and add tag selection to the code page
55615c7a4b8472f8bfccab8048f608978d389821 · Keenan Nemetz · 11d ago · parent 3a068983
Standardize filter rows and add tag selection to the code page The code page kept its branch picker in the header actions, had no tag picker, and left every list page to shape its own filters: search inputs ranged from 10rem to 18rem, some selects had a visible label and some did not, and text searches submitted through a Filter button, a Search button, or Enter alone while selects sometimes waited for a click. - One .filters row on issues, requests, activity, the code page and code search. One --search-w (18rem) for page and global search, a visible label on every filter select, auto-apply on select change, and one icon-and-Search button for text. - The code page puts its search, branch picker and new tag picker on the shared row under the header. The tag picker lists tags newest first and leaves the branch picker unclaimed when a tag is open. - data-autosubmit uses requestSubmit() so htmx swaps the filtered pane instead of a full page load. Checks: ./vole workflow check; ./vole workflow run verify.
server/web/templates/issues.html +9−9
| @@ -21,28 +21,28 @@ | |||
| 21 | 21 | <a class="chip{{if eq .State "all"}} active{{end}}" href="/r/{{.Name}}/issues?state=all{{if .Filter.Query}}&q={{urlquery .Filter.Query}}{{end}}{{if .Filter.Label}}&label={{urlquery .Filter.Label}}{{end}}{{if .Filter.Assignee}}&assignee={{urlquery .Filter.Assignee}}{{end}}">All <span class="chip-count">{{.Total}}</span></a> | |
| 22 | 22 | </div> | |
| 23 | 23 | ||
| 24 | <form method="get" action="/r/{{.Name}}/issues" class="filters" hx-get="/r/{{.Name}}/issues" hx-target="#issue-list" hx-swap="outerHTML" hx-push-url="true"> | ||
| 24 | <form method="get" action="/r/{{.Name}}/issues" class="filters" role="search" hx-get="/r/{{.Name}}/issues" hx-target="#issue-list" hx-swap="outerHTML" hx-push-url="true"> | ||
| 25 | 25 | <input type="hidden" name="state" value="{{.State}}"> | |
| 26 | <input name="q" type="search" placeholder="Search title and body" value="{{.Filter.Query}}"> | ||
| 26 | <input name="q" type="search" placeholder="Search title and body" aria-label="Search title and body" value="{{.Filter.Query}}"> | ||
| 27 | <button type="submit">{{icon "search"}}Search</button> | ||
| 27 | 28 | {{if .Labels}} | |
| 28 | 29 | <label class="filter-field"> | |
| 29 | <span class="filter-label">Labels</span> | ||
| 30 | <select name="label"> | ||
| 31 | <option value="">all labels</option> | ||
| 30 | <span class="filter-label">Label</span> | ||
| 31 | <select name="label" data-autosubmit> | ||
| 32 | <option value="">All</option> | ||
| 32 | 33 | {{range .Labels}}<option value="{{.}}"{{if eq . $.Filter.Label}} selected{{end}}>{{.}}</option>{{end}} | |
| 33 | 34 | </select> | |
| 34 | 35 | </label> | |
| 35 | 36 | {{end}} | |
| 36 | 37 | {{if .Assignees}} | |
| 37 | 38 | <label class="filter-field"> | |
| 38 | <span class="filter-label">Assignees</span> | ||
| 39 | <select name="assignee"> | ||
| 40 | <option value="">all assignees</option> | ||
| 39 | <span class="filter-label">Assignee</span> | ||
| 40 | <select name="assignee" data-autosubmit> | ||
| 41 | <option value="">All</option> | ||
| 41 | 42 | {{range .Assignees}}<option value="{{.}}"{{if eq . $.Filter.Assignee}} selected{{end}}>@{{.}}</option>{{end}} | |
| 42 | 43 | </select> | |
| 43 | 44 | </label> | |
| 44 | 45 | {{end}} | |
| 45 | <button type="submit">{{icon "sliders-horizontal"}}Filter</button> | ||
| 46 | 46 | {{if .Filtered}}<a class="button secondary" href="/r/{{.Name}}/issues" hx-get="/r/{{.Name}}/issues" hx-target="#issue-list" hx-swap="outerHTML" hx-push-url="true">{{icon "x"}}Clear</a>{{end}} | |
| 47 | 47 | </form> | |
| 48 | 48 | ||