8000 feat: display provisioner jobs and daemons for an organization by BrunoQuaresma · Pull Request #16532 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

feat: display provisioner jobs and daemons for an organization #16532

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 22 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b6430bb
Set base structure to display the provisioner jobs
BrunoQuaresma Feb 5, 2025
5d7d58f
Merge branch 'main' of https://github.com/coder/coder into bq/refacto…
BrunoQuaresma Feb 7, 2025
643c362
[WIP]: Load data and display them in the table
BrunoQuaresma Feb 7, 2025
f9db209
Merge branch 'main' of https://github.com/coder/coder into bq/refacto…
BrunoQuaresma Feb 10, 2025
6e967f1
Update table to use API data
BrunoQuaresma Feb 10, 2025
943b7d7
Finish job structure
BrunoQuaresma Feb 10, 2025
2bc6ccf
Display tiny alert for error
BrunoQuaresma Feb 10, 2025
71f4fe5
Fix tags
BrunoQuaresma Feb 10, 2025
f027485
Add daemons page
BrunoQuaresma Feb 10, 2025
dcf8140
Merge branch 'main' of https://github.com/coder/coder into bq/refacto…
BrunoQuaresma Feb 10, 2025
994e186
Merge branch 'main' of https://github.com/coder/coder into bq/refacto…
BrunoQuaresma Feb 11, 2025
3083cef
Merge branch 'main' of https://github.com/coder/coder into bq/refacto…
BrunoQuaresma Feb 11, 2025
d66141e
Display all daemon data from server
BrunoQuaresma Feb 11, 2025
49a7ec7
Remove unused imports
BrunoQuaresma Feb 11, 2025
ffee2ed
Run fmt
BrunoQuaresma Feb 11, 2025
7802636
Add cancel provisioner job
BrunoQuaresma Feb 12, 2025
4f9030f
Run fmt
BrunoQuaresma Feb 12, 2025
22dc7be
Merge branch 'main' of https://github.com/coder/coder into bq/refacto…
BrunoQuaresma Feb 13, 2025
0ff39e5
Merge branch 'main' of https://github.com/coder/coder into bq/refacto…
BrunoQuaresma Feb 14, 2025
5953960
Apply PR reviews
BrunoQuaresma Feb 14, 2025
aabf8df
FMT
BrunoQuaresma Feb 14, 2025
ed61ce7
Reset devcontainer.json
BrunoQuaresma Feb 18, 2025
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
Prev Previous commit
Next Next commit
[WIP]: Load data and display them in the table
  • Loading branch information
BrunoQuaresma committed Feb 7, 2025
commit 643c3626ea522c584bd4f40bd86d14d42acbdbee
11 changes: 10 additions & 1 deletion .devcontainer/devcontainer.json
< 10000 /tr>
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,14 @@
}
},
// SYS_PTRACE to enable go debugging
"runArgs": ["--cap-add=SYS_PTRACE"]
"runArgs": [
"--cap-add=SYS_PTRACE"
],
"customizations": {
"vscode": {
"extensions": [
"biomejs.biome"
]
}
}
}
7 changes: 7 additions & 0 deletions site/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2295,6 +2295,13 @@ class ApiMethods {
);
return res.data;
};

getProvisionerJobs = async (orgId: string) => {
const res = await this.axios.get<TypesGen.ProvisionerJob[]>(
`/api/v2/organizations/${orgId}/provisionerjobs`,
);
return res.data;
};
}

// This is a hard coded CSRF token/cookie pair for local development. In prod,
Expand Down
7 changes: 7 additions & 0 deletions site/src/api/queries/organizations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,13 @@ export const organizationPermissions = (organizationId: string | undefined) => {
};
};

export const provisionerJobs = (orgId: string) => {
return {
queryKey: ["organization", orgId, "provisionerjobs"],
queryFn: () => API.getProvisionerJobs(orgId),
};
};

