web: add API Drawer
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
562eb8af95
commit
fdd8e66b91
|
@ -1,6 +1,6 @@
|
||||||
import { Config, Configuration, CoreApi, CurrentTenant, Middleware, ResponseContext, RootApi, Tenant } from "authentik-api";
|
import { Config, Configuration, CoreApi, CurrentTenant, Middleware, ResponseContext, RootApi, Tenant } from "authentik-api";
|
||||||
import { getCookie } from "../utils";
|
import { getCookie } from "../utils";
|
||||||
import { API_DRAWER_MIDDLEWARE } from "../elements/notifications/APIDrawer";
|
import { APIMiddleware } from "../elements/notifications/APIDrawer";
|
||||||
import { MessageMiddleware } from "../elements/messages/Middleware";
|
import { MessageMiddleware } from "../elements/messages/Middleware";
|
||||||
|
|
||||||
export class LoggingMiddleware implements Middleware {
|
export class LoggingMiddleware implements Middleware {
|
||||||
|
@ -62,7 +62,7 @@ export const DEFAULT_CONFIG = new Configuration({
|
||||||
"X-CSRFToken": getCookie("authentik_csrf"),
|
"X-CSRFToken": getCookie("authentik_csrf"),
|
||||||
},
|
},
|
||||||
middleware: [
|
middleware: [
|
||||||
API_DRAWER_MIDDLEWARE,
|
new APIMiddleware(),
|
||||||
new MessageMiddleware(),
|
new MessageMiddleware(),
|
||||||
new LoggingMiddleware(),
|
new LoggingMiddleware(),
|
||||||
],
|
],
|
||||||
|
|
|
@ -230,6 +230,9 @@ body {
|
||||||
.pf-c-form-control[readonly] {
|
.pf-c-form-control[readonly] {
|
||||||
background-color: var(--ak-dark-background-light);
|
background-color: var(--ak-dark-background-light);
|
||||||
}
|
}
|
||||||
|
.pf-c-button.pf-m-plain:hover {
|
||||||
|
color: var(--ak-dark-foreground);
|
||||||
|
}
|
||||||
.pf-c-button.pf-m-control {
|
.pf-c-button.pf-m-control {
|
||||||
--pf-c-button--after--BorderColor: var(--ak-dark-background-lighter)
|
--pf-c-button--after--BorderColor: var(--ak-dark-background-lighter)
|
||||||
var(--ak-dark-background-lighter)
|
var(--ak-dark-background-lighter)
|
||||||
|
|
|
@ -9,7 +9,8 @@ export const TITLE_DEFAULT = "authentik";
|
||||||
export const ROUTE_SEPARATOR = ";";
|
export const ROUTE_SEPARATOR = ";";
|
||||||
|
|
||||||
export const EVENT_REFRESH = "ak-refresh";
|
export const EVENT_REFRESH = "ak-refresh";
|
||||||
export const EVENT_NOTIFICATION_TOGGLE = "ak-notification-toggle";
|
export const EVENT_NOTIFICATION_DRAWER_TOGGLE = "ak-notification-toggle";
|
||||||
|
export const EVENT_API_DRAWER_TOGGLE = "ak-api-drawer-toggle";
|
||||||
export const EVENT_SIDEBAR_TOGGLE = "ak-sidebar-toggle";
|
export const EVENT_SIDEBAR_TOGGLE = "ak-sidebar-toggle";
|
||||||
export const EVENT_API_DRAWER_REFRESH = "ak-api-drawer-refresh";
|
export const EVENT_API_DRAWER_REFRESH = "ak-api-drawer-refresh";
|
||||||
export const EVENT_WS_MESSAGE = "ak-ws-message";
|
export const EVENT_WS_MESSAGE = "ak-ws-message";
|
||||||
|
|
|
@ -12,7 +12,7 @@ import PFContent from "@patternfly/patternfly/components/Content/content.css";
|
||||||
import AKGlobal from "../authentik.css";
|
import AKGlobal from "../authentik.css";
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||||
import { EVENT_NOTIFICATION_TOGGLE, EVENT_SIDEBAR_TOGGLE, TITLE_DEFAULT } from "../constants";
|
import { EVENT_API_DRAWER_TOGGLE, EVENT_NOTIFICATION_DRAWER_TOGGLE, EVENT_SIDEBAR_TOGGLE, TITLE_DEFAULT } from "../constants";
|
||||||
import { DEFAULT_CONFIG, tenant } from "../api/Config";
|
import { DEFAULT_CONFIG, tenant } from "../api/Config";
|
||||||
import { EventsApi } from "../../api/dist";
|
import { EventsApi } from "../../api/dist";
|
||||||
|
|
||||||
|
@ -127,13 +127,26 @@ export class PageHeader extends LitElement {
|
||||||
${this.description ? html`<p>${this.description}</p>` : html``}
|
${this.description ? html`<p>${this.description}</p>` : html``}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<button
|
||||||
|
class="notification-trigger pf-c-button pf-m-plain"
|
||||||
|
@click=${() => {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent(EVENT_API_DRAWER_TOGGLE, {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i class="fas fa-code"></i>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="notification-trigger pf-c-button pf-m-plain ${this.hasNotifications
|
class="notification-trigger pf-c-button pf-m-plain ${this.hasNotifications
|
||||||
? "has-notifications"
|
? "has-notifications"
|
||||||
: ""}"
|
: ""}"
|
||||||
@click=${() => {
|
@click=${() => {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent(EVENT_NOTIFICATION_TOGGLE, {
|
new CustomEvent(EVENT_NOTIFICATION_DRAWER_TOGGLE, {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
}),
|
}),
|
||||||
|
@ -141,6 +154,7 @@ export class PageHeader extends LitElement {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<i class="fas fa-bell"></i>
|
<i class="fas fa-bell"></i>
|
||||||
</button>`;
|
</button>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,77 +1,114 @@
|
||||||
import { Middleware, ResponseContext } from "authentik-api";
|
import { Middleware, ResponseContext } from "authentik-api";
|
||||||
import { CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element";
|
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
import PFNotificationDrawer from "@patternfly/patternfly/components/NotificationDrawer/notification-drawer.css";
|
import PFNotificationDrawer from "@patternfly/patternfly/components/NotificationDrawer/notification-drawer.css";
|
||||||
import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";
|
import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css";
|
||||||
import AKGlobal from "../../authentik.css";
|
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||||
import PFContent from "@patternfly/patternfly/components/Content/content.css";
|
import PFContent from "@patternfly/patternfly/components/Content/content.css";
|
||||||
|
import AKGlobal from "../../authentik.css";
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { EVENT_API_DRAWER_REFRESH } from "../../constants";
|
import { EVENT_API_DRAWER_REFRESH, EVENT_API_DRAWER_TOGGLE } from "../../constants";
|
||||||
|
|
||||||
export interface RequestInfo {
|
export interface RequestInfo {
|
||||||
method: string;
|
method: string;
|
||||||
path: string;
|
path: string;
|
||||||
|
status: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class APIMiddleware implements Middleware {
|
export class APIMiddleware implements Middleware {
|
||||||
requests: RequestInfo[];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.requests = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
post?(context: ResponseContext): Promise<Response | void> {
|
post?(context: ResponseContext): Promise<Response | void> {
|
||||||
this.requests.push({
|
const request: RequestInfo = {
|
||||||
method: (context.init.method || "GET").toUpperCase(),
|
method: (context.init.method || "GET").toUpperCase(),
|
||||||
path: context.url,
|
path: context.url,
|
||||||
});
|
status: context.response.status,
|
||||||
if (this.requests.length > MAX_REQUESTS) {
|
};
|
||||||
this.requests.shift();
|
|
||||||
}
|
|
||||||
window.dispatchEvent(
|
window.dispatchEvent(
|
||||||
new CustomEvent(EVENT_API_DRAWER_REFRESH, {
|
new CustomEvent(EVENT_API_DRAWER_REFRESH, {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
|
detail: request,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return Promise.resolve(context.response);
|
return Promise.resolve(context.response);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export const MAX_REQUESTS = 50;
|
}
|
||||||
export const API_DRAWER_MIDDLEWARE = new APIMiddleware();
|
|
||||||
|
|
||||||
@customElement("ak-api-drawer")
|
@customElement("ak-api-drawer")
|
||||||
export class APIDrawer extends LitElement {
|
export class APIDrawer extends LitElement {
|
||||||
|
|
||||||
|
@property({attribute: false})
|
||||||
|
requests: RequestInfo[] = [];
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [PFBase, PFNotificationDrawer, PFContent, PFDropdown, AKGlobal];
|
return [PFBase, PFNotificationDrawer, PFButton, PFContent, PFDropdown, AKGlobal, css`
|
||||||
|
.pf-c-notification-drawer__header {
|
||||||
|
height: 114px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.pf-c-notification-drawer__header-action,
|
||||||
|
.pf-c-notification-drawer__header-action-close,
|
||||||
|
.pf-c-notification-drawer__header-action-close > .pf-c-button.pf-m-plain {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.pf-c-notification-drawer__list-item-description {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
`];
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.addEventListener(EVENT_API_DRAWER_REFRESH, () => {
|
window.addEventListener(EVENT_API_DRAWER_REFRESH, ((e: CustomEvent<RequestInfo>) => {
|
||||||
|
this.requests.splice(0, 0, e.detail);
|
||||||
|
if (this.requests.length > 50) {
|
||||||
|
this.requests.shift();
|
||||||
|
}
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
});
|
}) as EventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderItem(item: RequestInfo): TemplateResult {
|
renderItem(item: RequestInfo): TemplateResult {
|
||||||
return html`<li class="pf-c-notification-drawer__list-item pf-m-read">
|
return html`<li class="pf-c-notification-drawer__list-item pf-m-read">
|
||||||
<div class="pf-c-notification-drawer__list-item-header">
|
<div class="pf-c-notification-drawer__list-item-header">
|
||||||
<h2 class="pf-c-notification-drawer__list-item-header-title">${item.method}</h2>
|
<h2 class="pf-c-notification-drawer__list-item-header-title">${item.method}: ${item.status}</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="pf-c-notification-drawer__list-item-description">${item.path}</p>
|
<a class="pf-c-notification-drawer__list-item-description" href=${item.path}>${item.path}</a>
|
||||||
</li>`;
|
</li>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
return html`<div class="pf-c-drawer__body pf-m-no-padding">
|
return html`<div class="pf-c-drawer__body pf-m-no-padding">
|
||||||
<div class="pf-c-notification-drawer">
|
<div class="pf-c-notification-drawer">
|
||||||
<div class="pf-c-notification-drawer__header pf-c-content">
|
<div class="pf-c-notification-drawer__header">
|
||||||
<h1>${t`API Requests`}</h1>
|
<div class="text">
|
||||||
|
<h1 class="pf-c-notification-drawer__header-title">${t`API Requests`}</h1>
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-notification-drawer__header-action">
|
||||||
|
<div class="pf-c-notification-drawer__header-action-close">
|
||||||
|
<button
|
||||||
|
@click=${() => {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent(EVENT_API_DRAWER_TOGGLE, {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
class="pf-c-button pf-m-plain"
|
||||||
|
type="button"
|
||||||
|
aria-label="Close"
|
||||||
|
>
|
||||||
|
<i class="fas fa-times" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pf-c-notification-drawer__body">
|
<div class="pf-c-notification-drawer__body">
|
||||||
<ul class="pf-c-notification-drawer__list">
|
<ul class="pf-c-notification-drawer__list">
|
||||||
${API_DRAWER_MIDDLEWARE.requests.map((n) => this.renderItem(n))}
|
${this.requests.map((n) => this.renderItem(n))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,7 +17,7 @@ import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css"
|
||||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||||
import AKGlobal from "../../authentik.css";
|
import AKGlobal from "../../authentik.css";
|
||||||
import PFContent from "@patternfly/patternfly/components/Content/content.css";
|
import PFContent from "@patternfly/patternfly/components/Content/content.css";
|
||||||
import { EVENT_NOTIFICATION_TOGGLE } from "../../constants";
|
import { EVENT_NOTIFICATION_DRAWER_TOGGLE } from "../../constants";
|
||||||
import { ActionToLabel } from "../../pages/events/utils";
|
import { ActionToLabel } from "../../pages/events/utils";
|
||||||
|
|
||||||
@customElement("ak-notification-drawer")
|
@customElement("ak-notification-drawer")
|
||||||
|
@ -135,7 +135,7 @@ export class NotificationDrawer extends LitElement {
|
||||||
<button
|
<button
|
||||||
@click=${() => {
|
@click=${() => {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent(EVENT_NOTIFICATION_TOGGLE, {
|
new CustomEvent(EVENT_NOTIFICATION_DRAWER_TOGGLE, {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -24,7 +24,7 @@ import "../elements/messages/MessageContainer";
|
||||||
import "../elements/notifications/NotificationDrawer";
|
import "../elements/notifications/NotificationDrawer";
|
||||||
import "../elements/sidebar/Sidebar";
|
import "../elements/sidebar/Sidebar";
|
||||||
import { until } from "lit-html/directives/until";
|
import { until } from "lit-html/directives/until";
|
||||||
import { EVENT_NOTIFICATION_TOGGLE, EVENT_SIDEBAR_TOGGLE, VERSION } from "../constants";
|
import { EVENT_API_DRAWER_TOGGLE, EVENT_NOTIFICATION_DRAWER_TOGGLE, EVENT_SIDEBAR_TOGGLE, VERSION } from "../constants";
|
||||||
import { AdminApi } from "authentik-api";
|
import { AdminApi } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../api/Config";
|
import { DEFAULT_CONFIG } from "../api/Config";
|
||||||
import { WebsocketClient } from "../common/ws";
|
import { WebsocketClient } from "../common/ws";
|
||||||
|
@ -37,6 +37,9 @@ export class AdminInterface extends LitElement {
|
||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
notificationOpen = false;
|
notificationOpen = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean })
|
||||||
|
apiDrawerOpen = false;
|
||||||
|
|
||||||
ws: WebsocketClient;
|
ws: WebsocketClient;
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
|
@ -67,9 +70,12 @@ export class AdminInterface extends LitElement {
|
||||||
window.addEventListener(EVENT_SIDEBAR_TOGGLE, () => {
|
window.addEventListener(EVENT_SIDEBAR_TOGGLE, () => {
|
||||||
this.sidebarOpen = !this.sidebarOpen;
|
this.sidebarOpen = !this.sidebarOpen;
|
||||||
});
|
});
|
||||||
window.addEventListener(EVENT_NOTIFICATION_TOGGLE, () => {
|
window.addEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, () => {
|
||||||
this.notificationOpen = !this.notificationOpen;
|
this.notificationOpen = !this.notificationOpen;
|
||||||
});
|
});
|
||||||
|
window.addEventListener(EVENT_API_DRAWER_TOGGLE, () => {
|
||||||
|
this.apiDrawerOpen = !this.apiDrawerOpen;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
|
@ -81,7 +87,7 @@ export class AdminInterface extends LitElement {
|
||||||
</ak-sidebar>
|
</ak-sidebar>
|
||||||
<div class="pf-c-page__drawer">
|
<div class="pf-c-page__drawer">
|
||||||
<div
|
<div
|
||||||
class="pf-c-drawer ${this.notificationOpen
|
class="pf-c-drawer ${this.notificationOpen || this.apiDrawerOpen
|
||||||
? "pf-m-expanded"
|
? "pf-m-expanded"
|
||||||
: "pf-m-collapsed"}"
|
: "pf-m-collapsed"}"
|
||||||
>
|
>
|
||||||
|
@ -100,8 +106,8 @@ export class AdminInterface extends LitElement {
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ak-notification-drawer class="pf-c-drawer__panel pf-m-width-33">
|
${this.notificationOpen ? html`<ak-notification-drawer class="pf-c-drawer__panel pf-m-width-33"></ak-notification-drawer>` : html``}
|
||||||
</ak-notification-drawer>
|
${this.apiDrawerOpen ? html`<ak-api-drawer class="pf-c-drawer__panel pf-m-width-33"></ak-api-drawer>` : html``}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -77,16 +77,7 @@ export class TransportListPage extends TablePage<NotificationTransport> {
|
||||||
return [
|
return [
|
||||||
html`${item.name}`,
|
html`${item.name}`,
|
||||||
html`${item.modeVerbose}`,
|
html`${item.modeVerbose}`,
|
||||||
html` <ak-action-button
|
html`<ak-forms-modal>
|
||||||
.apiRequest=${() => {
|
|
||||||
return new EventsApi(DEFAULT_CONFIG).eventsTransportsTestCreate({
|
|
||||||
uuid: item.pk || "",
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
${t`Test`}
|
|
||||||
</ak-action-button>
|
|
||||||
<ak-forms-modal>
|
|
||||||
<span slot="submit"> ${t`Update`} </span>
|
<span slot="submit"> ${t`Update`} </span>
|
||||||
<span slot="header"> ${t`Update Notification Transport`} </span>
|
<span slot="header"> ${t`Update Notification Transport`} </span>
|
||||||
<ak-event-transport-form slot="form" .instancePk=${item.pk}>
|
<ak-event-transport-form slot="form" .instancePk=${item.pk}>
|
||||||
|
@ -94,7 +85,16 @@ export class TransportListPage extends TablePage<NotificationTransport> {
|
||||||
<button slot="trigger" class="pf-c-button pf-m-plain">
|
<button slot="trigger" class="pf-c-button pf-m-plain">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</button>
|
</button>
|
||||||
</ak-forms-modal>`,
|
</ak-forms-modal>
|
||||||
|
<ak-action-button
|
||||||
|
.apiRequest=${() => {
|
||||||
|
return new EventsApi(DEFAULT_CONFIG).eventsTransportsTestCreate({
|
||||||
|
uuid: item.pk || "",
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i class="fas fa-vial" aria-hidden="true"></i>
|
||||||
|
</ak-action-button>`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue