@knpkv/herdr-work 0.5.3 → 0.7.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.
- package/README.md +103 -0
- package/dist/display-state.d.ts +10 -0
- package/dist/display-state.d.ts.map +1 -0
- package/dist/display-state.js +5 -0
- package/dist/display-state.js.map +1 -0
- package/dist/errors.d.ts +21 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +12 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/legacy-lane-claim.d.ts +74 -0
- package/dist/internal/legacy-lane-claim.d.ts.map +1 -0
- package/dist/internal/legacy-lane-claim.js +81 -0
- package/dist/internal/legacy-lane-claim.js.map +1 -0
- package/dist/internal/session-index.d.ts +18 -0
- package/dist/internal/session-index.d.ts.map +1 -0
- package/dist/internal/session-index.js +23 -0
- package/dist/internal/session-index.js.map +1 -0
- package/dist/internal/terminal-reconcile.d.ts +31 -0
- package/dist/internal/terminal-reconcile.d.ts.map +1 -0
- package/dist/internal/terminal-reconcile.js +89 -0
- package/dist/internal/terminal-reconcile.js.map +1 -0
- package/dist/model.d.ts +939 -29
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +256 -7
- package/dist/model.js.map +1 -1
- package/dist/observed.d.ts +77 -0
- package/dist/observed.d.ts.map +1 -0
- package/dist/observed.js +240 -0
- package/dist/observed.js.map +1 -0
- package/dist/projection.d.ts +192 -12
- package/dist/projection.d.ts.map +1 -1
- package/dist/service.d.ts +121 -992
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +13 -3
- package/dist/service.js.map +1 -1
- package/dist/sql.d.ts.map +1 -1
- package/dist/sql.js +76 -3
- package/dist/sql.js.map +1 -1
- package/dist/store.d.ts +193 -11
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +768 -37
- package/dist/store.js.map +1 -1
- package/dist/view.d.ts.map +1 -1
- package/dist/view.js +169 -103
- package/dist/view.js.map +1 -1
- package/dist/work-triage.d.ts +72 -0
- package/dist/work-triage.d.ts.map +1 -0
- package/dist/work-triage.js +114 -0
- package/dist/work-triage.js.map +1 -0
- package/package.json +3 -3
- package/src/styles.css +229 -237
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
const DAY_MS = 86_400_000;
|
|
2
|
+
/** How long a finished goal stays in the "Done in the last 24 hours" group. */
|
|
3
|
+
export const workTriageDoneWindowMs = DAY_MS;
|
|
4
|
+
export const workTriageGroups = ["needs-you", "blocked", "moving", "done", "earlier"];
|
|
5
|
+
/** Which states have finished. Keyed by every WorkState, so a new state must be placed here to compile. */
|
|
6
|
+
const terminalState = {
|
|
7
|
+
planned: false,
|
|
8
|
+
working: false,
|
|
9
|
+
blocked: false,
|
|
10
|
+
review: false,
|
|
11
|
+
deployed: true,
|
|
12
|
+
completed: true,
|
|
13
|
+
abandoned: true
|
|
14
|
+
};
|
|
15
|
+
const terminal = (goal) => terminalState[goal.state];
|
|
16
|
+
const openRequestsOf = (goal) => (goal.requests ?? []).filter((request) => request.state === "open").toSorted((a, b) => a.requestedAt - b.requestedAt);
|
|
17
|
+
/**
|
|
18
|
+
* One group per goal, first match wins. An open request outranks every state, so a blocked goal
|
|
19
|
+
* with an open request is in "needs you" and not in the blocked count. A request without an
|
|
20
|
+
* approval target still counts: a person must act, even when the hub link is missing.
|
|
21
|
+
*/
|
|
22
|
+
const groupOf = (goal, openRequests, asOf) => {
|
|
23
|
+
if (openRequests.length > 0)
|
|
24
|
+
return "needs-you";
|
|
25
|
+
if (goal.state === "blocked")
|
|
26
|
+
return "blocked";
|
|
27
|
+
if (terminal(goal))
|
|
28
|
+
return asOf - goal.updatedAt <= workTriageDoneWindowMs ? "done" : "earlier";
|
|
29
|
+
return "moving";
|
|
30
|
+
};
|
|
31
|
+
const groupOrder = { "needs-you": 0, blocked: 1, moving: 2, done: 3, earlier: 4 };
|
|
32
|
+
/**
|
|
33
|
+
* Within "needs you", the oldest open request first; elsewhere, the most recently updated goal
|
|
34
|
+
* first. Ties keep the snapshot's own order, so the order is stable across polls.
|
|
35
|
+
*/
|
|
36
|
+
const compareRows = (left, right) => {
|
|
37
|
+
const byGroup = groupOrder[left.group] - groupOrder[right.group];
|
|
38
|
+
if (byGroup !== 0)
|
|
39
|
+
return byGroup;
|
|
40
|
+
if (left.group === "needs-you") {
|
|
41
|
+
const byRequest = (left.openRequests[0]?.requestedAt ?? 0) - (right.openRequests[0]?.requestedAt ?? 0);
|
|
42
|
+
if (byRequest !== 0)
|
|
43
|
+
return byRequest;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const byUpdate = right.goal.updatedAt - left.goal.updatedAt;
|
|
47
|
+
if (byUpdate !== 0)
|
|
48
|
+
return byUpdate;
|
|
49
|
+
}
|
|
50
|
+
return left.index - right.index;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Sorts one snapshot's goals into the triage groups and states the summary. The snapshot holds
|
|
54
|
+
* every goal (the model rejects a snapshot over `workSnapshotMaxGoals` rather than truncating it),
|
|
55
|
+
* so a zero here is a real zero.
|
|
56
|
+
*/
|
|
57
|
+
export const workTriage = (snapshot) => {
|
|
58
|
+
const rows = snapshot.goals
|
|
59
|
+
.map((goal, index) => {
|
|
60
|
+
const openRequests = openRequestsOf(goal);
|
|
61
|
+
return { goal, group: groupOf(goal, openRequests, snapshot.asOf), index, openRequests };
|
|
62
|
+
})
|
|
63
|
+
.toSorted(compareRows);
|
|
64
|
+
const needsYou = rows.filter((row) => row.group === "needs-you");
|
|
65
|
+
const blocked = rows.filter((row) => row.group === "blocked").length;
|
|
66
|
+
if (needsYou.length > 0 || blocked > 0) {
|
|
67
|
+
const first = needsYou[0];
|
|
68
|
+
const request = first?.openRequests[0];
|
|
69
|
+
return {
|
|
70
|
+
rows,
|
|
71
|
+
summary: {
|
|
72
|
+
_tag: "Attention",
|
|
73
|
+
blocked,
|
|
74
|
+
needsYou: needsYou.length,
|
|
75
|
+
oldestRequest: first === undefined || request === undefined ? null : { goal: first.goal, request }
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (rows.length === 0)
|
|
80
|
+
return { rows, summary: { _tag: "Empty" } };
|
|
81
|
+
const latest = rows.toSorted((a, b) => b.goal.updatedAt - a.goal.updatedAt)[0]?.goal ?? null;
|
|
82
|
+
return { rows, summary: { _tag: "Clear", latest, moving: rows.filter((row) => row.group === "moving").length } };
|
|
83
|
+
};
|
|
84
|
+
const plural = (count, one, many) => `${count} ${count === 1 ? one : many}`;
|
|
85
|
+
/**
|
|
86
|
+
* The summary as its one sentence: "3 goals need you, 2 blocked", "Nothing needs you", "No goals
|
|
87
|
+
* yet"; in the past tense "3 goals needed you, 2 blocked", "Nothing needed you", "No goals".
|
|
88
|
+
*/
|
|
89
|
+
export const workTriageSentence = (summary, tense = "present") => {
|
|
90
|
+
const [one, many, nothing] = tense === "present"
|
|
91
|
+
? ["goal needs", "goals need", "Nothing needs you"]
|
|
92
|
+
: ["goal needed", "goals needed", "Nothing needed you"];
|
|
93
|
+
switch (summary._tag) {
|
|
94
|
+
case "Attention":
|
|
95
|
+
if (summary.needsYou === 0)
|
|
96
|
+
return `${nothing}, ${summary.blocked} blocked`;
|
|
97
|
+
return summary.blocked === 0
|
|
98
|
+
? `${plural(summary.needsYou, one, many)} you`
|
|
99
|
+
: `${plural(summary.needsYou, one, many)} you, ${summary.blocked} blocked`;
|
|
100
|
+
case "Clear":
|
|
101
|
+
return nothing;
|
|
102
|
+
case "Empty":
|
|
103
|
+
return tense === "present" ? "No goals yet" : "No goals";
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
/** Group titles as the tab shows them. */
|
|
107
|
+
export const workTriageGroupTitle = {
|
|
108
|
+
"needs-you": "Needs you",
|
|
109
|
+
blocked: "Blocked",
|
|
110
|
+
moving: "Moving",
|
|
111
|
+
done: "Done in the last 24 hours",
|
|
112
|
+
earlier: "Finished earlier"
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=work-triage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-triage.js","sourceRoot":"","sources":["../src/work-triage.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knpkv/herdr-work",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Durable fleet work checkpoints and departure-board projections",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "knpkv",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"effect": "4.0.0",
|
|
55
|
-
"@knpkv/herdr-fleet": "^0.
|
|
56
|
-
"@knpkv/rly": "^0.
|
|
55
|
+
"@knpkv/herdr-fleet": "^0.6.1",
|
|
56
|
+
"@knpkv/rly": "^0.10.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@effect/platform-node": "4.0.0",
|