Skip to content
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

feat: Slug validation on update deployment #15

Merged
merged 42 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c1a51fc
wip: merge origin main
zacharyblasczyk Sep 5, 2024
69586cc
fix conflict
zacharyblasczyk Sep 5, 2024
cbb310c
Init Slug Validation
zacharyblasczyk Sep 5, 2024
5c4fed7
Merge remote-tracking branch 'origin' into zacharyb/slug-validation
zacharyblasczyk Sep 5, 2024
25d08e7
fix
zacharyblasczyk Sep 5, 2024
dd622de
tried to invalidate the system id that generates the deploymet by pas…
zacharyblasczyk Sep 5, 2024
17ae503
fix
zacharyblasczyk Sep 5, 2024
51aebbf
trying to fix
zacharyblasczyk Sep 5, 2024
225f662
revert
zacharyblasczyk Sep 9, 2024
2571c9a
Merge remote-tracking branch 'origin' into zacharyb/slug-validation
zacharyblasczyk Sep 9, 2024
c37efa0
fix workspace creation, default admin role
zacharyblasczyk Sep 9, 2024
6532707
validation
zacharyblasczyk Sep 10, 2024
4066620
cleanup
zacharyblasczyk Sep 10, 2024
4affbeb
cleanup
zacharyblasczyk Sep 10, 2024
c9ac07b
format
zacharyblasczyk Sep 10, 2024
ec29188
fix
zacharyblasczyk Sep 10, 2024
c19956c
fix merge conflicts
zacharyblasczyk Sep 13, 2024
3a1ab99
fixed most of the issues. handling createRelease next
zacharyblasczyk Sep 14, 2024
b352909
small fix
zacharyblasczyk Sep 14, 2024
3b3e14b
fix
zacharyblasczyk Sep 14, 2024
3c82aff
revert
zacharyblasczyk Sep 14, 2024
5a58d9f
revert
zacharyblasczyk Sep 14, 2024
8e3cb89
fix
zacharyblasczyk Sep 14, 2024
dbaabbb
revert
zacharyblasczyk Sep 14, 2024
95528ca
fix
zacharyblasczyk Sep 14, 2024
ccf5e78
revert
zacharyblasczyk Sep 14, 2024
bb8776d
revert
zacharyblasczyk Sep 14, 2024
f1e92a0
fix
zacharyblasczyk Sep 14, 2024
a2d406a
revert
zacharyblasczyk Sep 14, 2024
b63cc01
missed file
zacharyblasczyk Sep 14, 2024
ccf65e8
fix
zacharyblasczyk Sep 14, 2024
b5837fd
fix deployment
zacharyblasczyk Sep 14, 2024
1859a6c
fix
zacharyblasczyk Sep 14, 2024
96dc37c
merge
zacharyblasczyk Sep 17, 2024
227bc42
update
zacharyblasczyk Sep 17, 2024
bf4bdd2
Merge remote-tracking branch 'origin' into zacharyb/slug-validation
zacharyblasczyk Sep 17, 2024
732fecf
revert
zacharyblasczyk Sep 17, 2024
b3aeb43
fix
zacharyblasczyk Sep 17, 2024
7056e2c
onSubmit
zacharyblasczyk Sep 17, 2024
3f6216b
fix props
zacharyblasczyk Sep 17, 2024
2bca56c
merge conflict
zacharyblasczyk Sep 18, 2024
c3ee5b7
fix merge
zacharyblasczyk Sep 18, 2024
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
8 changes: 6 additions & 2 deletions apps/webservice/src/app/[workspaceSlug]/SidebarCreateMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import { CreateSystemDialog } from "./_components/CreateSystem";

