web/admin: rework event info page to show all event infos

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer 2023-02-05 00:23:32 +01:00
parent 52a0b19f7e
commit de389e2385
No known key found for this signature in database
3 changed files with 290 additions and 149 deletions

View File

@ -13,6 +13,7 @@ import { customElement, property } from "lit/decorators.js";
import { until } from "lit/directives/until.js"; import { until } from "lit/directives/until.js";
import PFButton from "@patternfly/patternfly/components/Button/button.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 PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
import PFList from "@patternfly/patternfly/components/List/list.css"; import PFList from "@patternfly/patternfly/components/List/list.css";
import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css"; import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css";
@ -30,6 +31,7 @@ export class EventInfo extends AKElement {
PFBase, PFBase,
PFButton, PFButton,
PFFlex, PFFlex,
PFCard,
PFList, PFList,
PFDescriptionList, PFDescriptionList,
css` css`
@ -56,40 +58,42 @@ export class EventInfo extends AKElement {
if (context === null) { if (context === null) {
return html`<span>-</span>`; return html`<span>-</span>`;
} }
return html`<dl class="pf-c-description-list pf-m-horizontal"> return html`<div class="pf-c-card__body">
<div class="pf-c-description-list__group"> <dl class="pf-c-description-list pf-m-horizontal">
<dt class="pf-c-description-list__term"> <div class="pf-c-description-list__group">
<span class="pf-c-description-list__text">${t`UID`}</span> <dt class="pf-c-description-list__term">
</dt> <span class="pf-c-description-list__text">${t`UID`}</span>
<dd class="pf-c-description-list__description"> </dt>
<div class="pf-c-description-list__text">${context.pk}</div> <dd class="pf-c-description-list__description">
</dd> <div class="pf-c-description-list__text">${context.pk}</div>
</div> </dd>
<div class="pf-c-description-list__group"> </div>
<dt class="pf-c-description-list__term"> <div class="pf-c-description-list__group">
<span class="pf-c-description-list__text">${t`Name`}</span> <dt class="pf-c-description-list__term">
</dt> <span class="pf-c-description-list__text">${t`Name`}</span>
<dd class="pf-c-description-list__description"> </dt>
<div class="pf-c-description-list__text">${context.name}</div> <dd class="pf-c-description-list__description">
</dd> <div class="pf-c-description-list__text">${context.name}</div>
</div> </dd>
<div class="pf-c-description-list__group"> </div>
<dt class="pf-c-description-list__term"> <div class="pf-c-description-list__group">
<span class="pf-c-description-list__text">${t`App`}</span> <dt class="pf-c-description-list__term">
</dt> <span class="pf-c-description-list__text">${t`App`}</span>
<dd class="pf-c-description-list__description"> </dt>
<div class="pf-c-description-list__text">${context.app}</div> <dd class="pf-c-description-list__description">
</dd> <div class="pf-c-description-list__text">${context.app}</div>
</div> </dd>
<div class="pf-c-description-list__group"> </div>
<dt class="pf-c-description-list__term"> <div class="pf-c-description-list__group">
<span class="pf-c-description-list__text">${t`Model Name`}</span> <dt class="pf-c-description-list__term">
</dt> <span class="pf-c-description-list__text">${t`Model Name`}</span>
<dd class="pf-c-description-list__description"> </dt>
<div class="pf-c-description-list__text">${context.model_name}</div> <dd class="pf-c-description-list__description">
</dd> <div class="pf-c-description-list__text">${context.model_name}</div>
</div> </dd>
</dl>`; </div>
</dl>
</div>`;
} }
getEmailInfo(context: EventContext): TemplateResult { getEmailInfo(context: EventContext): TemplateResult {
@ -139,12 +143,16 @@ export class EventInfo extends AKElement {
defaultResponse(): TemplateResult { defaultResponse(): TemplateResult {
return html`<div class="pf-l-flex"> return html`<div class="pf-l-flex">
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Context`}</h3> <div class="pf-c-card__title">${t`Context`}</div>
<code>${JSON.stringify(this.event?.context, null, 4)}</code> <div class="pf-c-card__body">
<code>${JSON.stringify(this.event?.context, null, 4)}</code>
</div>
</div> </div>
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`User`}</h3> <div class="pf-c-card__title">${t`User`}</div>
<code>${JSON.stringify(this.event?.user, null, 4)}</code> <div class="pf-c-card__body">
<code>${JSON.stringify(this.event?.user, null, 4)}</code>
</div>
</div> </div>
</div>`; </div>`;
} }
@ -204,45 +212,51 @@ new?labels=bug,from_authentik&title=${encodeURIComponent(title)}
case EventActions.ModelUpdated: case EventActions.ModelUpdated:
case EventActions.ModelDeleted: case EventActions.ModelDeleted:
return html` return html`
<h3>${t`Affected model:`}</h3> <div class="pf-c-card__title">${t`Affected model:`}</div>
${this.getModelInfo(this.event.context?.model as EventModel)} <div class="pf-c-card__body">
${this.getModelInfo(this.event.context?.model as EventModel)}
</div>
`; `;
case EventActions.AuthorizeApplication: case EventActions.AuthorizeApplication:
return html`<div class="pf-l-flex"> return html`<div class="pf-l-flex">
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Authorized application:`}</h3> <div class="pf-c-card__title">${t`Authorized application:`}</div>
${this.getModelInfo( <div class="pf-c-card__body">
this.event.context.authorized_application as EventModel, ${this.getModelInfo(
)} this.event.context.authorized_application as EventModel,
)}
</div>
</div> </div>
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Using flow`}</h3> <div class="pf-c-card__title">${t`Using flow`}</div>
<span <div class="pf-c-card__body">
>${until( <span
new FlowsApi(DEFAULT_CONFIG) >${until(
.flowsInstancesList({ new FlowsApi(DEFAULT_CONFIG)
flowUuid: this.event.context.flow as string, .flowsInstancesList({
}) flowUuid: this.event.context.flow as string,
.then((resp) => { })
return html`<a .then((resp) => {
href="#/flow/flows/${resp.results[0].slug}" return html`<a
>${resp.results[0].name}</a href="#/flow/flows/${resp.results[0].slug}"
>`; >${resp.results[0].name}</a
}), >`;
html`<ak-spinner size=${PFSize.Medium}></ak-spinner>`, }),
)} html`<ak-spinner size=${PFSize.Medium}></ak-spinner>`,
</span> )}
</span>
</div>
</div> </div>
</div> </div>
<ak-expand>${this.defaultResponse()}</ak-expand>`; <ak-expand>${this.defaultResponse()}</ak-expand>`;
case EventActions.EmailSent: case EventActions.EmailSent:
return html`<h3>${t`Email info:`}</h3> return html`<div class="pf-c-card__title">${t`Email info:`}</div>
${this.getEmailInfo(this.event.context)} <div class="pf-c-card__body">${this.getEmailInfo(this.event.context)}</div>
<ak-expand> <ak-expand>
<iframe srcdoc=${this.event.context.body}></iframe> <iframe srcdoc=${this.event.context.body}></iframe>
</ak-expand>`; </ak-expand>`;
case EventActions.SecretView: case EventActions.SecretView:
return html` <h3>${t`Secret:`}</h3> return html` <div class="pf-c-card__title">${t`Secret:`}</div>
${this.getModelInfo(this.event.context.secret as EventModel)}`; ${this.getModelInfo(this.event.context.secret as EventModel)}`;
case EventActions.SystemException: case EventActions.SystemException:
return html` <a return html` <a
@ -254,118 +268,134 @@ new?labels=bug,from_authentik&title=${encodeURIComponent(title)}
</a> </a>
<div class="pf-l-flex"> <div class="pf-l-flex">
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Exception`}</h3> <div class="pf-c-card__title">${t`Exception`}</div>
<pre>${this.event.context.message}</pre> <div class="pf-c-card__body">
<pre>${this.event.context.message}</pre>
</div>
</div> </div>
</div> </div>
<ak-expand>${this.defaultResponse()}</ak-expand>`; <ak-expand>${this.defaultResponse()}</ak-expand>`;
case EventActions.PropertyMappingException: case EventActions.PropertyMappingException:
return html`<div class="pf-l-flex"> return html`<div class="pf-l-flex">
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Exception`}</h3> <div class="pf-c-card__title">${t`Exception`}</div>
<pre>${this.event.context.message || this.event.context.error}</pre> <div class="pf-c-card__body">
<pre>${this.event.context.message || this.event.context.error}</pre>
</div>
</div> </div>
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Expression`}</h3> <div class="pf-c-card__title">${t`Expression`}</div>
<code>${this.event.context.expression}</code> <div class="pf-c-card__body">
<code>${this.event.context.expression}</code>
</div>
</div> </div>
</div> </div>
<ak-expand>${this.defaultResponse()}</ak-expand>`; <ak-expand>${this.defaultResponse()}</ak-expand>`;
case EventActions.PolicyException: case EventActions.PolicyException:
return html`<div class="pf-l-flex"> return html`<div class="pf-l-flex">
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Binding`}</h3> <div class="pf-c-card__title">${t`Binding`}</div>
${this.getModelInfo(this.event.context.binding as EventModel)} ${this.getModelInfo(this.event.context.binding as EventModel)}
</div> </div>
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Request`}</h3> <div class="pf-c-card__title">${t`Request`}</div>
<ul class="pf-c-list"> <div class="pf-c-card__body">
<li> <ul class="pf-c-list">
${t`Object`}: <li>
${this.getModelInfo( ${t`Object`}:
(this.event.context.request as EventContext) ${this.getModelInfo(
.obj as EventModel, (this.event.context.request as EventContext)
)} .obj as EventModel,
</li> )}
<li> </li>
<span <li>
>${t`Context`}: <span
<code >${t`Context`}:
>${JSON.stringify( <code
(this.event.context.request as EventContext) >${JSON.stringify(
.context, (this.event.context.request as EventContext)
null, .context,
4, null,
)}</code 4,
></span )}</code
> ></span
</li> >
</ul> </li>
</ul>
</div>
</div> </div>
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Exception`}</h3> <div class="pf-c-card__title">${t`Exception`}</div>
<code>${this.event.context.message || this.event.context.error}</code> <div class="pf-c-card__body">
<code
>${this.event.context.message || this.event.context.error}</code
>
</div>
</div> </div>
</div> </div>
<ak-expand>${this.defaultResponse()}</ak-expand>`; <ak-expand>${this.defaultResponse()}</ak-expand>`;
case EventActions.PolicyExecution: case EventActions.PolicyExecution:
return html`<div class="pf-l-flex"> return html`<div class="pf-l-flex">
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Binding`}</h3> <div class="pf-c-card__title">${t`Binding`}</div>
${this.getModelInfo(this.event.context.binding as EventModel)} ${this.getModelInfo(this.event.context.binding as EventModel)}
</div> </div>
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Request`}</h3> <div class="pf-c-card__title">${t`Request`}</div>
<ul class="pf-c-list"> <div class="pf-c-card__body">
<li> <ul class="pf-c-list">
${t`Object`}: <li>
${this.getModelInfo( ${t`Object`}:
(this.event.context.request as EventContext) ${this.getModelInfo(
.obj as EventModel, (this.event.context.request as EventContext)
)} .obj as EventModel,
</li> )}
<li> </li>
<span <li>
>${t`Context`}: <span
<code >${t`Context`}:
>${JSON.stringify( <code
(this.event.context.request as EventContext) >${JSON.stringify(
.context, (this.event.context.request as EventContext)
null, .context,
4, null,
)}</code 4,
></span )}</code
> ></span
</li> >
</ul> </li>
</ul>
</div>
</div> </div>
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Result`}</h3> <div class="pf-c-card__title">${t`Result`}</div>
<ul class="pf-c-list"> <div class="pf-c-card__body">
<li> <ul class="pf-c-list">
${t`Passing`}: <li>
${(this.event.context.result as EventContext).passing} ${t`Passing`}:
</li> ${(this.event.context.result as EventContext).passing}
<li> </li>
${t`Messages`}: <li>
<ul class="pf-c-list"> ${t`Messages`}:
${( <ul class="pf-c-list">
(this.event.context.result as EventContext) ${(
.messages as string[] (this.event.context.result as EventContext)
).map((msg) => { .messages as string[]
return html`<li>${msg}</li>`; ).map((msg) => {
})} return html`<li>${msg}</li>`;
</ul> })}
</li> </ul>
</ul> </li>
</ul>
</div>
</div> </div>
</div> </div>
<ak-expand>${this.defaultResponse()}</ak-expand>`; <ak-expand>${this.defaultResponse()}</ak-expand>`;
case EventActions.ConfigurationError: case EventActions.ConfigurationError:
return html`<h3>${this.event.context.message}</h3> return html`<div class="pf-c-card__title">${this.event.context.message}</div>
<ak-expand>${this.defaultResponse()}</ak-expand>`; <ak-expand>${this.defaultResponse()}</ak-expand>`;
case EventActions.UpdateAvailable: case EventActions.UpdateAvailable:
return html`<h3>${t`New version available!`}</h3> return html`<div class="pf-c-card__title">${t`New version available!`}</div>
<a <a
target="_blank" target="_blank"
href="https://github.com/goauthentik/authentik/releases/tag/version%2F${this href="https://github.com/goauthentik/authentik/releases/tag/version%2F${this
@ -379,14 +409,16 @@ new?labels=bug,from_authentik&title=${encodeURIComponent(title)}
if ("using_source" in this.event.context) { if ("using_source" in this.event.context) {
return html`<div class="pf-l-flex"> return html`<div class="pf-l-flex">
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Using source`}</h3> <div class="pf-c-card__title">${t`Using source`}</div>
${this.getModelInfo(this.event.context.using_source as EventModel)} ${this.getModelInfo(this.event.context.using_source as EventModel)}
</div> </div>
</div>`; </div>`;
} }
return this.defaultResponse(); return this.defaultResponse();
case EventActions.LoginFailed: case EventActions.LoginFailed:
return html` <h3>${t`Attempted to log in as ${this.event.context.username}`}</h3> return html` <div class="pf-c-card__title">
${t`Attempted to log in as ${this.event.context.username}`}
</div>
<ak-expand>${this.defaultResponse()}</ak-expand>`; <ak-expand>${this.defaultResponse()}</ak-expand>`;
case EventActions.Logout: case EventActions.Logout:
if (Object.keys(this.event.context).length === 0) { if (Object.keys(this.event.context).length === 0) {
@ -396,8 +428,10 @@ new?labels=bug,from_authentik&title=${encodeURIComponent(title)}
case EventActions.SystemTaskException: case EventActions.SystemTaskException:
return html`<div class="pf-l-flex"> return html`<div class="pf-l-flex">
<div class="pf-l-flex__item"> <div class="pf-l-flex__item">
<h3>${t`Exception`}</h3> <div class="pf-c-card__title">${t`Exception`}</div>
<pre>${this.event.context.message}</pre> <div class="pf-c-card__body">
<pre>${this.event.context.message}</pre>
</div>
</div> </div>
</div>`; </div>`;
default: default:

View File

@ -1,8 +1,10 @@
import "@goauthentik/admin/events/EventInfo"; import "@goauthentik/admin/events/EventInfo";
import { ActionToLabel } from "@goauthentik/admin/events/utils";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { EventWithContext } from "@goauthentik/common/events"; import { EventWithContext } from "@goauthentik/common/events";
import { AKElement } from "@goauthentik/elements/Base"; import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/PageHeader"; import "@goauthentik/elements/PageHeader";
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
@ -12,7 +14,9 @@ import { customElement, property } from "lit/decorators.js";
import AKGlobal from "@goauthentik/common/styles/authentik.css"; import AKGlobal from "@goauthentik/common/styles/authentik.css";
import PFCard from "@patternfly/patternfly/components/Card/card.css"; import PFCard from "@patternfly/patternfly/components/Card/card.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css"; import PFContent from "@patternfly/patternfly/components/Content/content.css";
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css"; import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { EventsApi } from "@goauthentik/api"; import { EventsApi } from "@goauthentik/api";
@ -34,19 +38,122 @@ export class EventInfoPage extends AKElement {
event!: EventWithContext; event!: EventWithContext;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFPage, PFContent, PFCard, AKGlobal]; return [PFBase, PFGrid, PFDescriptionList, PFPage, PFContent, PFCard, AKGlobal];
} }
render(): TemplateResult { render(): TemplateResult {
if (!this.event) {
return html`<ak-page-header icon="pf-icon pf-icon-catalog" header=${t`Loading`}>
</ak-page-header> `;
}
let geo: KeyUnknown | undefined = undefined;
if (Object.hasOwn(this.event.context, "geo")) {
geo = this.event.context.geo as KeyUnknown;
}
return html`<ak-page-header return html`<ak-page-header
icon="pf-icon pf-icon-catalog" icon="pf-icon pf-icon-catalog"
header=${t`Event ${this.event?.pk || ""}`} header=${t`Event ${this.event.pk}`}
> >
</ak-page-header> </ak-page-header>
<section class="pf-c-page__main-section pf-m-no-padding-mobile"> <section class="pf-c-page__main-section pf-m-no-padding-mobile">
<div class="pf-c-card"> <div class="pf-l-grid pf-m-gutter">
<div class="pf-c-card__title">${t`Event info`}</div> <div class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-4-col-on-xl">
<div class="pf-c-card__body"> <div class="pf-c-card__title">${t`Event info`}</div>
<div class="pf-c-card__body">
<dl class="pf-c-description-list pf-m-horizontal">
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${t`Action`}</span
>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${ActionToLabel(this.event.action)}
</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${t`App`}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${this.event.app}
</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${t`User`}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${this.event.user?.username
? html`<div>
<a
href="#/identity/users/${this.event
.user.pk}"
>${this.event.user?.username}</a
>
</div>
${this.event.user.on_behalf_of
? html`<small>
<a
href="#/identity/users/${this
.event.user.on_behalf_of
.pk}"
>${t`On behalf of ${this.event.user.on_behalf_of.username}`}</a
>
</small>`
: html``}`
: html`-`}
</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${t`Created`}</span
>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${this.event.created?.toLocaleString()}
</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${t`Client IP`}</span
>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<div>${this.event.clientIp || t`-`}</div>
${geo
? html`<small>${geo.city}, ${geo.country}</small> `
: html``}
</div>
</dd>
</div>
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${t`Tenant`}</span
>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${this.event.tenant?.name || t`-`}
</div>
</dd>
</div>
</dl>
</div>
</div>
<div class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-8-col-on-xl">
<ak-event-info .event=${this.event}></ak-event-info> <ak-event-info .event=${this.event}></ak-event-info>
</div> </div>
</div> </div>

View File

@ -76,7 +76,7 @@ export class EventListPage extends TablePage<Event> {
: html``}` : html``}`
: html`-`, : html`-`,
html`<span>${item.created?.toLocaleString()}</span>`, html`<span>${item.created?.toLocaleString()}</span>`,
html` <div>${item.clientIp || t`-`}</div> html`<div>${item.clientIp || t`-`}</div>
${geo ? html`<small>${geo.city}, ${geo.country}</small> ` : html``}`, ${geo ? html`<small>${geo.city}, ${geo.country}</small> ` : html``}`,
html`<span>${item.tenant?.name || t`-`}</span>`, html`<span>${item.tenant?.name || t`-`}</span>`,
html`<a href="#/events/log/${item.pk}"> html`<a href="#/events/log/${item.pk}">