1
1
import { buildInfo } from "api/queries/buildInfo" ;
2
- import { provisionerDaemonGroups } from "api/queries/organizations" ;
2
+ import {
3
+ provisionerDaemonGroups ,
4
+ provisionerJobs ,
5
+ } from "api/queries/organizations" ;
6
+ import type { Organization } from "api/typesGenerated" ;
7
+ import { Avatar } from "components/Avatar/Avatar" ;
8
+ import { Badge } from "components/Badge/Badge" ;
9
+ import { Button } from "components/Button/Button" ;
3
10
import { EmptyState } from "components/EmptyState/EmptyState" ;
11
+ import { Link } from "components/Link/Link" ;
12
+ import {
13
+ Table ,
14
+ TableBody ,
15
+ TableCell ,
16
+ TableHead ,
17
+ TableHeader ,
18
+ TableRow ,
19
+ } from "components/Table/Table" ;
20
+ import { TableEmpty } from "components/TableEmpty/TableEmpty" ;
21
+ import { TableLoader } from "components/TableLoader/TableLoader" ;
22
+ import { TabLink , Tabs , TabsList } from "components/Tabs/Tabs" ;
23
+ import {
24
+ Tooltip ,
25
+ TooltipContent ,
26
+ TooltipProvider ,
27
+ TooltipTrigger ,
28
+ } from "components/Tooltip/Tooltip" ;
4
29
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata" ;
30
+ import { BanIcon } from "lucide-react" ;
5
31
import { useDashboard } from "modules/dashboard/useDashboard" ;
6
32
import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout" ;
7
33
import type { FC } from "react" ;
8
34
import { Helmet } from "react-helmet-async" ;
9
35
import { useQuery } from "react-query" ;
10
36
import { useParams } from "react-router-dom" ;
37
+ import { docs } from "utils/docs" ;
11
38
import { pageTitle } from "utils/page" ;
12
- import { OrganizationProvisionersPageView } from "./OrganizationProvisionersPageView " ;
39
+ import { relativeTime } from "utils/time " ;
13
40
14
41
const OrganizationProvisionersPage : FC = ( ) => {
15
- const { organization : organizationName } = useParams ( ) as {
16
- organization : string ;
17
- } ;
42
+ // const { organization: organizationName } = useParams() as {
43
+ // organization: string;
44
+ // };
18
45
const { organization } = useOrganizationSettings ( ) ;
19
- const { entitlements } = useDashboard ( ) ;
20
- const { metadata } = useEmbeddedMetadata ( ) ;
21
- const buildInfoQuery = useQuery ( buildInfo ( metadata [ "build-info" ] ) ) ;
22
- const provisionersQuery = useQuery ( provisionerDaemonGroups ( organizationName ) ) ;
46
+ // const { entitlements } = useDashboard();
47
+ // const { metadata } = useEmbeddedMetadata();
48
+ // const buildInfoQuery = useQuery(buildInfo(metadata["build-info"]));
49
+ // const provisionersQuery = useQuery(provisionerDaemonGroups(organizationName));
23
50
24
51
if ( ! organization ) {
25
52
return < EmptyState message = "Organization not found" /> ;
@@ -35,14 +62,124 @@ const OrganizationProvisionersPage: FC = () => {
35
62
) }
36
63
</ title >
37
64
</ Helmet >
38
- < OrganizationProvisionersPageView
39
- showPaywall = { ! entitlements . features . multiple_organizations . enabled }
40
- error = { provisionersQuery . error }
41
- buildInfo = { buildInfoQuery . data }
42
- provisioners = { provisionersQuery . data }
43
- />
65
+
66
+ < div className = "flex flex-col gap-12" >
67
+ < header className = "flex flex-row items-baseline justify-between" >
68
+ < div className = "flex flex-col gap-2" >
69
+ < h1 className = "text-3xl m-0" > Provisioners</ h1 >
70
+ </ div >
71
+ </ header >
72
+
73
+ < main >
74
+ < Tabs active = "jobs" >
75
+ < TabsList >
76
+ < TabLink value = "jobs" to = "?tab=jobs" >
77
+ Jobs
78
+ </ TabLink >
79
+ < TabLink value = "daemons" to = "?tab=daemons" >
80
+ Daemons
81
+ </ TabLink >
82
+ </ TabsList >
83
+ </ Tabs >
84
+
85
+ < div className = "mt-6" >
86
+ < JobsTabContent org = { organization } />
87
+ </ div >
88
+ </ main >
89
+ </ div >
44
90
</ >
45
91
) ;
46
92
} ;
47
93
94
+ type JobsTabContentProps = {
95
+ org : Organization ;
96
+ } ;
97
+
98
+ const JobsTabContent : FC < JobsTabContentProps > = ( { org } ) => {
99
+ const { organization } = useOrganizationSettings ( ) ;
100
+ const { data : jobs , isLoadingError } = useQuery ( provisionerJobs ( org . id ) ) ;
101
+
102
+ return (
103
+ < section className = "flex flex-col gap-8" >
104
+ < p className = "text-sm text-content-secondary m-0 mt-2" >
105
+ Provisioner Jobs are the individual tasks assigned to Provisioners when
106
+ the workspaces are being built.{ " " }
107
+ < Link href = { docs ( "/admin/provisioners" ) } > View docs</ Link >
108
+ </ p >
109
+
110
+ < Table >
111
+ < TableHeader >
112
+ < TableRow >
113
+ < TableHead > Last seen</ TableHead >
114
+ < TableHead > Type</ TableHead >
115
+ < TableHead > Template</ TableHead >
116
+ < TableHead > Tags</ TableHead >
117
+ < TableHead > Status</ TableHead >
118
+ </ TableRow >
119
+ </ TableHeader >
120
+ < TableBody >
121
+ { jobs ? (
122
+ jobs . length > 0 ? (
123
+ jobs . map ( ( { metadata, ...job } ) => {
124
+ if ( ! metadata ) {
125
+ throw new Error (
126
+ `Metadata is required but it is missing in the job ${ job . id } ` ,
127
+ ) ;
128
+ }
129
+ return (
130
+ < TableRow key = { job . id } >
131
+ < TableCell className = "[&:first-letter]:uppercase" >
132
+ { relativeTime ( new Date ( job . created_at ) ) }
133
+ </ TableCell >
134
+ < TableCell >
135
+ < Badge size = "sm" > { job . type } </ Badge >
136
+ </ TableCell >
137
+ < TableCell >
138
+ < div className = "flex items-center gap-1" >
139
+ < Avatar
140
+ variant = "icon"
141
+ src = { metadata . template_icon . icon }
142
+ fallback = { template . display_name || template . name }
143
+ />
144
+ { metadata . template_display_name ??
145
+ metadata . template_name }
146
+ </ div >
147
+ </ TableCell >
148
+ < TableCell >
149
+ < Badge size = "sm" > [foo=bar]</ Badge >
150
+ </ TableCell >
151
+ < TableCell > Completed</ TableCell >
152
+ < TableCell className = "text-right" >
153
+ < TooltipProvider >
154
+ < Tooltip >
155
+ < TooltipTrigger asChild >
156
+ < Button
157
+ aria-label = "Cancel job"
158
+ size = "icon"
159
+ variant = "outline"
160
+ >
161
+ < BanIcon />
162
+ </ Button >
163
+ </ TooltipTrigger >
164
+ < TooltipContent > Cancel job</ TooltipContent >
165
+ </ Tooltip >
166
+ </ TooltipProvider >
167
+ </ TableCell >
168
+ </ TableRow >
169
+ ) ;
170
+ } )
171
+ ) : (
172
+ < TableEmpty message = "No provisioner jobs found" />
173
+ )
174
+ ) : isLoadingError ? (
175
+ < TableEmpty message = "Error loading the provisioner jobs" />
176
+ ) : (
177
+ < TableLoader />
178
+ ) }
179
+ </ TableBody >
180
+ </ Table >
181
+ </ section >
182
+ ) ;
183
+ } ;
184
+
48
185
export default OrganizationProvisionersPage ;
0 commit comments