Files
probo/apps/console/src/components/form/AuditSelectField.tsx
Bryan Frimin 13ca50df68 Fix relay lint in components and pages
Remove unused GraphQL fields (createdAt, updatedAt, totalCount,
__id, sourceId, etc.) from queries and fragments across 50+ files.

Add TypeScript generics to useMutation, usePaginationFragment,
useRefetchableFragment, and useLazyLoadQuery calls to satisfy
relay/generated-typescript-types.

Add justified eslint-disable comments for fields needed by Relay
cache normalization (id) or consumed by sibling components through
fragment spreads.

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-03-15 13:32:43 +01:00

124 lines
3.3 KiB
TypeScript

import { getAuditStateLabel, getAuditStateVariant } from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
import { Badge, Field, Option, Select } from "@probo/ui";
import { type ComponentProps, Suspense } from "react";
import {
type Control,
Controller,
type FieldValues,
type Path,
} from "react-hook-form";
import { graphql, useLazyLoadQuery } from "react-relay";
import type { AuditSelectFieldQuery } from "#/__generated__/core/AuditSelectFieldQuery.graphql";
const auditsQuery = graphql`
query AuditSelectFieldQuery($organizationId: ID!) {
organization: node(id: $organizationId) {
... on Organization {
audits(first: 100) {
edges {
node {
id
name
framework {
id
name
}
state
}
}
}
}
}
}
`;
type Props<T extends FieldValues = FieldValues> = {
organizationId: string;
control: Control<T>;
name: Path<T>;
label?: string;
error?: string;
} & ComponentProps<typeof Field>;
export function AuditSelectField<T extends FieldValues = FieldValues>({
organizationId,
control,
...props
}: Props<T>) {
return (
<Field {...props}>
<Suspense
fallback={<Select variant="editor" loading placeholder="Loading..." />}
>
<AuditSelectWithQuery
organizationId={organizationId}
control={control}
name={props.name}
disabled={props.disabled}
/>
</Suspense>
</Field>
);
}
function AuditSelectWithQuery<T extends FieldValues = FieldValues>(
props: Pick<Props<T>, "organizationId" | "control" | "name" | "disabled">,
) {
const { __ } = useTranslate();
const { name, organizationId, control } = props;
const data = useLazyLoadQuery<AuditSelectFieldQuery>(
auditsQuery,
{ organizationId },
{ fetchPolicy: "network-only" },
);
const audits
= data?.organization?.audits?.edges
?.map(edge => edge.node)
.filter(node => node !== null) ?? [];
const NONE_VALUE = "__NONE__";
return (
<Controller
control={control}
name={name}
render={({ field }) => (
<Select
disabled={props.disabled}
id={name}
variant="editor"
placeholder={__("Select an audit")}
onValueChange={value =>
field.onChange(value === NONE_VALUE ? "" : value)}
key={audits?.length.toString() ?? "0"}
{...field}
className="w-full"
value={field.value || NONE_VALUE}
>
<Option value={NONE_VALUE}>
<span className="text-txt-tertiary">{__("None")}</span>
</Option>
{audits?.map(audit => (
<Option key={audit.id} value={audit.id}>
<div className="flex items-center justify-between w-full">
<span>
{audit.name
? `${audit.framework.name} - ${audit.name}`
: audit.framework.name}
</span>
<div className="ml-3">
<Badge variant={getAuditStateVariant(audit.state)}>
{getAuditStateLabel(__, audit.state)}
</Badge>
</div>
</div>
</Option>
))}
</Select>
)}
/>
);
}