@askrjs/cli 0.0.3 → 0.0.4
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/README.md +37 -0
- package/dist/add.d.ts +16 -0
- package/dist/add.js +33 -29
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +0 -2
- package/dist/create.d.ts +5 -0
- package/dist/create.js +104 -26
- package/dist/directory-swap-DWoHtx7C.js +35 -0
- package/dist/discovery-Difb7Y4G.js +0 -2
- package/dist/generate.d.ts +5 -0
- package/dist/generate.js +77 -12
- package/dist/is-direct-execution-Cdlr-ZUl.js +0 -2
- package/dist/openapi.d.ts +25 -0
- package/dist/openapi.js +44 -12
- package/dist/planner-VAj7qlxr.js +0 -2
- package/dist/range-YUs9eimn.js +0 -2
- package/dist/registry-CyrRHRG5.js +0 -2
- package/dist/skills/askr-ssr-ssg/SKILL.md +3 -1
- package/dist/{skills-Bh0mEhIx.js → skills-B7CbWur9.js} +89 -26
- package/dist/skills.d.ts +18 -0
- package/dist/skills.js +1 -1
- package/dist/specification-DXnDOC-0.js +0 -2
- package/dist/ssg-config.d.ts +41 -0
- package/dist/ssg-config.js +1 -0
- package/dist/ssg.d.ts +61 -0
- package/dist/ssg.js +360 -24
- package/dist/templates/full-stack/package.json +1 -1
- package/dist/templates/full-stack/src/server/action-registry.ts +0 -1
- package/dist/templates/full-stack/tsconfig.json +1 -1
- package/dist/templates/spa/package.json +2 -3
- package/dist/templates/spa/src/pages/app/_routes.tsx +2 -0
- package/dist/templates/spa/src/pages/public/_routes.tsx +2 -0
- package/dist/templates/spa/tsconfig.json +2 -1
- package/dist/templates/spa/vitest.config.ts +0 -4
- package/dist/templates/ssg/README.md +1 -1
- package/dist/templates/ssg/package.json +1 -1
- package/dist/templates/ssg/ssg.config.ts +7 -0
- package/dist/templates/ssg/tests/ssg-config.test.ts +2 -0
- package/dist/templates/ssg/tsconfig.json +2 -1
- package/dist/templates/ssg/vitest.config.ts +0 -4
- package/dist/templates/ssr/package.json +2 -2
- package/dist/templates/startkit/package.json +2 -2
- package/dist/templates/startkit/src/lib/mock-data.ts +17 -39
- package/dist/templates/startkit/tsconfig.json +2 -1
- package/dist/update.d.ts +41 -0
- package/dist/update.js +0 -2
- package/dist/writer-D8qe_7ud.js +0 -2
- package/package.json +13 -8
- package/dist/add.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/create.js.map +0 -1
- package/dist/discovery-Difb7Y4G.js.map +0 -1
- package/dist/generate.js.map +0 -1
- package/dist/is-direct-execution-Cdlr-ZUl.js.map +0 -1
- package/dist/openapi.js.map +0 -1
- package/dist/planner-VAj7qlxr.js.map +0 -1
- package/dist/range-YUs9eimn.js.map +0 -1
- package/dist/registry-CyrRHRG5.js.map +0 -1
- package/dist/skills-Bh0mEhIx.js.map +0 -1
- package/dist/specification-DXnDOC-0.js.map +0 -1
- package/dist/ssg.js.map +0 -1
- package/dist/templates/full-stack/src/vite-server.d.ts +0 -5
- package/dist/templates/spa/src/styles.d.ts +0 -1
- package/dist/templates/ssg/src/vite-env.d.ts +0 -5
- package/dist/templates/ssr/src/vite-server.d.ts +0 -7
- package/dist/templates/startkit/src/vite-env.d.ts +0 -5
- package/dist/update.js.map +0 -1
- package/dist/writer-D8qe_7ud.js.map +0 -1
- package/skills/askr-accessibility/SKILL.md +0 -68
- package/skills/askr-accessibility/agents/openai.yaml +0 -4
- package/skills/askr-agent-execution/SKILL.md +0 -85
- package/skills/askr-agent-execution/agents/openai.yaml +0 -4
- package/skills/askr-agent-workflows/SKILL.md +0 -57
- package/skills/askr-agent-workflows/agents/openai.yaml +0 -4
- package/skills/askr-api-integration/SKILL.md +0 -79
- package/skills/askr-api-integration/agents/openai.yaml +0 -4
- package/skills/askr-app-builder/SKILL.md +0 -99
- package/skills/askr-app-builder/agents/openai.yaml +0 -4
- package/skills/askr-auth-access/SKILL.md +0 -74
- package/skills/askr-auth-access/agents/openai.yaml +0 -4
- package/skills/askr-cli-vite/SKILL.md +0 -76
- package/skills/askr-cli-vite/agents/openai.yaml +0 -4
- package/skills/askr-dashboard-charts/SKILL.md +0 -99
- package/skills/askr-dashboard-charts/agents/openai.yaml +0 -4
- package/skills/askr-design-system/SKILL.md +0 -86
- package/skills/askr-design-system/agents/openai.yaml +0 -4
- package/skills/askr-env-config/SKILL.md +0 -74
- package/skills/askr-env-config/agents/openai.yaml +0 -4
- package/skills/askr-error-loading-empty/SKILL.md +0 -89
- package/skills/askr-error-loading-empty/agents/openai.yaml +0 -4
- package/skills/askr-file-upload-artifacts/SKILL.md +0 -77
- package/skills/askr-file-upload-artifacts/agents/openai.yaml +0 -4
- package/skills/askr-forms-tables-crud/SKILL.md +0 -98
- package/skills/askr-forms-tables-crud/agents/openai.yaml +0 -4
- package/skills/askr-mental-model/SKILL.md +0 -109
- package/skills/askr-mental-model/agents/openai.yaml +0 -4
- package/skills/askr-migration-react/SKILL.md +0 -81
- package/skills/askr-migration-react/agents/openai.yaml +0 -4
- package/skills/askr-observability-debugging/SKILL.md +0 -83
- package/skills/askr-observability-debugging/agents/openai.yaml +0 -4
- package/skills/askr-project-structure/SKILL.md +0 -79
- package/skills/askr-project-structure/agents/openai.yaml +0 -4
- package/skills/askr-query-mutation/SKILL.md +0 -115
- package/skills/askr-query-mutation/agents/openai.yaml +0 -4
- package/skills/askr-realtime-streaming/SKILL.md +0 -76
- package/skills/askr-realtime-streaming/agents/openai.yaml +0 -4
- package/skills/askr-resources-data/SKILL.md +0 -100
- package/skills/askr-resources-data/agents/openai.yaml +0 -4
- package/skills/askr-routing-layouts/SKILL.md +0 -107
- package/skills/askr-routing-layouts/agents/openai.yaml +0 -4
- package/skills/askr-runtime-reactivity/SKILL.md +0 -92
- package/skills/askr-runtime-reactivity/agents/openai.yaml +0 -4
- package/skills/askr-ssr-ssg/SKILL.md +0 -76
- package/skills/askr-ssr-ssg/agents/openai.yaml +0 -4
- package/skills/askr-testing-determinism/SKILL.md +0 -75
- package/skills/askr-testing-determinism/agents/openai.yaml +0 -4
- package/skills/askr-theming/SKILL.md +0 -86
- package/skills/askr-theming/agents/openai.yaml +0 -4
- package/skills/askr-ui-composition/SKILL.md +0 -92
- package/skills/askr-ui-composition/agents/openai.yaml +0 -4
- package/templates/full-stack/AGENTS.md +0 -11
- package/templates/full-stack/README.md +0 -17
- package/templates/full-stack/gitignore.template +0 -4
- package/templates/full-stack/index.html +0 -13
- package/templates/full-stack/package.json +0 -39
- package/templates/full-stack/server.ts +0 -9
- package/templates/full-stack/src/action-authorizations.ts +0 -10
- package/templates/full-stack/src/actions/create-message.ts +0 -10
- package/templates/full-stack/src/i18n.ts +0 -8
- package/templates/full-stack/src/main.tsx +0 -11
- package/templates/full-stack/src/pages/home.tsx +0 -25
- package/templates/full-stack/src/pages/layout.tsx +0 -43
- package/templates/full-stack/src/pages/not-found.tsx +0 -7
- package/templates/full-stack/src/routes.tsx +0 -19
- package/templates/full-stack/src/schemas.ts +0 -10
- package/templates/full-stack/src/server/action-registry.ts +0 -8
- package/templates/full-stack/src/server/actions/create-message.ts +0 -14
- package/templates/full-stack/src/server/app.ts +0 -76
- package/templates/full-stack/src/server/dependencies.ts +0 -55
- package/templates/full-stack/src/server/entry-server.ts +0 -8
- package/templates/full-stack/src/telemetry.ts +0 -3
- package/templates/full-stack/src/vite-server.d.ts +0 -5
- package/templates/full-stack/tests/actions/create-message.test.ts +0 -12
- package/templates/full-stack/tsconfig.json +0 -15
- package/templates/full-stack/vite.config.ts +0 -10
- package/templates/spa/AGENTS.md +0 -60
- package/templates/spa/README.md +0 -96
- package/templates/spa/gitignore.template +0 -16
- package/templates/spa/index.html +0 -13
- package/templates/spa/package.json +0 -35
- package/templates/spa/src/adapters/operations-client.ts +0 -95
- package/templates/spa/src/components/shared/metric-card.tsx +0 -27
- package/templates/spa/src/components/shared/status-badge.tsx +0 -24
- package/templates/spa/src/features/operations/operations.query.ts +0 -9
- package/templates/spa/src/main.tsx +0 -10
- package/templates/spa/src/pages/_layout.tsx +0 -9
- package/templates/spa/src/pages/_routes.tsx +0 -27
- package/templates/spa/src/pages/app/_layout.tsx +0 -94
- package/templates/spa/src/pages/app/_routes.tsx +0 -10
- package/templates/spa/src/pages/app/admin-home.tsx +0 -170
- package/templates/spa/src/pages/app/agent-runs.tsx +0 -93
- package/templates/spa/src/pages/app/settings.tsx +0 -91
- package/templates/spa/src/pages/auth/_layout.tsx +0 -38
- package/templates/spa/src/pages/auth/_routes.tsx +0 -6
- package/templates/spa/src/pages/auth/login.tsx +0 -63
- package/templates/spa/src/pages/not-found.tsx +0 -22
- package/templates/spa/src/pages/public/_layout.tsx +0 -47
- package/templates/spa/src/pages/public/_routes.tsx +0 -6
- package/templates/spa/src/pages/public/home.tsx +0 -143
- package/templates/spa/src/shared/format.ts +0 -12
- package/templates/spa/src/shared/navigation.ts +0 -15
- package/templates/spa/src/styles/components.css +0 -49
- package/templates/spa/src/styles/layout.css +0 -192
- package/templates/spa/src/styles/reset.css +0 -44
- package/templates/spa/src/styles/theme.css +0 -57
- package/templates/spa/src/styles/tokens.css +0 -20
- package/templates/spa/src/styles.css +0 -7
- package/templates/spa/src/styles.d.ts +0 -1
- package/templates/spa/tests/app.test.tsx +0 -37
- package/templates/spa/tests/components/shared.test.tsx +0 -12
- package/templates/spa/tests/resources.test.ts +0 -22
- package/templates/spa/tsconfig.json +0 -20
- package/templates/spa/tsconfig.node.json +0 -10
- package/templates/spa/vite.config.ts +0 -24
- package/templates/spa/vitest.config.ts +0 -17
- package/templates/ssg/AGENTS.md +0 -55
- package/templates/ssg/README.md +0 -39
- package/templates/ssg/gitignore.template +0 -17
- package/templates/ssg/index.html +0 -13
- package/templates/ssg/package.json +0 -35
- package/templates/ssg/src/app.tsx +0 -14
- package/templates/ssg/src/components/badge.tsx +0 -3
- package/templates/ssg/src/components/counter.tsx +0 -30
- package/templates/ssg/src/components/site-shell.tsx +0 -111
- package/templates/ssg/src/jsx.d.ts +0 -23
- package/templates/ssg/src/main.tsx +0 -8
- package/templates/ssg/src/pages/about.tsx +0 -82
- package/templates/ssg/src/pages/content.tsx +0 -63
- package/templates/ssg/src/pages/example.tsx +0 -97
- package/templates/ssg/src/pages/home.tsx +0 -51
- package/templates/ssg/src/resources/user.ts +0 -15
- package/templates/ssg/src/routes.tsx +0 -15
- package/templates/ssg/src/styles.css +0 -89
- package/templates/ssg/src/vite-env.d.ts +0 -5
- package/templates/ssg/ssg.config.ts +0 -34
- package/templates/ssg/tests/app.test.tsx +0 -19
- package/templates/ssg/tests/components/counter.test.tsx +0 -18
- package/templates/ssg/tests/resources.test.ts +0 -11
- package/templates/ssg/tests/ssg-config.test.ts +0 -11
- package/templates/ssg/tsconfig.json +0 -20
- package/templates/ssg/tsconfig.node.json +0 -10
- package/templates/ssg/vite.config.ts +0 -24
- package/templates/ssg/vitest.config.ts +0 -17
- package/templates/ssr/AGENTS.md +0 -28
- package/templates/ssr/README.md +0 -38
- package/templates/ssr/gitignore.template +0 -16
- package/templates/ssr/index.html +0 -13
- package/templates/ssr/package.json +0 -34
- package/templates/ssr/server.ts +0 -10
- package/templates/ssr/src/app.tsx +0 -21
- package/templates/ssr/src/components/counter.tsx +0 -26
- package/templates/ssr/src/entry-server.tsx +0 -12
- package/templates/ssr/src/main.tsx +0 -11
- package/templates/ssr/src/pages/about.tsx +0 -75
- package/templates/ssr/src/pages/example.tsx +0 -113
- package/templates/ssr/src/pages/home.tsx +0 -56
- package/templates/ssr/src/resources/user.ts +0 -15
- package/templates/ssr/src/routes.tsx +0 -13
- package/templates/ssr/src/styles.css +0 -148
- package/templates/ssr/src/vite-server.d.ts +0 -7
- package/templates/ssr/tests/app.test.tsx +0 -24
- package/templates/ssr/tests/components/counter.test.tsx +0 -13
- package/templates/ssr/tests/resources.test.ts +0 -11
- package/templates/ssr/tsconfig.json +0 -22
- package/templates/ssr/tsconfig.node.json +0 -10
- package/templates/ssr/tsconfig.server.json +0 -15
- package/templates/ssr/vite.config.ts +0 -25
- package/templates/ssr/vitest.config.ts +0 -13
- package/templates/startkit/AGENTS.md +0 -77
- package/templates/startkit/README.md +0 -192
- package/templates/startkit/gitignore.template +0 -16
- package/templates/startkit/index.html +0 -13
- package/templates/startkit/package.json +0 -35
- package/templates/startkit/src/components/app-header.tsx +0 -93
- package/templates/startkit/src/components/app-sidebar.tsx +0 -95
- package/templates/startkit/src/components/data-table.tsx +0 -80
- package/templates/startkit/src/components/empty-state.tsx +0 -13
- package/templates/startkit/src/components/page-header.tsx +0 -23
- package/templates/startkit/src/components/stat-card.tsx +0 -24
- package/templates/startkit/src/features/accounts/account-filters.tsx +0 -61
- package/templates/startkit/src/features/accounts/account-table.tsx +0 -79
- package/templates/startkit/src/lib/format.ts +0 -31
- package/templates/startkit/src/lib/mock-data.ts +0 -441
- package/templates/startkit/src/lib/routes.ts +0 -116
- package/templates/startkit/src/main.tsx +0 -12
- package/templates/startkit/src/pages/_layout.tsx +0 -56
- package/templates/startkit/src/pages/auth/_layout.tsx +0 -7
- package/templates/startkit/src/pages/auth/login.tsx +0 -129
- package/templates/startkit/src/pages/home.tsx +0 -83
- package/templates/startkit/src/pages/not-found.tsx +0 -24
- package/templates/startkit/src/pages/workspace/_layout.tsx +0 -17
- package/templates/startkit/src/pages/workspace/accounts/index.tsx +0 -217
- package/templates/startkit/src/pages/workspace/dashboard.tsx +0 -118
- package/templates/startkit/src/pages/workspace/settings.tsx +0 -218
- package/templates/startkit/src/router.tsx +0 -7
- package/templates/startkit/src/routes/auth-config.ts +0 -38
- package/templates/startkit/src/routes/auth.ts +0 -8
- package/templates/startkit/src/routes/index.ts +0 -28
- package/templates/startkit/src/routes/public.ts +0 -8
- package/templates/startkit/src/routes/workspace/accounts.ts +0 -8
- package/templates/startkit/src/routes/workspace/index.ts +0 -14
- package/templates/startkit/src/styles/components.css +0 -396
- package/templates/startkit/src/styles/layout.css +0 -192
- package/templates/startkit/src/styles/reset.css +0 -38
- package/templates/startkit/src/styles/theme.css +0 -76
- package/templates/startkit/src/styles/tokens.css +0 -67
- package/templates/startkit/src/styles.css +0 -7
- package/templates/startkit/src/toast.ts +0 -55
- package/templates/startkit/src/utils/join-classes.ts +0 -4
- package/templates/startkit/src/vite-env.d.ts +0 -5
- package/templates/startkit/tests/app.test.tsx +0 -32
- package/templates/startkit/tests/preferences.test.ts +0 -43
- package/templates/startkit/tests/resources.test.ts +0 -82
- package/templates/startkit/tsconfig.json +0 -20
- package/templates/startkit/tsconfig.node.json +0 -10
- package/templates/startkit/vite.config.ts +0 -32
- package/templates/startkit/vitest.config.ts +0 -13
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Badge } from '@askrjs/themes/components';
|
|
2
|
-
|
|
3
|
-
export type RunStatus =
|
|
4
|
-
| 'queued'
|
|
5
|
-
| 'running'
|
|
6
|
-
| 'requires-action'
|
|
7
|
-
| 'succeeded'
|
|
8
|
-
| 'failed';
|
|
9
|
-
|
|
10
|
-
export type StatusBadgeProps = {
|
|
11
|
-
status: RunStatus;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const labels: Record<RunStatus, string> = {
|
|
15
|
-
queued: 'queued',
|
|
16
|
-
running: 'running',
|
|
17
|
-
'requires-action': 'needs review',
|
|
18
|
-
succeeded: 'succeeded',
|
|
19
|
-
failed: 'failed',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export default function StatusBadge({ status }: StatusBadgeProps) {
|
|
23
|
-
return <Badge data-status={status}>{labels[status]}</Badge>;
|
|
24
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { fallback, group, registerRoutes } from '@askrjs/askr/router';
|
|
2
|
-
import RootLayout from './_layout';
|
|
3
|
-
import AuthLayout from './auth/_layout';
|
|
4
|
-
import { registerAuthRoutes } from './auth/_routes';
|
|
5
|
-
import { registerAppRoutes } from './app/_routes';
|
|
6
|
-
import AppLayout from './app/_layout';
|
|
7
|
-
import NotFoundPage from './not-found';
|
|
8
|
-
import { registerPublicRoutes } from './public/_routes';
|
|
9
|
-
import PublicLayout from './public/_layout';
|
|
10
|
-
|
|
11
|
-
registerRoutes(() => {
|
|
12
|
-
group({ layout: RootLayout }, () => {
|
|
13
|
-
group({ layout: PublicLayout }, () => {
|
|
14
|
-
registerPublicRoutes();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
group({ layout: AuthLayout }, () => {
|
|
18
|
-
registerAuthRoutes();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
group({ layout: AppLayout }, () => {
|
|
22
|
-
registerAppRoutes();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
fallback(NotFoundPage);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BotIcon,
|
|
3
|
-
HomeIcon,
|
|
4
|
-
LogOutIcon,
|
|
5
|
-
MoonIcon,
|
|
6
|
-
SettingsIcon,
|
|
7
|
-
SunIcon,
|
|
8
|
-
} from '@askrjs/lucide';
|
|
9
|
-
import { Link, navigate } from '@askrjs/askr/router';
|
|
10
|
-
import { Button } from '@askrjs/themes/components';
|
|
11
|
-
import { Container, Inline, Stack } from '@askrjs/themes/components';
|
|
12
|
-
import { Header, Shell, ShellMain, ShellNav } from '@askrjs/themes/components';
|
|
13
|
-
import {
|
|
14
|
-
NavBrand,
|
|
15
|
-
NavGroup,
|
|
16
|
-
NavLink,
|
|
17
|
-
Sidebar,
|
|
18
|
-
} from '@askrjs/themes/components';
|
|
19
|
-
import { Badge } from '@askrjs/themes/components';
|
|
20
|
-
import { ThemeToggle } from '@askrjs/themes/theme';
|
|
21
|
-
import { appNavItems } from '../../shared/navigation';
|
|
22
|
-
|
|
23
|
-
const icons = {
|
|
24
|
-
home: <HomeIcon size={16} aria-hidden="true" />,
|
|
25
|
-
agents: <BotIcon size={16} aria-hidden="true" />,
|
|
26
|
-
settings: <SettingsIcon size={16} aria-hidden="true" />,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export default function AppLayout({ children }: { children?: unknown }) {
|
|
30
|
-
return (
|
|
31
|
-
<Shell variant="sidebar" class="app-shell">
|
|
32
|
-
<ShellNav>
|
|
33
|
-
<Sidebar
|
|
34
|
-
aria-label="Workspace navigation"
|
|
35
|
-
breakpoint="md"
|
|
36
|
-
collapsible="icon"
|
|
37
|
-
>
|
|
38
|
-
<NavBrand>
|
|
39
|
-
<Link href="/app" class="brand-link">
|
|
40
|
-
<span class="brand-mark">A</span>
|
|
41
|
-
<strong>{'{{appName}}'}</strong>
|
|
42
|
-
</Link>
|
|
43
|
-
</NavBrand>
|
|
44
|
-
<NavGroup label="Workspace">
|
|
45
|
-
{appNavItems.map((item) => (
|
|
46
|
-
<NavLink href={item.href} match={item.match}>
|
|
47
|
-
<Inline as="span" gap="2" align="center">
|
|
48
|
-
{icons[item.icon]}
|
|
49
|
-
<span>{item.label}</span>
|
|
50
|
-
</Inline>
|
|
51
|
-
</NavLink>
|
|
52
|
-
))}
|
|
53
|
-
</NavGroup>
|
|
54
|
-
<NavGroup label="Session" align="end">
|
|
55
|
-
<NavLink href="/" match="exact">
|
|
56
|
-
<Inline as="span" gap="2" align="center">
|
|
57
|
-
<LogOutIcon size={16} aria-hidden="true" />
|
|
58
|
-
<span>Sign out</span>
|
|
59
|
-
</Inline>
|
|
60
|
-
</NavLink>
|
|
61
|
-
</NavGroup>
|
|
62
|
-
</Sidebar>
|
|
63
|
-
</ShellNav>
|
|
64
|
-
<ShellMain>
|
|
65
|
-
<Header position="sticky" class="app-header">
|
|
66
|
-
<Container size="full">
|
|
67
|
-
<Inline justify="between" align="center" gap="3" wrap="wrap">
|
|
68
|
-
<Stack gap="none">
|
|
69
|
-
<span class="eyebrow">Operations console</span>
|
|
70
|
-
<strong>Agent workflow control plane</strong>
|
|
71
|
-
</Stack>
|
|
72
|
-
<Inline gap="2" align="center" wrap="wrap">
|
|
73
|
-
<Badge>event stream healthy</Badge>
|
|
74
|
-
<ThemeToggle
|
|
75
|
-
variant="ghost"
|
|
76
|
-
size="icon"
|
|
77
|
-
aria-label="Toggle color theme"
|
|
78
|
-
lightIcon={<SunIcon size={18} aria-hidden="true" />}
|
|
79
|
-
darkIcon={<MoonIcon size={18} aria-hidden="true" />}
|
|
80
|
-
/>
|
|
81
|
-
<Button variant="secondary" onPress={() => navigate('/')}>
|
|
82
|
-
Public site
|
|
83
|
-
</Button>
|
|
84
|
-
</Inline>
|
|
85
|
-
</Inline>
|
|
86
|
-
</Container>
|
|
87
|
-
</Header>
|
|
88
|
-
<Container size="full" class="app-main">
|
|
89
|
-
{children}
|
|
90
|
-
</Container>
|
|
91
|
-
</ShellMain>
|
|
92
|
-
</Shell>
|
|
93
|
-
);
|
|
94
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { route } from '@askrjs/askr/router';
|
|
2
|
-
import AgentRunsPage from './agent-runs';
|
|
3
|
-
import AdminHomePage from './admin-home';
|
|
4
|
-
import SettingsPage from './settings';
|
|
5
|
-
|
|
6
|
-
export function registerAppRoutes(): void {
|
|
7
|
-
route('/app', AdminHomePage);
|
|
8
|
-
route('/app/agents', AgentRunsPage);
|
|
9
|
-
route('/app/settings', SettingsPage);
|
|
10
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { resource } from '@askrjs/askr/resources';
|
|
2
|
-
import { createPlot } from '@askrjs/charts';
|
|
3
|
-
import { AlertCircleIcon, RefreshCwIcon } from '@askrjs/lucide';
|
|
4
|
-
import { Button } from '@askrjs/themes/components';
|
|
5
|
-
import {
|
|
6
|
-
Alert,
|
|
7
|
-
Badge,
|
|
8
|
-
Card,
|
|
9
|
-
CardContent,
|
|
10
|
-
CardDescription,
|
|
11
|
-
CardHeader,
|
|
12
|
-
CardTitle,
|
|
13
|
-
Skeleton,
|
|
14
|
-
} from '@askrjs/themes/components';
|
|
15
|
-
import { Block, Inline, Section, Stack } from '@askrjs/themes/components';
|
|
16
|
-
import { EmptyState } from '@askrjs/themes/components';
|
|
17
|
-
import MetricCard from '../../components/shared/metric-card';
|
|
18
|
-
import StatusBadge from '../../components/shared/status-badge';
|
|
19
|
-
import type { OperationsChartRow } from '../../adapters/operations-client';
|
|
20
|
-
import { loadOperations } from '../../features/operations/operations.query';
|
|
21
|
-
import { formatRelativeTime } from '../../shared/format';
|
|
22
|
-
|
|
23
|
-
const OperationsPlot = createPlot<OperationsChartRow>();
|
|
24
|
-
|
|
25
|
-
export default function AdminHomePage() {
|
|
26
|
-
const operations = resource(({ signal }) => loadOperations({ signal }), []);
|
|
27
|
-
const snapshot = operations.value;
|
|
28
|
-
|
|
29
|
-
if (operations.error && !snapshot) {
|
|
30
|
-
return (
|
|
31
|
-
<Section>
|
|
32
|
-
<EmptyState
|
|
33
|
-
icon={<AlertCircleIcon size={24} aria-hidden="true" />}
|
|
34
|
-
title="Operations could not load"
|
|
35
|
-
description="The dashboard keeps failures recoverable. Retry the owning resource instead of hiding the error in a toast."
|
|
36
|
-
actions={<Button onPress={() => operations.refresh()}>Retry</Button>}
|
|
37
|
-
/>
|
|
38
|
-
</Section>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<Stack gap="5">
|
|
44
|
-
<section class="page-heading">
|
|
45
|
-
<Stack gap="2">
|
|
46
|
-
<Badge>projection v{snapshot?.version ?? '...'}</Badge>
|
|
47
|
-
<h1>Workspace home</h1>
|
|
48
|
-
<p class="lead">
|
|
49
|
-
A consistency-aware dashboard for agent runs, queue health, and
|
|
50
|
-
event-sourced read models.
|
|
51
|
-
</p>
|
|
52
|
-
</Stack>
|
|
53
|
-
<Inline gap="2" align="center">
|
|
54
|
-
{operations.pending && snapshot ? <Badge>refreshing</Badge> : null}
|
|
55
|
-
<Button variant="secondary" onPress={() => operations.refresh()}>
|
|
56
|
-
<RefreshCwIcon size={14} aria-hidden="true" /> Refresh
|
|
57
|
-
</Button>
|
|
58
|
-
</Inline>
|
|
59
|
-
</section>
|
|
60
|
-
|
|
61
|
-
{operations.pending && !snapshot ? (
|
|
62
|
-
<Block gap="md">
|
|
63
|
-
<Skeleton style="height: 8rem" />
|
|
64
|
-
<Skeleton style="height: 8rem" />
|
|
65
|
-
<Skeleton style="height: 8rem" />
|
|
66
|
-
</Block>
|
|
67
|
-
) : null}
|
|
68
|
-
|
|
69
|
-
{snapshot ? (
|
|
70
|
-
<>
|
|
71
|
-
<Block gap="md" class="metric-grid">
|
|
72
|
-
{snapshot.metrics.map((metric) => (
|
|
73
|
-
<MetricCard
|
|
74
|
-
label={metric.label}
|
|
75
|
-
value={metric.value}
|
|
76
|
-
trend={metric.trend}
|
|
77
|
-
/>
|
|
78
|
-
))}
|
|
79
|
-
</Block>
|
|
80
|
-
|
|
81
|
-
<Block gap="md" align="stretch" class="chart-grid">
|
|
82
|
-
<Card>
|
|
83
|
-
<CardHeader>
|
|
84
|
-
<CardTitle>Run throughput</CardTitle>
|
|
85
|
-
<CardDescription>
|
|
86
|
-
Accepted commands by work type.
|
|
87
|
-
</CardDescription>
|
|
88
|
-
</CardHeader>
|
|
89
|
-
<CardContent>
|
|
90
|
-
<OperationsPlot.Root
|
|
91
|
-
data={snapshot.throughput}
|
|
92
|
-
rowKey="label"
|
|
93
|
-
label="Run throughput"
|
|
94
|
-
description="Accepted commands by work type."
|
|
95
|
-
>
|
|
96
|
-
<OperationsPlot.Bar x="label" y="value" />
|
|
97
|
-
</OperationsPlot.Root>
|
|
98
|
-
</CardContent>
|
|
99
|
-
</Card>
|
|
100
|
-
<Card>
|
|
101
|
-
<CardHeader>
|
|
102
|
-
<CardTitle>Projection lag</CardTitle>
|
|
103
|
-
<CardDescription>
|
|
104
|
-
Lower is better; stale states stay visible.
|
|
105
|
-
</CardDescription>
|
|
106
|
-
</CardHeader>
|
|
107
|
-
<CardContent>
|
|
108
|
-
<OperationsPlot.Root
|
|
109
|
-
data={snapshot.lag}
|
|
110
|
-
rowKey="label"
|
|
111
|
-
label="Projection lag"
|
|
112
|
-
description="Projection lag over the last hour."
|
|
113
|
-
>
|
|
114
|
-
<OperationsPlot.Line x="label" y="value" />
|
|
115
|
-
<OperationsPlot.Point x="label" y="value" />
|
|
116
|
-
</OperationsPlot.Root>
|
|
117
|
-
</CardContent>
|
|
118
|
-
</Card>
|
|
119
|
-
</Block>
|
|
120
|
-
|
|
121
|
-
{snapshot.consistency !== 'fresh' ? (
|
|
122
|
-
<Alert variant="warning">
|
|
123
|
-
Read models are {snapshot.consistency}. Last processed event is{' '}
|
|
124
|
-
{snapshot.lastEventId}.
|
|
125
|
-
</Alert>
|
|
126
|
-
) : null}
|
|
127
|
-
|
|
128
|
-
<Card>
|
|
129
|
-
<CardHeader>
|
|
130
|
-
<CardTitle>Recent agent runs</CardTitle>
|
|
131
|
-
<CardDescription>
|
|
132
|
-
Run state is modeled as product state, not a single loading
|
|
133
|
-
boolean.
|
|
134
|
-
</CardDescription>
|
|
135
|
-
</CardHeader>
|
|
136
|
-
<CardContent>
|
|
137
|
-
<div class="run-table-wrap">
|
|
138
|
-
<table class="run-table">
|
|
139
|
-
<thead>
|
|
140
|
-
<tr>
|
|
141
|
-
<th>Run</th>
|
|
142
|
-
<th>Status</th>
|
|
143
|
-
<th>Owner</th>
|
|
144
|
-
<th>Updated</th>
|
|
145
|
-
</tr>
|
|
146
|
-
</thead>
|
|
147
|
-
<tbody>
|
|
148
|
-
{snapshot.runs.map((run) => (
|
|
149
|
-
<tr>
|
|
150
|
-
<td>
|
|
151
|
-
<strong>{run.title}</strong>
|
|
152
|
-
<span>{run.id}</span>
|
|
153
|
-
</td>
|
|
154
|
-
<td>
|
|
155
|
-
<StatusBadge status={run.status} />
|
|
156
|
-
</td>
|
|
157
|
-
<td>{run.owner}</td>
|
|
158
|
-
<td>{formatRelativeTime(run.updatedAt)}</td>
|
|
159
|
-
</tr>
|
|
160
|
-
))}
|
|
161
|
-
</tbody>
|
|
162
|
-
</table>
|
|
163
|
-
</div>
|
|
164
|
-
</CardContent>
|
|
165
|
-
</Card>
|
|
166
|
-
</>
|
|
167
|
-
) : null}
|
|
168
|
-
</Stack>
|
|
169
|
-
);
|
|
170
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BotIcon,
|
|
3
|
-
CheckCircle2Icon,
|
|
4
|
-
Clock3Icon,
|
|
5
|
-
ShieldAlertIcon,
|
|
6
|
-
} from '@askrjs/lucide';
|
|
7
|
-
import {
|
|
8
|
-
Badge,
|
|
9
|
-
Card,
|
|
10
|
-
CardContent,
|
|
11
|
-
CardDescription,
|
|
12
|
-
CardHeader,
|
|
13
|
-
CardTitle,
|
|
14
|
-
} from '@askrjs/themes/components';
|
|
15
|
-
import { Block, Inline, Stack } from '@askrjs/themes/components';
|
|
16
|
-
import StatusBadge, {
|
|
17
|
-
type RunStatus,
|
|
18
|
-
} from '../../components/shared/status-badge';
|
|
19
|
-
|
|
20
|
-
const runs: Array<{
|
|
21
|
-
title: string;
|
|
22
|
-
status: RunStatus;
|
|
23
|
-
event: string;
|
|
24
|
-
description: string;
|
|
25
|
-
}> = [
|
|
26
|
-
{
|
|
27
|
-
title: 'Reconcile billing projection',
|
|
28
|
-
status: 'running',
|
|
29
|
-
event: 'tool call: compare-ledger',
|
|
30
|
-
description:
|
|
31
|
-
'Streaming events are appended to the timeline and reconciled by event id.',
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
title: 'Approve enterprise workspace',
|
|
35
|
-
status: 'requires-action',
|
|
36
|
-
event: 'approval requested',
|
|
37
|
-
description:
|
|
38
|
-
'Human gates are explicit product states, not hidden inside generated text.',
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
title: 'Refresh onboarding cohort',
|
|
42
|
-
status: 'succeeded',
|
|
43
|
-
event: 'projection caught up',
|
|
44
|
-
description:
|
|
45
|
-
'The read model confirms the command reached the user-visible view.',
|
|
46
|
-
},
|
|
47
|
-
];
|
|
48
|
-
|
|
49
|
-
export default function AgentRunsPage() {
|
|
50
|
-
return (
|
|
51
|
-
<Stack gap="5">
|
|
52
|
-
<section class="page-heading">
|
|
53
|
-
<Stack gap="2">
|
|
54
|
-
<Badge>agent workflows</Badge>
|
|
55
|
-
<h1>Agent runs</h1>
|
|
56
|
-
<p class="lead">
|
|
57
|
-
Timelines make queued, running, approval, failure, and projection
|
|
58
|
-
catch-up states easy to inspect.
|
|
59
|
-
</p>
|
|
60
|
-
</Stack>
|
|
61
|
-
</section>
|
|
62
|
-
|
|
63
|
-
<Block gap="md" class="agent-grid">
|
|
64
|
-
{runs.map((run) => (
|
|
65
|
-
<Card>
|
|
66
|
-
<CardHeader>
|
|
67
|
-
<Inline justify="between" align="start" gap="3">
|
|
68
|
-
<span class="card-icon">
|
|
69
|
-
{run.status === 'succeeded' ? (
|
|
70
|
-
<CheckCircle2Icon size={18} aria-hidden="true" />
|
|
71
|
-
) : run.status === 'requires-action' ? (
|
|
72
|
-
<ShieldAlertIcon size={18} aria-hidden="true" />
|
|
73
|
-
) : (
|
|
74
|
-
<BotIcon size={18} aria-hidden="true" />
|
|
75
|
-
)}
|
|
76
|
-
</span>
|
|
77
|
-
<StatusBadge status={run.status} />
|
|
78
|
-
</Inline>
|
|
79
|
-
<CardTitle>{run.title}</CardTitle>
|
|
80
|
-
<CardDescription>{run.description}</CardDescription>
|
|
81
|
-
</CardHeader>
|
|
82
|
-
<CardContent>
|
|
83
|
-
<Inline gap="2" align="center">
|
|
84
|
-
<Clock3Icon size={14} aria-hidden="true" />
|
|
85
|
-
<span>{run.event}</span>
|
|
86
|
-
</Inline>
|
|
87
|
-
</CardContent>
|
|
88
|
-
</Card>
|
|
89
|
-
))}
|
|
90
|
-
</Block>
|
|
91
|
-
</Stack>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { state } from '@askrjs/askr';
|
|
2
|
-
import { Input } from '@askrjs/ui';
|
|
3
|
-
import {
|
|
4
|
-
Button,
|
|
5
|
-
Field,
|
|
6
|
-
FieldHint,
|
|
7
|
-
InputGroup,
|
|
8
|
-
InputGroupText,
|
|
9
|
-
} from '@askrjs/themes/components';
|
|
10
|
-
import {
|
|
11
|
-
Badge,
|
|
12
|
-
Card,
|
|
13
|
-
CardContent,
|
|
14
|
-
CardDescription,
|
|
15
|
-
CardHeader,
|
|
16
|
-
CardTitle,
|
|
17
|
-
} from '@askrjs/themes/components';
|
|
18
|
-
import { Block, Stack } from '@askrjs/themes/components';
|
|
19
|
-
|
|
20
|
-
export default function SettingsPage() {
|
|
21
|
-
const [endpoint, setEndpoint] = state(
|
|
22
|
-
'https://api.example.test'
|
|
23
|
-
) as unknown as [
|
|
24
|
-
ReturnType<typeof state<string>>,
|
|
25
|
-
ReturnType<typeof state<string>>['set'],
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<Stack gap="5">
|
|
30
|
-
<section class="page-heading">
|
|
31
|
-
<Stack gap="2">
|
|
32
|
-
<Badge>environment</Badge>
|
|
33
|
-
<h1>Settings</h1>
|
|
34
|
-
<p class="lead">
|
|
35
|
-
Configuration stays in shared boundaries and adapters receive it
|
|
36
|
-
through one clear path.
|
|
37
|
-
</p>
|
|
38
|
-
</Stack>
|
|
39
|
-
</section>
|
|
40
|
-
|
|
41
|
-
<Block gap="md" align="start" class="settings-grid">
|
|
42
|
-
<Card>
|
|
43
|
-
<CardHeader>
|
|
44
|
-
<CardTitle>API adapter</CardTitle>
|
|
45
|
-
<CardDescription>
|
|
46
|
-
Keep generated clients and transport concerns out of route
|
|
47
|
-
components.
|
|
48
|
-
</CardDescription>
|
|
49
|
-
</CardHeader>
|
|
50
|
-
<CardContent>
|
|
51
|
-
<Field>
|
|
52
|
-
<label htmlFor="api-endpoint">Base URL</label>
|
|
53
|
-
<InputGroup>
|
|
54
|
-
<InputGroupText>URL</InputGroupText>
|
|
55
|
-
<Input
|
|
56
|
-
id="api-endpoint"
|
|
57
|
-
value={endpoint()}
|
|
58
|
-
onInput={(event: Event) =>
|
|
59
|
-
setEndpoint((event.currentTarget as HTMLInputElement).value)
|
|
60
|
-
}
|
|
61
|
-
/>
|
|
62
|
-
</InputGroup>
|
|
63
|
-
<FieldHint>
|
|
64
|
-
Demo-only value. Real apps should validate public config at
|
|
65
|
-
startup.
|
|
66
|
-
</FieldHint>
|
|
67
|
-
</Field>
|
|
68
|
-
</CardContent>
|
|
69
|
-
</Card>
|
|
70
|
-
|
|
71
|
-
<Card>
|
|
72
|
-
<CardHeader>
|
|
73
|
-
<CardTitle>Consistency policy</CardTitle>
|
|
74
|
-
<CardDescription>
|
|
75
|
-
Event-sourced apps should expose lag, retries, and stale states
|
|
76
|
-
directly.
|
|
77
|
-
</CardDescription>
|
|
78
|
-
</CardHeader>
|
|
79
|
-
<CardContent>
|
|
80
|
-
<Stack gap="3">
|
|
81
|
-
<Badge>pending-write copy enabled</Badge>
|
|
82
|
-
<Badge>projection lag visible</Badge>
|
|
83
|
-
<Badge>manual refresh available</Badge>
|
|
84
|
-
<Button variant="secondary">Save settings</Button>
|
|
85
|
-
</Stack>
|
|
86
|
-
</CardContent>
|
|
87
|
-
</Card>
|
|
88
|
-
</Block>
|
|
89
|
-
</Stack>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Link } from '@askrjs/askr/router';
|
|
2
|
-
import { MoonIcon, SunIcon } from '@askrjs/lucide';
|
|
3
|
-
import { Button } from '@askrjs/themes/components';
|
|
4
|
-
import { Container, Inline } from '@askrjs/themes/components';
|
|
5
|
-
import { Header } from '@askrjs/themes/components';
|
|
6
|
-
import { ThemeToggle } from '@askrjs/themes/theme';
|
|
7
|
-
|
|
8
|
-
export default function AuthLayout({ children }: { children?: unknown }) {
|
|
9
|
-
return (
|
|
10
|
-
<div class="auth-shell">
|
|
11
|
-
<Header position="sticky" class="auth-header">
|
|
12
|
-
<Container size="full">
|
|
13
|
-
<Inline justify="between" align="center" gap="3" wrap="wrap">
|
|
14
|
-
<Link href="/" class="brand-link">
|
|
15
|
-
<span class="brand-mark">A</span>
|
|
16
|
-
<strong>{'{{appName}}'}</strong>
|
|
17
|
-
</Link>
|
|
18
|
-
<Inline gap="2" align="center" wrap="wrap">
|
|
19
|
-
<ThemeToggle
|
|
20
|
-
variant="ghost"
|
|
21
|
-
size="icon"
|
|
22
|
-
aria-label="Toggle color theme"
|
|
23
|
-
lightIcon={<SunIcon size={18} aria-hidden="true" />}
|
|
24
|
-
darkIcon={<MoonIcon size={18} aria-hidden="true" />}
|
|
25
|
-
/>
|
|
26
|
-
<Button variant="secondary" asChild>
|
|
27
|
-
<Link href="/">Back to site</Link>
|
|
28
|
-
</Button>
|
|
29
|
-
</Inline>
|
|
30
|
-
</Inline>
|
|
31
|
-
</Container>
|
|
32
|
-
</Header>
|
|
33
|
-
<main class="auth-main">
|
|
34
|
-
<Container size="sm">{children}</Container>
|
|
35
|
-
</main>
|
|
36
|
-
</div>
|
|
37
|
-
);
|
|
38
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { state } from '@askrjs/askr';
|
|
2
|
-
import { navigate } from '@askrjs/askr/router';
|
|
3
|
-
import { LockKeyholeIcon } from '@askrjs/lucide';
|
|
4
|
-
import { Input } from '@askrjs/ui';
|
|
5
|
-
import {
|
|
6
|
-
Button,
|
|
7
|
-
Container,
|
|
8
|
-
Field,
|
|
9
|
-
FieldHint,
|
|
10
|
-
InputGroup,
|
|
11
|
-
InputGroupText,
|
|
12
|
-
} from '@askrjs/themes/components';
|
|
13
|
-
import {
|
|
14
|
-
Card,
|
|
15
|
-
CardContent,
|
|
16
|
-
CardDescription,
|
|
17
|
-
CardHeader,
|
|
18
|
-
CardTitle,
|
|
19
|
-
} from '@askrjs/themes/components';
|
|
20
|
-
import { Stack } from '@askrjs/themes/components';
|
|
21
|
-
|
|
22
|
-
export default function LoginPage() {
|
|
23
|
-
const [email, setEmail] = state('ops@example.com');
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<Container size="sm" class="auth-page">
|
|
27
|
-
<Card variant="raised">
|
|
28
|
-
<CardHeader>
|
|
29
|
-
<span class="card-icon">
|
|
30
|
-
<LockKeyholeIcon size={18} aria-hidden="true" />
|
|
31
|
-
</span>
|
|
32
|
-
<CardTitle>Sign in</CardTitle>
|
|
33
|
-
<CardDescription>
|
|
34
|
-
This starter keeps auth mocked, but the auth shell is isolated from
|
|
35
|
-
the public landing layout and ready for a real session provider.
|
|
36
|
-
</CardDescription>
|
|
37
|
-
</CardHeader>
|
|
38
|
-
<CardContent>
|
|
39
|
-
<Stack gap="4">
|
|
40
|
-
<Field>
|
|
41
|
-
<label htmlFor="email">Work email</label>
|
|
42
|
-
<InputGroup>
|
|
43
|
-
<InputGroupText>@</InputGroupText>
|
|
44
|
-
<Input
|
|
45
|
-
id="email"
|
|
46
|
-
type="email"
|
|
47
|
-
value={email()}
|
|
48
|
-
onInput={(event: Event) =>
|
|
49
|
-
setEmail((event.currentTarget as HTMLInputElement).value)
|
|
50
|
-
}
|
|
51
|
-
/>
|
|
52
|
-
</InputGroup>
|
|
53
|
-
<FieldHint>Use any address to enter the demo console.</FieldHint>
|
|
54
|
-
</Field>
|
|
55
|
-
<Button onPress={() => navigate('/app')}>
|
|
56
|
-
Continue to console
|
|
57
|
-
</Button>
|
|
58
|
-
</Stack>
|
|
59
|
-
</CardContent>
|
|
60
|
-
</Card>
|
|
61
|
-
</Container>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Link } from '@askrjs/askr/router';
|
|
2
|
-
import { Button } from '@askrjs/themes/components';
|
|
3
|
-
import { Container, Section } from '@askrjs/themes/components';
|
|
4
|
-
import { EmptyState } from '@askrjs/themes/components';
|
|
5
|
-
|
|
6
|
-
export default function NotFoundPage() {
|
|
7
|
-
return (
|
|
8
|
-
<Section paddingY="2xl">
|
|
9
|
-
<Container size="sm">
|
|
10
|
-
<EmptyState
|
|
11
|
-
title="Page not found"
|
|
12
|
-
description="The route tree is explicit, so unknown paths fall back here."
|
|
13
|
-
actions={
|
|
14
|
-
<Button asChild>
|
|
15
|
-
<Link href="/">Return home</Link>
|
|
16
|
-
</Button>
|
|
17
|
-
}
|
|
18
|
-
/>
|
|
19
|
-
</Container>
|
|
20
|
-
</Section>
|
|
21
|
-
);
|
|
22
|
-
}
|