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:
parent
c1eef9278d
commit
b6e8342466
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.`,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
~ ${this.forecast?.users}
|
~ ${(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.`,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
~ ${this.forecast?.externalUsers}
|
~ ${(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"
|
||||||
|
|
|
@ -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>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>`;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|
Reference in New Issue