update frontend

This commit is contained in:
Mats Tornberg
2025-11-24 09:10:03 +01:00
parent 187c49ef00
commit cfc9310fe6
16 changed files with 1625 additions and 892 deletions

View File

@@ -0,0 +1,228 @@
import type { ConfigDeviceForm, ParameterSpec } from "../types";
import { PROTOCOL_SPECS } from "../constants/protocols";
interface ConfigFormProps {
deviceId?: number;
configForm: ConfigDeviceForm;
configFeedback: { type: "success" | "error"; message: string } | null;
isConfigMutating: boolean;
hasExistingConfig: boolean;
currentProtocolSpec: (typeof PROTOCOL_SPECS)[number] | undefined;
availableParameterSpecs: ParameterSpec[];
onUpdateField: (field: "name" | "protocol" | "model", value: string) => void;
onUpdateParameterRow: (
index: number,
field: "key" | "value",
value: string
) => void;
onAddParameterRow: () => void;
onRemoveParameterRow: (index: number) => void;
onSave: (deviceId?: number) => void;
onReset: (deviceId?: number) => void;
onCancel: () => void;
onDelete?: (deviceId: number) => void;
}
const isEmpty = (value: string) =>
value.trim() === "" || value === "null" || value === "0";
export const ConfigForm = ({
deviceId,
configForm,
configFeedback,
isConfigMutating,
hasExistingConfig,
currentProtocolSpec,
availableParameterSpecs,
onUpdateField,
onUpdateParameterRow,
onAddParameterRow,
onRemoveParameterRow,
onSave,
onReset,
onCancel,
onDelete,
}: ConfigFormProps) => {
const idSuffix = deviceId ? `-${deviceId}` : "-new";
return (
<div className="config-form">
<div className="config-form-header">
<h3>{deviceId ? `Configure Device #${deviceId}` : "Add New Device"}</h3>
{hasExistingConfig && deviceId && onDelete && (
<button
type="button"
className="danger"
onClick={() => onDelete(deviceId)}
disabled={isConfigMutating}
>
Delete
</button>
)}
</div>
<label className="input-label" htmlFor={`config-name${idSuffix}`}>
Name
</label>
<input
id={`config-name${idSuffix}`}
value={configForm.name}
onChange={(event) => onUpdateField("name", event.target.value)}
placeholder="Living room lamp"
/>
<label className="input-label" htmlFor={`config-protocol${idSuffix}`}>
Protocol
</label>
<select
id={`config-protocol${idSuffix}`}
value={configForm.protocol}
onChange={(event) => onUpdateField("protocol", event.target.value)}
>
<option value="">Select protocol...</option>
{PROTOCOL_SPECS.map((spec) => (
<option key={spec.name} value={spec.name}>
{spec.name}
</option>
))}
</select>
<label className="input-label" htmlFor={`config-model${idSuffix}`}>
Model {currentProtocolSpec?.models ? "" : "(optional)"}
</label>
{currentProtocolSpec?.models ? (
<select
id={`config-model${idSuffix}`}
value={configForm.model}
onChange={(event) => onUpdateField("model", event.target.value)}
>
<option value="">Select model...</option>
{currentProtocolSpec.models.map((model) => (
<option key={model.name} value={model.name}>
{model.name}
</option>
))}
</select>
) : (
<input
id={`config-model${idSuffix}`}
value={configForm.model}
onChange={(event) => onUpdateField("model", event.target.value)}
placeholder="Optional model name"
disabled={!configForm.protocol}
/>
)}
<div className="parameter-header">
<h4>Parameters</h4>
<button
type="button"
className="outline"
onClick={onAddParameterRow}
disabled={isConfigMutating}
>
Add parameter
</button>
</div>
<div className="parameter-rows">
{configForm.parameters.map((parameter, index) => {
const paramSpec = availableParameterSpecs.find(
(spec) => spec.name === parameter.key
);
console.log(
"parameter:",
parameter,
"paramSpec:",
paramSpec,
!isEmpty(parameter.value)
);
if (!paramSpec && isEmpty(parameter.value)) {
return null;
}
return (
<div className="parameter-row" key={`parameter-${index}`}>
{availableParameterSpecs.length > 0 ? (
<select
value={parameter.key}
onChange={(event) =>
onUpdateParameterRow(index, "key", event.target.value)
}
disabled={!configForm.protocol}
>
<option value="">Select parameter...</option>
{availableParameterSpecs.map((spec) => (
<option key={spec.name} value={spec.name}>
{spec.name}
</option>
))}
</select>
) : (
<input
value={parameter.key}
placeholder="Parameter key"
onChange={(event) =>
onUpdateParameterRow(index, "key", event.target.value)
}
disabled={!configForm.protocol}
/>
)}
<input
value={parameter.value}
placeholder={paramSpec ? paramSpec.description : "Value"}
onChange={(event) =>
onUpdateParameterRow(index, "value", event.target.value)
}
disabled={!parameter.key}
/>
<button
type="button"
className="icon-btn subtle"
onClick={() => onRemoveParameterRow(index)}
>
</button>
</div>
);
})}
</div>
{configFeedback && (
<div className={`config-feedback ${configFeedback.type}`}>
{configFeedback.message}
</div>
)}
<div className="actions config-form-actions">
<button
type="button"
className="primary"
onClick={() => onSave(deviceId)}
disabled={isConfigMutating}
>
{hasExistingConfig
? "Save changes"
: deviceId
? "Create config"
: "Create device"}
</button>
<button
type="button"
className="ghost"
onClick={() => onReset(deviceId)}
disabled={isConfigMutating}
>
Reset
</button>
<button
type="button"
className="ghost"
onClick={onCancel}
disabled={isConfigMutating}
>
Cancel
</button>
</div>
</div>
);
};