10000 feat: add provisioner jobs into the UI by BrunoQuaresma · Pull Request #16867 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

feat: add provisioner jobs into the UI #16867

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: add provisioner jobs
  • Loading branch information
BrunoQuaresma committed Mar 6, 2025
commit 2e1ebb3bb44367b9642253fdd766ad842a9df73d
2 changes: 1 addition & 1 deletion site/src/components/Badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const badgeVariants = cva(
variants: {
variant: {
default:
"border-transparent bg-surface-secondary text-content-secondary shadow hover:bg-surface-tertiary",
"border-transparent bg-surface-secondary text-content-secondary shadow",
},
size: {
sm: "text-2xs font-regular",
Expand Down
17 changes: 12 additions & 5 deletions site/src/modules/management/OrganizationSidebarView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,18 @@ const OrganizationSettingsNavigation: FC<
)}
{orgPermissions.viewProvisioners &&
orgPermissions.viewProvisionerJobs && (
<SettingsSidebarNavItem
href={urlForSubpage(organization.name, "provisioners")}
>
Provisioners
</SettingsSidebarNavItem>
<>
<SettingsSidebarNavItem
href={urlForSubpage(organization.name, "provisioners")}
>
Provisioners
</SettingsSidebarNavItem>
<SettingsSidebarNavItem
href={urlForSubpage(organization.name, "provisioner-jobs")}
>
Provisioner Jobs
</SettingsSidebarNavItem>
</>
)}
{orgPermissions.viewIdpSyncSettings && (
<SettingsSidebarNavItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,70 +28,87 @@ import { CancelJobButton } from "./CancelJobButton";
import { DataGrid } from "./DataGrid";
import { JobStatusIndicator } from "./JobStatusIndicator";
import { Tag, Tags, TruncateTags } from "./Tags";
import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout";
import { Helmet } from "react-helmet-async";
import { pageTitle } from "utils/page";

type ProvisionerJobsPageProps = {
orgId: string;
};
const ProvisionerJobsPage: FC = () => {
const { organization } = useOrganizationSettings();

if (!organization) {
return <EmptyState message="Organization not found" />;
}

export const ProvisionerJobsPage: FC<ProvisionerJobsPageProps> = ({
orgId,
}) => {
const {
data: jobs,
isLoadingError,
refetch,
} = useQuery(provisionerJobs(orgId));
} = useQuery(provisionerJobs(organization?.id));

return (
<section className="flex flex-col gap-8">
<h2 className="sr-only">Provisioner jobs</h2>
<p className="text-sm text-content-secondary m-0 mt-2">
Provisioner Jobs are the individual tasks assigned to Provisioners when
the workspaces are being built.{" "}
<Link href={docs("/admin/provisioners")}>View docs</Link>
</p>

<Table>
<TableHeader>
<TableRow>
<TableHead>Created</TableHead>
<TableHead>Type</TableHead>
<TableHead>Template</TableHead>
<TableHead>Tags</TableHead>
<TableHead>Status</TableHead>
<TableHead />
</TableRow>
</TableHeader>
<TableBody>
{jobs ? (
jobs.length > 0 ? (
jobs.map((j) => <JobRow key={j.id} job={j} />)
<>
<Helmet>
<title>
{pageTitle(
"Provisioner Jobs",
organization.display_name || organization.name,
)}
</title>
</Helmet>
<section className="flex flex-col gap-8">
<header className="flex flex-row items-baseline justify-between">
<div className="flex flex-col gap-2">
<h1 className="text-3xl m-0">Provisioner Jobs</h1>
<p className="text-sm text-content-secondary m-0">
Provisioner Jobs are the individual tasks assigned to Provisioners
when the workspaces are being built.{" "}
<Link href={docs("/admin/provisioners")}>View docs</Link>
</p>
</div>
</header>

<Table>
<TableHeader>
<TableRow>
<TableHead>Created</TableHead>
<TableHead>Type</TableHead>
<TableHead>Template</TableHead>
<TableHead>Tags</TableHead>
<TableHead>Status</TableHead>
<TableHead />
</TableRow>
</TableHeader>
<TableBody>
{jobs ? (
jobs.length > 0 ? (
jobs.map((j) => <JobRow key={j.id} job={j} />)
) : (
<TableRow>
<TableCell colSpan={999}>
<EmptyState message="No provisioner jobs found" />
</TableCell>
</TableRow>
)
) : isLoadingError ? (
<TableRow>
<TableCell colSpan={999}>
<EmptyState
message="Error loading the provisioner jobs"
cta={<Button onClick={() => refetch()}>Retry</Button>}
/>
</TableCell>
</TableRow>
) : (
<TableRow>
<TableCell colSpan={999}>
<EmptyState message="No provisioner jobs found" />
<Loader />
</TableCell>
</TableRow>
)
) : isLoadingError ? (
<TableRow>
<TableCell colSpan={999}>
<EmptyState
message="Error loading the provisioner jobs"
cta={<Button onClick={() => refetch()}>Retry</Button>}
/>
</TableCell>
</TableRow>
) : (
<TableRow>
<TableCell colSpan={999}>
<Loader />
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</section>
)}
</TableBody>
</Table>
</section>
</>
);
};

Expand Down Expand Up @@ -133,20 +150,16 @@ const JobRow: FC<JobRowProps> = ({ job }) => {
<Badge size="sm">{job.type}</Badge>
</TableCell>
<TableCell>
{job.metadata.template_name ? (
<div className="flex items-center gap-1 whitespace-nowrap">
<Avatar
variant="icon"
src={metadata.template_icon}
fallback={
metadata.template_display_name || metadata.template_name
}
/>
{metadata.template_display_name ?? metadata.template_name}
</div>
) : (
<span className="whitespace-nowrap">Not linked</span>
)}
<div className="flex items-center gap-1 whitespace-nowrap">
<Avatar
variant="icon"
src={metadata.template_icon}
fallback={
metadata.template_display_name || metadata.template_name
}
/>
{metadata.template_display_name || metadata.template_name}
</div>
</TableCell>
<TableCell>
<TruncateTags tags={job.tags} />
Expand Down Expand Up @@ -213,3 +226,5 @@ const JobRow: FC<JobRowProps> = ({ job }) => {
</>
);
};

export default ProvisionerJobsPage;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { pageTitle } from "utils/page";
import { ProvisionerDaemonsPage } from "./ProvisionerDaemonsPage";
import { ProvisionerJobsPage } from "./ProvisionerJobsPage";
import ProvisionerJobsPage from "./ProvisionerJobsPage";

const ProvisionersPage: FC = () => {
const { organization, organizationPermissions } = useOrganizationSettings();
Expand Down Expand Up @@ -57,9 +57,7 @@ const ProvisionersPage: FC = () => {
</Tabs>

<div className="mt-6">
{tab.value === "jobs" && (
<ProvisionerJobsPage orgId={organization.id} />
)}
{tab.value === "jobs" && <ProvisionerJobsPage />}
{tab.value === "daemons" && (
<ProvisionerDaemonsPage orgId={organization.id} />
)}
Expand Down
10 changes: 10 additions & 0 deletions site/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ const ChangePasswordPage = lazy(
const IdpOrgSyncPage = lazy(
() => import("./pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage"),
);
const ProvisionerJobsPage = lazy(
() =>
import(
"./pages/OrganizationSettingsPage/ProvisionersPage/ProvisionerJobsPage"
),
);

const RoutesWithSuspense = () => {
return (
Expand Down Expand Up @@ -429,6 +435,10 @@ export const router = createBrowserRouter(
<Route path=":roleName" element={<CreateEditRolePage />} />
</Route>
<Route path="provisioners" element={<ProvisionersPage />} />
<Route
path="provisioner-jobs"
element={<ProvisionerJobsPage />}
/>
<Route path="idp-sync" element={<OrganizationIdPSyncPage />} />
<Route path="settings" element={<OrganizationSettingsPage />} />
</Route>
Expand Down
0