1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-13 06:43:35 +00:00

[PM-14462] - Update "Access Intelligence" to "Risk Insights" (#11853)

* rename acess intelligence to risk insights

* keep branch name

* replace all instances of AccessIntelligence. strip raw data + members to just the table

* revert change to feature flag name
This commit is contained in:
Jordan Aasen
2024-11-06 06:47:29 -08:00
committed by GitHub
parent 52c7d21e5f
commit b877624ce3
34 changed files with 103 additions and 159 deletions

View File

@@ -40,9 +40,9 @@
></bit-nav-item> ></bit-nav-item>
</bit-nav-group> </bit-nav-group>
<bit-nav-item <bit-nav-item
*ngIf="isAccessIntelligenceFeatureEnabled" *ngIf="isRiskInsightsFeatureEnabled"
[text]="'accessIntelligence' | i18n" [text]="'riskInsights' | i18n"
route="access-intelligence" route="risk-insights"
></bit-nav-item> ></bit-nav-item>
<bit-nav-group <bit-nav-group
icon="bwi-billing" icon="bwi-billing"

View File

@@ -51,7 +51,7 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
showPaymentAndHistory$: Observable<boolean>; showPaymentAndHistory$: Observable<boolean>;
hideNewOrgButton$: Observable<boolean>; hideNewOrgButton$: Observable<boolean>;
organizationIsUnmanaged$: Observable<boolean>; organizationIsUnmanaged$: Observable<boolean>;
isAccessIntelligenceFeatureEnabled = false; isRiskInsightsFeatureEnabled = false;
private _destroy = new Subject<void>(); private _destroy = new Subject<void>();
@@ -71,7 +71,7 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
async ngOnInit() { async ngOnInit() {
document.body.classList.remove("layout_frontend"); document.body.classList.remove("layout_frontend");
this.isAccessIntelligenceFeatureEnabled = await this.configService.getFeatureFlag( this.isRiskInsightsFeatureEnabled = await this.configService.getFeatureFlag(
FeatureFlag.AccessIntelligence, FeatureFlag.AccessIntelligence,
); );

View File

@@ -63,10 +63,10 @@ const routes: Routes = [
), ),
}, },
{ {
path: "access-intelligence", path: "risk-insights",
loadChildren: () => loadChildren: () =>
import("../../tools/access-intelligence/access-intelligence.module").then( import("../../tools/risk-insights/risk-insights.module").then(
(m) => m.AccessIntelligenceModule, (m) => m.RiskInsightsModule,
), ),
}, },
{ {

View File

@@ -1,9 +0,0 @@
import { NgModule } from "@angular/core";
import { AccessIntelligenceRoutingModule } from "./access-intelligence-routing.module";
import { AccessIntelligenceComponent } from "./access-intelligence.component";
@NgModule({
imports: [AccessIntelligenceComponent, AccessIntelligenceRoutingModule],
})
export class AccessIntelligenceModule {}

View File

@@ -1,120 +0,0 @@
<p>{{ "passwordsReportDesc" | i18n }}</p>
<div *ngIf="loading">
<i
class="bwi bwi-spinner bwi-spin tw-text-muted"
title="{{ 'loading' | i18n }}"
aria-hidden="true"
></i>
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
</div>
<div class="tw-mt-4 tw-flex tw-flex-col" *ngIf="!loading && dataSource.data.length">
<div class="tw-flex tw-gap-6">
<tools-card
class="tw-flex-1"
[title]="'atRiskMembers' | i18n"
[value]="totalMembersMap.size - 3"
[maxValue]="totalMembersMap.size"
>
</tools-card>
<tools-card
class="tw-flex-1"
[title]="'atRiskApplications' | i18n"
[value]="totalMembersMap.size - 1"
[maxValue]="totalMembersMap.size"
>
</tools-card>
</div>
<div class="tw-flex tw-mt-8 tw-mb-4 tw-gap-4">
<bit-search class="tw-grow" [formControl]="searchControl"></bit-search>
<button class="tw-rounded-lg" type="button" buttonType="secondary" bitButton>
<i class="bwi bwi-star-f tw-mr-2"></i>
{{ "markAppAsCritical" | i18n }}
</button>
</div>
<div class="tw-mt-4 tw-flex tw-flex-col" *ngIf="!loading && dataSource.data.length">
<div class="tw-flex tw-gap-6">
<tools-card
class="tw-flex-1"
[title]="'atRiskMembers' | i18n"
[value]="totalMembersMap.size - 3"
[maxValue]="totalMembersMap.size"
>
</tools-card>
<tools-card
class="tw-flex-1"
[title]="'atRiskApplications' | i18n"
[value]="totalMembersMap.size - 1"
[maxValue]="totalMembersMap.size"
>
</tools-card>
</div>
<div class="tw-flex tw-mt-8 tw-mb-4 tw-gap-4">
<bit-search class="tw-grow" [formControl]="searchControl"></bit-search>
<button
class="tw-rounded-lg"
type="button"
buttonType="secondary"
[disabled]="!selectedIds.size"
bitButton
[bitAction]="markAppsAsCritical"
appA11yTitle="{{ 'markAppAsCritical' | i18n }}"
>
<i class="bwi bwi-star-f tw-mr-2"></i>
{{ "markAppAsCritical" | i18n }}
</button>
</div>
<bit-table [dataSource]="dataSource">
<ng-container header>
<tr bitRow>
<th bitCell></th>
<th bitCell bitSortable="name">{{ "name" | i18n }}</th>
<th bitCell class="tw-text-right">{{ "weakness" | i18n }}</th>
<th bitCell class="tw-text-right">{{ "timesReused" | i18n }}</th>
<th bitCell class="tw-text-right">{{ "timesExposed" | i18n }}</th>
<th bitCell class="tw-text-right">{{ "totalMembers" | i18n }}</th>
</tr>
</ng-container>
<ng-template body let-rows$>
<tr bitRow *ngFor="let r of rows$ | async; trackBy: trackByFunction">
<td bitCell>
<input
bitCheckbox
type="checkbox"
[checked]="selectedIds.has(r.id)"
(change)="onCheckboxChange(r.id, $event)"
/>
</td>
<td bitCell>
<ng-container>
<span>{{ r.name }}</span>
</ng-container>
<br />
<small>{{ r.subTitle }}</small>
</td>
<td bitCell class="tw-text-right">
<span
bitBadge
*ngIf="passwordStrengthMap.has(r.id)"
[variant]="passwordStrengthMap.get(r.id)[1]"
>
{{ passwordStrengthMap.get(r.id)[0] | i18n }}
</span>
</td>
<td bitCell class="tw-text-right">
<span bitBadge *ngIf="passwordUseMap.has(r.login.password)" variant="warning">
{{ "reusedXTimes" | i18n: passwordUseMap.get(r.login.password) }}
</span>
</td>
<td bitCell class="tw-text-right">
<span bitBadge *ngIf="exposedPasswordMap.has(r.id)" variant="warning">
{{ "exposedXTimes" | i18n: exposedPasswordMap.get(r.id) }}
</span>
</td>
<td bitCell class="tw-text-right" data-testid="total-membership">
{{ totalMembersMap.get(r.id) || 0 }}
</td>
</tr>
</ng-template>
</bit-table>
</div>
</div>

View File

@@ -12,8 +12,8 @@ import { HeaderModule } from "../../layouts/header/header.module";
import { SharedModule } from "../../shared"; import { SharedModule } from "../../shared";
import { PipesModule } from "../../vault/individual-vault/pipes/pipes.module"; import { PipesModule } from "../../vault/individual-vault/pipes/pipes.module";
import { AccessIntelligenceTabType } from "./access-intelligence.component";
import { applicationTableMockData } from "./application-table.mock"; import { applicationTableMockData } from "./application-table.mock";
import { RiskInsightsTabType } from "./risk-insights.component";
@Component({ @Component({
standalone: true, standalone: true,
@@ -49,8 +49,8 @@ export class CriticalApplicationsComponent implements OnInit {
} }
goToAllAppsTab = async () => { goToAllAppsTab = async () => {
await this.router.navigate([`organizations/${this.organizationId}/access-intelligence`], { await this.router.navigate([`organizations/${this.organizationId}/risk-insights`], {
queryParams: { tabIndex: AccessIntelligenceTabType.AllApps }, queryParams: { tabIndex: RiskInsightsTabType.AllApps },
queryParamsHandling: "merge", queryParamsHandling: "merge",
}); });
}; };

View File

@@ -4,7 +4,7 @@ import { mock, MockProxy } from "jest-mock-extended";
import { of } from "rxjs"; import { of } from "rxjs";
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/access-intelligence"; import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/risk-insights";
import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";

View File

@@ -6,7 +6,7 @@ import { map } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/access-intelligence"; import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/risk-insights";
import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";

View File

@@ -0,0 +1,64 @@
<p>{{ "passwordsReportDesc" | i18n }}</p>
<div *ngIf="loading">
<i
class="bwi bwi-spinner bwi-spin tw-text-muted"
title="{{ 'loading' | i18n }}"
aria-hidden="true"
></i>
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
</div>
<div class="tw-flex tw-flex-col" *ngIf="!loading && dataSource.data.length">
<bit-table [dataSource]="dataSource">
<ng-container header>
<tr bitRow>
<th bitCell></th>
<th bitCell bitSortable="name">{{ "name" | i18n }}</th>
<th bitCell class="tw-text-right">{{ "weakness" | i18n }}</th>
<th bitCell class="tw-text-right">{{ "timesReused" | i18n }}</th>
<th bitCell class="tw-text-right">{{ "timesExposed" | i18n }}</th>
<th bitCell class="tw-text-right">{{ "totalMembers" | i18n }}</th>
</tr>
</ng-container>
<ng-template body let-rows$>
<tr bitRow *ngFor="let r of rows$ | async; trackBy: trackByFunction">
<td bitCell>
<input
bitCheckbox
type="checkbox"
[checked]="selectedIds.has(r.id)"
(change)="onCheckboxChange(r.id, $event)"
/>
</td>
<td bitCell>
<ng-container>
<span>{{ r.name }}</span>
</ng-container>
<br />
<small>{{ r.subTitle }}</small>
</td>
<td bitCell class="tw-text-right">
<span
bitBadge
*ngIf="passwordStrengthMap.has(r.id)"
[variant]="passwordStrengthMap.get(r.id)[1]"
>
{{ passwordStrengthMap.get(r.id)[0] | i18n }}
</span>
</td>
<td bitCell class="tw-text-right">
<span bitBadge *ngIf="passwordUseMap.has(r.login.password)" variant="warning">
{{ "reusedXTimes" | i18n: passwordUseMap.get(r.login.password) }}
</span>
</td>
<td bitCell class="tw-text-right">
<span bitBadge *ngIf="exposedPasswordMap.has(r.id)" variant="warning">
{{ "exposedXTimes" | i18n: exposedPasswordMap.get(r.id) }}
</span>
</td>
<td bitCell class="tw-text-right" data-testid="total-membership">
{{ totalMembersMap.get(r.id) || 0 }}
</td>
</tr>
</ng-template>
</bit-table>
</div>

View File

@@ -5,7 +5,7 @@ import { ActivatedRoute } from "@angular/router";
import { debounceTime, map } from "rxjs"; import { debounceTime, map } from "rxjs";
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/access-intelligence"; import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/risk-insights";
import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";

View File

@@ -4,7 +4,7 @@ import { mock } from "jest-mock-extended";
import { of } from "rxjs"; import { of } from "rxjs";
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/access-intelligence"; import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/risk-insights";
import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";

View File

@@ -6,7 +6,7 @@ import { map } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/access-intelligence"; import { PasswordHealthService } from "@bitwarden/bit-common/tools/reports/risk-insights";
import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";

View File

@@ -4,15 +4,15 @@ import { RouterModule, Routes } from "@angular/router";
import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard"; import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { AccessIntelligenceComponent } from "./access-intelligence.component"; import { RiskInsightsComponent } from "./risk-insights.component";
const routes: Routes = [ const routes: Routes = [
{ {
path: "", path: "",
component: AccessIntelligenceComponent, component: RiskInsightsComponent,
canActivate: [canAccessFeature(FeatureFlag.AccessIntelligence)], canActivate: [canAccessFeature(FeatureFlag.AccessIntelligence)],
data: { data: {
titleId: "accessIntelligence", titleId: "RiskInsights",
}, },
}, },
]; ];
@@ -21,4 +21,4 @@ const routes: Routes = [
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule], exports: [RouterModule],
}) })
export class AccessIntelligenceRoutingModule {} export class RiskInsightsRoutingModule {}

View File

@@ -1,4 +1,4 @@
<div class="tw-mb-1 text-primary" bitTypography="body1">{{ "accessIntelligence" | i18n }}</div> <div class="tw-mb-1 text-primary" bitTypography="body1">{{ "riskInsights" | i18n }}</div>
<h1 bitTypography="h1">{{ "passwordRisk" | i18n }}</h1> <h1 bitTypography="h1">{{ "passwordRisk" | i18n }}</h1>
<div class="tw-text-muted">{{ "discoverAtRiskPasswords" | i18n }}</div> <div class="tw-text-muted">{{ "discoverAtRiskPasswords" | i18n }}</div>
<div class="tw-bg-primary-100 tw-rounded-lg tw-w-full tw-px-8 tw-py-2 tw-my-4"> <div class="tw-bg-primary-100 tw-rounded-lg tw-w-full tw-px-8 tw-py-2 tw-my-4">

View File

@@ -15,7 +15,7 @@ import { PasswordHealthMembersURIComponent } from "./password-health-members-uri
import { PasswordHealthMembersComponent } from "./password-health-members.component"; import { PasswordHealthMembersComponent } from "./password-health-members.component";
import { PasswordHealthComponent } from "./password-health.component"; import { PasswordHealthComponent } from "./password-health.component";
export enum AccessIntelligenceTabType { export enum RiskInsightsTabType {
AllApps = 0, AllApps = 0,
CriticalApps = 1, CriticalApps = 1,
NotifiedMembers = 2, NotifiedMembers = 2,
@@ -23,7 +23,7 @@ export enum AccessIntelligenceTabType {
@Component({ @Component({
standalone: true, standalone: true,
templateUrl: "./access-intelligence.component.html", templateUrl: "./risk-insights.component.html",
imports: [ imports: [
AllApplicationsComponent, AllApplicationsComponent,
AsyncActionsModule, AsyncActionsModule,
@@ -39,8 +39,8 @@ export enum AccessIntelligenceTabType {
TabsModule, TabsModule,
], ],
}) })
export class AccessIntelligenceComponent { export class RiskInsightsComponent {
tabIndex: AccessIntelligenceTabType; tabIndex: RiskInsightsTabType;
dataLastUpdated = new Date(); dataLastUpdated = new Date();
apps: any[] = []; apps: any[] = [];
@@ -70,7 +70,7 @@ export class AccessIntelligenceComponent {
private router: Router, private router: Router,
) { ) {
route.queryParams.pipe(takeUntilDestroyed()).subscribe(({ tabIndex }) => { route.queryParams.pipe(takeUntilDestroyed()).subscribe(({ tabIndex }) => {
this.tabIndex = !isNaN(tabIndex) ? tabIndex : AccessIntelligenceTabType.AllApps; this.tabIndex = !isNaN(tabIndex) ? tabIndex : RiskInsightsTabType.AllApps;
}); });
} }
} }

View File

@@ -0,0 +1,9 @@
import { NgModule } from "@angular/core";
import { RiskInsightsRoutingModule } from "./risk-insights-routing.module";
import { RiskInsightsComponent } from "./risk-insights.component";
@NgModule({
imports: [RiskInsightsComponent, RiskInsightsRoutingModule],
})
export class RiskInsightsModule {}

View File

@@ -5,8 +5,8 @@
"criticalApplications": { "criticalApplications": {
"message": "Critical applications" "message": "Critical applications"
}, },
"accessIntelligence": { "riskInsights": {
"message": "Access Intelligence" "message": "Risk Insights"
}, },
"passwordRisk": { "passwordRisk": {
"message": "Password Risk" "message": "Password Risk"

View File

@@ -1,9 +1,9 @@
import { Inject, Injectable } from "@angular/core"; import { Inject, Injectable } from "@angular/core";
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { mockCiphers } from "@bitwarden/bit-common/tools/reports/access-intelligence/services/ciphers.mock"; import { mockCiphers } from "@bitwarden/bit-common/tools/reports/risk-insights/services/ciphers.mock";
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { mockMemberCipherDetailsResponse } from "@bitwarden/bit-common/tools/reports/access-intelligence/services/member-cipher-details-response.mock"; import { mockMemberCipherDetailsResponse } from "@bitwarden/bit-common/tools/reports/risk-insights/services/member-cipher-details-response.mock";
import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";