export const SidebarCreateMenu: React.FC<{
workspaceId: string;
workspaceSlug: string;
deploymentId?: string;
systemId?: string;
}> = ({ workspaceId, deploymentId, systemId }) => {
}> = ({ workspaceId, workspaceSlug, deploymentId, systemId }) => {
const [open, setOpen] = useState(false);
return (
<DropdownMenu open={open} onOpenChange={setOpen}>
Expand All @@ -38,7 +39,10 @@ export const SidebarCreateMenu: React.FC<{
forceMount
>
<DropdownMenuGroup>
<CreateSystemDialog workspaceId={workspaceId}>
<CreateSystemDialog
workspaceId={workspaceId}
workspaceSlug={workspaceSlug}
>
<DropdownMenuItem onSelect={(e) => e.preventDefault()}>
New System
</DropdownMenuItem>
Expand Down
1 change: 1 addition & 0 deletions apps/webservice/src/app/[workspaceSlug]/SidebarMain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const SidebarMain: React.FC<{

<SidebarCreateMenu
workspaceId={workspace.id}
workspaceSlug={workspace.slug}
systemId={system.data?.id}
deploymentId={deployment.data?.id}
/>
Expand Down
5 changes: 4 additions & 1 deletion apps/webservice/src/app/[workspaceSlug]/SidebarSystems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ export const SidebarSystems: React.FC<{
</CollapsibleTrigger>
<CollapsibleContent className="space-y-1">
{systems.length === 0 && (
<CreateSystemDialog workspaceId={workspace.id}>
<CreateSystemDialog
zacharyblasczyk marked this conversation as resolved.
Show resolved Hide resolved
workspaceId={workspace.id}
workspaceSlug={workspace.slug}
>
<Button
className="flex w-full items-center justify-start gap-1.5 text-left"
variant="ghost"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import React, { useEffect, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import slugify from "slugify";
import { z } from "zod";
Expand All @@ -22,6 +23,8 @@ import {
FormField,
FormItem,
FormLabel,
FormMessage,
FormRootMessage,
} from "@ctrlplane/ui/form";
import { Input } from "@ctrlplane/ui/input";
import {
Expand All @@ -35,12 +38,27 @@ import {
import { Textarea } from "@ctrlplane/ui/textarea";

import { api } from "~/trpc/react";
import { safeFormAwait } from "~/utils/error/safeAwait";

const deploymentForm = z.object({
name: z.string().min(3).max(255),
slug: z.string().min(3).max(255),
systemId: z.string().uuid(),
description: z.string().default(""),
name: z
zacharyblasczyk marked this conversation as resolved.
Show resolved Hide resolved
.string()
.min(3, { message: "Deployment name must be at least 3 characters long." })
.max(255, {
message: "Deployment name must be at most 255 characters long.",
}),
slug: z
.string()
.min(3, { message: "Slug must be at least 3 characters long." })
.max(255, { message: "Slug must be at most 255 characters long." }),
description: z
.string()
.max(255, { message: "Description must be at most 255 characters long." })
.optional()
.refine((val) => !val || val.length >= 3, {
message: "Description must be at least 3 characters long if provided.",
}),
});

type DeploymentFormValues = z.infer<typeof deploymentForm>;
Expand All @@ -51,22 +69,39 @@ export const CreateDeploymentDialog: React.FC<{
}> = ({ children, defaultSystemId = "" }) => {
const { workspaceSlug } = useParams<{ workspaceSlug: string }>();
const workspace = api.workspace.bySlug.useQuery(workspaceSlug);
const create = api.deployment.create.useMutation();
const router = useRouter();
const [open, setOpen] = useState(false);

const create = api.deployment.create.useMutation({
onSuccess: (deployment) => {
zacharyblasczyk marked this conversation as resolved.
Show resolved Hide resolved
router.refresh();
const slug = systems.data?.items.find(
(system) => system.id === deployment.systemId,
)?.slug;
if (slug == null) return;
router.push(
`/${workspaceSlug}/systems/${slug}/deployments/${deployment.slug}`,
);
setOpen(false);
},
});

const form = useForm<DeploymentFormValues>({
resolver: zodResolver(deploymentForm),
zacharyblasczyk marked this conversation as resolved.
Show resolved Hide resolved
defaultValues: {
systemId: defaultSystemId,
name: "",
slug: "",
description: "",
},
mode: "onChange",
zacharyblasczyk marked this conversation as resolved.
Show resolved Hide resolved
});

const { systemId, name } = form.watch();
useEffect(
() => form.setValue("slug", slugify(name, { lower: true })),
[form, name],
);
const [open, setOpen] = useState(false);
useEffect(() => {
if (!open) return;
if (defaultSystemId === "") return;
Expand All @@ -87,18 +122,13 @@ export const CreateDeploymentDialog: React.FC<{
form.setValue("systemId", firstSystem.id);
}, [defaultSystemId, form, systems, systemId]);

const router = useRouter();
const onSubmit = form.handleSubmit(async (data) => {
const deployment = await create.mutateAsync(data);
router.refresh();
const slug = systems.data?.items.find(
(system) => system.id === deployment.systemId,
)?.slug;
if (slug == null) return;
router.push(
`/${workspaceSlug}/systems/${slug}/deployments/${deployment.slug}`,
const [_, error] = await safeFormAwait(
create.mutateAsync({ ...data, description: data.description ?? "" }),
zacharyblasczyk marked this conversation as resolved.
Show resolved Hide resolved
form,
{ entityName: "deployment" },
);
setOpen(false);
if (error != null) return;
zacharyblasczyk marked this conversation as resolved.
Show resolved Hide resolved
});

return (
Expand Down Expand Up @@ -137,6 +167,7 @@ export const CreateDeploymentDialog: React.FC<{
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
Expand All @@ -152,6 +183,7 @@ export const CreateDeploymentDialog: React.FC<{
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
Expand All @@ -164,6 +196,7 @@ export const CreateDeploymentDialog: React.FC<{
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
Expand All @@ -176,9 +209,11 @@ export const CreateDeploymentDialog: React.FC<{
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormRootMessage />
<DialogFooter>
<Button type="submit">Create</Button>
</DialogFooter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
FormField,
FormItem,
FormLabel,
FormRootMessage,
useFieldArray,
useForm,
} from "@ctrlplane/ui/form";
Expand All @@ -39,6 +40,7 @@ import {
import { toast } from "@ctrlplane/ui/toast";

import { api } from "~/trpc/react";
import { safeFormAwait } from "~/utils/error/safeAwait";

const releaseDependency = z.object({
targetLabelGroupId: z.string().uuid().optional(),
Expand Down Expand Up @@ -109,7 +111,13 @@ export const CreateReleaseDialog: React.FC<{
const router = useRouter();
const utils = api.useUtils();
const onSubmit = form.handleSubmit(async (data) => {
const release = await create.mutateAsync(data);
const [release, error] = await safeFormAwait(
zacharyblasczyk marked this conversation as resolved.
Show resolved Hide resolved
create.mutateAsync(data),
form,
{ entityName: "release" },
);
if (error != null) return;

await utils.release.list.invalidate({ deploymentId: release.deploymentId });

const deployment = deployments.data?.find(
Expand Down Expand Up @@ -368,6 +376,7 @@ export const CreateReleaseDialog: React.FC<{
<Button type="submit">Create</Button>
</DialogFooter>
</form>
<FormRootMessage />
</Form>
</DialogContent>
</Dialog>
Expand Down
Loading
Loading