github-issue-tower-defence-management 1.151.6 → 1.152.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 (50) hide show
  1. package/.github/workflows/create-pr.yml +1 -1
  2. package/CHANGELOG.md +14 -0
  3. package/bin/adapter/entry-points/console/ui-dist/assets/index-DR_LIP9n.js +83 -0
  4. package/bin/adapter/entry-points/console/ui-dist/assets/index-lemrqYKZ.css +2 -0
  5. package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
  6. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +0 -19
  7. package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
  8. package/bin/adapter/entry-points/handlers/inTmuxByHumanDataWriter.js +1 -13
  9. package/bin/adapter/entry-points/handlers/inTmuxByHumanDataWriter.js.map +1 -1
  10. package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js +0 -41
  11. package/bin/adapter/repositories/TranscriptOwnerCallStatusProvider.js.map +1 -1
  12. package/bin/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.js +2 -21
  13. package/bin/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.js.map +1 -1
  14. package/package.json +1 -1
  15. package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +23 -0
  16. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.stories.tsx +0 -1
  17. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.test.tsx +6 -15
  18. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.tsx +1 -33
  19. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.tsx +4 -1
  20. package/src/adapter/entry-points/console/ui/src/features/console/logic/postedComments.test.ts +44 -0
  21. package/src/adapter/entry-points/console/ui/src/features/console/logic/postedComments.ts +17 -0
  22. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +77 -0
  23. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +14 -3
  24. package/src/adapter/entry-points/console/ui/src/index.css +0 -7
  25. package/src/adapter/entry-points/console/ui-dist/assets/index-DR_LIP9n.js +83 -0
  26. package/src/adapter/entry-points/console/ui-dist/assets/index-lemrqYKZ.css +2 -0
  27. package/src/adapter/entry-points/console/ui-dist/index.html +2 -2
  28. package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +0 -33
  29. package/src/adapter/entry-points/handlers/inTmuxByHumanDataWriter.test.ts +3 -104
  30. package/src/adapter/entry-points/handlers/inTmuxByHumanDataWriter.ts +0 -19
  31. package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.singleScan.test.ts +10 -12
  32. package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.test.ts +0 -178
  33. package/src/adapter/repositories/TranscriptOwnerCallStatusProvider.ts +0 -61
  34. package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.test.ts +0 -99
  35. package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.ts +1 -47
  36. package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
  37. package/types/adapter/entry-points/handlers/inTmuxByHumanDataWriter.d.ts +0 -2
  38. package/types/adapter/entry-points/handlers/inTmuxByHumanDataWriter.d.ts.map +1 -1
  39. package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts +0 -3
  40. package/types/adapter/repositories/TranscriptOwnerCallStatusProvider.d.ts.map +1 -1
  41. package/types/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.d.ts +0 -19
  42. package/types/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.d.ts.map +1 -1
  43. package/bin/adapter/entry-points/console/ui-dist/assets/index-ChJztBsb.js +0 -83
  44. package/bin/adapter/entry-points/console/ui-dist/assets/index-wDluFyBz.css +0 -2
  45. package/src/adapter/entry-points/console/ui-dist/assets/index-ChJztBsb.js +0 -83
  46. package/src/adapter/entry-points/console/ui-dist/assets/index-wDluFyBz.css +0 -2
  47. package/src/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.test.ts +0 -111
  48. package/src/adapter/entry-points/handlers/resolveUnansweredOwnerCalls.ts +0 -33
  49. package/src/domain/entities/UnansweredOwnerCall.ts +0 -4
  50. package/src/domain/usecases/intmux/UnansweredOwnerCallSessionKeyContract.test.ts +0 -141
@@ -1,14 +1,8 @@
1
1
  import { useRef, useState } from 'react';
2
- import {
3
- formatFullTimestamp,
4
- formatRelativeTime,
5
- } from '../../logic/relativeTime';
6
2
  import type { ConsoleComment } from '../../logic/types';
7
- import { ConsoleMarkdownContent } from '../content/ConsoleMarkdownContent';
8
3
 
