203 lines
13 KiB
HTML
203 lines
13 KiB
HTML
{{define "board.html"}}
|
||
{{template "shell-start" .}}
|
||
{{$filter := .BoardFilter}}
|
||
<header class="page-head board-page-head">
|
||
<div><p class="eyebrow">SHARED WORKSPACE</p><h1>Team board</h1><p>Plan, assign, and move work forward together.</p></div>
|
||
<div class="board-head-actions">
|
||
<details class="board-filter-menu">
|
||
<summary class="button secondary">⌕ Filters{{if $filter.Active}} <span>{{$filter.Count}}</span>{{end}}</summary>
|
||
<div class="board-filter-popover">
|
||
<header><div><p class="eyebrow">BOARD VIEW</p><h2>Filters{{if $filter.Active}} ({{$filter.Count}}){{end}}</h2></div>{{if $filter.Active}}<a href="/board">Clear all</a>{{end}}</header>
|
||
<form method="get" action="/board">
|
||
<ul>
|
||
<li><label><span>Tag</span><select name="tag" aria-label="Filter by tag">
|
||
<option value="">All tags</option>
|
||
{{range .BoardTags}}<option value="{{.ID}}" {{if eq $filter.TagID .ID}}selected{{end}}>{{.Name}}</option>{{end}}
|
||
</select></label></li>
|
||
<li><label><span>Assignee</span><select name="assignee" aria-label="Filter by assignee">
|
||
<option value="">Everyone</option>
|
||
{{range .Users}}<option value="{{.ID}}" {{if eq $filter.AssigneeID .ID}}selected{{end}}>{{.DisplayName}}</option>{{end}}
|
||
</select></label></li>
|
||
<li><label><span>Priority</span><select name="priority" aria-label="Filter by priority">
|
||
<option value="">All priorities</option>
|
||
<option value="urgent" {{if eq $filter.Priority "urgent"}}selected{{end}}>Urgent</option>
|
||
<option value="high" {{if eq $filter.Priority "high"}}selected{{end}}>High</option>
|
||
<option value="normal" {{if eq $filter.Priority "normal"}}selected{{end}}>Normal</option>
|
||
<option value="low" {{if eq $filter.Priority "low"}}selected{{end}}>Low</option>
|
||
</select></label></li>
|
||
</ul>
|
||
<button class="button primary full" type="submit">Apply filters</button>
|
||
</form>
|
||
</div>
|
||
</details>
|
||
<details class="tag-manager-panel">
|
||
<summary class="button secondary">◉ Manage tags</summary>
|
||
<div class="tag-manager">
|
||
<div><p class="eyebrow">BOARD LABELS</p><h2>Tag manager</h2><p>Create reusable labels for every card.</p></div>
|
||
<form method="post" action="/board/tags" class="tag-create-form">
|
||
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
||
<label>Tag name<input name="name" required maxlength="40" placeholder="e.g. Backend"></label>
|
||
<label>Color<select name="color"><option value="green">Green</option><option value="blue">Blue</option><option value="red">Red</option><option value="amber">Amber</option><option value="purple">Purple</option><option value="slate">Slate</option></select></label>
|
||
<button class="button primary" type="submit">Add tag</button>
|
||
</form>
|
||
<div class="tag-manager-list">
|
||
{{range .BoardTags}}
|
||
<div><span class="board-tag {{.Color}}">{{.Name}}</span><details class="tag-delete"><summary>Delete</summary><form method="post" action="/board/tags/{{.ID}}/delete"><input type="hidden" name="csrf" value="{{$.CSRF}}"><button class="text-button" type="submit">Confirm</button></form></details></div>
|
||
{{else}}<p>No tags yet. Create the first one above.</p>{{end}}
|
||
</div>
|
||
</div>
|
||
</details>
|
||
<details class="new-task-panel" {{if .Error}}open{{end}}>
|
||
<summary class="button primary">+ Add task</summary>
|
||
<form method="post" action="/board/tasks" class="new-task-form">
|
||
<input type="hidden" name="csrf" value="{{.CSRF}}">
|
||
<div class="new-task-form-head"><div><p class="eyebrow">NEW CARD</p><h2>Add work to the board</h2></div></div>
|
||
<label>Task title<input name="title" required maxlength="160" autofocus placeholder="What needs to be done?"></label>
|
||
<label>Description <small>Optional</small><textarea name="description" rows="4" maxlength="4000" placeholder="Add context, acceptance criteria, or links…"></textarea></label>
|
||
<fieldset class="card-tag-picker">
|
||
<legend>Tags <small>Optional · select multiple</small></legend>
|
||
<div class="tag-options">
|
||
{{range .BoardTags}}<label><input type="checkbox" name="tag_ids" value="{{.ID}}"><span class="board-tag {{.Color}}">{{.Name}}</span></label>
|
||
{{else}}<p class="tag-picker-empty">No tags yet. Create the first one below.</p>{{end}}
|
||
</div>
|
||
<details class="inline-tag-creator">
|
||
<summary>+ Create a new tag</summary>
|
||
<div class="inline-tag-fields">
|
||
<label>Tag name<input name="new_tag_name" maxlength="40" placeholder="e.g. Backend"></label>
|
||
<label>Color<select name="new_tag_color"><option value="green">Green</option><option value="blue">Blue</option><option value="red">Red</option><option value="amber">Amber</option><option value="purple">Purple</option><option value="slate">Slate</option></select></label>
|
||
</div>
|
||
<small>The new tag will be created and added to this card.</small>
|
||
</details>
|
||
</fieldset>
|
||
<fieldset class="assignee-picker">
|
||
<legend>Assignees <small>Optional · select multiple</small></legend>
|
||
<div>{{range .Users}}<label><input type="checkbox" name="assignee_ids" value="{{.ID}}"><span><i class="avatar">{{initial .DisplayName}}</i>{{.DisplayName}}</span></label>{{end}}</div>
|
||
</fieldset>
|
||
<div class="form-row">
|
||
<label>Importance<select name="importance"><option value="normal">Normal</option><option value="low">Low</option><option value="high">High</option><option value="urgent">Urgent</option></select></label>
|
||
<label>Column<select name="status"><option value="backlog">Backlog</option><option value="in_progress">In progress</option><option value="blocked">Blocked</option><option value="done">Done</option></select></label>
|
||
</div>
|
||
<label>Due date <small>Optional · Persian</small><span class="jalali-field"><input name="due_date" data-jalali-picker autocomplete="off" inputmode="numeric" placeholder="{{.TodayJalali}}" pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}"><button type="button" class="jalali-trigger" aria-label="Choose due date" title="Open Persian calendar">▦</button></span></label>
|
||
<button class="button dark full" type="submit">Create task</button>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
</header>
|
||
{{template "notice" .}}
|
||
|
||
<div class="kanban-board" data-board data-csrf="{{.CSRF}}">
|
||
{{range .Board}}
|
||
<section class="kanban-column {{.Status}}" data-board-column="{{.Status}}">
|
||
<header class="kanban-column-head">
|
||
<div><span class="column-dot"></span><strong>{{.Title}}</strong><small>{{.Hint}}</small></div>
|
||
<b>{{len .Tasks}}</b>
|
||
</header>
|
||
<div class="kanban-cards" data-drop-zone="{{.Status}}">
|
||
{{range .Tasks}}
|
||
{{$task := .}}
|
||
<article class="kanban-card" draggable="true" data-task-id="{{.ID}}">
|
||
{{if .Tags}}<div class="card-tags">{{range .Tags}}<span class="board-tag {{.Color}}">{{.Name}}</span>{{end}}</div>{{end}}
|
||
<div class="card-topline"><span class="task-id">#{{.ID}}</span><span class="card-signals"><span class="importance-badge {{.Importance}}">{{if eq .Importance "urgent"}}Urgent{{else if eq .Importance "high"}}High{{else if eq .Importance "low"}}Low{{else}}Normal{{end}}</span>{{if .DueDate}}<span class="task-due">Due {{dateFA .DueDate}}</span>{{end}}</span></div>
|
||
<h3>{{.Title}}</h3>
|
||
{{if .Description}}<p>{{.Description}}</p>{{end}}
|
||
<div class="task-meta">
|
||
{{if .Assignees}}<span class="task-assignees">{{range .Assignees}}<span class="task-assignee"><i class="avatar">{{initial .DisplayName}}</i><span>{{.DisplayName}}</span></span>{{end}}</span>{{else}}<span class="task-assignee unassigned"><i>?</i><span>Unassigned</span></span>{{end}}
|
||
<span class="task-creator">by {{.CreatorName}}</span>
|
||
</div>
|
||
<details class="card-controls">
|
||
<summary><span>Card controls</span><i>⌄</i></summary>
|
||
<div class="card-controls-body">
|
||
<details class="card-detail-editor">
|
||
<summary>People & importance</summary>
|
||
<form method="post" action="/board/tasks/{{.ID}}/details">
|
||
<input type="hidden" name="csrf" value="{{$.CSRF}}">
|
||
<fieldset class="compact-assignee-picker">
|
||
<legend>Assignees</legend>
|
||
<div>{{range $.Users}}<label><input type="checkbox" name="assignee_ids" value="{{.ID}}" {{if hasUser $task.Assignees .ID}}checked{{end}}><span><i class="avatar">{{initial .DisplayName}}</i>{{.DisplayName}}</span></label>{{end}}</div>
|
||
</fieldset>
|
||
<label>Importance<select name="importance"><option value="low" {{if eq $task.Importance "low"}}selected{{end}}>Low</option><option value="normal" {{if eq $task.Importance "normal"}}selected{{end}}>Normal</option><option value="high" {{if eq $task.Importance "high"}}selected{{end}}>High</option><option value="urgent" {{if eq $task.Importance "urgent"}}selected{{end}}>Urgent</option></select></label>
|
||
<button class="button primary full" type="submit">Save details</button>
|
||
</form>
|
||
</details>
|
||
{{if $.BoardTags}}
|
||
<details class="card-tag-editor">
|
||
<summary>Labels</summary>
|
||
<form method="post" action="/board/tasks/{{.ID}}/tags">
|
||
<input type="hidden" name="csrf" value="{{$.CSRF}}">
|
||
<div>{{range $.BoardTags}}<label><input type="checkbox" name="tag_ids" value="{{.ID}}" {{if hasTag $task.Tags .ID}}checked{{end}}><span class="board-tag {{.Color}}">{{.Name}}</span></label>{{end}}</div>
|
||
<button class="button primary full" type="submit">Save labels</button>
|
||
</form>
|
||
</details>
|
||
{{end}}
|
||
<div class="task-actions">
|
||
<form method="post" action="/board/tasks/{{.ID}}/move">
|
||
<input type="hidden" name="csrf" value="{{$.CSRF}}">
|
||
<select name="status" aria-label="Move task">
|
||
<option value="backlog" {{if eq .Status "backlog"}}selected{{end}}>Backlog</option>
|
||
<option value="in_progress" {{if eq .Status "in_progress"}}selected{{end}}>In progress</option>
|
||
<option value="blocked" {{if eq .Status "blocked"}}selected{{end}}>Blocked</option>
|
||
<option value="done" {{if eq .Status "done"}}selected{{end}}>Done</option>
|
||
</select>
|
||
<button class="text-button task-move-button" type="submit">Move</button>
|
||
</form>
|
||
{{if or (eq .CreatorID $.User.ID) (eq $.User.Role "admin")}}
|
||
<div class="task-lifecycle-actions">
|
||
<form method="post" action="/board/tasks/{{.ID}}/archive">
|
||
<input type="hidden" name="csrf" value="{{$.CSRF}}">
|
||
<button class="text-button archive-task" type="submit">Archive</button>
|
||
</form>
|
||
<details class="task-remove">
|
||
<summary>Delete</summary>
|
||
<form method="post" action="/board/tasks/{{.ID}}/delete">
|
||
<input type="hidden" name="csrf" value="{{$.CSRF}}">
|
||
<button class="text-button" type="submit">Delete permanently</button>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
</details>
|
||
</article>
|
||
{{end}}
|
||
{{if not .Tasks}}<div class="kanban-empty"><span>{{if $filter.Active}}No matching cards{{else}}Drop tasks here{{end}}</span></div>{{end}}
|
||
</div>
|
||
</section>
|
||
{{end}}
|
||
</div>
|
||
{{if .ArchivedTasks}}
|
||
<details class="archived-cards-panel">
|
||
<summary>Archived cards <span>{{len .ArchivedTasks}}</span></summary>
|
||
<div class="archived-card-list">
|
||
{{range .ArchivedTasks}}
|
||
<article class="archived-card">
|
||
<div>
|
||
{{if .Tags}}<div class="card-tags">{{range .Tags}}<span class="board-tag {{.Color}}">{{.Name}}</span>{{end}}</div>{{end}}
|
||
<span class="task-id">#{{.ID}} · {{.Status}}</span>
|
||
<h3>{{.Title}}</h3>
|
||
<small>Originally created by {{.CreatorName}}</small>
|
||
</div>
|
||
{{if or (eq .CreatorID $.User.ID) (eq $.User.Role "admin")}}
|
||
<div class="archived-card-actions">
|
||
<form method="post" action="/board/tasks/{{.ID}}/restore">
|
||
<input type="hidden" name="csrf" value="{{$.CSRF}}">
|
||
<button class="button secondary" type="submit">Restore</button>
|
||
</form>
|
||
<details class="archived-delete">
|
||
<summary class="text-button">Delete</summary>
|
||
<form method="post" action="/board/tasks/{{.ID}}/delete">
|
||
<input type="hidden" name="csrf" value="{{$.CSRF}}">
|
||
<button class="text-button" type="submit">Delete permanently</button>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
{{end}}
|
||
</article>
|
||
{{end}}
|
||
</div>
|
||
</details>
|
||
{{end}}
|
||
<script src="/static/board.js" defer></script>
|
||
{{template "shell-end" .}}
|
||
{{end}}
|