github-issue-tower-defence-management 1.178.1 → 1.180.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.
Files changed (82) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +1 -0
  3. package/bin/adapter/entry-points/cli/index.js +2 -0
  4. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  5. package/bin/adapter/entry-points/console/consoleOperationApi.js +42 -1
  6. package/bin/adapter/entry-points/console/consoleOperationApi.js.map +1 -1
  7. package/bin/adapter/entry-points/console/ui-dist/assets/index-I_2Yu8fM.js +86 -0
  8. package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
  9. package/bin/adapter/entry-points/console/webServer.js +6 -0
  10. package/bin/adapter/entry-points/console/webServer.js.map +1 -1
  11. package/bin/adapter/repositories/SystemDateRepository.js +10 -10
  12. package/bin/adapter/repositories/SystemDateRepository.js.map +1 -1
  13. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +23 -4
  14. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
  15. package/bin/domain/usecases/AnalyzeProblemByIssueUseCase.js +1 -1
  16. package/bin/domain/usecases/AnalyzeProblemByIssueUseCase.js.map +1 -1
  17. package/bin/domain/usecases/AnalyzeStoriesUseCase.js +1 -1
  18. package/bin/domain/usecases/AnalyzeStoriesUseCase.js.map +1 -1
  19. package/bin/domain/usecases/ClearPastNextActionDateHourUseCase.js +1 -1
  20. package/bin/domain/usecases/ClearPastNextActionDateHourUseCase.js.map +1 -1
  21. package/bin/domain/usecases/CreateEstimationIssueUseCase.js +3 -3
  22. package/bin/domain/usecases/CreateEstimationIssueUseCase.js.map +1 -1
  23. package/bin/domain/usecases/HandleScheduledEventUseCase.js +6 -6
  24. package/bin/domain/usecases/HandleScheduledEventUseCase.js.map +1 -1
  25. package/bin/domain/usecases/IssueRejectionEvaluator.js +3 -1
  26. package/bin/domain/usecases/IssueRejectionEvaluator.js.map +1 -1
  27. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +13 -0
  28. package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
  29. package/bin/domain/usecases/StartPreparationUseCase.js +1 -1
  30. package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
  31. package/bin/domain/usecases/issueReactivationTriggerIsPending.js +2 -2
  32. package/bin/domain/usecases/issueReactivationTriggerIsPending.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/adapter/entry-points/cli/index.test.ts +2 -0
  35. package/src/adapter/entry-points/cli/index.ts +6 -0
  36. package/src/adapter/entry-points/console/consoleOperationApi.test.ts +230 -0
  37. package/src/adapter/entry-points/console/consoleOperationApi.ts +48 -1
  38. package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +36 -0
  39. package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +25 -1
  40. package/src/adapter/entry-points/console/ui/src/features/console/components/list/ConsoleStoryReorderPanel.stories.tsx +30 -0
  41. package/src/adapter/entry-points/console/ui/src/features/console/components/list/ConsoleStoryReorderPanel.test.tsx +111 -0
  42. package/src/adapter/entry-points/console/ui/src/features/console/components/list/ConsoleStoryReorderPanel.tsx +91 -0
  43. package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +21 -0
  44. package/src/adapter/entry-points/console/ui/src/features/console/logic/relativeTime.test.ts +24 -2
  45. package/src/adapter/entry-points/console/ui/src/features/console/logic/relativeTime.ts +3 -1
  46. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +60 -11
  47. package/src/adapter/entry-points/console/ui-dist/assets/index-I_2Yu8fM.js +86 -0
  48. package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
  49. package/src/adapter/entry-points/console/webServer.ts +11 -0
  50. package/src/adapter/repositories/SystemDateRepository.test.ts +60 -0
  51. package/src/adapter/repositories/SystemDateRepository.ts +10 -10
  52. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +268 -2
  53. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +33 -4
  54. package/src/domain/usecases/AnalyzeProblemByIssueUseCase.ts +1 -1
  55. package/src/domain/usecases/AnalyzeStoriesUseCase.test.ts +80 -0
  56. package/src/domain/usecases/AnalyzeStoriesUseCase.ts +1 -1
  57. package/src/domain/usecases/ClearPastNextActionDateHourUseCase.ts +6 -4
  58. package/src/domain/usecases/CreateEstimationIssueUseCase.test.ts +225 -0
  59. package/src/domain/usecases/CreateEstimationIssueUseCase.ts +3 -3
  60. package/src/domain/usecases/HandleScheduledEventUseCase.test.ts +107 -0
  61. package/src/domain/usecases/HandleScheduledEventUseCase.ts +7 -7
  62. package/src/domain/usecases/IssueRejectionEvaluator.test.ts +83 -0
  63. package/src/domain/usecases/IssueRejectionEvaluator.ts +3 -1
  64. package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +136 -0
  65. package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +42 -1
  66. package/src/domain/usecases/StartPreparationUseCase.ts +5 -3
  67. package/src/domain/usecases/issueReactivationTriggerIsPending.test.ts +35 -33
  68. package/src/domain/usecases/issueReactivationTriggerIsPending.ts +6 -4
  69. package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
  70. package/types/adapter/entry-points/console/consoleOperationApi.d.ts +3 -1
  71. package/types/adapter/entry-points/console/consoleOperationApi.d.ts.map +1 -1
  72. package/types/adapter/entry-points/console/webServer.d.ts +2 -0
  73. package/types/adapter/entry-points/console/webServer.d.ts.map +1 -1
  74. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
  75. package/types/domain/usecases/ClearPastNextActionDateHourUseCase.d.ts.map +1 -1
  76. package/types/domain/usecases/IssueRejectionEvaluator.d.ts.map +1 -1
  77. package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts +3 -1
  78. package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
  79. package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
  80. package/types/domain/usecases/issueReactivationTriggerIsPending.d.ts.map +1 -1
  81. package/bin/adapter/entry-points/console/ui-dist/assets/index-KCmqh781.js +0 -86
  82. package/src/adapter/entry-points/console/ui-dist/assets/index-KCmqh781.js +0 -86
