This repository has no description
1{{ define "repo/fragments/editLabelPanel" }}
2 <form
3 id="edit-label-panel"
4 hx-put="/{{ .RepoInfo.FullName }}/labels/perform"
5 hx-indicator="#spinner"
6 hx-disabled-elt="#save-btn,#cancel-btn"
7 hx-swap="none"
8 class="flex flex-col gap-6"
9 >
10 <input type="hidden" name="repo" value="{{ .RepoInfo.RepoAt }}">
11 <input type="hidden" name="subject" value="{{ .Subject }}">
12 {{ template "editBasicLabels" . }}
13 {{ template "editKvLabels" . }}
14 {{ template "editLabelPanelActions" . }}
15 <div id="add-label-error" class="text-red-500 dark:text-red-400"></div>
16 </form>
17{{ end }}
18
19{{ define "editBasicLabels" }}
20 {{ $defs := .Defs }}
21 {{ $subject := .Subject }}
22 {{ $state := .State }}
23 {{ $prefix := .Prefix }}
24 {{ $labelStyle := "flex items-center gap-2 rounded py-1 px-2 border border-gray-200 dark:border-gray-700 text-sm bg-white dark:bg-gray-800 text-black dark:text-white" }}
25 {{ $hasNullDefs := false }}
26 {{ range $k, $d := $defs }}
27 {{ if $d.ValueType.IsNull }}{{ $hasNullDefs = true }}{{ end }}
28 {{ end }}
29 <div>
30 {{ template "repo/fragments/labelSectionHeaderText" "Labels" }}
31
32 <div class="flex flex-col gap-1 items-start">
33 {{ range $k, $d := $defs }}
34 {{ if $d.ValueType.IsNull }}
35 {{ $isChecked := $state.ContainsLabel $k }}
36 {{ $fieldName := $d.AtUri.String }}
37 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $d.AtUri }}{{ end }}
38 <label class="{{$labelStyle}}">
39 <input type="checkbox" name="{{ $fieldName }}" value="null" {{if $isChecked}}checked{{end}}>
40 {{ template "labels/fragments/labelDef" $d }}
41 </label>
42 {{ end }}
43 {{ end }}
44 {{ if not $hasNullDefs }}
45 <p class="text-gray-500 dark:text-gray-400 text-sm py-1">
46 No labels defined. You can choose default labels or define custom
47 labels in <a class="underline" href="/{{ $.RepoInfo.FullName }}/settings">settings</a>.
48 </p>
49 {{ end }}
50 </div>
51 </div>
52{{ end }}
53
54{{ define "editKvLabels" }}
55 {{ $defs := .Defs }}
56 {{ $subject := .Subject }}
57 {{ $state := .State }}
58 {{ $prefix := .Prefix }}
59 {{ $groupSuffix := "" }}
60 {{ if $prefix }}{{ $groupSuffix = printf "-%s" $prefix }}{{ end }}
61 {{ $labelStyle := "font-normal normal-case flex items-center gap-2 p-0" }}
62
63 {{ range $k, $d := $defs }}
64 {{ if (not $d.ValueType.IsNull) }}
65 {{ $fieldName := $d.AtUri.String }}
66 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $d.AtUri }}{{ end }}
67 {{ $valset := $state.GetValSet $k }}
68 <div id="label-{{$d.Id}}{{ $groupSuffix }}" class="flex flex-col gap-1">
69 {{ if not $d.ValueType.IsBool }}
70 {{ template "repo/fragments/labelSectionHeaderText" $d.Name }}
71 {{ end }}
72 {{ if (and $d.Multiple $d.ValueType.IsEnum) }}
73 <!-- checkbox -->
74 {{ range $variant := $d.ValueType.Enum }}
75 <label class="{{$labelStyle}}">
76 <input type="checkbox" name="{{ $fieldName }}" value="{{$variant}}" {{if $state.ContainsLabelAndVal $k $variant}}checked{{end}}>
77 {{ $variant }}
78 </label>
79 {{ end }}
80 {{ else if $d.Multiple }}
81 <!-- dynamically growing input fields -->
82 {{ range $v, $s := $valset }}
83 {{ template "multipleInputField" (dict "def" $d "value" $v "key" $k "prefix" $prefix) }}
84 {{ else }}
85 {{ template "multipleInputField" (dict "def" $d "value" "" "key" $k "prefix" $prefix) }}
86 {{ end }}
87 {{ template "addFieldButton" (dict "def" $d "prefix" $prefix "groupSuffix" $groupSuffix) }}
88 {{ if and $.LoggedInUser $d.ValueType.IsString $d.ValueType.IsDidFormat }}
89 {{ template "assignToMeButton" (dict "def" $d "user" $.LoggedInUser "groupSuffix" $groupSuffix) }}
90 {{ end }}
91 {{ else if $d.ValueType.IsEnum }}
92 <!-- radio buttons -->
93 {{ $isUsed := $state.ContainsLabel $k }}
94 {{ range $variant := $d.ValueType.Enum }}
95 <label class="{{$labelStyle}}">
96 <input type="radio" name="{{ $fieldName }}" value="{{$variant}}" {{if $state.ContainsLabelAndVal $k $variant}}checked{{end}}>
97 {{ $variant }}
98 </label>
99 {{ end }}
100 <label class="{{$labelStyle}}">
101 <input type="radio" name="{{ $fieldName }}" value="" {{ if not $isUsed }}checked{{ end }}>
102 None
103 </label>
104 {{ else }}
105 <!-- single input field based on value type -->
106 {{ range $v, $s := $valset }}
107 {{ template "valueTypeInput" (dict "def" $d "value" $v "key" $k "prefix" $prefix) }}
108 {{ else }}
109 {{ template "valueTypeInput" (dict "def" $d "value" "" "key" $k "prefix" $prefix) }}
110 {{ end }}
111 {{ end }}
112 </div>
113 {{ end }}
114 {{ end }}
115{{ end }}
116
117{{ define "multipleInputField" }}
118 <div class="flex gap-1 items-stretch">
119 <div class="flex-1 min-w-0">
120 {{ template "valueTypeInput" . }}
121 </div>
122 {{ template "removeFieldButton" }}
123 </div>
124{{ end }}
125
126{{ define "assignToMeButton" }}
127 {{ $def := .def }}
128 {{ $user := .user }}
129 {{ $groupSuffix := .groupSuffix }}
130 {{ $handle := trimPrefix (resolve $user.Did) "@" }}
131 <button type="button"
132 data-assign-to-me="{{ $def.Id }}{{ $groupSuffix }}"
133 data-handle="{{ $handle }}"
134 onclick="(() => {
135 const group = document.getElementById('label-' + this.dataset.assignToMe);
136 const handle = this.dataset.handle;
137 const inputs = group.querySelectorAll('input[type=text]');
138 const empty = Array.from(inputs).find(i => !i.value.trim());
139 if (empty) { empty.value = handle; return; }
140 if (Array.from(inputs).some(i => i.value.trim() === handle)) return;
141 const tpl = document.getElementById('tpl-' + this.dataset.assignToMe);
142 if (!tpl) return;
143 const addBtn = tpl.nextElementSibling;
144 addBtn.insertAdjacentHTML('beforebegin', tpl.innerHTML);
145 const newInput = addBtn.previousElementSibling.querySelector('input[type=text]');
146 if (newInput) newInput.value = handle;
147 })()"
148 class="text-xs text-gray-500 dark:text-gray-400 hover:underline self-end inline-flex items-center gap-1">
149 {{ i "user-round-plus" "size-3.5" }}
150 Assign to me
151 </button>
152{{ end }}
153
154{{ define "addFieldButton" }}
155 {{ $def := .def }}
156 {{ $prefix := .prefix }}
157 {{ $groupSuffix := .groupSuffix }}
158 <div style="display:none" id="tpl-{{ $def.Id }}{{ $groupSuffix }}">
159 {{ template "multipleInputField" (dict "def" $def "value" "" "key" $def.AtUri.String "prefix" $prefix) }}
160 </div>
161 <button type="button" onClick="this.insertAdjacentHTML('beforebegin', document.getElementById('tpl-{{ $def.Id }}{{ $groupSuffix }}').innerHTML)" class="w-full btn flex items-center gap-2">
162 {{ i "plus" "size-4" }} Add
163 </button>
164{{ end }}
165
166{{ define "removeFieldButton" }}
167 <button type="button" onClick="this.parentElement.remove()" class="btn flex items-center gap-2 text-red-400 dark:text-red-500">
168 {{ i "trash-2" "size-4" }}
169 </button>
170{{ end }}
171
172{{ define "valueTypeInput" }}
173 {{ $def := .def }}
174 {{ $valueType := $def.ValueType }}
175 {{ $value := .value }}
176 {{ $key := .key }}
177
178 {{ if $valueType.IsBool }}
179 {{ template "boolTypeInput" $ }}
180 {{ else if $valueType.IsInt }}
181 {{ template "intTypeInput" $ }}
182 {{ else if $valueType.IsString }}
183 {{ template "stringTypeInput" $ }}
184 {{ else if $valueType.IsNull }}
185 {{ template "nullTypeInput" $ }}
186 {{ end }}
187{{ end }}
188
189{{ define "boolTypeInput" }}
190 {{ $def := .def }}
191 {{ $prefix := .prefix }}
192 {{ $fieldName := $def.AtUri.String }}
193 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $def.AtUri }}{{ end }}
194 {{ $value := .value }}
195 {{ $isOn := eq $value "true" }}
196 <label class="font-normal normal-case flex items-center gap-2">
197 <input type="checkbox" name="{{ $fieldName }}" value="true" {{ if $isOn }}checked{{ end }}>
198 {{ $def.Name }}
199 </label>
200{{ end }}
201
202{{ define "intTypeInput" }}
203 {{ $def := .def }}
204 {{ $prefix := .prefix }}
205 {{ $fieldName := $def.AtUri.String }}
206 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $def.AtUri }}{{ end }}
207 {{ $value := .value }}
208 <input class="p-1 w-full" type="number" name="{{$fieldName}}" value="{{$value}}">
209{{ end }}
210
211{{ define "stringTypeInput" }}
212 {{ $def := .def }}
213 {{ $prefix := .prefix }}
214 {{ $fieldName := $def.AtUri.String }}
215 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $def.AtUri }}{{ end }}
216 {{ $valueType := $def.ValueType }}
217 {{ $value := .value }}
218
219 {{ if $valueType.IsDidFormat }}
220 {{ $value = trimPrefix (resolve .value) "@" }}
221 <actor-typeahead>
222 <input
223 autocapitalize="none"
224 autocorrect="off"
225 autocomplete="off"
226 placeholder="user.tngl.sh"
227 value="{{$value}}"
228 name="{{$fieldName}}"
229 type="text"
230 class="p-1 w-full h-full text-sm"
231 />
232 </actor-typeahead>
233 {{ else }}
234 <input class="p-1 w-full" type="text" name="{{$fieldName}}" value="{{$value}}">
235 {{ end }}
236{{ end }}
237
238{{ define "nullTypeInput" }}
239 {{ $def := .def }}
240 {{ $prefix := .prefix }}
241 {{ $fieldName := $def.AtUri.String }}
242 {{ if $prefix }}{{ $fieldName = printf "%s[%s]" $prefix $def.AtUri }}{{ end }}
243 <input class="p-1" type="hidden" name="{{$fieldName}}" value="null">
244{{ end }}
245
246{{ define "editLabelPanelActions" }}
247 <div class="flex gap-2 pt-2">
248 <button
249 id="cancel-btn"
250 type="button"
251 hx-get="/{{ .RepoInfo.FullName }}/label"
252 hx-vals='{"subject": "{{.Subject}}"}'
253 hx-swap="outerHTML"
254 hx-target="#edit-label-panel"
255 class="btn w-1/2 flex items-center gap-2 text-red-500 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300 group">
256 {{ i "x" "size-4" }} Cancel
257 </button>
258
259 <button
260 id="save-btn"
261 type="submit"
262 class="btn w-1/2 flex items-center">
263 <span class="inline-flex gap-2 items-center">{{ i "check" "size-4" }} Save</span>
264 <span id="spinner" class="group">
265 {{ i "loader-circle" "ml-2 w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
266 </span>
267 </button>
268 </div>
269{{ end }}