1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-28 12:45:45 +01:00

[PM-14038] - priority applications UI (#11723)

* priority applications UI

* add security icon
This commit is contained in:
Jordan Aasen 2024-10-30 11:25:06 -07:00 committed by GitHub
parent ab3d760dfd
commit 18f7d64a6d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 145 additions and 18 deletions

View File

@ -11,5 +11,5 @@ import { ButtonModule, NoItemsModule, Icons } from "@bitwarden/components";
imports: [ButtonModule, CommonModule, JslibModule, NoItemsModule], imports: [ButtonModule, CommonModule, JslibModule, NoItemsModule],
}) })
export class NoPriorityAppsComponent { export class NoPriorityAppsComponent {
noItemsIcon = Icons.NoResults; noItemsIcon = Icons.Security;
} }

View File

@ -1,4 +1,3 @@
<bit-container>
<p>{{ "passwordsReportDesc" | i18n }}</p> <p>{{ "passwordsReportDesc" | i18n }}</p>
<div *ngIf="loading"> <div *ngIf="loading">
<i <i
@ -8,7 +7,7 @@
></i> ></i>
<span class="tw-sr-only">{{ "loading" | i18n }}</span> <span class="tw-sr-only">{{ "loading" | i18n }}</span>
</div> </div>
<div *ngIf="!dataSource.data.length"> <div class="tw-mt-4" *ngIf="!dataSource.data.length">
<tools-no-priority-apps></tools-no-priority-apps> <tools-no-priority-apps></tools-no-priority-apps>
</div> </div>
<div class="tw-mt-4 tw-flex tw-flex-col" *ngIf="!loading && dataSource.data.length"> <div class="tw-mt-4 tw-flex tw-flex-col" *ngIf="!loading && dataSource.data.length">
@ -35,6 +34,38 @@
{{ "markAppAsCritical" | i18n }} {{ "markAppAsCritical" | i18n }}
</button> </button>
</div> </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"> <bit-table [dataSource]="dataSource">
<ng-container header> <ng-container header>
<tr bitRow> <tr bitRow>
@ -47,9 +78,14 @@
</tr> </tr>
</ng-container> </ng-container>
<ng-template body let-rows$> <ng-template body let-rows$>
<tr bitRow *ngFor="let r of rows$ | async"> <tr bitRow *ngFor="let r of rows$ | async; trackBy: trackByFunction">
<td bitCell> <td bitCell>
<app-vault-icon [cipher]="r"></app-vault-icon> <input
bitCheckbox
type="checkbox"
[checked]="selectedIds.has(r.id)"
(change)="onCheckboxChange(r.id, $event)"
/>
</td> </td>
<td bitCell> <td bitCell>
<ng-container> <ng-container>
@ -84,4 +120,4 @@
</ng-template> </ng-template>
</bit-table> </bit-table>
</div> </div>
</bit-container> </div>

View File

@ -11,7 +11,13 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { BadgeVariant, SearchModule, TableDataSource, TableModule } from "@bitwarden/components"; import {
BadgeVariant,
SearchModule,
TableDataSource,
TableModule,
ToastService,
} from "@bitwarden/components";
import { CardComponent } from "@bitwarden/tools-card"; import { CardComponent } from "@bitwarden/tools-card";
import { HeaderModule } from "../../layouts/header/header.module"; import { HeaderModule } from "../../layouts/header/header.module";
@ -53,6 +59,8 @@ export class PasswordHealthMembersComponent implements OnInit {
loading = true; loading = true;
selectedIds: Set<number> = new Set<number>();
protected searchControl = new FormControl("", { nonNullable: true }); protected searchControl = new FormControl("", { nonNullable: true });
private destroyRef = inject(DestroyRef); private destroyRef = inject(DestroyRef);
@ -63,6 +71,7 @@ export class PasswordHealthMembersComponent implements OnInit {
protected auditService: AuditService, protected auditService: AuditService,
protected i18nService: I18nService, protected i18nService: I18nService,
protected activatedRoute: ActivatedRoute, protected activatedRoute: ActivatedRoute,
protected toastService: ToastService,
) { ) {
this.searchControl.valueChanges this.searchControl.valueChanges
.pipe(debounceTime(200), takeUntilDestroyed()) .pipe(debounceTime(200), takeUntilDestroyed())
@ -91,7 +100,7 @@ export class PasswordHealthMembersComponent implements OnInit {
await passwordHealthService.generateReport(); await passwordHealthService.generateReport();
this.dataSource.data = passwordHealthService.reportCiphers; this.dataSource.data = []; //passwordHealthService.reportCiphers;
this.exposedPasswordMap = passwordHealthService.exposedPasswordMap; this.exposedPasswordMap = passwordHealthService.exposedPasswordMap;
this.passwordStrengthMap = passwordHealthService.passwordStrengthMap; this.passwordStrengthMap = passwordHealthService.passwordStrengthMap;
@ -99,4 +108,32 @@ export class PasswordHealthMembersComponent implements OnInit {
this.totalMembersMap = passwordHealthService.totalMembersMap; this.totalMembersMap = passwordHealthService.totalMembersMap;
this.loading = false; this.loading = false;
} }
markAppsAsCritical = async () => {
// TODO: Send to API once implemented
return new Promise((resolve) => {
setTimeout(() => {
this.selectedIds.clear();
this.toastService.showToast({
variant: "success",
title: null,
message: this.i18nService.t("appsMarkedAsCritical"),
});
resolve(true);
}, 1000);
});
};
trackByFunction(_: number, item: CipherView) {
return item.id;
}
onCheckboxChange(id: number, event: Event) {
const isChecked = (event.target as HTMLInputElement).checked;
if (isChecked) {
this.selectedIds.add(id);
} else {
this.selectedIds.delete(id);
}
}
} }

