proctolog 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +87 -3
- data/README.md +15 -4
- data/app/controllers/proctolog/application_controller.rb +1 -1
- data/app/controllers/proctolog/bursts_controller.rb +1 -1
- data/app/controllers/proctolog/choices_controller.rb +3 -1
- data/app/controllers/proctolog/decisions_controller.rb +1 -1
- data/app/controllers/proctolog/notes_controller.rb +2 -2
- data/app/controllers/proctolog/prompts_controller.rb +1 -1
- data/app/controllers/proctolog/pull_requests_controller.rb +2 -4
- data/app/controllers/proctolog/review_data_controller.rb +3 -1
- data/app/controllers/proctolog/shares_controller.rb +27 -0
- data/app/helpers/proctolog/decisions_helper.rb +6 -2
- data/app/helpers/proctolog/desk_helper.rb +48 -8
- data/app/helpers/proctolog/rounds_helper.rb +4 -2
- data/app/helpers/proctolog/shares_helper.rb +11 -0
- data/app/helpers/proctolog/standings_helper.rb +5 -4
- data/app/models/proctolog/burst.rb +17 -8
- data/app/models/proctolog/choices.rb +8 -0
- data/app/models/proctolog/doctor.rb +9 -1
- data/app/models/proctolog/github.rb +1 -1
- data/app/models/proctolog/marks.rb +1 -1
- data/app/models/proctolog/note.rb +4 -0
- data/app/models/proctolog/owner.rb +3 -0
- data/app/models/proctolog/pick.rb +12 -0
- data/app/models/proctolog/rounds.rb +37 -0
- data/app/models/proctolog/share/ngrok.rb +120 -0
- data/app/models/proctolog/share/settings.rb +23 -0
- data/app/models/proctolog/share/tailscale.rb +103 -0
- data/app/models/proctolog/share.rb +101 -0
- data/app/models/proctolog/standing.rb +24 -7
- data/app/views/proctolog/bursts/_line.html.erb +2 -2
- data/app/views/proctolog/bursts/_side.html.erb +6 -5
- data/app/views/proctolog/bursts/_side_stop.html.erb +4 -4
- data/app/views/proctolog/notes/_card.html.erb +7 -3
- data/app/views/proctolog/open_pull_requests/_side.html.erb +4 -3
- data/app/views/proctolog/open_pull_requests/_start.html.erb +8 -0
- data/app/views/proctolog/open_pull_requests/index.html.erb +4 -5
- data/app/views/proctolog/open_pull_requests/start/_first_time.html.erb +3 -0
- data/app/views/proctolog/open_pull_requests/start/_nothing_open.html.erb +3 -0
- data/app/views/proctolog/open_pull_requests/start/_nothing_written.html.erb +3 -0
- data/app/views/proctolog/shares/_line.html.erb +5 -0
- data/app/views/proctolog/shares/show.html.erb +48 -0
- data/app/views/proctolog/shares/ways/_ngrok.html.erb +6 -0
- data/app/views/proctolog/shares/ways/_tailscale.html.erb +2 -0
- data/bin/proctolog +92 -6
- data/completions/_proctolog +28 -4
- data/config/application.rb +23 -4
- data/config/initializers/grouse.rb +1 -1
- data/config/routes.rb +3 -0
- data/docs/manual/bursts.md +7 -2
- data/docs/manual/deciding.md +4 -1
- data/docs/manual/handover.md +6 -0
- data/docs/manual/reading.md +54 -27
- data/docs/manual/sharing.md +77 -0
- data/lib/proctolog/changelog.rb +50 -0
- data/lib/proctolog/version.rb +1 -1
- data/public/asking.js +31 -4
- data/public/decisions.js +4 -4
- data/public/desk.js +10 -6
- data/public/keys.js +6 -0
- data/public/notes.js +164 -58
- data/public/pick.css +21 -0
- data/public/respond.css +6 -0
- data/public/respond.js +51 -7
- data/public/review-drafts.js +47 -9
- data/public/review-rounds.js +27 -3
- data/public/share.css +58 -0
- data/public/side.js +11 -20
- data/public/terminal.css +451 -77
- data/public/viewer.js +700 -173
- metadata +18 -1
data/public/review-rounds.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { helping, keyOf } from "./keys.js";
|
|
1
|
+
import { helping, keyOf, overThePage } from "./keys.js";
|
|
2
2
|
import { prNumber } from "./pr-number.js";
|
|
3
3
|
import {
|
|
4
4
|
announce,
|
|
5
5
|
handOver,
|
|
6
6
|
draftsState,
|
|
7
7
|
registerRounds,
|
|
8
|
+
settled,
|
|
8
9
|
stale,
|
|
9
10
|
updateDrafts,
|
|
10
11
|
} from "./review-drafts.js";
|
|
@@ -28,6 +29,25 @@ const reviewData = async () => {
|
|
|
28
29
|
if (!response.ok) throw new Error(`Desk returned ${response.status}`);
|
|
29
30
|
return response.json();
|
|
30
31
|
};
|
|
32
|
+
// The pane's ↩, on each pull request something came back on, in the words
|
|
33
|
+
// the desk gives (DeskHelper#side_mark).
|
|
34
|
+
const markThePane = (back = {}) => {
|
|
35
|
+
for (const row of document.querySelectorAll("[data-side-pr]")) {
|
|
36
|
+
const said = back[row.dataset.sidePr];
|
|
37
|
+
Object.assign(row.querySelector("[data-side-mark]"), {
|
|
38
|
+
textContent: said ? "↩" : "",
|
|
39
|
+
role: said ? "img" : null,
|
|
40
|
+
ariaLabel: said ?? null,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
// Once the desk has the owner's word on an answer, it has moved the notes the
|
|
45
|
+
// answer was to (Rounds#move_notes), and the pane is marked again from it. A
|
|
46
|
+
// desk that does not answer leaves the pane as the page drew it.
|
|
47
|
+
const followThePane = async () => {
|
|
48
|
+
await settled();
|
|
49
|
+
markThePane((await reviewData()).back);
|
|
50
|
+
};
|
|
31
51
|
// What GitHub draws of each piece of markdown, by its words, asked once while
|
|
32
52
|
// the page is open: returned work is laid out again at every change of the
|
|
33
53
|
// drafts, and must not fall back to markdown each time. A piece that cannot
|
|
@@ -589,6 +609,7 @@ const mark = (item, resolution, latest, kind, text) => {
|
|
|
589
609
|
},
|
|
590
610
|
};
|
|
591
611
|
});
|
|
612
|
+
followThePane().catch(() => {});
|
|
592
613
|
selectResponse(
|
|
593
614
|
visibleResponses().find((node) => node.dataset.request === next) ||
|
|
594
615
|
visibleResponses()[0],
|
|
@@ -1275,6 +1296,7 @@ registerRounds({
|
|
|
1275
1296
|
context = await reviewData();
|
|
1276
1297
|
importServerBatches();
|
|
1277
1298
|
importServerResponses();
|
|
1299
|
+
markThePane(context.back);
|
|
1278
1300
|
},
|
|
1279
1301
|
});
|
|
1280
1302
|
|
|
@@ -1290,6 +1312,7 @@ tools
|
|
|
1290
1312
|
? "Agent response imported. Confirm or reply to its existing requests."
|
|
1291
1313
|
: "The desk has this answer already.",
|
|
1292
1314
|
);
|
|
1315
|
+
followThePane().catch(() => {});
|
|
1293
1316
|
} catch (error) {
|
|
1294
1317
|
announce(`Response could not be imported: ${error.message}`);
|
|
1295
1318
|
} finally {
|
|
@@ -1361,8 +1384,9 @@ document
|
|
|
1361
1384
|
.querySelector("[data-enter-responses]")
|
|
1362
1385
|
?.addEventListener("click", enterResponses);
|
|
1363
1386
|
document.addEventListener("focusin", (event) => {
|
|
1364
|
-
// A picture looked at closely
|
|
1365
|
-
|
|
1387
|
+
// A picture looked at closely, or a note written in Grouse's overlay, leaves
|
|
1388
|
+
// the response marked: Esc comes back to it.
|
|
1389
|
+
if (overThePage(event.target)) return;
|
|
1366
1390
|
const node = event.target.closest("[data-request]");
|
|
1367
1391
|
if (node) markResponse(node);
|
|
1368
1392
|
else activeResponse?.removeAttribute("aria-current");
|
data/public/share.css
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* Sharing the desk: where it is now, then each way to share it, in the
|
|
2
|
+
route's own frame, with what it needs first or its button under its words. */
|
|
3
|
+
|
|
4
|
+
.share .now {
|
|
5
|
+
margin-block: 0 0.5lh;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.share .ways {
|
|
9
|
+
border: 1px solid var(--rule);
|
|
10
|
+
border-top: 0;
|
|
11
|
+
background: var(--surface);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.share .way {
|
|
15
|
+
display: grid;
|
|
16
|
+
row-gap: 8px;
|
|
17
|
+
padding: var(--row-pad) 12px;
|
|
18
|
+
border-bottom: 1px solid var(--rule-soft);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.share .way:last-child {
|
|
22
|
+
border-bottom: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.share .way h3 {
|
|
26
|
+
margin: 0;
|
|
27
|
+
font-size: 1rem;
|
|
28
|
+
color: var(--ink);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.share .way p {
|
|
32
|
+
margin: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.share .way .facts {
|
|
36
|
+
color: var(--quiet);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.share .way form {
|
|
40
|
+
display: grid;
|
|
41
|
+
row-gap: 8px;
|
|
42
|
+
justify-items: start;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.share .allow {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-wrap: wrap;
|
|
48
|
+
gap: 4px 2ch;
|
|
49
|
+
align-items: baseline;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.share .allow input {
|
|
53
|
+
width: min(40ch, 100%);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.share code {
|
|
57
|
+
white-space: nowrap;
|
|
58
|
+
}
|
data/public/side.js
CHANGED
|
@@ -14,32 +14,23 @@ const made = (name, properties = {}, ...children) => {
|
|
|
14
14
|
return element;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
// "3 of 19 decisions reviewed", from the row's "~" and "3/19".
|
|
18
|
-
const progressInWords = (mark, fraction) => {
|
|
19
|
-
if (!fraction) return "no decisions to review";
|
|
20
|
-
const [reviewed, total] = fraction.split("/").map(Number);
|
|
21
|
-
const decisions = total === 1 ? "decision" : "decisions";
|
|
22
|
-
if (mark === "x")
|
|
23
|
-
return total === 1
|
|
24
|
-
? "its one decision reviewed"
|
|
25
|
-
: `all ${total} decisions reviewed`;
|
|
26
|
-
if (!reviewed) return `none of ${total} ${decisions} reviewed yet`;
|
|
27
|
-
return `${reviewed} of ${total} ${decisions} reviewed`;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
17
|
const MOVED = {
|
|
31
18
|
changed: "changed on GitHub since it was read",
|
|
32
19
|
closed: "no longer open on GitHub",
|
|
33
20
|
};
|
|
34
21
|
|
|
22
|
+
// The row's marks said in words: what came back from the agent, then each
|
|
23
|
+
// grade's beads with what they count, in the words the server labelled them with.
|
|
35
24
|
const marksOf = (row) => {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
25
|
+
const back = row.querySelector("[data-side-mark]");
|
|
26
|
+
const grades = row.querySelectorAll("[data-side-decisions] [role=img]");
|
|
38
27
|
return [
|
|
39
|
-
[
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
back.textContent && [back.textContent, back.ariaLabel],
|
|
29
|
+
...[...grades].map((grade) => [
|
|
30
|
+
made("span", { className: "beads" }, grade.cloneNode(true)),
|
|
31
|
+
grade.ariaLabel,
|
|
32
|
+
]),
|
|
33
|
+
!grades.length && ["", "no decisions to review"],
|
|
43
34
|
row.dataset.moved && ["*", MOVED[row.dataset.moved]],
|
|
44
35
|
].filter(Boolean);
|
|
45
36
|
};
|
|
@@ -62,7 +53,7 @@ const cardOf = (row) => {
|
|
|
62
53
|
made(
|
|
63
54
|
"div",
|
|
64
55
|
{},
|
|
65
|
-
made("dt", {
|
|
56
|
+
made("dt", {}, shown),
|
|
66
57
|
made("dd", { textContent: said }),
|
|
67
58
|
),
|
|
68
59
|
),
|