Fix some react hook form based prop types

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2025-12-03 14:20:24 +04:00
parent 21d2246f30
commit f3d45623bd
6 changed files with 56 additions and 59 deletions

View File

@@ -17,28 +17,27 @@ const deleteCustomDomainMutation = graphql`
} }
`; `;
type CustomDomain = {
readonly id: string;
readonly domain: string;
readonly sslStatus: string;
readonly dnsRecords?:
| readonly {
readonly type: string;
readonly name: string;
readonly value: string;
readonly ttl?: number;
readonly purpose: string;
}[]
| null;
readonly createdAt?: string | null;
readonly updatedAt?: string | null;
readonly sslExpiresAt?: string | null;
};
interface CustomDomainManagerProps { interface CustomDomainManagerProps {
organizationId: string; organizationId: string;
customDomain: customDomain: CustomDomain | null | undefined;
| {
readonly id: string;
readonly domain: string;
readonly sslStatus: string;
readonly dnsRecords?:
| readonly {
readonly type: string;
readonly name: string;
readonly value: string;
readonly ttl?: number;
readonly purpose: string;
}[]
| null;
readonly createdAt?: string | null;
readonly updatedAt?: string | null;
readonly sslExpiresAt?: string | null;
}
| null
| undefined;
} }
export function CustomDomainManager({ export function CustomDomainManager({
@@ -58,7 +57,7 @@ export function CustomDomainManager({
const domain = customDomain; const domain = customDomain;
const getStatusBadge = (domain: any) => { const getStatusBadge = (domain: CustomDomain) => {
if (domain.sslStatus === "ACTIVE") { if (domain.sslStatus === "ACTIVE") {
return <Badge variant="success">{__("Active")}</Badge>; return <Badge variant="success">{__("Active")}</Badge>;
} }

View File

@@ -1,19 +1,16 @@
import type { ComponentProps, JSX, JSXElementConstructor } from "react"; import type { ComponentProps } from "react";
import { Field } from "@probo/ui"; import { Field } from "@probo/ui";
import { Controller, type Control } from "react-hook-form"; import { Controller, type FieldValues } from "react-hook-form";
import { Select } from "@probo/ui"; import { Select } from "@probo/ui";
type Props<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> = type Props<T extends typeof Field | typeof Select, TFieldValues extends FieldValues = FieldValues> =
ComponentProps<T> & { ComponentProps<T> & Omit<ComponentProps<typeof Controller<TFieldValues>>, "render">;
control: Control<any>;
name: string;
};
export function ControlledField({ export function ControlledField<TFieldValues extends FieldValues = FieldValues>({
control, control,
name, name,
...props ...props
}: Props<typeof Field>) { }: Props<typeof Field, TFieldValues>) {
return ( return (
<Controller <Controller
control={control} control={control}

View File

@@ -1,21 +1,21 @@
import { Button, IconPlusLarge, IconTrashCan, Input, Label } from "@probo/ui"; import { Button, IconPlusLarge, IconTrashCan, Input, Label } from "@probo/ui";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { useFieldArray } from "react-hook-form"; import { useFieldArray } from "react-hook-form";
import type { Control } from "react-hook-form"; import type { ArrayPath, Control, FieldValue, FieldValues, Path } from "react-hook-form";
import type { UseFormRegister } from "react-hook-form"; import type { UseFormRegister } from "react-hook-form";
type Props = { type Props<TFieldValues extends FieldValues = FieldValues> = {
control: Control<any>; control: Control<TFieldValues>;
register: UseFormRegister<any>; register: UseFormRegister<TFieldValues>;
}; };
/** /**
* A field to handle multiple emails * A field to handle multiple emails
*/ */
export function EmailsField({ control, register }: Props) { export function EmailsField<TFieldValues extends FieldValues = FieldValues>({ control, register }: Props<TFieldValues>) {
const { __ } = useTranslate(); const { __ } = useTranslate();
const { fields, append, remove } = useFieldArray({ const { fields, append, remove } = useFieldArray({
name: "additionalEmailAddresses", name: "additionalEmailAddresses" as ArrayPath<TFieldValues>,
control, control,
}); });
@@ -26,7 +26,7 @@ export function EmailsField({ control, register }: Props) {
<div key={field.id} className="flex items-stretch"> <div key={field.id} className="flex items-stretch">
<Input <Input
className="w-full" className="w-full"
{...register(`additionalEmailAddresses.${index}`)} {...register(`additionalEmailAddresses.${index}` as Path<TFieldValues>)}
type="email" type="email"
/> />
<Button <Button
@@ -40,7 +40,7 @@ export function EmailsField({ control, register }: Props) {
variant="tertiary" variant="tertiary"
type="button" type="button"
icon={IconPlusLarge} icon={IconPlusLarge}
onClick={() => append("")} onClick={() => append("" as FieldValue<TFieldValues>)}
> >
{__("Add email")} {__("Add email")}
</Button> </Button>

View File

@@ -1,30 +1,30 @@
import { Field, Combobox, ComboboxItem } from "@probo/ui"; import { Field, Combobox, ComboboxItem } from "@probo/ui";
import { Suspense, useMemo, useState, type ComponentProps } from "react"; import { Suspense, useMemo, useState, type ComponentProps } from "react";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { type Control, Controller } from "react-hook-form"; import { type Control, Controller, type FieldPath, type FieldValues } from "react-hook-form";
import { usePaginatedMeasures } from "/hooks/graph/usePaginatedMeasures"; import { usePaginatedMeasures } from "/hooks/graph/usePaginatedMeasures";
type Props = { type Props<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
organizationId: string; organizationId: string;
control: Control<any>; control: Control<TFieldValues>;
name: string; name: TName;
label?: string; label?: string;
error?: string; error?: string;
disabled?: boolean; disabled?: boolean;
} & ComponentProps<typeof Field>; } & ComponentProps<typeof Field>;
export function MeasureSelectField({ export function MeasureSelectField<TFieldValues extends FieldValues = FieldValues>({
organizationId, organizationId,
control, control,
disabled, disabled,
...props ...props
}: Props) { }: Props<TFieldValues>) {
return ( return (
<Field {...props}> <Field {...props}>
<Suspense <Suspense
fallback={<Combobox onSearch={() => {}} placeholder="Loading..." disabled><div /></Combobox>} fallback={<Combobox onSearch={() => {}} placeholder="Loading..." disabled><div /></Combobox>}
> >
<MeasureSelectWithQuery <MeasureSelectWithQuery<TFieldValues>
organizationId={organizationId} organizationId={organizationId}
control={control} control={control}
name={props.name} name={props.name}
@@ -35,8 +35,8 @@ export function MeasureSelectField({
); );
} }
function MeasureSelectWithQuery( function MeasureSelectWithQuery<TFieldValues extends FieldValues = FieldValues>(
props: Pick<Props, "organizationId" | "control" | "name" | "disabled"> props: Pick<Props<TFieldValues>, "organizationId" | "control" | "name" | "disabled">
) { ) {
const { __ } = useTranslate(); const { __ } = useTranslate();
const { name, organizationId, control, disabled } = props; const { name, organizationId, control, disabled } = props;

View File

@@ -1,29 +1,29 @@
import { Avatar, Field, Option, Select } from "@probo/ui"; import { Avatar, Field, Option, Select } from "@probo/ui";
import { Suspense, type ComponentProps } from "react"; import { Suspense, type ComponentProps } from "react";
import { useTranslate } from "@probo/i18n"; import { useTranslate } from "@probo/i18n";
import { type Control, Controller } from "react-hook-form"; import { type Control, Controller, type FieldPath, type FieldValues } from "react-hook-form";
import { usePeople } from "/hooks/graph/PeopleGraph.ts"; import { usePeople } from "/hooks/graph/PeopleGraph.ts";
type Props = { type Props<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
organizationId: string; organizationId: string;
control: Control<any>; control: Control<TFieldValues>;
name: string; name: TName;
label?: string; label?: string;
error?: string; error?: string;
optional?: boolean; optional?: boolean;
} & ComponentProps<typeof Field>; } & ComponentProps<typeof Field>;
export function PeopleSelectField({ export function PeopleSelectField<TFieldValues extends FieldValues = FieldValues>({
organizationId, organizationId,
control, control,
...props ...props
}: Props) { }: Props<TFieldValues>) {
return ( return (
<Field {...props}> <Field {...props}>
<Suspense <Suspense
fallback={<Select variant="editor" loading placeholder="Loading..." />} fallback={<Select variant="editor" loading placeholder="Loading..." />}
> >
<PeopleSelectWithQuery <PeopleSelectWithQuery<TFieldValues>
organizationId={organizationId} organizationId={organizationId}
control={control} control={control}
name={props.name} name={props.name}
@@ -35,9 +35,9 @@ export function PeopleSelectField({
); );
} }
function PeopleSelectWithQuery( function PeopleSelectWithQuery<TFieldValues extends FieldValues = FieldValues>(
props: Pick< props: Pick<
Props, Props<TFieldValues>,
"organizationId" | "control" | "name" | "disabled" | "optional" "organizationId" | "control" | "name" | "disabled" | "optional"
>, >,
) { ) {

View File

@@ -53,9 +53,6 @@ export default function AssetDetailsPage(props: Props) {
const { snapshotId } = useParams<{ snapshotId?: string }>(); const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId); const isSnapshotMode = Boolean(snapshotId);
const { isAuthorized } = use(PermissionsContext); const { isAuthorized } = use(PermissionsContext);
if (!assetEntry || !assetEntry.id) {
return <div>{__("Asset not found")}</div>;
}
validateSnapshotConsistency(assetEntry, snapshotId); validateSnapshotConsistency(assetEntry, snapshotId);
@@ -82,6 +79,10 @@ export default function AssetDetailsPage(props: Props) {
const updateAsset = useUpdateAsset(); const updateAsset = useUpdateAsset();
if (!assetEntry || !assetEntry.id) {
return <div>{__("Asset not found")}</div>;
}
const onSubmit = handleSubmit(async (formData) => { const onSubmit = handleSubmit(async (formData) => {
await updateAsset({ await updateAsset({
id: assetEntry.id!, id: assetEntry.id!,