@@ -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
0 commit comments