github-issue-tower-defence-management 2.16.0 → 2.18.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 (40) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -0
  3. package/bin/adapter/entry-points/cli/fleetConfig.js +30 -4
  4. package/bin/adapter/entry-points/cli/fleetConfig.js.map +1 -1
  5. package/bin/adapter/entry-points/cli/index.js +5 -1
  6. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  7. package/bin/adapter/entry-points/console/ui-dist/assets/{index-DuOimMCC.js → index-CfqusL5j.js} +11 -11
  8. package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
  9. package/bin/adapter/entry-points/console/webServer.js +4 -1
  10. package/bin/adapter/entry-points/console/webServer.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/adapter/entry-points/cli/fleetConfig.test.ts +63 -0
  13. package/src/adapter/entry-points/cli/fleetConfig.ts +38 -5
  14. package/src/adapter/entry-points/cli/index.ts +13 -1
  15. package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +66 -0
  16. package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +4 -1
  17. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.stories.tsx +8 -0
  18. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.test.tsx +81 -2
  19. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleCommentComposer.tsx +12 -0
  20. package/src/adapter/entry-points/console/ui/src/features/console/components/layout/ConsoleTabList.stories.tsx +26 -0
  21. package/src/adapter/entry-points/console/ui/src/features/console/components/layout/ConsoleTabList.test.tsx +39 -0
  22. package/src/adapter/entry-points/console/ui/src/features/console/components/layout/ConsoleTabList.tsx +13 -0
  23. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.tsx +0 -5
  24. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleProjectList.test.ts +24 -1
  25. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleProjectList.ts +7 -3
  26. package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +17 -8
  27. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +5 -0
  28. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +6 -1
  29. package/src/adapter/entry-points/console/ui-dist/assets/{index-DuOimMCC.js → index-CfqusL5j.js} +11 -11
  30. package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
  31. package/src/adapter/entry-points/console/webServer.test.ts +34 -1
  32. package/src/adapter/entry-points/console/webServer.ts +6 -1
  33. package/types/adapter/entry-points/cli/fleetConfig.d.ts +3 -1
  34. package/types/adapter/entry-points/cli/fleetConfig.d.ts.map +1 -1
  35. package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
  36. package/types/adapter/entry-points/console/webServer.d.ts +1 -0
  37. package/types/adapter/entry-points/console/webServer.d.ts.map +1 -1
  38. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOkAndAwaitingWorkspaceActions.stories.tsx +0 -25
  39. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOkAndAwaitingWorkspaceActions.test.tsx +0 -62
  40. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOkAndAwaitingWorkspaceActions.tsx +0 -33
@@ -25,6 +25,7 @@ export type ConsoleTabBarProps = {
25
25
  airplaneModeFailures: string[];
26
26
  onAirplaneModeStartSync: () => void;
27
27
  onAirplaneModeTurnOff: () => void;
28
+ workflowImprovementIssueUrl?: string | null;
28
29
  };
29
30
 
