gitscope
← marzneshin / Diff · aa14012 → aa14012
Changes aa14012..aa14012
Patch commit
diff --git a/dashboard/src/features/hosts/dialogs/mutation/fields/fragment.tsx b/dashboard/src/features/hosts/dialogs/mutation/fields/fragment.tsx
index 87a0204..2ad049b 100644
--- a/dashboard/src/features/hosts/dialogs/mutation/fields/fragment.tsx
+++ b/dashboard/src/features/hosts/dialogs/mutation/fields/fragment.tsx
@@ -1,198 +1,194 @@
import {
- FormControl,
- FormField,
- FormItem,
- FormLabel,
- Input,
- Button,
- Popover,
- PopoverContent,
- PopoverTrigger,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ Input,
+ Button,
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
} from "@marzneshin/components";
-import {
- useWatch,
- useFormContext,
- FieldErrors,
- FieldError,
-} from "react-hook-form";
+import type { FieldErrors, FieldError } from "react-hook-form";
+import { useWatch, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { MailWarning, TrashIcon } from "lucide-react";
-import { FC } from "react";
+import type { FC } from "react";
interface FragmentForm {
- fragment: {
- packets: FieldError;
- length: FieldError;
- interval: FieldError;
- };
+ fragment: {
+ packets: FieldError;
+ length: FieldError;
+ interval: FieldError;
+ };
}
const FragmentErrorPopover: FC = () => {
- const form = useFormContext();
- const { t } = useTranslation();
- const errors = form.formState.errors as FieldErrors<FragmentForm>;
- return (
- <Popover>
- <PopoverTrigger>
- <MailWarning className="p-0 size-5 text-destructive bg-primary-background" />
- </PopoverTrigger>
- <PopoverContent className="bg-destructive-accent text-sm">
- <ul className="my-6 ml-3 list-disc [&>li]:mt-1 mt-0">
- {errors.fragment?.length?.message && (
- <li>
- <b>Length:</b> {t(errors.fragment.length.message as string)}
- </li>
- )}
- {errors.fragment?.packets?.message && (
- <li>
- <b>Packets:</b> {t(errors.fragment.packets.message as string)}
- </li>
- )}
- {errors.fragment?.interval?.message && (
- <li>
- <b>Interval:</b> {t(errors.fragment.interval.message as string)}
- </li>
- )}
- </ul>
- </PopoverContent>
- </Popover>
- );
+ const form = useFormContext();
+ const { t } = useTranslation();
+ const errors = form.formState.errors as FieldErrors<FragmentForm>;
+ return (
+ <Popover>
+ <PopoverTrigger>
+ <MailWarning className="p-0 size-5 text-destructive bg-primary-background" />
+ </PopoverTrigger>
+ <PopoverContent className="bg-destructive-accent text-sm">
+ <ul className="my-6 ml-3 list-disc [&>li]:mt-1 mt-0">
+ {errors.fragment?.length?.message && (
+ <li>
+ <b>Length:</b> {t(errors.fragment.length.message as string)}
+ </li>
+ )}
+ {errors.fragment?.packets?.message && (
+ <li>
+ <b>Packets:</b> {t(errors.fragment.packets.message as string)}
+ </li>
+ )}
+ {errors.fragment?.interval?.message && (
+ <li>
+ <b>Interval:</b> {t(errors.fragment.interval.message as string)}
+ </li>
+ )}
+ </ul>
+ </PopoverContent>
+ </Popover>
+ );
};
export const FragmentField = () => {
- const { t } = useTranslation();
- const form = useFormContext();
- const errors = form.formState.errors as FieldErrors<FragmentForm>;
- const fragment = useWatch({ name: "fragment" });
- const disabled = fragment === null;
+ const { t } = useTranslation();
+ const form = useFormContext();
+ const errors = form.formState.errors as FieldErrors<FragmentForm>;
+ const fragment = useWatch({ name: "fragment" });
+ const disabled = fragment === null || fragment === undefined;
- const enable = () => {
- form.setValue(
- "fragment",
- { length: "", packets: "", interval: "" },
- {
- shouldTouch: true,
- shouldDirty: true,
- },
- );
- };
+ const enable = () => {
+ form.setValue(
+ "fragment",
+ { length: "", packets: "", interval: "" },
+ {
+ shouldTouch: true,
+ shouldDirty: true,
+ },
+ );
+ };
- const disable = () => {
- form.setValue("fragment.length", "");
- form.setValue("fragment.packets", "");
- form.setValue("fragment.interval", "");
- form.setValue("fragment", null, {
- shouldValidate: true,
- shouldTouch: false,
- shouldDirty: false,
- });
- };
+ const disable = () => {
+ form.setValue("fragment.length", "");
+ form.setValue("fragment.packets", "");
+ form.setValue("fragment.interval", "");
+ form.setValue("fragment", null, {
+ shouldValidate: true,
+ shouldTouch: false,
+ shouldDirty: false,
+ });
+ };
- const hasFragmentErrors = (errors: FieldErrors<FragmentForm>) =>
- errors.fragment?.packets ||
- errors.fragment?.length ||
- errors.fragment?.interval;
+ const hasFragmentErrors = (errors: FieldErrors<FragmentForm>) =>
+ errors.fragment?.packets ||
+ errors.fragment?.length ||
+ errors.fragment?.interval;
- return (
- <FormField
- control={form.control}
- name="fragment"
- render={() => (
- <FormItem className="my-2 w-full">
- <FormLabel className="flex flex-row justify-between items-center">
- {t("fragment")}
- <div className="flex flex-row items-center gap-2">
- {hasFragmentErrors(errors) && <FragmentErrorPopover />}
- {!disabled && (
- <Button
- variant="destructive"
- className="p-0 size-5 bg-primary-background"
- onClick={(e) => {
- e.preventDefault();
- disable();
- }}
- >
- <TrashIcon className="text-red-400" />
- </Button>
- )}
- </div>
- </FormLabel>
+ return (
+ <FormField
+ control={form.control}
+ name="fragment"
+ render={() => (
+ <FormItem className="my-2 w-full">
+ <FormLabel className="flex flex-row justify-between items-center">
+ {t("fragment")}
+ <div className="flex flex-row items-center gap-2">
+ {hasFragmentErrors(errors) && <FragmentErrorPopover />}
+ {!disabled && (
+ <Button
+ variant="destructive"
+ className="p-0 size-5 bg-primary-background"
+ onClick={(e) => {
+ e.preventDefault();
+ disable();
+ }}
+ >
+ <TrashIcon className="text-red-400" />
+ </Button>
+ )}
+ </div>
+ </FormLabel>
- <FormControl>
- <div className="flex flex-row w-full items-center">
- {!disabled ? (
- <>
- <FormField
- name="fragment.packets"
- render={({ field }) => (
- <div className="flex flex-col">
- <FormItem>
- <FormLabel className="font-medium">
- {t("page.hosts.fragment.packets")}
- </FormLabel>
- <FormControl>
- <Input
- className="border rounded-none rounded-s-lg p-2 w-full"
- {...field}
- />
- </FormControl>
- </FormItem>
- </div>
- )}
- />
- <FormField
- name="fragment.length"
- render={({ field }) => (
- <div className="flex flex-col">
- <FormItem>
- <FormLabel className="font-medium">
- {t("page.hosts.fragment.length")}
- </FormLabel>
- <FormControl>
- <Input
- className="rounded-none w-full p-2"
- {...field}
- />
- </FormControl>
- </FormItem>
- </div>
- )}
- />
- <FormField
- name="fragment.interval"
- render={({ field }) => (
- <div className="flex flex-col">
- <FormItem>
- <FormLabel className="font-medium">
- {t("page.hosts.fragment.interval")}
- </FormLabel>
- <FormControl>
- <Input
- className="border w-full rounded-none rounded-e-lg p-2"
- {...field}
- />
- </FormControl>
- </FormItem>
- </div>
- )}
- />
- </>
- ) : (
- <Button
- className="border w-full"
- variant="ghost"
- onClick={(e) => {
- e.preventDefault();
- enable();
- }}
- >
- {t("disabled")}
- </Button>
- )}
- </div>
- </FormControl>
- </FormItem>
- )}
- />
- );
+ <FormControl>
+ <div className="flex flex-row w-full items-center">
+ {!disabled ? (
+ <>
+ <FormField
+ name="fragment.packets"
+ render={({ field }) => (
+ <div className="flex flex-col">
+ <FormItem>
+ <FormLabel className="font-medium">
+ {t("page.hosts.fragment.packets")}
+ </FormLabel>
+ <FormControl>
+ <Input
+ className="border rounded-none rounded-s-lg p-2 w-full"
+ {...field}
+ />
+ </FormControl>
+ </FormItem>
+ </div>
+ )}
+ />
+ <FormField
+ name="fragment.length"
+ render={({ field }) => (
+ <div className="flex flex-col">
+ <FormItem>
+ <FormLabel className="font-medium">
+ {t("page.hosts.fragment.length")}
+ </FormLabel>
+ <FormControl>
+ <Input
+ className="rounded-none w-full p-2"
+ {...field}
+ />
+ </FormControl>
+ </FormItem>
+ </div>
+ )}
+ />
+ <FormField
+ name="fragment.interval"
+ render={({ field }) => (
+ <div className="flex flex-col">
+ <FormItem>
+ <FormLabel className="font-medium">
+ {t("page.hosts.fragment.interval")}
+ </FormLabel>
+ <FormControl>
+ <Input
+ className="border w-full rounded-none rounded-e-lg p-2"
+ {...field}
+ />
+ </FormControl>
+ </FormItem>
+ </div>
+ )}
+ />
+ </>
+ ) : (
+ <Button
+ className="border w-full"
+ variant="ghost"
+ onClick={(e) => {
+ e.preventDefault();
+ enable();
+ }}
+ >
+ {t("disabled")}
+ </Button>
+ )}
+ </div>
+ </FormControl>
+ </FormItem>
+ )}
+ />
+ );
};
diff --git a/dashboard/src/features/hosts/dialogs/mutation/index.tsx b/dashboard/src/features/hosts/dialogs/mutation/index.tsx
index 9428b92..35ada51 100644
--- a/dashboard/src/features/hosts/dialogs/mutation/index.tsx
+++ b/dashboard/src/features/hosts/dialogs/mutation/index.tsx
@@ -1,4 +1,5 @@
-import { FC, useEffect } from "react";
+import { useEffect } from "react";
+import type { FC } from "react";
import {
DialogTitle,
DialogContent,
@@ -10,17 +11,19 @@ import {
AccordionContent,
AccordionItem,
AccordionTrigger,
+ ScrollArea,
+ HStack,
} from "@marzneshin/components";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useTranslation } from "react-i18next";
import {
HostSchema,
- HostType,
getDefaultValues,
useHostsCreationMutation,
useHostsUpdateMutation,
} from "@marzneshin/features/hosts";
+import type { HostType } from "@marzneshin/features/hosts";
import { RemarkField } from "./fields/remark";
import {
AddressField,
@@ -76,44 +79,49 @@ export const HostsMutationDialog: FC<MutationDialogProps> = ({
return (
<Dialog open={open} onOpenChange={onOpenChange} defaultOpen={true}>
- <DialogContent>
- <DialogHeader>
- <DialogTitle className="text-primary">
- {entity
- ? t("page.hosts.dialogs.edition.title")
- : t("page.hosts.dialogs.creation.title")}
- </DialogTitle>
- </DialogHeader>
- <Form {...form}>
- <form onSubmit={form.handleSubmit(submit)}>
- <RemarkField />
- <div className="flex flex-row gap-2 items-start">
- <AddressField />
- <PortField />
- </div>
- <Accordion type="single" collapsible>
- <AccordionItem value="item-1">
- <AccordionTrigger>{t("advanced-options")}</AccordionTrigger>
- <AccordionContent>
- <div className="flex flex-row gap-2 items-start">
- <HostField />
- <PathField />
- </div>
- <FragmentField />
- <MuxField />
- <SecurityFields />
- </AccordionContent>
- </AccordionItem>
- </Accordion>
- <Button
- className="mt-3 w-full font-semibold"
- type="submit"
- disabled={form.formState.isSubmitting}
+ <DialogContent className="min-w-full h-full md:h-auto md:min-w-[32rem]">
+ <ScrollArea className="flex flex-col h-full p-0">
+ <DialogHeader className="mb-3">
+ <DialogTitle className="text-primary">
+ {entity
+ ? t("page.hosts.dialogs.edition.title")
+ : t("page.hosts.dialogs.creation.title")}
+ </DialogTitle>
+ </DialogHeader>
+ <Form {...form}>
+ <form
+ onSubmit={form.handleSubmit(submit)}
+ className="h-full flex flex-col justify-between"
>
- {t("submit")}
- </Button>
- </form>
- </Form>
+ <RemarkField />
+ <HStack className="gap-2 items-start">
+ <AddressField />
+ <PortField />
+ </HStack>
+ <Accordion type="single" collapsible>
+ <AccordionItem value="item-1">
+ <AccordionTrigger>{t("advanced-options")}</AccordionTrigger>
+ <AccordionContent>
+ <div className="flex flex-row gap-2 items-start">
+ <HostField />
+ <PathField />
+ </div>
+ <FragmentField />
+ <MuxField />
+ <SecurityFields />
+ </AccordionContent>
+ </AccordionItem>
+ </Accordion>
+ <Button
+ className="mt-3 w-full font-semibold"
+ type="submit"
+ disabled={form.formState.isSubmitting}
+ >
+ {t("submit")}
+ </Button>
+ </form>
+ </Form>
+ </ScrollArea>
</DialogContent>
</Dialog>
);
diff --git a/dashboard/src/features/users/dialogs/mutation/index.tsx b/dashboard/src/features/users/dialogs/mutation/index.tsx
index 180ed74..a39844c 100644
--- a/dashboard/src/features/users/dialogs/mutation/index.tsx
+++ b/dashboard/src/features/users/dialogs/mutation/index.tsx
@@ -65,7 +65,7 @@ export const UsersMutationDialog: FC<UsersMutationDialogProps> = ({
return (
<Dialog open={open} onOpenChange={onOpenChange} defaultOpen={true}>
- <DialogContent className="min-w-full h-full md:h-[42rem] md:min-w-[42rem]">
+ <DialogContent className="min-w-full h-full md:h-auto md:min-w-[42rem]">
<ScrollArea className="flex flex-col justify-between h-full p-0">
<DialogHeader>
<DialogTitle className="text-primary">