feat: Add smart density defaults based on material type (#2)
Some checks failed
CI / style (push) Has been cancelled
CI / build-client (push) Has been cancelled
CI / build-amd64 (push) Has been cancelled
CI / build-tester (push) Has been cancelled
CI / test (cockroachdb) (push) Has been cancelled
CI / test (mariadb) (push) Has been cancelled
CI / test (postgres) (push) Has been cancelled
CI / test (sqlite) (push) Has been cancelled
CI / build-arm64 (push) Has been cancelled
CI / build-armv7 (push) Has been cancelled
CI / publish-images (push) Has been cancelled
CI / publish-release (push) Has been cancelled
Some checks failed
CI / style (push) Has been cancelled
CI / build-client (push) Has been cancelled
CI / build-amd64 (push) Has been cancelled
CI / build-tester (push) Has been cancelled
CI / test (cockroachdb) (push) Has been cancelled
CI / test (mariadb) (push) Has been cancelled
CI / test (postgres) (push) Has been cancelled
CI / test (sqlite) (push) Has been cancelled
CI / build-arm64 (push) Has been cancelled
CI / build-armv7 (push) Has been cancelled
CI / publish-images (push) Has been cancelled
CI / publish-release (push) Has been cancelled
Auto-fill density when entering material type in filament forms: - Add materialDefaults.ts with standard densities for common materials (PLA, ABS, PETG, TPU, PC, etc.) - Material field now uses AutoComplete with suggestions - Density auto-fills on material select or blur (fuzzy matching) - New filaments default to 1.75mm diameter and 1.24 g/cm³ (PLA) - Applied to both full filament create page and quick create modal Reduces tedious data entry for common materials while still allowing custom values for specialty filaments. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,15 +1,21 @@
|
||||
import { Create, useForm, useSelect } from "@refinedev/antd";
|
||||
import { HttpError, IResourceComponentsProps, useInvalidate, useTranslate } from "@refinedev/core";
|
||||
import { Button, ColorPicker, Divider, Form, Input, InputNumber, Radio, Select, Typography } from "antd";
|
||||
import { AutoComplete, Button, ColorPicker, Divider, Form, Input, InputNumber, Radio, Select, Typography } from "antd";
|
||||
import { PlusOutlined } from "@ant-design/icons";
|
||||
import TextArea from "antd/es/input/TextArea";
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { ExtraFieldFormItem, ParsedExtras, StringifiedExtras } from "../../components/extraFields";
|
||||
import { FilamentImportModal } from "../../components/filamentImportModal";
|
||||
import { VendorCreateModal } from "../../components/vendorCreateModal";
|
||||
import { MultiColorPicker } from "../../components/multiColorPicker";
|
||||
import {
|
||||
DEFAULT_DENSITY,
|
||||
DEFAULT_DIAMETER,
|
||||
getDensityForMaterial,
|
||||
KNOWN_MATERIALS,
|
||||
} from "../../utils/materialDefaults";
|
||||
import { formatNumberOnUserInput, numberParser, numberParserAllowEmpty } from "../../utils/parsing";
|
||||
import { ExternalFilament } from "../../utils/queryExternalDB";
|
||||
import { EntityType, useGetFields } from "../../utils/queryFields";
|
||||
@@ -36,6 +42,15 @@ export const FilamentCreate: React.FC<IResourceComponentsProps & CreateOrClonePr
|
||||
const [isVendorModalOpen, setIsVendorModalOpen] = useState(false);
|
||||
const invalidate = useInvalidate();
|
||||
const [colorType, setColorType] = useState<"single" | "multi">("single");
|
||||
const [materialSearch, setMaterialSearch] = useState("");
|
||||
|
||||
// Material options for AutoComplete
|
||||
const materialOptions = useMemo(() => {
|
||||
const filtered = materialSearch
|
||||
? KNOWN_MATERIALS.filter((m) => m.toLowerCase().includes(materialSearch.toLowerCase()))
|
||||
: KNOWN_MATERIALS;
|
||||
return filtered.map((material) => ({ value: material, label: material }));
|
||||
}, [materialSearch]);
|
||||
|
||||
const { form, formProps, formLoading, onFinish, redirect } = useForm<
|
||||
IFilament,
|
||||
@@ -56,6 +71,10 @@ export const FilamentCreate: React.FC<IResourceComponentsProps & CreateOrClonePr
|
||||
|
||||
// Parse the extra fields from string values into real types
|
||||
formProps.initialValues = ParsedExtras(formProps.initialValues);
|
||||
} else {
|
||||
// Set defaults for new filaments
|
||||
formProps.initialValues.density = formProps.initialValues.density ?? DEFAULT_DENSITY;
|
||||
formProps.initialValues.diameter = formProps.initialValues.diameter ?? DEFAULT_DIAMETER;
|
||||
}
|
||||
|
||||
const handleSubmit = async (redirectTo: "list" | "create") => {
|
||||
@@ -79,6 +98,14 @@ export const FilamentCreate: React.FC<IResourceComponentsProps & CreateOrClonePr
|
||||
setIsVendorModalOpen(false);
|
||||
};
|
||||
|
||||
// Auto-fill density when material is selected or entered
|
||||
const handleMaterialChange = (value: string) => {
|
||||
const density = getDensityForMaterial(value);
|
||||
if (density !== undefined) {
|
||||
form.setFieldValue("density", density);
|
||||
}
|
||||
};
|
||||
|
||||
const importFilament = async (filament: ExternalFilament) => {
|
||||
const vendor = await getOrCreateVendorFromExternal(filament.manufacturer);
|
||||
await invalidate({
|
||||
@@ -265,7 +292,14 @@ export const FilamentCreate: React.FC<IResourceComponentsProps & CreateOrClonePr
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input maxLength={64} />
|
||||
<AutoComplete
|
||||
options={materialOptions}
|
||||
onSearch={setMaterialSearch}
|
||||
onSelect={handleMaterialChange}
|
||||
onBlur={(e) => handleMaterialChange((e.target as HTMLInputElement).value)}
|
||||
placeholder={t("filament.form.material_placeholder")}
|
||||
maxLength={64}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("filament.fields.price")}
|
||||
|
||||
Reference in New Issue
Block a user