View File

@ -65,6 +65,9 @@
"markAppAsCritical": { "markAppAsCritical": {
"message": "Mark app as critical" "message": "Mark app as critical"
}, },
"appsMarkedAsCritical": {
"message": "Apps marked as critical"
},
"application": { "application": {
"message": "Application" "message": "Application"
}, },

View File

@ -1,3 +1,4 @@
export * from "./search"; export * from "./search";
export * from "./security";
export * from "./no-access"; export * from "./no-access";
export * from "./no-results"; export * from "./no-results";

View File

@ -0,0 +1,50 @@
import { svgIcon } from "../icon";
export const Security = svgIcon`
<svg width="96" height="96" viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="96" height="96" class="tw-fill-background"/>
<rect x="5" y="5" width="86" height="77" rx="7" class="tw-stroke-art-primary" stroke-width="2" stroke-linecap="round"/>
<rect x="63" y="15" width="18" height="18" rx="3" class="tw-stroke-art-primary" stroke-width="2" stroke-linecap="round"/>
<rect x="39" y="15" width="18" height="18" rx="3" class="tw-stroke-art-primary" stroke-width="2" stroke-linecap="round"/>
<rect x="15" y="15" width="18" height="18" rx="3" class="tw-stroke-art-primary" stroke-width="2" stroke-linecap="round"/>
<rect x="13" y="41" width="70" height="14" rx="7" class="tw-stroke-art-primary tw-fill-background" stroke-width="2" stroke-linecap="round"/>
<path d="M21.0039 48.3526V45.5728" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21.0039 48.3525L23.6272 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21.0039 48.3524L22.6279 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21.0029 48.3524L19.3789 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21.0022 48.3525L18.3789 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M30.0039 48.3526V45.5728" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M30.0039 48.3525L32.6272 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M30.0039 48.3524L31.6279 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M30.0029 48.3524L28.3789 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M30.0022 48.3525L27.3789 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M39.0039 48.3526V45.5728" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M39.0039 48.3525L41.6272 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M39.0039 48.3524L40.6279 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M39.0029 48.3524L37.3789 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M39.0022 48.3525L36.3789 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M48.0039 48.3526V45.5728" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M48.0039 48.3525L50.6272 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M48.0039 48.3524L49.6279 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M48.0029 48.3524L46.3789 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M48.0022 48.3525L45.3789 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M57.0039 48.3526V45.5728" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M57.0039 48.3525L59.6272 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M57.0039 48.3524L58.6279 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M57.0029 48.3524L55.3789 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M57.0022 48.3525L54.3789 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M66.0039 48.3526V45.5728" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M66.0039 48.3525L68.6272 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M66.0039 48.3524L67.6279 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M66.0029 48.3524L64.3789 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M66.0022 48.3525L63.3789 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M75.0039 48.3526V45.5728" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M75.0039 48.3525L77.6272 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M75.0039 48.3524L76.6279 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M75.0029 48.3524L73.3789 50.6268" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M75.0022 48.3525L72.3789 47.4933" class="tw-stroke-art-accent" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="35" y="72" width="26" height="20" rx="2" class="tw-stroke-art-primary tw-fill-background" stroke-width="2"/>
<rect x="47" y="78" width="2" height="8" rx="1" class="tw-stroke-art-accent"/>
<path d="M55 71V69C55 65.134 51.866 62 48 62V62C44.134 62 41 65.134 41 69V71" class="tw-stroke-art-primary" stroke-width="2"/>
</svg>
`;