30
31
  export const ConsoleTabList = ({
@@ -45,6 +46,7 @@ export const ConsoleTabList = ({
45
46
  airplaneModeFailures,
46
47
  onAirplaneModeStartSync,
47
48
  onAirplaneModeTurnOff,
49
+ workflowImprovementIssueUrl = null,
48
50
  }: ConsoleTabBarProps) => {
49
51
  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
50
52
  const [dropdownPos, setDropdownPos] = useState<{
@@ -183,6 +185,17 @@ export const ConsoleTabList = ({
183
185
  {settingsButton !== undefined && (
184
186
  <span className="console-tab-settings">{settingsButton}</span>
185
187
  )}
188
+ {workflowImprovementIssueUrl !== null && (
189
+ <a
190
+ href={workflowImprovementIssueUrl}
191
+ target="_blank"
192
+ rel="noreferrer"
193
+ className="console-tab-workflow-improvement-link"
194
+ aria-label="Open workflow improvement issue"
195
+ >
196
+ ⚡
197
+ </a>
198
+ )}
186
199
  {airplaneModeEnabled && (
187
200
  <ConsoleAirplaneModeButton
188
201
  status={airplaneModeStatus}
@@ -9,7 +9,6 @@ import type {
9
9
  } from '../../logic/types';
10
10
  import { ConsoleCloseActions } from './ConsoleCloseActions';
11
11
  import { ConsoleNextActionDateActions } from './ConsoleNextActionDateActions';
12
- import { ConsoleOkAndAwaitingWorkspaceActions } from './ConsoleOkAndAwaitingWorkspaceActions';
13
12
  import { ConsolePullRequestReviewActions } from './ConsolePullRequestReviewActions';
14
13
  import { ConsoleStatusActions } from './ConsoleStatusActions';
15
14
 
@@ -31,10 +30,6 @@ export const ConsoleOperationMenu = ({
31
30
  }: ConsoleOperationBarProps) => {
32
31
  return (
33
32
  <div className="console-operation-bar">
34
- <ConsoleOkAndAwaitingWorkspaceActions
35
- statusOptions={statusOptions}
36
- onOkAndAwaitingWorkspace={handlers.onOkAndAwaitingWorkspace}
37
- />
38
33
  {hasPullRequest && (
39
34
  <ConsolePullRequestReviewActions
40
35
  onReview={handlers.onReview}
@@ -6,7 +6,7 @@ describe('useConsoleProjectList', () => {
6
6
  jest.restoreAllMocks();
7
7
  });
8
8
 
9
- it('starts in loading state with empty pjcodes and no error', () => {
9
+ it('starts in loading state with empty pjcodes, null workflowImprovementIssueUrl and no error', () => {
10
10
  global.fetch = jest.fn(
11
11
  () => new Promise(() => undefined),
12
12
  ) as unknown as typeof fetch;
@@ -14,6 +14,7 @@ describe('useConsoleProjectList', () => {
14
14
  const { result } = renderHook(() => useConsoleProjectList());
15
15
  expect(result.current.isLoading).toBe(true);
16
16
  expect(result.current.pjcodes).toEqual([]);
17
+ expect(result.current.workflowImprovementIssueUrl).toBeNull();
17
18
  expect(result.current.error).toBeNull();
18
19
  });
19
20
 
@@ -29,6 +30,28 @@ describe('useConsoleProjectList', () => {
29
30
  expect(result.current.isLoading).toBe(false);
30
31
  });
31
32
  expect(result.current.pjcodes).toEqual(['acme', 'beta']);
33
+ expect(result.current.workflowImprovementIssueUrl).toBeNull();
34
+ expect(result.current.error).toBeNull();
35
+ });
36
+
37
+ it('populates workflowImprovementIssueUrl when the server returns it', async () => {
38
+ global.fetch = jest.fn(async () => ({
39
+ ok: true,
40
+ status: 200,
41
+ json: async () => ({
42
+ pjcodes: ['acme'],
43
+ workflowImprovementIssueUrl: 'https://github.com/owner/repo/issues/new',
44
+ }),
45
+ })) as unknown as typeof fetch;
46
+
47
+ const { result } = renderHook(() => useConsoleProjectList());
48
+ await waitFor(() => {
49
+ expect(result.current.isLoading).toBe(false);
50
+ });
51
+ expect(result.current.pjcodes).toEqual(['acme']);
52
+ expect(result.current.workflowImprovementIssueUrl).toBe(
53
+ 'https://github.com/owner/repo/issues/new',
54
+ );
32
55
  expect(result.current.error).toBeNull();
33
56
  });
34
57
 
@@ -3,12 +3,15 @@ import { fetchProjectList } from '../lib/consoleApi';
3
3
 
4
4
  export type ConsoleProjectListState = {
5
5
  pjcodes: string[];
6
+ workflowImprovementIssueUrl: string | null;
6
7
  isLoading: boolean;
7
8
  error: Error | null;
8
9
  };
9
10
 
10
11
  export const useConsoleProjectList = (): ConsoleProjectListState => {
11
12
  const [pjcodes, setPjcodes] = useState<string[]>([]);
13
+ const [workflowImprovementIssueUrl, setWorkflowImprovementIssueUrl] =
14
+ useState<string | null>(null);
12
15
  const [isLoading, setIsLoading] = useState(true);
13
16
  const [error, setError] = useState<Error | null>(null);
14
17
 
@@ -18,9 +21,10 @@ export const useConsoleProjectList = (): ConsoleProjectListState => {
18
21
  setError(null);
19
22
 
20
23
  fetchProjectList()
21
- .then((list) => {
24
+ .then((result) => {
22
25
  if (!cancelled) {
23
- setPjcodes(list);
26
+ setPjcodes(result.pjcodes);
27
+ setWorkflowImprovementIssueUrl(result.workflowImprovementIssueUrl);
24
28
  setIsLoading(false);
25
29
  }
26
30
  })
@@ -36,5 +40,5 @@ export const useConsoleProjectList = (): ConsoleProjectListState => {
36
40
  };
37
41
  }, []);
38
42
 
39
- return { pjcodes, isLoading, error };
43
+ return { pjcodes, workflowImprovementIssueUrl, isLoading, error };
40
44
  };
@@ -482,7 +482,12 @@ export const postConsoleReorderStory = async (
482
482
  }
483
483
  };
484
484
 
485
- export const fetchProjectList = async (): Promise<string[]> => {
485
+ export type ProjectListResponse = {
486
+ pjcodes: string[];
487
+ workflowImprovementIssueUrl: string | null;
488
+ };
489
+
490
+ export const fetchProjectList = async (): Promise<ProjectListResponse> => {
486
491
  const response = await fetch('/api/projects');
487
492
  if (!response.ok) {
488
493
  throw new Error(`HTTP ${response.status}`);
@@ -493,13 +498,17 @@ export const fetchProjectList = async (): Promise<string[]> => {
493
498
  typeof payload !== 'object' ||
494
499
  Array.isArray(payload)
495
500
  ) {
496
- return [];
501
+ return { pjcodes: [], workflowImprovementIssueUrl: null };
497
502
  }
498
503
  const record = payload as Record<string, unknown>;
499
- if (!Array.isArray(record.pjcodes)) {
500
- return [];
501
- }
502
- return record.pjcodes.filter(
503
- (entry): entry is string => typeof entry === 'string',
504
- );
504
+ const pjcodes = Array.isArray(record.pjcodes)
505
+ ? record.pjcodes.filter(
506
+ (entry): entry is string => typeof entry === 'string',
507
+ )
508
+ : [];
509
+ const workflowImprovementIssueUrl =
510
+ typeof record.workflowImprovementIssueUrl === 'string'
511
+ ? record.workflowImprovementIssueUrl
512
+ : null;
513
+ return { pjcodes, workflowImprovementIssueUrl };
505
514
  };
@@ -318,6 +318,11 @@ export const ConsoleItemDetailContainer = ({
318
318
  initialDraft={initialCommentDraft}
319
319
  onSubmit={addComment}
320
320
  onDraftChange={onCommentDraftChange}
321
+ onOkAndAwaitingWorkspace={
322
+ awaitingWorkspaceOption !== null
323
+ ? () => handlers.onOkAndAwaitingWorkspace(awaitingWorkspaceOption)
324
+ : undefined
325
+ }
321
326
  onSubmitAndMoveToAwaitingWorkspace={
322
327
  addCommentAndMoveToAwaitingWorkspace
323
328
  }
@@ -101,7 +101,11 @@ export const ConsolePage = () => {
101
101
  toggleDraftTimerMode,
102
102
  changeDraftMinutes,
103
103
  } = useConsoleTimerSettings();
104
- const { pjcodes, isLoading: isLoadingPjcodes } = useConsoleProjectList();
104
+ const {
105
+ pjcodes,
106
+ workflowImprovementIssueUrl,
107
+ isLoading: isLoadingPjcodes,
108
+ } = useConsoleProjectList();
105
109
  const { isTimerExpired } = useConsoleProjectTimer(pjcode);
106
110
  const overlayState = useConsoleOverlay(pjcode ?? OVERLAY_NAMESPACE_FALLBACK);
107
111
 
@@ -664,6 +668,7 @@ export const ConsolePage = () => {
664
668
  airplaneModeFailures={airplaneMode.failures}
665
669
  onAirplaneModeStartSync={airplaneMode.startSync}
666
670
  onAirplaneModeTurnOff={airplaneMode.turnOff}
671
+ workflowImprovementIssueUrl={workflowImprovementIssueUrl}
667
672
  />
668
673
  {activeTab === 'stories' ? (
669
674
  <ConsoleStoryList