@@ -417,3 +417,24 @@ export const postConsoleCreateIssue = async (
417
417
  }
418
418
  return payload.issueUrl;
419
419
  };
420
+
421
+ export const REORDER_STORY_OPERATION_PATH = '/api/reorderstory';
422
+
423
+ export type ConsoleReorderStoryRequest = {
424
+ pjcode: string;
425
+ storyOptionId: string;
426
+ direction: 'up' | 'down';
427
+ };
428
+
429
+ export const postConsoleReorderStory = async (
430
+ request: ConsoleReorderStoryRequest,
431
+ ): Promise<void> => {
432
+ const response = await fetch(REORDER_STORY_OPERATION_PATH, {
433
+ method: 'POST',
434
+ headers: { 'Content-Type': 'application/json' },
435
+ body: JSON.stringify(request),
436
+ });
437
+ if (!response.ok) {
438
+ throw new Error(await readOperationErrorReason(response));
439
+ }
440
+ };
@@ -39,14 +39,36 @@ describe('formatRelativeTime', () => {
39
39
  );
40
40
  });
41
41
 
42
+ it('returns month and day for 30+ days in the same UTC year', () => {
43
+ expect(formatRelativeTime('2026-05-01T12:00:00.000Z', now)).toBe('May 1');
44
+ });
45
+
46
+ it('includes the UTC year when the date is in a prior year', () => {
47
+ const result = formatRelativeTime('2025-12-01T12:00:00.000Z', now);
48
+ expect(result).toContain('2025');
49
+ expect(result).toContain('Dec');
50
+ });
51
+
52
+ it('uses UTC date boundary for the same-year check', () => {
53
+ const nowEndOf2025 = Date.parse('2025-12-31T23:59:59.000Z');
54
+ const result = formatRelativeTime('2025-10-01T00:00:00.000Z', nowEndOf2025);
55
+ expect(result).toContain('Oct');
56
+ expect(result).not.toContain('2025');
57
+ });
58
+
42
59
  it('returns an empty string for an invalid date', () => {
43
60
  expect(formatRelativeTime('nonsense', now)).toBe('');
44
61
  });
45
62
  });
46
63
 
