@@ -177,6 +177,91 @@ <h2 class="text-lg font-semibold text-gray-900">Today's Readiness</h2>
177177 </ div >
178178</ div >
179179
180+ <!-- API Keys Management -->
181+ < div class ="bg-white shadow rounded-lg p-6 mb-6 ">
182+ < div class ="flex items-center justify-between mb-4 ">
183+ < div >
184+ < h2 class ="text-lg font-semibold text-gray-900 "> API Keys</ h2 >
185+ < p class ="text-sm text-gray-600 "> Manage API keys for service-to-service authentication</ p >
186+ </ div >
187+ < span class ="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-100 text-blue-800 ">
188+ {{ api_keys|length }} key{% if api_keys|length != 1 %}s{% endif %}
189+ </ span >
190+ </ div >
191+
192+ {% if api_keys %}
193+ < div class ="overflow-x-auto ">
194+ < table class ="min-w-full divide-y divide-gray-200 ">
195+ < thead class ="bg-gray-50 ">
196+ < tr >
197+ < th scope ="col " class ="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider "> Key</ th >
198+ < th scope ="col " class ="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider "> Name</ th >
199+ < th scope ="col " class ="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider "> Scope</ th >
200+ < th scope ="col " class ="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider "> Rate Limit</ th >
201+ < th scope ="col " class ="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider "> Status</ th >
202+ < th scope ="col " class ="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider "> Last Used</ th >
203+ </ tr >
204+ </ thead >
205+ < tbody class ="bg-white divide-y divide-gray-200 ">
206+ {% for key in api_keys %}
207+ < tr class ="{% if not key.is_active %}bg-gray-50 opacity-60{% endif %} ">
208+ < td class ="px-4 py-3 whitespace-nowrap ">
209+ < code class ="text-sm font-mono bg-gray-100 px-2 py-1 rounded "> {{ key.key_prefix }}...</ code >
210+ </ td >
211+ < td class ="px-4 py-3 whitespace-nowrap text-sm text-gray-900 "> {{ key.name }}</ td >
212+ < td class ="px-4 py-3 whitespace-nowrap ">
213+ {% if key.user_id %}
214+ < span class ="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800 ">
215+ User: {{ key.user_id[:12] }}{% if key.user_id|length > 12 %}...{% endif %}
216+ </ span >
217+ {% else %}
218+ < span class ="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800 ">
219+ Service-level
220+ </ span >
221+ {% endif %}
222+ </ td >
223+ < td class ="px-4 py-3 whitespace-nowrap text-sm text-gray-500 ">
224+ < div class ="flex items-center ">
225+ < div class ="w-16 bg-gray-200 rounded-full h-2 mr-2 ">
226+ < div class ="bg-blue-600 h-2 rounded-full " style ="width: {{ (key.rate_limit_remaining / key.rate_limit_requests * 100)|round }}% "> </ div >
227+ </ div >
228+ < span > {{ key.rate_limit_remaining }}/{{ key.rate_limit_requests }}</ span >
229+ </ div >
230+ </ td >
231+ < td class ="px-4 py-3 whitespace-nowrap ">
232+ {% if key.is_active %}
233+ < span class ="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 ">
234+ Active
235+ </ span >
236+ {% else %}
237+ < span class ="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800 ">
238+ Revoked
239+ </ span >
240+ {% endif %}
241+ </ td >
242+ < td class ="px-4 py-3 whitespace-nowrap text-sm text-gray-500 ">
243+ {% if key.last_used_at %}
244+ {{ key.last_used_at.strftime('%Y-%m-%d %H:%M') }}
245+ {% else %}
246+ < span class ="text-gray-400 "> Never</ span >
247+ {% endif %}
248+ </ td >
249+ </ tr >
250+ {% endfor %}
251+ </ tbody >
252+ </ table >
253+ </ div >
254+ {% else %}
255+ < div class ="text-center py-8 ">
256+ < svg class ="mx-auto h-12 w-12 text-gray-400 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 ">
257+ < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z "> </ path >
258+ </ svg >
259+ < h3 class ="mt-2 text-sm font-medium text-gray-900 "> No API keys</ h3 >
260+ < p class ="mt-1 text-sm text-gray-500 "> API keys are created when users connect via OAuth.</ p >
261+ </ div >
262+ {% endif %}
263+ </ div >
264+
180265<!-- Sync Control -->
181266< div class ="bg-white shadow rounded-lg p-6 mb-6 ">
182267 < div class ="flex items-center justify-between mb-4 ">
0 commit comments