github-issue-tower-defence-management 1.86.0 → 1.88.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/.eslintrc.cjs +5 -1
- package/.github/workflows/console-ui.yml +47 -0
- package/.prettierignore +3 -0
- package/CHANGELOG.md +15 -0
- package/README.md +42 -0
- package/bin/adapter/entry-points/console/ui-dist/assets/index-DFxrSRH4.css +1 -0
- package/bin/adapter/entry-points/console/ui-dist/assets/index-DcOZ02ON.js +49 -0
- package/bin/adapter/entry-points/console/ui-dist/index.html +13 -0
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +54 -12
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/inTmuxByHumanDataWriter.js +67 -0
- package/bin/adapter/entry-points/handlers/inTmuxByHumanDataWriter.js.map +1 -0
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +306 -0
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
- package/bin/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.js +91 -0
- package/bin/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.js.map +1 -0
- package/package.json +22 -2
- package/scripts/copyConsoleUiDist.mjs +35 -0
- package/src/adapter/entry-points/console/ui/.storybook/main.ts +12 -0
- package/src/adapter/entry-points/console/ui/.storybook/preview.ts +15 -0
- package/src/adapter/entry-points/console/ui/biome.json +47 -0
- package/src/adapter/entry-points/console/ui/components.json +20 -0
- package/src/adapter/entry-points/console/ui/index.html +12 -0
- package/src/adapter/entry-points/console/ui/src/components/ui/badge.stories.tsx +35 -0
- package/src/adapter/entry-points/console/ui/src/components/ui/badge.tsx +28 -0
- package/src/adapter/entry-points/console/ui/src/components/ui/button.stories.tsx +34 -0
- package/src/adapter/entry-points/console/ui/src/components/ui/button.tsx +50 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/ConsoleListView.stories.tsx +44 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/ConsoleListView.tsx +58 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/ConsoleTabBar.stories.tsx +34 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/ConsoleTabBar.tsx +32 -0
- package/src/adapter/entry-points/console/ui/src/features/console/fixtures.ts +47 -0
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleList.ts +65 -0
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleToken.ts +64 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +19 -0
- package/src/adapter/entry-points/console/ui/src/features/console/types.ts +69 -0
- package/src/adapter/entry-points/console/ui/src/index.css +31 -0
- package/src/adapter/entry-points/console/ui/src/lib/utils.ts +4 -0
- package/src/adapter/entry-points/console/ui/src/main.tsx +15 -0
- package/src/adapter/entry-points/console/ui/src/vite-env.d.ts +1 -0
- package/src/adapter/entry-points/console/ui/tsconfig.json +24 -0
- package/src/adapter/entry-points/console/ui/vite.config.ts +19 -0
- package/src/adapter/entry-points/console/ui-dist/assets/index-DFxrSRH4.css +1 -0
- package/src/adapter/entry-points/console/ui-dist/assets/index-DcOZ02ON.js +49 -0
- package/src/adapter/entry-points/console/ui-dist/index.html +13 -0
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +26 -0
- package/src/adapter/entry-points/handlers/inTmuxByHumanDataWriter.test.ts +266 -0
- package/src/adapter/entry-points/handlers/inTmuxByHumanDataWriter.ts +103 -0
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +630 -0
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +492 -0
- package/src/domain/usecases/adapter-interfaces/IssueRepository.ts +51 -0
- package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.test.ts +285 -0
- package/src/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.ts +182 -0
- package/tsconfig.build.json +7 -1
- package/tsconfig.json +6 -1
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/inTmuxByHumanDataWriter.d.ts +16 -0
- package/types/adapter/entry-points/handlers/inTmuxByHumanDataWriter.d.ts.map +1 -0
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts +18 -1
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
- package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts +47 -0
- package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts.map +1 -1
- package/types/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.d.ts +57 -0
- package/types/domain/usecases/intmux/GenerateInTmuxByHumanDataUseCase.d.ts.map +1 -0
package/src/adapter/entry-points/console/ui/src/features/console/components/ConsoleListView.tsx
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Badge } from '@/components/ui/badge';
|
|
2
|
+
import type { ConsoleListItem } from '../types';
|
|
3
|
+
|
|
4
|
+
export type ConsoleListViewProps = {
|
|
5
|
+
items: ConsoleListItem[];
|
|
6
|
+
isLoading: boolean;
|
|
7
|
+
error: string | null;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const ConsoleListView = ({
|
|
11
|
+
items,
|
|
12
|
+
isLoading,
|
|
13
|
+
error,
|
|
14
|
+
}: ConsoleListViewProps) => {
|
|
15
|
+
if (error !== null) {
|
|
16
|
+
return (
|
|
17
|
+
<p role="alert" className="p-4 text-sm text-destructive">
|
|
18
|
+
Failed to load list: {error}
|
|
19
|
+
</p>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (isLoading) {
|
|
24
|
+
return <p className="p-4 text-sm text-muted-foreground">Loading list...</p>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (items.length === 0) {
|
|
28
|
+
return <p className="p-4 text-sm text-muted-foreground">No items.</p>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<ul className="divide-y divide-border">
|
|
33
|
+
{items.map((item) => (
|
|
34
|
+
<li key={item.itemId} className="flex flex-col gap-1 p-3">
|
|
35
|
+
<div className="flex items-center gap-2">
|
|
36
|
+
<Badge variant={item.isPr ? 'default' : 'secondary'}>
|
|
37
|
+
{item.isPr ? 'PR' : 'Issue'}
|
|
38
|
+
</Badge>
|
|
39
|
+
<a
|
|
40
|
+
href={item.url}
|
|
41
|
+
className="font-medium underline-offset-2 hover:underline"
|
|
42
|
+
>
|
|
43
|
+
{item.title}
|
|
44
|
+
</a>
|
|
45
|
+
<span className="text-sm text-muted-foreground">
|
|
46
|
+
#{item.number}
|
|
47
|
+
</span>
|
|
48
|
+
</div>
|
|
49
|
+
<div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
|
50
|
+
<span>{item.repo}</span>
|
|
51
|
+
{item.story !== '' && <span>story: {item.story}</span>}
|
|
52
|
+
<span>{new Date(item.createdAt).toISOString()}</span>
|
|
53
|
+
</div>
|
|
54
|
+
</li>
|
|
55
|
+
))}
|
|
56
|
+
</ul>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import type { ConsoleTabName } from '../types';
|
|
4
|
+
import { ConsoleTabBar } from './ConsoleTabBar';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof ConsoleTabBar> = {
|
|
7
|
+
title: 'Console/ConsoleTabBar',
|
|
8
|
+
component: ConsoleTabBar,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
|
|
13
|
+
type Story = StoryObj<typeof ConsoleTabBar>;
|
|
14
|
+
|
|
15
|
+
export const PrsActive: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
activeTab: 'prs',
|
|
18
|
+
onSelectTab: () => undefined,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const TriageActive: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
activeTab: 'triage',
|
|
25
|
+
onSelectTab: () => undefined,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const Interactive: Story = {
|
|
30
|
+
render: () => {
|
|
31
|
+
const [activeTab, setActiveTab] = useState<ConsoleTabName>('prs');
|
|
32
|
+
return <ConsoleTabBar activeTab={activeTab} onSelectTab={setActiveTab} />;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Button } from '@/components/ui/button';
|
|
2
|
+
import { cn } from '@/lib/utils';
|
|
3
|
+
import { CONSOLE_TABS, type ConsoleTabName } from '../types';
|
|
4
|
+
|
|
5
|
+
export type ConsoleTabBarProps = {
|
|
6
|
+
activeTab: ConsoleTabName;
|
|
7
|
+
onSelectTab: (tab: ConsoleTabName) => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const ConsoleTabBar = ({
|
|
11
|
+
activeTab,
|
|
12
|
+
onSelectTab,
|
|
13
|
+
}: ConsoleTabBarProps) => (
|
|
14
|
+
<nav
|
|
15
|
+
aria-label="Console tabs"
|
|
16
|
+
className="flex flex-wrap gap-1 border-b border-border p-2"
|
|
17
|
+
>
|
|
18
|
+
{CONSOLE_TABS.map((tab) => (
|
|
19
|
+
<Button
|
|
20
|
+
key={tab.name}
|
|
21
|
+
type="button"
|
|
22
|
+
size="sm"
|
|
23
|
+
variant={tab.name === activeTab ? 'default' : 'ghost'}
|
|
24
|
+
aria-current={tab.name === activeTab ? 'page' : undefined}
|
|
25
|
+
className={cn(tab.name === activeTab && 'font-semibold')}
|
|
26
|
+
onClick={() => onSelectTab(tab.name)}
|
|
27
|
+
>
|
|
28
|
+
{tab.label}
|
|
29
|
+
</Button>
|
|
30
|
+
))}
|
|
31
|
+
</nav>
|
|
32
|
+
);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ConsoleListItem } from './types';
|
|
2
|
+
|
|
3
|
+
export const consoleListItemsFixture: ConsoleListItem[] = [
|
|
4
|
+
{
|
|
5
|
+
number: 844,
|
|
6
|
+
title: 'Add serveConsole server skeleton under entry-points',
|
|
7
|
+
url: 'https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/pull/851',
|
|
8
|
+
repo: 'HiromiShikata/npm-cli-github-issue-tower-defence-management',
|
|
9
|
+
nameWithOwner:
|
|
10
|
+
'HiromiShikata/npm-cli-github-issue-tower-defence-management',
|
|
11
|
+
projectItemId: 'PVTI_lADOABCD1234zgABCD01',
|
|
12
|
+
itemId: 'PVTI_lADOABCD1234zgABCD01',
|
|
13
|
+
isPr: true,
|
|
14
|
+
story: 'TDPM Console port',
|
|
15
|
+
labels: ['claude'],
|
|
16
|
+
createdAt: '2026-06-17T02:14:33.000Z',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
number: 845,
|
|
20
|
+
title:
|
|
21
|
+
'Scaffold React console UI under entry-points with build bundling and minimal tab view',
|
|
22
|
+
url: 'https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/845',
|
|
23
|
+
repo: 'HiromiShikata/npm-cli-github-issue-tower-defence-management',
|
|
24
|
+
nameWithOwner:
|
|
25
|
+
'HiromiShikata/npm-cli-github-issue-tower-defence-management',
|
|
26
|
+
projectItemId: 'PVTI_lADOABCD1234zgABCD02',
|
|
27
|
+
itemId: 'PVTI_lADOABCD1234zgABCD02',
|
|
28
|
+
isPr: false,
|
|
29
|
+
story: 'TDPM Console port',
|
|
30
|
+
labels: ['claude'],
|
|
31
|
+
createdAt: '2026-06-17T05:48:09.000Z',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
number: 778,
|
|
35
|
+
title: 'Add Sonnet to Opus weekly-limit fallback routing per token',
|
|
36
|
+
url: 'https://github.com/HiromiShikata/npm-cli-github-issue-tower-defence-management/issues/778',
|
|
37
|
+
repo: 'HiromiShikata/npm-cli-github-issue-tower-defence-management',
|
|
38
|
+
nameWithOwner:
|
|
39
|
+
'HiromiShikata/npm-cli-github-issue-tower-defence-management',
|
|
40
|
+
projectItemId: 'PVTI_lADOABCD1234zgABCD03',
|
|
41
|
+
itemId: 'PVTI_lADOABCD1234zgABCD03',
|
|
42
|
+
isPr: false,
|
|
43
|
+
story: 'regular / workflow improvement',
|
|
44
|
+
labels: [],
|
|
45
|
+
createdAt: '2026-06-12T23:01:55.000Z',
|
|
46
|
+
},
|
|
47
|
+
];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import type { ConsoleListItem, ConsoleTabName } from '../types';
|
|
3
|
+
import { useConsoleToken } from './useConsoleToken';
|
|
4
|
+
|
|
5
|
+
const buildListUrl = (tab: ConsoleTabName): string => `./${tab}/list.json`;
|
|
6
|
+
|
|
7
|
+
const extractItems = (payload: unknown): ConsoleListItem[] => {
|
|
8
|
+
if (
|
|
9
|
+
payload !== null &&
|
|
10
|
+
typeof payload === 'object' &&
|
|
11
|
+
'items' in payload &&
|
|
12
|
+
Array.isArray((payload as { items: unknown }).items)
|
|
13
|
+
) {
|
|
14
|
+
return (payload as { items: ConsoleListItem[] }).items;
|
|
15
|
+
}
|
|
16
|
+
return [];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type ConsoleListState = {
|
|
20
|
+
items: ConsoleListItem[];
|
|
21
|
+
isLoading: boolean;
|
|
22
|
+
error: string | null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const useConsoleList = (tab: ConsoleTabName): ConsoleListState => {
|
|
26
|
+
const { appendToken } = useConsoleToken();
|
|
27
|
+
const [items, setItems] = useState<ConsoleListItem[]>([]);
|
|
28
|
+
const [isLoading, setIsLoading] = useState<boolean>(true);
|
|
29
|
+
const [error, setError] = useState<string | null>(null);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
let cancelled = false;
|
|
33
|
+
setIsLoading(true);
|
|
34
|
+
setError(null);
|
|
35
|
+
|
|
36
|
+
const url = appendToken(buildListUrl(tab));
|
|
37
|
+
fetch(url)
|
|
38
|
+
.then(async (response) => {
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new Error(`HTTP ${response.status}`);
|
|
41
|
+
}
|
|
42
|
+
return response.json();
|
|
43
|
+
})
|
|
44
|
+
.then((payload: unknown) => {
|
|
45
|
+
if (cancelled) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
setItems(extractItems(payload));
|
|
49
|
+
setIsLoading(false);
|
|
50
|
+
})
|
|
51
|
+
.catch((cause: unknown) => {
|
|
52
|
+
if (cancelled) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
56
|
+
setIsLoading(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
cancelled = true;
|
|
61
|
+
};
|
|
62
|
+
}, [tab, appendToken]);
|
|
63
|
+
|
|
64
|
+
return { items, isLoading, error };
|
|
65
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
const CONSOLE_TOKEN_STORAGE_KEY = 'tdpm-console-token';
|
|
4
|
+
|
|
5
|
+
const readTokenFromLocation = (search: string): string | null => {
|
|
6
|
+
const params = new URLSearchParams(search);
|
|
7
|
+
const tokenFromQuery = params.get('k');
|
|
8
|
+
if (tokenFromQuery !== null && tokenFromQuery !== '') {
|
|
9
|
+
return tokenFromQuery;
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const readPersistedToken = (): string | null => {
|
|
15
|
+
if (typeof localStorage === 'undefined') {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const persisted = localStorage.getItem(CONSOLE_TOKEN_STORAGE_KEY);
|
|
19
|
+
return persisted !== null && persisted !== '' ? persisted : null;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ConsoleTokenState = {
|
|
23
|
+
token: string | null;
|
|
24
|
+
appendToken: (dataUrl: string) => string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const useConsoleToken = (): ConsoleTokenState => {
|
|
28
|
+
const [token, setToken] = useState<string | null>(() => {
|
|
29
|
+
const search = typeof window === 'undefined' ? '' : window.location.search;
|
|
30
|
+
return readTokenFromLocation(search) ?? readPersistedToken();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (token === null) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (typeof localStorage !== 'undefined') {
|
|
38
|
+
localStorage.setItem(CONSOLE_TOKEN_STORAGE_KEY, token);
|
|
39
|
+
}
|
|
40
|
+
}, [token]);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (typeof window === 'undefined') {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const tokenFromQuery = readTokenFromLocation(window.location.search);
|
|
47
|
+
if (tokenFromQuery !== null) {
|
|
48
|
+
setToken(tokenFromQuery);
|
|
49
|
+
}
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
const appendToken = useCallback(
|
|
53
|
+
(dataUrl: string): string => {
|
|
54
|
+
if (token === null) {
|
|
55
|
+
return dataUrl;
|
|
56
|
+
}
|
|
57
|
+
const separator = dataUrl.includes('?') ? '&' : '?';
|
|
58
|
+
return `${dataUrl}${separator}k=${encodeURIComponent(token)}`;
|
|
59
|
+
},
|
|
60
|
+
[token],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return { token, appendToken };
|
|
64
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { ConsoleListView } from '../components/ConsoleListView';
|
|
3
|
+
import { ConsoleTabBar } from '../components/ConsoleTabBar';
|
|
4
|
+
import { useConsoleList } from '../hooks/useConsoleList';
|
|
5
|
+
import { CONSOLE_TABS, type ConsoleTabName } from '../types';
|
|
6
|
+
|
|
7
|
+
export const ConsolePage = () => {
|
|
8
|
+
const [activeTab, setActiveTab] = useState<ConsoleTabName>(
|
|
9
|
+
CONSOLE_TABS[0].name,
|
|
10
|
+
);
|
|
11
|
+
const { items, isLoading, error } = useConsoleList(activeTab);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<main className="mx-auto flex max-w-3xl flex-col">
|
|
15
|
+
<ConsoleTabBar activeTab={activeTab} onSelectTab={setActiveTab} />
|
|
16
|
+
<ConsoleListView items={items} isLoading={isLoading} error={error} />
|
|
17
|
+
</main>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export type ConsoleColor =
|
|
2
|
+
| 'GRAY'
|
|
3
|
+
| 'BLUE'
|
|
4
|
+
| 'GREEN'
|
|
5
|
+
| 'YELLOW'
|
|
6
|
+
| 'ORANGE'
|
|
7
|
+
| 'RED'
|
|
8
|
+
| 'PINK'
|
|
9
|
+
| 'PURPLE';
|
|
10
|
+
|
|
11
|
+
export type ConsoleListItem = {
|
|
12
|
+
number: number;
|
|
13
|
+
title: string;
|
|
14
|
+
url: string;
|
|
15
|
+
repo: string;
|
|
16
|
+
nameWithOwner: string;
|
|
17
|
+
projectItemId: string;
|
|
18
|
+
itemId: string;
|
|
19
|
+
isPr: boolean;
|
|
20
|
+
story: string;
|
|
21
|
+
labels: string[];
|
|
22
|
+
createdAt: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type ConsoleFieldOption = {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
color: ConsoleColor;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type ConsoleStatusTab = {
|
|
32
|
+
pjcode: string;
|
|
33
|
+
generatedAt: string;
|
|
34
|
+
statusOptions: ConsoleFieldOption[];
|
|
35
|
+
storyOrder: string[];
|
|
36
|
+
storyColors: Record<string, { color: ConsoleColor }>;
|
|
37
|
+
items: ConsoleListItem[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type ConsoleTriageTab = {
|
|
41
|
+
pjcode: string;
|
|
42
|
+
generatedAt: string;
|
|
43
|
+
storyOptions: ConsoleFieldOption[];
|
|
44
|
+
storyOrder: string[];
|
|
45
|
+
storyColors: Record<string, ConsoleColor>;
|
|
46
|
+
items: ConsoleListItem[];
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type ConsoleTabData = ConsoleStatusTab | ConsoleTriageTab;
|
|
50
|
+
|
|
51
|
+
export type ConsoleTabName =
|
|
52
|
+
| 'prs'
|
|
53
|
+
| 'triage'
|
|
54
|
+
| 'unread'
|
|
55
|
+
| 'failed-preparation'
|
|
56
|
+
| 'todo-by-human';
|
|
57
|
+
|
|
58
|
+
export type ConsoleTab = {
|
|
59
|
+
name: ConsoleTabName;
|
|
60
|
+
label: string;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const CONSOLE_TABS: ConsoleTab[] = [
|
|
64
|
+
{ name: 'prs', label: 'Awaiting Quality Check' },
|
|
65
|
+
{ name: 'triage', label: 'Triage' },
|
|
66
|
+
{ name: 'unread', label: 'Unread' },
|
|
67
|
+
{ name: 'failed-preparation', label: 'Failed Preparation' },
|
|
68
|
+
{ name: 'todo-by-human', label: 'Todo By Human' },
|
|
69
|
+
];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
@theme {
|
|
4
|
+
--color-border: hsl(0 0% 89.8%);
|
|
5
|
+
--color-input: hsl(0 0% 89.8%);
|
|
6
|
+
--color-ring: hsl(0 0% 3.9%);
|
|
7
|
+
--color-background: hsl(0 0% 100%);
|
|
8
|
+
--color-foreground: hsl(0 0% 3.9%);
|
|
9
|
+
--color-primary: hsl(0 0% 9%);
|
|
10
|
+
--color-primary-foreground: hsl(0 0% 98%);
|
|
11
|
+
--color-secondary: hsl(0 0% 96.1%);
|
|
12
|
+
--color-secondary-foreground: hsl(0 0% 9%);
|
|
13
|
+
--color-muted: hsl(0 0% 96.1%);
|
|
14
|
+
--color-muted-foreground: hsl(0 0% 45.1%);
|
|
15
|
+
--color-accent: hsl(0 0% 96.1%);
|
|
16
|
+
--color-accent-foreground: hsl(0 0% 9%);
|
|
17
|
+
--color-destructive: hsl(0 84.2% 60.2%);
|
|
18
|
+
--color-destructive-foreground: hsl(0 0% 98%);
|
|
19
|
+
--color-card: hsl(0 0% 100%);
|
|
20
|
+
--color-card-foreground: hsl(0 0% 3.9%);
|
|
21
|
+
--radius: 0.5rem;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
body {
|
|
25
|
+
margin: 0;
|
|
26
|
+
background-color: var(--color-background);
|
|
27
|
+
color: var(--color-foreground);
|
|
28
|
+
font-family:
|
|
29
|
+
ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
|
30
|
+
Roboto, Helvetica, Arial, sans-serif;
|
|
31
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { StrictMode } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { ConsolePage } from '@/features/console/pages/ConsolePage';
|
|
4
|
+
import './index.css';
|
|
5
|
+
|
|
6
|
+
const container = document.getElementById('root');
|
|
7
|
+
if (container === null) {
|
|
8
|
+
throw new Error('Root container #root not found');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
createRoot(container).render(
|
|
12
|
+
<StrictMode>
|
|
13
|
+
<ConsolePage />
|
|
14
|
+
</StrictMode>,
|
|
15
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"verbatimModuleSyntax": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "react-jsx",
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"noUncheckedSideEffectImports": true,
|
|
19
|
+
"paths": {
|
|
20
|
+
"@/*": ["./src/*"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"include": ["src", ".storybook"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
3
|
+
import react from '@vitejs/plugin-react';
|
|
4
|
+
import { defineConfig } from 'vite';
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
root: path.resolve(__dirname),
|
|
8
|
+
base: './',
|
|
9
|
+
plugins: [react(), tailwindcss()],
|
|
10
|
+
resolve: {
|
|
11
|
+
alias: {
|
|
12
|
+
'@': path.resolve(__dirname, 'src'),
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
build: {
|
|
16
|
+
outDir: path.resolve(__dirname, '../ui-dist'),
|
|
17
|
+
emptyOutDir: true,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-outline-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-border:#e5e5e5;--color-input:#e5e5e5;--color-ring:#0a0a0a;--color-background:#fff;--color-foreground:#0a0a0a;--color-primary:#171717;--color-primary-foreground:#fafafa;--color-secondary:#f5f5f5;--color-secondary-foreground:#171717;--color-muted-foreground:#737373;--color-accent:#f5f5f5;--color-accent-foreground:#171717;--color-destructive:#ef4444}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mx-auto{margin-inline:auto}.flex{display:flex}.inline-flex{display:inline-flex}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.max-w-3xl{max-width:var(--container-3xl)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)){border-color:var(--color-border)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-border{border-color:var(--color-border)}.border-input{border-color:var(--color-input)}.border-transparent{border-color:#0000}.bg-background{background-color:var(--color-background)}.bg-primary{background-color:var(--color-primary)}.bg-secondary{background-color:var(--color-secondary)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-2{padding-block:calc(var(--spacing) * 2)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.text-destructive{color:var(--color-destructive)}.text-foreground{color:var(--color-foreground)}.text-muted-foreground{color:var(--color-muted-foreground)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-secondary-foreground{color:var(--color-secondary-foreground)}.underline-offset-2{text-underline-offset:2px}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-primary\/90:hover{background-color:#171717e6}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--color-primary) 90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:#f5f5f5cc}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--color-secondary) 80%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--color-accent-foreground)}.hover\:underline:hover{text-decoration-line:underline}}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:var(--color-ring)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}}body{background-color:var(--color-background);color:var(--color-foreground);margin:0;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
|