Initial setup for adding support for api key based auth
This commit is contained in:
117
templates/dashboard/settings/api_keys.html
Normal file
117
templates/dashboard/settings/api_keys.html
Normal file
@@ -0,0 +1,117 @@
|
||||
{% extends 'dashboard.html' %}
|
||||
|
||||
{% block page %}
|
||||
<div class="p-6 max-w-4xl mx-auto">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">API Keys</h1>
|
||||
<button onclick="document.getElementById('create-key-modal').showModal()"
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">
|
||||
Generate New Key
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden">
|
||||
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<thead class="bg-gray-50 dark:bg-gray-700">
|
||||
<tr>
|
||||
<th
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
|
||||
Name</th>
|
||||
<th
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
|
||||
Key Prefix</th>
|
||||
<th
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
|
||||
Scopes</th>
|
||||
<th
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
|
||||
Created</th>
|
||||
<th
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
|
||||
Last Used</th>
|
||||
<th
|
||||
class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">
|
||||
Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
||||
{% for key in api_keys %}
|
||||
<tr id="key-row-{{ key.id }}">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-white">{{
|
||||
key.name }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ key.key[:8] }}...
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">
|
||||
{% for scope in key.scopes %}
|
||||
<span
|
||||
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 mr-1">
|
||||
{{ scope }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ key.created_at.strftime('%Y-%m-%d') }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ key.last_used_at.strftime('%Y-%m-%d %H:%M') if key.last_used_at else 'Never' }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<button hx-delete="{{ url_for('settings.delete_api_key', key_id=key.id) }}"
|
||||
hx-target="#key-row-{{ key.id }}" hx-swap="outerHTML"
|
||||
hx-confirm="Are you sure you want to revoke this key?"
|
||||
class="text-red-600 hover:text-red-900 dark:text-red-400 dark:hover:text-red-300">
|
||||
Revoke
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6" class="px-6 py-4 text-center text-sm text-gray-500 dark:text-gray-400">
|
||||
No API keys found. Generate one to get started.
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create Key Modal -->
|
||||
<dialog id="create-key-modal" class="p-0 rounded-lg shadow-xl backdrop:bg-gray-900/50">
|
||||
<div class="bg-white dark:bg-gray-800 w-full max-w-md p-6">
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-4">Generate New API Key</h3>
|
||||
<form action="{{ url_for('settings.create_api_key') }}" method="POST">
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Name</label>
|
||||
<input type="text" name="name" required placeholder="e.g., CI/CD Pipeline"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white">
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Scopes</label>
|
||||
<div class="space-y-2">
|
||||
<label class="flex items-center">
|
||||
<input type="checkbox" name="scopes" value="*" checked
|
||||
class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
|
||||
<span class="ml-2 text-sm text-gray-600 dark:text-gray-400">Full Access (*)</span>
|
||||
</label>
|
||||
<!-- Future: Add function specific scopes here -->
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-gray-500">Currently only full access is supported via UI.</p>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-3">
|
||||
<button type="button" onclick="document.getElementById('create-key-modal').close()"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-600 dark:hover:bg-gray-600">
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||
Generate
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</dialog>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user