@askrjs/cli 0.0.12 → 0.0.14

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.
@@ -27,151 +27,154 @@ export default function AdminHomePage() {
27
27
  const operations = resource(({ signal }) => loadOperations({ signal }), []);
28
28
  const snapshot = operations.value;
29
29
 
30
- if (operations.error && !snapshot) {
31
- return (
32
- <Section>
33
- <EmptyState
34
- icon={<AlertCircleIcon size={24} aria-hidden="true" />}
35
- title="Operations could not load"
36
- description="The dashboard keeps failures recoverable. Retry the owning resource instead of hiding the error in a toast."
37
- actions={<Button onPress={() => operations.refresh()}>Retry</Button>}
38
- />
39
- </Section>
40
- );
41
- }
30
+ const errorState = (
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
+ );
42
40
 
43
41
  return (
44
- <Stack gap="5">
45
- <section class="page-heading">
46
- <Stack gap="2">
47
- <Badge>projection v{snapshot?.version ?? '...'}</Badge>
48
- <h1>Workspace home</h1>
49
- <p class="lead">
50
- A consistency-aware dashboard for agent runs, queue health, and
51
- event-sourced read models.
52
- </p>
53
- </Stack>
54
- <Inline gap="2" align="center">
55
- {operations.pending && snapshot ? <Badge>refreshing</Badge> : null}
56
- <Button variant="secondary" onPress={() => operations.refresh()}>
57
- <RefreshCwIcon size={14} aria-hidden="true" /> Refresh
58
- </Button>
59
- </Inline>
60
- </section>
42
+ <Show when={!operations.error || snapshot} fallback={errorState}>
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>
61
60
 
62
- {operations.pending && !snapshot ? (
63
- <Block gap="md">
64
- <Skeleton style="height: 8rem" />
65
- <Skeleton style="height: 8rem" />
66
- <Skeleton style="height: 8rem" />
67
- </Block>
68
- ) : null}
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}
69
68
 
70
- <Show when={snapshot}>
71
- {(currentSnapshot) => (
72
- <>
73
- <Block gap="md" class="metric-grid">
74
- <For each={currentSnapshot.metrics} by={(metric) => metric.label}>
75
- {(metric) => (
76
- <MetricCard
77
- label={metric.label}
78
- value={metric.value}
79
- trend={metric.trend}
80
- />
81
- )}
82
- </For>
83
- </Block>
69
+ <Show when={snapshot}>
70
+ {(currentSnapshot) => (
71
+ <>
72
+ <Block gap="md" class="metric-grid">
73
+ <For
74
+ each={currentSnapshot.metrics}
75
+ by={(metric) => metric.label}
76
+ >
77
+ {(metric) => (
78
+ <MetricCard
79
+ label={metric.label}
80
+ value={metric.value}
81
+ trend={metric.trend}
82
+ />
83
+ )}
84
+ </For>
85
+ </Block>
86
+
87
+ <Block gap="md" align="stretch" class="chart-grid">
88
+ <Card>
89
+ <CardHeader>
90
+ <CardTitle>Run throughput</CardTitle>
91
+ <CardDescription>
92
+ Accepted commands by work type.
93
+ </CardDescription>
94
+ </CardHeader>
95
+ <CardContent>
96
+ <OperationsPlot.Root
97
+ data={currentSnapshot.throughput}
98
+ rowKey="label"
99
+ label="Run throughput"
100
+ description="Accepted commands by work type."
101
+ >
102
+ <OperationsPlot.Bar x="label" y="value" />
103
+ </OperationsPlot.Root>
104
+ </CardContent>
105
+ </Card>
106
+ <Card>
107
+ <CardHeader>
108
+ <CardTitle>Projection lag</CardTitle>
109
+ <CardDescription>
110
+ Lower is better; stale states stay visible.
111
+ </CardDescription>
112
+ </CardHeader>
113
+ <CardContent>
114
+ <OperationsPlot.Root
115
+ data={currentSnapshot.lag}
116
+ rowKey="label"
117
+ label="Projection lag"
118
+ description="Projection lag over the last hour."
119
+ >
120
+ <OperationsPlot.Line x="label" y="value" />
121
+ <OperationsPlot.Point x="label" y="value" />
122
+ </OperationsPlot.Root>
123
+ </CardContent>
124
+ </Card>
125
+ </Block>
126
+
127
+ {currentSnapshot.consistency !== 'fresh' ? (
128
+ <Alert variant="warning">
129
+ Read models are {currentSnapshot.consistency}. Last processed
130
+ event is {currentSnapshot.lastEventId}.
131
+ </Alert>
132
+ ) : null}
84
133
 
85
- <Block gap="md" align="stretch" class="chart-grid">
86
- <Card>
87
- <CardHeader>
88
- <CardTitle>Run throughput</CardTitle>
89
- <CardDescription>
90
- Accepted commands by work type.
91
- </CardDescription>
92
- </CardHeader>
93
- <CardContent>
94
- <OperationsPlot.Root
95
- data={currentSnapshot.throughput}
96
- rowKey="label"
97
- label="Run throughput"
98
- description="Accepted commands by work type."
99
- >
100
- <OperationsPlot.Bar x="label" y="value" />
101
- </OperationsPlot.Root>
102
- </CardContent>
103
- </Card>
104
134
  <Card>
105
135
  <CardHeader>
106
- <CardTitle>Projection lag</CardTitle>
136
+ <CardTitle>Recent agent runs</CardTitle>
107
137
  <CardDescription>
108
- Lower is better; stale states stay visible.
138
+ Run state is modeled as product state, not a single loading
139
+ boolean.
109
140
  </CardDescription>
110
141
  </CardHeader>
111
142
  <CardContent>
112
- <OperationsPlot.Root
113
- data={currentSnapshot.lag}
114
- rowKey="label"
115
- label="Projection lag"
116
- description="Projection lag over the last hour."
117
- >
118
- <OperationsPlot.Line x="label" y="value" />
119
- <OperationsPlot.Point x="label" y="value" />
120
- </OperationsPlot.Root>
143
+ <div class="run-table-wrap">
144
+ <table class="run-table">
145
+ <thead>
146
+ <tr>
147
+ <th>Run</th>
148
+ <th>Status</th>
149
+ <th>Owner</th>
150
+ <th>Updated</th>
151
+ </tr>
152
+ </thead>
153
+ <tbody>
154
+ <For each={currentSnapshot.runs} by={(run) => run.id}>
155
+ {(run) => (
156
+ <tr>
157
+ <td>
158
+ <strong>{run.title}</strong>
159
+ <span>{run.id}</span>
160
+ </td>
161
+ <td>
162
+ <StatusBadge status={run.status} />
163
+ </td>
164
+ <td>{run.owner}</td>
165
+ <td>{formatRelativeTime(run.updatedAt)}</td>
166
+ </tr>
167
+ )}
168
+ </For>
169
+ </tbody>
170
+ </table>
171
+ </div>
121
172
  </CardContent>
122
173
  </Card>
123
- </Block>
124
-
125
- {currentSnapshot.consistency !== 'fresh' ? (
126
- <Alert variant="warning">
127
- Read models are {currentSnapshot.consistency}. Last processed
128
- event is {currentSnapshot.lastEventId}.
129
- </Alert>
130
- ) : null}
131
-
132
- <Card>
133
- <CardHeader>
134
- <CardTitle>Recent agent runs</CardTitle>
135
- <CardDescription>
136
- Run state is modeled as product state, not a single loading
137
- boolean.
138
- </CardDescription>
139
- </CardHeader>
140
- <CardContent>
141
- <div class="run-table-wrap">
142
- <table class="run-table">
143
- <thead>
144
- <tr>
145
- <th>Run</th>
146
- <th>Status</th>
147
- <th>Owner</th>
148
- <th>Updated</th>
149
- </tr>
150
- </thead>
151
- <tbody>
152
- <For each={currentSnapshot.runs} by={(run) => run.id}>
153
- {(run) => (
154
- <tr>
155
- <td>
156
- <strong>{run.title}</strong>
157
- <span>{run.id}</span>
158
- </td>
159
- <td>
160
- <StatusBadge status={run.status} />
161
- </td>
162
- <td>{run.owner}</td>
163
- <td>{formatRelativeTime(run.updatedAt)}</td>
164
- </tr>
165
- )}
166
- </For>
167
- </tbody>
168
- </table>
169
- </div>
170
- </CardContent>
171
- </Card>
172
- </>
173
- )}
174
- </Show>
175
- </Stack>
174
+ </>
175
+ )}
176
+ </Show>
177
+ </Stack>
178
+ </Show>
176
179
  );
