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

stacklok / codegate-ui / 13903674755

17 Mar 2025 03:42PM UTC coverage: 61.874% (-4.6%) from 66.452%
13903674755

Pull #345

github

web-flow
Merge ce2550358 into 5d463ef04
Pull Request #345: feat: react-hook-form field array for provider muxes

443 of 798 branches covered (55.51%)

Branch coverage included in aggregate %.

63 of 93 new or added lines in 21 files covered. (67.74%)

50 existing lines in 4 files now uncovered.

904 of 1379 relevant lines covered (65.55%)

36.88 hits per line

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

0.0
/src/features/workspace/components/workspace-models-dropdown.tsx
1
import {
2
  ModelByProvider,
3
  V1ListAllModelsForAllProvidersResponse,
4
} from '@/api/generated'
5
import {
6
  DialogTrigger,
7
  Button,
8
  Popover,
9
  SearchField,
10
  ListBox,
11
  Input,
12
  OptionRenderer,
13
  OptionsSchema,
14
} from '@stacklok/ui-kit'
15
import { ChevronDown, SearchMd } from '@untitled-ui/icons-react'
16
import { map, groupBy } from 'lodash'
17
import { useState } from 'react'
18
import { deserializeMuxModel, serializeMuxModel } from '../lib/mux-model-serde'
19
import { PreferredMuxRule } from '../hooks/use-muxing-rules-form-workspace'
20

21
type Props = {
22
  rule: PreferredMuxRule
23
  isArchived: boolean
24
  models: V1ListAllModelsForAllProvidersResponse
25
  onChange: ({
26
    model,
27
    provider_name,
28
    provider_type,
29
  }: {
30
    model: string
31
    provider_name: string
32
    provider_type: string
33
  }) => void
34
}
35

36
function groupModelsByProviderName(
37
  models: ModelByProvider[]
38
): OptionsSchema<'listbox', string>[] {
UNCOV
39
  return map(groupBy(models, 'provider_name'), (items, providerName) => ({
×
40
    id: providerName,
41
    textValue: providerName,
UNCOV
42
    items: items.map((item) => ({
×
43
      id: serializeMuxModel(item),
44
      textValue: item.name,
45
    })),
46
  }))
47
}
48

49
function filterModels({
50
  groupedModels,
51
  searchItem,
52
}: {
53
  searchItem: string
54
  groupedModels: OptionsSchema<'listbox', string>[]
55
}) {
UNCOV
56
  const test = groupedModels
×
57
    .map((modelData) => {
UNCOV
58
      if (!searchItem) return modelData
×
59
      const filteredModels = modelData.items?.filter((item) => {
×
60
        return item.textValue.includes(searchItem)
×
61
      })
62

63
      const data = {
×
64
        ...modelData,
65
        items: filteredModels,
66
      }
67
      return data
×
68
    })
UNCOV
69
    .filter((item) => (item.items ? item.items.length > 0 : false))
×
70

UNCOV
71
  return test
×
72
}
73

74
export function WorkspaceModelsDropdown({
75
  rule,
76
  isArchived,
77
  models = [],
×
78
  onChange,
79
}: Props) {
UNCOV
80
  const [isOpen, setIsOpen] = useState(false)
×
UNCOV
81
  const [searchItem, setSearchItem] = useState('')
×
UNCOV
82
  const groupedModels = groupModelsByProviderName(models)
×
UNCOV
83
  const currentProvider = models.find(
×
UNCOV
84
    (p) => p.provider_name === rule.provider_name
×
85
  )
86
  const currentModel =
UNCOV
87
    currentProvider && rule.model
×
88
      ? `${currentProvider?.provider_name}/${rule.model}`
89
      : ''
UNCOV
90
  const selectedKey = rule.provider_type
×
91
    ? serializeMuxModel({
92
        name: rule.model,
93
        provider_name: rule.provider_name,
94
        provider_type: rule.provider_type,
95
      })
96
    : undefined
97

98
  return (
99
    <div className="flex w-full">
UNCOV
100
      <DialogTrigger isOpen={isOpen} onOpenChange={(test) => setIsOpen(test)}>
×
101
        <Button
102
          variant="secondary"
103
          isDisabled={isArchived}
104
          data-testid="workspace-models-dropdown"
105
          className="flex w-full cursor-pointer justify-between border-gray-400 bg-gray-25
106
            font-normal shadow-none"
107
        >
108
          <span>{currentModel || 'Select a model'}</span>
×
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={selectedKey ? [selectedKey] : []}
×
123
            onSelectionChange={(v) => {
UNCOV
124
              if (v === 'all') return
×
UNCOV
125
              const id = v.values().next().value?.toString()
×
UNCOV
126
              if (typeof id === 'string') {
×
UNCOV
127
                const model = deserializeMuxModel(id)
×
UNCOV
128
                onChange({
×
129
                  model: model.name,
130
                  provider_name: model.provider_name,
131
                  provider_type: model.provider_type,
132
                })
UNCOV
133
                setIsOpen(false)
×
134
              }
135
            }}
136
            className="-mx-1 mt-2 max-h-72 overflow-auto"
137
            renderEmptyState={() => (
138
              <p className="text-center">No models found</p>
139
            )}
140
          >
141
            {({ items, id, textValue }) => (
142
              <OptionRenderer
143
                items={items}
144
                id={id}
145
                textValue={textValue}
146
                type="listbox"
147
              />
148
            )}
149
          </ListBox>
150
        </Popover>
151
      </DialogTrigger>
152
    </div>
153
  )
154
}
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

© 2025 Coveralls, Inc