/**
* Fetch permissions for all provided organizations.
*
Expand Down
96 changes: 0 additions & 96 deletions site/src/pages/DeploymentSettingsPage/ProvisionersPage/ProvisionersPage.tsx
< 8000 /span>

This file was deleted.

167 changes: 152 additions & 15 deletions site/src/pages/OrganizationSettingsPage/OrganizationProvisionersPage.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
import { buildInfo } from "api/queries/buildInfo";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps I'm missing some context, could you explain why are we removing these pages? Will they be replaced now?

PS. It would be convenient to add Changes: to the PR description.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they will be replaced.

import { provisionerDaemonGroups } from "api/queries/organizations";
import {
provisionerDaemonGroups,
provisionerJobs,
} from "api/queries/organizations";
import type { Organization } from "api/typesGenerated";
import { Avatar } from "components/Avatar/Avatar";
import { Badge } from "components/Badge/Badge";
import { Button } from "components/Button/Button";
import { EmptyState } from "components/EmptyState/EmptyState";
import { Link } from "components/Link/Link";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "components/Table/Table";
import { TableEmpty } from "components/TableEmpty/TableEmpty";
import { TableLoader } from "components/TableLoader/TableLoader";
import { TabLink, Tabs, TabsList } from "components/Tabs/Tabs";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
import { BanIcon } from "lucide-react";
import { useDashboard } from "modules/dashboard/useDashboard";
import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout";
import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useQuery } from "react-query";
import { useParams } from "react-router-dom";
import { docs } from "utils/docs";
import { pageTitle } from "utils/page";
import { OrganizationProvisionersPageView } from "./OrganizationProvisionersPageView";
import { relativeTime } from "utils/time";

const OrganizationProvisionersPage: FC = () => {
const { organization: organizationName } = useParams() as {
organization: string;
};
// const { organization: organizationName } = useParams() as {
// organization: string;
// };
const { organization } = useOrganizationSettings();
const { entitlements } = useDashboard();
const { metadata } = useEmbeddedMetadata();
const buildInfoQuery = useQuery(buildInfo(metadata["build-info"]));
const provisionersQuery = useQuery(provisionerDaemonGroups(organizationName));
// const { entitlements } = useDashboard();
// const { metadata } = useEmbeddedMetadata();
// const buildInfoQuery = useQuery(buildInfo(metadata["build-info"]));
// const provisionersQuery = useQuery(provisionerDaemonGroups(organizationName));

if (!organization) {
return <EmptyState message="Organization not found" />;
Expand All @@ -35,14 +62,124 @@ const OrganizationProvisionersPage: FC = () => {
)}
</title>
</Helmet>
<OrganizationProvisionersPageView
showPaywall={!entitlements.features.multiple_organizations.enabled}
error={provisionersQuery.error}
buildInfo={buildInfoQuery.data}
provisioners={provisionersQuery.data}
/>

<div className="flex flex-col gap-12">
<header className="flex flex-row items-baseline justify-between">
<div className="flex flex-col gap-2">
<h1 className="text-3xl m-0">Provisioners</h1>
</div>
</header>

<main>
<Tabs active="jobs">
<TabsList>
<TabLink value="jobs" to="?tab=jobs">
Jobs
</TabLink>
<TabLink value="daemons" to="?tab=daemons">
Daemons
</TabLink>
</TabsList>
</Tabs>

<div className="mt-6">
<JobsTabContent org={organization} />
</div>
</main>
</div>
</>
);
};

type JobsTabContentProps = {
org: Organization;
};

const JobsTabContent: FC<JobsTabContentProps> = ({ org }) => {
const { organization } = useOrganizationSettings();
const { data: jobs, isLoadingError } = useQuery(provisionerJobs(org.id));

return (
<section className="flex flex-col gap-8">
<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>Last seen</TableHead>
<TableHead>Type</TableHead>
<TableHead>Template</TableHead>
<TableHead>Tags</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{jobs ? (
jobs.length > 0 ? (
jobs.map(({ metadata, ...job }) => {
if (!metadata) {
throw new Error(
`Metadata is required but it is missing in the job ${job.id}`,
);
}
return (
<TableRow key={job.id}>
<TableCell className="[&:first-letter]:uppercase">
{relativeTime(new Date(job.created_at))}
</TableCell>
<TableCell>
<Badge size="sm">{job.type}</Badge>
</TableCell>
<TableCell>
<div className="flex items-center gap-1">
<Avatar
variant="icon"
src={metadata.template_icon.icon}
fallback={template.display_name || template.name}
/>
{metadata.template_display_name ??
metadata.template_name}
</div>
</TableCell>
<TableCell>
<Badge size="sm">[foo=bar]</Badge>
</TableCell>
<TableCell>Completed</TableCell>
<TableCell className="text-right">
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
aria-label="Cancel job"
size="icon"
variant="outline"
>
<BanIcon />
</Button>
</TooltipTrigger>
<TooltipContent>Cancel job</TooltipContent>
</Tooltip>
</TooltipProvider>
</TableCell>
</TableRow>
);
})
) : (
<TableEmpty message="No provisioner jobs found" />
)
) : isLoadingError ? (
<TableEmpty message="Error loading the provisioner jobs" />
) : (
<TableLoader />
)}
</TableBody>
</Table>
</section>
);
};

export default OrganizationProvisionersPage;
Loading
0