backoffice nextJs replaces admin in rust
This commit is contained in:
27
apps/backoffice/app/tokens/create/route.ts
Normal file
27
apps/backoffice/app/tokens/create/route.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { NextResponse } from "next/server";
|
||||
import { apiFetch } from "../../../lib/api";
|
||||
|
||||
type CreatedToken = { token: string };
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const form = await req.formData();
|
||||
const name = String(form.get("name") || "").trim();
|
||||
const scope = String(form.get("scope") || "read").trim();
|
||||
|
||||
let created = "";
|
||||
if (name) {
|
||||
const res = await apiFetch<CreatedToken>("/admin/tokens", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name, scope })
|
||||
}).catch(() => null);
|
||||
created = res?.token || "";
|
||||
}
|
||||
|
||||
revalidatePath("/tokens");
|
||||
const url = new URL("/tokens", req.url);
|
||||
if (created) {
|
||||
url.searchParams.set("created", created);
|
||||
}
|
||||
return NextResponse.redirect(url);
|
||||
}
|
||||
66
apps/backoffice/app/tokens/page.tsx
Normal file
66
apps/backoffice/app/tokens/page.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { listTokens } from "../../lib/api";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function TokensPage({
|
||||
searchParams
|
||||
}: {
|
||||
searchParams: Promise<{ created?: string }>;
|
||||
}) {
|
||||
const params = await searchParams;
|
||||
const tokens = await listTokens().catch(() => []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>API Tokens</h1>
|
||||
|
||||
{params.created ? (
|
||||
<div className="card">
|
||||
<strong>Token created:</strong>
|
||||
<pre>{params.created}</pre>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="card">
|
||||
<form action="/tokens/create" method="post">
|
||||
<input name="name" placeholder="token name" required />
|
||||
<select name="scope" defaultValue="read">
|
||||
<option value="read">read</option>
|
||||
<option value="admin">admin</option>
|
||||
</select>
|
||||
<button type="submit">Create Token</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Scope</th>
|
||||
<th>Prefix</th>
|
||||
<th>Revoked</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{tokens.map((token) => (
|
||||
<tr key={token.id}>
|
||||
<td>{token.name}</td>
|
||||
<td>{token.scope}</td>
|
||||
<td>
|
||||
<code>{token.prefix}</code>
|
||||
</td>
|
||||
<td>{token.revoked_at ? "yes" : "no"}</td>
|
||||
<td>
|
||||
<form className="inline" action="/tokens/revoke" method="post">
|
||||
<input type="hidden" name="id" value={token.id} />
|
||||
<button type="submit">Revoke</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
13
apps/backoffice/app/tokens/revoke/route.ts
Normal file
13
apps/backoffice/app/tokens/revoke/route.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { NextResponse } from "next/server";
|
||||
import { apiFetch } from "../../../lib/api";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const form = await req.formData();
|
||||
const id = String(form.get("id") || "").trim();
|
||||
if (id) {
|
||||
await apiFetch(`/admin/tokens/${id}`, { method: "DELETE" }).catch(() => null);
|
||||
}
|
||||
revalidatePath("/tokens");
|
||||
return NextResponse.redirect(new URL("/tokens", req.url));
|
||||
}
|
||||
Reference in New Issue
Block a user