Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add link to provisioner jobs and daemons#17509

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
BrunoQuaresma merged 6 commits intomainfrombq/link-provisioners
Apr 28, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
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
27 changes: 14 additions & 13 deletionssite/src/api/api.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -396,7 +396,17 @@ export class MissingBuildParameters extends Error {
}

export type GetProvisionerJobsParams = {
status?: TypesGen.ProvisionerJobStatus;
status?: string;
limit?: number;
// IDs separated by comma
ids?: string;
};

export type GetProvisionerDaemonsParams = {
// IDs separated by comma
ids?: string;
// Stringified JSON Object
tags?: string;
limit?: number;
};

Expand DownExpand Up@@ -711,22 +721,13 @@ class ApiMethods {
return response.data;
};

/**
* @param organization Can be the organization's ID or name
* @param tags to filter provisioner daemons by.
*/
getProvisionerDaemonsByOrganization = async (
organization: string,
tags?:Record<string, string>,
params?:GetProvisionerDaemonsParams,
): Promise<TypesGen.ProvisionerDaemon[]> => {
const params = new URLSearchParams();

if (tags) {
params.append("tags", JSON.stringify(tags));
}

const response = await this.axios.get<TypesGen.ProvisionerDaemon[]>(
`/api/v2/organizations/${organization}/provisionerdaemons?${params}`,
`/api/v2/organizations/${organization}/provisionerdaemons`,
{ params },
);
return response.data;
};
Expand Down
17 changes: 11 additions & 6 deletionssite/src/api/queries/organizations.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
import { API, type GetProvisionerJobsParams } from "api/api";
import {
API,
type GetProvisionerDaemonsParams,
type GetProvisionerJobsParams,
} from "api/api";
import type {
CreateOrganizationRequest,
GroupSyncSettings,
Expand DownExpand Up@@ -164,16 +168,17 @@ export const organizations = () => {

export const getProvisionerDaemonsKey = (
organization: string,
tags?:Record<string, string>,
) => ["organization", organization,tags,"provisionerDaemons"];
params?:GetProvisionerDaemonsParams,
) => ["organization", organization, "provisionerDaemons", params];

export const provisionerDaemons = (
organization: string,
tags?:Record<string, string>,
params?:GetProvisionerDaemonsParams,
) => {
return {
queryKey: getProvisionerDaemonsKey(organization, tags),
queryFn: () => API.getProvisionerDaemonsByOrganization(organization, tags),
queryKey: getProvisionerDaemonsKey(organization, params),
queryFn: () =>
API.getProvisionerDaemonsByOrganization(organization, params),
};
};

Expand Down
3 changes: 2 additions & 1 deletionsite/src/components/Button/Button.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ import { forwardRef } from "react";
import { cn } from "utils/cn";

export const buttonVariants = cva(
`inline-flex items-center justify-center gap-1 whitespace-nowrap
`inline-flex items-center justify-center gap-1 whitespace-nowrap font-sans
border-solid rounded-md transition-colors
text-sm font-semibold font-medium cursor-pointer no-underline
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-content-link
Expand All@@ -30,6 +30,7 @@ export const buttonVariants = cva(
size: {
lg: "min-w-20 h-10 px-3 py-2 [&_svg]:size-icon-lg",
sm: "min-w-20 h-8 px-2 py-1.5 text-xs [&_svg]:size-icon-sm",
xs: "min-w-8 py-1 px-2 text-2xs rounded-md",
icon: "size-8 px-1.5 [&_svg]:size-icon-sm",
"icon-lg": "size-10 px-2 [&_svg]:size-icon-lg",
},
Expand Down
2 changes: 1 addition & 1 deletionsite/src/pages/CreateTokenPage/CreateTokenForm.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,6 @@ export const CreateTokenForm: FC<CreateTokenFormProps> = ({

{lifetimeDays === "custom" && (
<TextField
data-chromatic="ignore"
type="date"
label="Expires on"
defaultValue={dayjs().add(expDays, "day").format("YYYY-MM-DD")}
Expand All@@ -130,6 +129,7 @@ export const CreateTokenForm: FC<CreateTokenFormProps> = ({
setExpDays(lt);
}}
inputProps={{
"data-chromatic": "ignore",
min: dayjs().add(1, "day").format("YYYY-MM-DD"),
max: maxTokenLifetime
? dayjs()
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,7 +15,7 @@ const meta: Meta<typeof PermissionPillsList> = {
],
parameters: {
chromatic: {
diffThreshold: 0.5,
diffThreshold: 0.6,
},
},
};
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,17 +15,19 @@ import {
ProvisionerTruncateTags,
} from "modules/provisioners/ProvisionerTags";
import { type FC, useState } from "react";
import { Link as RouterLink } from "react-router-dom";
import { cn } from "utils/cn";
import { relativeTime } from "utils/time";
import { CancelJobButton } from "./CancelJobButton";

type JobRowProps = {
job: ProvisionerJob;
defaultIsOpen: boolean;
};

export const JobRow: FC<JobRowProps> = ({ job }) => {
export const JobRow: FC<JobRowProps> = ({ job, defaultIsOpen = false }) => {
const metadata = job.metadata;
const [isOpen, setIsOpen] = useState(false);
const [isOpen, setIsOpen] = useState(defaultIsOpen);
const queue = {
size: job.queue_size,
position: job.queue_position,
Expand DownExpand Up@@ -114,19 +116,36 @@ export const JobRow: FC<JobRowProps> = ({ job }) => {
: "[]"}
</dd>

<dt>Completed by provisioner:</dt>
<dd>{job.worker_id}</dd>
{job.worker_id && (
<>
<dt>Completed by provisioner:</dt>
<dd className="flex items-center gap-2">
<span>{job.worker_id}</span>
<Button size="xs" variant="outline" asChild>
<RouterLink
to={`../provisioners?${new URLSearchParams({ ids: job.worker_id })}`}
>
View provisioner
</RouterLink>
</Button>
</dd>
</>
)}

<dt>Associated workspace:</dt>
<dd>{job.metadata.workspace_name ?? "null"}</dd>

<dt>Creation time:</dt>
<dd data-chromatic="ignore">{job.created_at}</dd>

<dt>Queue:</dt>
<dd>
{job.queue_position}/{job.queue_size}
</dd>
{job.queue_position > 0 && (
<>
<dt>Queue:</dt>
<dd>
{job.queue_position}/{job.queue_size}
</dd>
</>
)}

<dt>Tags:</dt>
<dd>
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,18 +11,18 @@ const OrganizationProvisionerJobsPage: FC = () => {
const { organization } = useOrganizationSettings();
const [searchParams, setSearchParams] = useSearchParams();
const filter = {
status: searchParams.get("status") || "",
status: searchParams.get("status") ?? "",
ids: searchParams.get("ids") ?? "",
};
const queryParams = {
...filter,
limit: 100,
} as GetProvisionerJobsParams;
const {
data: jobs,
isLoadingError,
refetch,
} = useQuery({
...provisionerJobs(organization?.id || "", queryParams),
...provisionerJobs(organization?.id ?? "", {
...filter,
limit: 100,
}),
enabled: organization !== undefined,
});

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ const meta: Meta<typeof OrganizationProvisionerJobsPageView> = {
args: {
organization: MockOrganization,
jobs: MockProvisionerJobs,
filter: { status: "" },
filter: { status: "", ids: "" },
onRetry: fn(),
},
};
Expand DownExpand Up@@ -81,8 +81,8 @@ export const Empty: Story = {
export const OnFilter: Story = {
render: function FilterWithState({ ...args }) {
const [jobs, setJobs] = useState<ProvisionerJob[]>([]);
const [filter, setFilter] = useState({ status: "pending" });
const handleFilterChange = (newFilter: { status: string }) => {
const [filter, setFilter] = useState({ status: "pending", ids: "" });
const handleFilterChange = (newFilter: { status: string; ids: string }) => {
setFilter(newFilter);
const filteredJobs = MockProvisionerJobs.filter((job) =>
newFilter.status ? job.status === newFilter.status : true,
Expand All@@ -109,3 +109,13 @@ export const OnFilter: Story = {
await userEvent.click(option);
},
};

export const FilterByID: Story = {
args: {
jobs: [MockProvisionerJob],
filter: {
ids: MockProvisionerJob.id,
status: "",
},
},
};
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@ import type {
ProvisionerJob,
ProvisionerJobStatus,
} from "api/typesGenerated";
import { Badge } from "components/Badge/Badge";
import { Button } from "components/Button/Button";
import { EmptyState } from "components/EmptyState/EmptyState";
import { Link } from "components/Link/Link";
Expand DownExpand Up@@ -33,6 +34,13 @@ import {
TableHeader,
TableRow,
} from "components/Table/Table";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { XIcon } from "lucide-react";
import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { docs } from "utils/docs";
Expand DownExpand Up@@ -64,6 +72,7 @@ const StatusFilters: ProvisionerJobStatus[] = [

type JobProvisionersFilter = {
status: string;
ids: string;
};

type OrganizationProvisionerJobsPageViewProps = {
Expand DownExpand Up@@ -110,30 +119,62 @@ const OrganizationProvisionerJobsPageView: FC<
</SettingsHeaderDescription>
</SettingsHeader>

<Select
value={filter.status}
onValueChange={(status) => {
onFilterChange({ status: status as ProvisionerJobStatus });
}}
>
<SelectTrigger className="w-[180px]" data-testid="status-filter">
<SelectValue placeholder="All statuses" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{StatusFilters.map((status) => (
<SelectItem key={status} value={status}>
<StatusIndicator variant={variantByStatus[status]}>
<StatusIndicatorDot />
<span className="block first-letter:uppercase">
{status}
</span>
</StatusIndicator>
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<div className="flex items-center gap-2">
{filter.ids && (
<div className="relative">
<Badge className="h-10 text-sm pl-3 pr-10 font-mono">
{filter.ids}
</Badge>
<div className="size-10 flex items-center justify-center absolute top-0 right-0">
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
size="icon"
variant="subtle"
onClick={() => {
onFilterChange({ ...filter, ids: "" });
}}
>
<span className="sr-only">Clear ID</span>
<XIcon />
</Button>
</TooltipTrigger>
<TooltipContent>Clear ID</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</div>
)}

<Select
value={filter.status}
onValueChange={(status) => {
onFilterChange({
...filter,
status,
});
}}
>
<SelectTrigger className="w-[180px]" data-testid="status-filter">
<SelectValue placeholder="All statuses" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{StatusFilters.map((status) => (
<SelectItem key={status} value={status}>
<StatusIndicator variant={variantByStatus[status]}>
<StatusIndicatorDot />
<span className="block first-letter:uppercase">
{status}
</span>
</StatusIndicator>
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>

<Table className="mt-6">
<TableHeader>
Expand All@@ -149,7 +190,13 @@ const OrganizationProvisionerJobsPageView: FC<
<TableBody>
{jobs ? (
jobs.length > 0 ? (
jobs.map((j) => <JobRow key={j.id} job={j} />)
jobs.map((j) => (
<JobRow
defaultIsOpen={filter.ids.includes(j.id)}
key={j.id}
job={j}
/>
))
) : (
<TableRow>
<TableCell colSpan={999}>
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp