add github webhook copiers

This commit is contained in:
mbecker20
2024-05-06 00:00:47 -07:00
parent a70afcc461
commit 0f6b3d6e9b
4 changed files with 301 additions and 236 deletions

View File

@@ -19,7 +19,7 @@ import {
import { Textarea } from "@ui/textarea";
import { MinusCircle, PlusCircle } from "lucide-react";
import { useEffect, useState } from "react";
import { LabelsConfig, ResourceSelector } from "../common";
import { CopyGithubWebhook, LabelsConfig, ResourceSelector } from "../common";
export const BuildConfig = ({ id }: { id: string }) => {
const perms = useRead("GetPermissionLevel", {
@@ -155,6 +155,13 @@ export const BuildConfig = ({ id }: { id: string }) => {
/>
),
},
github_webhooks: {
["build" as any]: () => (
<ConfigItem label="Build">
<CopyGithubWebhook path={`/build/${id}`} />
</ConfigItem>
),
},
},
"Build Args": {
"Build Args": {

View File

@@ -2,6 +2,7 @@ import {
ActionButton,
ActionWithDialog,
ConfirmButton,
CopyButton,
TextUpdateMenu,
} from "@components/util";
import { useInvalidate, useRead, useWrite } from "@lib/hooks";
@@ -309,3 +310,18 @@ export const LabelsConfig = ({
/>
</ConfigItem>
);
export const CopyGithubWebhook = ({
path,
}: {
path: string;
}) => {
const base_url = useRead("GetCoreInfo", {}).data?.github_webhook_base_url;
const url = base_url + "/listener/github" + path;
return (
<div className="flex gap-2 items-center">
<Input className="w-[400px] max-w-[70vw]" value={url} disabled />
<CopyButton content={url} />
</div>
);
};

View File

@@ -39,7 +39,11 @@ import {
Trash2,
} from "lucide-react";
import { useState } from "react";
import { ResourceSelector } from "../common";
import { CopyGithubWebhook, ResourceSelector } from "../common";
import { ConfigItem } from "@components/config/util";
import { Input } from "@ui/input";
import { Section } from "@components/layouts";
import { Card, CardHeader } from "@ui/card";
export const ProcedureConfig = ({ id }: { id: string }) => {
const procedure = useRead("GetProcedure", { procedure: id }).data;
@@ -55,6 +59,7 @@ const ProcedureConfigInner = ({
const perms = useRead("GetPermissionLevel", {
target: { type: "Procedure", id: procedure._id?.$oid! },
}).data;
const [branch, setBranch] = useState("main");
const [config, setConfig] = useState<Partial<Types.ProcedureConfig>>({});
const { mutateAsync } = useWrite("UpdateProcedure");
const executions = config.executions || procedure.config.executions || [];
@@ -62,276 +67,301 @@ const ProcedureConfigInner = ({
const disabled = perms !== Types.PermissionLevel.Write;
return (
<ConfigLayout
disabled={disabled}
config={config as any}
onConfirm={async () => {
await mutateAsync({ id: procedure._id!.$oid, config });
setConfig({});
}}
onReset={() => setConfig(procedure.config)}
selector={
<div className="flex gap-2 items-center text-sm">
Procedure Type:
<Select
value={config.procedure_type || procedure.config.procedure_type}
onValueChange={(type) =>
setConfig({ ...config, procedure_type: type as any })
}
disabled={disabled}
>
<SelectTrigger className="w-32 capitalize" disabled={disabled}>
<SelectValue />
</SelectTrigger>
<SelectContent className="w-32">
{["Sequence", "Parallel"].map((key) => (
<SelectItem value={key} key={key} className="capitalize">
{key}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
}
>
<div className="grid gap-4">
<div className="text-muted-foreground">
{config.procedure_type === Types.ProcedureType.Parallel
? "Type Parallel: All of these executions will be started at the same time"
: "Type Sequence: These executions will be started only after the previous one finishes"}
</div>
<DataTable
tableKey="procedure-stages"
data={executions}
noResults={
<Button
onClick={() =>
setConfig({
...config,
executions: [default_enabled_execution()],
})
<>
<ConfigLayout
disabled={disabled}
config={config as any}
onConfirm={async () => {
await mutateAsync({ id: procedure._id!.$oid, config });
setConfig({});
}}
onReset={() => setConfig(procedure.config)}
selector={
<div className="flex gap-2 items-center text-sm">
Procedure Type:
<Select
value={config.procedure_type || procedure.config.procedure_type}
onValueChange={(type) =>
setConfig({ ...config, procedure_type: type as any })
}
disabled={disabled}
>
Create Stage
</Button>
}
columns={[
{
header: "Enabled",
cell: ({
row: {
original: { enabled },
index,
},
}) => {
return (
<Switch
checked={enabled}
onClick={() =>
setConfig({
...config,
executions: executions.map((item, i) =>
i === index ? { ...item, enabled: !enabled } : item
),
})
}
disabled={disabled}
/>
);
},
},
{
header: "Execution",
cell: ({ row: { original, index } }) => (
<ExecutionTypeSelector
disabled={disabled}
type={original.execution.type}
onSelect={(type) =>
setConfig({
...config,
executions: 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 },
<SelectTrigger className="w-32 capitalize" disabled={disabled}>
<SelectValue />
</SelectTrigger>
<SelectContent className="w-32">
{["Sequence", "Parallel"].map((key) => (
<SelectItem value={key} key={key} className="capitalize">
{key}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
}
>
<div className="grid gap-4">
<div className="text-muted-foreground">
{config.procedure_type === Types.ProcedureType.Parallel
? "Type Parallel: All of these executions will be started at the same time"
: "Type Sequence: These executions will be started only after the previous one finishes"}
</div>
<DataTable
tableKey="procedure-stages"
data={executions}
noResults={
<Button
onClick={() =>
setConfig({
...config,
executions: [default_enabled_execution()],
})
}
disabled={disabled}
>
Create Stage
</Button>
}
columns={[
{
header: "Enabled",
cell: ({
row: {
original: { enabled },
index,
},
index,
}) => {
return (
<Switch
checked={enabled}
onClick={() =>
setConfig({
...config,
executions: executions.map((item, i) =>
i === index ? { ...item, enabled: !enabled } : item
),
})
}
disabled={disabled}
/>
);
},
}) => {
const Component = TARGET_COMPONENTS[type].Component;
return (
<Component
},
{
header: "Execution",
cell: ({ row: { original, index } }) => (
<ExecutionTypeSelector
disabled={disabled}
params={params as any}
setParams={(params: any) =>
type={original.execution.type}
onSelect={(type) =>
setConfig({
...config,
executions: executions.map((item, i) =>
i === index
? {
? ({
...item,
execution: { type, params },
}
execution: {
type,
params:
TARGET_COMPONENTS[
type as Types.Execution["type"]
].params,
},
} as Types.EnabledExecution)
: item
),
})
}
/>
);
),
},
},
{
header: "Modify",
cell: ({ row }) => {
return (
<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">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuSeparator />
{row.index ? (
{
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) =>
setConfig({
...config,
executions: executions.map((item, i) =>
i === index
? {
...item,
execution: { type, params },
}
: item
),
})
}
/>
);
},
},
{
header: "Modify",
cell: ({ row }) => {
return (
<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">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuSeparator />
{row.index ? (
<DropdownMenuItem
className="flex gap-4 justify-between cursor-pointer"
onClick={() =>
setConfig({
...config,
executions: executions.map((item, i) => {
// Make sure its not the first row
if (i === row.index && row.index !== 0) {
return executions[row.index - 1];
} else if (i === row.index - 1) {
// Reverse the entry, moving this row "Up"
return executions[row.index];
} else {
return item;
}
}),
})
}
>
Move Up <ArrowUp className="w-4 h-4" />
</DropdownMenuItem>
) : undefined}
{row.index < executions.length - 1 && (
<DropdownMenuItem
className="flex gap-4 justify-between cursor-pointer"
onClick={() =>
setConfig({
...config,
executions: executions.map((item, i) => {
// The index also cannot be the last index, which cannot be moved down
if (
i === row.index &&
row.index !== executions.length - 1
) {
return executions[row.index + 1];
} else if (i === row.index + 1) {
// Move the row "Down"
return executions[row.index];
} else {
return item;
}
}),
})
}
>
Move Down <ArrowDown className="w-4 h-4" />
</DropdownMenuItem>
)}
<DropdownMenuSeparator />
<DropdownMenuItem
className="flex gap-4 justify-between cursor-pointer"
onClick={() =>
setConfig({
...config,
executions: executions.map((item, i) => {
// Make sure its not the first row
if (i === row.index && row.index !== 0) {
return executions[row.index - 1];
} else if (i === row.index - 1) {
// Reverse the entry, moving this row "Up"
return executions[row.index];
} else {
return item;
}
}),
executions: [
...executions.slice(0, row.index),
default_enabled_execution(),
...executions.slice(row.index),
],
})
}
>
Move Up <ArrowUp className="w-4 h-4" />
Insert Above{" "}
<div className="flex">
<ArrowUp className="w-4 h-4" />
<Plus className="w-4 h-4" />
</div>
</DropdownMenuItem>
) : undefined}
{row.index < executions.length - 1 && (
<DropdownMenuItem
className="flex gap-4 justify-between cursor-pointer"
onClick={() =>
setConfig({
...config,
executions: executions.map((item, i) => {
// The index also cannot be the last index, which cannot be moved down
if (
i === row.index &&
row.index !== executions.length - 1
) {
return executions[row.index + 1];
} else if (i === row.index + 1) {
// Move the row "Down"
return executions[row.index];
} else {
return item;
}
}),
executions: [
...executions.slice(0, row.index + 1),
default_enabled_execution(),
...executions.slice(row.index + 1),
],
})
}
>
Move Down <ArrowDown className="w-4 h-4" />
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={() =>
setConfig({
...config,
executions: [
...executions.slice(0, row.index),
default_enabled_execution(),
...executions.slice(row.index),
],
})
}
>
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={() =>
setConfig({
...config,
executions: [
...executions.slice(0, row.index + 1),
default_enabled_execution(),
...executions.slice(row.index + 1),
],
})
}
>
Insert Below{" "}
<div className="flex">
<ArrowDown className="w-4 h-4" />
<Plus className="w-4 h-4" />
</div>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
</DropdownMenuContent>
</DropdownMenu>
);
},
},
},
{
header: "Delete",
cell: ({ row: { index } }) => (
<ConfirmButton
title="Delete Row"
icon={<Trash2 className="w-4 h-4" />}
onClick={() =>
setConfig({
...config,
executions: executions.filter((_, i) => i !== index),
})
}
disabled={disabled}
{
header: "Delete",
cell: ({ row: { index } }) => (
<ConfirmButton
title="Delete Row"
icon={<Trash2 className="w-4 h-4" />}
onClick={() =>
setConfig({
...config,
executions: executions.filter((_, i) => i !== index),
})
}
disabled={disabled}
/>
),
},
]}
/>
</div>
</ConfigLayout>
<Section>
<Card>
<CardHeader className="p-4">
<ConfigItem label="Github Webhook" className="items-start">
<div className="flex flex-col gap-4">
<div className="flex items-center gap-2">
<div className="text-nowrap text-muted-foreground">
Listen on branch:
</div>
<Input
placeholder="Branch"
value={branch}
onChange={(e) => setBranch(e.target.value)}
/>
</div>
<CopyGithubWebhook
path={`/procedure/${procedure._id?.$oid!}/${branch}`}
/>
),
},
]}
/>
</div>
</ConfigLayout>
</div>
</ConfigItem>
</CardHeader>
</Card>
</Section>
</>
);
};

View File

@@ -10,7 +10,7 @@ import {
SelectValue,
} from "@ui/select";
import { useState } from "react";
import { ResourceSelector } from "../common";
import { CopyGithubWebhook, ResourceSelector } from "../common";
export const RepoConfig = ({ id }: { id: string }) => {
const perms = useRead("GetPermissionLevel", {
@@ -76,6 +76,18 @@ export const RepoConfig = ({ id }: { id: string }) => {
/>
),
},
github_webhooks: {
["clone" as any]: () => (
<ConfigItem label="Clone">
<CopyGithubWebhook path={`/repo/${id}/clone`} />
</ConfigItem>
),
["pull" as any]: () => (
<ConfigItem label="Pull">
<CopyGithubWebhook path={`/repo/${id}/pull`} />
</ConfigItem>
),
},
},
}}
/>