Skip to content

Commit

Permalink
fix: default workflow value not showing in webhook form
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanhopperlowe committed Nov 21, 2024
1 parent ec3d5ec commit 1972350
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 112 deletions.
2 changes: 2 additions & 0 deletions ui/admin/app/components/ui/multi-select.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// todo(ryanhopperlowe): this needs to get rewritten to use a popover with a command inside of it
// the dropdown is absolutely positioned and gets cut off when it's container is smaller
import { Command as CommandPrimitive, useCommandState } from "cmdk";
import { X } from "lucide-react";
import * as React from "react";
Expand Down
65 changes: 51 additions & 14 deletions ui/admin/app/components/webhooks/WebhookConfirmation.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { $path } from "remix-routes";

import { Webhook } from "~/lib/model/webhooks";
import { cn } from "~/lib/utils";

import { TypographyP } from "~/components/Typography";
import { CopyText } from "~/components/composed/CopyText";
Expand All @@ -16,17 +17,24 @@ import { Link } from "~/components/ui/link";

export type WebhookConfirmationProps = {
webhook: Webhook;
original?: Webhook;
token?: string;
secret: string;
type?: "github";
};

export const WebhookConfirmation = ({
webhook,
token: _token,
original,
token,
secret,
type: _ = "github",
}: WebhookConfirmationProps) => {
const showUrlChange =
!original ||
original.links?.invoke !== webhook.links?.invoke ||
!!token;

return (
<Dialog open>
<DialogContent className="max-w-[700px]" hideCloseButton>
Expand All @@ -35,29 +43,49 @@ export const WebhookConfirmation = ({
</DialogHeader>

<DialogDescription>
Your webhook has been saved in Otto. Make sure to copy
payload url and secret to your webhook provider.
Your webhook has been saved in Otto8. Make sure to copy the
payload URL and secret to your webhook provider.
</DialogDescription>

<DialogDescription>
This information will not be shown again.
</DialogDescription>

<div className="flex items-center justify-between">
<div
className={cn("flex flex-col gap-1", {
"flex-row gap-2": !showUrlChange,
})}
>
<TypographyP>Payload URL: </TypographyP>
<CopyText
text={webhook.links?.invoke ?? ""}
className="min-w-fit"
/>
{showUrlChange ? (
<CopyText
text={getWebhookUrl(webhook, token)}
className="min-w-fit"
/>
) : (
<TypographyP className="text-muted-foreground">
(Unchanged)
</TypographyP>
)}
</div>

<div className="flex items-center justify-between">
<div
className={cn("flex flex-col gap-1", {
"flex-row gap-2": !secret,
})}
>
<TypographyP>Secret: </TypographyP>
<CopyText
className="min-w-fit"
displayText={secret}
text={secret ?? ""}
/>
{secret ? (
<CopyText
className="min-w-fit"
displayText={secret}
text={secret ?? ""}
/>
) : (
<TypographyP className="text-muted-foreground">
(Unchanged)
</TypographyP>
)}
</div>

<DialogFooter>
Expand All @@ -73,3 +101,12 @@ export const WebhookConfirmation = ({
</Dialog>
);
};

function getWebhookUrl(webhook: Webhook, token?: string) {
if (!token) return webhook.links?.invoke ?? "";

const url = new URL(webhook.links?.invoke ?? "");
url.searchParams.set("token", token);

return url.toString();
}
209 changes: 116 additions & 93 deletions ui/admin/app/components/webhooks/WebhookForm.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import useSWR from "swr";

import { WorkflowService } from "~/lib/service/api/workflowService";

import { TypographyH4 } from "~/components/Typography";
import { TypographyH3, TypographyH4 } from "~/components/Typography";
import {
ControlledCustomInput,
ControlledInput,
} from "~/components/form/controlledInputs";
import { Button } from "~/components/ui/button";
import { FormItem, FormLabel } from "~/components/ui/form";
import { MultiSelect } from "~/components/ui/multi-select";
import { ScrollArea } from "~/components/ui/scroll-area";
import {
Select,
SelectContent,
SelectEmptyItem,
SelectItem,
SelectTrigger,
SelectValue,
Expand Down Expand Up @@ -54,109 +54,132 @@ export function WebhookFormContent() {
}, [form, validationHeader]);

return (
<form
onSubmit={handleSubmit}
className="space-y-8 p-8 max-w-3xl mx-auto"
>
<TypographyH4>
{isEdit ? "Edit Webhook" : "Create Webhook"}
</TypographyH4>

<ControlledInput control={form.control} name="name" label="Name" />

<ControlledInput
control={form.control}
name="description"
label="Description"
/>

<FormItem>
<FormLabel>Type</FormLabel>
<Select value="Github" disabled>
<SelectTrigger>
<SelectValue />
</SelectTrigger>

<SelectContent>
<SelectItem value="Github">Github</SelectItem>
</SelectContent>
</Select>
</FormItem>

{/* Extract to custom github component */}

<ControlledCustomInput
control={form.control}
name="workflow"
label="Workflow"
description="The workflow that will be triggered when the webhook is called."
<ScrollArea className="h-full">
<form
className="space-y-8 p-8 max-w-3xl mx-auto"
onSubmit={handleSubmit}
>
{({ field: { ref: _, ...field }, className }) => (
<Select {...field} onValueChange={field.onChange}>
<SelectTrigger className={className}>
<SelectValue placeholder="Select a workflow" />
<TypographyH3>
{isEdit ? "Edit Webhook" : "Create Webhook"}
</TypographyH3>

<ControlledInput
control={form.control}
name="name"
label="Name"
/>

<ControlledInput
control={form.control}
name="description"
label="Description"
/>

<FormItem>
<FormLabel>Type</FormLabel>
<Select value="GitHub" disabled>
<SelectTrigger>
<SelectValue />
</SelectTrigger>

<SelectContent>{getWorkflowOptions()}</SelectContent>
<SelectContent>
<SelectItem value="GitHub">GitHub</SelectItem>
</SelectContent>
</Select>
)}
</ControlledCustomInput>

<ControlledInput
control={form.control}
name="secret"
label="Secret"
description="This secret should match the secret you provide to GitHub."
placeholder={hasSecret ? "(unchanged)" : ""}
/>

<ControlledInput
control={form.control}
name="token"
label="Token (optional)"
description="Optionally provide a token to add an extra layer of security."
placeholder={hasToken ? "(unchanged)" : ""}
/>

<ControlledCustomInput
control={form.control}
name="headers"
label="Headers"
>
{({ field }) => (
<MultiSelect
{...field}
options={GithubHeaderOptions}
value={field.value.map((v) => ({ label: v, value: v }))}
creatable
onChange={(value) =>
field.onChange(value.map((v) => v.value))
}
side="top"
/>
)}
</ControlledCustomInput>

<Button
className="w-full"
type="submit"
disabled={isLoading}
loading={isLoading}
>
{isEdit ? "Update Webhook" : "Create Webhook"}
</Button>
</form>
</FormItem>

{/* Extract to custom github component */}

<ControlledCustomInput
control={form.control}
name="workflow"
label="Workflow"
description="The workflow that will be triggered when the webhook is called."
>
{({ field: { ref: _, ...field }, className }) => (
<Select
defaultValue={field.value}
onValueChange={field.onChange}
key={field.value}
>
<SelectTrigger className={className}>
<SelectValue placeholder="Select a workflow" />
</SelectTrigger>

<SelectContent>
{getWorkflowOptions()}
</SelectContent>
</Select>
)}
</ControlledCustomInput>

<ControlledInput
control={form.control}
name="secret"
label="Secret"
description="This secret should match the secret you provide to GitHub."
placeholder={hasSecret ? "(unchanged)" : ""}
/>

<TypographyH4>Advanced</TypographyH4>

<ControlledInput
control={form.control}
name="token"
label="Token (optional)"
description="Optionally provide a token to filter out unauthorized webhook requests."
placeholder={hasToken ? "(unchanged)" : ""}
/>

<ControlledCustomInput
control={form.control}
name="headers"
label="Headers"
>
{({ field }) => (
<MultiSelect
{...field}
options={GithubHeaderOptions}
value={field.value.map((v) => ({
label: v,
value: v,
}))}
creatable
onChange={(value) =>
field.onChange(value.map((v) => v.value))
}
side="top"
/>
)}
</ControlledCustomInput>

<Button
className="w-full"
type="submit"
disabled={isLoading}
loading={isLoading}
>
{isEdit ? "Update Webhook" : "Create Webhook"}
</Button>
</form>
</ScrollArea>
);

function getWorkflowOptions() {
const workflow = form.watch("workflow");

if (getWorkflows.isLoading)
return (
<SelectEmptyItem disabled>Loading workflows...</SelectEmptyItem>
<SelectItem value={workflow || "loading"} disabled>
Loading workflows...
</SelectItem>
);

if (!workflows?.length)
return (
<SelectEmptyItem disabled>No workflows found</SelectEmptyItem>
<SelectItem value={workflow || "empty"} disabled>
No workflows found
</SelectItem>
);

return workflows.map((workflow) => (
Expand Down
7 changes: 5 additions & 2 deletions ui/admin/app/components/webhooks/WebhookFormContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type WebhookFormContextType = {
const Context = createContext<WebhookFormContextType | null>(null);

const CreateSchema = WebhookSchema;
const EditSchema = WebhookSchema.omit({ token: true }).extend({
const EditSchema = WebhookSchema.extend({
secret: z.string(),
});

Expand Down Expand Up @@ -90,11 +90,14 @@ export function WebhookFormContextProvider({
return;
}

console.log("values", values);

mutate(WebhookApiService.getWebhooks.key());
showWebhookConfirmation({
webhook: data,
secret: values.secret,
token: values.token,
original: webhook,
});
});

Expand All @@ -104,7 +107,7 @@ export function WebhookFormContextProvider({
value={{
error: updateWebhook.error || createWebhook.error,
isEdit: !!webhookId,
hasSecret: !!webhookId,
hasSecret: !!webhook?.secret,
hasToken: !!webhook?.hasToken,
handleSubmit,
isLoading:
Expand Down
Loading

0 comments on commit 1972350

Please sign in to comment.