enterprise: add more info to enterprise forecast (#6292)

* add more info to enterprise forecast

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix banner colour

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix some layout

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix layout for warning banner

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-07-18 23:24:44 +02:00 committed by GitHub
parent c1eef9278d
commit b6e8342466
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 71 deletions

View File

@ -64,6 +64,8 @@ class LicenseForecastSerializer(PassiveSerializer):
users = IntegerField(required=True) users = IntegerField(required=True)
external_users = IntegerField(required=True) external_users = IntegerField(required=True)
forecasted_users = IntegerField(required=True)
forecasted_external_users = IntegerField(required=True)
class LicenseViewSet(UsedByMixin, ModelViewSet): class LicenseViewSet(UsedByMixin, ModelViewSet):
@ -142,8 +144,10 @@ class LicenseViewSet(UsedByMixin, ModelViewSet):
forecast_for_months = 12 forecast_for_months = 12
response = LicenseForecastSerializer( response = LicenseForecastSerializer(
data={ data={
"users": users_in_last_month * forecast_for_months, "users": LicenseKey.get_default_user_count(),
"external_users": external_in_last_month * forecast_for_months, "external_users": LicenseKey.get_external_user_count(),
"forecasted_users": (users_in_last_month * forecast_for_months),
"forecasted_external_users": (external_in_last_month * forecast_for_months),
} }
) )
response.is_valid(raise_exception=True) response.is_valid(raise_exception=True)

View File

@ -31746,8 +31746,14 @@ components:
type: integer type: integer
external_users: external_users:
type: integer type: integer
forecasted_users:
type: integer
forecasted_external_users:
type: integer
required: required:
- external_users - external_users
- forecasted_external_users
- forecasted_users
- users - users
LicenseRequest: LicenseRequest:
type: object type: object

View File

@ -75,17 +75,7 @@ export class AdminInterface extends Interface {
.display-none { .display-none {
display: none; display: none;
} }
:host {
display: flex;
flex-direction: column;
height: 100%;
}
ak-locale-context {
display: flex;
flex-grow: 1;
}
.pf-c-page { .pf-c-page {
flex-grow: 1;
background-color: var(--pf-c-page--BackgroundColor) !important; background-color: var(--pf-c-page--BackgroundColor) !important;
} }
/* Global page background colour */ /* Global page background colour */
@ -130,8 +120,7 @@ export class AdminInterface extends Interface {
} }
render(): TemplateResult { render(): TemplateResult {
return html` <ak-locale-context return html` <ak-locale-context>
><ak-enterprise-status interface="admin"></ak-enterprise-status>
<div class="pf-c-page"> <div class="pf-c-page">
<ak-sidebar <ak-sidebar
class="pf-c-page__sidebar ${this.sidebarOpen class="pf-c-page__sidebar ${this.sidebarOpen

View File

@ -11,7 +11,7 @@ import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table"; import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage"; import { TablePage } from "@goauthentik/elements/table/TablePage";
import { msg } from "@lit/localize"; import { msg, str } from "@lit/localize";
import { CSSResult, TemplateResult, css, html } from "lit"; import { CSSResult, TemplateResult, css, html } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
@ -148,17 +148,23 @@ export class EnterpriseLicenseListPage extends TablePage<License> {
class="pf-l-grid__item" class="pf-l-grid__item"
icon="pf-icon pf-icon-user" icon="pf-icon pf-icon-user"
header=${msg("Forecast default users")} header=${msg("Forecast default users")}
subtext=${msg("Estimated user count one year from now")} subtext=${msg(
str`Estimated user count one year from now based on ${this.forecast?.users} current users and ${this.forecast?.forecastedUsers} forecasted users.`,
)}
> >
~&nbsp;${this.forecast?.users} ~&nbsp;${(this.forecast?.users || 0) +
(this.forecast?.forecastedUsers || 0)}
</ak-aggregate-card> </ak-aggregate-card>
<ak-aggregate-card <ak-aggregate-card
class="pf-l-grid__item" class="pf-l-grid__item"
icon="pf-icon pf-icon-user" icon="pf-icon pf-icon-user"
header=${msg("Forecast external users")} header=${msg("Forecast external users")}
subtext=${msg("Estimated external user count one year from now")} subtext=${msg(
str`Estimated user count one year from now based on ${this.forecast?.externalUsers} current external users and ${this.forecast?.forecastedExternalUsers} forecasted external users.`,
)}
> >
~&nbsp;${this.forecast?.externalUsers} ~&nbsp;${(this.forecast?.externalUsers || 0) +
(this.forecast?.forecastedExternalUsers || 0)}
</ak-aggregate-card> </ak-aggregate-card>
<ak-aggregate-card <ak-aggregate-card
class="pf-l-grid__item" class="pf-l-grid__item"

View File

@ -63,7 +63,7 @@ export class PageHeader extends AKElement {
PFPage, PFPage,
PFContent, PFContent,
css` css`
:host { .bar {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
min-height: 114px; min-height: 114px;
@ -126,55 +126,58 @@ export class PageHeader extends AKElement {
} }
render(): TemplateResult { render(): TemplateResult {
return html`<button return html` <ak-enterprise-status interface="admin"></ak-enterprise-status>
class="sidebar-trigger pf-c-button pf-m-plain" <div class="bar">
@click=${() => { <button
this.dispatchEvent( class="sidebar-trigger pf-c-button pf-m-plain"
new CustomEvent(EVENT_SIDEBAR_TOGGLE, { @click=${() => {
bubbles: true, this.dispatchEvent(
composed: true, new CustomEvent(EVENT_SIDEBAR_TOGGLE, {
}), bubbles: true,
); composed: true,
}} }),
> );
<i class="fas fa-bars"></i> }}
</button> >
<section class="pf-c-page__main-section pf-m-light"> <i class="fas fa-bars"></i>
<div class="pf-c-content"> </button>
<h1> <section class="pf-c-page__main-section pf-m-light">
${this.renderIcon()} <div class="pf-c-content">
<slot name="header"> ${this.header} </slot> <h1>
</h1> ${this.renderIcon()}
${this.description ? html`<p>${this.description}</p>` : html``} <slot name="header"> ${this.header} </slot>
</div> </h1>
</section> ${this.description ? html`<p>${this.description}</p>` : html``}
<button </div>
class="notification-trigger pf-c-button pf-m-plain" </section>
@click=${() => { <button
this.dispatchEvent( class="notification-trigger pf-c-button pf-m-plain"
new CustomEvent(EVENT_API_DRAWER_TOGGLE, { @click=${() => {
bubbles: true, this.dispatchEvent(
composed: true, new CustomEvent(EVENT_API_DRAWER_TOGGLE, {
}), bubbles: true,
); composed: true,
}} }),
> );
<i class="fas fa-code"></i> }}
</button> >
<button <i class="fas fa-code"></i>
class="notification-trigger pf-c-button pf-m-plain ${this.hasNotifications </button>
? "has-notifications" <button
: ""}" class="notification-trigger pf-c-button pf-m-plain ${this.hasNotifications
@click=${() => { ? "has-notifications"
this.dispatchEvent( : ""}"
new CustomEvent(EVENT_NOTIFICATION_DRAWER_TOGGLE, { @click=${() => {
bubbles: true, this.dispatchEvent(
composed: true, new CustomEvent(EVENT_NOTIFICATION_DRAWER_TOGGLE, {
}), bubbles: true,
); composed: true,
}} }),
> );
<i class="fas fa-bell"></i> }}
</button> `; >
<i class="fas fa-bell"></i>
</button>
</div>`;
} }
} }

View File

@ -28,7 +28,7 @@ export class EnterpriseStatusBanner extends AKElement {
} }
renderBanner(): TemplateResult { renderBanner(): TemplateResult {
return html`<div class="pf-c-banner ${this.summary?.readOnly ? "pf-m-red" : "pf-m-orange"}"> return html`<div class="pf-c-banner ${this.summary?.readOnly ? "pf-m-red" : "pf-m-gold"}">
${msg("Warning: The current user count has exceeded the configured licenses.")} ${msg("Warning: The current user count has exceeded the configured licenses.")}
<a href="/if/admin/#/enterprise/licenses"> ${msg("Click here for more info.")} </a> <a href="/if/admin/#/enterprise/licenses"> ${msg("Click here for more info.")} </a>
</div>`; </div>`;

View File

@ -94,6 +94,12 @@ export class UserInterface extends Interface {
width: 100vw; width: 100vw;
position: absolute; position: absolute;
z-index: -1; z-index: -1;
top: 0;
left: 0;
}
ak-locale-context {
display: flex;
flex-direction: column;
} }
`, `,
]; ];