diff --git a/web/src/authentik.css b/web/src/authentik.css index b8a21648d..c9aab8a9f 100644 --- a/web/src/authentik.css +++ b/web/src/authentik.css @@ -103,6 +103,9 @@ select[multiple] { .pf-c-page { --pf-c-page--BackgroundColor: var(--ak-dark-background); } + .pf-c-drawer__content { + --pf-c-drawer__content--BackgroundColor: var(--ak-dark-background); + } .pf-c-title { color: var(--ak-dark-foreground); } diff --git a/web/src/elements/notifications/NotificationDrawer.ts b/web/src/elements/notifications/NotificationDrawer.ts new file mode 100644 index 000000000..9496125ba --- /dev/null +++ b/web/src/elements/notifications/NotificationDrawer.ts @@ -0,0 +1,92 @@ +import { gettext } from "django"; +import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; +import { PBResponse } from "../../api/Client"; +import { Notification } from "../../api/EventNotification"; +import { COMMON_STYLES } from "../../common/styles"; + +@customElement("ak-notification-drawer") +export class NotificationDrawer extends LitElement { + + @property({attribute: false}) + notifications?: PBResponse; + + @property({type: Number}) + unread = 0; + + static get styles(): CSSResult[] { + return COMMON_STYLES.concat( + css` + .pf-c-notification-drawer__header { + height: 82px; + padding: var(--pf-c-page__main-section--PaddingTop) var(--pf-c-page__main-section--PaddingRight) var(--pf-c-page__main-section--PaddingBottom) var(--pf-c-page__main-section--PaddingLeft); + } + ` + ); + } + + firstUpdated(): void { + Notification.list().then(r => { + this.notifications = r; + this.unread = r.results.filter((n) => n.seen).length; + }); + } + + renderItem(item: Notification): TemplateResult { + const delta = Date.now() - parseInt(item.created, 10); + const age = `${Math.round(delta / 1000 / 3600)} Hours ago`; + let level = ""; + switch (item.severity) { + case "notice": + level = "pf-m-info"; + break; + case "warning": + level = "pf-m-warning"; + break; + case "alert": + level = "pf-m-danger"; + break; + default: + break; + } + return html`
  • +
    + + + +

    + ${item.event?.action} +

    +
    +
    + ${item.body.substring(0, 75)} +
    +
    + ${age} +
    +
  • `; + } + + render(): TemplateResult { + if (!this.notifications) { + return html``; + } + return html`
    +
    +
    +

    + ${gettext("Notifications")} +

    + + ${gettext(`${this.unread} unread`)} + +
    +
    +
      + ${this.notifications.results.map(n => this.renderItem(n))} +
    +
    +
    +
    `; + } + +} diff --git a/web/src/elements/notifications/NotificationTrigger.ts b/web/src/elements/notifications/NotificationTrigger.ts new file mode 100644 index 000000000..1acb54fca --- /dev/null +++ b/web/src/elements/notifications/NotificationTrigger.ts @@ -0,0 +1,22 @@ +import { customElement, html, LitElement, TemplateResult } from "lit-element"; + +@customElement("ak-notification-trigger") +export class NotificationTrigger extends LitElement { + + constructor() { + super(); + this.addEventListener("click", () => { + this.dispatchEvent( + new CustomEvent("ak-notification-toggle", { + bubbles: true, + composed: true, + }) + ); + }); + } + + render(): TemplateResult { + return html``; + } + +} diff --git a/web/src/elements/sidebar/SidebarUser.ts b/web/src/elements/sidebar/SidebarUser.ts index 1e200ad73..73c79f188 100644 --- a/web/src/elements/sidebar/SidebarUser.ts +++ b/web/src/elements/sidebar/SidebarUser.ts @@ -1,4 +1,4 @@ -import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; +import { css, CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element"; // @ts-ignore import NavStyle from "@patternfly/patternfly/components/Nav/nav.css"; // @ts-ignore diff --git a/web/src/interfaces/Interface.ts b/web/src/interfaces/Interface.ts index b41fd8e45..61378e313 100644 --- a/web/src/interfaces/Interface.ts +++ b/web/src/interfaces/Interface.ts @@ -5,7 +5,7 @@ import { SidebarItem } from "../elements/sidebar/Sidebar"; import "../elements/router/RouterOutlet"; import "../elements/messages/MessageContainer"; import "../elements/sidebar/SidebarHamburger"; -import "../elements/notifications/NotificationDrawer" +import "../elements/notifications/NotificationDrawer"; export abstract class Interface extends LitElement { @property({type: Boolean})