github-issue-tower-defence-management 1.111.2 → 1.111.3
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/CHANGELOG.md +7 -0
- package/bin/adapter/entry-points/console/ui-dist/assets/{index-CT3t4Yje.js → index-Bu5bQZyP.js} +19 -19
- package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/console/ui/src/features/console/logic/overlay.test.ts +59 -0
- package/src/adapter/entry-points/console/ui/src/features/console/logic/overlay.ts +17 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.test.tsx +79 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +10 -5
- package/src/adapter/entry-points/console/ui-dist/assets/{index-CT3t4Yje.js → index-Bu5bQZyP.js} +19 -19
- package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>TDPM Console</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-Bu5bQZyP.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-BPH6W1yn.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
countPendingItems,
|
|
3
|
+
countTabPendingItems,
|
|
3
4
|
filterPendingItems,
|
|
5
|
+
filterTabPendingItems,
|
|
4
6
|
isOverlayEntryActed,
|
|
5
7
|
overlayKeyForItem,
|
|
6
8
|
overlayStorageKey,
|
|
9
|
+
tabIgnoresDoneOverlay,
|
|
7
10
|
writeOverlayEntry,
|
|
8
11
|
} from './overlay';
|
|
9
12
|
import type { ConsoleListItem, ConsoleOverlay } from './types';
|
|
@@ -123,6 +126,62 @@ describe('filterPendingItems', () => {
|
|
|
123
126
|
});
|
|
124
127
|
});
|
|
125
128
|
|
|
129
|
+
describe('tabIgnoresDoneOverlay', () => {
|
|
130
|
+
it('ignores the done overlay on the workflow-blocker tab', () => {
|
|
131
|
+
expect(tabIgnoresDoneOverlay('workflow-blocker')).toBe(true);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('applies the done overlay on every other tab', () => {
|
|
135
|
+
expect(tabIgnoresDoneOverlay('prs')).toBe(false);
|
|
136
|
+
expect(tabIgnoresDoneOverlay('triage')).toBe(false);
|
|
137
|
+
expect(tabIgnoresDoneOverlay('unread')).toBe(false);
|
|
138
|
+
expect(tabIgnoresDoneOverlay('failed-preparation')).toBe(false);
|
|
139
|
+
expect(tabIgnoresDoneOverlay('todo-by-human')).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('countTabPendingItems', () => {
|
|
144
|
+
it('counts every workflow-blocker item even when all are marked done', () => {
|
|
145
|
+
const overlay: ConsoleOverlay = {
|
|
146
|
+
PVTI_1: { ts: 100, mode: 'workflow-blocker', done: true },
|
|
147
|
+
PVTI_2: { ts: 100, mode: 'workflow-blocker', done: true },
|
|
148
|
+
};
|
|
149
|
+
expect(
|
|
150
|
+
countTabPendingItems([item(1), item(2)], overlay, 'workflow-blocker'),
|
|
151
|
+
).toBe(2);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('subtracts done items on tabs other than workflow-blocker', () => {
|
|
155
|
+
const overlay: ConsoleOverlay = {
|
|
156
|
+
PVTI_1: { ts: 100, mode: 'prs', done: true },
|
|
157
|
+
};
|
|
158
|
+
expect(countTabPendingItems([item(1), item(2)], overlay, 'prs')).toBe(1);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('filterTabPendingItems', () => {
|
|
163
|
+
it('keeps every workflow-blocker item even when all are marked done', () => {
|
|
164
|
+
const overlay: ConsoleOverlay = {
|
|
165
|
+
PVTI_1: { ts: 100, mode: 'workflow-blocker', done: true },
|
|
166
|
+
PVTI_2: { ts: 100, mode: 'workflow-blocker', done: true },
|
|
167
|
+
};
|
|
168
|
+
const result = filterTabPendingItems(
|
|
169
|
+
[item(1), item(2)],
|
|
170
|
+
overlay,
|
|
171
|
+
'workflow-blocker',
|
|
172
|
+
);
|
|
173
|
+
expect(result.map((entry) => entry.number)).toEqual([1, 2]);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('drops done items on tabs other than workflow-blocker', () => {
|
|
177
|
+
const overlay: ConsoleOverlay = {
|
|
178
|
+
PVTI_1: { ts: 100, mode: 'prs', done: true },
|
|
179
|
+
};
|
|
180
|
+
const result = filterTabPendingItems([item(1), item(2)], overlay, 'prs');
|
|
181
|
+
expect(result.map((entry) => entry.number)).toEqual([2]);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
126
185
|
describe('writeOverlayEntry', () => {
|
|
127
186
|
it('stamps the timestamp and mode on write', () => {
|
|
128
187
|
const next = writeOverlayEntry({}, 'PVTI_1', { done: true }, 'prs', 1234);
|
|
@@ -30,6 +30,23 @@ export const filterPendingItems = (
|
|
|
30
30
|
(item) => !isOverlayEntryActed(overlay[overlayKeyForItem(item)]),
|
|
31
31
|
);
|
|
32
32
|
|
|
33
|
+
export const tabIgnoresDoneOverlay = (tab: ConsoleTabName): boolean =>
|
|
34
|
+
tab === 'workflow-blocker';
|
|
35
|
+
|
|
36
|
+
export const countTabPendingItems = (
|
|
37
|
+
items: ConsoleListItem[],
|
|
38
|
+
overlay: ConsoleOverlay,
|
|
39
|
+
tab: ConsoleTabName,
|
|
40
|
+
): number =>
|
|
41
|
+
tabIgnoresDoneOverlay(tab) ? items.length : countPendingItems(items, overlay);
|
|
42
|
+
|
|
43
|
+
export const filterTabPendingItems = (
|
|
44
|
+
items: ConsoleListItem[],
|
|
45
|
+
overlay: ConsoleOverlay,
|
|
46
|
+
tab: ConsoleTabName,
|
|
47
|
+
): ConsoleListItem[] =>
|
|
48
|
+
tabIgnoresDoneOverlay(tab) ? items : filterPendingItems(items, overlay);
|
|
49
|
+
|
|
33
50
|
export const writeOverlayEntry = (
|
|
34
51
|
overlay: ConsoleOverlay,
|
|
35
52
|
key: string,
|
|
@@ -255,6 +255,85 @@ describe('ConsolePage', () => {
|
|
|
255
255
|
expect(queryByText('project: umino')).toBeNull();
|
|
256
256
|
});
|
|
257
257
|
|
|
258
|
+
it('keeps the workflow-blocker tab visible and lists its items even when every item is marked done in the overlay', async () => {
|
|
259
|
+
const blockerItems = [
|
|
260
|
+
{
|
|
261
|
+
number: 701,
|
|
262
|
+
title: 'Blocked deployment task',
|
|
263
|
+
url: 'https://github.com/o/r/issues/701',
|
|
264
|
+
repo: 'o/r',
|
|
265
|
+
nameWithOwner: 'o/r',
|
|
266
|
+
projectItemId: 'PVTI_B1',
|
|
267
|
+
itemId: 'PVTI_B1',
|
|
268
|
+
isPr: false,
|
|
269
|
+
story: 'TDPM Console port',
|
|
270
|
+
status: 'In Progress',
|
|
271
|
+
nextActionDate: null,
|
|
272
|
+
nextActionHour: null,
|
|
273
|
+
dependedIssueUrls: [],
|
|
274
|
+
labels: [],
|
|
275
|
+
createdAt: '2026-06-17T00:00:00.000Z',
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
number: 702,
|
|
279
|
+
title: 'Blocked rollout task',
|
|
280
|
+
url: 'https://github.com/o/r/issues/702',
|
|
281
|
+
repo: 'o/r',
|
|
282
|
+
nameWithOwner: 'o/r',
|
|
283
|
+
projectItemId: 'PVTI_B2',
|
|
284
|
+
itemId: 'PVTI_B2',
|
|
285
|
+
isPr: false,
|
|
286
|
+
story: 'TDPM Console port',
|
|
287
|
+
status: 'In Progress',
|
|
288
|
+
nextActionDate: null,
|
|
289
|
+
nextActionHour: null,
|
|
290
|
+
dependedIssueUrls: [],
|
|
291
|
+
labels: [],
|
|
292
|
+
createdAt: '2026-06-17T01:00:00.000Z',
|
|
293
|
+
},
|
|
294
|
+
];
|
|
295
|
+
const fetchMock = jest.fn(async (url: string) => {
|
|
296
|
+
const listMatch = url.match(/\/projects\/[^/]+\/([^/]+)\/list\.json/);
|
|
297
|
+
if (listMatch !== null) {
|
|
298
|
+
return {
|
|
299
|
+
ok: true,
|
|
300
|
+
status: 200,
|
|
301
|
+
json: async () =>
|
|
302
|
+
listMatch[1] === 'workflow-blocker'
|
|
303
|
+
? { ...listPayload('workflow-blocker'), items: blockerItems }
|
|
304
|
+
: listPayload(listMatch[1]),
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
return { ok: true, status: 200, json: async () => ({ body: '# body' }) };
|
|
308
|
+
});
|
|
309
|
+
global.fetch = fetchMock as unknown as typeof fetch;
|
|
310
|
+
localStorage.setItem(
|
|
311
|
+
'pv_overlay_umino',
|
|
312
|
+
JSON.stringify({
|
|
313
|
+
PVTI_B1: { ts: 1, mode: 'workflow-blocker', done: true },
|
|
314
|
+
PVTI_B2: { ts: 1, mode: 'workflow-blocker', done: true },
|
|
315
|
+
}),
|
|
316
|
+
);
|
|
317
|
+
window.history.replaceState(
|
|
318
|
+
{},
|
|
319
|
+
'',
|
|
320
|
+
'/projects/umino/workflow-blocker?k=token',
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const { getByText } = render(<ConsolePage />);
|
|
324
|
+
await waitFor(() => {
|
|
325
|
+
expect(getByText('Blocked deployment task')).toBeInTheDocument();
|
|
326
|
+
});
|
|
327
|
+
expect(getByText('Blocked rollout task')).toBeInTheDocument();
|
|
328
|
+
const blockerTab = within(tabBar())
|
|
329
|
+
.getByText('Workflow Blocker')
|
|
330
|
+
.closest('a');
|
|
331
|
+
expect(blockerTab).not.toBeNull();
|
|
332
|
+
expect(blockerTab?.querySelector('.console-tab-badge')?.textContent).toBe(
|
|
333
|
+
'2',
|
|
334
|
+
);
|
|
335
|
+
});
|
|
336
|
+
|
|
258
337
|
it('renders the failure toast in English without any Japanese characters', async () => {
|
|
259
338
|
const fetchMock = jest.fn(
|
|
260
339
|
async (url: string, init?: { method?: string }) => {
|
|
@@ -25,8 +25,8 @@ import {
|
|
|
25
25
|
previousPendingKeyBefore,
|
|
26
26
|
} from '../logic/navigation';
|
|
27
27
|
import {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
countTabPendingItems,
|
|
29
|
+
filterTabPendingItems,
|
|
30
30
|
overlayKeyForItem,
|
|
31
31
|
} from '../logic/overlay';
|
|
32
32
|
import type { ConsoleSwipeDirection } from '../logic/swipe';
|
|
@@ -64,9 +64,10 @@ export const ConsolePage = () => {
|
|
|
64
64
|
if (snapshot === null) {
|
|
65
65
|
continue;
|
|
66
66
|
}
|
|
67
|
-
result[tab.name] =
|
|
67
|
+
result[tab.name] = countTabPendingItems(
|
|
68
68
|
snapshot.items,
|
|
69
69
|
overlayState.overlay,
|
|
70
|
+
tab.name,
|
|
70
71
|
);
|
|
71
72
|
}
|
|
72
73
|
return result;
|
|
@@ -86,8 +87,12 @@ export const ConsolePage = () => {
|
|
|
86
87
|
if (activeSnapshot === null) {
|
|
87
88
|
return [];
|
|
88
89
|
}
|
|
89
|
-
return
|
|
90
|
-
|
|
90
|
+
return filterTabPendingItems(
|
|
91
|
+
activeSnapshot.items,
|
|
92
|
+
overlayState.overlay,
|
|
93
|
+
activeTab,
|
|
94
|
+
);
|
|
95
|
+
}, [activeSnapshot, overlayState.overlay, activeTab]);
|
|
91
96
|
|
|
92
97
|
const orderedPendingKeys = useMemo(
|
|
93
98
|
() => pendingItems.map((item) => overlayKeyForItem(item)),
|