1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-06 19:53:59 +00:00

Merge branch 'main' into PM-29919-Add-dropdown-to-select-email-verification-and-emails-field-to-Send-when-creating-or-editing-a-Send

This commit is contained in:
bmbitwarden
2026-01-20 08:38:53 -05:00
committed by GitHub
26 changed files with 152 additions and 58 deletions

View File

@@ -582,8 +582,8 @@
"archiveItem": {
"message": "Archive item"
},
"archiveItemConfirmDesc": {
"message": "Archived items are excluded from general search results and autofill suggestions. Are you sure you want to archive this item?"
"archiveItemDialogContent": {
"message": "Once archived, this item will be excluded from search results and autofill suggestions."
},
"archived": {
"message": "Archived"

View File

@@ -376,7 +376,8 @@ export class ItemMoreOptionsComponent {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "archiveItem" },
content: { key: "archiveItemConfirmDesc" },
content: { key: "archiveItemDialogContent" },
acceptButtonText: { key: "archiveVerb" },
type: "info",
});

View File

@@ -42,9 +42,23 @@
<app-vault-icon [cipher]="cipher"></app-vault-icon>
</div>
<span data-testid="item-name">{{ cipher.name }}</span>
@if (CipherViewLikeUtils.hasAttachments(cipher)) {
<i class="bwi bwi-paperclip bwi-sm" [appA11yTitle]="'attachments' | i18n"></i>
}
<div slot="default-trailing" class="tw-flex tw-gap-1.5">
@if (cipher.organizationId) {
<i
appOrgIcon
[tierType]="orgTierType(cipher)"
[size]="'small'"
[appA11yTitle]="orgIconTooltip(cipher)"
></i>
}
@if (CipherViewLikeUtils.hasAttachments(cipher)) {
<i
slot="default-trailing"
class="bwi bwi-paperclip bwi-sm"
[appA11yTitle]="'attachments' | i18n"
></i>
}
</div>
<span slot="secondary">{{ CipherViewLikeUtils.subtitle(cipher) }}</span>
</button>
<bit-item-action slot="end">

View File

@@ -1,11 +1,13 @@
import { CommonModule } from "@angular/common";
import { Component, inject } from "@angular/core";
import { toSignal } from "@angular/core/rxjs-interop";
import { Router } from "@angular/router";
import { combineLatest, firstValueFrom, map, Observable, startWith, switchMap } from "rxjs";
import { CollectionService } from "@bitwarden/admin-console/common";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -33,6 +35,7 @@ import {
import {
CanDeleteCipherDirective,
DecryptionFailureDialogComponent,
OrgIconDirective,
PasswordRepromptService,
} from "@bitwarden/vault";
@@ -60,6 +63,7 @@ import { ROUTES_AFTER_EDIT_DELETION } from "../components/vault-v2/add-edit/add-
SectionComponent,
SectionHeaderComponent,
TypographyModule,
OrgIconDirective,
CardComponent,
ButtonComponent,
],
@@ -79,6 +83,26 @@ export class ArchiveComponent {
private userId$: Observable<UserId> = this.accountService.activeAccount$.pipe(getUserId);
private readonly orgMap = toSignal(
this.userId$.pipe(
switchMap((userId) =>
this.organizationService.organizations$(userId).pipe(
map((orgs) => {
const map = new Map<string, Organization>();
for (const org of orgs) {
map.set(org.id, org);
}
return map;
}),
),
),
),
);
private readonly collections = toSignal(
this.userId$.pipe(switchMap((userId) => this.collectionService.decryptedCollections$(userId))),
);
protected archivedCiphers$ = this.userId$.pipe(
switchMap((userId) => this.cipherArchiveService.archivedCiphers$(userId)),
);
@@ -242,4 +266,22 @@ export class ArchiveComponent {
return this.passwordRepromptService.passwordRepromptCheck(cipher);
}
/**
* Get the organization tier type for the given cipher.
*/
orgTierType({ organizationId }: CipherViewLike) {
return this.orgMap()?.get(organizationId as string)?.productTierType;
}
/**
* Get the organization icon tooltip for the given cipher.
*/
orgIconTooltip({ collectionIds }: CipherViewLike) {
if (collectionIds.length !== 1) {
return this.i18nService.t("nCollections", collectionIds.length);
}
return this.collections()?.find((c) => c.id === collectionIds[0])?.name;
}
}

View File

