github-issue-tower-defence-management 1.91.0 → 1.91.2

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 (116) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +5 -4
  3. package/bin/adapter/entry-points/cli/index.js +1 -1
  4. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  5. package/bin/adapter/entry-points/handlers/consoleListsWriter.js +1 -0
  6. package/bin/adapter/entry-points/handlers/consoleListsWriter.js.map +1 -1
  7. package/bin/domain/usecases/console/GenerateConsoleListsUseCase.js +3 -0
  8. package/bin/domain/usecases/console/GenerateConsoleListsUseCase.js.map +1 -1
  9. package/package.json +1 -1
  10. package/src/adapter/entry-points/cli/index.test.ts +6 -1
  11. package/src/adapter/entry-points/cli/index.ts +1 -1
  12. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleMarkdownView.stories.tsx → content/ConsoleMarkdownContent.stories.tsx} +6 -6
  13. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleMarkdownView.test.tsx → content/ConsoleMarkdownContent.test.tsx} +6 -6
  14. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleMarkdownView.tsx → content/ConsoleMarkdownContent.tsx} +2 -2
  15. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleMermaidDiagram.stories.tsx → content/ConsoleMermaidDiagram.stories.tsx} +1 -1
  16. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleMermaidDiagram.test.tsx → content/ConsoleMermaidDiagram.test.tsx} +2 -2
  17. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleMermaidDiagram.tsx → content/ConsoleMermaidDiagram.tsx} +1 -1
  18. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleChangedFileList.stories.tsx → detail/ConsoleChangedFileList.stories.tsx} +1 -1
  19. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleChangedFileList.test.tsx → detail/ConsoleChangedFileList.test.tsx} +1 -1
  20. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleChangedFileList.tsx → detail/ConsoleChangedFileList.tsx} +2 -2
  21. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleCommentList.stories.tsx → detail/ConsoleCommentList.stories.tsx} +1 -1
  22. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleCommentList.test.tsx → detail/ConsoleCommentList.test.tsx} +1 -1
  23. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleCommentList.tsx → detail/ConsoleCommentList.tsx} +4 -4
  24. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleCommitList.stories.tsx → detail/ConsoleCommitList.stories.tsx} +1 -1
  25. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleCommitList.test.tsx → detail/ConsoleCommitList.test.tsx} +1 -1
  26. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleCommitList.tsx → detail/ConsoleCommitList.tsx} +2 -2
  27. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleItemDetail.stories.tsx → detail/ConsoleItemDetail.stories.tsx} +1 -1
  28. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleItemDetail.test.tsx → detail/ConsoleItemDetail.test.tsx} +2 -2
  29. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleItemDetail.tsx → detail/ConsoleItemDetail.tsx} +11 -8
  30. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleItemIcon.test.tsx → detail/ConsoleItemIcon.test.tsx} +1 -1
  31. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleItemIcon.tsx → detail/ConsoleItemIcon.tsx} +1 -1
  32. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsolePullRequestSection.stories.tsx → detail/ConsolePullRequestDetail.stories.tsx} +6 -6
  33. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsolePullRequestSection.test.tsx → detail/ConsolePullRequestDetail.test.tsx} +5 -5
  34. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsolePullRequestSection.tsx → detail/ConsolePullRequestDetail.tsx} +5 -5
  35. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleProjectHeader.stories.tsx → layout/ConsoleProjectSummary.stories.tsx} +5 -5
  36. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleProjectHeader.test.tsx → layout/ConsoleProjectSummary.test.tsx} +4 -4
  37. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleProjectHeader.tsx → layout/ConsoleProjectSummary.tsx} +3 -1
  38. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleTabBar.stories.tsx → layout/ConsoleTabList.stories.tsx} +7 -7
  39. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleTabBar.test.tsx → layout/ConsoleTabList.test.tsx} +7 -7
  40. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleTabBar.tsx → layout/ConsoleTabList.tsx} +2 -2
  41. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleListView.stories.tsx → list/ConsoleItemList.stories.tsx} +7 -7
  42. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleListView.test.tsx → list/ConsoleItemList.test.tsx} +9 -9
  43. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleListView.tsx → list/ConsoleItemList.tsx} +13 -7
  44. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleListItemRow.stories.tsx → list/ConsoleItemSummary.stories.tsx} +6 -6
  45. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleListItemRow.test.tsx → list/ConsoleItemSummary.test.tsx} +7 -7
  46. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleListItemRow.tsx → list/ConsoleItemSummary.tsx} +3 -3
  47. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleStoryGroupHeader.stories.tsx → list/ConsoleStorySummary.stories.tsx} +5 -5
  48. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleStoryGroupHeader.test.tsx → list/ConsoleStorySummary.test.tsx} +4 -4
  49. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleStoryGroupHeader.tsx → list/ConsoleStorySummary.tsx} +3 -3
  50. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleCloseActions.stories.tsx +14 -0
  51. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleCloseButtonGroup.test.tsx → operations/ConsoleCloseActions.test.tsx} +4 -6
  52. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleCloseButtonGroup.tsx → operations/ConsoleCloseActions.tsx} +2 -2
  53. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleNextActionDateActions.stories.tsx +20 -0
  54. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleNextActionDateGroup.test.tsx → operations/ConsoleNextActionDateActions.test.tsx} +5 -5
  55. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleNextActionDateGroup.tsx → operations/ConsoleNextActionDateActions.tsx} +2 -2
  56. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleOperationBar.stories.tsx → operations/ConsoleOperationMenu.stories.tsx} +7 -7
  57. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleOperationBar.test.tsx → operations/ConsoleOperationMenu.test.tsx} +8 -8
  58. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleOperationBar.tsx → operations/ConsoleOperationMenu.tsx} +16 -13
  59. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsolePullRequestReviewActions.stories.tsx +14 -0
  60. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsolePullRequestReviewGroup.test.tsx → operations/ConsolePullRequestReviewActions.test.tsx} +4 -4
  61. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsolePullRequestReviewGroup.tsx → operations/ConsolePullRequestReviewActions.tsx} +2 -2
  62. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleStatusActions.stories.tsx +17 -0
  63. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleStatusButtonGroup.test.tsx → operations/ConsoleStatusActions.test.tsx} +6 -6
  64. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleStatusButtonGroup.tsx → operations/ConsoleStatusActions.tsx} +7 -4
  65. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleStoryActions.stories.tsx +17 -0
  66. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleStoryButtonGroup.test.tsx → operations/ConsoleStoryActions.test.tsx} +5 -11
  67. package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleStoryButtonGroup.tsx → operations/ConsoleStoryActions.tsx} +3 -3
  68. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleCaches.ts +1 -1
  69. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleItemDetailData.test.ts +1 -1
  70. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleItemDetailData.ts +2 -2
  71. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts +2 -2
  72. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts +3 -3
  73. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOverlay.test.ts +1 -1
  74. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOverlay.ts +2 -2
  75. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleTabData.ts +2 -2
  76. package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +1 -1
  77. package/src/adapter/entry-points/console/ui/src/features/console/{grouping.ts → logic/grouping.ts} +2 -2
  78. package/src/adapter/entry-points/console/ui/src/features/console/logic/overlay.test.ts +146 -0
  79. package/src/adapter/entry-points/console/ui/src/features/console/logic/overlay.ts +48 -0
  80. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +4 -4
  81. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +6 -6
  82. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.test.tsx +55 -1
  83. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +12 -20
  84. package/src/adapter/entry-points/console/ui/src/features/console/{fixtures.ts → testing/fixtures.ts} +1 -1
  85. package/src/adapter/entry-points/console/ui-dist/assets/{index-BvuSQN9s.js → index-Druih-WG.js} +20 -20
  86. package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
  87. package/src/adapter/entry-points/handlers/consoleListsWriter.test.ts +27 -2
  88. package/src/adapter/entry-points/handlers/consoleListsWriter.ts +1 -0
  89. package/src/domain/usecases/console/GenerateConsoleListsUseCase.test.ts +26 -0
  90. package/src/domain/usecases/console/GenerateConsoleListsUseCase.ts +17 -1
  91. package/types/adapter/entry-points/handlers/consoleListsWriter.d.ts.map +1 -1
  92. package/types/domain/usecases/console/GenerateConsoleListsUseCase.d.ts +2 -1
  93. package/types/domain/usecases/console/GenerateConsoleListsUseCase.d.ts.map +1 -1
  94. package/src/adapter/entry-points/console/ui/src/features/console/components/ConsoleCloseButtonGroup.stories.tsx +0 -14
  95. package/src/adapter/entry-points/console/ui/src/features/console/components/ConsoleNextActionDateGroup.stories.tsx +0 -20
  96. package/src/adapter/entry-points/console/ui/src/features/console/components/ConsolePullRequestReviewGroup.stories.tsx +0 -14
  97. package/src/adapter/entry-points/console/ui/src/features/console/components/ConsoleStatusButtonGroup.stories.tsx +0 -17
  98. package/src/adapter/entry-points/console/ui/src/features/console/components/ConsoleStoryButtonGroup.stories.tsx +0 -17
  99. package/src/adapter/entry-points/console/ui/src/features/console/overlay.test.ts +0 -124
  100. package/src/adapter/entry-points/console/ui/src/features/console/overlay.ts +0 -101
  101. /package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsoleItemIcon.stories.tsx → detail/ConsoleItemIcon.stories.tsx} +0 -0
  102. /package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsolePanel.stories.tsx → layout/ConsolePanel.stories.tsx} +0 -0
  103. /package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsolePanel.test.tsx → layout/ConsolePanel.test.tsx} +0 -0
  104. /package/src/adapter/entry-points/console/ui/src/features/console/components/{ConsolePanel.tsx → layout/ConsolePanel.tsx} +0 -0
  105. /package/src/adapter/entry-points/console/ui/src/features/console/{colors.test.ts → logic/colors.test.ts} +0 -0
  106. /package/src/adapter/entry-points/console/ui/src/features/console/{colors.ts → logic/colors.ts} +0 -0
  107. /package/src/adapter/entry-points/console/ui/src/features/console/{fileStatus.test.ts → logic/fileStatus.test.ts} +0 -0
  108. /package/src/adapter/entry-points/console/ui/src/features/console/{fileStatus.ts → logic/fileStatus.ts} +0 -0
  109. /package/src/adapter/entry-points/console/ui/src/features/console/{grouping.test.ts → logic/grouping.test.ts} +0 -0
  110. /package/src/adapter/entry-points/console/ui/src/features/console/{itemIcons.test.ts → logic/itemIcons.test.ts} +0 -0
  111. /package/src/adapter/entry-points/console/ui/src/features/console/{itemIcons.ts → logic/itemIcons.ts} +0 -0
  112. /package/src/adapter/entry-points/console/ui/src/features/console/{operations.test.ts → logic/operations.test.ts} +0 -0
  113. /package/src/adapter/entry-points/console/ui/src/features/console/{operations.ts → logic/operations.ts} +0 -0
  114. /package/src/adapter/entry-points/console/ui/src/features/console/{relativeTime.test.ts → logic/relativeTime.test.ts} +0 -0
  115. /package/src/adapter/entry-points/console/ui/src/features/console/{relativeTime.ts → logic/relativeTime.ts} +0 -0
  116. /package/src/adapter/entry-points/console/ui/src/features/console/{types.ts → logic/types.ts} +0 -0
