From 7968c4357b875e210eddf3c2c08dbe0d488354e6 Mon Sep 17 00:00:00 2001 From: Fred KISSIE Date: Mon, 18 May 2026 22:14:49 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20edit=20org=20label?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- messages/en-US.json | 3 + src/components/CreateOrgLabelDialog.tsx | 2 +- src/components/EditOrgLabelDialog.tsx | 109 ++++++++++++++++++++++++ src/components/OrgLabelForm.tsx | 7 +- src/components/OrgLabelsTable.tsx | 20 ++++- 5 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 src/components/EditOrgLabelDialog.tsx diff --git a/messages/en-US.json b/messages/en-US.json index da5c8a4a5..ec6144233 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -265,6 +265,9 @@ "labelCreate": "Create Label", "createLabelDialogTitle": "Create Label", "createLabelDialogDescription": "Create a new label that can be attached to this organization", + "labelEdit": "Edit Label", + "editLabelDialogTitle": "Update Label", + "editLabelDialogDescription": "Edit a new label that can be attached to this organization", "labelDeleteConfirm": "Confirm Delete Label", "labelErrorDelete": "Failed to delete label", "labelMessageRemove": "This action is permanent. All sites, resources, and clients tagged with this label will be untagged.", diff --git a/src/components/CreateOrgLabelDialog.tsx b/src/components/CreateOrgLabelDialog.tsx index d91a075c0..9e1ab12f5 100644 --- a/src/components/CreateOrgLabelDialog.tsx +++ b/src/components/CreateOrgLabelDialog.tsx @@ -63,7 +63,7 @@ export function CreateOrgLabelDialog({ return ( - + {t("createLabelDialogTitle")} diff --git a/src/components/EditOrgLabelDialog.tsx b/src/components/EditOrgLabelDialog.tsx new file mode 100644 index 000000000..98891cd38 --- /dev/null +++ b/src/components/EditOrgLabelDialog.tsx @@ -0,0 +1,109 @@ +"use client"; + +import { useEnvContext } from "@app/hooks/useEnvContext"; +import { toast } from "@app/hooks/useToast"; +import { createApiClient, formatAxiosError } from "@app/lib/api"; +import type { CreateOrEditLabelResponse } from "@server/routers/labels/types"; +import type { AxiosResponse } from "axios"; +import { useTranslations } from "next-intl"; +import { useTransition } from "react"; +import { + Credenza, + CredenzaBody, + CredenzaClose, + CredenzaContent, + CredenzaDescription, + CredenzaFooter, + CredenzaHeader, + CredenzaTitle +} from "./Credenza"; +import { OrgLabelForm } from "./OrgLabelForm"; +import { Button } from "./ui/button"; + +export type EditOrgLabelDialogProps = { + open: boolean; + setOpen: (val: boolean) => void; + orgId: string; + onSuccess?: () => void; + label: { + name: string; + color: string; + labelId: number; + }; +}; + +export function EditOrgLabelDialog({ + open, + setOpen, + orgId, + onSuccess, + label +}: EditOrgLabelDialogProps) { + const t = useTranslations(); + const api = createApiClient(useEnvContext()); + const [isSubmitting, startTransition] = useTransition(); + + async function editOrgLabel(data: { name: string; color: string }) { + try { + const res = await api.patch< + AxiosResponse + >(`/org/${orgId}/label/${label.labelId}`, data); + + if (res.status === 200) { + setOpen(false); + onSuccess?.(); + + toast({ + title: t("success"), + description: t("labelEditSuccessMessage") + }); + } + } catch (e) { + toast({ + title: t("error"), + description: formatAxiosError(e, t("errorOccurred")), + variant: "destructive" + }); + } + } + + return ( + + + + {t("editLabelDialogTitle")} + + {t("editLabelDialogDescription")} + + + + { + startTransition(async () => editOrgLabel(data)); + }} + /> + + + + + + + + + + ); +} diff --git a/src/components/OrgLabelForm.tsx b/src/components/OrgLabelForm.tsx index 492c80e95..32a31550e 100644 --- a/src/components/OrgLabelForm.tsx +++ b/src/components/OrgLabelForm.tsx @@ -34,9 +34,10 @@ export type LabelFormData = z.infer; export type OrgLabelFormProps = { onSubmit: (data: LabelFormData) => void; + defaultValue?: LabelFormData; }; -export function OrgLabelForm({ onSubmit }: OrgLabelFormProps) { +export function OrgLabelForm({ onSubmit, defaultValue }: OrgLabelFormProps) { const t = useTranslations(); const colorValues = Object.values(LABEL_COLORS); @@ -46,8 +47,8 @@ export function OrgLabelForm({ onSubmit }: OrgLabelFormProps) { const form = useForm({ resolver: zodResolver(labelFormSchema), defaultValues: { - name: "", - color: randomColor + name: defaultValue?.name ?? "", + color: defaultValue?.color ?? randomColor } }); diff --git a/src/components/OrgLabelsTable.tsx b/src/components/OrgLabelsTable.tsx index 5fd90f28d..3ed95a9dc 100644 --- a/src/components/OrgLabelsTable.tsx +++ b/src/components/OrgLabelsTable.tsx @@ -33,6 +33,7 @@ import { getNextSortOrder, getSortDirection } from "@app/lib/sortColumn"; import { cn } from "@app/lib/cn"; import ConfirmDeleteDialog from "./ConfirmDeleteDialog"; import { CreateOrgLabelDialog } from "./CreateOrgLabelDialog"; +import { EditOrgLabelDialog } from "./EditOrgLabelDialog"; export type LabelRow = { labelId: number; @@ -134,7 +135,14 @@ export default function OrgLabelsTable({ - {t("edit")} + { + setSelectedLabel(row.original); + setIsEditModalOpen(true); + }} + > + {t("edit")} + { setSelectedLabel(row.original); @@ -192,6 +200,16 @@ export default function OrgLabelsTable({ string={selectedLabel.name} title={t("labelDelete")} /> + + + startTransition(() => router.refresh()) + } + label={selectedLabel} + /> )}