@knpkv/herdr-work 0.7.2 → 0.8.1

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.
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Deciding a goal's approval request inside the Work tab: what the host hands the board, and how
3
+ * a request's clock and bar read. Pure: the host owns the clock (`now`), the sending decision and
4
+ * the hub's answer; the board only presents them.
5
+ *
6
+ * The clock is display only. A request is decided or expired when the hub says so, never because
7
+ * the client clock reached zero: at zero it reads "expiring" and the bar stays usable, so the hub's
8
+ * refusal is what the reader sees.
9
+ *
10
+ * @module
11
+ */
12
+ import type { WorkRequest } from "./model.js";
13
+ /** One decision on the hub job behind a request. */
14
+ export interface WorkRequestDecision {
15
+ readonly jobId: string;
16
+ readonly decision: "approve" | "reject";
17
+ }
18
+ /**
19
+ * The hub's own words about the last decision sent from this page, for the job it decided.
20
+ * `outcome` is `accepted` when the hub took the decision, `refused` when it answered no, and
21
+ * `uncertain` when the request failed in transit (a 5xx, an unreadable reply). An accepted answer
22
+ * keeps the bar off until the host's pending list drops the job; an uncertain one gives way to the
23
+ * outcome a later snapshot proves.
24
+ */
25
+ export interface WorkRequestAnswer {
26
+ readonly jobId: string;
27
+ readonly outcome: "accepted" | "refused" | "uncertain";
28
+ readonly text: string;
29
+ }
30
+ /**
31
+ * What a host that can decide approvals gives the Work board. Without it (the LAN view, a host
32
+ * that is not the hub) every request keeps its link to the hub.
33
+ */
34
+ export interface WorkRequestDecisions {
35
+ /**
36
+ * The expiry of a hub job this host lists as pending: a time, `null` for a pending job without
37
+ * one, `undefined` when this host cannot decide the job (not pending here, or another host's).
38
+ */
39
+ readonly expiresAt: (jobId: string) => number | null | undefined;
40
+ /**
41
+ * Hub time: the snapshot's `observedAt` plus the time elapsed locally since it arrived, re-read
42
+ * while any clock is visible. Expiries are hub times, so a browser clock ahead or behind must not
43
+ * move them.
44
+ */
45
+ readonly now: number;
46
+ /** The decision waiting for the hub, if any. */
47
+ readonly sending: WorkRequestDecision | null;
48
+ /** The hub's answer to the last decision sent from this page. */
49
+ readonly answer: WorkRequestAnswer | null;
50
+ readonly onDecision: (decision: WorkRequestDecision) => void;
51
+ }
52
+ /** Under this much time left the clock keeps seconds. */
53
+ export declare const workRequestSoonMs: number;
54
+ /** "52s", "4m 12s", "11m": seconds only matter under five minutes; "expiring" at zero. */
55
+ export declare const workRequestClockText: (expiresAt: number, now: number) => string;
56
+ /** How a request can be decided on this page. */
57
+ export type WorkRequestDecidability = {
58
+ readonly _tag: "Here";
59
+ readonly jobId: string;
60
+ readonly expiresAt: number | null;
61
+ } | {
62
+ readonly _tag: "Elsewhere";
63
+ };
64
+ /**
65
+ * A request is decided here when the host lists its hub job as pending, or when this page already
66
+ * sent a decision for it and holds the answer, so the bar and its announcement stay mounted after
67
+ * the request leaves the queue.
68
+ */
69
+ export declare const workRequestDecidability: (request: WorkRequest, decisions: WorkRequestDecisions | undefined) => WorkRequestDecidability;
70
+ //# sourceMappingURL=request-decision.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-decision.d.ts","sourceRoot":"","sources":["../src/request-decision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAA;CACxC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,GAAG,WAAW,CAAA;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAChE;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAA;IAC5C,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAA;IACzC,QAAQ,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAC7D;AAED,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,QAAa,CAAA;AAE3C,0FAA0F;AAC1F,eAAO,MAAM,oBAAoB,cAAe,MAAM,OAAO,MAAM,KAAG,MAOrE,CAAA;AAED,iDAAiD;AACjD,MAAM,MAAM,uBAAuB,GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACpF;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAAA;AAElC;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,YACzB,WAAW,aACT,oBAAoB,GAAG,SAAS,KAC1C,uBAOF,CAAA"}
@@ -0,0 +1,29 @@
1
+ /** Under this much time left the clock keeps seconds. */
2
+ export const workRequestSoonMs = 5 * 60_000;
3
+ /** "52s", "4m 12s", "11m": seconds only matter under five minutes; "expiring" at zero. */
4
+ export const workRequestClockText = (expiresAt, now) => {
5
+ const left = expiresAt - now;
6
+ if (left <= 0)
7
+ return "expiring";
8
+ const seconds = Math.floor(left / 1000);
9
+ const minutes = Math.floor(seconds / 60);
10
+ if (minutes === 0)
11
+ return `${seconds}s`;
12
+ return left < workRequestSoonMs ? `${minutes}m ${String(seconds % 60).padStart(2, "0")}s` : `${minutes}m`;
13
+ };
14
+ /**
15
+ * A request is decided here when the host lists its hub job as pending, or when this page already
16
+ * sent a decision for it and holds the answer, so the bar and its announcement stay mounted after
17
+ * the request leaves the queue.
18
+ */
19
+ export const workRequestDecidability = (request, decisions) => {
20
+ const target = request.approvalTarget;
21
+ if (decisions === undefined || target === null)
22
+ return { _tag: "Elsewhere" };
23
+ const expiresAt = decisions.expiresAt(target.jobId);
24
+ const answered = decisions.answer?.jobId === target.jobId || decisions.sending?.jobId === target.jobId;
25
+ if (expiresAt === undefined && !answered)
26
+ return { _tag: "Elsewhere" };
27
+ return { _tag: "Here", expiresAt: expiresAt ?? null, jobId: target.jobId };
28
+ };
29
+ //# sourceMappingURL=request-decision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-decision.js","sourceRoot":"","sources":["../src/request-decision.ts"],"names":[],"mappings":"AAuDA,yDAAyD;AACzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAG,MAAM,CAAA;AAE3C,0FAA0F;AAC1F,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,SAAiB,EAAE,GAAW,EAAU,EAAE;IAC7E,MAAM,IAAI,GAAG,SAAS,GAAG,GAAG,CAAA;IAC5B,IAAI,IAAI,IAAI,CAAC;QAAE,OAAO,UAAU,CAAA;IAChC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAA;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAA;IACxC,IAAI,OAAO,KAAK,CAAC;QAAE,OAAO,GAAG,OAAO,GAAG,CAAA;IACvC,OAAO,IAAI,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAA;AAC3G,CAAC,CAAA;AAOD;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,OAAoB,EACpB,SAA2C,EAClB,EAAE;IAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,cAAc,CAAA;IACrC,IAAI,SAAS,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;IAC5E,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACnD,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,KAAK,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC,OAAO,EAAE,KAAK,KAAK,MAAM,CAAC,KAAK,CAAA;IACtG,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;IACtE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,IAAI,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAA;AAC5E,CAAC,CAAA"}
package/dist/store.js CHANGED
@@ -2053,7 +2053,7 @@ export class WorkStore {
2053
2053
  {
2054
2054
  id: jobId,
2055
2055
  kind: "status",
2056
- summary: workReassignActivitySummary(decoded, jobId, decoded.approvalHash),
2056
+ summary: workReassignActivitySummary(decoded),
2057
2057
  occurredAt: at
2058
2058
  }
2059
2059
  ],
@@ -2284,7 +2284,7 @@ export class WorkStore {
2284
2284
  {
2285
2285
  id: jobId,
2286
2286
  kind: "status",
2287
- summary: workAbandonActivitySummary(decoded, jobId, decoded.approvalHash),
2287
+ summary: workAbandonActivitySummary(decoded),
2288
2288
  occurredAt: at
2289
2289
  }
2290
2290
  ],