This commit is contained in:
Brian McGee
2025-07-31 15:39:01 +01:00
parent de8e62694c
commit 886d09e3f6

View File

@@ -17,18 +17,23 @@ interface MachineTag {
}
export type MachineTagsProps = FieldProps & {
input: ComponentProps<"select">;
name: string;
input: ComponentProps<"select">;
readOnly?: boolean;
disabled?: boolean;
required?: boolean;
defaultValue?: string[];
};
// tags which are applied to all machines and cannot be removed
const staticOptions = [{ value: "All", disabled: true }];
const uniqueOptions = (options: MachineTag[]) => {
const record: Record<string, MachineTag> = {};
options.forEach((option) => {
record[option.value] = option;
// we want to preserve the first one we encounter
// this allows us to prefix the default All tag and set a disabled status later on
record[option.value] = record[option.value] || option;
});
return Object.values(record);
};
@@ -40,6 +45,9 @@ const sortedOptions = (options: MachineTag[]) => {
});
};
const sortedAndUniqueOptions = (options: MachineTag[]) =>
sortedOptions(uniqueOptions(options));
const ItemComponent = (props: { item: CollectionNode<MachineTag> }) => {
return (
<Combobox.Item item={props.item} class="item">
@@ -56,44 +64,32 @@ const ItemComponent = (props: { item: CollectionNode<MachineTag> }) => {
};
export const MachineTags = (props: MachineTagsProps) => {
console.log("input", props.input);
// options which are applied to all machines and cannot be interacted with
const alwaysOptions = [{ value: "All", disabled: true }];
// convert default value into objects
const defaultValue = (props.defaultValue || []).map((value) => ({ value }));
const [selectedOptions, setSelectedOptions] = createSignal<MachineTag[]>(sortedOptions(uniqueOptions([
...alwaysOptions,
...defaultValue,
])));
const [availableOptions, setAvailableOptions] = createSignal<MachineTag[]>(
sortedOptions([...alwaysOptions, ...defaultValue]),
const [selectedOptions, setSelectedOptions] = createSignal<MachineTag[]>(
sortedAndUniqueOptions([...staticOptions, ...defaultValue]),
);
const _setAvailableOptions = (options: MachineTag[] | null) => {
if (options === null) setAvailableOptions([...alwaysOptions]);
const [availableOptions, setAvailableOptions] = createSignal<MachineTag[]>(
sortedAndUniqueOptions([...staticOptions, ...defaultValue]),
);
setAvailableOptions(
sortedOptions(uniqueOptions([...alwaysOptions, ...(options || [])])),
);
};
const _setSelectedOptions = (options: MachineTag[] | null) => {
if (options === null) setSelectedOptions([...alwaysOptions]);
if (options === null) setSelectedOptions([...staticOptions]);
setSelectedOptions(
sortedOptions(uniqueOptions([...alwaysOptions, ...(options || [])])),
sortedOptions(uniqueOptions([...staticOptions, ...(options || [])])),
);
};
const addSelectedOption = (option: MachineTag) => {
_setAvailableOptions([...availableOptions(), option]);
// ensure the new selected option exists in the list of available options
setAvailableOptions(sortedAndUniqueOptions([...availableOptions(), option]));
setSelectedOptions(
sortedOptions(uniqueOptions([...selectedOptions(), option])),
);
// update the selected options
setSelectedOptions(sortedAndUniqueOptions([...selectedOptions(), option]));
};
const removeSelectedOption = (option: MachineTag) => {
@@ -110,16 +106,20 @@ export const MachineTags = (props: MachineTagsProps) => {
}
};
const onKeyDown = (event) => {
const onKeyDown = (event: KeyboardEvent) => {
// react when enter is pressed inside of the text input
if (event.key === "Enter") {
event.preventDefault();
event.stopPropagation();
// get the current input value, exiting early if it's empty
const input = event.currentTarget as HTMLInputElement;
if (input.value === "") return;
// add the input value to the selected options
addSelectedOption({ value: input.value });
// reset the input value
input.value = "";
}
};