web: migrate Token List to web
This commit is contained in:
@ -1,11 +1,43 @@
|
||||
import { DefaultClient } from "./Client";
|
||||
import { AKResponse, DefaultClient, QueryArguments } from "./Client";
|
||||
import { User } from "./Users";
|
||||
|
||||
interface TokenResponse {
|
||||
key: string;
|
||||
export enum TokenIntent {
|
||||
INTENT_VERIFICATION = "verification",
|
||||
INTENT_API = "api",
|
||||
INTENT_RECOVERY = "recovery",
|
||||
}
|
||||
|
||||
export function tokenByIdentifier(identifier: string): Promise<string> {
|
||||
return DefaultClient.fetch<TokenResponse>(["core", "tokens", identifier, "view_key"]).then(
|
||||
(r) => r.key
|
||||
);
|
||||
export class Token {
|
||||
|
||||
pk: string;
|
||||
identifier: string;
|
||||
intent: TokenIntent;
|
||||
user: User;
|
||||
description: string;
|
||||
|
||||
expires: number;
|
||||
expiring: boolean;
|
||||
|
||||
constructor() {
|
||||
throw Error();
|
||||
}
|
||||
|
||||
static get(pk: string): Promise<User> {
|
||||
return DefaultClient.fetch<User>(["core", "tokens", pk]);
|
||||
}
|
||||
|
||||
static list(filter?: QueryArguments): Promise<AKResponse<Token>> {
|
||||
return DefaultClient.fetch<AKResponse<Token>>(["core", "tokens"], filter);
|
||||
}
|
||||
|
||||
static adminUrl(rest: string): string {
|
||||
return `/administration/tokens/${rest}`;
|
||||
}
|
||||
|
||||
static getKey(identifier: string): Promise<string> {
|
||||
return DefaultClient.fetch<{ key: string }>(["core", "tokens", identifier, "view_key"]).then(
|
||||
(r) => r.key
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { css, CSSResult, customElement, html, LitElement, property, TemplateResu
|
||||
import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
|
||||
// @ts-ignore
|
||||
import ButtonStyle from "@patternfly/patternfly/components/Button/button.css";
|
||||
import { tokenByIdentifier } from "../../api/Tokens";
|
||||
import { Token } from "../../api/Tokens";
|
||||
import { ColorStyles, ERROR_CLASS, PRIMARY_CLASS, SUCCESS_CLASS } from "../../constants";
|
||||
|
||||
@customElement("ak-token-copy-button")
|
||||
@ -35,7 +35,7 @@ export class TokenCopyButton extends LitElement {
|
||||
}, 1500);
|
||||
return;
|
||||
}
|
||||
tokenByIdentifier(this.identifier).then((token) => {
|
||||
Token.getKey(this.identifier).then((token) => {
|
||||
navigator.clipboard.writeText(token).then(() => {
|
||||
this.buttonClass = SUCCESS_CLASS;
|
||||
setTimeout(() => {
|
||||
|
@ -43,7 +43,7 @@ export class TablePagination extends LitElement {
|
||||
<button
|
||||
class="pf-c-button pf-m-plain"
|
||||
@click=${() => { this.pageChangeHandler(this.pages?.next || 0); }}
|
||||
?disabled="${(this.pages?.next || 0) < 0}"
|
||||
?disabled="${(this.pages?.next || 0) <= 0}"
|
||||
aria-label="${gettext("Go to next page")}"
|
||||
>
|
||||
<i class="fas fa-angle-right" aria-hidden="true"></i>
|
||||
|
@ -50,7 +50,7 @@ export const SIDEBAR_ITEMS: SidebarItem[] = [
|
||||
new SidebarItem("User", "/users"),
|
||||
new SidebarItem("Groups", "/groups"),
|
||||
new SidebarItem("Certificates", "/crypto/certificates"),
|
||||
new SidebarItem("Tokens", "/administration/tokens/"),
|
||||
new SidebarItem("Tokens", "/tokens"),
|
||||
).when((): Promise<boolean> => {
|
||||
return User.me().then(u => u.is_superuser);
|
||||
}),
|
||||
|
67
web/src/pages/tokens/TokenListPage.ts
Normal file
67
web/src/pages/tokens/TokenListPage.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { gettext } from "django";
|
||||
import { customElement, html, property, TemplateResult } from "lit-element";
|
||||
import { AKResponse } from "../../api/Client";
|
||||
import { TablePage } from "../../elements/table/TablePage";
|
||||
|
||||
import "../../elements/buttons/ModalButton";
|
||||
import "../../elements/buttons/Dropdown";
|
||||
import { TableColumn } from "../../elements/table/Table";
|
||||
import { Token } from "../../api/Tokens";
|
||||
|
||||
@customElement("ak-token-list")
|
||||
export class TokenListPage extends TablePage<Token> {
|
||||
searchEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
pageTitle(): string {
|
||||
return gettext("Tokens");
|
||||
}
|
||||
pageDescription(): string {
|
||||
return gettext("Tokens are used throughout authentik for Email validation stages, Recovery keys and API access.");
|
||||
}
|
||||
pageIcon(): string {
|
||||
return gettext("pf-icon pf-icon-security");
|
||||
}
|
||||
|
||||
@property()
|
||||
order = "expires";
|
||||
|
||||
apiEndpoint(page: number): Promise<AKResponse<Token>> {
|
||||
return Token.list({
|
||||
ordering: this.order,
|
||||
page: page,
|
||||
search: this.search || "",
|
||||
});
|
||||
}
|
||||
|
||||
columns(): TableColumn[] {
|
||||
return [
|
||||
new TableColumn("Identifier", "identifier"),
|
||||
new TableColumn("User", "user"),
|
||||
new TableColumn("Expires?", "expiring"),
|
||||
new TableColumn("Expiry date", "expires"),
|
||||
new TableColumn(""),
|
||||
];
|
||||
}
|
||||
|
||||
row(item: Token): TemplateResult[] {
|
||||
return [
|
||||
html`${item.identifier}`,
|
||||
html`${item.user.username}`,
|
||||
html`${item.expiring ? "Yes" : "No"}`,
|
||||
html`${item.expiring ? new Date(item.expires * 1000).toLocaleString() : '-'}`,
|
||||
html`
|
||||
<ak-modal-button href="${Token.adminUrl(`${item.pk}/delete/`)}">
|
||||
<ak-spinner-button slot="trigger" class="pf-m-danger">
|
||||
${gettext('Delete')}
|
||||
</ak-spinner-button>
|
||||
<div slot="modal"></div>
|
||||
</ak-modal-button>
|
||||
<ak-token-copy-button identifier="${item.identifier}">
|
||||
${gettext('Copy Key')}
|
||||
</ak-token-copy-button>
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -22,6 +22,7 @@ import "./pages/sources/SourcesListPage";
|
||||
import "./pages/sources/SourceViewPage";
|
||||
import "./pages/groups/GroupListPage";
|
||||
import "./pages/users/UserListPage";
|
||||
import "./pages/tokens/TokenListPage";
|
||||
import "./pages/system-tasks/SystemTaskListPage";
|
||||
|
||||
export const ROUTES: Route[] = [
|
||||
@ -47,6 +48,7 @@ export const ROUTES: Route[] = [
|
||||
new Route(new RegExp("^/groups$"), html`<ak-group-list></ak-group-list>`),
|
||||
new Route(new RegExp("^/users$"), html`<ak-user-list></ak-user-list>`),
|
||||
new Route(new RegExp("^/flows$"), html`<ak-flow-list></ak-flow-list>`),
|
||||
new Route(new RegExp("^/tokens$"), html`<ak-token-list></ak-token-list>`),
|
||||
new Route(new RegExp(`^/flows/(?<slug>${SLUG_REGEX})$`)).then((args) => {
|
||||
return html`<ak-flow-view .flowSlug=${args.slug}></ak-flow-view>`;
|
||||
}),
|
||||
|
Reference in New Issue
Block a user