web: clean up UserInterface in prep for OAuth and Silo Projects (#8278)
* This was pretty quick. While looking at the Oauth stuff, changes made to the UserInterface triggered
the "harder" eslint pass, which said "UserInterface exceeds permitted complexity (9)." I couldn't
disagree; it had lots of conditionals.
This commit:
- Changes no functionality; it's just cleanup.
- Breaks UserInterface into business and presentation layers
- The presentation layer:
  - Further breaks the presentation layer into a frame and conditional components. Each conditional
    is now a simple guard condition.
  - Taps into the event listener set-up for toggles, eliminating their local scope/window duplication
  - Extracts in-line complex expressions into isolated and scope functions to name them and make them
    easier to find and read.
  - Extracts the custom CSS into its own named variable, again, making it easier to find and read.
- The business layer:
  - Builds the window-level event listener at connection, and disconnects them correctly, allowing
    this whole interface to be used in a SPA.
  - Asserts a reliable contract at the presentation layer; there should be no question "Session" and
    "UIConfig" are available before rendering.
  - Renames `firstUpdated` to `fetchConfigurationDetails`, and calls it in the constructor. There
    ought to be no circumstances where this object is constructed outside a working environment; no
    sense in waiting until you've done a `render() { nothing }` pass to fetch details.
Oddities: There are a pair of `<!-- -->` HTML comments in the framing `render()`; those are there
just to stop prettier from slamming a string of conditional renders all into one line, making them
harder to read.
* Adding a small experiment: Typescript pattern matching.
* A few renames as requested by @BeryJu
			
			
This commit is contained in:
		
							
								
								
									
										3668
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3668
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -64,6 +64,7 @@ | ||||
|         "mermaid": "^10.8.0", | ||||
|         "rapidoc": "^9.3.4", | ||||
|         "style-mod": "^4.1.2", | ||||
|         "ts-pattern": "^5.0.6", | ||||
|         "webcomponent-qr-code": "^1.2.0", | ||||
|         "yaml": "^2.4.0" | ||||
|     }, | ||||
|  | ||||
| @ -5,10 +5,10 @@ import { | ||||
|     EVENT_WS_MESSAGE, | ||||
| } from "@goauthentik/common/constants"; | ||||
| import { configureSentry } from "@goauthentik/common/sentry"; | ||||
| import { UserDisplay } from "@goauthentik/common/ui/config"; | ||||
| import { UIConfig, UserDisplay } from "@goauthentik/common/ui/config"; | ||||
| import { me } from "@goauthentik/common/users"; | ||||
| import { first } from "@goauthentik/common/utils"; | ||||
| import { WebsocketClient } from "@goauthentik/common/ws"; | ||||
| import { AKElement } from "@goauthentik/elements/Base"; | ||||
| import { EnterpriseAwareInterface } from "@goauthentik/elements/Interface"; | ||||
| import "@goauthentik/elements/ak-locale-context"; | ||||
| import "@goauthentik/elements/buttons/ActionButton"; | ||||
| @ -23,9 +23,10 @@ import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand"; | ||||
| import "@goauthentik/elements/sidebar/SidebarItem"; | ||||
| import { ROUTES } from "@goauthentik/user/Routes"; | ||||
| import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; | ||||
| import { match } from "ts-pattern"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| import { CSSResult, TemplateResult, css, html } from "lit"; | ||||
| import { css, html, nothing } from "lit"; | ||||
| import { customElement, property, state } from "lit/decorators.js"; | ||||
|  | ||||
| import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css"; | ||||
| @ -38,36 +39,9 @@ import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||
| import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||
| import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css"; | ||||
|  | ||||
| import { CoreApi, EventsApi, SessionUser } from "@goauthentik/api"; | ||||
| import { CoreApi, CurrentBrand, EventsApi, SessionUser } from "@goauthentik/api"; | ||||
|  | ||||
| @customElement("ak-interface-user") | ||||
| export class UserInterface extends EnterpriseAwareInterface { | ||||
|     @property({ type: Boolean }) | ||||
|     notificationDrawerOpen = getURLParam("notificationDrawerOpen", false); | ||||
|  | ||||
|     @property({ type: Boolean }) | ||||
|     apiDrawerOpen = getURLParam("apiDrawerOpen", false); | ||||
|  | ||||
|     ws: WebsocketClient; | ||||
|  | ||||
|     @property({ type: Number }) | ||||
|     notificationsCount = 0; | ||||
|  | ||||
|     @state() | ||||
|     me?: SessionUser; | ||||
|  | ||||
|     static get styles(): CSSResult[] { | ||||
|         return [ | ||||
|             PFBase, | ||||
|             PFDisplay, | ||||
|             PFBrand, | ||||
|             PFPage, | ||||
|             PFAvatar, | ||||
|             PFButton, | ||||
|             PFDrawer, | ||||
|             PFDropdown, | ||||
|             PFNotificationBadge, | ||||
|             css` | ||||
| const customStyles = css` | ||||
|     .pf-c-page__main, | ||||
|     .pf-c-drawer__content, | ||||
|     .pf-c-page__drawer { | ||||
| @ -125,64 +99,87 @@ export class UserInterface extends EnterpriseAwareInterface { | ||||
|         min-height: calc(100vh - 76px); | ||||
|         max-height: calc(100vh - 76px); | ||||
|     } | ||||
|             `, | ||||
| `; | ||||
|  | ||||
| //  ___                     _        _   _ | ||||
| // | _ \_ _ ___ ___ ___ _ _| |_ __ _| |_(_)___ _ _ | ||||
| // |  _/ '_/ -_|_-</ -_) ' \  _/ _` |  _| / _ \ ' \ | ||||
| // |_| |_| \___/__/\___|_||_\__\__,_|\__|_\___/_||_| | ||||
| // | ||||
|  | ||||
| // Despite the length of the render() method and its accessories, this top-level Interface does | ||||
| // surprisingly little. It has been broken into two parts: the business logic at the bottom, and the | ||||
| // rendering code at the top, which is wholly independent of APIs and Interfaces. | ||||
|  | ||||
| // Because this is not exported, and because it's invoked as a web component, neither TSC or ESLint | ||||
| // trusts that we actually used it. Hence the double ignore below: | ||||
|  | ||||
| @customElement("ak-interface-user-presentation") | ||||
| // @ts-ignore | ||||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||||
| class UserInterfacePresentation extends AKElement { | ||||
|     static get styles() { | ||||
|         return [ | ||||
|             PFBase, | ||||
|             PFDisplay, | ||||
|             PFBrand, | ||||
|             PFPage, | ||||
|             PFAvatar, | ||||
|             PFButton, | ||||
|             PFDrawer, | ||||
|             PFDropdown, | ||||
|             PFNotificationBadge, | ||||
|             customStyles, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     constructor() { | ||||
|         super(); | ||||
|         this.ws = new WebsocketClient(); | ||||
|         window.addEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, () => { | ||||
|             this.notificationDrawerOpen = !this.notificationDrawerOpen; | ||||
|             updateURLParams({ | ||||
|                 notificationDrawerOpen: this.notificationDrawerOpen, | ||||
|             }); | ||||
|         }); | ||||
|         window.addEventListener(EVENT_API_DRAWER_TOGGLE, () => { | ||||
|             this.apiDrawerOpen = !this.apiDrawerOpen; | ||||
|             updateURLParams({ | ||||
|                 apiDrawerOpen: this.apiDrawerOpen, | ||||
|             }); | ||||
|         }); | ||||
|         window.addEventListener(EVENT_WS_MESSAGE, () => { | ||||
|             this.firstUpdated(); | ||||
|         }); | ||||
|         configureSentry(true); | ||||
|     @property({ type: Object }) | ||||
|     uiConfig!: UIConfig; | ||||
|  | ||||
|     @property({ type: Object }) | ||||
|     me!: SessionUser; | ||||
|  | ||||
|     @property({ type: Boolean, reflect: true }) | ||||
|     notificationDrawerOpen = false; | ||||
|  | ||||
|     @property({ type: Boolean, reflect: true }) | ||||
|     apiDrawerOpen = false; | ||||
|  | ||||
|     @property({ type: Number }) | ||||
|     notificationsCount = 0; | ||||
|  | ||||
|     @property({ type: Object }) | ||||
|     brand!: CurrentBrand; | ||||
|  | ||||
|     get userDisplayName() { | ||||
|         return match<UserDisplay, string>(this.uiConfig.navbar.userDisplay) | ||||
|             .with(UserDisplay.username, () => this.me.user.username) | ||||
|             .with(UserDisplay.name, () => this.me.user.name) | ||||
|             .with(UserDisplay.email, () => this.me.user.email || "") | ||||
|             .otherwise(() => this.me.user.username); | ||||
|     } | ||||
|  | ||||
|     async firstUpdated(): Promise<void> { | ||||
|         this.me = await me(); | ||||
|         const notifications = await new EventsApi(DEFAULT_CONFIG).eventsNotificationsList({ | ||||
|             seen: false, | ||||
|             ordering: "-created", | ||||
|             pageSize: 1, | ||||
|             user: this.me.user.pk, | ||||
|         }); | ||||
|         this.notificationsCount = notifications.pagination.count; | ||||
|     } | ||||
|  | ||||
|     render(): TemplateResult { | ||||
|         if (!this.uiConfig || !this.me) { | ||||
|             return html``; | ||||
|         } | ||||
|         let userDisplay = ""; | ||||
|         switch (this.uiConfig.navbar.userDisplay) { | ||||
|             case UserDisplay.username: | ||||
|                 userDisplay = this.me.user.username; | ||||
|                 break; | ||||
|             case UserDisplay.name: | ||||
|                 userDisplay = this.me.user.name; | ||||
|                 break; | ||||
|             case UserDisplay.email: | ||||
|                 userDisplay = this.me.user.email || ""; | ||||
|                 break; | ||||
|             default: | ||||
|                 userDisplay = this.me.user.username; | ||||
|         } | ||||
|         const canAccessAdmin = | ||||
|     get canAccessAdmin() { | ||||
|         return ( | ||||
|             this.me.user.isSuperuser || | ||||
|             // TODO: somehow add `access_admin_interface` to the API schema | ||||
|             this.me.user.systemPermissions.includes("access_admin_interface"); | ||||
|             this.me.user.systemPermissions.includes("access_admin_interface") | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     get isFullyConfigured() { | ||||
|         return !!(this.uiConfig && this.me && this.brand); | ||||
|     } | ||||
|  | ||||
|     render() { | ||||
|         // The `!` in the field definitions above only re-assure typescript and eslint that the | ||||
|         // values *should* be available, not that they *are*. Thus this contract check; it asserts | ||||
|         // that the contract we promised is being honored, and the rest of the code that depends on | ||||
|         // `!` being truthful is not being lied to. | ||||
|         if (!this.isFullyConfigured) { | ||||
|             throw new Error("ak-interface-user-presentation misused; no valid values passed"); | ||||
|         } | ||||
|  | ||||
|         return html` <ak-locale-context> | ||||
|             <ak-enterprise-status interface="user"></ak-enterprise-status> | ||||
|             <div class="pf-c-page"> | ||||
| @ -196,85 +193,18 @@ export class UserInterface extends EnterpriseAwareInterface { | ||||
|                         <a href="#/" class="pf-c-page__header-brand-link"> | ||||
|                             <img | ||||
|                                 class="pf-c-brand" | ||||
|                                 src="${first(this.brand?.brandingLogo, DefaultBrand.brandingLogo)}" | ||||
|                                 alt="${(this.brand?.brandingTitle, DefaultBrand.brandingTitle)}" | ||||
|                                 src="${this.brand.brandingLogo}" | ||||
|                                 alt="${this.brand.brandingTitle}" | ||||
|                             /> | ||||
|                         </a> | ||||
|                     </div> | ||||
|                     <div class="pf-c-page__header-tools"> | ||||
|                         <div class="pf-c-page__header-tools-group"> | ||||
|                             ${this.uiConfig.enabledFeatures.apiDrawer | ||||
|                                 ? html`<div | ||||
|                                       class="pf-c-page__header-tools-item pf-m-hidden pf-m-visible-on-lg" | ||||
|                                   > | ||||
|                                       <button | ||||
|                                           class="pf-c-button pf-m-plain" | ||||
|                                           type="button" | ||||
|                                           @click=${() => { | ||||
|                                               this.apiDrawerOpen = !this.apiDrawerOpen; | ||||
|                                               updateURLParams({ | ||||
|                                                   apiDrawerOpen: this.apiDrawerOpen, | ||||
|                                               }); | ||||
|                                           }} | ||||
|                                       > | ||||
|                                           <pf-tooltip | ||||
|                                               position="top" | ||||
|                                               content=${msg("Open API drawer")} | ||||
|                                           > | ||||
|                                               <i class="fas fa-code" aria-hidden="true"></i> | ||||
|                                           </pf-tooltip> | ||||
|                                       </button> | ||||
|                                   </div>` | ||||
|                                 : html``} | ||||
|                             ${this.uiConfig.enabledFeatures.notificationDrawer | ||||
|                                 ? html`<div | ||||
|                                       class="pf-c-page__header-tools-item pf-m-hidden pf-m-visible-on-lg" | ||||
|                                   > | ||||
|                                       <button | ||||
|                                           class="pf-c-button pf-m-plain" | ||||
|                                           type="button" | ||||
|                                           aria-label="${msg("Unread notifications")}" | ||||
|                                           @click=${() => { | ||||
|                                               this.notificationDrawerOpen = | ||||
|                                                   !this.notificationDrawerOpen; | ||||
|                                               updateURLParams({ | ||||
|                                                   notificationDrawerOpen: | ||||
|                                                       this.notificationDrawerOpen, | ||||
|                                               }); | ||||
|                                           }} | ||||
|                                       > | ||||
|                                           <span | ||||
|                                               class="pf-c-notification-badge ${this | ||||
|                                                   .notificationsCount > 0 | ||||
|                                                   ? "pf-m-unread" | ||||
|                                                   : ""}" | ||||
|                                           > | ||||
|                                               <pf-tooltip | ||||
|                                                   position="top" | ||||
|                                                   content=${msg("Open Notification drawer")} | ||||
|                                               > | ||||
|                                                   <i class="fas fa-bell" aria-hidden="true"></i> | ||||
|                                               </pf-tooltip> | ||||
|                                               <span class="pf-c-notification-badge__count" | ||||
|                                                   >${this.notificationsCount}</span | ||||
|                                               > | ||||
|                                           </span> | ||||
|                                       </button> | ||||
|                                   </div> ` | ||||
|                                 : html``} | ||||
|                             ${this.uiConfig.enabledFeatures.settings | ||||
|                                 ? html` <div class="pf-c-page__header-tools-item"> | ||||
|                                       <a | ||||
|                                           class="pf-c-button pf-m-plain" | ||||
|                                           type="button" | ||||
|                                           href="#/settings" | ||||
|                                       > | ||||
|                                           <pf-tooltip position="top" content=${msg("Settings")}> | ||||
|                                               <i class="fas fa-cog" aria-hidden="true"></i> | ||||
|                                           </pf-tooltip> | ||||
|                                       </a> | ||||
|                                   </div>` | ||||
|                                 : html``} | ||||
|                             ${this.renderApiDrawerTrigger()} | ||||
|                             <!-- --> | ||||
|                             ${this.renderNotificationDrawerTrigger()} | ||||
|                             <!-- --> | ||||
|                             ${this.renderSettings()} | ||||
|                             <div class="pf-c-page__header-tools-item"> | ||||
|                                 <a | ||||
|                                     href="/flows/-/default/invalidation/" | ||||
| @ -285,39 +215,14 @@ export class UserInterface extends EnterpriseAwareInterface { | ||||
|                                     </pf-tooltip> | ||||
|                                 </a> | ||||
|                             </div> | ||||
|                             ${canAccessAdmin | ||||
|                                 ? html`<a | ||||
|                                       class="pf-c-button pf-m-secondary pf-m-small pf-u-display-none pf-u-display-block-on-md" | ||||
|                                       href="/if/admin/" | ||||
|                                   > | ||||
|                                       ${msg("Admin interface")} | ||||
|                                   </a>` | ||||
|                                 : html``} | ||||
|                             ${this.renderAdminInterfaceLink()} | ||||
|                         </div> | ||||
|                         ${this.me.original | ||||
|                             ? html`  | ||||
|                                   <div class="pf-c-page__header-tools"> | ||||
|                                       <div class="pf-c-page__header-tools-group"> | ||||
|                                           <ak-action-button | ||||
|                                               class="pf-m-warning pf-m-small" | ||||
|                                               .apiRequest=${() => { | ||||
|                                                   return new CoreApi(DEFAULT_CONFIG) | ||||
|                                                       .coreUsersImpersonateEndRetrieve() | ||||
|                                                       .then(() => { | ||||
|                                                           window.location.reload(); | ||||
|                                                       }); | ||||
|                                               }} | ||||
|                                           > | ||||
|                                               ${msg("Stop impersonation")} | ||||
|                                           </ak-action-button> | ||||
|                                       </div> | ||||
|                                   </div>` | ||||
|                             : html``} | ||||
|                         ${this.renderImpersonation()} | ||||
|                         <div class="pf-c-page__header-tools-group"> | ||||
|                             <div | ||||
|                                 class="pf-c-page__header-tools-item pf-m-hidden pf-m-visible-on-md" | ||||
|                             > | ||||
|                                 ${userDisplay} | ||||
|                                 ${this.userDisplayName} | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <img | ||||
| @ -368,4 +273,202 @@ export class UserInterface extends EnterpriseAwareInterface { | ||||
|             </div> | ||||
|         </ak-locale-context>`; | ||||
|     } | ||||
|  | ||||
|     renderApiDrawerTrigger() { | ||||
|         if (!this.uiConfig.enabledFeatures.apiDrawer) { | ||||
|             return nothing; | ||||
|         } | ||||
|  | ||||
|         const onClick = (ev: Event) => { | ||||
|             ev.stopPropagation(); | ||||
|             this.dispatchEvent( | ||||
|                 new Event(EVENT_API_DRAWER_TOGGLE, { bubbles: true, composed: true }), | ||||
|             ); | ||||
|         }; | ||||
|  | ||||
|         return html`<div class="pf-c-page__header-tools-item pf-m-hidden pf-m-visible-on-lg"> | ||||
|             <button class="pf-c-button pf-m-plain" type="button" @click=${onClick}> | ||||
|                 <pf-tooltip position="top" content=${msg("Open API drawer")}> | ||||
|                     <i class="fas fa-code" aria-hidden="true"></i> | ||||
|                 </pf-tooltip> | ||||
|             </button> | ||||
|         </div>`; | ||||
|     } | ||||
|  | ||||
|     renderNotificationDrawerTrigger() { | ||||
|         if (!this.uiConfig.enabledFeatures.notificationDrawer) { | ||||
|             return nothing; | ||||
|         } | ||||
|  | ||||
|         const onClick = (ev: Event) => { | ||||
|             ev.stopPropagation(); | ||||
|             this.dispatchEvent( | ||||
|                 new Event(EVENT_NOTIFICATION_DRAWER_TOGGLE, { bubbles: true, composed: true }), | ||||
|             ); | ||||
|         }; | ||||
|  | ||||
|         return html`<div class="pf-c-page__header-tools-item pf-m-hidden pf-m-visible-on-lg"> | ||||
|             <button | ||||
|                 class="pf-c-button pf-m-plain" | ||||
|                 type="button" | ||||
|                 aria-label="${msg("Unread notifications")}" | ||||
|                 @click=${onClick} | ||||
|             > | ||||
|                 <span | ||||
|                     class="pf-c-notification-badge ${this.notificationsCount > 0 | ||||
|                         ? "pf-m-unread" | ||||
|                         : ""}" | ||||
|                 > | ||||
|                     <pf-tooltip position="top" content=${msg("Open Notification drawer")}> | ||||
|                         <i class="fas fa-bell" aria-hidden="true"></i> | ||||
|                     </pf-tooltip> | ||||
|                     <span class="pf-c-notification-badge__count">${this.notificationsCount}</span> | ||||
|                 </span> | ||||
|             </button> | ||||
|         </div> `; | ||||
|     } | ||||
|  | ||||
|     renderSettings() { | ||||
|         if (!this.uiConfig.enabledFeatures.settings) { | ||||
|             return nothing; | ||||
|         } | ||||
|  | ||||
|         return html` <div class="pf-c-page__header-tools-item"> | ||||
|             <a class="pf-c-button pf-m-plain" type="button" href="#/settings"> | ||||
|                 <pf-tooltip position="top" content=${msg("Settings")}> | ||||
|                     <i class="fas fa-cog" aria-hidden="true"></i> | ||||
|                 </pf-tooltip> | ||||
|             </a> | ||||
|         </div>`; | ||||
|     } | ||||
|  | ||||
|     renderAdminInterfaceLink() { | ||||
|         if (!this.canAccessAdmin) { | ||||
|             return nothing; | ||||
|         } | ||||
|  | ||||
|         return html`<a | ||||
|             class="pf-c-button pf-m-secondary pf-m-small pf-u-display-none pf-u-display-block-on-md" | ||||
|             href="/if/admin/" | ||||
|         > | ||||
|             ${msg("Admin interface")} | ||||
|         </a>`; | ||||
|     } | ||||
|  | ||||
|     renderImpersonation() { | ||||
|         if (!this.me.original) { | ||||
|             return nothing; | ||||
|         } | ||||
|  | ||||
|         const onClick = () => { | ||||
|             return new CoreApi(DEFAULT_CONFIG).coreUsersImpersonateEndRetrieve().then(() => { | ||||
|                 window.location.reload(); | ||||
|             }); | ||||
|         }; | ||||
|  | ||||
|         return html`  | ||||
|             <div class="pf-c-page__header-tools"> | ||||
|                 <div class="pf-c-page__header-tools-group"> | ||||
|                     <ak-action-button class="pf-m-warning pf-m-small" .apiRequest=${onClick}> | ||||
|                         ${msg("Stop impersonation")} | ||||
|                     </ak-action-button> | ||||
|                 </div> | ||||
|             </div>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
| //  ___         _ | ||||
| // | _ )_  _ __(_)_ _  ___ ______ | ||||
| // | _ \ || (_-< | ' \/ -_|_-<_-< | ||||
| // |___/\_,_/__/_|_||_\___/__/__/ | ||||
| // | ||||
| // | ||||
| @customElement("ak-interface-user") | ||||
| export class UserInterface extends EnterpriseAwareInterface { | ||||
|     @property({ type: Boolean }) | ||||
|     notificationDrawerOpen = getURLParam("notificationDrawerOpen", false); | ||||
|  | ||||
|     @state() | ||||
|     apiDrawerOpen = getURLParam("apiDrawerOpen", false); | ||||
|  | ||||
|     ws: WebsocketClient; | ||||
|  | ||||
|     @state() | ||||
|     notificationsCount = 0; | ||||
|  | ||||
|     @state() | ||||
|     me?: SessionUser; | ||||
|  | ||||
|     constructor() { | ||||
|         super(); | ||||
|         this.ws = new WebsocketClient(); | ||||
|         this.fetchConfigurationDetails(); | ||||
|         configureSentry(true); | ||||
|         this.toggleNotificationDrawer = this.toggleNotificationDrawer.bind(this); | ||||
|         this.toggleApiDrawer = this.toggleApiDrawer.bind(this); | ||||
|         this.fetchConfigurationDetails = this.fetchConfigurationDetails.bind(this); | ||||
|     } | ||||
|  | ||||
|     connectedCallback() { | ||||
|         super.connectedCallback(); | ||||
|         window.addEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, this.toggleNotificationDrawer); | ||||
|         window.addEventListener(EVENT_API_DRAWER_TOGGLE, this.toggleApiDrawer); | ||||
|         window.addEventListener(EVENT_WS_MESSAGE, this.fetchConfigurationDetails); | ||||
|     } | ||||
|  | ||||
|     disconnectedCallback() { | ||||
|         window.removeEventListener(EVENT_NOTIFICATION_DRAWER_TOGGLE, this.toggleNotificationDrawer); | ||||
|         window.removeEventListener(EVENT_API_DRAWER_TOGGLE, this.toggleApiDrawer); | ||||
|         window.removeEventListener(EVENT_WS_MESSAGE, this.fetchConfigurationDetails); | ||||
|         super.disconnectedCallback(); | ||||
|     } | ||||
|  | ||||
|     toggleNotificationDrawer() { | ||||
|         this.notificationDrawerOpen = !this.notificationDrawerOpen; | ||||
|         updateURLParams({ | ||||
|             notificationDrawerOpen: this.notificationDrawerOpen, | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     toggleApiDrawer() { | ||||
|         this.apiDrawerOpen = !this.apiDrawerOpen; | ||||
|         updateURLParams({ | ||||
|             apiDrawerOpen: this.apiDrawerOpen, | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     fetchConfigurationDetails() { | ||||
|         me().then((me: SessionUser) => { | ||||
|             this.me = me; | ||||
|             new EventsApi(DEFAULT_CONFIG) | ||||
|                 .eventsNotificationsList({ | ||||
|                     seen: false, | ||||
|                     ordering: "-created", | ||||
|                     pageSize: 1, | ||||
|                     user: this.me.user.pk, | ||||
|                 }) | ||||
|                 .then((notifications) => { | ||||
|                     this.notificationsCount = notifications.pagination.count; | ||||
|                 }); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     get isFullyConfigured() { | ||||
|         return !!(this.uiConfig && this.me); | ||||
|     } | ||||
|  | ||||
|     render() { | ||||
|         if (!this.isFullyConfigured) { | ||||
|             return nothing; | ||||
|         } | ||||
|  | ||||
|         return html`<ak-interface-user-presentation | ||||
|             .uiConfig=${this.uiConfig} | ||||
|             .me=${this.me} | ||||
|             .brand=${this.brand ?? DefaultBrand} | ||||
|             ?notificationDrawerOpen=${this.notificationDrawerOpen} | ||||
|             ?apiDrawerOpen=${this.apiDrawerOpen} | ||||
|             notificationsCount=${this.notificationsCount} | ||||
|         ></ak-interface-user-presentation>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Ken Sternberg
					Ken Sternberg