1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 13:23:34 +00:00

[PM-14268] - Access intelligence - add tabbing and events (#11831)

* comment code

* small fixes

* undo change to flags
This commit is contained in:
Jordan Aasen
2024-11-04 10:45:34 -08:00
committed by GitHub
parent 527f48f78f
commit c36fbcf8b7
6 changed files with 60 additions and 15 deletions

View File

@@ -15,7 +15,7 @@
{{ "refresh" | i18n }} {{ "refresh" | i18n }}
</a> </a>
</div> </div>
<bit-tab-group [(selectedIndex)]="tabIndex"> <bit-tab-group [(selectedIndex)]="tabIndex" (selectedIndexChange)="onTabChange($event)">
<bit-tab label="{{ 'allApplicationsWithCount' | i18n: apps.length }}"> <bit-tab label="{{ 'allApplicationsWithCount' | i18n: apps.length }}">
<tools-all-applications></tools-all-applications> <tools-all-applications></tools-all-applications>
</bit-tab> </bit-tab>

View File

@@ -1,8 +1,7 @@
import { CommonModule } from "@angular/common"; import { CommonModule } from "@angular/common";
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { ActivatedRoute } from "@angular/router"; import { ActivatedRoute, Router } from "@angular/router";
import { first } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AsyncActionsModule, ButtonModule, TabsModule } from "@bitwarden/components"; import { AsyncActionsModule, ButtonModule, TabsModule } from "@bitwarden/components";
@@ -18,7 +17,7 @@ import { PasswordHealthComponent } from "./password-health.component";
export enum AccessIntelligenceTabType { export enum AccessIntelligenceTabType {
AllApps = 0, AllApps = 0,
PriorityApps = 1, CriticalApps = 1,
NotifiedMembers = 2, NotifiedMembers = 2,
} }
@@ -58,8 +57,19 @@ export class AccessIntelligenceComponent {
); );
} }
constructor(route: ActivatedRoute) { onTabChange = async (newIndex: number) => {
route.queryParams.pipe(takeUntilDestroyed(), first()).subscribe(({ tabIndex }) => { await this.router.navigate([], {
relativeTo: this.route,
queryParams: { tabIndex: newIndex },
queryParamsHandling: "merge",
});
};
constructor(
protected route: ActivatedRoute,
private router: Router,
) {
route.queryParams.pipe(takeUntilDestroyed()).subscribe(({ tabIndex }) => {
this.tabIndex = !isNaN(tabIndex) ? tabIndex : AccessIntelligenceTabType.AllApps; this.tabIndex = !isNaN(tabIndex) ? tabIndex : AccessIntelligenceTabType.AllApps;
}); });
} }

View File

@@ -14,13 +14,15 @@
</h2> </h2>
</ng-container> </ng-container>
<ng-container slot="description"> <ng-container slot="description">
<p class="tw-text-muted"> <div class="tw-flex tw-flex-col tw-mb-2">
{{ "noAppsInOrgDescription" | i18n }} <span class="tw-text-muted">
{{ "noAppsInOrgDescription" | i18n }}
</span>
<a class="text-primary" routerLink="/login">{{ "learnMore" | i18n }}</a> <a class="text-primary" routerLink="/login">{{ "learnMore" | i18n }}</a>
</p> </div>
</ng-container> </ng-container>
<ng-container slot="button"> <ng-container slot="button">
<button bitButton buttonType="primary" type="button"> <button (click)="goToCreateNewLoginItem()" bitButton buttonType="primary" type="button">
{{ "createNewLoginItem" | i18n }} {{ "createNewLoginItem" | i18n }}
</button> </button>
</ng-container> </ng-container>
@@ -50,7 +52,15 @@
class="tw-grow" class="tw-grow"
[formControl]="searchControl" [formControl]="searchControl"
></bit-search> ></bit-search>
<button class="tw-rounded-lg" type="button" buttonType="secondary" bitButton> <button
class="tw-rounded-lg"
type="button"
buttonType="secondary"
bitButton
[disabled]="!selectedIds.size"
[loading]="markingAsCritical"
(click)="markAppsAsCritical()"
>
<i class="bwi bwi-star-f tw-mr-2"></i> <i class="bwi bwi-star-f tw-mr-2"></i>
{{ "markAppAsCritical" | i18n }} {{ "markAppAsCritical" | i18n }}
</button> </button>

View File

