vibe-squire 2.2.0 → 2.3.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/dist/status/dto/status-snapshot.dto.d.ts +1 -0
- package/dist/status/dto/status-snapshot.dto.js +7 -0
- package/dist/status/dto/status-snapshot.dto.js.map +1 -1
- package/dist/status/status-snapshot.schema.d.ts +1 -0
- package/dist/status/status-snapshot.schema.js +1 -0
- package/dist/status/status-snapshot.schema.js.map +1 -1
- package/dist/status/status.controller.d.ts +1 -0
- package/dist/status/status.service.d.ts +2 -0
- package/dist/status/status.service.js +32 -3
- package/dist/status/status.service.js.map +1 -1
- package/dist/sync/triage-live-state.queries.d.ts +6 -0
- package/dist/sync/triage-live-state.queries.js +27 -0
- package/dist/sync/triage-live-state.queries.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/ui/activity-api.controller.d.ts +4 -12
- package/dist/ui/activity-api.controller.js +12 -3
- package/dist/ui/activity-api.controller.js.map +1 -1
- package/dist/ui/public/operator-activity.js +122 -10
- package/dist/ui/public/operator-shell.js +53 -0
- package/dist/ui/public/operator.css +37 -1
- package/dist/ui/ui-presenter.d.ts +16 -12
- package/dist/ui/ui-presenter.js +34 -12
- package/dist/ui/ui-presenter.js.map +1 -1
- package/dist/ui/views/partials/nav.hbs +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { PrismaService } from '../prisma/prisma.service';
|
|
1
2
|
import { PollRunHistoryService } from '../sync/poll-run-history.service';
|
|
2
3
|
export declare class ActivityApiController {
|
|
3
4
|
private readonly pollRunHistory;
|
|
4
|
-
|
|
5
|
+
private readonly prisma;
|
|
6
|
+
constructor(pollRunHistory: PollRunHistoryService, prisma: PrismaService);
|
|
5
7
|
runs(limitRaw?: string): Promise<{
|
|
6
8
|
runs: {
|
|
7
9
|
id: string;
|
|
@@ -23,17 +25,7 @@ export declare class ActivityApiController {
|
|
|
23
25
|
skippedTriage: number | null;
|
|
24
26
|
skippedDeclined: number | null;
|
|
25
27
|
itemCount: number;
|
|
26
|
-
items:
|
|
27
|
-
prUrl: string;
|
|
28
|
-
githubRepo: string;
|
|
29
|
-
prNumber: number;
|
|
30
|
-
prTitle: string;
|
|
31
|
-
authorLogin: string | null;
|
|
32
|
-
decision: string;
|
|
33
|
-
decisionLabel: string;
|
|
34
|
-
detail: string | null;
|
|
35
|
-
kanbanIssueId: string | null;
|
|
36
|
-
}>;
|
|
28
|
+
items: import("./ui-presenter").ActivityItem[];
|
|
37
29
|
}[];
|
|
38
30
|
}>;
|
|
39
31
|
}
|
|
@@ -15,14 +15,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.ActivityApiController = void 0;
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
17
|
const swagger_1 = require("@nestjs/swagger");
|
|
18
|
+
const prisma_service_1 = require("../prisma/prisma.service");
|
|
18
19
|
const poll_run_history_service_1 = require("../sync/poll-run-history.service");
|
|
20
|
+
const triage_live_state_queries_1 = require("../sync/triage-live-state.queries");
|
|
19
21
|
const ui_presenter_1 = require("./ui-presenter");
|
|
20
22
|
const DEFAULT_LIMIT = 40;
|
|
21
23
|
const MAX_LIMIT = 100;
|
|
22
24
|
let ActivityApiController = class ActivityApiController {
|
|
23
25
|
pollRunHistory;
|
|
24
|
-
|
|
26
|
+
prisma;
|
|
27
|
+
constructor(pollRunHistory, prisma) {
|
|
25
28
|
this.pollRunHistory = pollRunHistory;
|
|
29
|
+
this.prisma = prisma;
|
|
26
30
|
}
|
|
27
31
|
async runs(limitRaw) {
|
|
28
32
|
let limit = DEFAULT_LIMIT;
|
|
@@ -33,7 +37,11 @@ let ActivityApiController = class ActivityApiController {
|
|
|
33
37
|
}
|
|
34
38
|
}
|
|
35
39
|
const rows = await this.pollRunHistory.listRecentForUi(limit);
|
|
36
|
-
|
|
40
|
+
const allPrUrls = new Set(rows.flatMap((r) => r.items.map((i) => i.prUrl)));
|
|
41
|
+
const live = await (0, triage_live_state_queries_1.fetchTriageLiveState)(this.prisma, allPrUrls);
|
|
42
|
+
return {
|
|
43
|
+
runs: (0, ui_presenter_1.presentActivityRunsForView)(rows, live),
|
|
44
|
+
};
|
|
37
45
|
}
|
|
38
46
|
};
|
|
39
47
|
exports.ActivityApiController = ActivityApiController;
|
|
@@ -53,6 +61,7 @@ __decorate([
|
|
|
53
61
|
exports.ActivityApiController = ActivityApiController = __decorate([
|
|
54
62
|
(0, swagger_1.ApiTags)('activity'),
|
|
55
63
|
(0, common_1.Controller)('api/activity'),
|
|
56
|
-
__metadata("design:paramtypes", [poll_run_history_service_1.PollRunHistoryService
|
|
64
|
+
__metadata("design:paramtypes", [poll_run_history_service_1.PollRunHistoryService,
|
|
65
|
+
prisma_service_1.PrismaService])
|
|
57
66
|
], ActivityApiController);
|
|
58
67
|
//# sourceMappingURL=activity-api.controller.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-api.controller.js","sourceRoot":"","sources":["../../src/ui/activity-api.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwD;AACxD,6CAAuE;AACvE,+EAAyE;AACzE,iDAA4D;AAE5D,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,SAAS,GAAG,GAAG,CAAC;AAIf,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;
|
|
1
|
+
{"version":3,"file":"activity-api.controller.js","sourceRoot":"","sources":["../../src/ui/activity-api.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwD;AACxD,6CAAuE;AACvE,6DAAyD;AACzD,+EAAyE;AACzE,iFAAyE;AACzE,iDAA4D;AAE5D,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,SAAS,GAAG,GAAG,CAAC;AAIf,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAEb;IACA;IAFnB,YACmB,cAAqC,EACrC,MAAqB;QADrB,mBAAc,GAAd,cAAc,CAAuB;QACrC,WAAM,GAAN,MAAM,CAAe;IACrC,CAAC;IAUE,AAAN,KAAK,CAAC,IAAI,CAAiB,QAAiB;QAC1C,IAAI,KAAK,GAAG,aAAa,CAAC;QAC1B,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;YAC9C,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YACxC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5E,MAAM,IAAI,GAAG,MAAM,IAAA,gDAAoB,EAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAEhE,OAAO;YACL,IAAI,EAAE,IAAA,yCAA0B,EAAC,IAAI,EAAE,IAAI,CAAC;SAC7C,CAAC;IACJ,CAAC;CACF,CAAA;AA9BY,sDAAqB;AAc1B;IARL,IAAA,YAAG,EAAC,MAAM,CAAC;IACX,IAAA,sBAAY,EAAC;QACZ,OAAO,EAAE,qDAAqD;KAC/D,CAAC;IACD,IAAA,uBAAa,EAAC;QACb,WAAW,EACT,6EAA6E;KAChF,CAAC;IACU,WAAA,IAAA,cAAK,EAAC,OAAO,CAAC,CAAA;;;;iDAezB;gCA7BU,qBAAqB;IAFjC,IAAA,iBAAO,EAAC,UAAU,CAAC;IACnB,IAAA,mBAAU,EAAC,cAAc,CAAC;qCAGU,gDAAqB;QAC7B,8BAAa;GAH7B,qBAAqB,CA8BjC"}
|
|
@@ -18,13 +18,79 @@
|
|
|
18
18
|
skipped_board_limit: true,
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
var OPTIMISTIC_KEY = 'vs_triage_optimistic';
|
|
22
|
+
|
|
23
|
+
function loadOptimistic() {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(localStorage.getItem(OPTIMISTIC_KEY) || '{}');
|
|
26
|
+
} catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function saveOptimistic(map) {
|
|
32
|
+
try {
|
|
33
|
+
localStorage.setItem(OPTIMISTIC_KEY, JSON.stringify(map));
|
|
34
|
+
} catch {
|
|
35
|
+
/* quota exceeded — ignore */
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function markOptimistic(prUrl, action) {
|
|
40
|
+
var map = loadOptimistic();
|
|
41
|
+
map[prUrl] = action;
|
|
42
|
+
saveOptimistic(map);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function clearOptimistic(prUrl) {
|
|
46
|
+
var map = loadOptimistic();
|
|
47
|
+
delete map[prUrl];
|
|
48
|
+
saveOptimistic(map);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function applyOptimistic(items) {
|
|
52
|
+
var map = loadOptimistic();
|
|
53
|
+
var dirty = false;
|
|
54
|
+
for (var i = 0; i < items.length; i++) {
|
|
55
|
+
var it = items[i];
|
|
56
|
+
var opt = map[it.prUrl];
|
|
57
|
+
if (!opt) continue;
|
|
58
|
+
var eff = it.effectiveDecision || it.decision;
|
|
59
|
+
if (opt === 'accept' && !isTriageable(eff)) {
|
|
60
|
+
delete map[it.prUrl];
|
|
61
|
+
dirty = true;
|
|
62
|
+
} else if (opt === 'decline' && eff === 'skipped_declined') {
|
|
63
|
+
delete map[it.prUrl];
|
|
64
|
+
dirty = true;
|
|
65
|
+
} else if (opt === 'reconsider' && isTriageable(eff)) {
|
|
66
|
+
delete map[it.prUrl];
|
|
67
|
+
dirty = true;
|
|
68
|
+
} else if (opt === 'accept') {
|
|
69
|
+
it.effectiveDecision = 'linked_existing';
|
|
70
|
+
it.decisionLabel = 'Accepted (pending refresh)';
|
|
71
|
+
} else if (opt === 'decline') {
|
|
72
|
+
it.effectiveDecision = 'skipped_declined';
|
|
73
|
+
it.decisionLabel = 'Declined (pending refresh)';
|
|
74
|
+
} else if (opt === 'reconsider') {
|
|
75
|
+
it.effectiveDecision = 'skipped_triage';
|
|
76
|
+
it.decisionLabel = 'Pending triage';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (dirty) saveOptimistic(map);
|
|
80
|
+
}
|
|
81
|
+
|
|
21
82
|
function isTriageable(decision) {
|
|
22
83
|
return TRIAGEABLE_DECISIONS[decision] === true;
|
|
23
84
|
}
|
|
24
85
|
|
|
86
|
+
function effectiveOf(it) {
|
|
87
|
+
return it.effectiveDecision || it.decision;
|
|
88
|
+
}
|
|
89
|
+
|
|
25
90
|
function triageSortKey(it) {
|
|
26
|
-
|
|
27
|
-
if (
|
|
91
|
+
var eff = effectiveOf(it);
|
|
92
|
+
if (isTriageable(eff)) return 0;
|
|
93
|
+
if (eff === 'skipped_declined') return 1;
|
|
28
94
|
return 2;
|
|
29
95
|
}
|
|
30
96
|
|
|
@@ -39,7 +105,8 @@
|
|
|
39
105
|
|
|
40
106
|
function triageActionButtons(it) {
|
|
41
107
|
var url = esc(it.prUrl);
|
|
42
|
-
|
|
108
|
+
var eff = effectiveOf(it);
|
|
109
|
+
if (isTriageable(eff)) {
|
|
43
110
|
return (
|
|
44
111
|
'<div class="triage-actions" style="margin-top:0.3rem">' +
|
|
45
112
|
'<button class="btn btn-sm primary js-triage-accept" data-pr-url="' +
|
|
@@ -51,7 +118,7 @@
|
|
|
51
118
|
'</div>'
|
|
52
119
|
);
|
|
53
120
|
}
|
|
54
|
-
if (
|
|
121
|
+
if (eff === 'skipped_declined') {
|
|
55
122
|
return (
|
|
56
123
|
'<div class="triage-actions" style="margin-top:0.3rem">' +
|
|
57
124
|
'<button class="btn btn-sm ghost js-triage-reconsider" data-pr-url="' +
|
|
@@ -65,7 +132,11 @@
|
|
|
65
132
|
|
|
66
133
|
function renderItemsTable(items) {
|
|
67
134
|
if (!items || !items.length) return '';
|
|
135
|
+
applyOptimistic(items);
|
|
68
136
|
var sorted = sortItemsForTriage(items);
|
|
137
|
+
var hasTriageable = sorted.some(function (it) {
|
|
138
|
+
return isTriageable(effectiveOf(it));
|
|
139
|
+
});
|
|
69
140
|
var rows = sorted
|
|
70
141
|
.map(function (it) {
|
|
71
142
|
var detailParts = [];
|
|
@@ -86,9 +157,10 @@
|
|
|
86
157
|
'<div class="muted" style="font-size:0.8rem">@' +
|
|
87
158
|
esc(it.authorLogin) +
|
|
88
159
|
'</div>';
|
|
89
|
-
var
|
|
160
|
+
var eff = effectiveOf(it);
|
|
161
|
+
var rowClass = isTriageable(eff)
|
|
90
162
|
? ' class="triage-pending-row"'
|
|
91
|
-
:
|
|
163
|
+
: eff === 'skipped_declined'
|
|
92
164
|
? ' class="triage-declined-row"'
|
|
93
165
|
: '';
|
|
94
166
|
return (
|
|
@@ -121,10 +193,16 @@
|
|
|
121
193
|
})
|
|
122
194
|
.join('');
|
|
123
195
|
return (
|
|
124
|
-
'<details class="activity-details"
|
|
196
|
+
'<details class="activity-details"' +
|
|
197
|
+
(hasTriageable ? ' open' : '') +
|
|
198
|
+
'>' +
|
|
125
199
|
'<summary class="activity-details-summary">PR details (' +
|
|
126
200
|
items.length +
|
|
127
|
-
')
|
|
201
|
+
')' +
|
|
202
|
+
(hasTriageable
|
|
203
|
+
? ' · <span class="triage-attention-hint">needs attention</span>'
|
|
204
|
+
: '') +
|
|
205
|
+
'</summary>' +
|
|
128
206
|
'<div class="table-wrap activity-items-wrap">' +
|
|
129
207
|
'<table class="data-table activity-items-table">' +
|
|
130
208
|
'<thead><tr><th>PR</th><th>Repo</th><th>Outcome</th><th>Detail</th></tr></thead>' +
|
|
@@ -209,6 +287,37 @@
|
|
|
209
287
|
);
|
|
210
288
|
}
|
|
211
289
|
|
|
290
|
+
function countUniqueTriageable(runs) {
|
|
291
|
+
var seen = {};
|
|
292
|
+
var count = 0;
|
|
293
|
+
for (var r = 0; r < runs.length; r++) {
|
|
294
|
+
var items = runs[r].items || [];
|
|
295
|
+
for (var i = 0; i < items.length; i++) {
|
|
296
|
+
var eff = items[i].effectiveDecision || items[i].decision;
|
|
297
|
+
if (isTriageable(eff) && !seen[items[i].prUrl]) {
|
|
298
|
+
seen[items[i].prUrl] = true;
|
|
299
|
+
count++;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return count;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function renderTriageBanner(runs) {
|
|
307
|
+
applyOptimistic((runs[0] && runs[0].items) || []);
|
|
308
|
+
var count = countUniqueTriageable(runs);
|
|
309
|
+
if (count === 0) return '';
|
|
310
|
+
return (
|
|
311
|
+
'<div class="banner banner-triage-attention">' +
|
|
312
|
+
'<strong>' +
|
|
313
|
+
count +
|
|
314
|
+
' PR' +
|
|
315
|
+
(count === 1 ? '' : 's') +
|
|
316
|
+
'</strong> awaiting your review or decline decision.' +
|
|
317
|
+
'</div>'
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
212
321
|
function renderRuns(runs) {
|
|
213
322
|
if (!runs || !runs.length) {
|
|
214
323
|
return (
|
|
@@ -217,7 +326,7 @@
|
|
|
217
326
|
'</div>'
|
|
218
327
|
);
|
|
219
328
|
}
|
|
220
|
-
return runs.map(renderRun).join('');
|
|
329
|
+
return renderTriageBanner(runs) + runs.map(renderRun).join('');
|
|
221
330
|
}
|
|
222
331
|
|
|
223
332
|
var pollTimer = null;
|
|
@@ -283,6 +392,8 @@
|
|
|
283
392
|
|
|
284
393
|
function triageAction(endpoint, prUrl, btn) {
|
|
285
394
|
btn.disabled = true;
|
|
395
|
+
markOptimistic(prUrl, endpoint);
|
|
396
|
+
void load();
|
|
286
397
|
fetch('/api/pr/' + endpoint, {
|
|
287
398
|
method: 'POST',
|
|
288
399
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -293,7 +404,8 @@
|
|
|
293
404
|
void load();
|
|
294
405
|
})
|
|
295
406
|
.catch(function () {
|
|
296
|
-
|
|
407
|
+
clearOptimistic(prUrl);
|
|
408
|
+
void load();
|
|
297
409
|
});
|
|
298
410
|
}
|
|
299
411
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
var SSE_EVENT =
|
|
5
5
|
VS.STATUS_SNAPSHOT_EVENT || g.__VS_SSE_EVENT__ || 'vibesquire:status-snapshot';
|
|
6
6
|
var stateEl = document.getElementById('nav-sse-state');
|
|
7
|
+
var badgeEl = document.getElementById('nav-triage-badge');
|
|
7
8
|
|
|
8
9
|
function setSse(s) {
|
|
9
10
|
if (!stateEl) return;
|
|
@@ -11,6 +12,48 @@
|
|
|
11
12
|
stateEl.className = 'sse sse-' + s;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
/* ── Nav badge ── */
|
|
16
|
+
|
|
17
|
+
function updateTriageBadge(count) {
|
|
18
|
+
if (!badgeEl) return;
|
|
19
|
+
if (count > 0) {
|
|
20
|
+
badgeEl.textContent = String(count);
|
|
21
|
+
badgeEl.hidden = false;
|
|
22
|
+
} else {
|
|
23
|
+
badgeEl.textContent = '';
|
|
24
|
+
badgeEl.hidden = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* ── Web Notifications ── */
|
|
29
|
+
|
|
30
|
+
var lastNotifiedTriageKey = '';
|
|
31
|
+
|
|
32
|
+
function requestNotificationPermission() {
|
|
33
|
+
if (!('Notification' in g)) return;
|
|
34
|
+
if (Notification.permission === 'default') {
|
|
35
|
+
Notification.requestPermission();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function maybeNotifyTriage(count) {
|
|
40
|
+
if (!('Notification' in g) || Notification.permission !== 'granted') return;
|
|
41
|
+
if (count <= 0) {
|
|
42
|
+
lastNotifiedTriageKey = '';
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
var key = String(count);
|
|
46
|
+
if (key === lastNotifiedTriageKey) return;
|
|
47
|
+
lastNotifiedTriageKey = key;
|
|
48
|
+
new Notification('vibe-squire: PRs need triage', {
|
|
49
|
+
body: count + ' PR(s) awaiting your review or decline decision',
|
|
50
|
+
icon: '/ui/assets/favicon.svg',
|
|
51
|
+
tag: 'vs-triage',
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* ── Snapshot dispatch ── */
|
|
56
|
+
|
|
14
57
|
function publishSnapshot(snap) {
|
|
15
58
|
if (!snap || typeof snap !== 'object') return;
|
|
16
59
|
try {
|
|
@@ -18,9 +61,17 @@
|
|
|
18
61
|
} catch {
|
|
19
62
|
/* ignore */
|
|
20
63
|
}
|
|
64
|
+
var triageCount =
|
|
65
|
+
typeof snap.pending_triage_count === 'number'
|
|
66
|
+
? snap.pending_triage_count
|
|
67
|
+
: 0;
|
|
68
|
+
updateTriageBadge(triageCount);
|
|
69
|
+
maybeNotifyTriage(triageCount);
|
|
21
70
|
g.dispatchEvent(new CustomEvent(SSE_EVENT, { detail: snap }));
|
|
22
71
|
}
|
|
23
72
|
|
|
73
|
+
/* ── SSE connection ── */
|
|
74
|
+
|
|
24
75
|
var es = new EventSource('/api/status/stream');
|
|
25
76
|
setSse('connecting');
|
|
26
77
|
es.onopen = function () {
|
|
@@ -40,4 +91,6 @@
|
|
|
40
91
|
/* ignore */
|
|
41
92
|
}
|
|
42
93
|
};
|
|
94
|
+
|
|
95
|
+
requestNotificationPermission();
|
|
43
96
|
})();
|
|
@@ -145,6 +145,23 @@ code {
|
|
|
145
145
|
color: var(--accent);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
.nav-badge {
|
|
149
|
+
display: inline-flex;
|
|
150
|
+
align-items: center;
|
|
151
|
+
justify-content: center;
|
|
152
|
+
min-width: 1.25rem;
|
|
153
|
+
height: 1.25rem;
|
|
154
|
+
padding: 0 0.35rem;
|
|
155
|
+
border-radius: 999px;
|
|
156
|
+
background: var(--warn);
|
|
157
|
+
color: var(--bg);
|
|
158
|
+
font-size: 0.7rem;
|
|
159
|
+
font-weight: 700;
|
|
160
|
+
font-family: var(--mono);
|
|
161
|
+
margin-left: 0.4rem;
|
|
162
|
+
vertical-align: middle;
|
|
163
|
+
}
|
|
164
|
+
|
|
148
165
|
.nav-foot {
|
|
149
166
|
margin-top: auto;
|
|
150
167
|
font-size: 0.72rem;
|
|
@@ -707,7 +724,8 @@ textarea.input {
|
|
|
707
724
|
|
|
708
725
|
/* Triage rows */
|
|
709
726
|
.triage-pending-row {
|
|
710
|
-
background: rgba(
|
|
727
|
+
background: rgba(201, 162, 39, 0.09);
|
|
728
|
+
border-left: 3px solid var(--warn);
|
|
711
729
|
}
|
|
712
730
|
|
|
713
731
|
.triage-declined-row {
|
|
@@ -719,3 +737,21 @@ textarea.input {
|
|
|
719
737
|
gap: 0.35rem;
|
|
720
738
|
flex-wrap: wrap;
|
|
721
739
|
}
|
|
740
|
+
|
|
741
|
+
.triage-attention-hint {
|
|
742
|
+
color: var(--warn);
|
|
743
|
+
font-weight: 600;
|
|
744
|
+
font-size: 0.82rem;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* Triage attention banner */
|
|
748
|
+
.banner-triage-attention {
|
|
749
|
+
background: rgba(201, 162, 39, 0.12);
|
|
750
|
+
border: 1px solid rgba(201, 162, 39, 0.3);
|
|
751
|
+
border-left: 3px solid var(--warn);
|
|
752
|
+
color: var(--text-strong);
|
|
753
|
+
padding: 0.65rem 1rem;
|
|
754
|
+
border-radius: 6px;
|
|
755
|
+
font-size: 0.9rem;
|
|
756
|
+
margin-bottom: 1rem;
|
|
757
|
+
}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import type { SetupEvaluation } from '../setup/setup-evaluation.service';
|
|
2
2
|
import type { PollRunHistoryService } from '../sync/poll-run-history.service';
|
|
3
3
|
import type { UiNavEntry } from '../ports/ui-nav.types';
|
|
4
|
+
import type { TriageLiveState } from '../sync/triage-live-state.queries';
|
|
5
|
+
export type { TriageLiveState } from '../sync/triage-live-state.queries';
|
|
4
6
|
export type PollRunRowForActivity = Awaited<ReturnType<PollRunHistoryService['listRecentForUi']>>[number];
|
|
5
|
-
export
|
|
7
|
+
export type ActivityItem = {
|
|
8
|
+
prUrl: string;
|
|
9
|
+
githubRepo: string;
|
|
10
|
+
prNumber: number;
|
|
11
|
+
prTitle: string;
|
|
12
|
+
authorLogin: string | null;
|
|
13
|
+
decision: string;
|
|
14
|
+
effectiveDecision: string;
|
|
15
|
+
decisionLabel: string;
|
|
16
|
+
detail: string | null;
|
|
17
|
+
kanbanIssueId: string | null;
|
|
18
|
+
};
|
|
19
|
+
export declare function presentActivityRunsForView(rows: PollRunRowForActivity[], live?: TriageLiveState): Array<{
|
|
6
20
|
id: string;
|
|
7
21
|
startedAt: string;
|
|
8
22
|
startedAtLabel: string;
|
|
@@ -22,17 +36,7 @@ export declare function presentActivityRunsForView(rows: PollRunRowForActivity[]
|
|
|
22
36
|
skippedTriage: number | null;
|
|
23
37
|
skippedDeclined: number | null;
|
|
24
38
|
itemCount: number;
|
|
25
|
-
items:
|
|
26
|
-
prUrl: string;
|
|
27
|
-
githubRepo: string;
|
|
28
|
-
prNumber: number;
|
|
29
|
-
prTitle: string;
|
|
30
|
-
authorLogin: string | null;
|
|
31
|
-
decision: string;
|
|
32
|
-
decisionLabel: string;
|
|
33
|
-
detail: string | null;
|
|
34
|
-
kanbanIssueId: string | null;
|
|
35
|
-
}>;
|
|
39
|
+
items: ActivityItem[];
|
|
36
40
|
}>;
|
|
37
41
|
export declare function escapeForPre(s: string): string;
|
|
38
42
|
export declare function destinationTypeLabel(t: string): string;
|
package/dist/ui/ui-presenter.js
CHANGED
|
@@ -11,6 +11,7 @@ exports.uiNavLocals = uiNavLocals;
|
|
|
11
11
|
exports.githubNotSourceRedirectUrl = githubNotSourceRedirectUrl;
|
|
12
12
|
exports.vibeKanbanNotDestinationRedirectUrl = vibeKanbanNotDestinationRedirectUrl;
|
|
13
13
|
const poll_run_labels_1 = require("../sync/poll-run-labels");
|
|
14
|
+
const poll_run_decisions_1 = require("../sync/poll-run-decisions");
|
|
14
15
|
function formatActivityRunTime(d) {
|
|
15
16
|
const t = d.getTime();
|
|
16
17
|
if (Number.isNaN(t)) {
|
|
@@ -18,7 +19,24 @@ function formatActivityRunTime(d) {
|
|
|
18
19
|
}
|
|
19
20
|
return d.toLocaleString();
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
+
const TRIAGE_DECISIONS = new Set([
|
|
23
|
+
poll_run_decisions_1.POLL_RUN_ITEM_DECISION.skippedTriage,
|
|
24
|
+
poll_run_decisions_1.POLL_RUN_ITEM_DECISION.skippedBoardLimit,
|
|
25
|
+
]);
|
|
26
|
+
const EMPTY_LIVE_STATE = {
|
|
27
|
+
acceptedPrUrls: new Set(),
|
|
28
|
+
declinedPrUrls: new Set(),
|
|
29
|
+
};
|
|
30
|
+
function resolveEffectiveDecision(decision, prUrl, live) {
|
|
31
|
+
if (!TRIAGE_DECISIONS.has(decision))
|
|
32
|
+
return decision;
|
|
33
|
+
if (live.acceptedPrUrls.has(prUrl))
|
|
34
|
+
return poll_run_decisions_1.POLL_RUN_ITEM_DECISION.linkedExisting;
|
|
35
|
+
if (live.declinedPrUrls.has(prUrl))
|
|
36
|
+
return poll_run_decisions_1.POLL_RUN_ITEM_DECISION.skippedDeclined;
|
|
37
|
+
return decision;
|
|
38
|
+
}
|
|
39
|
+
function presentActivityRunsForView(rows, live = EMPTY_LIVE_STATE) {
|
|
22
40
|
return rows.map((r) => ({
|
|
23
41
|
id: r.id,
|
|
24
42
|
startedAt: r.startedAt.toISOString(),
|
|
@@ -39,17 +57,21 @@ function presentActivityRunsForView(rows) {
|
|
|
39
57
|
skippedTriage: r.skippedTriage,
|
|
40
58
|
skippedDeclined: r.skippedDeclined,
|
|
41
59
|
itemCount: r.items.length,
|
|
42
|
-
items: r.items.map((i) =>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
60
|
+
items: r.items.map((i) => {
|
|
61
|
+
const eff = resolveEffectiveDecision(i.decision, i.prUrl, live);
|
|
62
|
+
return {
|
|
63
|
+
prUrl: i.prUrl,
|
|
64
|
+
githubRepo: i.githubRepo,
|
|
65
|
+
prNumber: i.prNumber,
|
|
66
|
+
prTitle: i.prTitle,
|
|
67
|
+
authorLogin: i.authorLogin,
|
|
68
|
+
decision: i.decision,
|
|
69
|
+
effectiveDecision: eff,
|
|
70
|
+
decisionLabel: (0, poll_run_labels_1.pollDecisionLabel)(eff),
|
|
71
|
+
detail: i.detail,
|
|
72
|
+
kanbanIssueId: i.kanbanIssueId,
|
|
73
|
+
};
|
|
74
|
+
}),
|
|
53
75
|
}));
|
|
54
76
|
}
|
|
55
77
|
function escapeForPre(s) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui-presenter.js","sourceRoot":"","sources":["../../src/ui/ui-presenter.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"ui-presenter.js","sourceRoot":"","sources":["../../src/ui/ui-presenter.ts"],"names":[],"mappings":"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"}
|