mirror of
https://github.com/moghtech/komodo.git
synced 2026-04-29 21:27:26 -05:00
* refactor listener api implementation for Gitlab integration * version 1.16.3 * builder delete id link cleanup * refactor and add "__ALL__" branch to avoid branch filtering * frontend config the webhook url * action webhook config * clean up webhook url copy * add __ALL__ branch switch for Actions / Procedures
1158 lines
33 KiB
TypeScript
1158 lines
33 KiB
TypeScript
import {
|
|
ConfigInput,
|
|
ConfigItem,
|
|
ConfigSwitch,
|
|
WebhookBuilder,
|
|
} from "@components/config/util";
|
|
import { Section } from "@components/layouts";
|
|
import {
|
|
useLocalStorage,
|
|
useRead,
|
|
useWebhookIdOrName,
|
|
useWebhookIntegrations,
|
|
useWrite,
|
|
} from "@lib/hooks";
|
|
import { Types } from "komodo_client";
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@ui/card";
|
|
import { Input } from "@ui/input";
|
|
import { useEffect, useState } from "react";
|
|
import { CopyWebhook, ResourceSelector } from "../common";
|
|
import { ConfigLayout } from "@components/config";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@ui/popover";
|
|
import { Button } from "@ui/button";
|
|
import {
|
|
ArrowDown,
|
|
ArrowUp,
|
|
ChevronsUpDown,
|
|
Info,
|
|
Minus,
|
|
MinusCircle,
|
|
Plus,
|
|
PlusCircle,
|
|
SearchX,
|
|
Settings,
|
|
} from "lucide-react";
|
|
import {
|
|
Command,
|
|
CommandEmpty,
|
|
CommandGroup,
|
|
CommandInput,
|
|
CommandItem,
|
|
CommandList,
|
|
} from "@ui/command";
|
|
import { Switch } from "@ui/switch";
|
|
import { DataTable } from "@ui/data-table";
|
|
import { HoverCard, HoverCardContent, HoverCardTrigger } from "@ui/hover-card";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@ui/dropdown-menu";
|
|
import { DotsHorizontalIcon } from "@radix-ui/react-icons";
|
|
import { filterBySplit } from "@lib/utils";
|
|
import { useToast } from "@ui/use-toast";
|
|
import { fmt_upper_camelcase } from "@lib/formatting";
|
|
|
|
export const ProcedureConfig = ({ id }: { id: string }) => {
|
|
const procedure = useRead("GetProcedure", { procedure: id }).data;
|
|
if (!procedure) return null;
|
|
return <ProcedureConfigInner procedure={procedure} />;
|
|
};
|
|
|
|
const PROCEDURE_GIT_PROVIDER = "Procedure";
|
|
|
|
const ProcedureConfigInner = ({
|
|
procedure,
|
|
}: {
|
|
procedure: Types.Procedure;
|
|
}) => {
|
|
const [branch, setBranch] = useState("main");
|
|
const [config, setConfig] = useLocalStorage<Partial<Types.ProcedureConfig>>(
|
|
`procedure-${procedure._id?.$oid}-update-v1`,
|
|
{}
|
|
);
|
|
const perms = useRead("GetPermissionLevel", {
|
|
target: { type: "Procedure", id: procedure._id?.$oid! },
|
|
}).data;
|
|
const global_disabled =
|
|
useRead("GetCoreInfo", {}).data?.ui_write_disabled ?? false;
|
|
const { mutateAsync } = useWrite("UpdateProcedure");
|
|
const { integrations } = useWebhookIntegrations();
|
|
const [id_or_name] = useWebhookIdOrName();
|
|
const webhook_integration = integrations[PROCEDURE_GIT_PROVIDER] ?? "Github";
|
|
|
|
const stages = config.stages || procedure.config?.stages || [];
|
|
const disabled = global_disabled || perms !== Types.PermissionLevel.Write;
|
|
|
|
const add_stage = () =>
|
|
setConfig((config) => ({
|
|
...config,
|
|
stages: [...stages, new_stage()],
|
|
}));
|
|
|
|
return (
|
|
<div className="flex flex-col gap-8">
|
|
<ConfigLayout
|
|
original={procedure.config}
|
|
titleOther={
|
|
<div className="flex items-center gap-4 text-muted-foreground">
|
|
<div className="flex items-center gap-2">
|
|
<Settings className="w-4 h-4" />
|
|
<h2 className="text-xl">Config</h2>
|
|
</div>
|
|
<HoverCard openDelay={200}>
|
|
<HoverCardTrigger asChild>
|
|
<Button variant="outline">
|
|
<Info className="w-4 h-4" />
|
|
</Button>
|
|
</HoverCardTrigger>
|
|
<HoverCardContent align="start">
|
|
<div>
|
|
The executions in a stage are all run in parallel. The stages
|
|
themselves are run sequentially.
|
|
</div>
|
|
</HoverCardContent>
|
|
</HoverCard>
|
|
</div>
|
|
}
|
|
disabled={disabled}
|
|
config={config}
|
|
onConfirm={async () => {
|
|
await mutateAsync({ id: procedure._id!.$oid, config });
|
|
setConfig({});
|
|
}}
|
|
onReset={() => setConfig({})}
|
|
>
|
|
{stages.map((stage, index) => (
|
|
<Stage
|
|
stage={stage}
|
|
setStage={(stage) =>
|
|
setConfig((config) => ({
|
|
...config,
|
|
stages: stages.map((s, i) => (index === i ? stage : s)),
|
|
}))
|
|
}
|
|
removeStage={() =>
|
|
setConfig((config) => ({
|
|
...config,
|
|
stages: stages.filter((_, i) => index !== i),
|
|
}))
|
|
}
|
|
moveUp={
|
|
index === 0
|
|
? undefined
|
|
: () =>
|
|
setConfig((config) => ({
|
|
...config,
|
|
stages: stages.map((stage, i) => {
|
|
// Make sure its not the first row
|
|
if (i === index && index !== 0) {
|
|
return stages[index - 1];
|
|
} else if (i === index - 1) {
|
|
// Reverse the entry, moving this row "Up"
|
|
return stages[index];
|
|
} else {
|
|
return stage;
|
|
}
|
|
}),
|
|
}))
|
|
}
|
|
moveDown={
|
|
index === stages.length - 1
|
|
? undefined
|
|
: () =>
|
|
setConfig((config) => ({
|
|
...config,
|
|
stages: stages.map((stage, i) => {
|
|
// The index also cannot be the last index, which cannot be moved down
|
|
if (i === index && index !== stages.length - 1) {
|
|
return stages[index + 1];
|
|
} else if (i === index + 1) {
|
|
// Move the row "Down"
|
|
return stages[index];
|
|
} else {
|
|
return stage;
|
|
}
|
|
}),
|
|
}))
|
|
}
|
|
insertAbove={() =>
|
|
setConfig((config) => ({
|
|
...config,
|
|
stages: [
|
|
...stages.slice(0, index),
|
|
new_stage(),
|
|
...stages.slice(index),
|
|
],
|
|
}))
|
|
}
|
|
insertBelow={() =>
|
|
setConfig((config) => ({
|
|
...config,
|
|
stages: [
|
|
...stages.slice(0, index + 1),
|
|
new_stage(),
|
|
...stages.slice(index + 1),
|
|
],
|
|
}))
|
|
}
|
|
disabled={disabled}
|
|
/>
|
|
))}
|
|
<Button
|
|
variant="secondary"
|
|
onClick={add_stage}
|
|
className="w-fit"
|
|
disabled={disabled}
|
|
>
|
|
Add Stage
|
|
</Button>
|
|
</ConfigLayout>
|
|
<Section>
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Webhook</CardTitle>
|
|
<CardDescription>
|
|
Trigger this Procedure with a webhook.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex flex-col gap-4">
|
|
<ConfigItem>
|
|
<WebhookBuilder git_provider={PROCEDURE_GIT_PROVIDER}>
|
|
<div className="text-nowrap text-muted-foreground text-sm">
|
|
Listen on branch:
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<Input
|
|
placeholder="Branch"
|
|
value={branch}
|
|
onChange={(e) => setBranch(e.target.value)}
|
|
className="w-[200px]"
|
|
disabled={branch === "__ALL__"}
|
|
/>
|
|
<div className="flex items-center gap-2">
|
|
<div className="text-muted-foreground text-sm">
|
|
All branches:
|
|
</div>
|
|
<Switch
|
|
checked={branch === "__ALL__"}
|
|
onCheckedChange={(checked) => {
|
|
if (checked) {
|
|
setBranch("__ALL__");
|
|
} else {
|
|
setBranch("main");
|
|
}
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</WebhookBuilder>
|
|
</ConfigItem>
|
|
<ConfigItem label="Webhook Url - Run">
|
|
<CopyWebhook
|
|
integration={webhook_integration}
|
|
path={`/procedure/${id_or_name === "Id" ? procedure._id?.$oid! : procedure.name}/${branch}`}
|
|
/>
|
|
</ConfigItem>
|
|
<ConfigSwitch
|
|
label="Webhook Enabled"
|
|
value={
|
|
config.webhook_enabled ?? procedure.config?.webhook_enabled
|
|
}
|
|
disabled={disabled}
|
|
onChange={(webhook_enabled) =>
|
|
setConfig({ ...config, webhook_enabled })
|
|
}
|
|
/>
|
|
<ConfigInput
|
|
label="Custom Secret"
|
|
description="Provide a custom webhook secret for this resource, or use the global default."
|
|
placeholder="Input custom secret"
|
|
value={
|
|
config.webhook_secret ?? procedure.config?.webhook_secret
|
|
}
|
|
disabled={disabled}
|
|
onChange={(webhook_secret) =>
|
|
setConfig({ ...config, webhook_secret })
|
|
}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</Section>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const Stage = ({
|
|
stage,
|
|
setStage,
|
|
removeStage,
|
|
moveUp,
|
|
moveDown,
|
|
insertAbove,
|
|
insertBelow,
|
|
disabled,
|
|
}: {
|
|
stage: Types.ProcedureStage;
|
|
setStage: (stage: Types.ProcedureStage) => void;
|
|
removeStage: () => void;
|
|
insertAbove: () => void;
|
|
insertBelow: () => void;
|
|
moveUp: (() => void) | undefined;
|
|
moveDown: (() => void) | undefined;
|
|
disabled: boolean;
|
|
}) => {
|
|
return (
|
|
<Card className="p-4 flex flex-col gap-4">
|
|
<div className="flex justify-between items-center">
|
|
<Input
|
|
value={stage.name}
|
|
onChange={(e) => setStage({ ...stage, name: e.target.value })}
|
|
className="w-[300px] text-md"
|
|
/>
|
|
<div className="flex gap-4 items-center">
|
|
<div>Enabled:</div>
|
|
<Switch
|
|
checked={stage.enabled}
|
|
onCheckedChange={(enabled) => setStage({ ...stage, enabled })}
|
|
/>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild disabled={disabled}>
|
|
<Button
|
|
variant="ghost"
|
|
className="h-8 w-8 p-0"
|
|
disabled={disabled}
|
|
>
|
|
<span className="sr-only">Open menu</span>
|
|
<DotsHorizontalIcon className="h-4 w-4" />
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end">
|
|
{moveUp && (
|
|
<DropdownMenuItem
|
|
className="flex gap-4 justify-between cursor-pointer"
|
|
onClick={moveUp}
|
|
>
|
|
Move Up <ArrowUp className="w-4 h-4" />
|
|
</DropdownMenuItem>
|
|
)}
|
|
{moveDown && (
|
|
<DropdownMenuItem
|
|
className="flex gap-4 justify-between cursor-pointer"
|
|
onClick={moveDown}
|
|
>
|
|
Move Down <ArrowDown className="w-4 h-4" />
|
|
</DropdownMenuItem>
|
|
)}
|
|
|
|
{(moveUp ?? moveDown) && <DropdownMenuSeparator />}
|
|
|
|
<DropdownMenuItem
|
|
className="flex gap-4 justify-between cursor-pointer"
|
|
onClick={insertAbove}
|
|
>
|
|
Insert Above{" "}
|
|
<div className="flex">
|
|
<ArrowUp className="w-4 h-4" />
|
|
<Plus className="w-4 h-4" />
|
|
</div>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className="flex gap-4 justify-between cursor-pointer"
|
|
onClick={insertBelow}
|
|
>
|
|
Insert Below{" "}
|
|
<div className="flex">
|
|
<ArrowDown className="w-4 h-4" />
|
|
<Plus className="w-4 h-4" />
|
|
</div>
|
|
</DropdownMenuItem>
|
|
|
|
<DropdownMenuSeparator />
|
|
|
|
<DropdownMenuItem
|
|
className="flex gap-4 justify-between cursor-pointer"
|
|
onClick={removeStage}
|
|
>
|
|
Remove <Minus className="w-4 h-4" />
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</div>
|
|
<DataTable
|
|
tableKey="procedure-stage-executions"
|
|
data={stage.executions!}
|
|
noResults={
|
|
<Button
|
|
onClick={() =>
|
|
setStage({
|
|
...stage,
|
|
executions: [default_enabled_execution()],
|
|
})
|
|
}
|
|
variant="secondary"
|
|
disabled={disabled}
|
|
>
|
|
Add Execution
|
|
</Button>
|
|
}
|
|
columns={[
|
|
{
|
|
header: "Execution",
|
|
cell: ({ row: { original, index } }) => (
|
|
<ExecutionTypeSelector
|
|
disabled={disabled}
|
|
type={original.execution.type}
|
|
onSelect={(type) =>
|
|
setStage({
|
|
...stage,
|
|
executions: stage.executions!.map((item, i) =>
|
|
i === index
|
|
? ({
|
|
...item,
|
|
execution: {
|
|
type,
|
|
params:
|
|
TARGET_COMPONENTS[
|
|
type as Types.Execution["type"]
|
|
].params,
|
|
},
|
|
} as Types.EnabledExecution)
|
|
: item
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
),
|
|
},
|
|
{
|
|
header: "Target",
|
|
cell: ({
|
|
row: {
|
|
original: {
|
|
execution: { type, params },
|
|
},
|
|
index,
|
|
},
|
|
}) => {
|
|
const Component = TARGET_COMPONENTS[type].Component;
|
|
return (
|
|
<Component
|
|
disabled={disabled}
|
|
params={params as any}
|
|
setParams={(params: any) =>
|
|
setStage({
|
|
...stage,
|
|
executions: stage.executions!.map((item, i) =>
|
|
i === index
|
|
? {
|
|
...item,
|
|
execution: { type, params },
|
|
}
|
|
: item
|
|
) as Types.EnabledExecution[],
|
|
})
|
|
}
|
|
/>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
header: "Add / Remove",
|
|
cell: ({ row: { index } }) => (
|
|
<div className="flex items-center gap-2">
|
|
<Button
|
|
variant="secondary"
|
|
onClick={() =>
|
|
setStage({
|
|
...stage,
|
|
executions: [
|
|
...stage.executions!.slice(0, index + 1),
|
|
default_enabled_execution(),
|
|
...stage.executions!.slice(index + 1),
|
|
],
|
|
})
|
|
}
|
|
disabled={disabled}
|
|
>
|
|
<PlusCircle className="w-4 h-4" />
|
|
</Button>
|
|
<Button
|
|
variant="secondary"
|
|
onClick={() =>
|
|
setStage({
|
|
...stage,
|
|
executions: stage.executions!.filter(
|
|
(_, i) => i !== index
|
|
),
|
|
})
|
|
}
|
|
disabled={disabled}
|
|
>
|
|
<MinusCircle className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
header: "Enabled",
|
|
cell: ({
|
|
row: {
|
|
original: { enabled },
|
|
index,
|
|
},
|
|
}) => {
|
|
return (
|
|
<Switch
|
|
checked={enabled}
|
|
onClick={() =>
|
|
setStage({
|
|
...stage,
|
|
executions: stage.executions!.map((item, i) =>
|
|
i === index ? { ...item, enabled: !enabled } : item
|
|
),
|
|
})
|
|
}
|
|
disabled={disabled}
|
|
/>
|
|
);
|
|
},
|
|
},
|
|
]}
|
|
/>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
const new_stage = () => ({
|
|
name: "Stage",
|
|
enabled: true,
|
|
executions: [default_enabled_execution()],
|
|
});
|
|
|
|
const default_enabled_execution: () => Types.EnabledExecution = () => ({
|
|
enabled: true,
|
|
execution: {
|
|
type: "None",
|
|
params: {},
|
|
},
|
|
});
|
|
|
|
const ExecutionTypeSelector = ({
|
|
type,
|
|
onSelect,
|
|
disabled,
|
|
}: {
|
|
type: Types.Execution["type"];
|
|
onSelect: (type: Types.Execution["type"]) => void;
|
|
disabled: boolean;
|
|
}) => {
|
|
const execution_types = Object.keys(TARGET_COMPONENTS).filter(
|
|
(c) => !["None"].includes(c)
|
|
);
|
|
|
|
const [open, setOpen] = useState(false);
|
|
const [search, setSearch] = useState("");
|
|
const filtered = filterBySplit(execution_types, search, (item) => item);
|
|
|
|
return (
|
|
<Popover open={open} onOpenChange={setOpen}>
|
|
<PopoverTrigger asChild>
|
|
<Button variant="secondary" className="flex gap-2" disabled={disabled}>
|
|
{fmt_upper_camelcase(type)}
|
|
<ChevronsUpDown className="w-3 h-3" />
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-[200px] max-h-[200px] p-0" sideOffset={12}>
|
|
<Command shouldFilter={false}>
|
|
<CommandInput
|
|
placeholder="Search Executions"
|
|
className="h-9"
|
|
value={search}
|
|
onValueChange={setSearch}
|
|
/>
|
|
<CommandList>
|
|
<CommandEmpty className="flex justify-evenly items-center pt-2">
|
|
Empty.
|
|
<SearchX className="w-3 h-3" />
|
|
</CommandEmpty>
|
|
<CommandGroup className="overflow-auto">
|
|
{filtered.map((type) => (
|
|
<CommandItem
|
|
key={type}
|
|
onSelect={() => onSelect(type as Types.Execution["type"])}
|
|
className="flex items-center justify-between"
|
|
>
|
|
<div className="p-1">{fmt_upper_camelcase(type)}</div>
|
|
</CommandItem>
|
|
))}
|
|
</CommandGroup>
|
|
</CommandList>
|
|
</Command>
|
|
</PopoverContent>
|
|
</Popover>
|
|
);
|
|
};
|
|
|
|
type ExecutionType = Types.Execution["type"];
|
|
|
|
type ExecutionConfigComponent<
|
|
T extends ExecutionType,
|
|
P = Extract<Types.Execution, { type: T }>["params"],
|
|
> = React.FC<{
|
|
params: P;
|
|
setParams: React.Dispatch<React.SetStateAction<P>>;
|
|
disabled: boolean;
|
|
}>;
|
|
|
|
type MinExecutionType = Exclude<
|
|
ExecutionType,
|
|
| "StartContainer"
|
|
| "RestartContainer"
|
|
| "PauseContainer"
|
|
| "UnpauseContainer"
|
|
| "StopContainer"
|
|
| "DestroyContainer"
|
|
| "DeleteNetwork"
|
|
| "DeleteImage"
|
|
| "DeleteVolume"
|
|
>;
|
|
|
|
type ExecutionConfigParams<T extends MinExecutionType> = Extract<
|
|
Types.Execution,
|
|
{ type: T }
|
|
>["params"];
|
|
|
|
type ExecutionConfigs = {
|
|
[ExType in MinExecutionType]: {
|
|
Component: ExecutionConfigComponent<ExType>;
|
|
params: ExecutionConfigParams<ExType>;
|
|
};
|
|
};
|
|
|
|
const TARGET_COMPONENTS: ExecutionConfigs = {
|
|
None: {
|
|
params: {},
|
|
Component: () => <></>,
|
|
},
|
|
// Procedure
|
|
RunProcedure: {
|
|
params: { procedure: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Procedure"
|
|
selected={params.procedure}
|
|
onSelect={(procedure) => setParams({ procedure })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
// Action
|
|
RunAction: {
|
|
params: { action: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Action"
|
|
selected={params.action}
|
|
onSelect={(action) => setParams({ action })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
// Build
|
|
RunBuild: {
|
|
params: { build: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Build"
|
|
selected={params.build}
|
|
onSelect={(build) => setParams({ build })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
CancelBuild: {
|
|
params: { build: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Build"
|
|
selected={params.build}
|
|
onSelect={(build) => setParams({ build })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
// Deployment
|
|
Deploy: {
|
|
params: { deployment: "" },
|
|
Component: ({ params, setParams, disabled }) => {
|
|
return (
|
|
<ResourceSelector
|
|
type="Deployment"
|
|
selected={params.deployment}
|
|
onSelect={(deployment) => setParams({ deployment })}
|
|
disabled={disabled}
|
|
/>
|
|
);
|
|
},
|
|
},
|
|
StartDeployment: {
|
|
params: { deployment: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Deployment"
|
|
selected={params.deployment}
|
|
onSelect={(deployment) => setParams({ deployment })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
RestartDeployment: {
|
|
params: { deployment: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Deployment"
|
|
selected={params.deployment}
|
|
onSelect={(deployment) => setParams({ deployment })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PauseDeployment: {
|
|
params: { deployment: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Deployment"
|
|
selected={params.deployment}
|
|
onSelect={(deployment) => setParams({ deployment })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
UnpauseDeployment: {
|
|
params: { deployment: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Deployment"
|
|
selected={params.deployment}
|
|
onSelect={(deployment) => setParams({ deployment })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
StopDeployment: {
|
|
params: { deployment: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Deployment"
|
|
selected={params.deployment}
|
|
onSelect={(id) => setParams({ deployment: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
DestroyDeployment: {
|
|
params: { deployment: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Deployment"
|
|
selected={params.deployment}
|
|
onSelect={(deployment) => setParams({ deployment })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
// Stack
|
|
DeployStack: {
|
|
params: { stack: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Stack"
|
|
selected={params.stack}
|
|
onSelect={(id) => setParams({ stack: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
DeployStackIfChanged: {
|
|
params: { stack: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Stack"
|
|
selected={params.stack}
|
|
onSelect={(id) => setParams({ stack: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
StartStack: {
|
|
params: { stack: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Stack"
|
|
selected={params.stack}
|
|
onSelect={(id) => setParams({ stack: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
RestartStack: {
|
|
params: { stack: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Stack"
|
|
selected={params.stack}
|
|
onSelect={(id) => setParams({ stack: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PauseStack: {
|
|
params: { stack: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Stack"
|
|
selected={params.stack}
|
|
onSelect={(id) => setParams({ stack: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
UnpauseStack: {
|
|
params: { stack: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Stack"
|
|
selected={params.stack}
|
|
onSelect={(id) => setParams({ stack: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
StopStack: {
|
|
params: { stack: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Stack"
|
|
selected={params.stack}
|
|
onSelect={(id) => setParams({ stack: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
DestroyStack: {
|
|
params: { stack: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Stack"
|
|
selected={params.stack}
|
|
onSelect={(id) => setParams({ stack: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
// Repo
|
|
CloneRepo: {
|
|
params: { repo: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Repo"
|
|
selected={params.repo}
|
|
onSelect={(repo) => setParams({ repo })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PullRepo: {
|
|
params: { repo: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Repo"
|
|
selected={params.repo}
|
|
onSelect={(repo) => setParams({ repo })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
BuildRepo: {
|
|
params: { repo: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Repo"
|
|
selected={params.repo}
|
|
onSelect={(repo) => setParams({ repo })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
CancelRepoBuild: {
|
|
params: { repo: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Repo"
|
|
selected={params.repo}
|
|
onSelect={(repo) => setParams({ repo })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
// Server
|
|
// StartContainer: {
|
|
// params: { server: "" },
|
|
// Component: ({ params, setParams, disabled }) => (
|
|
// <ResourceSelector
|
|
// type="Server"
|
|
// selected={params.server}
|
|
// onSelect={(server) => setParams({ server })}
|
|
// disabled={disabled}
|
|
// />
|
|
// ),
|
|
// },
|
|
// RestartContainer: {
|
|
// params: { server: "" },
|
|
// Component: ({ params, setParams, disabled }) => (
|
|
// <ResourceSelector
|
|
// type="Server"
|
|
// selected={params.server}
|
|
// onSelect={(server) => setParams({ server })}
|
|
// disabled={disabled}
|
|
// />
|
|
// ),
|
|
// },
|
|
// PauseContainer: {
|
|
// params: { server: "" },
|
|
// Component: ({ params, setParams, disabled }) => (
|
|
// <ResourceSelector
|
|
// type="Server"
|
|
// selected={params.server}
|
|
// onSelect={(server) => setParams({ server })}
|
|
// disabled={disabled}
|
|
// />
|
|
// ),
|
|
// },
|
|
// UnpauseContainer: {
|
|
// params: { server: "" },
|
|
// Component: ({ params, setParams, disabled }) => (
|
|
// <ResourceSelector
|
|
// type="Server"
|
|
// selected={params.server}
|
|
// onSelect={(server) => setParams({ server })}
|
|
// disabled={disabled}
|
|
// />
|
|
// ),
|
|
// },
|
|
// StopContainer: {
|
|
// params: { server: "" },
|
|
// Component: ({ params, setParams, disabled }) => (
|
|
// <ResourceSelector
|
|
// type="Server"
|
|
// selected={params.server}
|
|
// onSelect={(server) => setParams({ server })}
|
|
// disabled={disabled}
|
|
// />
|
|
// ),
|
|
// },
|
|
// DestroyContainer: {
|
|
// params: { server: "", container: "" },
|
|
// Component: ({ params, setParams, disabled }) => (
|
|
// <ResourceSelector
|
|
// type="Server"
|
|
// selected={params.server}
|
|
// onSelect={(server) => setParams({ server })}
|
|
// disabled={disabled}
|
|
// />
|
|
// ),
|
|
// },
|
|
StartAllContainers: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(id) => setParams({ server: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
RestartAllContainers: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(id) => setParams({ server: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PauseAllContainers: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(id) => setParams({ server: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
UnpauseAllContainers: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(id) => setParams({ server: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
StopAllContainers: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(id) => setParams({ server: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PruneContainers: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(server) => setParams({ server })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PruneNetworks: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(server) => setParams({ server })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PruneImages: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(server) => setParams({ server })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PruneVolumes: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(server) => setParams({ server })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PruneDockerBuilders: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(server) => setParams({ server })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PruneBuildx: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(server) => setParams({ server })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
PruneSystem: {
|
|
params: { server: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="Server"
|
|
selected={params.server}
|
|
onSelect={(server) => setParams({ server })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
RunSync: {
|
|
params: { sync: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="ResourceSync"
|
|
selected={params.sync}
|
|
onSelect={(id) => setParams({ sync: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
CommitSync: {
|
|
params: { sync: "" },
|
|
Component: ({ params, setParams, disabled }) => (
|
|
<ResourceSelector
|
|
type="ResourceSync"
|
|
selected={params.sync}
|
|
onSelect={(id) => setParams({ sync: id })}
|
|
disabled={disabled}
|
|
/>
|
|
),
|
|
},
|
|
|
|
Sleep: {
|
|
params: { duration_ms: 0 },
|
|
Component: ({ params, setParams, disabled }) => {
|
|
const { toast } = useToast();
|
|
const [internal, setInternal] = useState(
|
|
params.duration_ms?.toString() ?? ""
|
|
);
|
|
useEffect(() => {
|
|
setInternal(params.duration_ms?.toString() ?? "");
|
|
}, [params.duration_ms]);
|
|
return (
|
|
<Input
|
|
placeholder="Duration in milliseconds"
|
|
value={internal}
|
|
onChange={(e) => setInternal(e.target.value)}
|
|
onBlur={() => {
|
|
const duration_ms = Number(internal);
|
|
if (duration_ms) {
|
|
setParams({ duration_ms });
|
|
} else {
|
|
toast({
|
|
title: "Duration must be valid number",
|
|
variant: "destructive",
|
|
});
|
|
}
|
|
}}
|
|
disabled={disabled}
|
|
/>
|
|
);
|
|
},
|
|
},
|
|
};
|