@mikitasazan/notify 1.7.0 → 1.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.
- package/dist/cli-flags.js +1 -1
- package/dist/cli.js +73 -61
- package/dist/events.d.ts +142 -118
- package/dist/events.js +23 -21
- package/dist/render.d.ts +48 -45
- package/dist/render.js +233 -198
- package/dist/routes.d.ts +31 -27
- package/dist/routes.js +25 -20
- package/package.json +1 -1
package/dist/events.d.ts
CHANGED
|
@@ -1,57 +1,61 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* `send.ts`)
|
|
4
|
-
*
|
|
2
|
+
* The event catalogue — the single entry point for sending. `notify()` (see
|
|
3
|
+
* `send.ts`) accepts ONLY values of this type: there is no free text in the
|
|
4
|
+
* API, so a "custom" message cannot technically be written.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
6
|
+
* The schema evolution rule (there is no version and never will be — a
|
|
7
|
+
* message lives one second and is read by eyes, there is nothing to
|
|
8
|
+
* version):
|
|
9
|
+
* - a new field on an EXISTING type is added ONLY as optional;
|
|
10
|
+
* - required fields are never added — only a new event type.
|
|
11
|
+
* That keeps old caller code and a new package compatible both ways.
|
|
11
12
|
*/
|
|
12
13
|
export type Project = 'playhub' | 'one-q' | 'arvent' | 'game-publisher' | 'vault' | 'mac-config' | 'alitools';
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
15
|
+
* A stable machine key for the task — the last line of every card, shaped
|
|
16
|
+
* as `#key` (with no project name: the card already sits in its own
|
|
17
|
+
* project's forum — `targets()` never sends it to someone else's). The
|
|
18
|
+
* daily parser uses it to check "is this 🔴 already closed by a later card
|
|
19
|
+
* with the same key?" without comparing human wording, which changes. It
|
|
20
|
+
* is optional: without it, the key is derived from the type and the title
|
|
21
|
+
* (see `render.ts`), but a derived one inherits the fragility of wording —
|
|
22
|
+
* our regular senders pass it explicitly. The key never reaches CLI output
|
|
23
|
+
* (stderr, which the VPS watchdog also reads as one combined stream by the
|
|
24
|
+
* words `sent|failed|skipped`) — a new word there would blind the
|
|
25
|
+
* watchdog.
|
|
24
26
|
*/
|
|
25
27
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* The common part of any event. `path` is a local file that travels WITH the
|
|
29
|
+
* card: the card becomes a caption on the attachment. There has been no
|
|
30
|
+
* separate `file` type since 25.08.2026 — an Arvent run used to send the
|
|
31
|
+
* verdict and the log as two cards about one piece of news.
|
|
30
32
|
*/
|
|
31
33
|
type Keyed = {
|
|
32
34
|
key?: string;
|
|
33
|
-
/**
|
|
35
|
+
/** A local file; the card goes out as its caption (caption limit 1024). */
|
|
34
36
|
path?: string;
|
|
35
|
-
/**
|
|
37
|
+
/** The file's name in the chat; defaults to the name from `path`. */
|
|
36
38
|
filename?: string;
|
|
37
39
|
};
|
|
38
40
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
+
* A list item inside a message: a task from a digest, a failed check, a
|
|
42
|
+
* remark. `url` is optional — then it renders as a plain row.
|
|
41
43
|
*/
|
|
42
44
|
/**
|
|
43
|
-
* `label` —
|
|
44
|
-
* `#287`)
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* `label` — an optional bold prefix before `text` (`#243 (overdue)`,
|
|
46
|
+
* `#287`) for items inside a report's named groups. Without `label` an
|
|
47
|
+
* item renders as an ordinary numbered/bulleted row — that is already how
|
|
48
|
+
* digest tasks and the list of disabled workflows work.
|
|
47
49
|
*/
|
|
48
50
|
/**
|
|
49
|
-
* `group` —
|
|
50
|
-
* `lines`
|
|
51
|
+
* `group` — the name of the block the item will sit under. The same law
|
|
52
|
+
* `lines` and `stats` follow: without a name the item goes into the
|
|
53
|
+
* general list, as before.
|
|
51
54
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* 🔁
|
|
55
|
+
* Introduced because the import list was mixing three DIFFERENT things in
|
|
56
|
+
* one listing and telling them apart by an icon at the start of the row:
|
|
57
|
+
* 🆕 came out today, 🔁 came out of the queue, ⚠ did not come out at all.
|
|
58
|
+
* The icon was doing a heading's job.
|
|
55
59
|
*/
|
|
56
60
|
export type Item = {
|
|
57
61
|
text: string;
|
|
@@ -60,73 +64,84 @@ export type Item = {
|
|
|
60
64
|
group?: string;
|
|
61
65
|
};
|
|
62
66
|
export type NotifyEvent = Keyed & (
|
|
63
|
-
/**
|
|
67
|
+
/** Shipping code to the server. */
|
|
64
68
|
{
|
|
65
69
|
type: 'deploy';
|
|
66
70
|
project: Project;
|
|
67
71
|
status: 'ok' | 'fail';
|
|
68
72
|
commit?: string;
|
|
69
|
-
/**
|
|
73
|
+
/** A link to the commit — the "commit" row becomes clickable. */
|
|
70
74
|
commitUrl?: string;
|
|
71
|
-
/**
|
|
75
|
+
/** The commit's title — renders as the `Title:` field, the body follows as a quote. */
|
|
72
76
|
commitTitle?: string;
|
|
73
|
-
/**
|
|
77
|
+
/** The commit's body, if there is one — the same quote shape as the title. */
|
|
74
78
|
commitBody?: string;
|
|
75
79
|
workflowUrl?: string;
|
|
76
|
-
/**
|
|
80
|
+
/** The run's name, for the link's visible text (defaults to `open`). */
|
|
77
81
|
workflowName?: string;
|
|
78
82
|
url?: string;
|
|
79
83
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
84
|
+
* Where it shipped to. Fill it in ONLY when there is more than one
|
|
85
|
+
* environment: on sites with a single prod, "where: prod" is a row
|
|
86
|
+
* the eye reads and learns nothing from.
|
|
83
87
|
*/
|
|
84
88
|
target?: string;
|
|
85
89
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
+
* Where it was run from: "manually from the Mac," "GitHub Actions."
|
|
91
|
+
* This is exactly the news — there are two deploy paths, they carry
|
|
92
|
+
* different consequences (a manual one runs from the laptop and takes
|
|
93
|
+
* its variables from the local .env), and the card shows which one
|
|
94
|
+
* fired.
|
|
90
95
|
*/
|
|
91
96
|
via?: string;
|
|
92
|
-
/**
|
|
97
|
+
/** An explanation: why a post-deploy run was cancelled/skipped. */
|
|
93
98
|
note?: string;
|
|
94
99
|
}
|
|
95
|
-
/**
|
|
100
|
+
/** A recurring scheduled task: a game import, a DB backup, a validator. */
|
|
96
101
|
| {
|
|
97
102
|
type: 'job';
|
|
98
103
|
project: Project;
|
|
99
104
|
job: string;
|
|
100
105
|
/**
|
|
101
|
-
* `disabled` —
|
|
102
|
-
*
|
|
106
|
+
* `disabled` — the task was switched off from outside (GitHub Actions
|
|
107
|
+
* ran out of free minutes, for example), it did not fail on its own.
|
|
103
108
|
*
|
|
104
|
-
* `silent` —
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
109
|
+
* `silent` — the task did not report in on time: it did not fail, it
|
|
110
|
+
* gave no sign of life at all. This is a state of the TASK, not a
|
|
111
|
+
* separate event type — it used to live under the type
|
|
112
|
+
* `heartbeat_miss`, and the owner rightly asked why one scheduled task
|
|
113
|
+
* of his carried two different tags. Worse: the silence watchdog sends
|
|
114
|
+
* the same machine key as the task itself, so a red card
|
|
115
|
+
* `#heartbeat #daily_import` did not get closed by a green
|
|
116
|
+
* `#job #daily_import` — the parser looks for a pair by the FULL tag.
|
|
117
|
+
* One stream per task fixes that.
|
|
112
118
|
*/
|
|
113
119
|
status: 'ok' | 'fail' | 'disabled' | 'silent';
|
|
114
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* The one qualifier the name needs to be readable on its own, printed in
|
|
122
|
+
* brackets right after it: `Yandex game import (reporting again)`. It is
|
|
123
|
+
* the same slot a report uses for the day it covers. Anything that is a
|
|
124
|
+
* FACT about the job goes in a row of its own; this is for the word that
|
|
125
|
+
* finishes the name.
|
|
126
|
+
*/
|
|
127
|
+
aside?: string;
|
|
128
|
+
/** How often the task owes a check-in — for `silent` and for recovering from it. */
|
|
115
129
|
expected?: string;
|
|
116
|
-
/**
|
|
130
|
+
/** When it was last seen. */
|
|
117
131
|
lastSeen?: string;
|
|
118
132
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
* (
|
|
123
|
-
*
|
|
133
|
+
* Numbers from the sender. The third element is the GROUP NAME the
|
|
134
|
+
* row will sit under. The owner asked for groups six times, and every
|
|
135
|
+
* time the sender was already trying to fake them with whatever was
|
|
136
|
+
* at hand: parentheses in the label ("GA4 users (sum of days)"), an
|
|
137
|
+
* icon at the start of the row (🆕 versus ⚠), an extra row at the
|
|
138
|
+
* bottom. There was nothing to group with — now there is.
|
|
124
139
|
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
140
|
+
* Without the third element the row goes with no heading, as before:
|
|
141
|
+
* every existing sender keeps working unchanged.
|
|
127
142
|
*/
|
|
128
143
|
stats?: Array<[label: string, value: string | number, group?: string]>;
|
|
129
|
-
/**
|
|
144
|
+
/** Details: exactly what failed, notes from the run; for `disabled` — the list of switched-off processes (each with its own link). */
|
|
130
145
|
items?: Item[];
|
|
131
146
|
note?: string;
|
|
132
147
|
/**
|
|
@@ -136,9 +151,10 @@ export type NotifyEvent = Keyed & (
|
|
|
136
151
|
*/
|
|
137
152
|
command?: string;
|
|
138
153
|
/**
|
|
139
|
-
* WHAT that command does. The owner, on a bare `rm` in a card: "
|
|
140
|
-
*
|
|
141
|
-
* cannot read is one he cannot run, so it never
|
|
154
|
+
* WHAT that command does. The owner, on a bare `rm` in a card: "I'm
|
|
155
|
+
* about to type it and do god knows what, I don't even know what I'm
|
|
156
|
+
* doing." A command he cannot read is one he cannot run, so it never
|
|
157
|
+
* travels alone.
|
|
142
158
|
*/
|
|
143
159
|
commandNote?: string;
|
|
144
160
|
/**
|
|
@@ -148,34 +164,40 @@ export type NotifyEvent = Keyed & (
|
|
|
148
164
|
*/
|
|
149
165
|
logs?: string;
|
|
150
166
|
workflowUrl?: string;
|
|
151
|
-
/**
|
|
167
|
+
/** The run's name, for the link's visible text (defaults to `open`). */
|
|
152
168
|
workflowName?: string;
|
|
153
169
|
/**
|
|
154
|
-
*
|
|
155
|
-
* `--url`.
|
|
156
|
-
*
|
|
170
|
+
* A fallback name for the run link: half the senders send it as
|
|
171
|
+
* `--url`. The renderer takes `workflowUrl ?? url`, so both names
|
|
172
|
+
* work. In new calls prefer `workflowUrl` — it says where it leads.
|
|
157
173
|
*/
|
|
158
174
|
url?: string;
|
|
159
175
|
}
|
|
160
|
-
/**
|
|
176
|
+
/** A summary with numbers: a daily report, an analytics digest. */
|
|
161
177
|
| {
|
|
162
178
|
type: 'report';
|
|
163
179
|
project: Project;
|
|
164
180
|
title: string;
|
|
165
|
-
|
|
166
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Printed in brackets after the title — which day the report covers, or
|
|
183
|
+
* which day its arrows are measured against. Same slot, same name, as a
|
|
184
|
+
* job's. `period` is the old spelling of this field and the CLI still
|
|
185
|
+
* accepts `--period` for it.
|
|
186
|
+
*/
|
|
187
|
+
aside?: string;
|
|
188
|
+
/** Empty/not passed when `groups` is used — the two kinds of report are not mixed in one event. */
|
|
167
189
|
lines?: Array<[label: string, value: string | number, group?: string]>;
|
|
168
190
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* `lines`.
|
|
191
|
+
* A list of items with links — for task digests, where the value is
|
|
192
|
+
* in the names themselves, not in a number. Renders as a separate
|
|
193
|
+
* block after `lines`.
|
|
172
194
|
*/
|
|
173
195
|
items?: Item[];
|
|
174
196
|
/**
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
197
|
+
* Named groups (a task board: Ready/In Progress/Not on the board;
|
|
198
|
+
* analytics: Metrics/Links) — each with its own heading and list of
|
|
199
|
+
* items. Replaces `lines`/`items` when set: different reports use
|
|
200
|
+
* either the flat form or groups, never both at once.
|
|
179
201
|
*/
|
|
180
202
|
groups?: Array<{
|
|
181
203
|
name: string;
|
|
@@ -183,18 +205,18 @@ export type NotifyEvent = Keyed & (
|
|
|
183
205
|
}>;
|
|
184
206
|
url?: string;
|
|
185
207
|
}
|
|
186
|
-
/**
|
|
208
|
+
/** The CI outcome on the main branch. */
|
|
187
209
|
| {
|
|
188
210
|
type: 'ci';
|
|
189
211
|
project: Project;
|
|
190
212
|
status: 'ok' | 'fail';
|
|
191
213
|
branch?: string;
|
|
192
214
|
commit?: string;
|
|
193
|
-
/**
|
|
215
|
+
/** A link to the commit — the hash becomes clickable. */
|
|
194
216
|
commitUrl?: string;
|
|
195
|
-
/**
|
|
217
|
+
/** The commit's title (subject) — a separate `Title:` field, not a quote. */
|
|
196
218
|
commitTitle?: string;
|
|
197
|
-
/**
|
|
219
|
+
/** The commit's body (after the subject) — the same quote shape as the title. */
|
|
198
220
|
commitBody?: string;
|
|
199
221
|
actor?: string;
|
|
200
222
|
/**
|
|
@@ -202,16 +224,17 @@ export type NotifyEvent = Keyed & (
|
|
|
202
224
|
* schedule, a manual press. Renders as `Reason:`, same as on deploy.
|
|
203
225
|
*/
|
|
204
226
|
note?: string;
|
|
205
|
-
/**
|
|
227
|
+
/** A link to the run (workflow run) — separate from `url`, a fallback for `workflowUrl`. */
|
|
206
228
|
workflowUrl?: string;
|
|
207
|
-
/**
|
|
229
|
+
/** The run's name, for the link's visible text (defaults to `open`). */
|
|
208
230
|
workflowName?: string;
|
|
209
231
|
url?: string;
|
|
210
232
|
}
|
|
211
233
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
234
|
+
* A pull request event. The kinds cover the whole life of a PR, because
|
|
235
|
+
* the owner follows the team's work through the Ops tab, not through
|
|
236
|
+
* mail: mail only arrives when you were personally pinged, and half of
|
|
237
|
+
* the events never reach it.
|
|
215
238
|
*/
|
|
216
239
|
| {
|
|
217
240
|
type: 'pr';
|
|
@@ -225,26 +248,26 @@ export type NotifyEvent = Keyed & (
|
|
|
225
248
|
reviewer?: string;
|
|
226
249
|
url?: string;
|
|
227
250
|
}
|
|
228
|
-
/**
|
|
251
|
+
/** An issue event: filed, taken up, closed. */
|
|
229
252
|
| {
|
|
230
253
|
type: 'issue';
|
|
231
254
|
project: Project;
|
|
232
255
|
action: 'opened' | 'assigned' | 'closed';
|
|
233
256
|
number: number;
|
|
234
257
|
title: string;
|
|
235
|
-
/**
|
|
258
|
+
/** The issue's body — a quote under the `Title:` field, separate from the title. */
|
|
236
259
|
body?: string;
|
|
237
260
|
author?: string;
|
|
238
261
|
assignee?: string;
|
|
239
262
|
url?: string;
|
|
240
263
|
}
|
|
241
|
-
/**
|
|
264
|
+
/** The app is broken right now (a runtime alert). */
|
|
242
265
|
| {
|
|
243
266
|
type: 'incident';
|
|
244
267
|
project: Project;
|
|
245
268
|
title: string;
|
|
246
269
|
detail?: string;
|
|
247
|
-
/**
|
|
270
|
+
/** A local path to the logs (not a URL — renders monospaced, to copy, not to click). */
|
|
248
271
|
logs?: string;
|
|
249
272
|
url?: string;
|
|
250
273
|
}
|
|
@@ -284,10 +307,10 @@ export type NotifyEvent = Keyed & (
|
|
|
284
307
|
status?: 'fail' | 'ok';
|
|
285
308
|
}
|
|
286
309
|
/**
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
310
|
+
* DEPRECATED since 1.4.2: use `job` with status `silent`. The type stays,
|
|
311
|
+
* because the silence watchdog lives on the server and sends exactly this
|
|
312
|
+
* one until it is redeployed — removing it means losing the silence card
|
|
313
|
+
* exactly when it is needed. Do not add new calls.
|
|
291
314
|
*/
|
|
292
315
|
| {
|
|
293
316
|
type: 'heartbeat_miss';
|
|
@@ -295,27 +318,28 @@ export type NotifyEvent = Keyed & (
|
|
|
295
318
|
job: string;
|
|
296
319
|
lastSeen?: string;
|
|
297
320
|
expected?: string;
|
|
298
|
-
/**
|
|
321
|
+
/** The task reported in again — same type, a green card instead of a red one, the key (for matching) does not change. */
|
|
299
322
|
recovered?: boolean;
|
|
300
|
-
/**
|
|
323
|
+
/** A ready-made reason sentence; without it, one is built from lastSeen/expected. */
|
|
301
324
|
note?: string;
|
|
302
325
|
});
|
|
303
326
|
export type EventType = NotifyEvent['type'];
|
|
304
|
-
/**
|
|
327
|
+
/** Red = with sound. Everything else is silent. (There is no separate "incidents" topic any more — an incident is visible in the project's feed.) */
|
|
305
328
|
/**
|
|
306
|
-
*
|
|
329
|
+
* The icon dictionary. Two laws, both set by the owner on 25.08.2026:
|
|
307
330
|
*
|
|
308
|
-
* 1.
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
* silent —
|
|
312
|
-
* 2.
|
|
313
|
-
*
|
|
314
|
-
*
|
|
331
|
+
* 1. WITHIN one tag every word gets its own icon. There used to be exactly
|
|
332
|
+
* four icons for the whole package, and `Issue: opened` looked the same
|
|
333
|
+
* as `Issue: assigned`, while a task's three different kinds of trouble —
|
|
334
|
+
* fail, disabled, silent — were the same red circle.
|
|
335
|
+
* 2. BETWEEN tags the same meaning looks the same. `fail` is 🔴 whether on a
|
|
336
|
+
* deploy, on CI, or on a task; "something new appeared" is 🆕 on a board
|
|
337
|
+
* task, on a PR, and on a file alike.
|
|
315
338
|
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
339
|
+
* And a third law that keeps the first two honest: the sound is a fixed
|
|
340
|
+
* property of the icon. Not of the event, not of the status — of the icon.
|
|
341
|
+
* While the sound was a separate rule, `🔴 PR: changes_requested` arrived
|
|
342
|
+
* silent.
|
|
319
343
|
*/
|
|
320
344
|
export declare const ICON: {
|
|
321
345
|
readonly ok: "✅";
|
|
@@ -339,7 +363,7 @@ export declare const PR_ICON: Record<Extract<NotifyEvent, {
|
|
|
339
363
|
export declare const ISSUE_ICON: Record<Extract<NotifyEvent, {
|
|
340
364
|
type: 'issue';
|
|
341
365
|
}>['action'], string>;
|
|
342
|
-
/**
|
|
366
|
+
/** One place decides the card's icon — both the render and the sound take it from here. */
|
|
343
367
|
export declare const iconFor: (e: NotifyEvent) => string;
|
|
344
368
|
export declare const severity: (e: NotifyEvent) => "info" | "error";
|
|
345
369
|
export {};
|
package/dist/events.js
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* `send.ts`)
|
|
4
|
-
*
|
|
2
|
+
* The event catalogue — the single entry point for sending. `notify()` (see
|
|
3
|
+
* `send.ts`) accepts ONLY values of this type: there is no free text in the
|
|
4
|
+
* API, so a "custom" message cannot technically be written.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
6
|
+
* The schema evolution rule (there is no version and never will be — a
|
|
7
|
+
* message lives one second and is read by eyes, there is nothing to
|
|
8
|
+
* version):
|
|
9
|
+
* - a new field on an EXISTING type is added ONLY as optional;
|
|
10
|
+
* - required fields are never added — only a new event type.
|
|
11
|
+
* That keeps old caller code and a new package compatible both ways.
|
|
11
12
|
*/
|
|
12
|
-
/**
|
|
13
|
+
/** Red = with sound. Everything else is silent. (There is no separate "incidents" topic any more — an incident is visible in the project's feed.) */
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
+
* The icon dictionary. Two laws, both set by the owner on 25.08.2026:
|
|
15
16
|
*
|
|
16
|
-
* 1.
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* silent —
|
|
20
|
-
* 2.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
17
|
+
* 1. WITHIN one tag every word gets its own icon. There used to be exactly
|
|
18
|
+
* four icons for the whole package, and `Issue: opened` looked the same
|
|
19
|
+
* as `Issue: assigned`, while a task's three different kinds of trouble —
|
|
20
|
+
* fail, disabled, silent — were the same red circle.
|
|
21
|
+
* 2. BETWEEN tags the same meaning looks the same. `fail` is 🔴 whether on a
|
|
22
|
+
* deploy, on CI, or on a task; "something new appeared" is 🆕 on a board
|
|
23
|
+
* task, on a PR, and on a file alike.
|
|
23
24
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
25
|
+
* And a third law that keeps the first two honest: the sound is a fixed
|
|
26
|
+
* property of the icon. Not of the event, not of the status — of the icon.
|
|
27
|
+
* While the sound was a separate rule, `🔴 PR: changes_requested` arrived
|
|
28
|
+
* silent.
|
|
27
29
|
*/
|
|
28
30
|
export const ICON = {
|
|
29
31
|
ok: '✅', // passed, closed, done
|
|
@@ -59,7 +61,7 @@ const JOB_ICON = {
|
|
|
59
61
|
disabled: ICON.off,
|
|
60
62
|
silent: ICON.unknown
|
|
61
63
|
};
|
|
62
|
-
/**
|
|
64
|
+
/** One place decides the card's icon — both the render and the sound take it from here. */
|
|
63
65
|
export const iconFor = (e) => {
|
|
64
66
|
switch (e.type) {
|
|
65
67
|
case 'deploy':
|