Skip to content

Commit d66141e

Browse files
committed
Display all daemon data from server
1 parent 3083cef commit d66141e

File tree

5 files changed

+212
-59
lines changed

5 files changed

+212
-59
lines changed

site/src/api/queries/organizations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {
33
AuthorizationResponse,
44
CreateOrganizationRequest,
55
GroupSyncSettings,
6+
ProvisionerDaemon,
67
RoleSyncSettings,
78
UpdateOrganizationRequest,
89
} from "api/typesGenerated";
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { FC, HTMLProps } from "react";
2+
import { cn } from "utils/cn";
3+
4+
export const DataGrid: FC<HTMLProps<HTMLDivElement>> = ({
5+
className,
6+
...props
7+
}) => {
8+
return (
9+
<div
10+
{...props}
11+
className={cn([
12+
"grid grid-cols-[auto_1fr] gap-x-4 items-center",
13+
"[&_span:nth-of-type(even)]:text-content-primary [&_span:nth-of-type(even)]:font-mono",
14+
"[&_span:nth-of-type(even)]:leading-[22px]",
15+
className,
16+
])}
17+
/>
18+
);
19+
};
20+
21+
export const DataGridSpace: FC<HTMLProps<HTMLDivElement>> = ({
22+
className,
23+
...props
24+
}) => {
25+
return (
26+
<div aria-hidden {...props} className={cn(["h-6 col-span-2", className])} />
27+
);
28+
};

site/src/pages/OrganizationSettingsPage/ProvisionersPage/ProvisionerDaemonsPage.tsx

