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.
Files changed (48) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +2 -2
  3. package/bin/adapter/entry-points/console/consoleOperationApi.js +6 -1
  4. package/bin/adapter/entry-points/console/consoleOperationApi.js.map +1 -1
  5. package/bin/adapter/entry-points/console/ui-dist/assets/index-DID_sTas.js +103 -0
  6. package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
  7. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +11 -8
  8. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
  9. package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js +3 -0
  10. package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js.map +1 -1
  11. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +1 -1
  12. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
  13. package/package.json +1 -1
  14. package/src/adapter/entry-points/console/consoleOperationApi.test.ts +28 -1
  15. package/src/adapter/entry-points/console/consoleOperationApi.ts +7 -0
  16. package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +1 -1
  17. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleFileDiff.tsx +1 -1
  18. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.stories.tsx +1 -0
  19. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.stories.tsx +10 -0
  20. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.test.tsx +33 -0
  21. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.tsx +6 -1
  22. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsolePullRequestReviewActions.stories.tsx +8 -2
  23. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsolePullRequestReviewActions.test.tsx +39 -3
  24. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsolePullRequestReviewActions.tsx +21 -10
  25. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts +63 -0
  26. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts +15 -2
  27. package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +2 -0
  28. package/src/adapter/entry-points/console/ui/src/features/console/logic/operations.test.ts +24 -0
  29. package/src/adapter/entry-points/console/ui/src/features/console/logic/operations.ts +15 -0
  30. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +73 -0
  31. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +24 -14
  32. package/src/adapter/entry-points/console/ui-dist/assets/index-DID_sTas.js +103 -0
  33. package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
  34. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +70 -0
  35. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +13 -7
  36. package/src/adapter/repositories/issue/GraphqlProjectItemRepository.test.ts +30 -0
  37. package/src/adapter/repositories/issue/GraphqlProjectItemRepository.ts +4 -1
  38. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +32 -4
  39. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +2 -2
  40. package/src/domain/usecases/adapter-interfaces/IssueRepository.ts +6 -0
  41. package/types/adapter/entry-points/console/consoleOperationApi.d.ts.map +1 -1
  42. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts +2 -2
  43. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
  44. package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts.map +1 -1
  45. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts +5 -1
  46. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts.map +1 -1
  47. package/bin/adapter/entry-points/console/ui-dist/assets/index-Dx_VHaDe.js +0 -101
  48. 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 Default: Story = {};
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 onReview={() => {}} />,
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('reports each review action', () => {
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 onReview={onReview} />,
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
- <button
24
- key={button.action}
25
- type="button"
26
- className={`console-op-button console-op-button-${button.variant}`}
27
- onClick={() => onReview(button.action)}
28
- >
29
- {button.label}
30
- </button>
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
  );
@@ -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();
@@ -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
  },
@@ -25,6 +25,8 @@ export type ConsoleReviewRequest = {
25
25
  projectItemId: string;
26
26
  commentBody?: string;
27
27
  changedFilePath?: string;
28
+ line?: number;
29
+ side?: ConsoleReviewCommentSide;
28
30
  };
29
31
 
30
32
  export type ConsoleTriageRequest = {
@@ -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, useMemo } from 'react';
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 { ConsoleOperationHandlers } from '../logic/operations';
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 = useMemo(
86
- () => buildAddInlineComment(item.url),
87
- [buildAddInlineComment, item.url],
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: () => operations.reviewPullRequest(item, prUrl, action),
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}