enterprise: initial enterprise (#5721)
* initial Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add user type Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add external users Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add ui, add more logic, add public JWT validation key Signed-off-by: Jens Langhammer <jens@goauthentik.io> * revert to not use install_id as session jwt signing key Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix more Signed-off-by: Jens Langhammer <jens@goauthentik.io> * switch to PKI Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add more licensing stuff Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add install ID to form Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix bugs Signed-off-by: Jens Langhammer <jens@goauthentik.io> * start adding tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fixes Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use x5c correctly Signed-off-by: Jens Langhammer <jens@goauthentik.io> * license checks Signed-off-by: Jens Langhammer <jens@goauthentik.io> * use production CA Signed-off-by: Jens Langhammer <jens@goauthentik.io> * more Signed-off-by: Jens Langhammer <jens@goauthentik.io> * more UI stuff Signed-off-by: Jens Langhammer <jens@goauthentik.io> * rename to summary Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update locale, improve ui Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add direct button Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update link Signed-off-by: Jens Langhammer <jens@goauthentik.io> * format and such Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove old attributes from ldap Signed-off-by: Jens Langhammer <jens@goauthentik.io> * remove is_enterprise_licensed Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix admin interface styling issue Signed-off-by: Jens Langhammer <jens@goauthentik.io> * Update authentik/core/models.py Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com> Signed-off-by: Jens L. <jens@beryju.org> * fix default case Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io> Signed-off-by: Jens L. <jens@beryju.org> Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
This commit is contained in:
222
web/src/admin/enterprise/EnterpriseLicenseListPage.ts
Normal file
222
web/src/admin/enterprise/EnterpriseLicenseListPage.ts
Normal file
@ -0,0 +1,222 @@
|
||||
import "@goauthentik/admin/enterprise/EnterpriseLicenseForm";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { PFColor } from "@goauthentik/elements/Label";
|
||||
import "@goauthentik/elements/Spinner";
|
||||
import "@goauthentik/elements/buttons/SpinnerButton";
|
||||
import "@goauthentik/elements/cards/AggregateCard";
|
||||
import "@goauthentik/elements/forms/DeleteBulkForm";
|
||||
import "@goauthentik/elements/forms/ModalForm";
|
||||
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
|
||||
import { TableColumn } from "@goauthentik/elements/table/Table";
|
||||
import { TablePage } from "@goauthentik/elements/table/TablePage";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { CSSResult, TemplateResult, css, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
|
||||
import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
|
||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||
import PFCard from "@patternfly/patternfly/components/Card/card.css";
|
||||
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
|
||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
|
||||
|
||||
import { EnterpriseApi, License, LicenseForecast, LicenseSummary } from "@goauthentik/api";
|
||||
|
||||
@customElement("ak-enterprise-license-list")
|
||||
export class EnterpriseLicenseListPage extends TablePage<License> {
|
||||
checkbox = true;
|
||||
|
||||
searchEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
pageTitle(): string {
|
||||
return msg("Licenses");
|
||||
}
|
||||
pageDescription(): string {
|
||||
return msg("Manage enterprise licenses");
|
||||
}
|
||||
pageIcon(): string {
|
||||
return "pf-icon pf-icon-key";
|
||||
}
|
||||
|
||||
@property()
|
||||
order = "name";
|
||||
|
||||
@state()
|
||||
forecast?: LicenseForecast;
|
||||
|
||||
@state()
|
||||
summary?: LicenseSummary;
|
||||
|
||||
@state()
|
||||
installID?: string;
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return super.styles.concat(
|
||||
PFDescriptionList,
|
||||
PFGrid,
|
||||
PFBanner,
|
||||
PFFormControl,
|
||||
PFButton,
|
||||
PFCard,
|
||||
css`
|
||||
.pf-m-no-padding-bottom {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
`,
|
||||
);
|
||||
}
|
||||
|
||||
async apiEndpoint(page: number): Promise<PaginatedResponse<License>> {
|
||||
this.forecast = await new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseForecastRetrieve();
|
||||
this.summary = await new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseSummaryRetrieve();
|
||||
this.installID = (
|
||||
await new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseGetInstallIdRetrieve()
|
||||
).installId;
|
||||
return new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseList({
|
||||
ordering: this.order,
|
||||
page: page,
|
||||
pageSize: (await uiConfig()).pagination.perPage,
|
||||
search: this.search || "",
|
||||
});
|
||||
}
|
||||
|
||||
columns(): TableColumn[] {
|
||||
return [
|
||||
new TableColumn(msg("Name"), "name"),
|
||||
new TableColumn(msg("Users")),
|
||||
new TableColumn(msg("Expiry date")),
|
||||
new TableColumn(msg("Actions")),
|
||||
];
|
||||
}
|
||||
|
||||
renderToolbarSelected(): TemplateResult {
|
||||
const disabled = this.selectedElements.length < 1;
|
||||
return html`<ak-forms-delete-bulk
|
||||
objectLabel=${msg("License(s)")}
|
||||
.objects=${this.selectedElements}
|
||||
.metadata=${(item: License) => {
|
||||
return [
|
||||
{ key: msg("Name"), value: item.name },
|
||||
{ key: msg("Expiry"), value: item.expiry?.toLocaleString() },
|
||||
];
|
||||
}}
|
||||
.usedBy=${(item: License) => {
|
||||
return new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseUsedByList({
|
||||
licenseUuid: item.licenseUuid,
|
||||
});
|
||||
}}
|
||||
.delete=${(item: License) => {
|
||||
return new EnterpriseApi(DEFAULT_CONFIG).enterpriseLicenseDestroy({
|
||||
licenseUuid: item.licenseUuid,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
|
||||
${msg("Delete")}
|
||||
</button>
|
||||
</ak-forms-delete-bulk>`;
|
||||
}
|
||||
|
||||
renderSectionBefore(): TemplateResult {
|
||||
return html`
|
||||
<div class="pf-c-banner pf-m-info">
|
||||
${msg("Enterprise is in preview.")}
|
||||
<a href="mailto:hello@goauthentik.io">${msg("Send us feedback!")}</a>
|
||||
</div>
|
||||
<section class="pf-c-page__main-section pf-m-no-padding-bottom">
|
||||
<div
|
||||
class="pf-l-grid pf-m-gutter pf-m-all-6-col-on-sm pf-m-all-4-col-on-md pf-m-all-3-col-on-lg pf-m-all-3-col-on-xl"
|
||||
>
|
||||
<div class="pf-l-grid__item pf-c-card">
|
||||
<div class="pf-c-card__title">${msg("How to get a license")}</div>
|
||||
<div class="pf-c-card__body">
|
||||
${this.installID
|
||||
? html` <a
|
||||
target="_blank"
|
||||
href=${`https://customers.goauthentik.io/from_authentik/purchase/?install_id=${this.installID}`}
|
||||
class="pf-c-button pf-m-primary pf-m-block"
|
||||
>${msg("Go to the customer portal")}</a
|
||||
>`
|
||||
: html`<ak-spinner></ak-spinner>`}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-l-grid__item pf-c-card">
|
||||
<ak-aggregate-card
|
||||
icon="pf-icon pf-icon-user"
|
||||
header=${msg("Forecasted default users")}
|
||||
subtext=${msg("Estimated user count one year from now")}
|
||||
>
|
||||
${this.forecast?.users}
|
||||
</ak-aggregate-card>
|
||||
</div>
|
||||
<div class="pf-l-grid__item pf-c-card">
|
||||
<ak-aggregate-card
|
||||
icon="pf-icon pf-icon-user"
|
||||
header=${msg("Forecasted external users")}
|
||||
subtext=${msg("Estimated external user count one year from now")}
|
||||
>
|
||||
${this.forecast?.externalUsers}
|
||||
</ak-aggregate-card>
|
||||
</div>
|
||||
<div class="pf-l-grid__item pf-c-card">
|
||||
<ak-aggregate-card
|
||||
icon="pf-icon pf-icon-user"
|
||||
header=${msg("Expiry")}
|
||||
subtext=${msg("Cumulative license expiry")}
|
||||
>
|
||||
${this.summary?.hasLicense
|
||||
? this.summary.latestValid.toLocaleString()
|
||||
: "-"}
|
||||
</ak-aggregate-card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
row(item: License): TemplateResult[] {
|
||||
let color = PFColor.Green;
|
||||
if (item.expiry) {
|
||||
const now = new Date();
|
||||
const inAMonth = new Date();
|
||||
inAMonth.setDate(inAMonth.getDate() + 30);
|
||||
if (item.expiry <= inAMonth) {
|
||||
color = PFColor.Orange;
|
||||
}
|
||||
if (item.expiry <= now) {
|
||||
color = PFColor.Red;
|
||||
}
|
||||
}
|
||||
return [
|
||||
html`<div>${item.name}</div>`,
|
||||
html`<div>
|
||||
<small>0 / ${item.users}</small>
|
||||
<small>0 / ${item.externalUsers}</small>
|
||||
</div>`,
|
||||
html`<ak-label color=${color}> ${item.expiry?.toLocaleString()} </ak-label>`,
|
||||
html`<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Update")} </span>
|
||||
<span slot="header"> ${msg("Update License")} </span>
|
||||
<ak-enterprise-license-form slot="form" .instancePk=${item.licenseUuid}>
|
||||
</ak-enterprise-license-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-plain">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</ak-forms-modal>`,
|
||||
];
|
||||
}
|
||||
|
||||
renderObjectCreate(): TemplateResult {
|
||||
return html`
|
||||
<ak-forms-modal>
|
||||
<span slot="submit"> ${msg("Create")} </span>
|
||||
<span slot="header"> ${msg("Create License")} </span>
|
||||
<ak-enterprise-license-form slot="form"> </ak-enterprise-license-form>
|
||||
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
|
||||
</ak-forms-modal>
|
||||
`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user