Lines changed: 99 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import { provisionerDaemons } from "api/queries/organizations";
2-
import type {
3-
Organization,
4-
ProvisionerDaemon,
5-
ProvisionerDaemonStatus,
6-
} from "api/typesGenerated";
7-
import { Badge } from "components/Badge/Badge";
2+
import type { Organization, ProvisionerDaemon } from "api/typesGenerated";
83
import { Link } from "components/Link/Link";
94
import {
105
StatusIndicator,
@@ -20,14 +15,18 @@ import {
2015
TableRow,
2116
} from "components/Table/Table";
2217
import { TableEmpty } from "components/TableEmpty/TableEmpty";
23-
import { TableLoader } from "components/TableLoader/TableLoader";
2418
import { ChevronDownIcon, ChevronRightIcon } from "lucide-react";
2519
import { useState, type FC } from "react";
2620
import { useQuery } from "react-query";
2721
import { cn } from "utils/cn";
2822
import { docs } from "utils/docs";
2923
import { relativeTime } from "utils/time";
3024
import { JobStatusIndicator } from "./JobStatusIndicator";
25+
import { Avatar } from "components/Avatar/Avatar";
26+
import { DataGrid, DataGridSpace } from "./DataGrid";
27+
import { ShrinkTags, Tag, Tags } from "./Tags";
28+
import { Loader } from "components/Loader/Loader";
29+
import { EmptyState } from "components/EmptyState/EmptyState";
3130

3231
type ProvisionerDaemonsPageProps = {
3332
org: Organization;
@@ -36,9 +35,18 @@ type ProvisionerDaemonsPageProps = {
3635
export const ProvisionerDaemonsPage: FC<ProvisionerDaemonsPageProps> = ({
3736
org,
3837
}) => {
39-
const { data: daemons, isLoadingError } = useQuery(
40-
provisionerDaemons(org.id),
41-
);
38+
const { data: daemons, isLoadingError } = useQuery({
39+
...provisionerDaemons(org.id),
40+
select: (data) =>
41+
data.toSorted((a, b) => {
42+
if (!a.last_seen_at) return 1;
43+
if (!b.last_seen_at) return -1;
44+
return (
45+
new Date(b.last_seen_at).getTime() -
46+
new Date(a.last_seen_at).getTime()
47+
);
48+
}),
49+
});
4250

4351
return (
4452
<section className="flex flex-col gap-8">
@@ -69,12 +77,24 @@ export const ProvisionerDaemonsPage: FC<ProvisionerDaemonsPageProps> = ({
6977
daemons.length > 0 ? (
7078
daemons.map((d) => <DaemonRow key={d.id} daemon={d} />)
7179
) : (
72-
<TableEmpty message="No provisioner daemons found" />
80+
<TableRow>
81+
<TableCell colSpan={999}>
82+
<EmptyState message="No provisioner daemons found" />
83+
</TableCell>
84+
</TableRow>
7385
)
7486
) : isLoadingError ? (
75-
<TableEmpty message="Error loading the provisioner daemons" />
87+
<TableRow>
88+
<TableCell colSpan={999}>
89+
<EmptyState message="Error loading the provisioner daemons" />
90+
</TableCell>
91+
</TableRow>
7692
) : (
77-
<TableLoader />
93+
<TableRow>
94+
<TableCell colSpan={999}>
95+
<Loader />
96+
</TableCell>
97+
</TableRow>
7898
)}
7999
</TableBody>
80100
</Table>
@@ -116,39 +136,46 @@ const DaemonRow: FC<DaemonRowProps> = ({ daemon }) => {
116136
</span>
117137
</button>
118138
</TableCell>
119-
<TableCell>{daemon.name}</TableCell>
120-
<TableCell>Template</TableCell>
121139
<TableCell>
122-
<div className="flex items-center gap-1 flex-wrap">
123-
{Object.entries(daemon.tags).map(([k, v]) => (
124-
<Badge size="sm" key={k} className="whitespace-nowrap">
125-
[{k}
126-
{v && `=${v}`}]
127-
</Badge>
128-
))}
129-
</div>
140+
<span className="block whitespace-nowrap text-ellipsis overflow-hidden">
141+
{daemon.name}
142+
</span>
130143
</TableCell>
131144
<TableCell>
132-
<StatusIndicator
133-
size="sm"
134-
variant={statusIndicatorVariant(daemon.status)}
135-
>
145+
{daemon.current_job ? (
146+
<div className="flex items-center gap-1 whitespace-nowrap">
147+
<Avatar
148+
variant="icon"
149+
src={daemon.current_job.template_icon}
150+
fallback={
151+
daemon.current_job.template_display_name ||
152+
daemon.current_job.template_name
153+
}
154+
/>
155+
{daemon.current_job.template_display_name ??
156+
daemon.current_job.template_name}
157+
</div>
158+
) : (
159+
<span className="whitespace-nowrap">Not linked</span>
160+
)}
161+
</TableCell>
162+
<TableCell>
163+
<ShrinkTags tags={daemon.tags} />
164+
</TableCell>
165+
<TableCell>
166+
<StatusIndicator size="sm" variant={statusIndicatorVariant(daemon)}>
136167
<StatusIndicatorDot />
137-
<span className="[&:first-letter]:uppercase">{daemon.status}</span>
168+
<span className="[&:first-letter]:uppercase">
169+
{statusLabel(daemon)}
170+
</span>
138171
</StatusIndicator>
139172
</TableCell>
140173
</TableRow>
141174

142175
{isOpen && (
143176
<TableRow>
144177
<TableCell colSpan={999} className="p-4 border-t-0">
145-
<div
146-
className={cn([
147-
"grid grid-cols-[auto_1fr] gap-x-4 items-center",
148-
"[&_span:nth-child(even)]:text-content-primary [&_span:nth-child(even)]:font-mono",
149-
"[&_span:nth-child(even)]:leading-[22px]",
150-
])}
151-
>
178+
<DataGrid>
152179
<span>Last seen:</span>
153180
<span>{daemon.last_seen_at}</span>
154181

@@ -158,8 +185,19 @@ const DaemonRow: FC<DaemonRowProps> = ({ daemon }) => {
158185
<span>Version:</span>
159186
<span>{daemon.version}</span>
160187

188+
<span>Tags:</span>
189+
<span>
190+
<Tags>
191+
{Object.entries(daemon.tags).map(([key, value]) => (
192+
<Tag key={key} label={key} value={value} />
193+
))}
194+
</Tags>
195+
</span>
196+
161197
{daemon.current_job && (
162198
<>
199+
<DataGridSpace />
200+
163201
<span>Last job:</span>
164202
<span>{daemon.current_job.id}</span>
165203

@@ -172,6 +210,8 @@ const DaemonRow: FC<DaemonRowProps> = ({ daemon }) => {
172210

173211
{daemon.previous_job && (
174212
<>
213+
<DataGridSpace />
214+
175215
<span>Previous job:</span>
176216
<span>{daemon.previous_job.id}</span>
177217

@@ -181,7 +221,7 @@ const DaemonRow: FC<DaemonRowProps> = ({ daemon }) => {
181221
</span>
182222
</>
183223
)}
184-
</div>
224+
</DataGrid>
185225
</TableCell>
186226
</TableRow>
187227
)}
@@ -190,9 +230,13 @@ const DaemonRow: FC<DaemonRowProps> = ({ daemon }) => {
190230
};
191231

192232
function statusIndicatorVariant(
193-
status: ProvisionerDaemonStatus | null,
233+
daemon: ProvisionerDaemon,
194234
): StatusIndicatorProps["variant"] {
195-
switch (status) {
235+
if (daemon.previous_job && daemon.previous_job.status === "failed") {
236+
return "failed";
237+
}
238+
239+
switch (daemon.status) {
196240
case "idle":
197241
return "success";
198242
case "busy":
@@ -202,3 +246,20 @@ function statusIndicatorVariant(
202246
return "inactive";
203247
}
204248
}
249+
250+
function statusLabel(daemon: ProvisionerDaemon) {
251+
if (daemon.previous_job && daemon.previous_job.status === "failed") {
252+
return "Last job failed";
253+
}
254+
255+
switch (daemon.status) {
256+
case "idle":
257+
return "Idle";
258+
case "busy":
259+
return "Busy...";
260+
case "offline":
261+
return "Disconnected";
262+
case null:
263+
return "Unknown";
264+
}
265+
}

site/src/pages/OrganizationSettingsPage/ProvisionersPage/ProvisionerJobsPage.tsx

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
TableRow,
1414
} from "components/Table/Table";
1515
import { TableEmpty } from "components/TableEmpty/TableEmpty";
16-
import { TableLoader } from "components/TableLoader/TableLoader";
1716
import {
1817
Tooltip,
1918
TooltipContent,
@@ -32,6 +31,10 @@ import { cn } from "utils/cn";
3231
import { docs } from "utils/docs";
3332
import { relativeTime } from "utils/time";
3433
import { JobStatusIndicator } from "./JobStatusIndicator";
34+
import { DataGrid } from "./DataGrid";
35+
import { ShrinkTags, Tag, Tags } from "./Tags";
36+
import { Loader } from "components/Loader/Loader";
37+
import { EmptyState } from "components/EmptyState/EmptyState";
3538

3639
type ProvisionerJobsPageProps = {
3740
org: Organization;
@@ -64,12 +67,24 @@ export const ProvisionerJobsPage: FC<ProvisionerJobsPageProps> = ({ org }) => {
6467
jobs.length > 0 ? (
6568
jobs.map((j) => <JobRow key={j.id} job={j} />)
6669
) : (
67-
<TableEmpty message="No provisioner jobs found" />
70+
<TableRow>
71+
<TableCell colSpan={999}>
72+
<EmptyState message="No provisioner jobs found" />
73+
</TableCell>
74+
</TableRow>
6875
)
6976
) : isLoadingError ? (
70-
<TableEmpty message="Error loading the provisioner jobs" />
77+
<TableRow>
78+
<TableCell colSpan={999}>
79+
<EmptyState message="Error loading the provisioner jobs" />
80+
</TableCell>
81+
</TableRow>
7182
) : (
72-
<TableLoader />
83+
<TableRow>
84+
<TableCell colSpan={999}>
85+
<Loader />
86+
</TableCell>
87+
</TableRow>
7388
)}
7489
</TableBody>
7590
</Table>
@@ -127,18 +142,11 @@ const JobRow: FC<JobRowProps> = ({ job }) => {
127142
{metadata.template_display_name ?? metadata.template_name}
128143
</div>
129144
) : (
130-
"Not linked to any template"
145+
<span className="whitespace-nowrap">Not linked</span>
131146
)}
132147
</TableCell>
133148
<TableCell>
134-
<div className="flex items-center gap-1 flex-wrap">
135-
{Object.entries(job.tags).map(([k, v]) => (
136-
<Badge size="sm" key={k} className="whitespace-nowrap">
137-
[{k}
138-
{v && `=${v}`}]
139-
</Badge>
140-
))}
141-
</div>
149+
<ShrinkTags tags={job.tags} />
142150
</TableCell>
143151
<TableCell>
144152
<JobStatusIndicator job={job} />
@@ -176,13 +184,7 @@ const JobRow: FC<JobRowProps> = ({ job }) => {
176184
<span className="[&:first-letter]:uppercase">{job.error}</span>
177185
</div>
178186
)}
179-
<div
180-
className={cn([
181-
"grid grid-cols-[auto_1fr] gap-x-4 items-center",
182-
"[&_span:nth-child(even)]:text-content-primary [&_span:nth-child(even)]:font-mono",
183-
"[&_span:nth-child(even)]:leading-[22px]",
184-
])}
185-
>
187+
<DataGrid>
186188
<span>Job ID:</span>
187189
<span>{job.id}</span>
188190

@@ -206,7 +208,16 @@ const JobRow: FC<JobRowProps> = ({ job }) => {
206208
<span>
207209
{job.queue_position}/{job.queue_size}
208210
</span>
209-
</div>
211+
212+
<span>Tags:</span>
213+
<span>
214+
<Tags>
215+
{Object.entries(job.tags).map(([key, value]) => (
216+
<Tag key={key} label={key} value={value} />
217+
))}
218+
</Tags>
219+
</span>
220+
</DataGrid>
210221
</TableCell>
211222
</TableRow>
212223
)}

0 commit comments

Comments
 (0)