47
64
  describe('formatFullTimestamp', () => {
48
- it('formats a timestamp and returns empty for invalid input', () => {
49
- expect(formatFullTimestamp('2026-06-19T12:00:00.000Z')).not.toBe('');
65
+ it('formats a UTC timestamp in ja-JP locale', () => {
66
+ expect(formatFullTimestamp('2026-06-19T09:05:00.000Z')).toMatch(
67
+ /2026.06.19.09.05/,
68
+ );
69
+ });
70
+
71
+ it('returns empty string for invalid input', () => {
50
72
  expect(formatFullTimestamp('nonsense')).toBe('');
51
73
  });
52
74
  });
@@ -28,8 +28,9 @@ export const formatRelativeTime = (iso: string, now: number): string => {
28
28
  return `${days} days ago`;
29
29
  }
30
30
  const date = new Date(then);
31
- const sameYear = date.getFullYear() === new Date(now).getFullYear();
31
+ const sameYear = date.getUTCFullYear() === new Date(now).getUTCFullYear();
32
32
  return date.toLocaleDateString('en-US', {
33
+ timeZone: 'UTC',
33
34
  year: sameYear ? undefined : 'numeric',
34
35
  month: 'short',
35
36
  day: 'numeric',
@@ -42,6 +43,7 @@ export const formatFullTimestamp = (iso: string): string => {
42
43
  return '';
43
44
  }
44
45
  return new Date(then).toLocaleString('ja-JP', {
46
+ timeZone: 'UTC',
45
47
  year: 'numeric',
46
48
  month: '2-digit',
47
49
  day: '2-digit',
@@ -1,7 +1,8 @@
1
- import { useCallback, useEffect, useMemo, useRef } from 'react';
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import { ConsoleTabList } from '../components/layout/ConsoleTabList';
3
3
  import { ConsoleItemList } from '../components/list/ConsoleItemList';
4
4
  import { ConsoleStoryList } from '../components/list/ConsoleStoryList';
5
+ import { ConsoleStoryReorderPanel } from '../components/list/ConsoleStoryReorderPanel';
5
6
  import {
6
7
  ConsoleErrorToast,
7
8
  ConsoleUndoToast,
@@ -15,7 +16,10 @@ import { useConsoleOverlay } from '../hooks/useConsoleOverlay';
15
16
  import { useConsolePjcode } from '../hooks/useConsolePjcode';
16
17
  import { useConsoleSwipeNavigation } from '../hooks/useConsoleSwipeNavigation';
17
18
  import { useConsoleTabData } from '../hooks/useConsoleTabData';
18
- import { postConsoleCreateIssue } from '../lib/consoleApi';
19
+ import {
20
+ postConsoleCreateIssue,
21
+ postConsoleReorderStory,
22
+ } from '../lib/consoleApi';
19
23
  import {
20
24
  actionAdvances,
21
25
  actionToastColor,
@@ -136,6 +140,17 @@ export const ConsolePage = () => {
136
140
  const generatedAt = activeSnapshot?.generatedAt ?? null;
137
141
  const fromCache = activeSnapshot?.fromCache ?? false;
138
142
 
143
+ const [localStoryOptionsOverride, setLocalStoryOptionsOverride] = useState<{
144
+ generatedAt: string | undefined;
145
+ stories: typeof storyOptions;
146
+ } | null>(null);
147
+
148
+ const triageStoryOptions =
149
+ localStoryOptionsOverride !== null &&
150
+ localStoryOptionsOverride.generatedAt === activeSnapshot?.generatedAt
151
+ ? localStoryOptionsOverride.stories
152
+ : storyOptions.filter((o) => o.color !== 'GRAY');
153
+
139
154
  const selectedItem = useMemo<ConsoleListItem | null>(() => {
140
155
  if (selectedItemKey === null || activeSnapshot === null) {
141
156
  return null;
@@ -265,6 +280,32 @@ export const ConsolePage = () => {
265
280
  [pjcode, defaultNameWithOwner],
266
281
  );
267
282
 
283
+ const handleReorderStory = useCallback(
284
+ async (storyOptionId: string, direction: 'up' | 'down'): Promise<void> => {
285
+ if (pjcode === null) {
286
+ throw new Error('No project specified in the URL path.');
287
+ }
288
+ await postConsoleReorderStory({ pjcode, storyOptionId, direction });
289
+ const index = triageStoryOptions.findIndex((o) => o.id === storyOptionId);
290
+ if (index === -1) {
291
+ return;
292
+ }
293
+ const swapIndex = index + (direction === 'up' ? -1 : 1);
294
+ if (swapIndex < 0 || swapIndex >= triageStoryOptions.length) {
295
+ return;
296
+ }
297
+ const next = [...triageStoryOptions];
298
+ const temp = next[index];
299
+ next[index] = next[swapIndex];
300
+ next[swapIndex] = temp;
301
+ setLocalStoryOptionsOverride({
302
+ generatedAt: activeSnapshot?.generatedAt,
303
+ stories: next,
304
+ });
305
+ },
306
+ [pjcode, triageStoryOptions, activeSnapshot?.generatedAt],
307
+ );
308
+
268
309
  return (
269
310
  <main className="console-app">
270
311
  {actionQueue.pending !== null && (
@@ -299,15 +340,23 @@ export const ConsolePage = () => {
299
340
  onCreateIssue={handleCreateIssue}
300
341
  />
301
342
  ) : selectedItem === null ? (
302
- <ConsoleItemList
303
- rows={rows}
304
- storyColors={storyColors}
305
- activeItemId={null}
306
- now={now}
307
- isLoading={isLoading}
308
- error={error}
309
- onSelectItem={(item) => navigation.openItem(item.projectItemId)}
310
- />
343
+ <>
344
+ {activeTab === 'triage' && triageStoryOptions.length > 0 && (
345
+ <ConsoleStoryReorderPanel
346
+ stories={triageStoryOptions}
347
+ onReorderStory={handleReorderStory}
348
+ />
349
+ )}
350
+ <ConsoleItemList
351
+ rows={rows}
352
+ storyColors={storyColors}
353
+ activeItemId={null}
354
+ now={now}
355
+ isLoading={isLoading}
356
+ error={error}
357
+ onSelectItem={(item) => navigation.openItem(item.projectItemId)}
358
+ />
359
+ </>
311
360
  ) : (
312
361
  <div className="console-detail-screen" ref={detailScreenRef}>
313
362
  <ConsoleItemDetailContainer