@@ -1,14 +1,17 @@
1
- import { type ConsoleOperationHandlers, isTodoByHumanTab } from '../operations';
1
+ import {
2
+ type ConsoleOperationHandlers,
3
+ isTodoByHumanTab,
4
+ } from '../../logic/operations';
2
5
  import type {
3
6
  ConsoleFieldOption,
4
7
  ConsoleListItem,
5
8
  ConsoleTabName,
6
- } from '../types';
7
- import { ConsoleCloseButtonGroup } from './ConsoleCloseButtonGroup';
8
- import { ConsoleNextActionDateGroup } from './ConsoleNextActionDateGroup';
9
- import { ConsolePullRequestReviewGroup } from './ConsolePullRequestReviewGroup';
10
- import { ConsoleStatusButtonGroup } from './ConsoleStatusButtonGroup';
11
- import { ConsoleStoryButtonGroup } from './ConsoleStoryButtonGroup';
9
+ } from '../../logic/types';
10
+ import { ConsoleCloseActions } from './ConsoleCloseActions';
11
+ import { ConsoleNextActionDateActions } from './ConsoleNextActionDateActions';
12
+ import { ConsolePullRequestReviewActions } from './ConsolePullRequestReviewActions';
13
+ import { ConsoleStatusActions } from './ConsoleStatusActions';
14
+ import { ConsoleStoryActions } from './ConsoleStoryActions';
12
15
 
