Skip to content

Commit aa04a8f

Browse files
committed
fix(admin): surface unavailable API key models
1 parent 5aa2d74 commit aa04a8f

6 files changed

Lines changed: 416 additions & 9 deletions

File tree

lib/codex_pooler_web/live/admin/components/pages/api_keys/page_components.ex

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,10 @@ defmodule CodexPoolerWeb.Admin.ApiKeyPageComponents do
149149
attr :pools, :list, required: true
150150
attr :groups, :list, required: true
151151
attr :usage_summaries, :map, required: true
152+
attr :model_policy_summaries, :map, required: true
152153
attr :selected_pool, :any, default: nil
154+
attr :model_policy_filter, :string, default: nil
155+
attr :unavailable_model_policy_count, :integer, required: true
153156
attr :can_manage_pools?, :boolean, required: true
154157

155158
def api_key_groups(assigns) do
@@ -169,10 +172,56 @@ defmodule CodexPoolerWeb.Admin.ApiKeyPageComponents do
169172
</div>
170173
<.link
171174
id="api-key-clear-pool-filter"
172-
patch={~p"/admin/api-keys"}
175+
patch={api_key_filter_path(nil, @model_policy_filter)}
173176
class="btn btn-ghost btn-xs"
174177
>
175-
Show all API keys
178+
Show all Pools
179+
</.link>
180+
</div>
181+
182+
<div
183+
:if={@model_policy_filter == "unavailable"}
184+
id="api-key-active-model-policy-filter"
185+
class="flex flex-wrap items-center justify-between gap-3 rounded-box border border-warning/25 bg-warning/10 px-4 py-3 text-sm shadow-sm"
186+
>
187+
<div class="flex items-center gap-2 text-base-content/75">
188+
<.icon name="hero-exclamation-triangle" class="size-4 text-warning" />
189+
<span>
190+
Showing API keys with unavailable model references
191+
<span class="font-medium text-base-content">
192+
{ApiKeysReadModel.unavailable_model_policy_count_label(@unavailable_model_policy_count)}
193+
</span>
194+
</span>
195+
</div>
196+
<.link
197+
id="api-key-clear-model-policy-filter"
198+
patch={api_key_filter_path(@selected_pool, nil)}
199+
class="btn btn-ghost btn-xs"
200+
>
201+
Show all model policies
202+
</.link>
203+
</div>
204+
205+
<div
206+
:if={@model_policy_filter != "unavailable" and @unavailable_model_policy_count > 0}
207+
id="api-key-model-policy-attention"
208+
class="flex flex-wrap items-center justify-between gap-3 rounded-box border border-warning/25 bg-warning/10 px-4 py-3 text-sm shadow-sm"
209+
>
210+
<div class="grid gap-1 text-base-content/75 sm:flex sm:items-center sm:gap-2">
211+
<span class="flex items-center gap-2 font-semibold text-base-content">
212+
<.icon name="hero-exclamation-triangle" class="size-4 text-warning" />
213+
Model policy attention
214+
</span>
215+
<span>
216+
{ApiKeysReadModel.unavailable_model_policy_count_label(@unavailable_model_policy_count)} reference models that are not in the current routable catalog.
217+
</span>
218+
</div>
219+
<.link
220+
id="api-key-filter-unavailable-model-policies"
221+
patch={api_key_filter_path(@selected_pool, "unavailable")}
222+
class="btn btn-warning btn-outline btn-xs"
223+
>
224+
Show affected keys
176225
</.link>
177226
</div>
178227
@@ -275,6 +324,22 @@ defmodule CodexPoolerWeb.Admin.ApiKeyPageComponents do
275324
<span id={"api-key-row-#{api_key.id}-models"}>
276325
Models: {ApiKeysReadModel.model_policy_label(api_key.allowed_model_identifiers)}
277326
</span>
327+
<span
328+
:if={
329+
ApiKeysReadModel.model_policy_warning_label(
330+
Map.get(@model_policy_summaries, api_key.id)
331+
)
332+
}
333+
id={"api-key-row-#{api_key.id}-model-policy-warning"}
334+
class="inline-flex items-start gap-1.5 rounded-box border border-warning/25 bg-warning/10 px-2 py-1 text-xs font-medium leading-5 text-warning"
335+
>
336+
<.icon name="hero-exclamation-triangle" class="mt-0.5 size-3.5 shrink-0" />
337+
<span>
338+
{ApiKeysReadModel.model_policy_warning_label(
339+
Map.get(@model_policy_summaries, api_key.id)
340+
)}
341+
</span>
342+
</span>
278343
</div>
279344
</td>
280345
<td class="w-16 align-middle text-center">
@@ -289,6 +354,29 @@ defmodule CodexPoolerWeb.Admin.ApiKeyPageComponents do
289354
"""
290355
end
291356

357+
defp api_key_filter_path(selected_pool, model_policy_filter) do
358+
params =
359+
%{}
360+
|> maybe_put_pool_filter(selected_pool)
361+
|> maybe_put_model_policy_filter(model_policy_filter)
362+
363+
if map_size(params) == 0 do
364+
~p"/admin/api-keys"
365+
else
366+
~p"/admin/api-keys?#{params}"
367+
end
368+
end
369+
370+
defp maybe_put_pool_filter(params, %{id: pool_id}) when is_binary(pool_id),
371+
do: Map.put(params, "pool_id", pool_id)
372+
373+
defp maybe_put_pool_filter(params, _selected_pool), do: params
374+
375+
defp maybe_put_model_policy_filter(params, "unavailable"),
376+
do: Map.put(params, "model_policy", "unavailable")
377+
378+
defp maybe_put_model_policy_filter(params, _model_policy_filter), do: params
379+
292380
attr :api_key, :any, required: true
293381

294382
defp api_key_actions_menu(assigns) do

lib/codex_pooler_web/live/admin/components/pages/api_keys/wizard_components.ex

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,17 @@ defmodule CodexPoolerWeb.Admin.ApiKeyWizardComponents do
233233
options={@service_tier_options}
234234
/>
235235
</div>
236+
<div
237+
:if={@selector_state.enforced_unavailable_warning}
238+
id="api-key-enforced-model-warning"
239+
class="alert alert-warning items-start"
240+
>
241+
<.icon name="hero-exclamation-triangle" class="size-5" />
242+
<div class="grid gap-1">
243+
<p class="font-semibold">Enforced model unavailable</p>
244+
<p class="text-sm">{@selector_state.enforced_unavailable_warning.message}</p>
245+
</div>
246+
</div>
236247
<p class="text-sm leading-6 text-base-content/60">
237248
Service tier is only enforced when selected. Auto lets the upstream choose, default requests
238249
standard capacity, flex opts into lower-priority flexible capacity, and priority asks for the

lib/codex_pooler_web/live/admin/pages/api_keys_live.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@ defmodule CodexPoolerWeb.Admin.ApiKeysLive do
2626
filter_values: %{"pool_id" => ""},
2727
selected_pool: nil,
2828
api_key_usage_summaries: %{},
29+
api_key_model_policy_summaries: %{},
2930
api_key_form: nil,
3031
api_key_params: %{},
3132
api_key_pool_groups: [],
33+
model_policy_filter: nil,
34+
unavailable_model_policy_count: 0,
3235
api_key_wizard_step: "basics",
3336
api_key_model_selector_state: ApiKeysReadModel.empty_model_selector_state(),
3437
api_key_review_errors: [],
@@ -370,7 +373,10 @@ defmodule CodexPoolerWeb.Admin.ApiKeysLive do
370373
pools={@pools}
371374
groups={@api_key_pool_groups}
372375
usage_summaries={@api_key_usage_summaries}
376+
model_policy_summaries={@api_key_model_policy_summaries}
373377
selected_pool={@selected_pool}
378+
model_policy_filter={@model_policy_filter}
379+
unavailable_model_policy_count={@unavailable_model_policy_count}
374380
can_manage_pools?={Pools.can_manage_pools?(@current_scope)}
375381
/>
376382
</section>

0 commit comments

Comments
 (0)