CSSの最適化や内部挙動の改良
This commit is contained in:
@@ -1,35 +1,38 @@
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "content"}}
|
||||
<h1 class="mb-4"><i class="bi bi-key me-2"></i>APIキー管理</h1>
|
||||
<h1 class="mb-4"><i class="bi bi-key me-2" aria-hidden="true"></i>APIキー管理</h1>
|
||||
|
||||
{{if .error}}<div class="alert alert-danger">{{.error}}</div>{{end}}
|
||||
{{if .error}}<div class="alert alert-danger" role="alert">{{.error}}</div>{{end}}
|
||||
|
||||
{{if .newKey}}
|
||||
<div class="alert alert-success">
|
||||
<h5 class="alert-heading"><i class="bi bi-check-circle me-2"></i>APIキーが作成されました</h5>
|
||||
<div class="alert alert-success" role="status">
|
||||
<h5 class="alert-heading"><i class="bi bi-check-circle me-2" aria-hidden="true"></i>APIキーが作成されました</h5>
|
||||
<p class="mb-2">キー名: <strong>{{.newKeyName}}</strong></p>
|
||||
<p class="mb-0">以下のキーを安全な場所に保存してください。このキーは二度と表示されません。</p>
|
||||
<hr>
|
||||
<div class="d-flex align-items-center">
|
||||
<code class="flex-grow-1 bg-dark text-light p-2 rounded me-2" id="newApiKey">{{.newKey}}</code>
|
||||
<button class="btn btn-outline-secondary" onclick="copyKey()"><i class="bi bi-clipboard"></i></button>
|
||||
<code class="flex-grow-1 bg-dark text-light p-2 rounded me-2" id="newApiKey" aria-label="APIキー">{{.newKey}}</code>
|
||||
<button class="btn btn-outline-secondary" id="copyKeyBtn" aria-label="APIキーをコピー">
|
||||
<i class="bi bi-clipboard" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-plus-circle me-2"></i>新規APIキー作成
|
||||
<i class="bi bi-plus-circle me-2" aria-hidden="true"></i>新規APIキー作成
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="/admin/api-keys" method="POST" class="row g-3">
|
||||
{{.csrfField}}
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" name="name" placeholder="キー名(例: 外部連携用)" required>
|
||||
<label for="keyName" class="visually-hidden">キー名</label>
|
||||
<input type="text" class="form-control" id="keyName" name="name" placeholder="キー名(例: 外部連携用)" required>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<button type="submit" class="btn btn-primary w-100"><i class="bi bi-plus me-1"></i>作成</button>
|
||||
<button type="submit" class="btn btn-primary w-100"><i class="bi bi-plus me-1" aria-hidden="true"></i>作成</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -37,31 +40,32 @@
|
||||
|
||||
{{if .apiKeys}}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<table class="table table-hover" aria-label="APIキー一覧">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>キー名</th>
|
||||
<th>作成者</th>
|
||||
<th>最終使用</th>
|
||||
<th>作成日</th>
|
||||
<th style="width: 100px">操作</th>
|
||||
<th scope="col">ID</th>
|
||||
<th scope="col">キー名</th>
|
||||
<th scope="col">作成者</th>
|
||||
<th scope="col">最終使用</th>
|
||||
<th scope="col">作成日</th>
|
||||
<th scope="col" style="width: 100px">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .apiKeys}}
|
||||
<tr>
|
||||
<td>{{.ID}}</td>
|
||||
<td><i class="bi bi-key me-1"></i>{{.Name}}</td>
|
||||
<td><i class="bi bi-key me-1" aria-hidden="true"></i>{{.Name}}</td>
|
||||
<td>{{if .User}}{{.User.Name}}{{else}}-{{end}}</td>
|
||||
<td>{{if .LastUsed}}{{formatDateTime .LastUsed}}{{else}}<span class="text-muted">未使用</span>{{end}}</td>
|
||||
<td>{{formatDate .CreatedAt}}</td>
|
||||
<td>
|
||||
<form action="/admin/api-keys/{{.ID}}/delete" method="POST" class="d-inline"
|
||||
onsubmit="return confirm('このAPIキーを削除しますか?')">
|
||||
data-confirm="このAPIキーを削除しますか?">
|
||||
<input type="hidden" name="_csrf" value="{{$.csrfToken}}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="削除"><i
|
||||
class="bi bi-trash"></i></button>
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" aria-label="{{.Name}}を削除">
|
||||
<i class="bi bi-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -71,7 +75,7 @@
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-key display-1 text-muted"></i>
|
||||
<i class="bi bi-key display-1 text-muted" aria-hidden="true"></i>
|
||||
<h3 class="mt-3">APIキーがありません</h3>
|
||||
<p class="text-muted">上のフォームから新しいAPIキーを作成してください。</p>
|
||||
</div>
|
||||
@@ -79,12 +83,11 @@
|
||||
|
||||
<div class="card mt-4">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-info-circle me-2"></i>API使用方法
|
||||
<i class="bi bi-info-circle me-2" aria-hidden="true"></i>API使用方法
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="mb-2">APIにアクセスするには、<code>Authorization</code>ヘッダーにAPIキーを設定してください:</p>
|
||||
<pre
|
||||
class="bg-dark text-light p-3 rounded"><code>curl -H "Authorization: Bearer YOUR_API_KEY" http://localhost:8080/api/v1/assignments</code></pre>
|
||||
<pre class="bg-dark text-light p-3 rounded"><code>curl -H "Authorization: Bearer YOUR_API_KEY" http://localhost:8080/api/v1/assignments</code></pre>
|
||||
<h6 class="mt-3">利用可能なエンドポイント:</h6>
|
||||
<ul class="mb-0">
|
||||
<li><code>GET /api/v1/assignments</code> - 課題一覧取得</li>
|
||||
@@ -110,11 +113,20 @@
|
||||
|
||||
{{define "scripts"}}
|
||||
<script>
|
||||
function copyKey() {
|
||||
const key = document.getElementById('newApiKey').innerText;
|
||||
navigator.clipboard.writeText(key).then(() => {
|
||||
alert('APIキーをコピーしました');
|
||||
var copyKeyBtn = document.getElementById('copyKeyBtn');
|
||||
if (copyKeyBtn) {
|
||||
copyKeyBtn.addEventListener('click', function() {
|
||||
var key = document.getElementById('newApiKey').textContent.trim();
|
||||
if (!navigator.clipboard) {
|
||||
showCopyFeedback('クリップボードがサポートされていません。手動でコピーしてください。');
|
||||
return;
|
||||
}
|
||||
navigator.clipboard.writeText(key).then(function() {
|
||||
showCopyFeedback('APIキーをコピーしました');
|
||||
}).catch(function(err) {
|
||||
showCopyFeedback('コピーに失敗しました: ' + (err.message || '不明なエラー'));
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
@@ -1,55 +1,68 @@
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "content"}}
|
||||
<h1 class="mb-4"><i class="bi bi-people me-2"></i>ユーザー管理</h1>
|
||||
<h1 class="mb-4"><i class="bi bi-people me-2" aria-hidden="true"></i>ユーザー管理</h1>
|
||||
|
||||
{{if .error}}<div class="alert alert-danger">{{.error}}</div>{{end}}
|
||||
{{if .error}}<div class="alert alert-danger" role="alert">{{.error}}</div>{{end}}
|
||||
|
||||
{{if .users}}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<table class="table table-hover" aria-label="ユーザー一覧">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>名前</th>
|
||||
<th>メールアドレス</th>
|
||||
<th>ロール</th>
|
||||
<th>登録日</th>
|
||||
<th style="width: 200px">操作</th>
|
||||
<th scope="col">ID</th>
|
||||
<th scope="col">名前</th>
|
||||
<th scope="col">メールアドレス</th>
|
||||
<th scope="col">ロール</th>
|
||||
<th scope="col">登録日</th>
|
||||
<th scope="col" style="width: 200px">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .users}}
|
||||
<tr {{if eq .ID $.currentUserID}}class="table-primary" {{end}}>
|
||||
<tr {{if eq .ID $.currentUserID}}class="table-primary"{{end}}>
|
||||
<td>{{.ID}}</td>
|
||||
<td>{{.Name}}{{if eq .ID $.currentUserID}}<span class="badge bg-info ms-2">自分</span>{{end}}</td>
|
||||
<td>{{.Email}}</td>
|
||||
<td>{{if eq .Role "admin"}}<span class="badge bg-danger">管理者</span>{{else}}<span
|
||||
class="badge bg-secondary">ユーザー</span>{{end}}</td>
|
||||
<td>
|
||||
{{if eq .Role "admin"}}
|
||||
<span class="badge bg-danger">管理者</span>
|
||||
{{else}}
|
||||
<span class="badge bg-secondary">ユーザー</span>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>{{formatDate .CreatedAt}}</td>
|
||||
<td>
|
||||
{{if ne .ID $.currentUserID}}
|
||||
<form action="/admin/users/{{.ID}}/role" method="POST" class="d-inline" {{if eq .Role "admin"
|
||||
}}onsubmit="return confirm('このユーザーを一般ユーザーに降格しますか?')"
|
||||
{{else}}onsubmit="return confirm('このユーザーを管理者に昇格しますか?')" {{end}}>
|
||||
{{if eq .Role "admin"}}
|
||||
<form action="/admin/users/{{.ID}}/role" method="POST" class="d-inline"
|
||||
data-confirm="このユーザーを一般ユーザーに降格しますか?">
|
||||
<input type="hidden" name="_csrf" value="{{$.csrfToken}}">
|
||||
{{if eq .Role "admin"}}
|
||||
<input type="hidden" name="role" value="user">
|
||||
<button type="submit" class="btn btn-sm btn-outline-secondary" title="ユーザーに降格"><i
|
||||
class="bi bi-arrow-down"></i></button>
|
||||
{{else}}
|
||||
<input type="hidden" name="role" value="admin">
|
||||
<button type="submit" class="btn btn-sm btn-outline-warning" title="管理者に昇格"><i
|
||||
class="bi bi-arrow-up"></i></button>
|
||||
{{end}}
|
||||
<button type="submit" class="btn btn-sm btn-outline-secondary" aria-label="{{.Name}}をユーザーに降格">
|
||||
<i class="bi bi-arrow-down" aria-hidden="true"></i>
|
||||
</button>
|
||||
</form>
|
||||
<form action="/admin/users/{{.ID}}/delete" method="POST" class="d-inline"
|
||||
onsubmit="return confirm('このユーザーを削除しますか?')">
|
||||
{{else}}
|
||||
<form action="/admin/users/{{.ID}}/role" method="POST" class="d-inline"
|
||||
data-confirm="このユーザーを管理者に昇格しますか?">
|
||||
<input type="hidden" name="_csrf" value="{{$.csrfToken}}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" title="削除"><i
|
||||
class="bi bi-trash"></i></button>
|
||||
<input type="hidden" name="role" value="admin">
|
||||
<button type="submit" class="btn btn-sm btn-outline-warning" aria-label="{{.Name}}を管理者に昇格">
|
||||
<i class="bi bi-arrow-up" aria-hidden="true"></i>
|
||||
</button>
|
||||
</form>
|
||||
{{else}}<span class="text-muted">-</span>{{end}}
|
||||
{{end}}
|
||||
<form action="/admin/users/{{.ID}}/delete" method="POST" class="d-inline"
|
||||
data-confirm="このユーザーを削除しますか?">
|
||||
<input type="hidden" name="_csrf" value="{{$.csrfToken}}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" aria-label="{{.Name}}を削除">
|
||||
<i class="bi bi-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</form>
|
||||
{{else}}
|
||||
<span class="text-muted">-</span>
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
@@ -58,8 +71,8 @@
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-people display-1 text-muted"></i>
|
||||
<i class="bi bi-people display-1 text-muted" aria-hidden="true"></i>
|
||||
<h3 class="mt-3">ユーザーがいません</h3>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
Reference in New Issue
Block a user