Skip to content

Commit

Permalink
move sort & suggested label out of ComboBox
Browse files Browse the repository at this point in the history
  • Loading branch information
ivyjeong13 committed Dec 20, 2024
1 parent 3ea9704 commit 0471e06
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 54 deletions.
57 changes: 16 additions & 41 deletions ui/admin/app/components/composed/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ type ComboBoxProps<T extends BaseOption> = {
onChange: (option: T | null) => void;
options: (T | GroupedOption<T>)[];
placeholder?: string;
suggested?: string[];
renderOption?: (option: T) => ReactNode;
value?: T | null;
};

export function ComboBox<T extends BaseOption>({
disabled,
placeholder,
value,
suggested,
renderOption,
...props
}: {
disabled?: boolean;
Expand All @@ -58,7 +58,7 @@ export function ComboBox<T extends BaseOption>({
<PopoverContent className="w-full p-0" align="start">
<ComboBoxList
setOpen={setOpen}
suggested={suggested}
renderOption={renderOption}
value={value}
{...props}
/>
Expand All @@ -74,7 +74,7 @@ export function ComboBox<T extends BaseOption>({
<div className="mt-4 border-t">
<ComboBoxList
setOpen={setOpen}
suggested={suggested}
renderOption={renderOption}
value={value}
{...props}
/>
Expand All @@ -95,12 +95,9 @@ export function ComboBox<T extends BaseOption>({
}}
>
<span className="text-ellipsis overflow-hidden">
{value ? value.name : placeholder}{" "}
{value?.name && suggested?.includes(value.name) && (
<span className="text-muted-foreground">
(Suggested)
</span>
)}
{renderOption && value
? renderOption(value)
: (value?.name ?? placeholder)}
</span>
</Button>
);
Expand All @@ -113,7 +110,7 @@ function ComboBoxList<T extends BaseOption>({
onChange,
options,
setOpen,
suggested,
renderOption,
value,
placeholder = "Filter...",
emptyLabel = "No results found.",
Expand Down Expand Up @@ -160,22 +157,6 @@ function ComboBoxList<T extends BaseOption>({
[] as (T | GroupedOption<T>)[]
);

const sortBySuggested = (
a: T | GroupedOption<T>,
b: T | GroupedOption<T>
) => {
// Handle nested groups - keep original order
if ("heading" in a || "heading" in b) return 0;

const aIsSuggested = a.name && suggested?.includes(a.name);
const bIsSuggested = b.name && suggested?.includes(b.name);

// If both or neither are suggested, maintain original order
if (aIsSuggested === bIsSuggested) return 0;
// Sort suggested items first
return aIsSuggested ? -1 : 1;
};

const handleValueChange = (value: string) => {
setFilteredOptions(filterOptions(options, value));
};
Expand Down Expand Up @@ -215,14 +196,11 @@ function ComboBoxList<T extends BaseOption>({
function renderGroupedOption(group: GroupedOption<T>) {
return (
<CommandGroup key={group.heading} heading={group.heading}>
{group.value
.slice() // Create a copy to avoid mutating original array
.sort(sortBySuggested)
.map((option) =>
"heading" in option
? renderGroupedOption(option)
: renderUngroupedOption(option)
)}
{group.value.map((option) =>
"heading" in option
? renderGroupedOption(option)
: renderUngroupedOption(option)
)}
</CommandGroup>
);
}
Expand All @@ -239,12 +217,9 @@ function ComboBoxList<T extends BaseOption>({
className="justify-between"
>
<span>
{option.name || option.id}{" "}
{option?.name && suggested?.includes(option.name) && (
<span className="text-muted-foreground">
(Suggested)
</span>
)}
{renderOption
? renderOption(option)
: (option.name ?? option.id)}
</span>
{value?.id === option.id && <CheckIcon className="w-4 h-4" />}
</CommandItem>
Expand Down
55 changes: 42 additions & 13 deletions ui/admin/app/components/model/DefaultModelAliasForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,15 @@ export function DefaultModelAliasForm({
}
options={getOptionsByUsageAndProvider(
activeModelOptions,
usage
usage,
alias
)}
suggested={getSuggested(alias)}
renderOption={(option) =>
renderDisplayOption(
option,
alias
)
}
value={
field.value
? models?.find(
Expand Down Expand Up @@ -219,21 +225,33 @@ export function DefaultModelAliasForm({
</Form>
);

function getSuggested(alias: ModelAlias) {
return alias && SUGGESTED_MODEL_SELECTIONS[alias]
? [SUGGESTED_MODEL_SELECTIONS[alias]]
: [];
function renderDisplayOption(option: Model, alias: ModelAlias) {
const suggestion = alias && SUGGESTED_MODEL_SELECTIONS[alias];

return (
<span>
{option.name}{" "}
{suggestion === option.name && (
<span className="text-muted-foreground">(Suggested)</span>
)}
</span>
);
}

function getOptionsByUsageAndProvider(
modelOptions: Model[] | undefined,
usage: ModelUsage
usage: ModelUsage,
aliasFor: ModelAlias
) {
if (!modelOptions) return [];

const suggested = aliasFor && SUGGESTED_MODEL_SELECTIONS[aliasFor];
const usageGroupName = getModelUsageLabel(usage);
const usageModelProviderGroups =
getModelOptionsByModelProvider(modelOptions);
const usageModelProviderGroups = getModelOptionsByModelProvider(
modelOptions,
suggested ? [suggested] : []
);

const otherModelProviderGroups =
getModelOptionsByModelProvider(otherModels);
const usageGroup = {
Expand Down Expand Up @@ -290,7 +308,10 @@ export function DefaultModelAliasFormDialog({
);
}

export function getModelOptionsByModelProvider(models: Model[]) {
export function getModelOptionsByModelProvider(
models: Model[],
suggestions?: string[]
) {
const byModelProviderGroups = filterModelsByActive(models).reduce(
(acc, model) => {
acc[model.modelProvider] = acc[model.modelProvider] || [];
Expand All @@ -302,9 +323,17 @@ export function getModelOptionsByModelProvider(models: Model[]) {

return Object.entries(byModelProviderGroups).map(
([modelProvider, models]) => {
const sorted = models.sort((a, b) =>
(a.name ?? "").localeCompare(b.name ?? "")
);
const sorted = models.sort((a, b) => {
const aIsSuggested = a.name && suggestions?.includes(a.name);
const bIsSuggested = b.name && suggestions?.includes(b.name);

if (aIsSuggested === bIsSuggested) return 0;
if (aIsSuggested || bIsSuggested) {
return aIsSuggested ? -1 : 1;
}

return (a.name ?? "").localeCompare(b.name ?? "");
});
return {
heading: modelProvider,
value: sorted,
Expand Down

0 comments on commit 0471e06

Please sign in to comment.