• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stacklok / codegate-ui / 13316161854

13 Feb 2025 08:08PM UTC coverage: 68.796%. First build
13316161854

Pull #311

github

web-flow
Merge c16fb6962 into 7f2c040ad
Pull Request #311: feat: add support muxing rules

392 of 632 branches covered (62.03%)

Branch coverage included in aggregate %.

99 of 118 new or added lines in 13 files covered. (83.9%)

825 of 1137 relevant lines covered (72.56%)

67.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.77
/src/features/workspace/components/workspace-models-dropdown.tsx
1
import {
2
  ModelByProvider,
3
  MuxRule,
4
  V1ListAllModelsForAllProvidersResponse,
5
} from "@/api/generated";
6
import {
7
  DialogTrigger,
8
  Button,
9
  Popover,
10
  SearchField,
11
  ListBox,
12
  Input,
13
  OptionRenderer,
14
  OptionsSchema,
15
} from "@stacklok/ui-kit";
16
import { ChevronDown, SearchMd } from "@untitled-ui/icons-react";
17
import { useState } from "react";
18

19
type Props = {
20
  rule: MuxRule & { id: string };
21
  isArchived: boolean;
22
  models: V1ListAllModelsForAllProvidersResponse;
23
  onChange: ({
24
    model,
25
    provider_id,
26
  }: {
27
    model: string;
28
    provider_id: string;
29
  }) => void;
30
};
31

32
function groupModelsByProviderName(
33
  models: ModelByProvider[],
34
): OptionsSchema<"listbox", string>[] {
35
  return models.reduce<OptionsSchema<"listbox", string>[]>(
35✔
36
    (groupedProviders, item) => {
37
      const providerData = groupedProviders.find(
85✔
38
        (group) => group.id === item.provider_name,
85✔
39
      );
40
      if (!providerData) {
85✔
41
        groupedProviders.push({
34✔
42
          id: item.provider_name,
43
          items: [],
44
          textValue: item.provider_name,
45
        });
46
      }
47

48
      (providerData?.items ?? []).push({
85✔
49
        id: item.name,
50
        textValue: item.name,
51
      });
52

53
      return groupedProviders;
85✔
54
    },
55
    [],
56
  );
57
}
58

59
function filterModels({
60
  groupedModels,
61
  searchItem,
62
}: {
63
  searchItem: string;
64
  groupedModels: OptionsSchema<"listbox", string>[];
65
}) {
66
  return groupedModels
35✔
67
    .map((modelData) => {
68
      if (!searchItem) return modelData;
34!
NEW
69
      const filteredModels = modelData.items?.filter((item) => {
×
NEW
70
        return item.textValue.includes(searchItem);
×
71
      });
72

NEW
73
      const data = {
×
74
        ...modelData,
75
        items: filteredModels,
76
      };
NEW
77
      return data;
×
78
    })
79
    .filter((item) => (item.items ? item.items.length > 0 : false));
34!
80
}
81

82
export function WorkspaceModelsDropdown({
83
  rule,
84
  isArchived,
85
  models = [],
×
86
  onChange,
87
}: Props) {
88
  const [isOpen, setIsOpen] = useState(false);
35✔
89
  const [searchItem, setSearchItem] = useState("");
35✔
90
  const groupedModels = groupModelsByProviderName(models);
35✔
91
  const currentProvider = models.find(
35✔
92
    (p) => p.provider_id === rule.provider_id,
70✔
93
  );
94
  const currentModel =
95
    currentProvider && rule.model
35✔
96
      ? `${currentProvider?.provider_name}/${rule.model}`
97
      : "";
98

99
  return (
100
    <div className="w-full flex">
101
      <DialogTrigger isOpen={isOpen} onOpenChange={(test) => setIsOpen(test)}>
3✔
102
        <Button
103
          variant="secondary"
104
          isDisabled={isArchived}
105
          data-testid="workspace-models-dropdown"
106
          className="flex justify-between cursor-pointer bg-gray-25 border-gray-400 shadow-none font-normal w-full"
107
        >
108
          <span>{currentModel || "Select a model"}</span>
63✔
109
          <ChevronDown className="shrink-0" />
110
        </Button>
111

112
        <Popover className="w-[32rem] p-3" placement="top end">
113
          <SearchField onChange={setSearchItem} autoFocus aria-label="search">
114
            <Input icon={<SearchMd />} />
115
          </SearchField>
116

117
          <ListBox
118
            aria-label="models"
119
            items={filterModels({ searchItem, groupedModels })}
120
            selectionMode="single"
121
            selectionBehavior="replace"
122
            selectedKeys={rule.model ? [rule.model] : []}
35✔
123
            onSelectionChange={(v) => {
124
              if (v === "all") {
3!
NEW
125
                return;
×
126
              }
127
              const selectedValue = v.values().next().value;
3✔
128
              const providerId = models.find(
3✔
129
                (item) => item.name === selectedValue,
9✔
130
              )?.provider_id;
131
              if (typeof selectedValue === "string" && providerId) {
3!
132
                onChange({
3✔
133
                  model: selectedValue,
134
                  provider_id: providerId,
135
                });
136

137
                setIsOpen(false);
3✔
138
              }
139
            }}
140
            className="-mx-1 mt-2 max-h-72 overflow-auto"
141
            renderEmptyState={() => (
142
              <p className="text-center">No models found</p>
143
            )}
144
          >
145
            {({ items, id, textValue }) => (
146
              <OptionRenderer
147
                items={items}
148
                id={id}
149
                textValue={textValue}
150
                type="listbox"
151
              />
152
            )}
153
          </ListBox>
154
        </Popover>
155
      </DialogTrigger>
156
    </div>
157
  );
158
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc