github-issue-tower-defence-management 1.117.6 → 1.117.8
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 +14 -0
- package/README.md +2 -2
- package/bin/adapter/entry-points/console/consoleOperationApi.js +6 -1
- package/bin/adapter/entry-points/console/consoleOperationApi.js.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/index-DID_sTas.js +103 -0
- package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +11 -8
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
- package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js +3 -0
- package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js.map +1 -1
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +1 -1
- package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/console/consoleOperationApi.test.ts +28 -1
- package/src/adapter/entry-points/console/consoleOperationApi.ts +7 -0
- package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +1 -1
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleFileDiff.tsx +1 -1
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.stories.tsx +1 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.stories.tsx +10 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.test.tsx +33 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.tsx +6 -1
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsolePullRequestReviewActions.stories.tsx +8 -2
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsolePullRequestReviewActions.test.tsx +39 -3
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsolePullRequestReviewActions.tsx +21 -10
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts +63 -0
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts +15 -2
- package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +2 -0
- package/src/adapter/entry-points/console/ui/src/features/console/logic/operations.test.ts +24 -0
- package/src/adapter/entry-points/console/ui/src/features/console/logic/operations.ts +15 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +73 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +24 -14
- package/src/adapter/entry-points/console/ui-dist/assets/index-DID_sTas.js +103 -0
- package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +70 -0
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +13 -7
- package/src/adapter/repositories/issue/GraphqlProjectItemRepository.test.ts +30 -0
- package/src/adapter/repositories/issue/GraphqlProjectItemRepository.ts +4 -1
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +32 -4
- package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +2 -2
- package/src/domain/usecases/adapter-interfaces/IssueRepository.ts +6 -0
- package/types/adapter/entry-points/console/consoleOperationApi.d.ts.map +1 -1
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts +2 -2
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
- package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts.map +1 -1
- package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts +5 -1
- package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/index-Dx_VHaDe.js +0 -101
- package/src/adapter/entry-points/console/ui-dist/assets/index-Dx_VHaDe.js +0 -101
|
@@ -4,11 +4,17 @@ import { ConsolePullRequestReviewActions } from './ConsolePullRequestReviewActio
|
|
|
4
4
|
const meta: Meta<typeof ConsolePullRequestReviewActions> = {
|
|
5
5
|
title: 'Console/ConsolePullRequestReviewActions',
|
|
6
6
|
component: ConsolePullRequestReviewActions,
|
|
7
|
-
args: { onReview: () => {} },
|
|
7
|
+
args: { onReview: () => {}, rejectEnabled: false },
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export default meta;
|
|
11
11
|
|
|
12
12
|
type Story = StoryObj<typeof ConsolePullRequestReviewActions>;
|
|
13
13
|
|
|
14
|
-
export const
|
|
14
|
+
export const RejectDisabled: Story = {
|
|
15
|
+
args: { rejectEnabled: false },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const RejectEnabled: Story = {
|
|
19
|
+
args: { rejectEnabled: true },
|
|
20
|
+
};
|
|
@@ -4,7 +4,10 @@ import { ConsolePullRequestReviewActions } from './ConsolePullRequestReviewActio
|
|
|
4
4
|
describe('ConsolePullRequestReviewActions', () => {
|
|
5
5
|
it('renders the four buttons left to right', () => {
|
|
6
6
|
const { getAllByRole } = render(
|
|
7
|
-
<ConsolePullRequestReviewActions
|
|
7
|
+
<ConsolePullRequestReviewActions
|
|
8
|
+
onReview={() => {}}
|
|
9
|
+
rejectEnabled={false}
|
|
10
|
+
/>,
|
|
8
11
|
);
|
|
9
12
|
expect(getAllByRole('button').map((button) => button.textContent)).toEqual([
|
|
10
13
|
'Unnecessary',
|
|
@@ -14,10 +17,43 @@ describe('ConsolePullRequestReviewActions', () => {
|
|
|
14
17
|
]);
|
|
15
18
|
});
|
|
16
19
|
|
|
17
|
-
it('
|
|
20
|
+
it('disables Reject until an inline comment has been entered', () => {
|
|
21
|
+
const { getByText, rerender } = render(
|
|
22
|
+
<ConsolePullRequestReviewActions
|
|
23
|
+
onReview={() => {}}
|
|
24
|
+
rejectEnabled={false}
|
|
25
|
+
/>,
|
|
26
|
+
);
|
|
27
|
+
expect(getByText('Reject')).toBeDisabled();
|
|
28
|
+
expect(getByText('Approve')).not.toBeDisabled();
|
|
29
|
+
rerender(
|
|
30
|
+
<ConsolePullRequestReviewActions
|
|
31
|
+
onReview={() => {}}
|
|
32
|
+
rejectEnabled={true}
|
|
33
|
+
/>,
|
|
34
|
+
);
|
|
35
|
+
expect(getByText('Reject')).not.toBeDisabled();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('does not report a reject action while disabled', () => {
|
|
39
|
+
const onReview = jest.fn();
|
|
40
|
+
const { getByText } = render(
|
|
41
|
+
<ConsolePullRequestReviewActions
|
|
42
|
+
onReview={onReview}
|
|
43
|
+
rejectEnabled={false}
|
|
44
|
+
/>,
|
|
45
|
+
);
|
|
46
|
+
fireEvent.click(getByText('Reject'));
|
|
47
|
+
expect(onReview).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('reports each review action when reject is enabled', () => {
|
|
18
51
|
const onReview = jest.fn();
|
|
19
52
|
const { getByText } = render(
|
|
20
|
-
<ConsolePullRequestReviewActions
|
|
53
|
+
<ConsolePullRequestReviewActions
|
|
54
|
+
onReview={onReview}
|
|
55
|
+
rejectEnabled={true}
|
|
56
|
+
/>,
|
|
21
57
|
);
|
|
22
58
|
fireEvent.click(getByText('Unnecessary'));
|
|
23
59
|
fireEvent.click(getByText('Totally wrong'));
|
|
@@ -2,6 +2,7 @@ import type { ConsoleReviewAction } from '../../logic/operations';
|
|
|
2
2
|
|
|
3
3
|
export type ConsolePullRequestReviewGroupProps = {
|
|
4
4
|
onReview: (action: ConsoleReviewAction) => void;
|
|
5
|
+
rejectEnabled: boolean;
|
|
5
6
|
};
|
|
6
7
|
|
|
7
8
|
const REVIEW_BUTTONS: {
|
|
@@ -17,17 +18,27 @@ const REVIEW_BUTTONS: {
|
|
|
17
18
|
|
|
18
19
|
export const ConsolePullRequestReviewActions = ({
|
|
19
20
|
onReview,
|
|
21
|
+
rejectEnabled,
|
|
20
22
|
}: ConsolePullRequestReviewGroupProps) => (
|
|
21
23
|
<div className="console-op-group console-op-group-review">
|
|
22
|
-
{REVIEW_BUTTONS.map((button) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
{REVIEW_BUTTONS.map((button) => {
|
|
25
|
+
const disabled = button.action === 'request_changes' && !rejectEnabled;
|
|
26
|
+
return (
|
|
27
|
+
<button
|
|
28
|
+
key={button.action}
|
|
29
|
+
type="button"
|
|
30
|
+
className={`console-op-button console-op-button-${button.variant}`}
|
|
31
|
+
disabled={disabled}
|
|
32
|
+
title={
|
|
33
|
+
disabled
|
|
34
|
+
? 'Enter an inline comment on the diff to enable Reject'
|
|
35
|
+
: undefined
|
|
36
|
+
}
|
|
37
|
+
onClick={() => onReview(button.action)}
|
|
38
|
+
>
|
|
39
|
+
{button.label}
|
|
40
|
+
</button>
|
|
41
|
+
);
|
|
42
|
+
})}
|
|
32
43
|
</div>
|
|
33
44
|
);
|
package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts
CHANGED
|
@@ -272,6 +272,69 @@ describe('useConsoleOperations', () => {
|
|
|
272
272
|
});
|
|
273
273
|
});
|
|
274
274
|
|
|
275
|
+
it('sends the entered inline comment as the request-changes body and anchor', async () => {
|
|
276
|
+
const fetchMock = captureFetch();
|
|
277
|
+
const { result } = setup();
|
|
278
|
+
await act(async () => {
|
|
279
|
+
await result.current.operations.reviewPullRequest(
|
|
280
|
+
prItem,
|
|
281
|
+
prItem.url,
|
|
282
|
+
'request_changes',
|
|
283
|
+
[
|
|
284
|
+
{
|
|
285
|
+
path: 'src/index.ts',
|
|
286
|
+
line: 17,
|
|
287
|
+
side: 'RIGHT',
|
|
288
|
+
body: 'Please rename this variable.',
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
);
|
|
292
|
+
});
|
|
293
|
+
expect(fetchMock.mock.calls[0][0]).toBe('/api/review?k=token');
|
|
294
|
+
expect(lastBody(fetchMock)).toMatchObject({
|
|
295
|
+
pjcode: 'umino',
|
|
296
|
+
action: 'request_changes',
|
|
297
|
+
prUrl: prItem.url,
|
|
298
|
+
commentBody: 'src/index.ts:17 Please rename this variable.',
|
|
299
|
+
changedFilePath: 'src/index.ts',
|
|
300
|
+
line: 17,
|
|
301
|
+
side: 'RIGHT',
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('aggregates multiple entered inline comments into the request-changes body', async () => {
|
|
306
|
+
const fetchMock = captureFetch();
|
|
307
|
+
const { result } = setup();
|
|
308
|
+
await act(async () => {
|
|
309
|
+
await result.current.operations.reviewPullRequest(
|
|
310
|
+
prItem,
|
|
311
|
+
prItem.url,
|
|
312
|
+
'request_changes',
|
|
313
|
+
[
|
|
314
|
+
{
|
|
315
|
+
path: 'src/a.ts',
|
|
316
|
+
line: 3,
|
|
317
|
+
side: 'RIGHT',
|
|
318
|
+
body: 'First concern.',
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
path: 'src/b.ts',
|
|
322
|
+
line: 9,
|
|
323
|
+
side: 'LEFT',
|
|
324
|
+
body: 'Second concern.',
|
|
325
|
+
},
|
|
326
|
+
],
|
|
327
|
+
);
|
|
328
|
+
});
|
|
329
|
+
expect(lastBody(fetchMock)).toMatchObject({
|
|
330
|
+
action: 'request_changes',
|
|
331
|
+
commentBody: 'src/a.ts:3 First concern.\n\nsrc/b.ts:9 Second concern.',
|
|
332
|
+
changedFilePath: 'src/a.ts',
|
|
333
|
+
line: 3,
|
|
334
|
+
side: 'RIGHT',
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
275
338
|
it('invalidates the operated item body and comments cache on a review', async () => {
|
|
276
339
|
captureFetch();
|
|
277
340
|
localStorage.clear();
|
package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts
CHANGED
|
@@ -9,8 +9,10 @@ import {
|
|
|
9
9
|
postConsoleReviewComment,
|
|
10
10
|
} from '../lib/consoleApi';
|
|
11
11
|
import {
|
|
12
|
+
buildRequestChangesBody,
|
|
12
13
|
type ConsoleCloseAction,
|
|
13
14
|
type ConsoleNextActionDateAction,
|
|
15
|
+
type ConsolePendingReviewComment,
|
|
14
16
|
type ConsoleReviewAction,
|
|
15
17
|
TOTALLY_WRONG_COMMENT_BODY,
|
|
16
18
|
UNNECESSARY_COMMENT_BODY,
|
|
@@ -35,6 +37,7 @@ export type ConsoleOperationsApi = {
|
|
|
35
37
|
item: ConsoleListItem,
|
|
36
38
|
prUrl: string,
|
|
37
39
|
action: ConsoleReviewAction,
|
|
40
|
+
pendingReviewComments?: ConsolePendingReviewComment[],
|
|
38
41
|
) => Promise<void>;
|
|
39
42
|
setNextActionDate: (
|
|
40
43
|
item: ConsoleListItem,
|
|
@@ -71,6 +74,7 @@ const reviewRequest = (
|
|
|
71
74
|
item: ConsoleListItem,
|
|
72
75
|
prUrl: string,
|
|
73
76
|
action: ConsoleReviewAction,
|
|
77
|
+
pendingReviewComments: ConsolePendingReviewComment[],
|
|
74
78
|
): ConsoleReviewRequest => {
|
|
75
79
|
if (action === 'approve') {
|
|
76
80
|
return {
|
|
@@ -81,12 +85,20 @@ const reviewRequest = (
|
|
|
81
85
|
};
|
|
82
86
|
}
|
|
83
87
|
if (action === 'request_changes') {
|
|
88
|
+
const firstComment = pendingReviewComments[0];
|
|
84
89
|
return {
|
|
85
90
|
pjcode,
|
|
86
91
|
action: 'request_changes',
|
|
87
92
|
prUrl,
|
|
88
93
|
projectItemId: item.projectItemId,
|
|
89
|
-
commentBody:
|
|
94
|
+
commentBody: buildRequestChangesBody(pendingReviewComments),
|
|
95
|
+
...(firstComment === undefined
|
|
96
|
+
? {}
|
|
97
|
+
: {
|
|
98
|
+
changedFilePath: firstComment.path,
|
|
99
|
+
line: firstComment.line,
|
|
100
|
+
side: firstComment.side,
|
|
101
|
+
}),
|
|
90
102
|
};
|
|
91
103
|
}
|
|
92
104
|
if (action === 'totally_wrong') {
|
|
@@ -144,6 +156,7 @@ export const useConsoleOperations = (
|
|
|
144
156
|
item: ConsoleListItem,
|
|
145
157
|
prUrl: string,
|
|
146
158
|
action: ConsoleReviewAction,
|
|
159
|
+
pendingReviewComments: ConsolePendingReviewComment[] = [],
|
|
147
160
|
) => {
|
|
148
161
|
if (pjcode === null) {
|
|
149
162
|
throw missingPjcodeError();
|
|
@@ -151,7 +164,7 @@ export const useConsoleOperations = (
|
|
|
151
164
|
await postConsoleOperation(
|
|
152
165
|
appendToken,
|
|
153
166
|
REVIEW_OPERATION_PATH,
|
|
154
|
-
reviewRequest(pjcode, item, prUrl, action),
|
|
167
|
+
reviewRequest(pjcode, item, prUrl, action, pendingReviewComments),
|
|
155
168
|
);
|
|
156
169
|
markDone(item);
|
|
157
170
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
buildRequestChangesBody,
|
|
2
3
|
IN_TMUX_BY_HUMAN_NAME,
|
|
3
4
|
isTodoByHumanTab,
|
|
4
5
|
STATUS_BUTTON_NAMES,
|
|
@@ -35,3 +36,26 @@ describe('isTodoByHumanTab', () => {
|
|
|
35
36
|
expect(isTodoByHumanTab('prs')).toBe(false);
|
|
36
37
|
});
|
|
37
38
|
});
|
|
39
|
+
|
|
40
|
+
describe('buildRequestChangesBody', () => {
|
|
41
|
+
it('renders a single inline comment with its file and line prefix', () => {
|
|
42
|
+
expect(
|
|
43
|
+
buildRequestChangesBody([
|
|
44
|
+
{ path: 'src/a.ts', line: 12, side: 'RIGHT', body: 'Please fix.' },
|
|
45
|
+
]),
|
|
46
|
+
).toBe('src/a.ts:12 Please fix.');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('joins multiple inline comments with blank lines', () => {
|
|
50
|
+
expect(
|
|
51
|
+
buildRequestChangesBody([
|
|
52
|
+
{ path: 'src/a.ts', line: 3, side: 'RIGHT', body: 'First.' },
|
|
53
|
+
{ path: 'src/b.ts', line: 9, side: 'LEFT', body: 'Second.' },
|
|
54
|
+
]),
|
|
55
|
+
).toBe('src/a.ts:3 First.\n\nsrc/b.ts:9 Second.');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('returns an empty string when there are no comments', () => {
|
|
59
|
+
expect(buildRequestChangesBody([])).toBe('');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
import type { ConsoleReviewCommentSide } from '../lib/consoleApi';
|
|
1
2
|
import type { ConsoleFieldOption, ConsoleTabName } from './types';
|
|
2
3
|
|
|
3
4
|
export const TOTALLY_WRONG_COMMENT_BODY = 'totally wrong';
|
|
4
5
|
export const UNNECESSARY_COMMENT_BODY = 'This pull request is unnecessary.';
|
|
5
6
|
|
|
7
|
+
export type ConsolePendingReviewComment = {
|
|
8
|
+
path: string;
|
|
9
|
+
line: number;
|
|
10
|
+
side: ConsoleReviewCommentSide;
|
|
11
|
+
body: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const buildRequestChangesBody = (
|
|
15
|
+
comments: ConsolePendingReviewComment[],
|
|
16
|
+
): string =>
|
|
17
|
+
comments
|
|
18
|
+
.map((comment) => `${comment.path}:${comment.line} ${comment.body}`)
|
|
19
|
+
.join('\n\n');
|
|
20
|
+
|
|
6
21
|
export type ConsoleReviewAction =
|
|
7
22
|
| 'approve'
|
|
8
23
|
| 'request_changes'
|
|
@@ -111,9 +111,82 @@ describe('ConsoleItemDetailContainer', () => {
|
|
|
111
111
|
prItem,
|
|
112
112
|
prItem.url,
|
|
113
113
|
'approve',
|
|
114
|
+
[],
|
|
114
115
|
);
|
|
115
116
|
});
|
|
116
117
|
|
|
118
|
+
it('disables Reject until an inline comment is entered and then commits it as the request-changes review', async () => {
|
|
119
|
+
const operations = buildOperations();
|
|
120
|
+
const onQueueAction = jest.fn();
|
|
121
|
+
const {
|
|
122
|
+
container,
|
|
123
|
+
findByRole,
|
|
124
|
+
getAllByRole,
|
|
125
|
+
getByPlaceholderText,
|
|
126
|
+
getByText,
|
|
127
|
+
} = render(
|
|
128
|
+
<ConsoleItemDetailContainer
|
|
129
|
+
tab="prs"
|
|
130
|
+
item={prItem}
|
|
131
|
+
caches={buildCaches({ prFiles: consoleChangedFilesFixture })}
|
|
132
|
+
operations={operations}
|
|
133
|
+
statusOptions={consoleStatusOptionsFixture}
|
|
134
|
+
storyOptions={consoleStoryOptionsFixture}
|
|
135
|
+
storyColors={consoleStoryColorsFixture}
|
|
136
|
+
storyName="TDPM Console port"
|
|
137
|
+
overlayStatus={null}
|
|
138
|
+
now={Date.parse('2026-06-19T12:00:00.000Z')}
|
|
139
|
+
onQueueAction={onQueueAction}
|
|
140
|
+
/>,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
await waitFor(() => {
|
|
144
|
+
expect(getByText('Reject')).toBeInTheDocument();
|
|
145
|
+
});
|
|
146
|
+
expect(getByText('Reject')).toBeDisabled();
|
|
147
|
+
|
|
148
|
+
const fileRow = await findByRole('button', {
|
|
149
|
+
name: new RegExp(consoleChangedFilesFixture[0].path),
|
|
150
|
+
});
|
|
151
|
+
fireEvent.click(fileRow);
|
|
152
|
+
const commentButton = getAllByRole('button', {
|
|
153
|
+
name: /^Comment on line/,
|
|
154
|
+
})[0];
|
|
155
|
+
fireEvent.click(commentButton);
|
|
156
|
+
fireEvent.change(
|
|
157
|
+
getByPlaceholderText('Leave a review comment on this line…'),
|
|
158
|
+
{ target: { value: 'Please rename this variable.' } },
|
|
159
|
+
);
|
|
160
|
+
const submitButton = container.querySelector(
|
|
161
|
+
'.console-diff-composer-submit',
|
|
162
|
+
);
|
|
163
|
+
fireEvent.click(submitButton as Element);
|
|
164
|
+
|
|
165
|
+
await waitFor(() => {
|
|
166
|
+
expect(getByText('Reject')).not.toBeDisabled();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
fireEvent.click(getByText('Reject'));
|
|
170
|
+
const rejectInput = onQueueAction.mock.calls.at(-1)?.[0];
|
|
171
|
+
expect(rejectInput.kind).toEqual({
|
|
172
|
+
type: 'review',
|
|
173
|
+
action: 'request_changes',
|
|
174
|
+
});
|
|
175
|
+
rejectInput.commit();
|
|
176
|
+
const reviewCall = (
|
|
177
|
+
operations.reviewPullRequest as jest.Mock
|
|
178
|
+
).mock.calls.at(-1);
|
|
179
|
+
expect(reviewCall?.[2]).toBe('request_changes');
|
|
180
|
+
expect(reviewCall?.[3]).toEqual([
|
|
181
|
+
{
|
|
182
|
+
path: consoleChangedFilesFixture[0].path,
|
|
183
|
+
line: expect.any(Number),
|
|
184
|
+
side: expect.stringMatching(/LEFT|RIGHT/),
|
|
185
|
+
body: 'Please rename this variable.',
|
|
186
|
+
},
|
|
187
|
+
]);
|
|
188
|
+
});
|
|
189
|
+
|
|
117
190
|
it('routes an inline review comment on an issue related pull request to that pull request url', async () => {
|
|
118
191
|
const operations = buildOperations();
|
|
119
192
|
const relatedPullRequest = consoleRelatedPullRequestsFixture[0];
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import { useCallback,
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
2
2
|
import { ConsoleCommentComposer } from '../components/detail/ConsoleCommentComposer';
|
|
3
|
+
import type { ConsoleAddInlineComment } from '../components/detail/ConsoleFileDiff';
|
|
3
4
|
import { ConsoleItemDetail } from '../components/detail/ConsoleItemDetail';
|
|
4
5
|
import { ConsoleOperationMenu } from '../components/operations/ConsoleOperationMenu';
|
|
5
6
|
import type { ConsoleCaches } from '../hooks/useConsoleCaches';
|
|
6
7
|
import { useConsoleItemDetailData } from '../hooks/useConsoleItemDetailData';
|
|
7
8
|
import type { ConsoleOperationsApi } from '../hooks/useConsoleOperations';
|
|
8
9
|
import { useConsoleToken } from '../hooks/useConsoleToken';
|
|
9
|
-
import type { ConsoleReviewCommentSide } from '../lib/consoleApi';
|
|
10
10
|
import { buildImageProxyUrl } from '../lib/imageProxy';
|
|
11
11
|
import type { ConsoleActionKind } from '../logic/actionToast';
|
|
12
12
|
import { resolveStoryColorEnum } from '../logic/grouping';
|
|
13
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
ConsoleOperationHandlers,
|
|
15
|
+
ConsolePendingReviewComment,
|
|
16
|
+
} from '../logic/operations';
|
|
14
17
|
import type {
|
|
15
18
|
ConsoleColor,
|
|
16
19
|
ConsoleFieldOption,
|
|
@@ -71,20 +74,23 @@ export const ConsoleItemDetailContainer = ({
|
|
|
71
74
|
[caches.state],
|
|
72
75
|
);
|
|
73
76
|
const hasPullRequest = item.isPr || detail.relatedPullRequests.length > 0;
|
|
77
|
+
const [pendingReviewComments, setPendingReviewComments] = useState<
|
|
78
|
+
ConsolePendingReviewComment[]
|
|
79
|
+
>([]);
|
|
74
80
|
const buildAddInlineComment = useCallback(
|
|
75
|
-
(prUrl: string) =>
|
|
76
|
-
(
|
|
77
|
-
path: string,
|
|
78
|
-
line: number,
|
|
79
|
-
side: ConsoleReviewCommentSide,
|
|
80
|
-
body: string,
|
|
81
|
-
) =>
|
|
81
|
+
(prUrl: string): ConsoleAddInlineComment =>
|
|
82
|
+
(path, line, side, body) =>
|
|
82
83
|
operations.addInlineReviewComment(prUrl, path, line, side, body),
|
|
83
84
|
[operations],
|
|
84
85
|
);
|
|
85
|
-
const addInlineComment =
|
|
86
|
-
() =>
|
|
87
|
-
|
|
86
|
+
const addInlineComment = useCallback<ConsoleAddInlineComment>(
|
|
87
|
+
async (path, line, side, body) => {
|
|
88
|
+
setPendingReviewComments((previous) => [
|
|
89
|
+
...previous,
|
|
90
|
+
{ path, line, side, body },
|
|
91
|
+
]);
|
|
92
|
+
},
|
|
93
|
+
[],
|
|
88
94
|
);
|
|
89
95
|
|
|
90
96
|
const handlers: ConsoleOperationHandlers = {
|
|
@@ -92,10 +98,13 @@ export const ConsoleItemDetailContainer = ({
|
|
|
92
98
|
const prUrl = item.isPr
|
|
93
99
|
? item.url
|
|
94
100
|
: (detail.relatedPullRequests[0]?.pullRequest.url ?? item.url);
|
|
101
|
+
const reviewComments =
|
|
102
|
+
action === 'request_changes' ? pendingReviewComments : [];
|
|
95
103
|
onQueueAction({
|
|
96
104
|
kind: { type: 'review', action },
|
|
97
105
|
item,
|
|
98
|
-
commit: () =>
|
|
106
|
+
commit: () =>
|
|
107
|
+
operations.reviewPullRequest(item, prUrl, action, reviewComments),
|
|
99
108
|
});
|
|
100
109
|
},
|
|
101
110
|
onSetNextActionDate: (action) => {
|
|
@@ -180,6 +189,7 @@ export const ConsoleItemDetailContainer = ({
|
|
|
180
189
|
tab={tab}
|
|
181
190
|
item={item}
|
|
182
191
|
hasPullRequest={hasPullRequest}
|
|
192
|
+
rejectEnabled={pendingReviewComments.length > 0}
|
|
183
193
|
statusOptions={statusOptions}
|
|
184
194
|
storyOptions={storyOptions}
|
|
185
195
|
handlers={handlers}
|