Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e09eaa6
feat(dirt): add newApplications$ observable to orchestrator
AlexRubik Oct 28, 2025
2c09085
feat(dirt): add saveApplicationReviewStatus$ to orchestrator
AlexRubik Oct 28, 2025
1846293
feat(dirt): expose newApplications$ in data service
AlexRubik Oct 28, 2025
3fc8928
feat(dirt): make AllActivitiesService reactive to new applications
AlexRubik Oct 28, 2025
6d2d8ea
feat(dirt): connect dialog to review status save method
AlexRubik Oct 28, 2025
245f956
feat(dirt): add i18n strings for application review
AlexRubik Oct 28, 2025
7a29406
fix(dirt): add subscription cleanup to AllActivitiesService
AlexRubik Oct 28, 2025
b1da2cb
fix(dirt): replace manual takeUntil with takeUntilDestroyed in AllActโ€ฆ
AlexRubik Oct 29, 2025
907a784
refactor(dirt): remove newApplications from OrganizationReportSummary
AlexRubik Oct 29, 2025
8340dc2
cleanup
AlexRubik Oct 29, 2025
cf15d25
fix(dirt): improve dialog type safety and error logging
AlexRubik Oct 29, 2025
bf1c415
Merge branch 'main' into dirt/pm-27284/new-applications-card-real-data
AlexRubik Oct 29, 2025
6912be9
fixing mock data and test cases for new apps
ttalty Oct 29, 2025
5d37ede
feat(dirt): create assign tasks view component
AlexRubik Oct 30, 2025
eb74aa2
refactor(dirt): add multi-view state management to new applications dโ€ฆ
AlexRubik Oct 30, 2025
b5fdcda
feat(dirt): integrate assign tasks view into dialog
AlexRubik Oct 30, 2025
a928399
feat(dirt): add embedded assign tasks view to dialog template
AlexRubik Oct 30, 2025
a1ee9f1
feat(dirt): add i18n keys for assign tasks view
AlexRubik Oct 30, 2025
c449442
resolve organizationId and DI issues in assign tasks flow
AlexRubik Oct 30, 2025
286d50a
Merge branch 'main' into dirt/pm-27619/assign-tasks-dialog
AlexRubik Oct 30, 2025
f3d87e7
cleanup styling
AlexRubik Oct 30, 2025
580981e
refactor(dirt): remove newApplications validation from OrganizationReโ€ฆ
AlexRubik Oct 30, 2025
ed283f1
Merge branch 'dirt/pm-27284/new-applications-card-real-data' into dirโ€ฆ
AlexRubik Oct 30, 2025
08df1ea
improve assign tasks view display
AlexRubik Oct 30, 2025
8d99996
logic to fetch totals and new styling
AlexRubik Oct 30, 2025
22b18ae
Merge branch 'main' into dirt/pm-27619/assign-tasks-dialog
AlexRubik Oct 30, 2025
ba4c3e2
Merge branch 'main' into dirt/pm-27619/assign-tasks-dialog
AlexRubik Oct 30, 2025
3050da1
Merge branch 'main' into dirt/pm-27619/assign-tasks-dialog
AlexRubik Oct 31, 2025
ec4855c
Fix review applications review view and assign view flow
Banrion Nov 2, 2025
41d02bb
Fix null type checks
Banrion Nov 2, 2025
b9c9737
refactor assign tasks dialog: use callout component, add video, fix Oโ€ฆ
maxkpower Nov 3, 2025
831cf53
Add columns, description, search, and bulk select to new applicationsโ€ฆ
maxkpower Nov 3, 2025
f7534a7
Add count placeholder for critical applications marked message
maxkpower Nov 3, 2025
7aa3cf4
Merge branch 'main' into dirt/pm-27619/assign-tasks-dialog
maxkpower Nov 3, 2025
185e639
Merge branch 'main' into dirt/pm-27619/assign-tasks-dialog
Banrion Nov 3, 2025
1dd92f8
Address claude comments
Banrion Nov 3, 2025
32dd082
Merge remote-tracking branch 'refs/remotes/origin/dirt/pm-27619/assigโ€ฆ
Banrion Nov 3, 2025
bdda6e9
Merge branch 'main' into dirt/pm-27619/assign-tasks-dialog
maxkpower Nov 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/web/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
"message": "Members with access to at-risk items for critical applications"
},
"membersWithAtRiskPasswords": {
"message": "members with at-risk passwords"
"message": "Members with at-risk passwords"
},
"membersWillReceiveNotification": {
"message": "Members will receive a notification to resolve at-risk logins through the browser extension."
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿค” The size difference in these two video files surprise me. Is one compressed or built upon the other somehow?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch, one was attached as .mov to the ticket so I converted with ffmpeg. Will check / optimise

Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,22 @@
<!-- Left Panel -->
<div class="tw-flex tw-flex-col tw-gap-4 tw-flex-1">
<!-- Task Summary Info Card -->
<div
class="tw-flex tw-flex-col tw-p-6 tw-box-border tw-bg-secondary-100 tw-text-main tw-border-solid tw-border tw-border-secondary-300 tw-rounded-lg"
>
<div class="tw-flex tw-items-center tw-mb-3">
<i class="bwi bwi-info-circle tw-text-primary-600 tw-mr-2" aria-hidden="true"></i>
<span bitTypography="h6" class="tw-font-semibold">{{ "taskSummary" | i18n }}</span>
</div>

<div bitTypography="body1" class="tw-text-main">
<strong>{{ atRiskCriticalMembersCount() }}</strong>
{{ "membersWithAtRiskPasswords" | i18n }}
for
<strong>{{ criticalApplicationsCount() }}</strong>
{{ "criticalApplications" | i18n }}
</div>
</div>
<bit-callout type="info" [title]="'taskSummary' | i18n" class="tw-mb-6">
<strong>{{ atRiskCriticalMembersCount() }}</strong>
{{ "membersWithAtRiskPasswords" | i18n }}
for
<strong>{{ criticalApplicationsCount() }}</strong>
{{ "criticalApplications" | i18n }}
</bit-callout>

<!-- Stat Box: Members with At-Risk Passwords -->
<div class="tw-flex tw-items-start tw-gap-3">
<bit-icon-tile
icon="bwi-users"
variant="primary"
size="large"
aria-label=""
shape="circle"
aria-hidden="true"
></bit-icon-tile>
<div class="tw-flex tw-flex-col">
<span bitTypography="h2" class="tw-font-bold tw-mb-1">
Expand All @@ -45,7 +37,8 @@
icon="bwi-desktop"
variant="warning"
size="large"
aria-label=""
shape="circle"
aria-hidden="true"
></bit-icon-tile>
<div class="tw-flex tw-flex-col">
<div class="tw-flex tw-items-baseline tw-gap-2 tw-mb-1">
Expand All @@ -63,104 +56,21 @@
</div>
</div>

<!-- Right Panel: Browser Extension Mockup -->
<!-- Right Panel: Browser Extension Video -->
<div class="tw-flex tw-flex-col tw-gap-4 tw-flex-1">
<!-- Browser Extension Mockup -->
<div
class="tw-relative tw-bg-secondary-100 tw-rounded-lg tw-p-4 tw-border tw-border-secondary-300"
>
<!-- Browser Window Mockup -->
<div class="tw-bg-background tw-rounded tw-shadow-md tw-overflow-hidden">
<!-- Browser Top Bar -->
<div
class="tw-flex tw-items-center tw-gap-2 tw-bg-secondary-100 tw-px-3 tw-py-2 tw-border-b tw-border-secondary-300"
>
<div class="tw-flex tw-gap-1">
<div class="tw-size-3 tw-rounded-full tw-bg-secondary-300"></div>
<div class="tw-size-3 tw-rounded-full tw-bg-secondary-300"></div>
<div class="tw-size-3 tw-rounded-full tw-bg-secondary-300"></div>
</div>
<div
class="tw-flex-1 tw-bg-background tw-rounded tw-px-2 tw-py-1 tw-text-xs tw-text-muted tw-border tw-border-secondary-300"
>
example.com
</div>
<div class="tw-size-4 tw-bg-secondary-300 tw-rounded"></div>
</div>

<!-- Browser Content Area -->
<div class="tw-p-4 tw-bg-primary-100 tw-min-h-[200px] tw-relative">
<!-- Extension Popup Mockup -->
<div
class="tw-absolute tw-top-4 tw-right-4 tw-w-64 tw-bg-background tw-rounded-lg tw-shadow-lg tw-border tw-border-secondary-300 tw-p-4"
>
<!-- Extension Items -->
<div class="tw-space-y-3 tw-mb-4">
<div class="tw-flex tw-items-center tw-gap-2">
<div class="tw-size-6 tw-bg-secondary-300 tw-rounded"></div>
<div class="tw-flex-1 tw-h-2 tw-bg-secondary-300 tw-rounded"></div>
<button
type="button"
class="tw-text-xs tw-px-2 tw-py-1 tw-bg-secondary-100 tw-rounded tw-text-main"
>
{{ "change" | i18n }}
</button>
</div>
<div class="tw-flex tw-items-center tw-gap-2">
<div class="tw-size-6 tw-bg-secondary-300 tw-rounded"></div>
<div class="tw-flex-1 tw-h-2 tw-bg-secondary-300 tw-rounded"></div>
<button
type="button"
class="tw-text-xs tw-px-2 tw-py-1 tw-bg-secondary-100 tw-rounded tw-text-main"
>
{{ "change" | i18n }}
</button>
</div>
<div class="tw-flex tw-items-center tw-gap-2">
<div class="tw-size-6 tw-bg-secondary-300 tw-rounded"></div>
<div class="tw-flex-1 tw-h-2 tw-bg-secondary-300 tw-rounded"></div>
<button
type="button"
class="tw-text-xs tw-px-2 tw-py-1 tw-bg-secondary-100 tw-rounded tw-text-main"
>
{{ "change" | i18n }}
</button>
</div>
</div>

<!-- Review Section -->
<div class="tw-mb-4">
<div class="tw-h-3 tw-bg-secondary-300 tw-rounded tw-mb-2 tw-w-3/4"></div>
<div class="tw-h-2 tw-bg-secondary-300 tw-rounded tw-w-full tw-mb-1"></div>
<div class="tw-h-2 tw-bg-secondary-300 tw-rounded tw-w-5/6"></div>
</div>

<!-- Pagination Dots -->
<div class="tw-flex tw-justify-center tw-gap-1 tw-mb-3">
<div class="tw-size-1.5 tw-rounded-full tw-bg-primary-600"></div>
<div class="tw-size-1.5 tw-rounded-full tw-bg-secondary-300"></div>
<div class="tw-size-1.5 tw-rounded-full tw-bg-secondary-300"></div>
</div>

<!-- Review Button -->
<button
type="button"
class="tw-w-full tw-py-2 tw-bg-primary-600 tw-text-contrast tw-rounded tw-text-sm tw-font-semibold"
>
{{ "reviewAtRiskPasswords" | i18n }}
</button>
</div>

<!-- Mouse Cursor Mockup -->
<div
class="tw-absolute tw-top-8 tw-right-16 tw-size-4 tw-border-2 tw-border-text-main tw-bg-background"
></div>
</div>
</div>
</div>
<video
class="tw-w-full tw-rounded-lg"
autoplay
loop
muted
playsinline
src="/videos/access-intelligence-assign-tasks.mp4"
appDarkImgSrc="/videos/access-intelligence-assign-tasks-dark.mp4"
aria-hidden="true"
></video>

<!-- Description Text -->
<div bitTypography="body2" class="tw-text-muted">
<div bitTypography="helper" class="tw-text-muted">
{{ "membersWillReceiveNotification" | i18n }}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { CommonModule } from "@angular/common";
import { Component, input } from "@angular/core";
import { ChangeDetectionStrategy, Component, input } from "@angular/core";

import { ButtonModule, IconTileComponent, TypographyModule } from "@bitwarden/components";
import {
ButtonModule,
CalloutComponent,
IconTileComponent,
TypographyModule,
} from "@bitwarden/components";
import { I18nPipe } from "@bitwarden/ui-common";
import { DarkImageSourceDirective } from "@bitwarden/vault";

import { DefaultAdminTaskService } from "../../../../vault/services/default-admin-task.service";
import { AccessIntelligenceSecurityTasksService } from "../../shared/security-tasks.service";
Expand All @@ -17,12 +23,19 @@ import { AccessIntelligenceSecurityTasksService } from "../../shared/security-ta
* Without these providers, Angular would throw NullInjectorError when trying to inject
* DefaultAdminTaskService, which is required by AccessIntelligenceSecurityTasksService.
*/
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "dirt-assign-tasks-view",
templateUrl: "./assign-tasks-view.component.html",
imports: [CommonModule, ButtonModule, TypographyModule, I18nPipe, IconTileComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
CommonModule,
ButtonModule,
TypographyModule,
I18nPipe,
IconTileComponent,
DarkImageSourceDirective,
CalloutComponent,
],
providers: [AccessIntelligenceSecurityTasksService, DefaultAdminTaskService],
})
export class AssignTasksViewComponent {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<bit-dialog [dialogSize]="'default'">
<bit-dialog [dialogSize]="'large'">
<span bitDialogTitle>
{{
currentView() === DialogView.SelectApplications
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { CommonModule } from "@angular/common";
import { Component, DestroyRef, Inject, inject, signal } from "@angular/core";
import {
ChangeDetectionStrategy,
Component,
DestroyRef,
Inject,
inject,
signal,
} from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { from, switchMap } from "rxjs";

Expand All @@ -11,6 +18,7 @@ import {
} from "@bitwarden/bit-common/dirt/reports/risk-insights";
import { getUniqueMembers } from "@bitwarden/bit-common/dirt/reports/risk-insights/helpers";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { OrganizationId } from "@bitwarden/common/types/guid";
import {
ButtonModule,
Expand Down Expand Up @@ -58,11 +66,10 @@ export const NewApplicationsDialogResultType = Object.freeze({
export type NewApplicationsDialogResultType =
(typeof NewApplicationsDialogResultType)[keyof typeof NewApplicationsDialogResultType];

// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
@Component({
selector: "dirt-new-applications-dialog",
templateUrl: "./new-applications-dialog.component.html",
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
CommonModule,
ButtonModule,
Expand Down Expand Up @@ -101,6 +108,7 @@ export class NewApplicationsDialogComponent {
private toastService: ToastService,
private i18nService: I18nService,
private accessIntelligenceSecurityTasksService: AccessIntelligenceSecurityTasksService,
private logService: LogService,
) {}

/**
Expand Down Expand Up @@ -140,6 +148,11 @@ export class NewApplicationsDialogComponent {
}

handleMarkAsCritical() {
if (this.markingAsCritical() || this.saving()) {
return; // Prevent action if already processing
}
this.markingAsCritical.set(true);

const onlyNewCriticalApplications = this.dialogParams.newApplications.filter((newApp) =>
this.selectedApplications().has(newApp.applicationName),
);
Expand All @@ -150,6 +163,7 @@ export class NewApplicationsDialogComponent {
this.atRiskCriticalMembersCount.set(atRiskCriticalMembersCount);

this.currentView.set(DialogView.AssignTasks);
this.markingAsCritical.set(false);
}

/**
Expand Down Expand Up @@ -209,7 +223,11 @@ export class NewApplicationsDialogComponent {
this.saving.set(false);
this.handleAssigningCompleted();
},
error: () => {
error: (error: unknown) => {
this.logService.error(
"[NewApplicationsDialog] Failed to save application review or assign tasks",
error,
);
this.saving.set(false);
this.toastService.showToast({
variant: "error",
Expand Down