feat: add PATCH method for scans

This commit is contained in:
Pablo Lara
2024-10-11 16:18:15 +02:00
parent f29e87f45b
commit 1fff7ef1d3
11 changed files with 196 additions and 33 deletions
+40 -1
View File
@@ -42,7 +42,8 @@ export const getScans = async ({
revalidatePath("/scans");
return parsedData;
} catch (error) {
console.error("Error fetching providers:", error);
// eslint-disable-next-line no-console
console.error("Error fetching scans:", error);
return undefined;
}
};
@@ -94,3 +95,41 @@ export const scanOnDemand = async (formData: FormData) => {
};
}
};
export const updateScan = async (formData: FormData) => {
const session = await auth();
const keyServer = process.env.API_BASE_URL;
const scanId = formData.get("scanId");
const scanName = formData.get("scanName");
const url = new URL(`${keyServer}/scans/${scanId}`);
try {
const response = await fetch(url.toString(), {
method: "PATCH",
headers: {
"Content-Type": "application/vnd.api+json",
Accept: "application/vnd.api+json",
Authorization: `Bearer ${session?.accessToken}`,
},
body: JSON.stringify({
data: {
type: "Scan",
id: scanId,
attributes: {
name: scanName,
},
},
}),
});
const data = await response.json();
revalidatePath("/scans");
return parseStringify(data);
} catch (error) {
console.error(error);
return {
error: getErrorMessage(error),
};
}
};
+1 -1
View File
@@ -9,11 +9,11 @@ import {
filterScans,
} from "@/components/filters";
import {
ColumnGetScans,
ColumnGetScansSchedule,
SkeletonTableScans,
} from "@/components/scans/table";
import { ColumnProviderScans } from "@/components/scans/table/provider-scans";
import { ColumnGetScans } from "@/components/scans/table/scans";
import { Header } from "@/components/ui";
import { DataTable } from "@/components/ui/table";
import { SearchParamsProps } from "@/types";
+1 -1
View File
@@ -77,7 +77,7 @@ export const EditForm = ({
name="alias"
type="text"
label="Alias"
labelPlacement="inside"
labelPlacement="outside"
placeholder={providerAlias}
variant="bordered"
isRequired={false}
+119
View File
@@ -0,0 +1,119 @@
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { Dispatch, SetStateAction } from "react";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { updateScan } from "@/actions/scans";
import { SaveIcon } from "@/components/icons";
import { useToast } from "@/components/ui";
import { CustomButton, CustomInput } from "@/components/ui/custom";
import { Form } from "@/components/ui/form";
import { editScanFormSchema } from "@/types";
export const EditScanForm = ({
scanId,
scanName,
setIsOpen,
}: {
scanId: string;
scanName: string;
setIsOpen: Dispatch<SetStateAction<boolean>>;
}) => {
const formSchema = editScanFormSchema(scanName);
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
scanId: scanId,
scanName: scanName,
},
});
const { toast } = useToast();
const isLoading = form.formState.isSubmitting;
const onSubmitClient = async (values: z.infer<typeof formSchema>) => {
const formData = new FormData();
Object.entries(values).forEach(
([key, value]) => value !== undefined && formData.append(key, value),
);
const data = await updateScan(formData);
if (data?.errors && data.errors.length > 0) {
const error = data.errors[0];
const errorMessage = `${error.detail}`;
// show error
toast({
variant: "destructive",
title: "Oops! Something went wrong",
description: errorMessage,
});
} else {
toast({
title: "Success!",
description: "The scan was updated successfully.",
});
setIsOpen(false); // Close the modal on success
}
};
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmitClient)}
className="flex flex-col space-y-4"
>
<div className="text-md">
Current name: <span className="font-bold">{scanName}</span>
</div>
<div>
<CustomInput
control={form.control}
name="scanName"
type="text"
label="Name"
labelPlacement="outside"
placeholder={scanName}
variant="bordered"
isRequired={false}
isInvalid={!!form.formState.errors.scanName}
/>
</div>
<input type="hidden" name="scanId" value={scanId} />
<div className="flex w-full justify-center sm:space-x-6">
<CustomButton
type="button"
ariaLabel="Cancel"
className="w-full bg-transparent"
variant="faded"
size="lg"
radius="lg"
onPress={() => setIsOpen(false)}
disabled={isLoading}
>
<span>Cancel</span>
</CustomButton>
<CustomButton
type="submit"
ariaLabel="Save"
className="w-full"
variant="solid"
color="action"
size="lg"
isLoading={isLoading}
startContent={!isLoading && <SaveIcon size={24} />}
>
{isLoading ? <>Loading</> : <span>Save</span>}
</CustomButton>
</div>
</form>
</Form>
);
};
+1
View File
@@ -1,2 +1,3 @@
export * from "./edit-scan-form";
export * from "./scan-on-demand-form";
export * from "./schedule-form";
@@ -6,7 +6,7 @@ import { DateWithTime, EntityInfoShort } from "@/components/ui/entities";
import { DataTableColumnHeader, StatusBadge } from "@/components/ui/table";
import { ScanProps } from "@/types";
import { DataTableRowActions } from "./data-table-row-actions";
import { DataTableRowActions } from "./scans/data-table-row-actions";
const getScanData = (row: { original: ScanProps }) => {
return row.original;
-2
View File
@@ -1,4 +1,2 @@
export * from "./column-get-scans";
export * from "./column-get-scans-schedule";
export * from "./data-table-row-actions";
export * from "./skeleton-table-scans";
@@ -9,7 +9,6 @@ import {
DropdownTrigger,
} from "@nextui-org/react";
import {
AddNoteBulkIcon,
DeleteDocumentBulkIcon,
EditDocumentBulkIcon,
} from "@nextui-org/shared-icons";
@@ -20,7 +19,8 @@ import { useState } from "react";
import { VerticalDotsIcon } from "@/components/icons";
import { CustomAlertModal } from "@/components/ui/custom";
// import { EditForm } from "../forms";
import { EditScanForm } from "../../forms";
// import { DeleteForm } from "../forms/delete-form";
interface DataTableRowActionsProps<ProviderProps> {
@@ -34,28 +34,27 @@ export function DataTableRowActions<ProviderProps>({
}: DataTableRowActionsProps<ProviderProps>) {
const [isEditOpen, setIsEditOpen] = useState(false);
const [isDeleteOpen, setIsDeleteOpen] = useState(false);
const providerId = (row.original as { id: string }).id;
// const providerAlias = (row.original as any).attributes?.alias;
const scanId = (row.original as { id: string }).id;
const scanName = (row.original as any).attributes?.name;
return (
<>
<CustomAlertModal
isOpen={isEditOpen}
onOpenChange={setIsEditOpen}
title="Edit Provider"
description={"Edit the provider details"}
title="Edit Scan"
description={"Edit the scan details"}
>
<p>Hello</p>
{/* <EditForm
providerId={providerId}
providerAlias={providerAlias}
<EditScanForm
scanId={scanId}
scanName={scanName}
setIsOpen={setIsEditOpen}
/> */}
/>
</CustomAlertModal>
<CustomAlertModal
isOpen={isDeleteOpen}
onOpenChange={setIsDeleteOpen}
title="Are you absolutely sure?"
description="This action cannot be undone. This will permanently delete your provider account and remove your data from the server."
description="This action cannot be undone. This will permanently delete your scan."
>
<p>Hello</p>
{/* <DeleteForm providerId={providerId} setIsOpen={setIsDeleteOpen} /> */}
@@ -75,23 +74,14 @@ export function DataTableRowActions<ProviderProps>({
variant="flat"
>
<DropdownSection title="Actions">
<DropdownItem
key="new"
description="Check the connection to the provider"
textValue="Check Connection"
startContent={<AddNoteBulkIcon className={iconClasses} />}
>
<p>action here + {providerId}</p>
{/* <CheckConnectionProvider id={providerId} /> */}
</DropdownItem>
<DropdownItem
key="edit"
description="Allows you to edit the provider"
textValue="Edit Provider"
description="Allows you to edit the scan"
textValue="Edit Scan"
startContent={<EditDocumentBulkIcon className={iconClasses} />}
onClick={() => setIsEditOpen(true)}
>
Edit Provider
Edit Scan
</DropdownItem>
</DropdownSection>
<DropdownSection title="Danger zone">
@@ -99,8 +89,8 @@ export function DataTableRowActions<ProviderProps>({
key="delete"
className="text-danger"
color="danger"
description="Delete the provider permanently"
textValue="Delete Provider"
description="Delete the scan permanently"
textValue="Delete Scan"
startContent={
<DeleteDocumentBulkIcon
className={clsx(iconClasses, "!text-danger")}
@@ -108,7 +98,7 @@ export function DataTableRowActions<ProviderProps>({
}
onClick={() => setIsDeleteOpen(true)}
>
Delete Provider
Delete Scan
</DropdownItem>
</DropdownSection>
</DropdownMenu>
+2
View File
@@ -0,0 +1,2 @@
export * from "./column-get-scans";
export * from "./data-table-row-actions";
+14
View File
@@ -1,5 +1,19 @@
import { z } from "zod";
export const editScanFormSchema = (currentName: string) =>
z.object({
scanName: z
.string()
.refine((val) => val === "" || val.length >= 3, {
message: "The alias must be empty or have at least 3 characters.",
})
.refine((val) => val !== currentName, {
message: "The new name must be different from the current one.",
})
.optional(),
scanId: z.string(),
});
export const onDemandScanFormSchema = () =>
z.object({
providerId: z.string(),