mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
Add initial "Reporting" tab
This commit is contained in:
@@ -55,6 +55,8 @@ import { ResetPasswordPolicyComponent } from "../organizations/policies/reset-pa
|
||||
import { SendOptionsPolicyComponent } from "../organizations/policies/send-options.component";
|
||||
import { SingleOrgPolicyComponent } from "../organizations/policies/single-org.component";
|
||||
import { TwoFactorAuthenticationPolicyComponent } from "../organizations/policies/two-factor-authentication.component";
|
||||
import { ReportListComponent as OrgReportListComponent } from "../organizations/reporting/report-list.component";
|
||||
import { ReportingComponent as OrgReportingComponent } from "../organizations/reporting/reporting.component";
|
||||
import { AccountComponent as OrgAccountComponent } from "../organizations/settings/account.component";
|
||||
import { AdjustSubscription } from "../organizations/settings/adjust-subscription.component";
|
||||
import { BillingSyncApiKeyComponent } from "../organizations/settings/billing-sync-api-key.component";
|
||||
@@ -267,6 +269,8 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
|
||||
OrgUserConfirmComponent,
|
||||
OrgUserGroupsComponent,
|
||||
OrgWeakPasswordsReportComponent,
|
||||
OrgReportingComponent,
|
||||
OrgReportListComponent,
|
||||
GeneratorComponent,
|
||||
PasswordGeneratorHistoryComponent,
|
||||
PasswordGeneratorPolicyComponent,
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<bit-tab-item *ngIf="showGroupsTab" [route]="['groups']">{{
|
||||
"groups" | i18n
|
||||
}}</bit-tab-item>
|
||||
<bit-tab-item *ngIf="showReportsTab" [route]="['reports']">{{
|
||||
"reports" | i18n
|
||||
<bit-tab-item *ngIf="showReportsTab" [route]="['reporting']">{{
|
||||
"reporting" | i18n
|
||||
}}</bit-tab-item>
|
||||
<bit-tab-item *ngIf="showBillingTab" [route]="['billing']">{{
|
||||
"billing" | i18n
|
||||
|
||||
@@ -14,6 +14,8 @@ import { EventsComponent } from "./manage/events.component";
|
||||
import { ManageComponent } from "./manage/manage.component";
|
||||
import { PoliciesComponent } from "./manage/policies.component";
|
||||
import { MembersComponent } from "./members/members.component";
|
||||
import { ReportListComponent } from "./reporting/report-list.component";
|
||||
import { ReportingComponent } from "./reporting/reporting.component";
|
||||
import { NavigationPermissionsService } from "./services/navigation-permissions.service";
|
||||
import { AccountComponent } from "./settings/account.component";
|
||||
import { OrganizationBillingComponent } from "./settings/organization-billing.component";
|
||||
@@ -198,6 +200,82 @@ const routes: Routes = [
|
||||
permissions: [Permissions.ManageGroups],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "reporting",
|
||||
component: ReportingComponent,
|
||||
canActivate: [PermissionsGuard],
|
||||
data: {
|
||||
permissions: [Permissions.AccessReports],
|
||||
},
|
||||
children: [
|
||||
{ path: "", pathMatch: "full", redirectTo: "reports" },
|
||||
{
|
||||
path: "reports",
|
||||
component: ReportListComponent,
|
||||
canActivate: [PermissionsGuard],
|
||||
data: {
|
||||
titleId: "reports",
|
||||
permissions: [Permissions.AccessReports],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "exposed-passwords-report",
|
||||
component: ExposedPasswordsReportComponent,
|
||||
canActivate: [PermissionsGuard],
|
||||
data: {
|
||||
titleId: "exposedPasswordsReport",
|
||||
permissions: [Permissions.AccessReports],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "inactive-two-factor-report",
|
||||
component: InactiveTwoFactorReportComponent,
|
||||
canActivate: [PermissionsGuard],
|
||||
data: {
|
||||
titleId: "inactive2faReport",
|
||||
permissions: [Permissions.AccessReports],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "reused-passwords-report",
|
||||
component: ReusedPasswordsReportComponent,
|
||||
canActivate: [PermissionsGuard],
|
||||
data: {
|
||||
titleId: "reusedPasswordsReport",
|
||||
permissions: [Permissions.AccessReports],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "unsecured-websites-report",
|
||||
component: UnsecuredWebsitesReportComponent,
|
||||
canActivate: [PermissionsGuard],
|
||||
data: {
|
||||
titleId: "unsecuredWebsitesReport",
|
||||
permissions: [Permissions.AccessReports],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "weak-passwords-report",
|
||||
component: WeakPasswordsReportComponent,
|
||||
canActivate: [PermissionsGuard],
|
||||
data: {
|
||||
titleId: "weakPasswordsReport",
|
||||
permissions: [Permissions.AccessReports],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "events",
|
||||
component: EventsComponent,
|
||||
canActivate: [PermissionsGuard],
|
||||
data: {
|
||||
titleId: "eventLogs",
|
||||
permissions: [Permissions.AccessEventLogs],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<ng-container *ngIf="homepage">
|
||||
<div class="page-header">
|
||||
<h1>{{ "reports" | i18n }}</h1>
|
||||
</div>
|
||||
|
||||
<p>{{ "orgsReportsDesc" | i18n }}</p>
|
||||
|
||||
<div class="tw-inline-grid tw-grid-cols-3 tw-gap-4">
|
||||
<div *ngFor="let report of reports">
|
||||
<app-report-card [type]="report"></app-report-card>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col">
|
||||
<a bitButton routerLink="./" *ngIf="!homepage">
|
||||
<i class="bwi bwi-angle-left" aria-hidden="true"></i>
|
||||
{{ "backToReports" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { NavigationEnd, Router } from "@angular/router";
|
||||
import { filter, Subscription } from "rxjs";
|
||||
|
||||
import { ReportTypes } from "../../reports/report-card.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-org-report-list",
|
||||
templateUrl: "report-list.component.html",
|
||||
})
|
||||
export class ReportListComponent {
|
||||
reports = [
|
||||
ReportTypes.exposedPasswords,
|
||||
ReportTypes.reusedPasswords,
|
||||
ReportTypes.weakPasswords,
|
||||
ReportTypes.unsecuredWebsites,
|
||||
ReportTypes.inactive2fa,
|
||||
];
|
||||
|
||||
homepage = true;
|
||||
subscription: Subscription;
|
||||
|
||||
constructor(router: Router) {
|
||||
this.subscription = router.events
|
||||
.pipe(filter((event) => event instanceof NavigationEnd))
|
||||
.subscribe((event) => {
|
||||
this.homepage = (event as NavigationEnd).urlAfterRedirects.endsWith("/reports");
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<div class="container page-content">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<div class="card" *ngIf="organization">
|
||||
<div class="card-header">{{ "reporting" | i18n }}</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<a
|
||||
routerLink="reports"
|
||||
class="list-group-item"
|
||||
routerLinkActive="active"
|
||||
*ngIf="organization.canAccessReports"
|
||||
>
|
||||
{{ "reports" | i18n }}
|
||||
</a>
|
||||
<a
|
||||
routerLink="events"
|
||||
class="list-group-item"
|
||||
routerLinkActive="active"
|
||||
*ngIf="organization.canAccessEventLogs && accessEvents"
|
||||
>
|
||||
{{ "eventLogs" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
|
||||
import { Organization } from "@bitwarden/common/models/domain/organization";
|
||||
|
||||
@Component({
|
||||
selector: "app-org-reporting",
|
||||
templateUrl: "reporting.component.html",
|
||||
})
|
||||
export class ReportingComponent implements OnInit {
|
||||
organization: Organization;
|
||||
accessEvents = false;
|
||||
|
||||
constructor(private route: ActivatedRoute, private organizationService: OrganizationService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.parent.params.subscribe(async (params) => {
|
||||
this.organization = await this.organizationService.get(params.organizationId);
|
||||
this.accessEvents = this.organization.useEvents;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<a
|
||||
class="tw-border tw-border-solid tw-border-secondary-300 tw-rounded tw-overflow-hidden tw-h-full tw-w-72 tw-block !tw-text-main hover:tw-no-underline hover:tw-scale-105 tw-transition-all focus:tw-outline-none focus:tw-ring focus:tw-ring-offset-2 focus:tw-ring-primary-700"
|
||||
class="tw-border tw-border-solid tw-border-secondary-300 tw-rounded tw-overflow-hidden tw-h-full tw-max-w-[18rem] tw-block !tw-text-main hover:tw-no-underline hover:tw-scale-105 tw-transition-all focus:tw-outline-none focus:tw-ring focus:tw-ring-offset-2 focus:tw-ring-primary-700"
|
||||
[routerLink]="route"
|
||||
(click)="click()"
|
||||
>
|
||||
|
||||
@@ -1478,6 +1478,10 @@
|
||||
"message": "Identify and close security gaps in your online accounts by clicking the reports below.",
|
||||
"description": "Vault Health Reports can be used to evaluate the security of your Bitwarden Personal or Organization Vault."
|
||||
},
|
||||
"orgsReportsDesc": {
|
||||
"message": "Identify and close security gaps in your organization's accounts by clicking the reports below.",
|
||||
"description": "Vault Health Reports can be used to evaluate the security of your Bitwarden Personal or Organization Vault."
|
||||
},
|
||||
"unsecuredWebsitesReport": {
|
||||
"message": "Unsecure Websites"
|
||||
},
|
||||
@@ -5213,5 +5217,8 @@
|
||||
},
|
||||
"members": {
|
||||
"message": "Members"
|
||||
},
|
||||
"reporting": {
|
||||
"message": "Reporting"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user