diff --git a/apps/web/src/app/modules/loose-components.module.ts b/apps/web/src/app/modules/loose-components.module.ts index 10d23cf62ef..898b146e42e 100644 --- a/apps/web/src/app/modules/loose-components.module.ts +++ b/apps/web/src/app/modules/loose-components.module.ts @@ -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, diff --git a/apps/web/src/app/organizations/layouts/organization-layout.component.html b/apps/web/src/app/organizations/layouts/organization-layout.component.html index 03f699325bb..2b9458df923 100644 --- a/apps/web/src/app/organizations/layouts/organization-layout.component.html +++ b/apps/web/src/app/organizations/layouts/organization-layout.component.html @@ -14,8 +14,8 @@ {{ "groups" | i18n }} - {{ - "reports" | i18n + {{ + "reporting" | i18n }} {{ "billing" | i18n diff --git a/apps/web/src/app/organizations/organization-routing.module.ts b/apps/web/src/app/organizations/organization-routing.module.ts index 31f167ab43d..8c6264806d8 100644 --- a/apps/web/src/app/organizations/organization-routing.module.ts +++ b/apps/web/src/app/organizations/organization-routing.module.ts @@ -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], + }, + }, + ], + }, ], }, ]; diff --git a/apps/web/src/app/organizations/reporting/report-list.component.html b/apps/web/src/app/organizations/reporting/report-list.component.html new file mode 100644 index 00000000000..605146e024a --- /dev/null +++ b/apps/web/src/app/organizations/reporting/report-list.component.html @@ -0,0 +1,24 @@ + + + +

{{ "orgsReportsDesc" | i18n }}

+ +
+
+ +
+
+
+ + + + diff --git a/apps/web/src/app/organizations/reporting/report-list.component.ts b/apps/web/src/app/organizations/reporting/report-list.component.ts new file mode 100644 index 00000000000..3c644743b7b --- /dev/null +++ b/apps/web/src/app/organizations/reporting/report-list.component.ts @@ -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(); + } +} diff --git a/apps/web/src/app/organizations/reporting/reporting.component.html b/apps/web/src/app/organizations/reporting/reporting.component.html new file mode 100644 index 00000000000..8f5bac5fc8f --- /dev/null +++ b/apps/web/src/app/organizations/reporting/reporting.component.html @@ -0,0 +1,30 @@ +
+
+
+ +
+
+ +
+
+
diff --git a/apps/web/src/app/organizations/reporting/reporting.component.ts b/apps/web/src/app/organizations/reporting/reporting.component.ts new file mode 100644 index 00000000000..29ae5fe7230 --- /dev/null +++ b/apps/web/src/app/organizations/reporting/reporting.component.ts @@ -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; + }); + } +} diff --git a/apps/web/src/app/reports/report-card.component.html b/apps/web/src/app/reports/report-card.component.html index 7882e27906a..138a9b6a687 100644 --- a/apps/web/src/app/reports/report-card.component.html +++ b/apps/web/src/app/reports/report-card.component.html @@ -1,5 +1,5 @@ diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index e89d318a761..2469b63c6a2 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -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" } }