9
4
  export type ConsoleCommentComposerProps = {
10
5
  initiallyOpen: boolean;
11
- now: number;
12
6
  onSubmit: (body: string) => Promise<ConsoleComment>;
13
7
  onUploadFile?: (file: File) => Promise<string>;
14
8
  };
@@ -38,7 +32,6 @@ export const appendAttachmentMarkdown = (
38
32
 
39
33
  export const ConsoleCommentComposer = ({
40
34
  initiallyOpen,
41
- now,
42
35
  onSubmit,
43
36
  onUploadFile,
44
37
  }: ConsoleCommentComposerProps) => {
@@ -48,7 +41,6 @@ export const ConsoleCommentComposer = ({
48
41
  const [uploadStatus, setUploadStatus] = useState<UploadStatus>({
49
42
  kind: 'idle',
50
43
  });
51
- const [posted, setPosted] = useState<ConsoleComment[]>([]);
52
44
  const fileInputRef = useRef<HTMLInputElement | null>(null);
53
45
 
54
46
  const submit = async (): Promise<void> => {
@@ -58,8 +50,7 @@ export const ConsoleCommentComposer = ({
58
50
  }
59
51
  setStatus({ kind: 'posting' });
60
52
  try {
61
- const comment = await onSubmit(body);
62
- setPosted((previous) => [...previous, comment]);
53
+ await onSubmit(body);
63
54
  setDraft('');
64
55
  setStatus({ kind: 'idle' });
65
56
  } catch (error) {
@@ -101,29 +92,6 @@ export const ConsoleCommentComposer = ({
101
92
  >
102
93
  {open ? '✕ Close' : '💬 Add a comment'}
103
94
  </button>
104
- {posted.length > 0 && (
105
- <div className="console-composer-posted">
106
- {posted.map((comment) => (
107
- <article
108
- key={`${comment.author}:${comment.createdAt}:${comment.body}`}
109
- className="console-comment"
110
- >
111
- <header
112
- className="console-comment-header"
113
- title={formatFullTimestamp(comment.createdAt)}
114
- >
115
- <span className="console-comment-author">
116
- {comment.author === '' ? 'you' : comment.author}
117
- </span>
118
- <span className="console-comment-time">
119
- {formatRelativeTime(comment.createdAt, now)}
120
- </span>
121
- </header>
122
- <ConsoleMarkdownContent body={comment.body} />
123
- </article>
124
- ))}
125
- </div>
126
- )}
127
95
  {open && (
128
96
  <div className="console-composer-form">
129
97
  <textarea
@@ -51,6 +51,7 @@ export type ConsoleItemDetailProps = {
51
51
  bodyIsLoading: boolean;
52
52
  bodyError: string | null;
53
53
  comments: ConsoleComment[];
54
+ hasPostedComment?: boolean;
54
55
  commentsAreLoading: boolean;
55
56
  commentsError: string | null;
56
57
  files: ConsoleChangedFile[];
@@ -82,6 +83,7 @@ export const ConsoleItemDetail = ({
82
83
  bodyIsLoading,
83
84
  bodyError,
84
85
  comments,
86
+ hasPostedComment = false,
85
87
  commentsAreLoading,
86
88
  commentsError,
87
89
  files,
@@ -275,9 +277,10 @@ export const ConsoleItemDetail = ({
275
277
  )}
276
278
 
277
279
  <ConsolePanel
280
+ key={hasPostedComment ? 'comments-with-posted' : 'comments'}
278
281
  title="Comments"
279
282
  count={commentsCount}
280
- defaultCollapsed={item.isPr}
283
+ defaultCollapsed={item.isPr && !hasPostedComment}
281
284
  >
282
285
  <ConsoleCommentList
283
286
  comments={comments}
@@ -0,0 +1,44 @@
1
+ import { mergePostedComments } from './postedComments';
2
+ import type { ConsoleComment } from './types';
3
+
4
+ const loadedComment: ConsoleComment = {
5
+ author: 'HiromiShikata',
6
+ body: 'Loaded from GitHub.',
7
+ createdAt: '2026-06-19T10:00:00.000Z',
8
+ };
9
+
10
+ const postedComment: ConsoleComment = {
11
+ author: 'HiromiShikata',
12
+ body: 'Posted from the console.',
13
+ createdAt: '2026-06-19T11:58:00.000Z',
14
+ };
15
+
16
+ describe('mergePostedComments', () => {
17
+ it('appends a posted comment after the loaded comments', () => {
18
+ expect(mergePostedComments([loadedComment], [postedComment])).toEqual([
19
+ loadedComment,
20
+ postedComment,
21
+ ]);
22
+ });
23
+
24
+ it('drops a posted comment that the reloaded comments already carry', () => {
25
+ expect(
26
+ mergePostedComments([loadedComment, postedComment], [postedComment]),
27
+ ).toEqual([loadedComment, postedComment]);
28
+ });
29
+
30
+ it('keeps a posted comment whose body differs from an otherwise identical loaded comment', () => {
31
+ const editedComment: ConsoleComment = {
32
+ ...postedComment,
33
+ body: 'Posted from the console, then edited.',
34
+ };
35
+ expect(mergePostedComments([postedComment], [editedComment])).toEqual([
36
+ postedComment,
37
+ editedComment,
38
+ ]);
39
+ });
40
+
41
+ it('returns the loaded comments unchanged when nothing was posted', () => {
42
+ expect(mergePostedComments([loadedComment], [])).toEqual([loadedComment]);
43
+ });
44
+ });
@@ -0,0 +1,17 @@
1
+ import type { ConsoleComment } from './types';
2
+
3
+ const commentIdentity = (comment: ConsoleComment): string =>
4
+ JSON.stringify([comment.author, comment.createdAt, comment.body]);
5
+
6
+ export const mergePostedComments = (
7
+ loadedComments: ConsoleComment[],
8
+ postedComments: ConsoleComment[],
9
+ ): ConsoleComment[] => {
10
+ const loadedIdentities = new Set(loadedComments.map(commentIdentity));
11
+ return [
12
+ ...loadedComments,
13
+ ...postedComments.filter(
14
+ (comment) => !loadedIdentities.has(commentIdentity(comment)),
15
+ ),
16
+ ];
17
+ };
@@ -140,6 +140,83 @@ describe('ConsoleItemDetailContainer', () => {
140
140
  expect(getByPlaceholderText('Leave a comment…')).toBeInTheDocument();
141
141
  });
142
142
 
143
+ it('puts a posted comment in the scrolling comment list and leaves the sticky dock holding only the input', async () => {
144
+ const operations = buildOperations();
145
+ operations.addComment = jest.fn(async (_item, body) => ({
146
+ author: 'HiromiShikata',
147
+ body,
148
+ createdAt: '2026-06-19T11:58:00.000Z',
149
+ }));
150
+ const { container, getByPlaceholderText, getByText } = render(
151
+ <ConsoleItemDetailContainer
152
+ tab="unread"
153
+ item={issueItem}
154
+ caches={buildCaches()}
155
+ operations={operations}
156
+ statusOptions={consoleStatusOptionsFixture}
157
+ storyOptions={consoleStoryOptionsFixture}
158
+ storyColors={consoleStoryColorsFixture}
159
+ storyName="TDPM Console port"
160
+ overlayStatus={null}
161
+ now={Date.parse('2026-06-19T12:00:00.000Z')}
162
+ onQueueAction={jest.fn()}
163
+ />,
164
+ );
165
+
166
+ fireEvent.change(getByPlaceholderText('Leave a comment…'), {
167
+ target: { value: 'The dock must not grow with every comment.' },
168
+ });
169
+ fireEvent.click(getByText('Comment'));
170
+
171
+ await waitFor(() => {
172
+ expect(
173
+ container.querySelector('.console-comment-list')?.textContent,
174
+ ).toContain('The dock must not grow with every comment.');
175
+ });
176
+ expect(
177
+ container.querySelector('.console-detail-dock')?.textContent,
178
+ ).not.toContain('The dock must not grow with every comment.');
179
+ expect(
180
+ container.querySelectorAll('.console-detail-dock .console-comment')
181
+ .length,
182
+ ).toBe(0);
183
+ });
184
+
185
+ it('opens the comments panel of a pull request item so the posted comment is on screen', async () => {
186
+ const operations = buildOperations();
187
+ operations.addComment = jest.fn(async (_item, body) => ({
188
+ author: 'HiromiShikata',
189
+ body,
190
+ createdAt: '2026-06-19T11:58:00.000Z',
191
+ }));
192
+ const { container, getByPlaceholderText, getByText } = render(
193
+ <ConsoleItemDetailContainer
194
+ tab="prs"
195
+ item={prItem}
196
+ caches={buildCaches()}
197
+ operations={operations}
198
+ statusOptions={consoleStatusOptionsFixture}
199
+ storyOptions={consoleStoryOptionsFixture}
200
+ storyColors={consoleStoryColorsFixture}
201
+ storyName="TDPM Console port"
202
+ overlayStatus={null}
203
+ now={Date.parse('2026-06-19T12:00:00.000Z')}
204
+ onQueueAction={jest.fn()}
205
+ />,
206
+ );
207
+
208
+ fireEvent.change(getByPlaceholderText('Leave a comment…'), {
209
+ target: { value: 'Posted from the pull request item.' },
210
+ });
211
+ fireEvent.click(getByText('Comment'));
212
+
213
+ await waitFor(() => {
214
+ expect(
215
+ container.querySelector('.console-comment-list')?.textContent,
216
+ ).toContain('Posted from the pull request item.');
217
+ });
218
+ });
219
+
143
220
  it('shows Approve for an issue item from the generated related open pull request urls before the related pull requests are fetched', () => {
144
221
  const operations = buildOperations();
145
222
  const onQueueAction = jest.fn();
@@ -13,8 +13,10 @@ import type {
13
13
  ConsoleOperationHandlers,
14
14
  ConsolePendingReviewComment,
15
15
  } from '../logic/operations';
16
+ import { mergePostedComments } from '../logic/postedComments';
16
17
  import type {
17
18
  ConsoleColor,
19
+ ConsoleComment,
18
20
  ConsoleFieldOption,
19
21
  ConsoleListItem,
20
22
  ConsoleOverlayStatus,
@@ -87,6 +89,15 @@ export const ConsoleItemDetailContainer = ({
87
89
  },
88
90
  [],
89
91
  );
92
+ const [postedComments, setPostedComments] = useState<ConsoleComment[]>([]);
93
+ const addComment = useCallback(
94
+ async (body: string): Promise<ConsoleComment> => {
95
+ const comment = await operations.addComment(item, body);
96
+ setPostedComments((previous) => [...previous, comment]);
97
+ return comment;
98
+ },
99
+ [item, operations],
100
+ );
90
101
 
91
102
  const handlers: ConsoleOperationHandlers = {
92
103
  onReview: (action) => {
@@ -159,7 +170,8 @@ export const ConsoleItemDetailContainer = ({
159
170
  body={detail.body}
160
171
  bodyIsLoading={detail.bodyIsLoading}
161
172
  bodyError={detail.bodyError}
162
- comments={detail.comments}
173
+ comments={mergePostedComments(detail.comments, postedComments)}
174
+ hasPostedComment={postedComments.length > 0}
163
175
  commentsAreLoading={detail.commentsAreLoading}
164
176
  commentsError={detail.commentsError}
165
177
  files={detail.files}
@@ -179,8 +191,7 @@ export const ConsoleItemDetailContainer = ({
179
191
  commentComposer={
180
192
  <ConsoleCommentComposer
181
193
  initiallyOpen
182
- now={now}
183
- onSubmit={(body) => operations.addComment(item, body)}
194
+ onSubmit={addComment}
184
195
  onUploadFile={(file) => operations.uploadAttachment(item, file)}
185
196
  />
186
197
  }
@@ -855,13 +855,6 @@ body {
855
855
  color: #e6edf3;
856
856
  }
857
857
 
858
- .console-composer-posted {
859
- margin-top: 8px;
860
- display: flex;
861
- flex-direction: column;
862
- gap: 8px;
863
- }
864
-
865
858
  .console-composer-form {
866
859
  margin-top: 8px;
867
860
  }