1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-10-14 06:48:18 +02:00

[PM-13156] - Access intelligence page (#11420)

* WIP - access intelligence page

* finish access intelligence page

* finish access intelligence page

* use tab label directive

* remove extension swap change

* only show when feature flag enabled

* Move files under tools ownership

---------

Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
This commit is contained in:
Jordan Aasen 2024-10-09 08:19:38 -07:00 committed by GitHub
parent 36c965c453
commit 7fc987d806
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 239 additions and 0 deletions

View File

@ -39,6 +39,11 @@
*ngIf="organization.canAccessReports" *ngIf="organization.canAccessReports"
></bit-nav-item> ></bit-nav-item>
</bit-nav-group> </bit-nav-group>
<bit-nav-item
*ngIf="isAccessIntelligenceFeatureEnabled"
[text]="'accessIntelligence' | i18n"
route="access-intelligence"
></bit-nav-item>
<bit-nav-group <bit-nav-group
icon="bwi-billing" icon="bwi-billing"
[text]="'billing' | i18n" [text]="'billing' | i18n"

View File

@ -51,6 +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;
private _destroy = new Subject<void>(); private _destroy = new Subject<void>();
@ -70,6 +71,10 @@ 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(
FeatureFlag.AccessIntelligence,
);
this.organization$ = this.route.params this.organization$ = this.route.params
.pipe(takeUntil(this._destroy)) .pipe(takeUntil(this._destroy))
.pipe<string>(map((p) => p.organizationId)) .pipe<string>(map((p) => p.organizationId))

View File

@ -62,6 +62,13 @@ const routes: Routes = [
(m) => m.OrganizationReportingModule, (m) => m.OrganizationReportingModule,
), ),
}, },
{
path: "access-intelligence",
loadChildren: () =>
import("../../tools/access-intelligence/access-intelligence.module").then(
(m) => m.AccessIntelligenceModule,
),
},
{ {
path: "billing", path: "billing",
loadChildren: () => loadChildren: () =>

View File

@ -0,0 +1,25 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { unauthGuardFn } from "@bitwarden/angular/auth/guards";
import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { AccessIntelligenceComponent } from "./access-intelligence.component";
const routes: Routes = [
{
path: "",
component: AccessIntelligenceComponent,
canActivate: [canAccessFeature(FeatureFlag.AccessIntelligence), unauthGuardFn()],
data: {
titleId: "accessIntelligence",
},
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class AccessIntelligenceRoutingModule {}

View File

@ -0,0 +1,23 @@
<app-header></app-header>
<bit-tab-group [(selectedIndex)]="tabIndex">
<bit-tab label="{{ 'allApplicationsWithCount' | i18n: apps.length }}">
<h2 bitTypography="h2">{{ "allApplications" | i18n }}</h2>
<tools-application-table></tools-application-table>
</bit-tab>
<bit-tab>
<ng-template bitTabLabel>
<i class="bwi bwi-star"></i>
{{ "priorityApplicationsWithCount" | i18n: priorityApps.length }}
</ng-template>
<h2 bitTypography>{{ "priorityApplications" | i18n }}</h2>
<tools-application-table></tools-application-table>
</bit-tab>
<bit-tab>
<ng-template bitTabLabel>
<i class="bwi bwi-envelope"></i>
{{ "notifiedMembersWithCount" | i18n: priorityApps.length }}
</ng-template>
<h2 bitTypography="h2">{{ "notifiedMembers" | i18n }}</h2>
<tools-notified-members-table></tools-notified-members-table>
</bit-tab>
</bit-tab-group>

View File

@ -0,0 +1,45 @@
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { ActivatedRoute } from "@angular/router";
import { first } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { TabsModule } from "@bitwarden/components";
import { HeaderModule } from "../../layouts/header/header.module";
import { ApplicationTableComponent } from "./application-table.component";
import { NotifiedMembersTableComponent } from "./notified-members-table.component";
export enum AccessIntelligenceTabType {
AllApps = 0,
PriorityApps = 1,
NotifiedMembers = 2,
}
@Component({
standalone: true,
templateUrl: "./access-intelligence.component.html",
imports: [
ApplicationTableComponent,
CommonModule,
JslibModule,
HeaderModule,
NotifiedMembersTableComponent,
TabsModule,
],
})
export class AccessIntelligenceComponent {
tabIndex: AccessIntelligenceTabType;
apps: any[] = [];
priorityApps: any[] = [];
notifiedMembers: any[] = [];
constructor(route: ActivatedRoute) {
route.queryParams.pipe(takeUntilDestroyed(), first()).subscribe(({ tabIndex }) => {
this.tabIndex = !isNaN(tabIndex) ? tabIndex : AccessIntelligenceTabType.AllApps;
});
}
}

View File

@ -0,0 +1,9 @@
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

@ -0,0 +1,11 @@
<!-- <bit-table [dataSource]="dataSource"> -->
<ng-container header>
<tr>
<th bitCell>{{ "application" | i18n }}</th>
<th bitCell>{{ "atRiskPasswords" | i18n }}</th>
<th bitCell>{{ "totalPasswords" | i18n }}</th>
<th bitCell>{{ "atRiskMembers" | i18n }}</th>
<th bitCell>{{ "totalMembers" | i18n }}</th>
</tr>
</ng-container>
<!-- </bit-table> -->

View File

@ -0,0 +1,19 @@
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { TableDataSource, TableModule } from "@bitwarden/components";
@Component({
standalone: true,
selector: "tools-application-table",
templateUrl: "./application-table.component.html",
imports: [CommonModule, JslibModule, TableModule],
})
export class ApplicationTableComponent {
protected dataSource = new TableDataSource<any>();
constructor() {
this.dataSource.data = [];
}
}

View File

@ -0,0 +1,11 @@
<!-- <bit-table [dataSource]="dataSource"> -->
<ng-container header>
<tr>
<th bitCell>{{ "member" | i18n }}</th>
<th bitCell>{{ "atRiskPasswords" | i18n }}</th>
<th bitCell>{{ "totalPasswords" | i18n }}</th>
<th bitCell>{{ "atRiskApplications" | i18n }}</th>
<th bitCell>{{ "totalApplications" | i18n }}</th>
</tr>
</ng-container>
<!-- </bit-table> -->

View File

@ -0,0 +1,19 @@
import { CommonModule } from "@angular/common";
import { Component } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { TableDataSource, TableModule } from "@bitwarden/components";
@Component({
standalone: true,
selector: "tools-notified-members-table",
templateUrl: "./notified-members-table.component.html",
imports: [CommonModule, JslibModule, TableModule],
})
export class NotifiedMembersTableComponent {
dataSource = new TableDataSource<any>();
constructor() {
this.dataSource.data = [];
}
}

View File

@ -1,4 +1,64 @@
{ {
"allApplications": {
"message": "All applications"
},
"priorityApplications": {
"message": "Priority applications"
},
"accessIntelligence": {
"message": "Access Intelligence"
},
"notifiedMembers": {
"message": "Notified members"
},
"allApplicationsWithCount": {
"message": "All applications ($COUNT$)",
"placeholders": {
"count": {
"content": "$1",
"example": "3"
}
}
},
"priorityApplicationsWithCount": {
"message": "Priority applications ($COUNT$)",
"placeholders": {
"count": {
"content": "$1",
"example": "3"
}
}
},
"notifiedMembersWithCount": {
"message": "Notified members ($COUNT$)",
"placeholders": {
"count": {
"content": "$1",
"example": "3"
}
}
},
"application": {
"message": "Application"
},
"atRiskPasswords": {
"message": "At-risk passwords"
},
"totalPasswords": {
"message": "Total passwords"
},
"atRiskMembers": {
"message": "At-risk members"
},
"totalMembers": {
"message": "Total members"
},
"atRiskApplications": {
"message": "At-risk applications"
},
"totalApplications": {
"message": "Total applications"
},
"whatTypeOfItem": { "whatTypeOfItem": {
"message": "What type of item is this?" "message": "What type of item is this?"
}, },