♻️ refactor

This commit is contained in:
Fred KISSIE
2026-03-31 22:44:18 +02:00
parent a4d8789c20
commit 543542713b
4 changed files with 146 additions and 59 deletions

View File

@@ -1063,7 +1063,7 @@ export function InternalResourceForm({
]
)
}
enableAutocomplete={true}
enableAutocomplete
autocompleteOptions={
allRoles
}

View File

@@ -3,18 +3,9 @@ import type { ListClientsResponse } from "@server/routers/client";
import { useQuery } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { useDebounce } from "use-debounce";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList
} from "./ui/command";
import { cn } from "@app/lib/cn";
import { CheckIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import { MultiSelectTags } from "./multi-select-tags";
export type SelectedMachine = Pick<
ListClientsResponse["clients"][number],
@@ -57,52 +48,71 @@ export function MachinesSelector({
return allMachines;
}, [machines, selectedMachines, debouncedValue]);
const selectedMachinesIds = new Set(
selectedMachines.map((m) => m.clientId)
);
// const selectedMachinesIds = new Set(
// selectedMachines.map((m) => m.clientId)
// );
return (
<Command shouldFilter={false}>
<CommandInput
placeholder={t("machineSearch")}
value={machineSearchQuery}
onValueChange={setMachineSearchQuery}
/>
<CommandList>
<CommandEmpty>{t("machineNotFound")}</CommandEmpty>
<CommandGroup>
{machinesShown.map((m) => (
<CommandItem
value={`${m.name}:${m.clientId}`}
key={m.clientId}
onSelect={() => {
let newMachineClients = [];
if (selectedMachinesIds.has(m.clientId)) {
newMachineClients = selectedMachines.filter(
(mc) => mc.clientId !== m.clientId
);
} else {
newMachineClients = [
...selectedMachines,
m
];
}
onSelectMachines(newMachineClients);
}}
>
<CheckIcon
className={cn(
"mr-2 h-4 w-4",
selectedMachinesIds.has(m.clientId)
? "opacity-100"
: "opacity-0"
)}
/>
{`${m.name}`}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
<MultiSelectTags
emptyPlaceholder={t("machineNotFound")}
searchPlaceholder={t("machineSearch")}
value={selectedMachines.map((m) => ({
...m,
text: m.name,
id: m.clientId.toString()
}))}
onChange={(values) => {
onSelectMachines(values);
}}
options={machinesShown.map((m) => ({
...m,
id: m.clientId.toString(),
text: m.name
}))}
onSearch={setMachineSearchQuery}
searchQuery={machineSearchQuery}
/>
// <Command shouldFilter={false}>
// <CommandInput
// placeholder={t("machineSearch")}
// value={machineSearchQuery}
// onValueChange={setMachineSearchQuery}
// />
// <CommandList>
// <CommandEmpty>{t("machineNotFound")}</CommandEmpty>
// <CommandGroup>
// {machinesShown.map((m) => (
// <CommandItem
// value={`${m.name}:${m.clientId}`}
// key={m.clientId}
// onSelect={() => {
// let newMachineClients = [];
// if (selectedMachinesIds.has(m.clientId)) {
// newMachineClients = selectedMachines.filter(
// (mc) => mc.clientId !== m.clientId
// );
// } else {
// newMachineClients = [
// ...selectedMachines,
// m
// ];
// }
// onSelectMachines(newMachineClients);
// }}
// >
// <CheckIcon
// className={cn(
// "mr-2 h-4 w-4",
// selectedMachinesIds.has(m.clientId)
// ? "opacity-100"
// : "opacity-0"
// )}
// />
// {`${m.name}`}
// </CommandItem>
// ))}
// </CommandGroup>
// </CommandList>
// </Command>
);
}

View File

@@ -0,0 +1,77 @@
import type { Ref } from "react";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList
} from "./ui/command";
import { cn } from "@app/lib/cn";
import { CheckIcon } from "lucide-react";
export type TagValue = { text: string; id: string };
export type MultiSelectTagsProps<T extends TagValue> = {
emptyPlaceholder: string;
searchPlaceholder: string;
searchQuery?: string;
options: Array<T>;
value: Array<T>;
onChange: (newValue: Array<T>) => void;
onSearch: (query: string) => void;
ref?: Ref<HTMLButtonElement>;
};
export function MultiSelectTags<T extends TagValue>({
emptyPlaceholder,
searchPlaceholder,
searchQuery,
value,
options,
onSearch,
onChange
}: MultiSelectTagsProps<T>) {
const selectedValues = new Set(value.map((v) => v.id));
return (
<Command shouldFilter={false}>
<CommandInput
placeholder={searchPlaceholder}
value={searchQuery}
onValueChange={onSearch}
/>
<CommandList>
<CommandEmpty>{emptyPlaceholder}</CommandEmpty>
<CommandGroup>
{options.map((option) => (
<CommandItem
value={option.id}
key={option.id}
onSelect={() => {
let newValues = [];
if (selectedValues.has(option.id)) {
newValues = value.filter(
(v) => v.id !== option.id
);
} else {
newValues = [...value, option];
}
onChange(newValues);
}}
>
<CheckIcon
className={cn(
"mr-2 h-4 w-4",
selectedValues.has(option.id)
? "opacity-100"
: "opacity-0"
)}
/>
{`${option.text}`}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
);
}

View File

@@ -522,7 +522,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
onBlur={handleInputBlur}
{...inputProps}
className={cn(
"border-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
"border-0 px-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
// className,
styleClasses?.input
)}
@@ -692,7 +692,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
onBlur={handleInputBlur}
{...inputProps}
className={cn(
"border-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
"border-0 px-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
// className,
styleClasses?.input
)}
@@ -770,7 +770,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
onBlur={handleInputBlur}
{...inputProps}
className={cn(
"border-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
"border-0 px-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
// className,
styleClasses?.input
)}