Repository navigation
Expand file tree
/
Copy pathoptions.html
More file actions
309 lines (295 loc) · 22.8 KB
/
Copy pathoptions.html
File metadata and controls
309 lines (295 loc) · 22.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitHub Issue Toolkit - settings</title>
<style>
:root {
color-scheme: light dark;
--bg-base: #f6f8fa;
--bg-surface: #ffffff;
--bg-elevated: #f6f8fa;
--bg-input: #ffffff;
--border-default: #d0d7de;
--border-strong: #8c959f;
--border-focus: #0969da;
--text-primary: #1f2328;
--text-secondary: #59636e;
--text-muted: #1f2328;
--accent: #0969da;
--accent-hover: #0860ca;
--btn-bg: #f6f8fa;
--btn-bg-hover: #eaeef2;
--code-bg: rgba(175, 184, 193, 0.2);
--green: #1a7f37;
--red: #d1242f;
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
--font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}
@media (prefers-color-scheme: dark) {
:root {
--bg-base: #0d1117;
--bg-surface: #161b22;
--bg-elevated: #0d1117;
--bg-input: #0d1117;
--border-default: #30363d;
--border-strong: #6e7681;
--border-focus: #58a6ff;
--text-primary: #e6edf3;
--text-secondary: #8b949e;
--text-muted: #c9d1d9;
--accent: #58a6ff;
--accent-hover: #79b8ff;
--btn-bg: #21262d;
--btn-bg-hover: #30363d;
--code-bg: rgba(110, 118, 129, 0.4);
--green: #3fb950;
--red: #f85149;
}
}
* { box-sizing: border-box; }
.only-dark { display: none; }
@media (prefers-color-scheme: dark) { .only-dark { display: block; } .only-light { display: none; } }
body { margin: 0; min-height: 100vh; background: var(--bg-base); color: var(--text-primary); font: 14px/1.55 var(--font-sans); }
.page { max-width: 720px; margin: 0 auto; padding: 40px 24px 64px; }
header { display: flex; align-items: center; gap: 14px; margin-bottom: 8px; }
header img { width: 44px; height: 44px; border-radius: 10px; }
header h1 { font-size: 20px; font-weight: 600; margin: 0; line-height: 1.2; }
header .subtitle { color: var(--text-secondary); font-size: 13px; margin-top: 2px; }
.lead { color: var(--text-muted); margin: 16px 0 24px; }
.card { background: var(--bg-surface); border: 1px solid var(--border-default); border-radius: 12px; padding: 24px; margin-bottom: 16px; }
.card.access { border-color: var(--accent); }
.card h2 { font-size: 15px; font-weight: 600; margin: 0 0 4px; }
.marks { display: grid; grid-template-columns: 28px 1fr; gap: 10px 10px; align-items: center; margin-top: 14px; }
.marks > span:nth-child(odd) { display: flex; justify-content: center; }
.marks .t { color: var(--text-secondary); font-size: 13px; }
.marks .t b { color: var(--text-primary); font-weight: 600; }
.marks i { font-style: normal; }
.mk-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
.mk-free { box-shadow: inset 0 0 0 1px var(--text-secondary); opacity: .5; }
.mk-at { background: #1a7f37; opacity: .8; }
.mk-n { padding: 1px 6px; border-radius: 9999px; font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; color: #9a6700; background: rgba(154, 103, 0, 0.14); }
.mk-idle { color: #ffffff; background: #9a6700; }
.mk-err { box-shadow: inset 0 0 0 1px #d1242f; }
.card p.desc { color: var(--text-secondary); margin: 0 0 16px; font-size: 13px; }
label { display: block; font-weight: 600; font-size: 13px; margin: 16px 0 6px; }
label:first-of-type { margin-top: 0; }
.input-row { display: flex; gap: 8px; }
input[type="text"], input[type="password"], input[type="number"] {
flex: 1; width: 100%; padding: 9px 12px;
background: var(--bg-input); border: 1px solid var(--border-default); border-radius: 8px;
color: var(--text-primary); font: 14px var(--font-sans); outline: none;
transition: border-color .15s, box-shadow .15s;
}
input::placeholder { color: var(--text-secondary); }
input:focus { border-color: var(--border-focus); box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.25); }
.hint { color: var(--text-secondary); font-size: 12px; margin: 6px 0 0; }
.hint a, footer a { color: var(--accent); text-decoration: none; }
.hint a:hover, footer a:hover { text-decoration: underline; }
code, .mono { font-family: var(--font-mono); font-size: 12px; background: var(--code-bg); border-radius: 5px; padding: 1px 6px; }
.actions { display: flex; align-items: center; gap: 10px; margin-top: 20px; flex-wrap: wrap; }
button {
padding: 8px 16px; border-radius: 8px; border: 1px solid var(--border-default);
background: var(--btn-bg); color: var(--text-primary); font: 600 13px var(--font-sans); cursor: pointer;
transition: background .15s, border-color .15s;
}
button:hover { background: var(--btn-bg-hover); }
button.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
button.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
#status { font-size: 13px; }
#status.ok { color: var(--green); }
#status.err { color: var(--red); }
.chip-input {
display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
min-height: 42px; padding: 6px 8px;
background: var(--bg-input); border: 1px solid var(--border-default); border-radius: 8px;
cursor: text; transition: border-color .15s, box-shadow .15s;
}
.chip-input:focus-within { border-color: var(--border-focus); box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.25); }
.chip-input input {
flex: 1 1 160px; min-width: 120px; border: none; background: transparent; padding: 4px 6px;
color: var(--text-primary); font: 14px var(--font-sans); outline: none;
}
.chip {
display: inline-flex; align-items: center; gap: 4px; height: 26px; padding: 0 4px 0 10px;
border-radius: 999px; border: 1px solid var(--chip-border); background: var(--chip-bg); color: var(--chip-fg);
font-size: 13px; font-weight: 500; line-height: 1; white-space: nowrap;
}
.chip button {
all: unset; display: inline-flex; align-items: center; justify-content: center;
width: 18px; height: 18px; border-radius: 50%; cursor: pointer; color: inherit; font-size: 14px; line-height: 1; opacity: .7;
}
.chip button:hover { opacity: 1; background: rgba(0, 0, 0, 0.12); }
.chip.c0 { --chip-bg: rgba(9, 105, 218, 0.12); --chip-border: rgba(9, 105, 218, 0.4); --chip-fg: #0969da; }
.chip.c1 { --chip-bg: rgba(130, 80, 223, 0.12); --chip-border: rgba(130, 80, 223, 0.4); --chip-fg: #8250df; }
.chip.c2 { --chip-bg: rgba(26, 127, 55, 0.12); --chip-border: rgba(26, 127, 55, 0.4); --chip-fg: #1a7f37; }
.chip.c3 { --chip-bg: rgba(188, 76, 0, 0.12); --chip-border: rgba(188, 76, 0, 0.4); --chip-fg: #bc4c00; }
.chip.c4 { --chip-bg: rgba(191, 57, 137, 0.12); --chip-border: rgba(191, 57, 137, 0.4); --chip-fg: #bf3989; }
.chip.c5 { --chip-bg: rgba(89, 99, 110, 0.12); --chip-border: rgba(89, 99, 110, 0.4); --chip-fg: #59636e; }
@media (prefers-color-scheme: dark) {
.chip.c0 { --chip-fg: #58a6ff; } .chip.c1 { --chip-fg: #a371f7; } .chip.c2 { --chip-fg: #3fb950; }
.chip.c3 { --chip-fg: #f0883e; } .chip.c4 { --chip-fg: #db61a2; } .chip.c5 { --chip-fg: #8b949e; }
.mk-at { background: #3fb950; }
.mk-n { color: #d29922; background: rgba(210, 153, 34, 0.16); }
.mk-idle { color: #1f2328; background: #d29922; }
.mk-err { box-shadow: inset 0 0 0 1px #ff8182; }
.chip button:hover { background: rgba(255, 255, 255, 0.12); }
}
kbd { font: 11px var(--font-mono); padding: 1px 5px; border: 1px solid var(--border-default); border-bottom-width: 2px; border-radius: 4px; background: var(--code-bg); }
footer { color: var(--text-secondary); font-size: 12px; margin-top: 24px; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px; }
.mono:empty { display: none; }
label.check { display: flex; align-items: center; gap: 8px; font-weight: 500; margin-top: 0; }
label.check input { width: 16px; height: 16px; margin: 0; accent-color: var(--accent); }
select {
width: 100%; padding: 9px 12px; background: var(--bg-input); border: 1px solid var(--border-default); border-radius: 8px;
color: var(--text-primary); font: 14px var(--font-sans); outline: none;
}
.shortcut { display: grid; grid-template-columns: 100px 56px 150px 1fr 56px 34px; gap: 8px; align-items: center; margin-bottom: 8px; }
.shortcut-head { margin-bottom: 6px; color: var(--text-secondary); font-size: 12px; font-weight: 600; }
.shortcut-head span:nth-child(5), .shortcut input[type="radio"] { justify-self: center; }
.shortcut input[type="text"]:nth-child(2) { text-align: center; padding: 9px 4px; }
.shortcut input[type="radio"] { width: 16px; height: 16px; margin: 0; accent-color: var(--accent); }
.shortcut button { padding: 8px 0; }
.shortcut button:disabled { opacity: .4; cursor: default; }
select:focus { border-color: var(--border-focus); box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.25); }
</style>
</head>
<body>
<div class="page">
<header>
<img class="only-dark" src="icons/icon-dark-128.png" alt="">
<img class="only-light" src="icons/icon-light-128.png" alt="">
<div>
<h1>GitHub Issue Toolkit</h1>
<div class="subtitle">Extension settings</div>
</div>
</header>
<p class="lead">Shows the values of custom issue fields and the age of issues as badges on sub-issue lists and on project views, and keeps your pinned epics one click away.</p>
<section class="card access" id="access" hidden>
<h2>Site access</h2>
<p class="desc">This browser has not granted the extension access to <code>github.com</code> and <code>api.github.com</code> yet. Firefox asks for this separately from the installation.</p>
<button id="grant" type="button" class="primary">Allow access to github.com</button>
</section>
<section class="card">
<h2>GitHub access</h2>
<p class="desc">Field values are read through the GitHub API. The token is stored in this browser profile only and is sent to nothing but <code>api.github.com</code>. Fields with "Organization only" visibility need a token of an organization member.</p>
<label for="token">Personal access token</label>
<div class="input-row">
<input id="token" type="password" autocomplete="off" spellcheck="false" placeholder="github_pat_... or ghp_...">
<button id="toggle" type="button" title="Show or hide the token">Show</button>
</div>
<p class="hint">
Recommended: a <a href="https://github.com/settings/tokens/new?scopes=repo&description=github-issue-toolkit" target="_blank" rel="noopener">classic token</a> with the <code>repo</code> scope. If the organization enforces SSO, open "Configure SSO" next to the new token and authorize it for that organization.
A <a href="https://github.com/settings/personal-access-tokens/new" target="_blank" rel="noopener">fine-grained token</a> also works: set the organization as resource owner, pick the repositories, and under Repository permissions set <code>Issues</code> to <code>Read-only</code>.
</p>
</section>
<section class="card">
<h2>Fields to show (optional)</h2>
<p class="desc">Names of the issue fields to display, matched case-insensitively against the fields defined by the organization. Badges appear in this order; single-select values use the option's colour. An entry starting with <code>label:</code> shows labels instead: <code>label:area/*</code> every label starting with <code>area/</code>, <code>label:bug</code> only that one, in the badge colour nearest to the label's.</p>
<label for="field-input">Field names</label>
<div id="chips" class="chip-input" role="list" aria-label="Field names">
<input id="field-input" type="text" spellcheck="false" autocomplete="off" placeholder="Add a field and press Enter">
</div>
<p class="hint">Press <kbd>Enter</kbd> or <kbd>,</kbd> to add a field, <kbd>Backspace</kbd> or the × button to remove one. Leave it empty to show no field badges; the rest of the extension works without them.</p>
<label class="check" style="margin-top:14px"><input id="skip-shown" type="checkbox"> Skip fields the view already shows (project columns, card fields and the board's grouping)</label>
</section>
<section class="card">
<h2>Issue age</h2>
<p class="desc">Adds a badge with the time elapsed since the issue was created, next to the field badges, on sub-issue lists and on project table and board views.</p>
<label class="check"><input id="age-enabled" type="checkbox"> Show the age of each issue (off by default)</label>
<label for="age-unit">Unit</label>
<select id="age-unit">
<option value="months">Months (default), e.g. 3 mo</option>
<option value="weeks">Weeks, e.g. 14w</option>
<option value="days">Days, e.g. 98d</option>
</select>
<label for="age-warn">Highlight issues open longer than (days)</label>
<input id="age-warn" type="number" min="0" step="1" inputmode="numeric" placeholder="90">
<p class="hint">The badge turns yellow past this age. 0 turns the highlight off. Default 90.</p>
<p class="hint">An issue younger than the unit reads today, this week or this month. Hovering the badge shows the exact age in months and days and the creation date.</p>
</section>
<section class="card">
<h2>Epic kanban</h2>
<p class="desc">Adds a List and Kanban toggle above the sub-issues list of an issue. The board reads every field the sub-issues carry, not only the ones above: you pick the field that forms the columns and the one that orders the cards inside each column, and both choices are remembered. Columns follow the order the organization gave the field's options. Filter the board down to one value of any dimension to see a single sprint or priority at a time, or hide the closed sub-issues with the checkbox in the toolbar.</p>
<label class="check"><input id="kanban-enabled" type="checkbox"> Show the kanban toggle on sub-issue lists</label>
<label class="check" style="margin-top:8px"><input id="kanban-drag" type="checkbox"> Move a card by dragging it to another column, when the columns come from a single-select field or the issue state</label>
<p class="hint">Dragging writes to GitHub: it sets the field value, or closes and reopens the issue. The token needs write access to the issue's repository (the <code>repo</code> scope for classic tokens, <code>Issues: Read and write</code> for fine-grained ones). Nothing is written unless you drag a card.</p>
</section>
<section class="card">
<h2>Sub-issue progress</h2>
<p class="desc">On a Projects table grouped by parent issue, GitHub's bar in each group header counts every sub-issue of an issue, including the ones the view hides with a filter or a slice. This replaces it with one that counts only the sub-issues inside the scope the view is narrowed to and shows the scope as tags, for example <code>14 / 18 done</code> followed by <code>release:2.1</code>. The Sub-issues progress column keeps GitHub's own bar.</p>
<label class="check"><input id="progress-enabled" type="checkbox"> Replace GitHub's sub-issue progress (off by default)</label>
<label for="progress-scope">Scope field (optional)</label>
<input id="progress-scope" type="text" spellcheck="false" autocomplete="off" placeholder="Release">
<p class="hint">The field whose value narrows the count, or several separated by commas, <code>Release, Owner</code> for example, matched case-insensitively. Each value is read from what the view is sliced by, or from a <code>release:2.1</code> term in its filter, and a sub-issue must have all of them. When the view is narrowed to none of them, GitHub's own bar stays. Leave it empty to count every sub-issue.</p>
<label for="progress-done-field">Counts as done (optional)</label>
<div class="input-row">
<input id="progress-done-field" type="text" spellcheck="false" autocomplete="off" placeholder="Stage" aria-label="Field that marks a sub-issue as done">
<input id="progress-done-value" type="text" spellcheck="false" autocomplete="off" placeholder="Done" aria-label="Value of that field that marks a sub-issue as done">
</div>
<p class="hint">A sub-issue counts as done when this field has this value, <code>Stage</code> and <code>Done</code> for example. Leave both empty and a closed sub-issue is a done one. Needs a token that can read issue fields, like the badges.</p>
</section>
<section class="card">
<h2>Pull requests</h2>
<p class="desc">Badges on the pull request list, next to the labels of each row. Everything comes from the same read-only API access as the field badges.</p>
<label class="check"><input id="pr-association" type="checkbox"> Author's relation to the repository</label>
<label class="check" style="margin-top:8px"><input id="pr-fork" type="checkbox"> Opened from a fork</label>
<label class="check" style="margin-top:8px"><input id="pr-size" type="checkbox"> Size: added lines in green and removed lines in red, changed files on hover</label>
<label class="check" style="margin-top:8px"><input id="pr-merge-state" type="checkbox"> Merge state: mergeable, behind base, blocked, conflicts, checks failing</label>
</section>
<section class="card">
<h2>Contributor load</h2>
<p class="desc">On an issue or pull request, a mark next to a username saying what that person already holds in the same organization. For deciding whether to assign someone one more thing.</p>
<label class="check"><input id="load-enabled" type="checkbox"> Show what each contributor is holding (off by default)</label>
<label for="load-limit">Flag anyone assigned more than (issues)</label>
<input id="load-limit" type="number" min="0" step="1" inputmode="numeric" placeholder="1">
<p class="hint">Default 1. The mark reads like this:</p>
<div class="marks">
<span><i class="mk-dot mk-free"></i></span><span class="t">Nothing assigned. <b>Free to take one.</b></span>
<span><i class="mk-dot mk-at"></i></span><span class="t">At or under the limit.</span>
<span><i class="mk-n">4/3</i></span><span class="t">Over the limit. <b>Four assigned, three pull requests open.</b></span>
<span><i class="mk-n mk-idle">3/0</i></span><span class="t">Over the limit and <b>nothing pushed yet</b>.</span>
<span><i class="mk-dot mk-err"></i></span><span class="t">Could not be read, usually a missing token. Hover the name again to retry.</span>
</div>
<p class="hint">Hovering the mark lists every issue that person holds, each with the pull request that closes it when there is one, and carries a refresh button for when the ten minute cache is behind. Your own name gets no mark. Counts cover the repositories your token can read, so a fine-grained token limited to a few repositories sees only those.</p>
</section>
<section class="card">
<h2>Issue sidebar</h2>
<p class="desc">A small button between the issue and its sidebar hides the whole metadata column, assignees, labels, type, fields, projects and the rest, giving the issue body and the kanban board the full width. The button stays in the same place either way, and what you choose holds on every issue until you press it again.</p>
<label class="check"><input id="sidebar-toggle" type="checkbox"> Show the button that hides the issue sidebar</label>
<label class="check" style="margin-top:8px"><input id="hide-projects" type="checkbox"> Hide the Projects section of the issue sidebar (off by default)</label>
<p class="hint">Takes GitHub's own Projects box, with its status and fields, out of the sidebar on every issue, while the rest of the sidebar stays. The issue remains in its projects; only the box is hidden.</p>
</section>
<section class="card">
<h2>Pinned issues</h2>
<p class="desc">A pin button in GitHub's top bar, next to the notifications bell, opens a panel with your pinned issues, for example epics. From there you can copy the reference or make the issue you are looking at a sub-issue of a pinned epic. Linking writes to GitHub, so the token needs write access to the issue's repository (the <code>repo</code> scope for classic tokens, <code>Issues: Read and write</code> for fine-grained ones).</p>
<label class="check"><input id="pins-enabled" type="checkbox"> Show the pinned issues button in GitHub's top bar</label>
<div class="actions" style="margin-top:12px">
<span id="pins-count" class="hint" style="margin:0"></span>
<button id="pins-clear" type="button">Remove all pins</button>
</div>
</section>
<section class="card">
<h2>Address bar search</h2>
<p class="desc">Type <code>@gh</code> and a space in the address bar, then a shortcut name and the words to look for, for example <code>@gh repo flow</code>. Each shortcut searches one kind of item and adds its qualifiers to your words, so <code>org:acme</code> keeps the search inside one organization. A shortcut name on its own, <code>@gh pr</code>, lists what its qualifiers match right away. Text that does not start with a shortcut name goes to the default shortcut. Results appear as you type; Enter on the text itself opens the GitHub search page.</p>
<div class="shortcut shortcut-head" aria-hidden="true"><span>Name</span><span>Icon</span><span>Searches</span><span>Qualifiers</span><span>Default</span><span></span></div>
<div id="shortcuts"></div>
<div class="actions" style="margin-top:4px">
<button id="shortcut-add" type="button">Add shortcut</button>
</div>
<p class="hint">Qualifiers use <a href="https://docs.github.com/en/search-github/searching-on-github" target="_blank" rel="noopener">GitHub search syntax</a>, for example <code>org:acme is:open</code> or <code>repo:acme/webapp</code>. Repository names inside an <code>org:</code> or <code>user:</code> also match on any part of the name, so <code>app</code> finds <code>webapp</code>. With one <code>repo:</code> qualifier, a number such as <code>#1234</code> goes straight to that issue or pull request. The icon is optional, an emoji such as 📦 or 🔀, shown before each result of the shortcut: the browser puts the same magnifier in front of every suggestion and lets no extension change it.</p>
</section>
<div class="actions">
<button id="save" class="primary" type="button">Save</button>
<button id="test" type="button">Test token</button>
<span id="status" role="status"></span>
</div>
<footer>
<span>GitHub Issue Toolkit <span id="version" class="mono"></span></span>
<span>Not affiliated with GitHub.</span>
</footer>
</div>
<script src="options.js"></script>
</body>
</html>