github-issue-tower-defence-management 1.180.0 → 1.181.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.
- package/CHANGELOG.md +20 -0
- package/bin/adapter/entry-points/console/ui-dist/assets/index-BUFcVUVD.js +86 -0
- package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/bin/adapter/repositories/GoogleSpreadsheetRepository.js +41 -12
- package/bin/adapter/repositories/GoogleSpreadsheetRepository.js.map +1 -1
- package/bin/domain/usecases/CheckIssueReviewReadinessUseCase.js +2 -1
- package/bin/domain/usecases/CheckIssueReviewReadinessUseCase.js.map +1 -1
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js +2 -1
- package/bin/domain/usecases/NotifyFinishedIssuePreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js +2 -1
- package/bin/domain/usecases/RevertOrphanedPreparationUseCase.js.map +1 -1
- package/bin/domain/usecases/TriagerApprovalDispatchUseCase.js +3 -3
- package/bin/domain/usecases/TriagerApprovalDispatchUseCase.js.map +1 -1
- package/bin/domain/usecases/extractFencedJsonBlocks.js +18 -0
- package/bin/domain/usecases/extractFencedJsonBlocks.js.map +1 -0
- package/bin/domain/usecases/extractNextStepAgent.js +14 -23
- package/bin/domain/usecases/extractNextStepAgent.js.map +1 -1
- package/bin/domain/usecases/findLastAgentReport.js +2 -3
- package/bin/domain/usecases/findLastAgentReport.js.map +1 -1
- package/bin/domain/usecases/isAgentReportBody.js +43 -0
- package/bin/domain/usecases/isAgentReportBody.js.map +1 -0
- package/bin/domain/usecases/isPullRequestDeclaredUnnecessary.js +12 -19
- package/bin/domain/usecases/isPullRequestDeclaredUnnecessary.js.map +1 -1
- package/package.json +1 -1
- 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/ConsoleItemDetail.stories.tsx +1 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOkAndAwaitingWorkspaceActions.stories.tsx +25 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOkAndAwaitingWorkspaceActions.test.tsx +50 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOkAndAwaitingWorkspaceActions.tsx +41 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.stories.tsx +1 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.test.tsx +1 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.tsx +5 -0
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts +70 -0
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts +29 -0
- package/src/adapter/entry-points/console/ui/src/features/console/logic/actionToast.test.ts +14 -0
- package/src/adapter/entry-points/console/ui/src/features/console/logic/actionToast.ts +5 -1
- package/src/adapter/entry-points/console/ui/src/features/console/logic/operations.ts +1 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +1 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +7 -0
- package/src/adapter/entry-points/console/ui-dist/assets/index-BUFcVUVD.js +86 -0
- package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/src/adapter/repositories/GoogleSpreadsheetRepository.test.ts +47 -0
- package/src/adapter/repositories/GoogleSpreadsheetRepository.ts +76 -36
- package/src/domain/usecases/CheckIssueReviewReadinessUseCase.ts +2 -1
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.test.ts +50 -0
- package/src/domain/usecases/NotifyFinishedIssuePreparationUseCase.ts +2 -1
- package/src/domain/usecases/RevertOrphanedPreparationUseCase.ts +2 -1
- package/src/domain/usecases/TriagerApprovalDispatchUseCase.ts +6 -5
- package/src/domain/usecases/extractFencedJsonBlocks.test.ts +40 -0
- package/src/domain/usecases/extractFencedJsonBlocks.ts +21 -0
- package/src/domain/usecases/extractNextStepAgent.test.ts +19 -0
- package/src/domain/usecases/extractNextStepAgent.ts +15 -27
- package/src/domain/usecases/findLastAgentReport.test.ts +28 -0
- package/src/domain/usecases/findLastAgentReport.ts +2 -3
- package/src/domain/usecases/isAgentReportBody.test.ts +108 -0
- package/src/domain/usecases/isAgentReportBody.ts +52 -0
- package/src/domain/usecases/isPullRequestDeclaredUnnecessary.test.ts +33 -0
- package/src/domain/usecases/isPullRequestDeclaredUnnecessary.ts +15 -23
- package/types/adapter/repositories/GoogleSpreadsheetRepository.d.ts +3 -1
- package/types/adapter/repositories/GoogleSpreadsheetRepository.d.ts.map +1 -1
- package/types/domain/usecases/CheckIssueReviewReadinessUseCase.d.ts.map +1 -1
- package/types/domain/usecases/NotifyFinishedIssuePreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/RevertOrphanedPreparationUseCase.d.ts.map +1 -1
- package/types/domain/usecases/TriagerApprovalDispatchUseCase.d.ts.map +1 -1
- package/types/domain/usecases/extractFencedJsonBlocks.d.ts +2 -0
- package/types/domain/usecases/extractFencedJsonBlocks.d.ts.map +1 -0
- package/types/domain/usecases/extractNextStepAgent.d.ts.map +1 -1
- package/types/domain/usecases/findLastAgentReport.d.ts.map +1 -1
- package/types/domain/usecases/isAgentReportBody.d.ts +4 -0
- package/types/domain/usecases/isAgentReportBody.d.ts.map +1 -0
- package/types/domain/usecases/isPullRequestDeclaredUnnecessary.d.ts.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/index-I_2Yu8fM.js +0 -86
- package/src/adapter/entry-points/console/ui-dist/assets/index-I_2Yu8fM.js +0 -86
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isPullRequestDeclaredUnnecessary = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const extractFencedJsonBlocks_1 = require("./extractFencedJsonBlocks");
|
|
5
|
+
const isAgentReportBody_1 = require("./isAgentReportBody");
|
|
6
6
|
const isPullRequestDeclaredUnnecessary = (comments, isTrustedAuthor) => {
|
|
7
7
|
const lastComment = comments[comments.length - 1];
|
|
8
8
|
if (!lastComment ||
|
|
9
9
|
!isTrustedAuthor(lastComment.author) ||
|
|
10
|
-
!lastComment.content
|
|
10
|
+
!(0, isAgentReportBody_1.isAgentReportBody)(lastComment.content)) {
|
|
11
11
|
return false;
|
|
12
12
|
}
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
catch (error) {
|
|
22
|
-
console.warn('Invalid JSON in report body while checking pullRequestRequired:', error);
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
if (typeof reportJson !== 'object' || reportJson === null) {
|
|
26
|
-
return false;
|
|
13
|
+
for (const block of (0, extractFencedJsonBlocks_1.extractFencedJsonBlocks)(lastComment.content, 'pullRequestRequired')) {
|
|
14
|
+
if (typeof block !== 'object' || block === null) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const report = { ...block };
|
|
18
|
+
if (report.pullRequestRequired === false) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
27
21
|
}
|
|
28
|
-
|
|
29
|
-
return report.pullRequestRequired === false;
|
|
22
|
+
return false;
|
|
30
23
|
};
|
|
31
24
|
exports.isPullRequestDeclaredUnnecessary = isPullRequestDeclaredUnnecessary;
|
|
32
25
|
//# sourceMappingURL=isPullRequestDeclaredUnnecessary.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isPullRequestDeclaredUnnecessary.js","sourceRoot":"","sources":["../../../src/domain/usecases/isPullRequestDeclaredUnnecessary.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"isPullRequestDeclaredUnnecessary.js","sourceRoot":"","sources":["../../../src/domain/usecases/isPullRequestDeclaredUnnecessary.ts"],"names":[],"mappings":";;;AAAA,uEAAoE;AACpE,2DAAwD;AAEjD,MAAM,gCAAgC,GAAG,CAC9C,QAA+C,EAC/C,eAA4C,EACnC,EAAE;IACX,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,IACE,CAAC,WAAW;QACZ,CAAC,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC;QACpC,CAAC,IAAA,qCAAiB,EAAC,WAAW,CAAC,OAAO,CAAC,EACvC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,IAAA,iDAAuB,EACzC,WAAW,CAAC,OAAO,EACnB,qBAAqB,CACtB,EAAE,CAAC;QACF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAChD,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAA4B,EAAE,GAAG,KAAK,EAAE,CAAC;QACrD,IAAI,MAAM,CAAC,mBAAmB,KAAK,KAAK,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAzBW,QAAA,gCAAgC,oCAyB3C"}
|
package/package.json
CHANGED
|
@@ -112,7 +112,7 @@ test('renders the Workflow Blocker tab leftmost and shows its detail operations'
|
|
|
112
112
|
).click();
|
|
113
113
|
|
|
114
114
|
await expect(
|
|
115
|
-
page.locator('.console-op-button', { hasText:
|
|
115
|
+
page.locator('.console-op-button', { hasText: /^Awaiting Workspace$/ }),
|
|
116
116
|
).toBeVisible();
|
|
117
117
|
await expect(
|
|
118
118
|
page.locator('.console-op-button', { hasText: 'Close as not planned' }),
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { consoleStatusOptionsFixture } from '../../testing/fixtures';
|
|
3
|
+
import { ConsoleOkAndAwaitingWorkspaceActions } from './ConsoleOkAndAwaitingWorkspaceActions';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof ConsoleOkAndAwaitingWorkspaceActions> = {
|
|
6
|
+
title: 'Console/ConsoleOkAndAwaitingWorkspaceActions',
|
|
7
|
+
component: ConsoleOkAndAwaitingWorkspaceActions,
|
|
8
|
+
args: { onOkAndAwaitingWorkspace: () => {} },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
|
|
13
|
+
type Story = StoryObj<typeof ConsoleOkAndAwaitingWorkspaceActions>;
|
|
14
|
+
|
|
15
|
+
export const WithAwaitingWorkspaceOption: Story = {
|
|
16
|
+
args: { statusOptions: consoleStatusOptionsFixture },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const WithoutAwaitingWorkspaceOption: Story = {
|
|
20
|
+
args: {
|
|
21
|
+
statusOptions: consoleStatusOptionsFixture.filter(
|
|
22
|
+
(o) => o.name.toLowerCase() !== 'awaiting workspace',
|
|
23
|
+
),
|
|
24
|
+
},
|
|
25
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { fireEvent, render } from '@testing-library/react';
|
|
2
|
+
import { consoleStatusOptionsFixture } from '../../testing/fixtures';
|
|
3
|
+
import { ConsoleOkAndAwaitingWorkspaceActions } from './ConsoleOkAndAwaitingWorkspaceActions';
|
|
4
|
+
|
|
5
|
+
const [awaitingWorkspaceOption] = consoleStatusOptionsFixture.filter(
|
|
6
|
+
(o) => o.name.toLowerCase() === 'awaiting workspace',
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
const statusOptionsWithoutAwaitingWorkspace =
|
|
10
|
+
consoleStatusOptionsFixture.filter(
|
|
11
|
+
(o) => o.name.toLowerCase() !== 'awaiting workspace',
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
describe('ConsoleOkAndAwaitingWorkspaceActions', () => {
|
|
15
|
+
it('renders the button when the awaiting workspace option is present', () => {
|
|
16
|
+
const { getByRole } = render(
|
|
17
|
+
<ConsoleOkAndAwaitingWorkspaceActions
|
|
18
|
+
statusOptions={consoleStatusOptionsFixture}
|
|
19
|
+
onOkAndAwaitingWorkspace={() => {}}
|
|
20
|
+
/>,
|
|
21
|
+
);
|
|
22
|
+
expect(
|
|
23
|
+
getByRole('button', { name: 'ok & Awaiting Workspace' }),
|
|
24
|
+
).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns null when the awaiting workspace option is absent', () => {
|
|
28
|
+
const { container } = render(
|
|
29
|
+
<ConsoleOkAndAwaitingWorkspaceActions
|
|
30
|
+
statusOptions={statusOptionsWithoutAwaitingWorkspace}
|
|
31
|
+
onOkAndAwaitingWorkspace={() => {}}
|
|
32
|
+
/>,
|
|
33
|
+
);
|
|
34
|
+
expect(container.firstChild).toBeNull();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('calls the callback with the awaiting workspace option on click', () => {
|
|
38
|
+
const onOkAndAwaitingWorkspace = jest.fn();
|
|
39
|
+
const { getByRole } = render(
|
|
40
|
+
<ConsoleOkAndAwaitingWorkspaceActions
|
|
41
|
+
statusOptions={consoleStatusOptionsFixture}
|
|
42
|
+
onOkAndAwaitingWorkspace={onOkAndAwaitingWorkspace}
|
|
43
|
+
/>,
|
|
44
|
+
);
|
|
45
|
+
fireEvent.click(getByRole('button', { name: 'ok & Awaiting Workspace' }));
|
|
46
|
+
expect(onOkAndAwaitingWorkspace).toHaveBeenCalledWith(
|
|
47
|
+
awaitingWorkspaceOption,
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { colorFromEnum } from '../../logic/colors';
|
|
2
|
+
import type { ConsoleFieldOption } from '../../logic/types';
|
|
3
|
+
|
|
4
|
+
export type ConsoleOkAndAwaitingWorkspaceActionsProps = {
|
|
5
|
+
statusOptions: ConsoleFieldOption[];
|
|
6
|
+
onOkAndAwaitingWorkspace: (option: ConsoleFieldOption) => void;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const AWAITING_WORKSPACE_NAME = 'awaiting workspace';
|
|
10
|
+
|
|
11
|
+
export const ConsoleOkAndAwaitingWorkspaceActions = ({
|
|
12
|
+
statusOptions,
|
|
13
|
+
onOkAndAwaitingWorkspace,
|
|
14
|
+
}: ConsoleOkAndAwaitingWorkspaceActionsProps) => {
|
|
15
|
+
const option = statusOptions.find(
|
|
16
|
+
(o) => o.name.toLowerCase() === AWAITING_WORKSPACE_NAME,
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
if (option === undefined) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const palette = colorFromEnum(option.color);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className="console-op-group">
|
|
27
|
+
<button
|
|
28
|
+
type="button"
|
|
29
|
+
className="console-op-button"
|
|
30
|
+
style={{
|
|
31
|
+
color: palette.fg,
|
|
32
|
+
borderColor: palette.border,
|
|
33
|
+
backgroundColor: palette.bg,
|
|
34
|
+
}}
|
|
35
|
+
onClick={() => onOkAndAwaitingWorkspace(option)}
|
|
36
|
+
>
|
|
37
|
+
ok & Awaiting Workspace
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
} from '../../logic/types';
|
|
10
10
|
import { ConsoleCloseActions } from './ConsoleCloseActions';
|
|
11
11
|
import { ConsoleNextActionDateActions } from './ConsoleNextActionDateActions';
|
|
12
|
+
import { ConsoleOkAndAwaitingWorkspaceActions } from './ConsoleOkAndAwaitingWorkspaceActions';
|
|
12
13
|
import { ConsolePullRequestReviewActions } from './ConsolePullRequestReviewActions';
|
|
13
14
|
import { ConsoleStatusActions } from './ConsoleStatusActions';
|
|
14
15
|
import { ConsoleStoryActions } from './ConsoleStoryActions';
|
|
@@ -34,6 +35,10 @@ export const ConsoleOperationMenu = ({
|
|
|
34
35
|
const showStory = tab === 'triage';
|
|
35
36
|
return (
|
|
36
37
|
<div className="console-operation-bar">
|
|
38
|
+
<ConsoleOkAndAwaitingWorkspaceActions
|
|
39
|
+
statusOptions={statusOptions}
|
|
40
|
+
onOkAndAwaitingWorkspace={handlers.onOkAndAwaitingWorkspace}
|
|
41
|
+
/>
|
|
37
42
|
{hasPullRequest && (
|
|
38
43
|
<ConsolePullRequestReviewActions
|
|
39
44
|
onReview={handlers.onReview}
|
package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts
CHANGED
|
@@ -415,4 +415,74 @@ describe('useConsoleOperations', () => {
|
|
|
415
415
|
).rejects.toThrow('No project specified in the URL path.');
|
|
416
416
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
417
417
|
});
|
|
418
|
+
|
|
419
|
+
it('posts an ok comment then sets status to awaiting workspace in order', async () => {
|
|
420
|
+
let callCount = 0;
|
|
421
|
+
const calls: Array<[string, unknown]> = [];
|
|
422
|
+
global.fetch = jest.fn(async (url: unknown, opts: unknown) => {
|
|
423
|
+
calls.push([url as string, opts]);
|
|
424
|
+
callCount += 1;
|
|
425
|
+
if (callCount === 1) {
|
|
426
|
+
return {
|
|
427
|
+
ok: true,
|
|
428
|
+
status: 200,
|
|
429
|
+
json: async () => ({
|
|
430
|
+
comment: {
|
|
431
|
+
author: 'bot',
|
|
432
|
+
body: 'ok',
|
|
433
|
+
createdAt: '2026-01-01T00:00:00Z',
|
|
434
|
+
},
|
|
435
|
+
}),
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
return { ok: true, status: 200, json: async () => ({ ok: true }) };
|
|
439
|
+
}) as unknown as typeof fetch;
|
|
440
|
+
const { result } = setup();
|
|
441
|
+
const [option] = consoleStatusOptionsFixture.filter(
|
|
442
|
+
(o) => o.name.toLowerCase() === 'awaiting workspace',
|
|
443
|
+
);
|
|
444
|
+
await act(async () => {
|
|
445
|
+
await result.current.operations.okAndMoveToAwaitingWorkspace(
|
|
446
|
+
issueItem,
|
|
447
|
+
option,
|
|
448
|
+
);
|
|
449
|
+
});
|
|
450
|
+
expect(calls[0][0]).toBe('/api/comment');
|
|
451
|
+
expect(JSON.parse((calls[0][1] as { body: string }).body)).toMatchObject({
|
|
452
|
+
pjcode: 'acme',
|
|
453
|
+
url: issueItem.url,
|
|
454
|
+
body: 'ok',
|
|
455
|
+
});
|
|
456
|
+
expect(calls[1][0]).toBe('/api/triage');
|
|
457
|
+
expect(JSON.parse((calls[1][1] as { body: string }).body)).toMatchObject({
|
|
458
|
+
pjcode: 'acme',
|
|
459
|
+
action: 'set_status',
|
|
460
|
+
issueUrl: issueItem.url,
|
|
461
|
+
statusName: option.name,
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
it('does not call the status endpoint when the comment post fails', async () => {
|
|
466
|
+
let callCount = 0;
|
|
467
|
+
global.fetch = jest.fn(async () => {
|
|
468
|
+
callCount += 1;
|
|
469
|
+
if (callCount === 1) {
|
|
470
|
+
return { ok: false, status: 500, text: async () => 'error' };
|
|
471
|
+
}
|
|
472
|
+
return { ok: true, status: 200, json: async () => ({ ok: true }) };
|
|
473
|
+
}) as unknown as typeof fetch;
|
|
474
|
+
const { result } = setup();
|
|
475
|
+
const [option] = consoleStatusOptionsFixture.filter(
|
|
476
|
+
(o) => o.name.toLowerCase() === 'awaiting workspace',
|
|
477
|
+
);
|
|
478
|
+
await expect(
|
|
479
|
+
act(async () => {
|
|
480
|
+
await result.current.operations.okAndMoveToAwaitingWorkspace(
|
|
481
|
+
issueItem,
|
|
482
|
+
option,
|
|
483
|
+
);
|
|
484
|
+
}),
|
|
485
|
+
).rejects.toThrow();
|
|
486
|
+
expect(callCount).toBe(1);
|
|
487
|
+
});
|
|
418
488
|
});
|
package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts
CHANGED
|
@@ -61,6 +61,10 @@ export type ConsoleOperationsApi = {
|
|
|
61
61
|
item: ConsoleListItem,
|
|
62
62
|
action: ConsoleCloseAction,
|
|
63
63
|
) => Promise<void>;
|
|
64
|
+
okAndMoveToAwaitingWorkspace: (
|
|
65
|
+
item: ConsoleListItem,
|
|
66
|
+
option: ConsoleFieldOption,
|
|
67
|
+
) => Promise<void>;
|
|
64
68
|
addComment: (item: ConsoleListItem, body: string) => Promise<ConsoleComment>;
|
|
65
69
|
uploadAttachment: (item: ConsoleListItem, file: File) => Promise<string>;
|
|
66
70
|
addInlineReviewComment: (
|
|
@@ -276,6 +280,30 @@ export const useConsoleOperations = (
|
|
|
276
280
|
[pjcode, markDone],
|
|
277
281
|
);
|
|
278
282
|
|
|
283
|
+
const okAndMoveToAwaitingWorkspace = useCallback(
|
|
284
|
+
async (item: ConsoleListItem, option: ConsoleFieldOption) => {
|
|
285
|
+
if (pjcode === null) {
|
|
286
|
+
throw missingPjcodeError();
|
|
287
|
+
}
|
|
288
|
+
await postConsoleComment({ pjcode, url: item.url, body: 'ok' });
|
|
289
|
+
const request: ConsoleTriageRequest = {
|
|
290
|
+
pjcode,
|
|
291
|
+
action: 'set_status',
|
|
292
|
+
issueUrl: item.url,
|
|
293
|
+
projectItemId: item.projectItemId,
|
|
294
|
+
statusName: option.name,
|
|
295
|
+
};
|
|
296
|
+
await postConsoleOperation(TRIAGE_OPERATION_PATH, request);
|
|
297
|
+
invalidateItemContent(item);
|
|
298
|
+
patchOverlay(
|
|
299
|
+
overlayKeyForItem(item),
|
|
300
|
+
{ done: true, status: { name: option.name, color: option.color } },
|
|
301
|
+
mode,
|
|
302
|
+
);
|
|
303
|
+
},
|
|
304
|
+
[pjcode, invalidateItemContent, patchOverlay, mode],
|
|
305
|
+
);
|
|
306
|
+
|
|
279
307
|
const addComment = useCallback(
|
|
280
308
|
async (item: ConsoleListItem, body: string) => {
|
|
281
309
|
if (pjcode === null) {
|
|
@@ -340,6 +368,7 @@ export const useConsoleOperations = (
|
|
|
340
368
|
setStatus,
|
|
341
369
|
setInTmuxByHuman,
|
|
342
370
|
closeIssue,
|
|
371
|
+
okAndMoveToAwaitingWorkspace,
|
|
343
372
|
addComment,
|
|
344
373
|
uploadAttachment,
|
|
345
374
|
addInlineReviewComment,
|
|
@@ -127,6 +127,17 @@ describe('actionToastColor', () => {
|
|
|
127
127
|
actionToastColor({ type: 'next_action_date', action: 'snooze_1day' }),
|
|
128
128
|
).toBe('amber');
|
|
129
129
|
expect(actionToastColor({ type: 'close', action: 'close' })).toBe('red');
|
|
130
|
+
expect(actionToastColor({ type: 'ok_and_awaiting_workspace' })).toBe(
|
|
131
|
+
'blue',
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('actionToastMessage for ok_and_awaiting_workspace', () => {
|
|
137
|
+
it('returns the composite label', () => {
|
|
138
|
+
expect(
|
|
139
|
+
actionToastMessage({ type: 'ok_and_awaiting_workspace' }, 'prs'),
|
|
140
|
+
).toBe('ok → Awaiting Workspace');
|
|
130
141
|
});
|
|
131
142
|
});
|
|
132
143
|
|
|
@@ -138,6 +149,9 @@ describe('actionAdvances', () => {
|
|
|
138
149
|
expect(actionAdvances({ type: 'set_status', optionName: 'x' }, 'prs')).toBe(
|
|
139
150
|
true,
|
|
140
151
|
);
|
|
152
|
+
expect(actionAdvances({ type: 'ok_and_awaiting_workspace' }, 'prs')).toBe(
|
|
153
|
+
true,
|
|
154
|
+
);
|
|
141
155
|
});
|
|
142
156
|
|
|
143
157
|
it('does not advance a snooze except on the manual triage tabs', () => {
|
|
@@ -20,7 +20,8 @@ export type ConsoleActionKind =
|
|
|
20
20
|
| { type: 'set_story'; optionName: string }
|
|
21
21
|
| { type: 'set_status'; optionName: string }
|
|
22
22
|
| { type: 'set_in_tmux_by_human'; optionName: string }
|
|
23
|
-
| { type: 'close'; action: ConsoleCloseAction }
|
|
23
|
+
| { type: 'close'; action: ConsoleCloseAction }
|
|
24
|
+
| { type: 'ok_and_awaiting_workspace' };
|
|
24
25
|
|
|
25
26
|
export const ACTION_TOAST_DELAY_MS = 5000;
|
|
26
27
|
|
|
@@ -56,6 +57,8 @@ export const actionToastMessage = (
|
|
|
56
57
|
return `Status → ${kind.optionName}`;
|
|
57
58
|
case 'set_in_tmux_by_human':
|
|
58
59
|
return 'Added to In Tmux by human';
|
|
60
|
+
case 'ok_and_awaiting_workspace':
|
|
61
|
+
return 'ok → Awaiting Workspace';
|
|
59
62
|
case 'close':
|
|
60
63
|
return kind.action === 'close' ? 'Closed' : 'Closed as not planned';
|
|
61
64
|
}
|
|
@@ -81,6 +84,7 @@ export const actionToastColor = (
|
|
|
81
84
|
case 'set_story':
|
|
82
85
|
case 'set_status':
|
|
83
86
|
case 'set_in_tmux_by_human':
|
|
87
|
+
case 'ok_and_awaiting_workspace':
|
|
84
88
|
return 'blue';
|
|
85
89
|
case 'close':
|
|
86
90
|
return 'red';
|
|
@@ -38,6 +38,7 @@ export type ConsoleOperationHandlers = {
|
|
|
38
38
|
onSetStatus: (option: ConsoleFieldOption) => void;
|
|
39
39
|
onSetInTmuxByHuman: (option: ConsoleFieldOption) => void;
|
|
40
40
|
onClose: (action: ConsoleCloseAction) => void;
|
|
41
|
+
onOkAndAwaitingWorkspace: (option: ConsoleFieldOption) => void;
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
export const STATUS_BUTTON_NAMES: string[] = [
|
|
@@ -74,6 +74,7 @@ const buildOperations = (): ConsoleOperationsApi => ({
|
|
|
74
74
|
setStatus: jest.fn(async () => {}),
|
|
75
75
|
setInTmuxByHuman: jest.fn(async () => {}),
|
|
76
76
|
closeIssue: jest.fn(async () => {}),
|
|
77
|
+
okAndMoveToAwaitingWorkspace: jest.fn(async () => {}),
|
|
77
78
|
addComment: jest.fn(async () => ({
|
|
78
79
|
author: 'HiromiShikata',
|
|
79
80
|
body: 'comment body',
|
|
@@ -150,6 +150,13 @@ export const ConsoleItemDetailContainer = ({
|
|
|
150
150
|
commit: () => operations.closeIssue(item, action),
|
|
151
151
|
});
|
|
152
152
|
},
|
|
153
|
+
onOkAndAwaitingWorkspace: (option: ConsoleFieldOption) => {
|
|
154
|
+
onQueueAction({
|
|
155
|
+
kind: { type: 'ok_and_awaiting_workspace' },
|
|
156
|
+
item,
|
|
157
|
+
commit: () => operations.okAndMoveToAwaitingWorkspace(item, option),
|
|
158
|
+
});
|
|
159
|
+
},
|
|
153
160
|
};
|
|
154
161
|
|
|
155
162
|
const resolvedStoryName =
|