mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
fix(rule-engine): use a real date picker, and stop the label wrapping
Date fields rendered as a native <input type="date">, which ignores the
form's styling and varies by browser. They now use Mantine's DateInput,
kept on the `YYYY-MM-DD` string the API's date columns take — no Date
round-trip, so none of the UTC-parsing shift that new Date("2026-01-01")
introduces east of Greenwich.
Labels were passed as an element, which put a flex box inside the
<label>: a line of dead space above every input, and Mantine's own
required asterisk pushed onto its own line. Passing the plain string and
withAsterisk lets Mantine render both.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { DateInput } from "@mantine/dates";
|
||||
import { Loader2, Plus, Trash2 } from "lucide-react";
|
||||
import {
|
||||
ActionIcon,
|
||||
@@ -162,16 +163,6 @@ const inputStyles = {
|
||||
label: { fontWeight: 600, marginBottom: 6, color: "var(--mantine-color-gray-8)" },
|
||||
} as const;
|
||||
|
||||
const FieldLabel = ({ label, required }: { label: string; required?: boolean }) => (
|
||||
<Group gap={4} wrap="nowrap">
|
||||
<span>{label}</span>
|
||||
{required ? (
|
||||
<Text component="span" c="red" size="sm">
|
||||
*
|
||||
</Text>
|
||||
) : null}
|
||||
</Group>
|
||||
);
|
||||
|
||||
const RuleEngineFormDialog = ({
|
||||
open,
|
||||
@@ -405,7 +396,11 @@ const RuleEngineFormDialog = ({
|
||||
);
|
||||
}
|
||||
|
||||
const label = <FieldLabel label={field.label} required={field.required} />;
|
||||
// A plain string, so Mantine renders the label and its required asterisk
|
||||
// itself. Passing an element here put a flex box inside the <label>,
|
||||
// which added a line of dead space above every input and bumped
|
||||
// Mantine's own asterisk onto a line of its own.
|
||||
const label = field.label;
|
||||
|
||||
if (field.type === "tierList") {
|
||||
const rows = Array.isArray(values[field.name])
|
||||
@@ -513,6 +508,7 @@ const RuleEngineFormDialog = ({
|
||||
<MultiSelect
|
||||
key={field.name}
|
||||
label={label}
|
||||
withAsterisk={field.required}
|
||||
description={field.description}
|
||||
placeholder={
|
||||
selectOptionsLoading
|
||||
@@ -602,6 +598,31 @@ const RuleEngineFormDialog = ({
|
||||
);
|
||||
}
|
||||
|
||||
if (field.type === "date") {
|
||||
const raw = String(values[field.name] ?? "");
|
||||
return (
|
||||
<DateInput
|
||||
key={field.name}
|
||||
label={label}
|
||||
description={field.description}
|
||||
placeholder="Select date"
|
||||
// Mantine's DateValue accepts a `YYYY-MM-DD` string, which is exactly
|
||||
// what the API's date columns take — so the value passes straight
|
||||
// through with no Date round-trip, and none of the UTC-parsing shift
|
||||
// that `new Date("2026-01-01")` would introduce east of Greenwich.
|
||||
value={raw || null}
|
||||
onChange={(v) => setField(field.name, v ?? "")}
|
||||
disabled={field.disabled || (field.disabledOnEdit && !!initialRecord)}
|
||||
required={field.required}
|
||||
error={fieldErrors[field.name] || undefined}
|
||||
clearable
|
||||
size="md"
|
||||
radius="md"
|
||||
styles={inputStyles}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const isNumber = field.type === "number";
|
||||
const computed = field.computeValue ? field.computeValue(values) : undefined;
|
||||
|
||||
@@ -610,7 +631,7 @@ const RuleEngineFormDialog = ({
|
||||
key={field.name}
|
||||
label={label}
|
||||
description={field.description}
|
||||
type={isNumber ? "number" : field.type === "date" ? "date" : "text"}
|
||||
type={isNumber ? "number" : "text"}
|
||||
// Every rule-engine number (sizes, capacities, counts, points, rates,
|
||||
// display order) is a non-negative magnitude — reject negatives outright
|
||||
// rather than letting a typed "-" reach the API.
|
||||
|
||||
Reference in New Issue
Block a user