feat(frontend): list tokens, use formatted dates

This commit is contained in:
Sam 2023-03-15 23:28:57 +01:00
parent 4fbbafc763
commit bfa810fbb2
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
10 changed files with 66 additions and 18 deletions

View file

@ -43,6 +43,7 @@
"base64-arraybuffer": "^1.0.2", "base64-arraybuffer": "^1.0.2",
"bootstrap": "5.3.0-alpha1", "bootstrap": "5.3.0-alpha1",
"bootstrap-icons": "^1.10.3", "bootstrap-icons": "^1.10.3",
"jose": "^4.13.1",
"luxon": "^3.3.0", "luxon": "^3.3.0",
"marked": "^4.2.12", "marked": "^4.2.12",
"sanitize-html": "^2.10.0", "sanitize-html": "^2.10.0",

View file

@ -20,6 +20,7 @@ specifiers:
eslint: ^8.28.0 eslint: ^8.28.0
eslint-config-prettier: ^8.5.0 eslint-config-prettier: ^8.5.0
eslint-plugin-svelte3: ^4.0.0 eslint-plugin-svelte3: ^4.0.0
jose: ^4.13.1
luxon: ^3.3.0 luxon: ^3.3.0
marked: ^4.2.12 marked: ^4.2.12
postcss: ^8.4.21 postcss: ^8.4.21
@ -40,6 +41,7 @@ dependencies:
base64-arraybuffer: 1.0.2 base64-arraybuffer: 1.0.2
bootstrap: 5.3.0-alpha1_@popperjs+core@2.11.6 bootstrap: 5.3.0-alpha1_@popperjs+core@2.11.6
bootstrap-icons: 1.10.3 bootstrap-icons: 1.10.3
jose: 4.13.1
luxon: 3.3.0 luxon: 3.3.0
marked: 4.2.12 marked: 4.2.12
sanitize-html: 2.10.0 sanitize-html: 2.10.0
@ -1546,6 +1548,10 @@ packages:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true dev: true
/jose/4.13.1:
resolution: {integrity: sha512-MSJQC5vXco5Br38mzaQKiq9mwt7lwj2eXpgpRyQYNHYt2lq1PjkWa7DLXX0WVcQLE9HhMh3jPiufS7fhJf+CLQ==}
dev: false
/js-sdsl/4.3.0: /js-sdsl/4.3.0:
resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==} resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==}
dev: true dev: true

View file

@ -74,7 +74,7 @@ export interface MemberPartialUser {
export interface Invite { export interface Invite {
code: string; code: string;
created: Date; created: string;
used: boolean; used: boolean;
} }

View file

@ -32,5 +32,5 @@ interface CallbackResponse {
require_invite: boolean; require_invite: boolean;
is_deleted: boolean; is_deleted: boolean;
deleted_at?: Date; deleted_at?: string;
} }

View file

@ -46,7 +46,7 @@
active={$page.url.pathname === "/settings/tokens"} active={$page.url.pathname === "/settings/tokens"}
href="/settings/tokens" href="/settings/tokens"
> >
API tokens Tokens
</ListGroupItem> </ListGroupItem>
<ListGroupItem <ListGroupItem
tag="a" tag="a"

View file

@ -5,16 +5,7 @@
import ErrorAlert from "$lib/components/ErrorAlert.svelte"; import ErrorAlert from "$lib/components/ErrorAlert.svelte";
import FallbackImage from "$lib/components/FallbackImage.svelte"; import FallbackImage from "$lib/components/FallbackImage.svelte";
import { userStore } from "$lib/store"; import { userStore } from "$lib/store";
import { import { Button, Icon, Modal, ModalBody, ModalFooter, ModalHeader, Table } from "sveltestrap";
Alert,
Button,
Icon,
Modal,
ModalBody,
ModalFooter,
ModalHeader,
Table,
} from "sveltestrap";
import type { PageData } from "./$types"; import type { PageData } from "./$types";
export let data: PageData; export let data: PageData;

View file

@ -15,5 +15,5 @@ export const load = async () => {
interface ExportResponse { interface ExportResponse {
path: string; path: string;
created_at: Date; created_at: string;
} }

View file

@ -2,7 +2,8 @@
import type { APIError, Invite } from "$lib/api/entities"; import type { APIError, Invite } from "$lib/api/entities";
import { apiFetchClient } from "$lib/api/fetch"; import { apiFetchClient } from "$lib/api/fetch";
import ErrorAlert from "$lib/components/ErrorAlert.svelte"; import ErrorAlert from "$lib/components/ErrorAlert.svelte";
import { Alert, Button, Modal, Table } from "sveltestrap"; import { DateTime } from "luxon";
import { Button, Modal, Table } from "sveltestrap";
import type { PageData } from "./$types"; import type { PageData } from "./$types";
export let data: PageData; export let data: PageData;
@ -43,7 +44,11 @@
{#each data.invites as invite} {#each data.invites as invite}
<tr> <tr>
<td><code>{invite.code}</code></td> <td><code>{invite.code}</code></td>
<td>{invite.created}</td> <td
>{DateTime.fromISO(invite.created)
.toLocal()
.toLocaleString(DateTime.DATETIME_MED)}</td
>
<td>{invite.used ? "yes" : "no"}</td> <td>{invite.used ? "yes" : "no"}</td>
</tr> </tr>
{/each} {/each}

View file

@ -1,3 +1,36 @@
<h1>API tokens</h1> <script lang="ts">
import { DateTime } from "luxon";
import { Icon, Table } from "sveltestrap";
import type { PageData } from "./$types";
<p>This page is a work in progress, sorry!</p> export let data: PageData;
import * as jose from "jose";
const claims = jose.decodeJwt(localStorage.getItem("pronouns-token")!);
</script>
<h1>Tokens ({data.tokens.length})</h1>
<Table bordered striped hover>
<thead>
<th>ID</th>
<th>Created at</th>
<th>Expires at</th>
<th>Current?</th>
</thead>
<tbody>
{#each data.tokens as token}
<tr>
<td><code>{token.id}</code></td>
<td>{DateTime.fromISO(token.created).toLocal().toLocaleString(DateTime.DATETIME_MED)}</td>
<td>{DateTime.fromISO(token.expires).toLocal().toLocaleString(DateTime.DATETIME_MED)}</td>
<td
>{#if claims["jti"] === token.id}<Icon name="check-lg" alt="Current token" />{:else}<Icon
name="x-lg"
alt="Not current token"
/>{/if}</td
>
</tr>
{/each}
</tbody>
</Table>

View file

@ -0,0 +1,12 @@
import { apiFetchClient } from "$lib/api/fetch";
export const load = async () => {
const tokens = await apiFetchClient<Token[]>("/auth/tokens");
return { tokens };
};
interface Token {
id: string;
created: string;
expires: string;
}