import "./ReportParameters.css"; import { Checkbox, Field, FieldDescription, Label, Select, Textfield } from "@digdir/designsystemet-react"; import { coerceParameterValue, getLocalizedString, type ReportParameter, type ReportParameterValue, type ReportParameterValues, } from "@olenbetong/appframe-core"; import { useParameterOptions } from "@olenbetong/appframe-react"; import { Combobox } from "@olenbetong/appframe-ds"; import clsx from "clsx"; import { useId } from "react"; import type { FilterEditorSize } from "../filter/types.js"; export type ReportParametersProps = { /** The report's parameters, from `useReport`. */ parameters: ReportParameter[]; /** Current values, by parameter name. */ values: ReportParameterValues; onChange: (values: ReportParameterValues) => void; readOnly?: boolean; /** Heading above the parameters. Pass `null` to render none. */ legend?: string | null; className?: string; "data-size"?: FilterEditorSize; }; /** * The parameter form of the report launcher. * * Reports rarely have parameters, so this renders nothing at all when the list * is empty and the launcher can include it unconditionally. * * Each parameter gets the editor its metadata asks for: a lookup combobox when * it is backed by a record source, a select when it has a fixed item list, and * otherwise an editor for its data type. Values are coerced to the parameter's * type as they are entered, so what the caller holds is what gets sent to the * report. * * @example * ```jsx * let { parameters, defaultValues } = useReport(reportId); * let [values, setValues] = useState(defaultValues); * * * ``` */ export function ReportParameters({ parameters, values, onChange, readOnly, legend = getLocalizedString("Parameters"), className, "data-size": size = "sm", }: ReportParametersProps) { if (parameters.length === 0) return null; function update(parameter: ReportParameter, value: ReportParameterValue) { onChange({ ...values, [parameter.name]: value }); } return (
{legend && {legend}}
{parameters.map((parameter) => ( update(parameter, value)} readOnly={readOnly} size={size} /> ))}
); } type ReportParameterFieldProps = { parameter: ReportParameter; value: ReportParameterValue; onChange: (value: ReportParameterValue) => void; readOnly?: boolean; size: FilterEditorSize; }; /** The editor for a single parameter. */ export function ReportParameterField({ parameter, value, onChange, readOnly, size }: ReportParameterFieldProps) { // The hook returns nothing for parameters that are not lookups, so it can be // called for every parameter. let { options, loading } = useParameterOptions(parameter); let id = useId(); let commonProps = { "data-size": size, label: parameter.label, description: parameter.description ?? undefined, readOnly, }; switch (parameter.editor) { case "boolean": return (
onChange(event.target.checked)} />
); case "select": return (
{parameter.description && {parameter.description}}
); case "lookup": return (
option.value === String(value ?? "")) ?? null} getOptionLabel={(option) => option.label} getOptionKey={(option) => option.value} isOptionEqualToValue={(option, selected) => option.value === selected.value} onChange={(_event, option) => onChange(option ? coerceParameterValue(parameter, option.value) : null)} />
); case "number": return (
onChange(coerceParameterValue(parameter, event.target.value))} />
); case "date": return (
onChange(event.target.value === "" ? null : event.target.value)} />
); default: return (
onChange(event.target.value === "" ? null : event.target.value)} />
); } }