@@ -40,6 +40,7 @@ export class AllApplicationsComponent implements OnInit {
protected loading = false; protected loading = false;
protected organization: Organization; protected organization: Organization;
noItemsIcon = Icons.Security; noItemsIcon = Icons.Security;
protected markingAsCritical = false;
// MOCK DATA // MOCK DATA
protected mockData = applicationTableMockData; protected mockData = applicationTableMockData;
@@ -76,8 +77,18 @@ export class AllApplicationsComponent implements OnInit {
.subscribe((v) => (this.dataSource.filter = v)); .subscribe((v) => (this.dataSource.filter = v));
} }
goToCreateNewLoginItem = async () => {
// TODO: implement
this.toastService.showToast({
variant: "warning",
title: null,
message: "Not yet implemented",
});
};
markAppsAsCritical = async () => { markAppsAsCritical = async () => {
// TODO: Send to API once implemented // TODO: Send to API once implemented
this.markingAsCritical = true;
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { setTimeout(() => {
this.selectedIds.clear(); this.selectedIds.clear();
@@ -87,6 +98,7 @@ export class AllApplicationsComponent implements OnInit {
message: this.i18nService.t("appsMarkedAsCritical"), message: this.i18nService.t("appsMarkedAsCritical"),
}); });
resolve(true); resolve(true);
this.markingAsCritical = false;
}, 1000); }, 1000);
}); });
}; };

View File

@@ -19,7 +19,9 @@
</p> </p>
</ng-container> </ng-container>
<ng-container slot="button"> <ng-container slot="button">
<button bitButton buttonType="primary" type="button">{{ "markCriticalApps" | i18n }}</button> <button (click)="goToAllAppsTab()" bitButton buttonType="primary" type="button">
{{ "markCriticalApps" | i18n }}
</button>
</ng-container> </ng-container>
</bit-no-items> </bit-no-items>
</div> </div>

View File

@@ -1,7 +1,7 @@
import { Component, DestroyRef, inject, OnInit } from "@angular/core"; import { Component, DestroyRef, inject, OnInit } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { FormControl } from "@angular/forms"; import { FormControl } from "@angular/forms";
import { ActivatedRoute } from "@angular/router"; import { ActivatedRoute, Router } from "@angular/router";
import { debounceTime, map } from "rxjs"; import { debounceTime, map } from "rxjs";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -12,6 +12,7 @@ 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";
@Component({ @Component({
@@ -26,8 +27,10 @@ export class CriticalApplicationsComponent implements OnInit {
protected searchControl = new FormControl("", { nonNullable: true }); protected searchControl = new FormControl("", { nonNullable: true });
private destroyRef = inject(DestroyRef); private destroyRef = inject(DestroyRef);
protected loading = false; protected loading = false;
protected organizationId: string;
noItemsIcon = Icons.Security; noItemsIcon = Icons.Security;
// MOCK DATA // MOCK DATA
protected mockData = applicationTableMockData;
protected mockAtRiskMembersCount = 0; protected mockAtRiskMembersCount = 0;
protected mockAtRiskAppsCount = 0; protected mockAtRiskAppsCount = 0;
protected mockTotalMembersCount = 0; protected mockTotalMembersCount = 0;
@@ -38,18 +41,26 @@ export class CriticalApplicationsComponent implements OnInit {
.pipe( .pipe(
takeUntilDestroyed(this.destroyRef), takeUntilDestroyed(this.destroyRef),
map(async (params) => { map(async (params) => {
// const organizationId = params.get("organizationId"); this.organizationId = params.get("organizationId");
// TODO: use organizationId to fetch data // TODO: use organizationId to fetch data
}), }),
) )
.subscribe(); .subscribe();
} }
goToAllAppsTab = async () => {
await this.router.navigate([`organizations/${this.organizationId}/access-intelligence`], {
queryParams: { tabIndex: AccessIntelligenceTabType.AllApps },
queryParamsHandling: "merge",
});
};
constructor( constructor(
protected i18nService: I18nService, protected i18nService: I18nService,
protected activatedRoute: ActivatedRoute, protected activatedRoute: ActivatedRoute,
protected router: Router,
) { ) {
this.dataSource.data = applicationTableMockData; this.dataSource.data = []; //applicationTableMockData;
this.searchControl.valueChanges this.searchControl.valueChanges
.pipe(debounceTime(200), takeUntilDestroyed()) .pipe(debounceTime(200), takeUntilDestroyed())
.subscribe((v) => (this.dataSource.filter = v)); .subscribe((v) => (this.dataSource.filter = v));