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.
@@ -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-CT3t4Yje.js"></script>
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,6 +1,6 @@
1
1
  {
2
2
  "name": "github-issue-tower-defence-management",
3
- "version": "1.111.2",
3
+ "version": "1.111.3",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -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
- countPendingItems,
29
- filterPendingItems,
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] = countPendingItems(
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 filterPendingItems(activeSnapshot.items, overlayState.overlay);
90
- }, [activeSnapshot, overlayState.overlay]);
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)),