@@ -2949,9 +2949,9 @@ dependencies = [
[[package]]
name = "sha2"
version = "0.10.8"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",

View File

@@ -58,7 +58,7 @@ security-framework = "=3.5.1"
security-framework-sys = "=2.15.0"
serde = "=1.0.209"
serde_json = "=1.0.127"
sha2 = "=0.10.8"
sha2 = "=0.10.9"
ssh-encoding = "=0.2.0"
ssh-key = { version = "=0.6.7", default-features = false }
sysinfo = "=0.37.2"

View File

@@ -4397,8 +4397,8 @@
"archiveItem": {
"message": "Archive item"
},
"archiveItemConfirmDesc": {
"message": "Archived items are excluded from general search results and autofill suggestions. Are you sure you want to archive this item?"
"archiveItemDialogContent": {
"message": "Once archived, this item will be excluded from search results and autofill suggestions."
},
"unArchiveAndSave": {
"message": "Unarchive and save"

View File

@@ -12,7 +12,7 @@ import { VaultFilter, CollectionFilter } from "@bitwarden/vault";
imports: [A11yTitleDirective, NavigationModule],
})
export class CollectionFilterComponent {
protected readonly collection = input<TreeNode<CollectionFilter>>();
protected readonly collection = input.required<TreeNode<CollectionFilter>>();
protected readonly activeFilter = input<VaultFilter>();
protected readonly displayName = computed<string>(() => {

View File

@@ -13,7 +13,7 @@ import { VaultFilter, FolderFilter } from "@bitwarden/vault";
imports: [A11yTitleDirective, NavigationModule, IconButtonModule, I18nPipe],
})
export class FolderFilterComponent {
protected readonly folder = input<TreeNode<FolderFilter>>();
protected readonly folder = input.required<TreeNode<FolderFilter>>();
protected readonly activeFilter = input<VaultFilter>();
protected onEditFolder = output<FolderFilter>();

View File

@@ -1,3 +1,5 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Component, computed, input, inject } from "@angular/core";
import { DisplayMode } from "@bitwarden/angular/vault/vault-filter/models/display-mode";
@@ -20,7 +22,7 @@ export class OrganizationFilterComponent {
private vaultFilterService: VaultFilterServiceAbstraction = inject(VaultFilterServiceAbstraction);
protected readonly hide = input(false);
protected readonly organizations = input<TreeNode<OrganizationFilter>>();
protected readonly organizations = input.required<TreeNode<OrganizationFilter>>();
protected readonly activeFilter = input<VaultFilter>();
protected readonly activeOrganizationDataOwnership = input<boolean>(false);
protected readonly activeSingleOrganizationPolicy = input<boolean>(false);
@@ -56,7 +58,6 @@ export class OrganizationFilterComponent {
if (!organization.node.enabled) {
this.toastService.showToast({
variant: "error",
title: null,
message: this.i18nService.t("disabledOrganizationFilterError"),
});
return;

View File

@@ -6,10 +6,13 @@
[text]="archiveFilter.name | i18n"
[attr.aria-pressed]="activeFilter()?.isArchived"
[appA11yTitle]="archiveFilter.name | i18n"
/>
@if (!(canArchive$ | async)) {
<app-premium-badge />
}
>
@if (!(canArchive$ | async)) {
<ng-container slot="end">
<app-premium-badge />
</ng-container>
}
</bit-nav-item>
}
<bit-nav-item
[icon]="trashFilter.icon"

View File

@@ -1,3 +1,5 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { Component, viewChild, input, inject } from "@angular/core";
import { combineLatest, firstValueFrom, map, switchMap } from "rxjs";
@@ -23,7 +25,10 @@ export class StatusFilterComponent {
private cipherArchiveService: CipherArchiveService = inject(CipherArchiveService);
protected readonly hideArchive = input(false);
protected readonly activeFilter = input<VaultFilter>();
protected readonly activeFilter = input.required<VaultFilter>();
private readonly premiumBadgeComponent = viewChild(PremiumBadgeComponent);
protected readonly archiveFilter: CipherTypeFilter = {
id: "archive",
name: "archiveNoun",
@@ -38,7 +43,7 @@ export class StatusFilterComponent {
};
protected applyFilter(filterType: CipherStatus) {
let filter: CipherTypeFilter = null;
let filter: CipherTypeFilter | null = null;
if (filterType === "archive") {
filter = this.archiveFilter;
} else if (filterType === "trash") {
@@ -50,8 +55,6 @@ export class StatusFilterComponent {
}
}
private readonly premiumBadgeComponent = viewChild.required(PremiumBadgeComponent);
private userId$ = this.accountService.activeAccount$.pipe(getUserId);
protected canArchive$ = this.userId$.pipe(
switchMap((userId) => this.cipherArchiveService.userCanArchive$(userId)),
@@ -71,7 +74,7 @@ export class StatusFilterComponent {
if (canArchive || hasArchivedCiphers) {
this.applyFilter("archive");
} else {
await this.premiumBadgeComponent().promptForPremium(event);
await this.premiumBadgeComponent()?.promptForPremium(event);
}
}
}

View File

@@ -20,7 +20,7 @@ export class TypeFilterComponent {
RestrictedItemTypesService,
);
protected readonly cipherTypes = input<TreeNode<CipherTypeFilter>>();
protected readonly cipherTypes = input.required<TreeNode<CipherTypeFilter>>();
protected readonly activeFilter = input<VaultFilter>();
protected applyTypeFilter(event: Event, cipherType: TreeNode<CipherTypeFilter>) {

View File

@@ -1,3 +1,5 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { Component, inject, OnInit, output, computed, signal } from "@angular/core";
import { firstValueFrom, Observable, Subject, takeUntil } from "rxjs";

View File

@@ -1,3 +1,5 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit, ViewChild } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";

View File

@@ -746,7 +746,8 @@ export class VaultComponent<C extends CipherViewLike> implements OnInit, OnDestr
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "archiveItem" },
content: { key: "archiveItemConfirmDesc" },
content: { key: "archiveItemDialogContent" },
acceptButtonText: { key: "archiveVerb" },
type: "info",
});

View File

@@ -11707,8 +11707,8 @@
"message": "Archive item",
"description": "Verb"
},
"archiveItemConfirmDesc": {
"message": "Archived items are excluded from general search results and autofill suggestions. Are you sure you want to archive this item?"
"archiveItemDialogContent": {
"message": "Once archived, this item will be excluded from search results and autofill suggestions."
},
"archiveBulkItems": {
"message": "Archive items",