177
180
  }
@@ -1,4 +1,4 @@
1
- import { For } from '@askrjs/askr/control';
1
+ import { Case, For, Match } from '@askrjs/askr/control';
2
2
  import { Skeleton } from '@askrjs/themes/components';
3
3
  import EmptyState from './empty-state';
4
4
  import { joinClasses } from '../utils/join-classes';
@@ -22,38 +22,8 @@ export default function DataTable<Row>(props: {
22
22
  emptyTitle?: string;
23
23
  emptyDescription?: string;
24
24
  }) {
25
- if (props.errorText) {
26
- return (
27
- <EmptyState title="Could not load table" description={props.errorText} />
28
- );
29
- }
30
-
31
- if (props.isLoading) {
32
- return (
33
- <div
34
- class={joinClasses('panel stack-sm', props.class)}
35
- aria-hidden="true"
36
- >
37
- <Skeleton class="skeleton-line" />
38
- <Skeleton class="skeleton-line" />
39
- <Skeleton class="skeleton-line" />
40
- </div>
41
- );
42
- }
43
-
44
- if (props.rows().length === 0) {
45
- return (
46
- <EmptyState
47
- title={props.emptyTitle ?? 'No rows found'}
48
- description={
49
- props.emptyDescription ??
50
- 'Try changing filters or adding new records.'
51
- }
52
- />
53
- );
54
- }
55
-
56
- return (
25
+ const rows = props.rows();
26
+ const table = (
57
27
  <div class={joinClasses('table-wrap', props.class)}>
58
28
  <table class={props.tableClass}>
59
29
  <thead>
@@ -79,4 +49,34 @@ export default function DataTable<Row>(props: {
79
49
  </table>
80
50
  </div>
81
51
  );
52
+
53
+ return (
54
+ <Case fallback={table}>
55
+ <Match when={props.errorText}>
56
+ <EmptyState
57
+ title="Could not load table"
58
+ description={props.errorText ?? 'The table could not be loaded.'}
59
+ />
60
+ </Match>
61
+ <Match when={props.isLoading}>
62
+ <div
63
+ class={joinClasses('panel stack-sm', props.class)}
64
+ aria-hidden="true"
65
+ >
66
+ <Skeleton class="skeleton-line" />
67
+ <Skeleton class="skeleton-line" />
68
+ <Skeleton class="skeleton-line" />
69
+ </div>
70
+ </Match>
71
+ <Match when={rows.length === 0}>
72
+ <EmptyState
73
+ title={props.emptyTitle ?? 'No rows found'}
74
+ description={
75
+ props.emptyDescription ??
76
+ 'Try changing filters or adding new records.'
77
+ }
78
+ />
79
+ </Match>
80
+ </Case>
81
+ );
82
82
  }
@@ -0,0 +1,35 @@
1
+ import { Browser } from "playwright-core";
2
+ //#region src/bin/verify-hydration.d.ts
3
+ type CliIo = Pick<Console, "error" | "log">;
4
+ interface ParsedVerifyHydrationArgs {
5
+ cwd: string;
6
+ outputDir: string;
7
+ routes: string[];
8
+ rootSelector: string;
9
+ buildScript: string;
10
+ build: boolean;
11
+ timeoutMs: number;
12
+ browserChannel?: string;
13
+ help: boolean;
14
+ errors: string[];
15
+ }
16
+ interface RouteMetadata {
17
+ path: string;
18
+ filePath: string;
19
+ status?: string;
20
+ }
21
+ interface StaticOutputServer {
22
+ origin: string;
23
+ close(): Promise<void>;
24
+ }
25
+ interface VerifyHydrationDeps {
26
+ runBuild?: (cwd: string, script: string) => Promise<void>;
27
+ launchBrowser?: (channel?: string) => Promise<Browser>;
28
+ startServer?: (outputDir: string, routes: readonly RouteMetadata[]) => Promise<StaticOutputServer>;
29
+ }
30
+ declare function parseVerifyHydrationArgs(args: string[], defaultCwd?: string): ParsedVerifyHydrationArgs;
31
+ declare function startStaticOutputServer(outputDir: string, routes: readonly RouteMetadata[]): Promise<StaticOutputServer>;
32
+ declare function verifyHydrationRoutes(browser: Browser, origin: string, routes: readonly RouteMetadata[], rootSelector: string, timeoutMs: number): Promise<string[]>;
33
+ declare function runVerifyHydrationCli(args?: string[], deps?: VerifyHydrationDeps, io?: CliIo): Promise<number>;
34
+ //#endregion
35
+ export { parseVerifyHydrationArgs, runVerifyHydrationCli, startStaticOutputServer, verifyHydrationRoutes };