1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-20 02:03:39 +00:00

[PM-26352] drawers for activity cards (#16895)

* new drawer functions for crit apps

* logic for triggering the drawer functions in components

* cleanup unused logic and rename "navigation" to "action"
- ... since the click is now triggering the drawer instead of navigating to another tab/page

* null check for reportData in drawer methods

* use criticalReportResults$ to avoid duplicating logic

* use criticalReportResults$ to avoid dupe logic

* remove unused code
This commit is contained in:
Alex
2025-10-28 11:44:42 -04:00
committed by GitHub
parent bf66b5ac19
commit 2058c772ac
5 changed files with 97 additions and 38 deletions

View File

@@ -175,6 +175,65 @@ export class RiskInsightsDataService {
} }
}; };
setDrawerForCriticalAtRiskMembers = async (invokerId: string = ""): Promise<void> => {
const { open, activeDrawerType, invokerId: currentInvokerId } = this.drawerDetailsSubject.value;
const shouldClose =
open && activeDrawerType === DrawerType.OrgAtRiskMembers && currentInvokerId === invokerId;
if (shouldClose) {
this.closeDrawer();
} else {
const reportResults = await firstValueFrom(this.criticalReportResults$);
if (!reportResults?.reportData) {
return;
}
// Generate at-risk member list from critical applications
const atRiskMemberDetails = getAtRiskMemberList(reportResults.reportData);
this.drawerDetailsSubject.next({
open: true,
invokerId,
activeDrawerType: DrawerType.OrgAtRiskMembers,
atRiskMemberDetails,
appAtRiskMembers: null,
atRiskAppDetails: null,
});
}
};
setDrawerForCriticalAtRiskApps = async (invokerId: string = ""): Promise<void> => {
const { open, activeDrawerType, invokerId: currentInvokerId } = this.drawerDetailsSubject.value;
const shouldClose =
open && activeDrawerType === DrawerType.OrgAtRiskApps && currentInvokerId === invokerId;
if (shouldClose) {
this.closeDrawer();
} else {
const reportResults = await firstValueFrom(this.criticalReportResults$);
if (!reportResults?.reportData) {
return;
}
// Filter critical applications for those with at-risk passwords
const criticalAtRiskApps = reportResults.reportData
.filter((app) => app.atRiskPasswordCount > 0)
.map((app) => ({
applicationName: app.applicationName,
atRiskPasswordCount: app.atRiskPasswordCount,
}));
this.drawerDetailsSubject.next({
open: true,
invokerId,
activeDrawerType: DrawerType.OrgAtRiskApps,
atRiskMemberDetails: [],
appAtRiskMembers: null,
atRiskAppDetails: criticalAtRiskApps,
});
}
};
// ------------------------------ Critical application methods -------------- // ------------------------------ Critical application methods --------------
saveCriticalApplications(selectedUrls: string[]) { saveCriticalApplications(selectedUrls: string[]) {
return this.orchestrator.saveCriticalApplications$(selectedUrls); return this.orchestrator.saveCriticalApplications$(selectedUrls);

View File

@@ -23,11 +23,11 @@
</button> </button>
</div> </div>
} }
@if (showNavigationLink && !buttonText) { @if (showActionLink && !buttonText) {
<div class="tw-flex tw-items-baseline tw-mt-4 tw-gap-2"> <div class="tw-flex tw-items-baseline tw-mt-4 tw-gap-2">
<p bitTypography="body1"> <p bitTypography="body1">
<a bitLink (click)="navigateToLink(navigationLink)" rel="noreferrer"> <a bitLink href="#" (click)="onActionClick(); $event.preventDefault()" rel="noreferrer">
{{ navigationText }} {{ actionText }}
</a> </a>
</p> </p>
</div> </div>

View File

@@ -37,25 +37,14 @@ export class ActivityCardComponent {
@Input() metricDescription: string = ""; @Input() metricDescription: string = "";
/** /**
* The link to navigate to for more information * The text to display for the action link
*/ */
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals @Input() actionText: string = "";
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() navigationLink: string = "";
/** /**
* The text to display for the navigation link * Show action link
*/ */
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals @Input() showActionLink: boolean = false;
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() navigationText: string = "";
/**
* Show Navigation link
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() showNavigationLink: boolean = false;
/** /**
* Icon class to display next to metrics (e.g., "bwi-exclamation-triangle"). * Icon class to display next to metrics (e.g., "bwi-exclamation-triangle").
@@ -86,13 +75,18 @@ export class ActivityCardComponent {
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() buttonClick = new EventEmitter<void>(); @Output() buttonClick = new EventEmitter<void>();
constructor(private router: Router) {} /**
* Event emitted when action link is clicked
*/
@Output() actionClick = new EventEmitter<void>();
navigateToLink = async (navigationLink: string) => { constructor(private router: Router) {}
await this.router.navigateByUrl(navigationLink);
};
onButtonClick = () => { onButtonClick = () => {
this.buttonClick.emit(); this.buttonClick.emit();
}; };
onActionClick = () => {
this.actionClick.emit();
};
} }

View File

@@ -13,9 +13,9 @@
[title]="'atRiskMembers' | i18n" [title]="'atRiskMembers' | i18n"
[cardMetrics]="'membersAtRiskCount' | i18n: totalCriticalAppsAtRiskMemberCount" [cardMetrics]="'membersAtRiskCount' | i18n: totalCriticalAppsAtRiskMemberCount"
[metricDescription]="'membersWithAccessToAtRiskItemsForCriticalApps' | i18n" [metricDescription]="'membersWithAccessToAtRiskItemsForCriticalApps' | i18n"
navigationText="{{ 'viewAtRiskMembers' | i18n }}" actionText="{{ 'viewAtRiskMembers' | i18n }}"
navigationLink="{{ getLinkForRiskInsightsTab(RiskInsightsTabType.AllApps) }}" [showActionLink]="totalCriticalAppsAtRiskMemberCount > 0"
[showNavigationLink]="totalCriticalAppsAtRiskMemberCount > 0" (actionClick)="onViewAtRiskMembers()"
> >
</dirt-activity-card> </dirt-activity-card>
</li> </li>
@@ -35,9 +35,9 @@
: ('criticalApplicationsAreAtRisk' : ('criticalApplicationsAreAtRisk'
| i18n: totalCriticalAppsAtRiskCount : totalCriticalAppsCount) | i18n: totalCriticalAppsAtRiskCount : totalCriticalAppsCount)
" "
navigationText="{{ 'viewAtRiskApplications' | i18n }}" actionText="{{ 'viewAtRiskApplications' | i18n }}"
navigationLink="{{ getLinkForRiskInsightsTab(RiskInsightsTabType.CriticalApps) }}" [showActionLink]="totalCriticalAppsAtRiskCount > 0"
[showNavigationLink]="totalCriticalAppsAtRiskCount > 0" (actionClick)="onViewAtRiskApplications()"
> >
</dirt-activity-card> </dirt-activity-card>
</li> </li>

View File

@@ -15,7 +15,6 @@ import { getById } from "@bitwarden/common/platform/misc";
import { DialogService } from "@bitwarden/components"; import { DialogService } from "@bitwarden/components";
import { SharedModule } from "@bitwarden/web-vault/app/shared"; import { SharedModule } from "@bitwarden/web-vault/app/shared";
import { RiskInsightsTabType } from "../models/risk-insights.models";
import { ApplicationsLoadingComponent } from "../shared/risk-insights-loading.component"; import { ApplicationsLoadingComponent } from "../shared/risk-insights-loading.component";
import { ActivityCardComponent } from "./activity-card.component"; import { ActivityCardComponent } from "./activity-card.component";
@@ -82,15 +81,6 @@ export class AllActivityComponent implements OnInit {
} }
} }
get RiskInsightsTabType() {
return RiskInsightsTabType;
}
getLinkForRiskInsightsTab(tabIndex: RiskInsightsTabType): string {
const organizationId = this.activatedRoute.snapshot.paramMap.get("organizationId");
return `/organizations/${organizationId}/access-intelligence/risk-insights?tabIndex=${tabIndex}`;
}
/** /**
* Handles the review new applications button click. * Handles the review new applications button click.
* Opens a dialog showing the list of new applications that can be marked as critical. * Opens a dialog showing the list of new applications that can be marked as critical.
@@ -102,4 +92,20 @@ export class AllActivityComponent implements OnInit {
await firstValueFrom(dialogRef.closed); await firstValueFrom(dialogRef.closed);
}; };
/**
* Handles the "View at-risk members" link click.
* Opens the at-risk members drawer for critical applications only.
*/
onViewAtRiskMembers = async () => {
await this.dataService.setDrawerForCriticalAtRiskMembers("activityTabAtRiskMembers");
};
/**
* Handles the "View at-risk applications" link click.
* Opens the at-risk applications drawer for critical applications only.
*/
onViewAtRiskApplications = async () => {
await this.dataService.setDrawerForCriticalAtRiskApps("activityTabAtRiskApplications");
};
} }