Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EC-551] Update Event Logs Client Column #3572

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions apps/web/src/app/core/event.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,16 +464,14 @@ export class EventService {
private formatGroupId(ev: EventResponse) {
const shortId = this.getShortId(ev.groupId);
const a = this.makeAnchor(shortId);
a.setAttribute(
"href",
"#/organizations/" + ev.organizationId + "/manage/groups?search=" + shortId
);
a.setAttribute("href", "#/organizations/" + ev.organizationId + "/groups?search=" + shortId);
return a.outerHTML;
}

private formatCollectionId(ev: EventResponse) {
const shortId = this.getShortId(ev.collectionId);
const a = this.makeAnchor(shortId);
// TODO: Update view/edit collection link after EC-14 is completed
a.setAttribute(
"href",
"#/organizations/" + ev.organizationId + "/manage/collections?search=" + shortId
Expand All @@ -488,7 +486,7 @@ export class EventService {
"href",
"#/organizations/" +
ev.organizationId +
"/manage/people?search=" +
"/members?search=" +
shortId +
"&viewEvents=" +
ev.organizationUserId
Expand Down
100 changes: 51 additions & 49 deletions apps/web/src/app/organizations/manage/events.component.html
Original file line number Diff line number Diff line change
@@ -1,54 +1,57 @@
<div class="page-header d-flex">
<div class="tw-mb-4">
<h1>{{ "eventLogs" | i18n }}</h1>
<div class="ml-auto d-flex">
<div class="form-inline">
<label class="sr-only" for="start">{{ "startDate" | i18n }}</label>
<div class="tw-mt-4 tw-flex tw-items-center">
<bit-form-field>
<bit-label>{{ "from" | i18n }}</bit-label>
<input
bitInput
type="datetime-local"
class="form-control form-control-sm"
id="start"
placeholder="{{ 'startDate' | i18n }}"
[(ngModel)]="start"
placeholder="YYYY-MM-DDTHH:MM"
(change)="dirtyDates = true"
/>
<span class="mx-2">-</span>
<label class="sr-only" for="end">{{ "endDate" | i18n }}</label>
</bit-form-field>
<span class="tw-mx-2">-</span>
<bit-form-field>
<bit-label>{{ "to" | i18n }}</bit-label>
<input
bitInput
type="datetime-local"
class="form-control form-control-sm"
id="end"
placeholder="{{ 'endDate' | i18n }}"
[(ngModel)]="end"
placeholder="YYYY-MM-DDTHH:MM"
(change)="dirtyDates = true"
/>
</div>
<form #refreshForm [appApiAction]="refreshPromise" class="d-inline">
</bit-form-field>
<form #refreshForm [appApiAction]="refreshPromise">
<button
class="tw-mx-3 tw-mt-1"
type="button"
class="btn btn-sm btn-outline-primary ml-3"
bitButton
buttonType="primary"
(click)="loadEvents(true)"
[disabled]="loaded && refreshForm.loading"
>
<i
class="bwi bwi-refresh bwi-fw"
aria-hidden="true"
[ngClass]="{ 'bwi-spin': loaded && refreshForm.loading }"
></i>
{{ "refresh" | i18n }}
{{ "update" | i18n }}
</button>
</form>
<form #exportForm [appApiAction]="exportPromise" class="d-inline">
<form #exportForm [appApiAction]="exportPromise">
<button
type="button"
class="btn btn-sm btn-outline-primary btn-submit manual ml-3"
class="tw-mt-1"
bitButton
[ngClass]="{ loading: exportForm.loading }"
(click)="exportEvents()"
[disabled]="(loaded && exportForm.loading) || dirtyDates"
>
<i class="bwi bwi-spinner bwi-spin" aria-hidden="true"></i>
<span>{{ "export" | i18n }}</span>
<i
class="bwi bwi-fw"
aria-hidden="true"
[ngClass]="{
'bwi-sign-in': !exportForm.loading,
'bwi-spinner bwi-spin': exportForm.loading
}"
></i>
</button>
</form>
</div>
Expand All @@ -63,45 +66,44 @@ <h1>{{ "eventLogs" | i18n }}</h1>
</ng-container>
<ng-container *ngIf="loaded">
<p *ngIf="!events || !events.length">{{ "noEventsInList" | i18n }}</p>
<table class="table table-hover" *ngIf="events && events.length">
<thead>
<bit-table *ngIf="events && events.length">
<ng-container header>
<tr>
<th class="border-top-0" width="210">{{ "timestamp" | i18n }}</th>
<th class="border-top-0" width="40">
<span class="sr-only">{{ "device" | i18n }}</span>
</th>
<th class="border-top-0" width="150">{{ "user" | i18n }}</th>
<th class="border-top-0">{{ "event" | i18n }}</th>
<th bitCell style="width: 210px">{{ "timestamp" | i18n }}</th>
<th bitCell style="width: 100px">{{ "client" | i18n }}</th>
<th bitCell style="width: 150px">{{ "member" | i18n }}</th>
<th bitCell>{{ "event" | i18n }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let e of events">
<td>{{ e.date | date: "medium" }}</td>
<td>
<i
class="text-muted bwi bwi-lg {{ e.appIcon }}"
title="{{ e.appName }}, {{ e.ip }}"
aria-hidden="true"
></i>
<span class="sr-only">{{ e.appName }}, {{ e.ip }}</span>
</ng-container>
<ng-container body>
<tr bitRow *ngFor="let e of events">
<td bitCell>{{ e.date | date: "medium" }}</td>
<td bitCell>
<span title="{{ e.appName }}, {{ e.ip }}">{{ e.appName }}</span>
</td>
<td>
<td bitCell>
<span title="{{ e.userEmail }}">{{ e.userName }}</span>
</td>
<td [innerHTML]="e.message"></td>
<td bitCell [innerHTML]="e.message"></td>
</tr>
</tbody>
</table>
</ng-container>
</bit-table>
<button
#moreBtn
[appApiAction]="morePromise"
type="button"
class="btn btn-block btn-link btn-submit"
bitButton
buttonType="primary"
(click)="loadEvents(false)"
[disabled]="loaded && moreBtn.loading"
*ngIf="continuationToken"
>
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
<i
class="bwi bwi-spinner bwi-spin"
title="{{ 'loading' | i18n }}"
aria-hidden="true"
*ngIf="moreBtn.loading"
></i>
<span>{{ "loadMore" | i18n }}</span>
</button>
</ng-container>
37 changes: 23 additions & 14 deletions apps/web/src/app/organizations/manage/events.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Component, OnInit } from "@angular/core";
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { concatMap, Subject, takeUntil } from "rxjs";

import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
Expand All @@ -20,13 +21,13 @@ import { EventService } from "../../core";
selector: "app-org-events",
templateUrl: "events.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class EventsComponent extends BaseEventsComponent implements OnInit {
export class EventsComponent extends BaseEventsComponent implements OnInit, OnDestroy {
exportFileName = "org-events";
organizationId: string;
organization: Organization;

private orgUsersUserIdMap = new Map<string, any>();
private destroy$ = new Subject<void>();

constructor(
private apiService: ApiService,
Expand All @@ -53,17 +54,20 @@ export class EventsComponent extends BaseEventsComponent implements OnInit {
}

async ngOnInit() {
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
this.organization = await this.organizationService.get(this.organizationId);
if (this.organization == null || !this.organization.useEvents) {
this.router.navigate(["/organizations", this.organizationId]);
return;
}

await this.load();
});
this.route.params
.pipe(
concatMap(async (params) => {
this.organizationId = params.organizationId;
this.organization = await this.organizationService.get(this.organizationId);
if (this.organization == null || !this.organization.useEvents) {
await this.router.navigate(["/organizations", this.organizationId]);
return;
}
await this.load();
}),
takeUntil(this.destroy$)
)
.subscribe();
}

async load() {
Expand Down Expand Up @@ -126,4 +130,9 @@ export class EventsComponent extends BaseEventsComponent implements OnInit {

return null;
}

ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
7 changes: 5 additions & 2 deletions apps/web/src/app/shared/shared.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DragDropModule } from "@angular/cdk/drag-drop";
import { DatePipe, CommonModule } from "@angular/common";
import { CommonModule, DatePipe } from "@angular/common";
import { NgModule } from "@angular/core";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { RouterModule } from "@angular/router";
Expand All @@ -12,9 +12,10 @@ import {
ButtonModule,
CalloutModule,
FormFieldModule,
IconModule,
MenuModule,
TableModule,
TabsModule,
IconModule,
} from "@bitwarden/components";

// Register the locales for the application
Expand Down Expand Up @@ -46,6 +47,7 @@ import "./locales";
FormFieldModule,
IconModule,
TabsModule,
TableModule,
],
exports: [
CommonModule,
Expand All @@ -65,6 +67,7 @@ import "./locales";
FormFieldModule,
IconModule,
TabsModule,
TableModule,
],
providers: [DatePipe],
bootstrap: [],
Expand Down
16 changes: 16 additions & 0 deletions apps/web/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -4512,6 +4512,10 @@
"clients": {
"message": "Clients"
},
"client": {
"message": "Client",
"description": "This is used as a table header to describe which client application created an event log."
},
"providerAdmin": {
"message": "Provider Admin"
},
Expand Down Expand Up @@ -5431,5 +5435,17 @@
},
"numberOfUsers": {
"message": "Number of users"
},
"from": {
"message": "From"
},
"to": {
"message": "To"
},
"member": {
"message": "Member"
},
"update": {
"message": "Update"
}
}
1 change: 1 addition & 0 deletions libs/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export * from "./menu";
export * from "./dialog";
export * from "./link";
export * from "./tabs";
export * from "./table";
export * from "./toggle-group";
export * from "./utils/i18n-mock.service";