13
16
  export type ConsoleOperationBarProps = {
14
17
  tab: ConsoleTabName;
@@ -19,7 +22,7 @@ export type ConsoleOperationBarProps = {
19
22
  handlers: ConsoleOperationHandlers;
20
23
  };
21
24
 
22
- export const ConsoleOperationBar = ({
25
+ export const ConsoleOperationMenu = ({
23
26
  tab,
24
27
  item,
25
28
  hasPullRequest,
@@ -32,24 +35,24 @@ export const ConsoleOperationBar = ({
32
35
  return (
33
36
  <div className="console-operation-bar">
34
37
  {hasPullRequest && (
35
- <ConsolePullRequestReviewGroup onReview={handlers.onReview} />
38
+ <ConsolePullRequestReviewActions onReview={handlers.onReview} />
36
39
  )}
37
- <ConsoleNextActionDateGroup
40
+ <ConsoleNextActionDateActions
38
41
  isTodoByHuman={isTodoByHumanTab(tab)}
39
42
  onSetNextActionDate={handlers.onSetNextActionDate}
40
43
  />
41
44
  {showStory && (
42
- <ConsoleStoryButtonGroup
45
+ <ConsoleStoryActions
43
46
  storyOptions={storyOptions}
44
47
  onSetStory={handlers.onSetStory}
45
48
  />
46
49
  )}
47
- <ConsoleStatusButtonGroup
50
+ <ConsoleStatusActions
48
51
  statusOptions={statusOptions}
49
52
  onSetStatus={handlers.onSetStatus}
50
53
  onSetInTmuxByHuman={handlers.onSetInTmuxByHuman}
51
54
  />
52
- {showClose && <ConsoleCloseButtonGroup onClose={handlers.onClose} />}
55
+ {showClose && <ConsoleCloseActions onClose={handlers.onClose} />}
53
56
  </div>
54
57
  );
55
58
  };
@@ -0,0 +1,14 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ConsolePullRequestReviewActions } from './ConsolePullRequestReviewActions';
3
+
4
+ const meta: Meta<typeof ConsolePullRequestReviewActions> = {
5
+ title: 'Console/ConsolePullRequestReviewActions',
6
+ component: ConsolePullRequestReviewActions,
7
+ args: { onReview: () => {} },
8
+ };
9
+
10
+ export default meta;
11
+
12
+ type Story = StoryObj<typeof ConsolePullRequestReviewActions>;
13
+
14
+ export const Default: Story = {};
@@ -1,10 +1,10 @@
1
1
  import { fireEvent, render } from '@testing-library/react';
2
- import { ConsolePullRequestReviewGroup } from './ConsolePullRequestReviewGroup';
2
+ import { ConsolePullRequestReviewActions } from './ConsolePullRequestReviewActions';
3
3
 
4
- describe('ConsolePullRequestReviewGroup', () => {
4
+ describe('ConsolePullRequestReviewActions', () => {
5
5
  it('renders the four buttons left to right', () => {
6
6
  const { getAllByRole } = render(
7
- <ConsolePullRequestReviewGroup onReview={() => {}} />,
7
+ <ConsolePullRequestReviewActions onReview={() => {}} />,
8
8
  );
9
9
  expect(getAllByRole('button').map((button) => button.textContent)).toEqual([
10
10
  'Unnecessary',
@@ -17,7 +17,7 @@ describe('ConsolePullRequestReviewGroup', () => {
17
17
  it('reports each review action', () => {
18
18
  const onReview = jest.fn();
19
19
  const { getByText } = render(
20
- <ConsolePullRequestReviewGroup onReview={onReview} />,
20
+ <ConsolePullRequestReviewActions onReview={onReview} />,
21
21
  );
22
22
  fireEvent.click(getByText('Unnecessary'));
23
23
  fireEvent.click(getByText('Totally wrong'));
@@ -1,4 +1,4 @@
1
- import type { ConsoleReviewAction } from '../operations';
1
+ import type { ConsoleReviewAction } from '../../logic/operations';
2
2
 
3
3
  export type ConsolePullRequestReviewGroupProps = {
4
4
  onReview: (action: ConsoleReviewAction) => void;
@@ -15,7 +15,7 @@ const REVIEW_BUTTONS: {
15
15
  { action: 'approve', label: 'Approve', color: '#3fb950' },
16
16
  ];
17
17
 
18
- export const ConsolePullRequestReviewGroup = ({
18
+ export const ConsolePullRequestReviewActions = ({
19
19
  onReview,
20
20
  }: ConsolePullRequestReviewGroupProps) => (
21
21
  <div className="console-op-group">
@@ -0,0 +1,17 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { consoleStatusOptionsFixture } from '../../testing/fixtures';
3
+ import { ConsoleStatusActions } from './ConsoleStatusActions';
4
+
5
+ const meta: Meta<typeof ConsoleStatusActions> = {
6
+ title: 'Console/ConsoleStatusActions',
7
+ component: ConsoleStatusActions,
8
+ args: { onSetStatus: () => {}, onSetInTmuxByHuman: () => {} },
9
+ };
10
+
11
+ export default meta;
12
+
13
+ type Story = StoryObj<typeof ConsoleStatusActions>;
14
+
15
+ export const AllStatusOptions: Story = {
16
+ args: { statusOptions: consoleStatusOptionsFixture },
17
+ };
@@ -1,11 +1,11 @@
1
1
  import { fireEvent, render } from '@testing-library/react';
2
- import { consoleStatusOptionsFixture } from '../fixtures';
3
- import { ConsoleStatusButtonGroup } from './ConsoleStatusButtonGroup';
2
+ import { consoleStatusOptionsFixture } from '../../testing/fixtures';
3
+ import { ConsoleStatusActions } from './ConsoleStatusActions';
4
4
 
5
- describe('ConsoleStatusButtonGroup', () => {
5
+ describe('ConsoleStatusActions', () => {
6
6
  it('renders only the four routed status buttons that exist in the data', () => {
7
7
  const { getByText, queryByText } = render(
8
- <ConsoleStatusButtonGroup
8
+ <ConsoleStatusActions
9
9
  statusOptions={consoleStatusOptionsFixture}
10
10
  onSetStatus={() => {}}
11
11
  onSetInTmuxByHuman={() => {}}
@@ -22,7 +22,7 @@ describe('ConsoleStatusButtonGroup', () => {
22
22
  const onSetStatus = jest.fn();
23
23
  const onSetInTmuxByHuman = jest.fn();
24
24
  const { getByText } = render(
25
- <ConsoleStatusButtonGroup
25
+ <ConsoleStatusActions
26
26
  statusOptions={consoleStatusOptionsFixture}
27
27
  onSetStatus={onSetStatus}
28
28
  onSetInTmuxByHuman={onSetInTmuxByHuman}
@@ -38,7 +38,7 @@ describe('ConsoleStatusButtonGroup', () => {
38
38
 
39
39
  it('renders nothing when no routed option exists', () => {
40
40
  const { container } = render(
41
- <ConsoleStatusButtonGroup
41
+ <ConsoleStatusActions
42
42
  statusOptions={[{ id: 'x', name: 'Preparation', color: 'YELLOW' }]}
43
43
  onSetStatus={() => {}}
44
44
  onSetInTmuxByHuman={() => {}}
@@ -1,6 +1,9 @@
1
- import { colorFromEnum } from '../colors';
2
- import { IN_TMUX_BY_HUMAN_NAME, STATUS_BUTTON_NAMES } from '../operations';
3
- import type { ConsoleFieldOption } from '../types';
1
+ import { colorFromEnum } from '../../logic/colors';
2
+ import {
3
+ IN_TMUX_BY_HUMAN_NAME,
4
+ STATUS_BUTTON_NAMES,
5
+ } from '../../logic/operations';
6
+ import type { ConsoleFieldOption } from '../../logic/types';
4
7
 
5
8
  export type ConsoleStatusButtonGroupProps = {
6
9
  statusOptions: ConsoleFieldOption[];
@@ -18,7 +21,7 @@ const findStatusOption = (
18
21
  );
19
22
  };
20
23
 
21
- export const ConsoleStatusButtonGroup = ({
24
+ export const ConsoleStatusActions = ({
22
25
  statusOptions,
23
26
  onSetStatus,
24
27
  onSetInTmuxByHuman,
@@ -0,0 +1,17 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { consoleStoryOptionsFixture } from '../../testing/fixtures';
3
+ import { ConsoleStoryActions } from './ConsoleStoryActions';
4
+
5
+ const meta: Meta<typeof ConsoleStoryActions> = {
6
+ title: 'Console/ConsoleStoryActions',
7
+ component: ConsoleStoryActions,
8
+ args: { onSetStory: () => {} },
9
+ };
10
+
11
+ export default meta;
12
+
13
+ type Story = StoryObj<typeof ConsoleStoryActions>;
14
+
15
+ export const AssignableStories: Story = {
16
+ args: { storyOptions: consoleStoryOptionsFixture },
17
+ };
@@ -1,5 +1,5 @@
1
1
  import { fireEvent, render } from '@testing-library/react';
2
- import { ConsoleStoryButtonGroup } from './ConsoleStoryButtonGroup';
2
+ import { ConsoleStoryActions } from './ConsoleStoryActions';
3
3
 
4
4
  const options = [
5
5
  { id: '1', name: 'TDPM Console port', color: 'BLUE' as const },
@@ -11,10 +11,10 @@ const options = [
11
11
  { id: '3', name: 'Move to Okinawa', color: 'PURPLE' as const },
12
12
  ];
13
13
 
14
- describe('ConsoleStoryButtonGroup', () => {
14
+ describe('ConsoleStoryActions', () => {
15
15
  it('excludes no-story options', () => {
16
16
  const { getByText, queryByText } = render(
17
- <ConsoleStoryButtonGroup storyOptions={options} onSetStory={() => {}} />,
17
+ <ConsoleStoryActions storyOptions={options} onSetStory={() => {}} />,
18
18
  );
19
19
  expect(getByText('TDPM Console port')).toBeInTheDocument();
20
20
  expect(getByText('Move to Okinawa')).toBeInTheDocument();
@@ -24,10 +24,7 @@ describe('ConsoleStoryButtonGroup', () => {
24
24
  it('reports the selected story option', () => {
25
25
  const onSetStory = jest.fn();
26
26
  const { getByText } = render(
27
- <ConsoleStoryButtonGroup
28
- storyOptions={options}
29
- onSetStory={onSetStory}
30
- />,
27
+ <ConsoleStoryActions storyOptions={options} onSetStory={onSetStory} />,
31
28
  );
32
29
  fireEvent.click(getByText('Move to Okinawa'));
33
30
  expect(onSetStory).toHaveBeenCalledWith(options[2]);
@@ -35,10 +32,7 @@ describe('ConsoleStoryButtonGroup', () => {
35
32
 
36
33
  it('renders nothing when only no-story options exist', () => {
37
34
  const { container } = render(
38
- <ConsoleStoryButtonGroup
39
- storyOptions={[options[1]]}
40
- onSetStory={() => {}}
41
- />,
35
+ <ConsoleStoryActions storyOptions={[options[1]]} onSetStory={() => {}} />,
42
36
  );
43
37
  expect(container.firstChild).toBeNull();
44
38
  });
@@ -1,5 +1,5 @@
1
- import { colorFromEnum } from '../colors';
2
- import type { ConsoleFieldOption } from '../types';
1
+ import { colorFromEnum } from '../../logic/colors';
2
+ import type { ConsoleFieldOption } from '../../logic/types';
3
3
 
4
4
  export type ConsoleStoryButtonGroupProps = {
5
5
  storyOptions: ConsoleFieldOption[];
@@ -9,7 +9,7 @@ export type ConsoleStoryButtonGroupProps = {
9
9
  const isNoStoryOption = (option: ConsoleFieldOption): boolean =>
10
10
  option.name.toLowerCase().includes('no story');
11
11
 
12
- export const ConsoleStoryButtonGroup = ({
12
+ export const ConsoleStoryActions = ({
13
13
  storyOptions,
14
14
  onSetStory,
15
15
  }: ConsoleStoryButtonGroupProps) => {
@@ -10,7 +10,7 @@ import type {
10
10
  ConsoleCommit,
11
11
  ConsoleIssueState,
12
12
  ConsoleRelatedPullRequest,
13
- } from '../types';
13
+ } from '../logic/types';
14
14
  import { useConsoleToken } from './useConsoleToken';
15
15
 
16
16
  export type ConsoleCaches = {
@@ -7,7 +7,7 @@ import type {
7
7
  ConsoleIssueState,
8
8
  ConsoleListItem,
9
9
  ConsoleRelatedPullRequest,
10
- } from '../types';
10
+ } from '../logic/types';
11
11
  import type { ConsoleCaches } from './useConsoleCaches';
12
12
  import { useConsoleItemDetailData } from './useConsoleItemDetailData';
13
13
 
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState } from 'react';
2
- import type { ConsoleRelatedPullRequestView } from '../components/ConsoleItemDetail';
2
+ import type { ConsoleRelatedPullRequestView } from '../components/detail/ConsoleItemDetail';
3
3
  import type {
4
4
  ConsoleChangedFile,
5
5
  ConsoleComment,
@@ -7,7 +7,7 @@ import type {
7
7
  ConsoleIssueState,
8
8
  ConsoleListItem,
9
9
  ConsoleRelatedPullRequest,
10
- } from '../types';
10
+ } from '../logic/types';
11
11
  import type { ConsoleCaches } from './useConsoleCaches';
12
12
  import { useConsoleResource } from './useConsoleResource';
13
13
 
@@ -1,9 +1,9 @@
1
1
  import { act, renderHook } from '@testing-library/react';
2
+ import { overlayStorageKey } from '../logic/overlay';
2
3
  import {
3
4
  consoleListItemsFixture,
4
5
  consoleStatusOptionsFixture,
5
- } from '../fixtures';
6
- import { overlayStorageKey } from '../overlay';
6
+ } from '../testing/fixtures';
7
7
  import { useConsoleOperations } from './useConsoleOperations';
8
8
  import { useConsoleOverlay } from './useConsoleOverlay';
9
9
 
@@ -11,13 +11,13 @@ import {
11
11
  type ConsoleReviewAction,
12
12
  TOTALLY_WRONG_COMMENT_BODY,
13
13
  UNNECESSARY_COMMENT_BODY,
14
- } from '../operations';
15
- import { overlayKeyForItem } from '../overlay';
14
+ } from '../logic/operations';
15
+ import { overlayKeyForItem } from '../logic/overlay';
16
16
  import type {
17
17
  ConsoleFieldOption,
18
18
  ConsoleListItem,
19
19
  ConsoleTabName,
20
- } from '../types';
20
+ } from '../logic/types';
21
21
  import type { ConsoleOverlayState } from './useConsoleOverlay';
22
22
  import { useConsoleToken } from './useConsoleToken';
23
23
 
@@ -1,5 +1,5 @@
1
1
  import { act, renderHook } from '@testing-library/react';
2
- import { overlayStorageKey } from '../overlay';
2
+ import { overlayStorageKey } from '../logic/overlay';
3
3
  import { useConsoleOverlay } from './useConsoleOverlay';
4
4
 
5
5
  describe('useConsoleOverlay', () => {
@@ -1,10 +1,10 @@
1
1
  import { useCallback, useState } from 'react';
2
- import { overlayStorageKey, writeOverlayEntry } from '../overlay';
2
+ import { overlayStorageKey, writeOverlayEntry } from '../logic/overlay';
3
3
  import type {
4
4
  ConsoleOverlay,
5
5
  ConsoleOverlayEntry,
6
6
  ConsoleTabName,
7
- } from '../types';
7
+ } from '../logic/types';
8
8
 
9
9
  const isOverlayEntry = (value: unknown): value is ConsoleOverlayEntry =>
10
10
  value !== null &&
@@ -4,8 +4,8 @@ import type {
4
4
  ConsoleListItem,
5
5
  ConsoleStoryColorSource,
6
6
  ConsoleTabName,
7
- } from '../types';
8
- import { CONSOLE_TABS } from '../types';
7
+ } from '../logic/types';
8
+ import { CONSOLE_TABS } from '../logic/types';
9
9
  import { useConsoleToken } from './useConsoleToken';
10
10
 
11
11
  export type ConsoleTabSnapshot = {
@@ -4,7 +4,7 @@ import type {
4
4
  ConsoleCommit,
5
5
  ConsoleIssueState,
6
6
  ConsoleRelatedPullRequest,
7
- } from '../types';
7
+ } from '../logic/types';
8
8
 
9
9
  export type ConsoleApiClient = {
10
10
  fetchItemBody: (url: string) => Promise<string>;
@@ -44,12 +44,12 @@ export type ConsoleListGroupRow = {
44
44
  count: number;
45
45
  };
46
46
 
47
- export type ConsoleListItemRow = {
47
+ export type ConsoleItemSummary = {
48
48
  kind: 'item';
49
49
  item: ConsoleListItem;
50
50
  };
51
51
 
52
- export type ConsoleListRow = ConsoleListGroupRow | ConsoleListItemRow;
52
+ export type ConsoleListRow = ConsoleListGroupRow | ConsoleItemSummary;
53
53
 
54
54
  export const buildConsoleListRows = (
55
55
  items: ConsoleListItem[],
@@ -0,0 +1,146 @@
1
+ import {
2
+ countPendingItems,
3
+ filterPendingItems,
4
+ isOverlayEntryActed,
5
+ overlayKeyForItem,
6
+ overlayStorageKey,
7
+ writeOverlayEntry,
8
+ } from './overlay';
9
+ import type { ConsoleListItem, ConsoleOverlay } from './types';
10
+
11
+ const item = (number: number): ConsoleListItem => ({
12
+ number,
13
+ title: `Item ${number}`,
14
+ url: `https://github.com/o/r/issues/${number}`,
15
+ repo: 'o/r',
16
+ nameWithOwner: 'o/r',
17
+ projectItemId: `PVTI_${number}`,
18
+ itemId: `PVTI_${number}`,
19
+ isPr: false,
20
+ story: 'Story',
21
+ labels: [],
22
+ createdAt: '2026-06-10T00:00:00.000Z',
23
+ });
24
+
25
+ describe('overlay helpers', () => {
26
+ it('builds the per-project storage key', () => {
27
+ expect(overlayStorageKey('umino')).toBe('pv_overlay_umino');
28
+ });
29
+
30
+ it('uses the projectItemId as the overlay key when present', () => {
31
+ expect(overlayKeyForItem(item(5))).toBe('PVTI_5');
32
+ });
33
+
34
+ it('falls back to the itemId when the projectItemId is empty', () => {
35
+ expect(overlayKeyForItem({ ...item(5), projectItemId: '' })).toBe('PVTI_5');
36
+ });
37
+ });
38
+
39
+ describe('isOverlayEntryActed', () => {
40
+ it('treats a done entry as acted', () => {
41
+ expect(isOverlayEntryActed({ ts: 100, mode: 'prs', done: true })).toBe(
42
+ true,
43
+ );
44
+ });
45
+
46
+ it('treats a missing entry as not acted', () => {
47
+ expect(isOverlayEntryActed(undefined)).toBe(false);
48
+ });
49
+
50
+ it('treats an entry without done as not acted', () => {
51
+ expect(
52
+ isOverlayEntryActed({
53
+ ts: 100,
54
+ mode: 'prs',
55
+ story: { name: 'Story', color: 'BLUE' },
56
+ }),
57
+ ).toBe(false);
58
+ });
59
+
60
+ it('treats a done entry as acted regardless of the mode it was written in', () => {
61
+ expect(isOverlayEntryActed({ ts: 100, mode: 'triage', done: true })).toBe(
62
+ true,
63
+ );
64
+ });
65
+ });
66
+
67
+ describe('counts driven to zero do not revive on tab switch', () => {
68
+ it('keeps a done item subtracted in the tab it was processed in', () => {
69
+ const overlay: ConsoleOverlay = {
70
+ PVTI_1: { ts: 500, mode: 'prs', done: true },
71
+ };
72
+ expect(countPendingItems([item(1)], overlay)).toBe(0);
73
+ });
74
+
75
+ it('keeps a done item subtracted from every tab regardless of its mode', () => {
76
+ const overlay: ConsoleOverlay = {
77
+ PVTI_1: { ts: 100, mode: 'triage', done: true },
78
+ };
79
+ expect(countPendingItems([item(1)], overlay)).toBe(0);
80
+ });
81
+
82
+ it('does not revive a done item even when an entry was processed before the snapshot it still appears in', () => {
83
+ const overlay: ConsoleOverlay = {
84
+ PVTI_1: { ts: 100, mode: 'prs', done: true },
85
+ };
86
+ expect(countPendingItems([item(1)], overlay)).toBe(0);
87
+ });
88
+
89
+ it('does not revive a done item when it appears in a tab other than the one it was processed in', () => {
90
+ const overlay: ConsoleOverlay = {
91
+ PVTI_1: { ts: 100, mode: 'prs', done: true },
92
+ };
93
+ expect(countPendingItems([item(1)], overlay)).toBe(0);
94
+ expect(filterPendingItems([item(1)], overlay)).toEqual([]);
95
+ });
96
+
97
+ it('counts an item that has no done entry', () => {
98
+ expect(countPendingItems([item(1)], {})).toBe(1);
99
+ });
100
+ });
101
+
102
+ describe('filterPendingItems', () => {
103
+ it('drops acted items and keeps the rest', () => {
104
+ const overlay: ConsoleOverlay = {
105
+ PVTI_1: { ts: 500, mode: 'prs', done: true },
106
+ };
107
+ const result = filterPendingItems([item(1), item(2)], overlay);
108
+ expect(result.map((entry) => entry.number)).toEqual([2]);
109
+ });
110
+
111
+ it('keeps the badge count and the filtered list consistent', () => {
112
+ const overlay: ConsoleOverlay = {
113
+ PVTI_1: { ts: 500, mode: 'prs', done: true },
114
+ };
115
+ const items = [item(1), item(2)];
116
+ expect(countPendingItems(items, overlay)).toBe(
117
+ filterPendingItems(items, overlay).length,
118
+ );
119
+ });
120
+ });
121
+
122
+ describe('writeOverlayEntry', () => {
123
+ it('stamps the timestamp and mode on write', () => {
124
+ const next = writeOverlayEntry({}, 'PVTI_1', { done: true }, 'prs', 1234);
125
+ expect(next.PVTI_1).toEqual({ done: true, ts: 1234, mode: 'prs' });
126
+ });
127
+
128
+ it('merges a patch into an existing entry while refreshing ts and mode', () => {
129
+ const overlay: ConsoleOverlay = {
130
+ PVTI_1: { ts: 100, mode: 'prs', done: true },
131
+ };
132
+ const next = writeOverlayEntry(
133
+ overlay,
134
+ 'PVTI_1',
135
+ { story: { name: 'New Story', color: 'GREEN' } },
136
+ 'triage',
137
+ 999,
138
+ );
139
+ expect(next.PVTI_1).toEqual({
140
+ done: true,
141
+ story: { name: 'New Story', color: 'GREEN' },
142
+ ts: 999,
143
+ mode: 'triage',
144
+ });
145
+ });
146
+ });
@@ -0,0 +1,48 @@
1
+ import type {
2
+ ConsoleListItem,
3
+ ConsoleOverlay,
4
+ ConsoleOverlayEntry,
5
+ ConsoleTabName,
6
+ } from './types';
7
+
8
+ export const overlayStorageKey = (pjcode: string): string =>
9
+ `pv_overlay_${pjcode}`;
10
+
11
+ export const overlayKeyForItem = (item: ConsoleListItem): string =>
12
+ item.projectItemId !== '' ? item.projectItemId : item.itemId;
13
+
14
+ export const isOverlayEntryActed = (
15
+ entry: ConsoleOverlayEntry | undefined,
16
+ ): boolean => entry !== undefined && entry.done === true;
17
+
18
+ export const countPendingItems = (
19
+ items: ConsoleListItem[],
20
+ overlay: ConsoleOverlay,
21
+ ): number =>
22
+ items.filter((item) => !isOverlayEntryActed(overlay[overlayKeyForItem(item)]))
23
+ .length;
24
+
25
+ export const filterPendingItems = (
26
+ items: ConsoleListItem[],
27
+ overlay: ConsoleOverlay,
28
+ ): ConsoleListItem[] =>
29
+ items.filter(
30
+ (item) => !isOverlayEntryActed(overlay[overlayKeyForItem(item)]),
31
+ );
32
+
33
+ export const writeOverlayEntry = (
34
+ overlay: ConsoleOverlay,
35
+ key: string,
36
+ patch: Partial<Omit<ConsoleOverlayEntry, 'ts' | 'mode'>>,
37
+ mode: ConsoleTabName,
38
+ now: number,
39
+ ): ConsoleOverlay => {
40
+ const existing = overlay[key];
41
+ const next: ConsoleOverlayEntry = {
42
+ ...(existing ?? {}),
43
+ ...patch,
44
+ ts: now,
45
+ mode,
46
+ };
47
+ return { ...overlay, [key]: next };
48
+ };
@@ -1,13 +1,13 @@
1
1
  import { fireEvent, render, waitFor } from '@testing-library/react';
2
+ import type { ConsoleCaches } from '../hooks/useConsoleCaches';
3
+ import type { ConsoleOperationsApi } from '../hooks/useConsoleOperations';
4
+ import { ResourceCache } from '../lib/resourceCache';
2
5
  import {
3
6
  consoleListItemsFixture,
4
7
  consoleStatusOptionsFixture,
5
8
  consoleStoryColorsFixture,
6
9
  consoleStoryOptionsFixture,
7
- } from '../fixtures';
8
- import type { ConsoleCaches } from '../hooks/useConsoleCaches';
9
- import type { ConsoleOperationsApi } from '../hooks/useConsoleOperations';
10
- import { ResourceCache } from '../lib/resourceCache';
10
+ } from '../testing/fixtures';
11
11
  import { ConsoleItemDetailContainer } from './ConsoleItemDetailContainer';
12
12
 
13
13
  jest.mock('../lib/mermaidLoader', () => ({
@@ -1,10 +1,10 @@
1
- import { ConsoleItemDetail } from '../components/ConsoleItemDetail';
2
- import { ConsoleOperationBar } from '../components/ConsoleOperationBar';
3
- import { resolveStoryColorEnum } from '../grouping';
1
+ import { ConsoleItemDetail } from '../components/detail/ConsoleItemDetail';
2
+ import { ConsoleOperationMenu } from '../components/operations/ConsoleOperationMenu';
4
3
  import type { ConsoleCaches } from '../hooks/useConsoleCaches';
5
4
  import { useConsoleItemDetailData } from '../hooks/useConsoleItemDetailData';
6
5
  import type { ConsoleOperationsApi } from '../hooks/useConsoleOperations';
7
- import type { ConsoleOperationHandlers } from '../operations';
6
+ import { resolveStoryColorEnum } from '../logic/grouping';
7
+ import type { ConsoleOperationHandlers } from '../logic/operations';
8
8
  import type {
9
9
  ConsoleColor,
10
10
  ConsoleFieldOption,
@@ -12,7 +12,7 @@ import type {
12
12
  ConsoleOverlayStatus,
13
13
  ConsoleStoryColorSource,
14
14
  ConsoleTabName,
15
- } from '../types';
15
+ } from '../logic/types';
16
16
 
17
17
  export type ConsoleItemDetailContainerProps = {
18
18
  tab: ConsoleTabName;
@@ -95,7 +95,7 @@ export const ConsoleItemDetailContainer = ({
95
95
  relatedPullRequests={detail.relatedPullRequests}
96
96
  now={now}
97
97
  operationBar={
98
- <ConsoleOperationBar
98
+ <ConsoleOperationMenu
99
99
  tab={tab}
100
100
  item={item}
101
101
  hasPullRequest={hasPullRequest}