From 69264c884147728fa8a4d27c2326454d6ffa8496 Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:43:42 +0100 Subject: [PATCH 01/23] [PM-32212] Migrate platform font icons to bit-icon (#18970) * Changes on browser * Changes on desktop * Changes on web * Fix chromatic story --------- Co-authored-by: Daniel James Smith --- .../popup/layout/popup-page.component.html | 2 +- .../popup/layout/popup-page.component.ts | 4 +- .../src/app/accounts/settings.component.html | 42 ++++++------------- .../src/app/accounts/settings.component.ts | 2 + .../layout/account-switcher.component.html | 17 +++----- .../app/layout/search/search.component.html | 2 +- apps/desktop/src/app/shared/shared.module.ts | 3 ++ apps/desktop/src/index.html | 1 + .../environment-selector.component.html | 10 ++--- .../layouts/header/web-header.component.html | 10 ++--- .../org-switcher/org-switcher.component.html | 17 ++++---- .../account-fingerprint.component.html | 2 +- .../onboarding/onboarding-task.component.html | 8 +++- .../onboarding/onboarding-task.component.ts | 4 +- .../onboarding/onboarding.component.html | 8 +--- .../onboarding/onboarding.stories.ts | 4 +- apps/web/src/app/shared/shared.module.ts | 3 ++ .../platform/proxy-cookie-redirect.html | 1 + apps/web/src/index.html | 1 + 19 files changed, 66 insertions(+), 75 deletions(-) diff --git a/apps/browser/src/platform/popup/layout/popup-page.component.html b/apps/browser/src/platform/popup/layout/popup-page.component.html index bb24fb800aa..dc07d025e60 100644 --- a/apps/browser/src/platform/popup/layout/popup-page.component.html +++ b/apps/browser/src/platform/popup/layout/popup-page.component.html @@ -40,7 +40,7 @@ class="tw-absolute tw-inset-0 tw-flex tw-items-center tw-justify-center tw-text-main" [ngClass]="{ 'tw-invisible': !loading() }" > - + diff --git a/apps/browser/src/platform/popup/layout/popup-page.component.ts b/apps/browser/src/platform/popup/layout/popup-page.component.ts index 7d4b7decb7f..e661bf2ca00 100644 --- a/apps/browser/src/platform/popup/layout/popup-page.component.ts +++ b/apps/browser/src/platform/popup/layout/popup-page.component.ts @@ -13,7 +13,7 @@ import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { filter, switchMap, fromEvent, startWith, map } from "rxjs"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { ScrollLayoutHostDirective, ScrollLayoutService } from "@bitwarden/components"; +import { IconModule, ScrollLayoutHostDirective, ScrollLayoutService } from "@bitwarden/components"; @Component({ selector: "popup-page", @@ -21,7 +21,7 @@ import { ScrollLayoutHostDirective, ScrollLayoutService } from "@bitwarden/compo host: { class: "tw-h-full tw-flex tw-flex-col tw-overflow-y-hidden", }, - imports: [CommonModule, ScrollLayoutHostDirective], + imports: [CommonModule, IconModule, ScrollLayoutHostDirective], changeDetection: ChangeDetectionStrategy.OnPush, }) export class PopupPageComponent { diff --git a/apps/desktop/src/app/accounts/settings.component.html b/apps/desktop/src/app/accounts/settings.component.html index d5042918d2f..90ff8f3a791 100644 --- a/apps/desktop/src/app/accounts/settings.component.html +++ b/apps/desktop/src/app/accounts/settings.component.html @@ -16,16 +16,10 @@ [attr.aria-expanded]="showSecurity" appAutofocus > - - + {{ "security" | i18n }} @@ -147,16 +141,10 @@ (click)="showAccountPreferences = !showAccountPreferences" [attr.aria-expanded]="showAccountPreferences" > - - + {{ "accountPreferences" | i18n }} @@ -222,16 +210,10 @@ (click)="showAppPreferences = !showAppPreferences" [attr.aria-expanded]="showAppPreferences" > - - + {{ "appPreferences" | i18n }} diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts index f2e828b95ce..7bab7db3c29 100644 --- a/apps/desktop/src/app/accounts/settings.component.ts +++ b/apps/desktop/src/app/accounts/settings.component.ts @@ -45,6 +45,7 @@ import { DialogService, FormFieldModule, IconButtonModule, + IconModule, ItemModule, LinkModule, SectionComponent, @@ -89,6 +90,7 @@ import { NativeMessagingManifestService } from "../services/native-messaging-man FormsModule, ReactiveFormsModule, IconButtonModule, + IconModule, ItemModule, JslibModule, LinkModule, diff --git a/apps/desktop/src/app/layout/account-switcher.component.html b/apps/desktop/src/app/layout/account-switcher.component.html index ef177ea1bb6..7d0ee8fac83 100644 --- a/apps/desktop/src/app/layout/account-switcher.component.html +++ b/apps/desktop/src/app/layout/account-switcher.component.html @@ -31,11 +31,7 @@ {{ "switchAccount" | i18n }} - + ) - + class="bwi-2x text-muted" + >
diff --git a/apps/desktop/src/app/layout/search/search.component.html b/apps/desktop/src/app/layout/search/search.component.html index 515385c2076..b5bcd264897 100644 --- a/apps/desktop/src/app/layout/search/search.component.html +++ b/apps/desktop/src/app/layout/search/search.component.html @@ -7,5 +7,5 @@ [formControl]="searchText" appAutofocus /> - + diff --git a/apps/desktop/src/app/shared/shared.module.ts b/apps/desktop/src/app/shared/shared.module.ts index 6eed4a197f3..85b3b800e83 100644 --- a/apps/desktop/src/app/shared/shared.module.ts +++ b/apps/desktop/src/app/shared/shared.module.ts @@ -7,6 +7,7 @@ import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { IconModule } from "@bitwarden/components"; import { AvatarComponent } from "../components/avatar.component"; import { ServicesModule } from "../services/services.module"; @@ -17,6 +18,7 @@ import { ServicesModule } from "../services/services.module"; A11yModule, DragDropModule, FormsModule, + IconModule, JslibModule, OverlayModule, ReactiveFormsModule, @@ -30,6 +32,7 @@ import { ServicesModule } from "../services/services.module"; DatePipe, DragDropModule, FormsModule, + IconModule, JslibModule, OverlayModule, ReactiveFormsModule, diff --git a/apps/desktop/src/index.html b/apps/desktop/src/index.html index 37eb64adf35..044d7eb0e2f 100644 --- a/apps/desktop/src/index.html +++ b/apps/desktop/src/index.html @@ -13,6 +13,7 @@ +
diff --git a/apps/web/src/app/components/environment-selector/environment-selector.component.html b/apps/web/src/app/components/environment-selector/environment-selector.component.html index 9862f62c2e2..44039bfe605 100644 --- a/apps/web/src/app/components/environment-selector/environment-selector.component.html +++ b/apps/web/src/app/components/environment-selector/environment-selector.component.html @@ -7,11 +7,11 @@ region == currentRegion ? 'javascript:void(0)' : region.urls.webVault + routeAndParams " > - + > {{ region.domain }} @@ -19,7 +19,7 @@ {{ "accessing" | i18n }}: {{ currentRegion?.domain }} - + diff --git a/apps/web/src/app/layouts/header/web-header.component.html b/apps/web/src/app/layouts/header/web-header.component.html index 995169e3dc1..9288c96237e 100644 --- a/apps/web/src/app/layouts/header/web-header.component.html +++ b/apps/web/src/app/layouts/header/web-header.component.html @@ -60,11 +60,11 @@ - + {{ "accountSettings" | i18n }} - + {{ "getHelp" | i18n }} - + {{ "getApps" | i18n }} diff --git a/apps/web/src/app/layouts/org-switcher/org-switcher.component.html b/apps/web/src/app/layouts/org-switcher/org-switcher.component.html index a9acddeb0b8..b8f7c5ab0c0 100644 --- a/apps/web/src/app/layouts/org-switcher/org-switcher.component.html +++ b/apps/web/src/app/layouts/org-switcher/org-switcher.component.html @@ -7,13 +7,14 @@ [routerLinkActiveOptions]="{ exact: true }" [(open)]="open" > - + > - + > -
{{ fingerprint }} diff --git a/apps/web/src/app/shared/components/onboarding/onboarding-task.component.html b/apps/web/src/app/shared/components/onboarding/onboarding-task.component.html index f0c0b01e06e..e52771a282b 100644 --- a/apps/web/src/app/shared/components/onboarding/onboarding-task.component.html +++ b/apps/web/src/app/shared/components/onboarding/onboarding-task.component.html @@ -1,10 +1,14 @@ - {{ title }}{{ title }} diff --git a/apps/web/src/app/shared/components/onboarding/onboarding-task.component.ts b/apps/web/src/app/shared/components/onboarding/onboarding-task.component.ts index 277a4d2d26e..47a618a1269 100644 --- a/apps/web/src/app/shared/components/onboarding/onboarding-task.component.ts +++ b/apps/web/src/app/shared/components/onboarding/onboarding-task.component.ts @@ -2,6 +2,8 @@ // @ts-strict-ignore import { Component, Input } from "@angular/core"; +import { BitwardenIcon } from "@bitwarden/components"; + // FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush // eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @Component({ @@ -21,7 +23,7 @@ export class OnboardingTaskComponent { // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals // eslint-disable-next-line @angular-eslint/prefer-signals @Input() - icon = "bwi-info-circle"; + icon: BitwardenIcon = "bwi-info-circle"; // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals // eslint-disable-next-line @angular-eslint/prefer-signals diff --git a/apps/web/src/app/shared/components/onboarding/onboarding.component.html b/apps/web/src/app/shared/components/onboarding/onboarding.component.html index 2433ec51fcc..ca98ceb8fbf 100644 --- a/apps/web/src/app/shared/components/onboarding/onboarding.component.html +++ b/apps/web/src/app/shared/components/onboarding/onboarding.component.html @@ -6,11 +6,7 @@ {{ "complete" | i18n: amountCompleted : tasks.length }} - +
    @@ -24,5 +20,5 @@ - + diff --git a/apps/web/src/app/shared/components/onboarding/onboarding.stories.ts b/apps/web/src/app/shared/components/onboarding/onboarding.stories.ts index 6873700e2bc..26c951fb11f 100644 --- a/apps/web/src/app/shared/components/onboarding/onboarding.stories.ts +++ b/apps/web/src/app/shared/components/onboarding/onboarding.stories.ts @@ -4,7 +4,7 @@ import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/an import { delay, of, startWith } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { LinkModule, SvgModule, ProgressModule } from "@bitwarden/components"; +import { LinkModule, SvgModule, ProgressModule, IconModule } from "@bitwarden/components"; import { PreloadedEnglishI18nModule } from "../../../core/tests"; @@ -16,7 +16,7 @@ export default { component: OnboardingComponent, decorators: [ moduleMetadata({ - imports: [JslibModule, RouterModule, LinkModule, SvgModule, ProgressModule], + imports: [JslibModule, RouterModule, LinkModule, IconModule, SvgModule, ProgressModule], declarations: [OnboardingTaskComponent], }), applicationConfig({ diff --git a/apps/web/src/app/shared/shared.module.ts b/apps/web/src/app/shared/shared.module.ts index b83555fd84e..729238e0b0d 100644 --- a/apps/web/src/app/shared/shared.module.ts +++ b/apps/web/src/app/shared/shared.module.ts @@ -18,6 +18,7 @@ import { DialogModule, FormFieldModule, IconButtonModule, + IconModule, SvgModule, LinkModule, MenuModule, @@ -63,6 +64,7 @@ import { DialogModule, FormFieldModule, IconButtonModule, + IconModule, SvgModule, LinkModule, MenuModule, @@ -99,6 +101,7 @@ import { DialogModule, FormFieldModule, IconButtonModule, + IconModule, SvgModule, LinkModule, MenuModule, diff --git a/apps/web/src/connectors/platform/proxy-cookie-redirect.html b/apps/web/src/connectors/platform/proxy-cookie-redirect.html index 1daa6d2e412..1918fcd771c 100644 --- a/apps/web/src/connectors/platform/proxy-cookie-redirect.html +++ b/apps/web/src/connectors/platform/proxy-cookie-redirect.html @@ -18,6 +18,7 @@
    Bitwarden
    +
    + Date: Fri, 13 Feb 2026 10:02:36 -0500 Subject: [PATCH 02/23] [PM-32075] Fix self host bug due to type mismatch (#18919) * fix self host bug with data model * fix type issues * fix types, make successful required --- .../members/components/bulk/bulk-status.component.ts | 5 ++--- .../members/deprecated_members.component.ts | 2 +- .../organizations/members/members.component.spec.ts | 4 ++-- .../organizations/members/members.component.ts | 2 +- .../member-actions/member-actions.service.spec.ts | 2 +- .../services/member-actions/member-actions.service.ts | 8 ++------ .../member-dialog-manager.service.ts | 4 +++- .../providers/manage/deprecated_members.component.ts | 10 ++++++---- .../providers/manage/members.component.ts | 10 ++++++---- 9 files changed, 24 insertions(+), 23 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-status.component.ts b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-status.component.ts index 5c9bf919ed4..cfddb17627a 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-status.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-status.component.ts @@ -9,7 +9,6 @@ import { } from "@bitwarden/common/admin-console/enums"; import { ProviderUserBulkResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user-bulk.response"; import { ProviderUserUserDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user.response"; -import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { DIALOG_DATA, DialogConfig, DialogService } from "@bitwarden/components"; @@ -34,7 +33,7 @@ type BulkStatusEntry = { type BulkStatusDialogData = { users: Array; filteredUsers: Array; - request: Promise>; + request: Promise; successfulMessage: string; }; @@ -63,7 +62,7 @@ export class BulkStatusComponent implements OnInit { async showBulkStatus(data: BulkStatusDialogData) { try { const response = await data.request; - const keyedErrors: any = response.data + const keyedErrors: any = (response ?? []) .filter((r) => r.error !== "") .reduce((a, x) => ({ ...a, [x.id]: x.error }), {}); const keyedFilteredUsers: any = data.filteredUsers.reduce( diff --git a/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.ts b/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.ts index dae9bafbcfe..1f1e19e2a6f 100644 --- a/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.ts @@ -446,7 +446,7 @@ export class MembersComponent extends BaseMembersComponent try { const result = await this.memberActionsService.bulkReinvite(organization, filteredUsers); - if (!result.successful) { + if (result.successful.length === 0) { throw new Error(); } diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.spec.ts b/apps/web/src/app/admin-console/organizations/members/members.component.spec.ts index 1cd90989b12..9a371de1acd 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.spec.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.component.spec.ts @@ -515,7 +515,7 @@ describe("vNextMembersComponent", () => { }; jest.spyOn(component["dataSource"](), "isIncreasedBulkLimitEnabled").mockReturnValue(false); jest.spyOn(component["dataSource"](), "getCheckedUsers").mockReturnValue([invitedUser]); - mockMemberActionsService.bulkReinvite.mockResolvedValue({ successful: true }); + mockMemberActionsService.bulkReinvite.mockResolvedValue({ successful: [{}], failed: [] }); await component.bulkReinvite(mockOrg); @@ -549,7 +549,7 @@ describe("vNextMembersComponent", () => { jest.spyOn(component["dataSource"](), "isIncreasedBulkLimitEnabled").mockReturnValue(false); jest.spyOn(component["dataSource"](), "getCheckedUsers").mockReturnValue([invitedUser]); const error = new Error("Bulk reinvite failed"); - mockMemberActionsService.bulkReinvite.mockResolvedValue({ successful: false, failed: error }); + mockMemberActionsService.bulkReinvite.mockResolvedValue({ successful: [], failed: error }); await component.bulkReinvite(mockOrg); diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.ts b/apps/web/src/app/admin-console/organizations/members/members.component.ts index 6139c5f07a5..826bdfb5f69 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.component.ts @@ -426,7 +426,7 @@ export class vNextMembersComponent { const result = await this.memberActionsService.bulkReinvite(organization, filteredUsers); - if (!result.successful) { + if (result.successful.length === 0) { this.validationService.showError(result.failed); } diff --git a/apps/web/src/app/admin-console/organizations/members/services/member-actions/member-actions.service.spec.ts b/apps/web/src/app/admin-console/organizations/members/services/member-actions/member-actions.service.spec.ts index 688c7ed77ce..1ba056a24f6 100644 --- a/apps/web/src/app/admin-console/organizations/members/services/member-actions/member-actions.service.spec.ts +++ b/apps/web/src/app/admin-console/organizations/members/services/member-actions/member-actions.service.spec.ts @@ -507,7 +507,7 @@ describe("MemberActionsService", () => { const result = await service.bulkReinvite(mockOrganization, users); - expect(result.successful).toBeUndefined(); + expect(result.successful).toHaveLength(0); expect(result.failed).toHaveLength(totalUsers); expect(result.failed.every((f) => f.error === errorMessage)).toBe(true); expect(organizationUserApiService.postManyOrganizationUserReinvite).toHaveBeenCalledTimes(2); diff --git a/apps/web/src/app/admin-console/organizations/members/services/member-actions/member-actions.service.ts b/apps/web/src/app/admin-console/organizations/members/services/member-actions/member-actions.service.ts index e5f8c0c6673..7d573c8eeef 100644 --- a/apps/web/src/app/admin-console/organizations/members/services/member-actions/member-actions.service.ts +++ b/apps/web/src/app/admin-console/organizations/members/services/member-actions/member-actions.service.ts @@ -37,11 +37,7 @@ export interface MemberActionResult { } export class BulkActionResult { - constructor() { - this.failed = []; - } - - successful?: OrganizationUserBulkResponse[]; + successful: OrganizationUserBulkResponse[] = []; failed: { id: string; error: string }[] = []; } @@ -316,7 +312,7 @@ export class MemberActionsService { } return { - successful: allSuccessful.length > 0 ? allSuccessful : undefined, + successful: allSuccessful, failed: allFailed, }; } diff --git a/apps/web/src/app/admin-console/organizations/members/services/member-dialog-manager/member-dialog-manager.service.ts b/apps/web/src/app/admin-console/organizations/members/services/member-dialog-manager/member-dialog-manager.service.ts index 18106031fd0..6c367692376 100644 --- a/apps/web/src/app/admin-console/organizations/members/services/member-dialog-manager/member-dialog-manager.service.ts +++ b/apps/web/src/app/admin-console/organizations/members/services/member-dialog-manager/member-dialog-manager.service.ts @@ -1,8 +1,10 @@ import { Injectable, WritableSignal } from "@angular/core"; import { firstValueFrom, lastValueFrom } from "rxjs"; +import { OrganizationUserBulkResponse } from "@bitwarden/admin-console/common"; import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { ProviderUserBulkResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user-bulk.response"; import { ProductTierType } from "@bitwarden/common/billing/enums"; import { OrganizationBillingMetadataResponse } from "@bitwarden/common/billing/models/response/organization-billing-metadata.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -197,7 +199,7 @@ export class MemberDialogManagerService { async openBulkStatusDialog( users: OrganizationUserView[], filteredUsers: OrganizationUserView[], - request: Promise, + request: Promise, successMessage: string, ): Promise { const dialogRef = BulkStatusComponent.open(this.dialogService, { diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.ts index 1b1ae25c027..464b9982689 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.ts @@ -223,10 +223,12 @@ export class MembersComponent extends BaseMembersComponent { } } else { // Feature flag disabled - show legacy dialog - const request = this.apiService.postManyProviderUserReinvite( - this.providerId, - new ProviderUserBulkRequest(checkedInvitedUsers.map((user) => user.id)), - ); + const request = this.apiService + .postManyProviderUserReinvite( + this.providerId, + new ProviderUserBulkRequest(checkedInvitedUsers.map((user) => user.id)), + ) + .then((response) => response.data); const dialogRef = BulkStatusComponent.open(this.dialogService, { data: { diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/members.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/members.component.ts index c63bda449c5..308b93ac2e3 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/members.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/members.component.ts @@ -236,10 +236,12 @@ export class vNextMembersComponent { } } else { // In self-hosted environments, show legacy dialog - const request = this.apiService.postManyProviderUserReinvite( - providerId, - new ProviderUserBulkRequest(checkedInvitedUsers.map((user) => user.id)), - ); + const request = this.apiService + .postManyProviderUserReinvite( + providerId, + new ProviderUserBulkRequest(checkedInvitedUsers.map((user) => user.id)), + ) + .then((response) => response.data); const dialogRef = BulkStatusComponent.open(this.dialogService, { data: { From b567fea7e77ecb3a1f30afb2d6acfddb644f6330 Mon Sep 17 00:00:00 2001 From: Jared Date: Fri, 13 Feb 2026 11:38:35 -0500 Subject: [PATCH 03/23] [PM-29506] Rid of old feature flag for members feature flag (#18884) * [PM-31750] Refactor members routing and user confirmation logic * Simplified user confirmation process by removing feature flag checks. * Updated routing to directly use the new members component without feature flagging. * Removed deprecated members component references from routing modules. * Cleaned up feature flag enum by removing unused entries. * trigger claude * [PM-31750] Refactor members component and remove deprecated files * Renamed vNextMembersComponent to MembersComponent for consistency. * Removed deprecated_members.component.ts and associated HTML files. * Updated routing and references to use the new MembersComponent. * Cleaned up related tests to reflect the component name change. * Refactor import statements in security-tasks.service.ts for improved readability * Update apps/web/src/app/admin-console/organizations/manage/user-confirm.component.ts Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> * Remove BaseMembersComponent and related imports from the admin console, streamlining member management functionality. * Remove unused ConfigService import from UserConfirmComponent to clean up code. * Implement feature flag logic for user restoration in MemberDialogComponent, allowing conditional restoration based on DefaultUserCollectionRestore flag. --------- Co-authored-by: Thomas Rittson Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> --- .../common/base-members.component.ts | 245 ------- .../manage/user-confirm.component.ts | 13 - .../member-dialog/member-dialog.component.ts | 2 +- .../members/deprecated_members.component.html | 495 -------------- .../members/deprecated_members.component.ts | 624 ------------------ .../members/members-routing.module.ts | 23 +- .../members/members.component.spec.ts | 14 +- .../members/members.component.ts | 2 +- .../organizations/members/members.module.ts | 4 +- .../manage/deprecated_members.component.html | 225 ------- .../manage/deprecated_members.component.ts | 351 ---------- .../providers/manage/members.component.ts | 2 +- .../providers/providers-routing.module.ts | 27 +- .../providers/providers.module.ts | 4 +- .../shared/security-tasks.service.ts | 6 +- libs/common/src/enums/feature-flag.enum.ts | 2 - 16 files changed, 34 insertions(+), 2005 deletions(-) delete mode 100644 apps/web/src/app/admin-console/common/base-members.component.ts delete mode 100644 apps/web/src/app/admin-console/organizations/members/deprecated_members.component.html delete mode 100644 apps/web/src/app/admin-console/organizations/members/deprecated_members.component.ts delete mode 100644 bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.html delete mode 100644 bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.ts diff --git a/apps/web/src/app/admin-console/common/base-members.component.ts b/apps/web/src/app/admin-console/common/base-members.component.ts deleted file mode 100644 index 5ecf4269a1a..00000000000 --- a/apps/web/src/app/admin-console/common/base-members.component.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { Directive } from "@angular/core"; -import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; -import { FormControl } from "@angular/forms"; -import { firstValueFrom, lastValueFrom, debounceTime, combineLatest, BehaviorSubject } from "rxjs"; - -import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service"; -import { - OrganizationUserStatusType, - OrganizationUserType, - ProviderUserStatusType, - ProviderUserType, -} from "@bitwarden/common/admin-console/enums"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { ProviderUserUserDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user.response"; -import { ListResponse } from "@bitwarden/common/models/response/list.response"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { DialogService, ToastService } from "@bitwarden/components"; -import { KeyService } from "@bitwarden/key-management"; - -import { OrganizationUserView } from "../organizations/core/views/organization-user.view"; -import { UserConfirmComponent } from "../organizations/manage/user-confirm.component"; -import { MemberActionResult } from "../organizations/members/services/member-actions/member-actions.service"; - -import { PeopleTableDataSource, peopleFilter } from "./people-table-data-source"; - -export type StatusType = OrganizationUserStatusType | ProviderUserStatusType; -export type UserViewTypes = ProviderUserUserDetailsResponse | OrganizationUserView; - -/** - * A refactored copy of BasePeopleComponent, using the component library table and other modern features. - * This will replace BasePeopleComponent once all subclasses have been changed over to use this class. - */ -@Directive() -export abstract class BaseMembersComponent { - /** - * Shows a banner alerting the admin that users need to be confirmed. - */ - get showConfirmUsers(): boolean { - return ( - this.dataSource.activeUserCount > 1 && - this.dataSource.confirmedUserCount > 0 && - this.dataSource.confirmedUserCount < 3 && - this.dataSource.acceptedUserCount > 0 - ); - } - - get showBulkConfirmUsers(): boolean { - return this.dataSource - .getCheckedUsers() - .every((member) => member.status == this.userStatusType.Accepted); - } - - get showBulkReinviteUsers(): boolean { - return this.dataSource - .getCheckedUsers() - .every((member) => member.status == this.userStatusType.Invited); - } - - abstract userType: typeof OrganizationUserType | typeof ProviderUserType; - abstract userStatusType: typeof OrganizationUserStatusType | typeof ProviderUserStatusType; - - protected abstract dataSource: PeopleTableDataSource; - - firstLoaded: boolean = false; - - /** - * The currently selected status filter, or undefined to show all active users. - */ - status?: StatusType; - - /** - * The currently executing promise - used to avoid multiple user actions executing at once. - */ - actionPromise?: Promise; - - protected searchControl = new FormControl("", { nonNullable: true }); - protected statusToggle = new BehaviorSubject(undefined); - - constructor( - protected apiService: ApiService, - protected i18nService: I18nService, - protected keyService: KeyService, - protected validationService: ValidationService, - protected logService: LogService, - protected userNamePipe: UserNamePipe, - protected dialogService: DialogService, - protected organizationManagementPreferencesService: OrganizationManagementPreferencesService, - protected toastService: ToastService, - ) { - // Connect the search input and status toggles to the table dataSource filter - combineLatest([this.searchControl.valueChanges.pipe(debounceTime(200)), this.statusToggle]) - .pipe(takeUntilDestroyed()) - .subscribe( - ([searchText, status]) => (this.dataSource.filter = peopleFilter(searchText, status)), - ); - } - - abstract edit(user: UserView, organization?: Organization): void; - abstract getUsers(organization?: Organization): Promise | UserView[]>; - abstract removeUser(id: string, organization?: Organization): Promise; - abstract reinviteUser(id: string, organization?: Organization): Promise; - abstract confirmUser( - user: UserView, - publicKey: Uint8Array, - organization?: Organization, - ): Promise; - abstract invite(organization?: Organization): void; - - async load(organization?: Organization) { - // Load new users from the server - const response = await this.getUsers(organization); - - // GetUsers can return a ListResponse or an Array - if (response instanceof ListResponse) { - this.dataSource.data = response.data != null && response.data.length > 0 ? response.data : []; - } else if (Array.isArray(response)) { - this.dataSource.data = response; - } - - this.firstLoaded = true; - } - - protected async removeUserConfirmationDialog(user: UserView) { - return this.dialogService.openSimpleDialog({ - title: this.userNamePipe.transform(user), - content: { key: "removeUserConfirmation" }, - type: "warning", - }); - } - - async remove(user: UserView, organization?: Organization) { - const confirmed = await this.removeUserConfirmationDialog(user); - if (!confirmed) { - return false; - } - - this.actionPromise = this.removeUser(user.id, organization); - try { - const result = await this.actionPromise; - if (result.success) { - this.toastService.showToast({ - variant: "success", - message: this.i18nService.t("removedUserId", this.userNamePipe.transform(user)), - }); - this.dataSource.removeUser(user); - } else { - throw new Error(result.error); - } - } catch (e) { - this.validationService.showError(e); - } - this.actionPromise = undefined; - } - - async reinvite(user: UserView, organization?: Organization) { - if (this.actionPromise != null) { - return; - } - - this.actionPromise = this.reinviteUser(user.id, organization); - try { - const result = await this.actionPromise; - if (result.success) { - this.toastService.showToast({ - variant: "success", - message: this.i18nService.t("hasBeenReinvited", this.userNamePipe.transform(user)), - }); - } else { - throw new Error(result.error); - } - } catch (e) { - this.validationService.showError(e); - } - this.actionPromise = undefined; - } - - async confirm(user: UserView, organization?: Organization) { - const confirmUser = async (publicKey: Uint8Array) => { - try { - this.actionPromise = this.confirmUser(user, publicKey, organization); - const result = await this.actionPromise; - if (result.success) { - user.status = this.userStatusType.Confirmed; - this.dataSource.replaceUser(user); - - this.toastService.showToast({ - variant: "success", - message: this.i18nService.t("hasBeenConfirmed", this.userNamePipe.transform(user)), - }); - } else { - throw new Error(result.error); - } - } catch (e) { - this.validationService.showError(e); - throw e; - } finally { - this.actionPromise = undefined; - } - }; - - if (this.actionPromise != null) { - return; - } - - try { - const publicKeyResponse = await this.apiService.getUserPublicKey(user.userId); - const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey); - - const autoConfirm = await firstValueFrom( - this.organizationManagementPreferencesService.autoConfirmFingerPrints.state$, - ); - if (user == null) { - throw new Error("Cannot confirm null user."); - } - if (autoConfirm == null || !autoConfirm) { - const dialogRef = UserConfirmComponent.open(this.dialogService, { - data: { - name: this.userNamePipe.transform(user), - userId: user.userId, - publicKey: publicKey, - confirmUser: () => confirmUser(publicKey), - }, - }); - await lastValueFrom(dialogRef.closed); - - return; - } - - try { - const fingerprint = await this.keyService.getFingerprint(user.userId, publicKey); - this.logService.info(`User's fingerprint: ${fingerprint.join("-")}`); - } catch (e) { - this.logService.error(e); - } - await confirmUser(publicKey); - } catch (e) { - this.logService.error(`Handled exception: ${e}`); - } - } -} diff --git a/apps/web/src/app/admin-console/organizations/manage/user-confirm.component.ts b/apps/web/src/app/admin-console/organizations/manage/user-confirm.component.ts index 03130d0b946..788d01695b0 100644 --- a/apps/web/src/app/admin-console/organizations/manage/user-confirm.component.ts +++ b/apps/web/src/app/admin-console/organizations/manage/user-confirm.component.ts @@ -2,11 +2,8 @@ // @ts-strict-ignore import { Component, Inject, OnInit } from "@angular/core"; import { FormControl, FormGroup } from "@angular/forms"; -import { firstValueFrom } from "rxjs"; import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { DIALOG_DATA, DialogConfig, DialogRef, DialogService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; @@ -17,8 +14,6 @@ export type UserConfirmDialogData = { name: string; userId: string; publicKey: Uint8Array; - // @TODO remove this when doing feature flag cleanup for members component refactor. - confirmUser?: (publicKey: Uint8Array) => Promise; }; // FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush @@ -46,7 +41,6 @@ export class UserConfirmComponent implements OnInit { private keyService: KeyService, private logService: LogService, private organizationManagementPreferencesService: OrganizationManagementPreferencesService, - private configService: ConfigService, ) { this.name = data.name; this.userId = data.userId; @@ -76,13 +70,6 @@ export class UserConfirmComponent implements OnInit { await this.organizationManagementPreferencesService.autoConfirmFingerPrints.set(true); } - const membersComponentRefactorEnabled = await firstValueFrom( - this.configService.getFeatureFlag$(FeatureFlag.MembersComponentRefactor), - ); - if (!membersComponentRefactorEnabled) { - await this.data.confirmUser(this.publicKey); - } - this.dialogRef.close(true); }; diff --git a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts index 6848f76286f..43520449535 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts @@ -195,9 +195,9 @@ export class MemberDialogComponent implements OnDestroy { private accountService: AccountService, organizationService: OrganizationService, private toastService: ToastService, - private configService: ConfigService, private deleteManagedMemberWarningService: DeleteManagedMemberWarningService, private organizationUserService: OrganizationUserService, + private configService: ConfigService, ) { this.organization$ = accountService.activeAccount$.pipe( getUserId, diff --git a/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.html b/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.html deleted file mode 100644 index 65bab31c728..00000000000 --- a/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.html +++ /dev/null @@ -1,495 +0,0 @@ -@let organization = this.organization(); -@if (organization) { - - - - - - - - -
    - - - {{ "all" | i18n }} - {{ - allCount - }} - - - - {{ "invited" | i18n }} - {{ - invitedCount - }} - - - - {{ "needsConfirmation" | i18n }} - {{ - acceptedUserCount - }} - - - - {{ "revoked" | i18n }} - {{ - revokedCount - }} - - -
    - - - {{ "loading" | i18n }} - - -

    {{ "noMembersInList" | i18n }}

    - - - {{ "usersNeedConfirmed" | i18n }} - - - - - - - - - - - {{ "name" | i18n }} - {{ (organization.useGroups ? "groups" : "collections") | i18n }} - {{ "role" | i18n }} - {{ "policies" | i18n }} - -
    - - -
    - - - - - - - - - - - - - - - -
    - - - - - - - -
    - -
    -
    - - - {{ "invited" | i18n }} - - - {{ "needsConfirmation" | i18n }} - - - {{ "revoked" | i18n }} - -
    -
    - {{ u.email }} -
    -
    -
    - -
    - - -
    - -
    -
    - {{ u.name ?? u.email }} - - {{ "invited" | i18n }} - - - {{ "needsConfirmation" | i18n }} - - - {{ "revoked" | i18n }} - -
    -
    - {{ u.email }} -
    -
    -
    - -
    - - - - - - - - - - - - - - - {{ u.type | userType }} - - - - - {{ u.type | userType }} - - - - - - - {{ "userUsingTwoStep" | i18n }} - - @let resetPasswordPolicyEnabled = resetPasswordPolicyEnabled$ | async; - - - {{ "enrolledAccountRecovery" | i18n }} - - - -
    -
    - -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    -
    -
    -} diff --git a/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.ts b/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.ts deleted file mode 100644 index 1f1e19e2a6f..00000000000 --- a/apps/web/src/app/admin-console/organizations/members/deprecated_members.component.ts +++ /dev/null @@ -1,624 +0,0 @@ -import { Component, computed, Signal } from "@angular/core"; -import { takeUntilDestroyed, toSignal } from "@angular/core/rxjs-interop"; -import { ActivatedRoute } from "@angular/router"; -import { - combineLatest, - concatMap, - filter, - firstValueFrom, - from, - map, - merge, - Observable, - shareReplay, - switchMap, - take, -} from "rxjs"; - -import { OrganizationUserUserDetailsResponse } from "@bitwarden/admin-console/common"; -import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service"; -import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; -import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { - OrganizationUserStatusType, - OrganizationUserType, - PolicyType, -} from "@bitwarden/common/admin-console/enums"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { OrganizationMetadataServiceAbstraction } from "@bitwarden/common/billing/abstractions/organization-metadata.service.abstraction"; -import { OrganizationBillingMetadataResponse } from "@bitwarden/common/billing/models/response/organization-billing-metadata.response"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; -import { getById } from "@bitwarden/common/platform/misc"; -import { DialogService, ToastService } from "@bitwarden/components"; -import { KeyService } from "@bitwarden/key-management"; -import { UserId } from "@bitwarden/user-core"; -import { BillingConstraintService } from "@bitwarden/web-vault/app/billing/members/billing-constraint/billing-constraint.service"; -import { OrganizationWarningsService } from "@bitwarden/web-vault/app/billing/organizations/warnings/services"; - -import { BaseMembersComponent } from "../../common/base-members.component"; -import { - CloudBulkReinviteLimit, - MaxCheckedCount, - PeopleTableDataSource, -} from "../../common/people-table-data-source"; -import { OrganizationUserView } from "../core/views/organization-user.view"; - -import { AccountRecoveryDialogResultType } from "./components/account-recovery/account-recovery-dialog.component"; -import { MemberDialogResult, MemberDialogTab } from "./components/member-dialog"; -import { - MemberDialogManagerService, - MemberExportService, - OrganizationMembersService, -} from "./services"; -import { DeleteManagedMemberWarningService } from "./services/delete-managed-member/delete-managed-member-warning.service"; -import { - MemberActionsService, - MemberActionResult, -} from "./services/member-actions/member-actions.service"; - -class MembersTableDataSource extends PeopleTableDataSource { - protected statusType = OrganizationUserStatusType; -} - -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection -@Component({ - templateUrl: "deprecated_members.component.html", - standalone: false, -}) -export class MembersComponent extends BaseMembersComponent { - userType = OrganizationUserType; - userStatusType = OrganizationUserStatusType; - memberTab = MemberDialogTab; - protected dataSource: MembersTableDataSource; - - readonly organization: Signal; - status: OrganizationUserStatusType | undefined; - - private userId$: Observable = this.accountService.activeAccount$.pipe(getUserId); - - resetPasswordPolicyEnabled$: Observable; - - protected readonly canUseSecretsManager: Signal = computed( - () => this.organization()?.useSecretsManager ?? false, - ); - protected readonly showUserManagementControls: Signal = computed( - () => this.organization()?.canManageUsers ?? false, - ); - protected billingMetadata$: Observable; - - // Fixed sizes used for cdkVirtualScroll - protected rowHeight = 66; - protected rowHeightClass = `tw-h-[66px]`; - - constructor( - apiService: ApiService, - i18nService: I18nService, - organizationManagementPreferencesService: OrganizationManagementPreferencesService, - keyService: KeyService, - validationService: ValidationService, - logService: LogService, - userNamePipe: UserNamePipe, - dialogService: DialogService, - toastService: ToastService, - private route: ActivatedRoute, - protected deleteManagedMemberWarningService: DeleteManagedMemberWarningService, - private organizationWarningsService: OrganizationWarningsService, - private memberActionsService: MemberActionsService, - private memberDialogManager: MemberDialogManagerService, - protected billingConstraint: BillingConstraintService, - protected memberService: OrganizationMembersService, - private organizationService: OrganizationService, - private accountService: AccountService, - private policyService: PolicyService, - private policyApiService: PolicyApiServiceAbstraction, - private organizationMetadataService: OrganizationMetadataServiceAbstraction, - private memberExportService: MemberExportService, - private environmentService: EnvironmentService, - ) { - super( - apiService, - i18nService, - keyService, - validationService, - logService, - userNamePipe, - dialogService, - organizationManagementPreferencesService, - toastService, - ); - - this.dataSource = new MembersTableDataSource(this.environmentService); - - const organization$ = this.route.params.pipe( - concatMap((params) => - this.userId$.pipe( - switchMap((userId) => - this.organizationService.organizations$(userId).pipe(getById(params.organizationId)), - ), - filter((organization): organization is Organization => organization != null), - shareReplay({ refCount: true, bufferSize: 1 }), - ), - ), - ); - - this.organization = toSignal(organization$); - - const policies$ = combineLatest([this.userId$, organization$]).pipe( - switchMap(([userId, organization]) => - organization.isProviderUser - ? from(this.policyApiService.getPolicies(organization.id)).pipe( - map((response) => Policy.fromListResponse(response)), - ) - : this.policyService.policies$(userId), - ), - ); - - this.resetPasswordPolicyEnabled$ = combineLatest([organization$, policies$]).pipe( - map( - ([organization, policies]) => - policies - .filter((policy) => policy.type === PolicyType.ResetPassword) - .find((p) => p.organizationId === organization.id)?.enabled ?? false, - ), - ); - - combineLatest([this.route.queryParams, organization$]) - .pipe( - concatMap(async ([qParams, organization]) => { - await this.load(organization!); - - this.searchControl.setValue(qParams.search); - - if (qParams.viewEvents != null) { - const user = this.dataSource.data.filter((u) => u.id === qParams.viewEvents); - if (user.length > 0 && user[0].status === OrganizationUserStatusType.Confirmed) { - this.openEventsDialog(user[0], organization!); - } - } - }), - takeUntilDestroyed(), - ) - .subscribe(); - - organization$ - .pipe( - switchMap((organization) => - merge( - this.organizationWarningsService.showInactiveSubscriptionDialog$(organization), - this.organizationWarningsService.showSubscribeBeforeFreeTrialEndsDialog$(organization), - ), - ), - takeUntilDestroyed(), - ) - .subscribe(); - - this.billingMetadata$ = organization$.pipe( - switchMap((organization) => - this.organizationMetadataService.getOrganizationMetadata$(organization.id), - ), - shareReplay({ bufferSize: 1, refCount: false }), - ); - - // Stripe is slow, so kick this off in the background but without blocking page load. - // Anyone who needs it will still await the first emission. - this.billingMetadata$.pipe(take(1), takeUntilDestroyed()).subscribe(); - } - - override async load(organization: Organization) { - await super.load(organization); - } - - async getUsers(organization: Organization): Promise { - return await this.memberService.loadUsers(organization); - } - - async removeUser(id: string, organization: Organization): Promise { - return await this.memberActionsService.removeUser(organization, id); - } - - async revokeUser(id: string, organization: Organization): Promise { - return await this.memberActionsService.revokeUser(organization, id); - } - - async restoreUser(id: string, organization: Organization): Promise { - return await this.memberActionsService.restoreUser(organization, id); - } - - async reinviteUser(id: string, organization: Organization): Promise { - return await this.memberActionsService.reinviteUser(organization, id); - } - - async confirmUser( - user: OrganizationUserView, - publicKey: Uint8Array, - organization: Organization, - ): Promise { - return await this.memberActionsService.confirmUser(user, publicKey, organization); - } - - async revoke(user: OrganizationUserView, organization: Organization) { - const confirmed = await this.revokeUserConfirmationDialog(user); - - if (!confirmed) { - return false; - } - - this.actionPromise = this.revokeUser(user.id, organization); - try { - const result = await this.actionPromise; - if (result.success) { - this.toastService.showToast({ - variant: "success", - message: this.i18nService.t("revokedUserId", this.userNamePipe.transform(user)), - }); - await this.load(organization); - } else { - throw new Error(result.error); - } - } catch (e) { - this.validationService.showError(e); - } - this.actionPromise = undefined; - } - - async restore(user: OrganizationUserView, organization: Organization) { - this.actionPromise = this.restoreUser(user.id, organization); - try { - const result = await this.actionPromise; - if (result.success) { - this.toastService.showToast({ - variant: "success", - message: this.i18nService.t("restoredUserId", this.userNamePipe.transform(user)), - }); - await this.load(organization); - } else { - throw new Error(result.error); - } - } catch (e) { - this.validationService.showError(e); - } - this.actionPromise = undefined; - } - - allowResetPassword( - orgUser: OrganizationUserView, - organization: Organization, - orgResetPasswordPolicyEnabled: boolean, - ): boolean { - return this.memberActionsService.allowResetPassword( - orgUser, - organization, - orgResetPasswordPolicyEnabled, - ); - } - - showEnrolledStatus( - orgUser: OrganizationUserUserDetailsResponse, - organization: Organization, - orgResetPasswordPolicyEnabled: boolean, - ): boolean { - return ( - organization.useResetPassword && - orgUser.resetPasswordEnrolled && - orgResetPasswordPolicyEnabled - ); - } - - private async handleInviteDialog(organization: Organization) { - const billingMetadata = await firstValueFrom(this.billingMetadata$); - const allUserEmails = this.dataSource.data?.map((user) => user.email) ?? []; - - const result = await this.memberDialogManager.openInviteDialog( - organization, - billingMetadata, - allUserEmails, - ); - - if (result === MemberDialogResult.Saved) { - await this.load(organization); - } - } - - async invite(organization: Organization) { - const billingMetadata = await firstValueFrom(this.billingMetadata$); - const seatLimitResult = this.billingConstraint.checkSeatLimit(organization, billingMetadata); - if (!(await this.billingConstraint.seatLimitReached(seatLimitResult, organization))) { - await this.handleInviteDialog(organization); - this.organizationMetadataService.refreshMetadataCache(); - } - } - - async edit( - user: OrganizationUserView, - organization: Organization, - initialTab: MemberDialogTab = MemberDialogTab.Role, - ) { - const billingMetadata = await firstValueFrom(this.billingMetadata$); - - const result = await this.memberDialogManager.openEditDialog( - user, - organization, - billingMetadata, - initialTab, - ); - - switch (result) { - case MemberDialogResult.Deleted: - this.dataSource.removeUser(user); - break; - case MemberDialogResult.Saved: - case MemberDialogResult.Revoked: - case MemberDialogResult.Restored: - await this.load(organization); - break; - } - } - - async bulkRemove(organization: Organization) { - if (this.actionPromise != null) { - return; - } - - const users = this.dataSource.getCheckedUsersWithLimit(MaxCheckedCount); - - await this.memberDialogManager.openBulkRemoveDialog(organization, users); - this.organizationMetadataService.refreshMetadataCache(); - await this.load(organization); - } - - async bulkDelete(organization: Organization) { - if (this.actionPromise != null) { - return; - } - - const users = this.dataSource.getCheckedUsersWithLimit(MaxCheckedCount); - - await this.memberDialogManager.openBulkDeleteDialog(organization, users); - await this.load(organization); - } - - async bulkRevoke(organization: Organization) { - await this.bulkRevokeOrRestore(true, organization); - } - - async bulkRestore(organization: Organization) { - await this.bulkRevokeOrRestore(false, organization); - } - - async bulkRevokeOrRestore(isRevoking: boolean, organization: Organization) { - if (this.actionPromise != null) { - return; - } - - const users = this.dataSource.getCheckedUsersWithLimit(MaxCheckedCount); - - await this.memberDialogManager.openBulkRestoreRevokeDialog(organization, users, isRevoking); - await this.load(organization); - } - - async bulkReinvite(organization: Organization) { - if (this.actionPromise != null) { - return; - } - - let users: OrganizationUserView[]; - if (this.dataSource.isIncreasedBulkLimitEnabled()) { - users = this.dataSource.getCheckedUsersInVisibleOrder(); - } else { - users = this.dataSource.getCheckedUsers(); - } - - const allInvitedUsers = users.filter((u) => u.status === OrganizationUserStatusType.Invited); - - // Capture the original count BEFORE enforcing the limit - const originalInvitedCount = allInvitedUsers.length; - - // When feature flag is enabled, limit invited users and uncheck the excess - let filteredUsers: OrganizationUserView[]; - if (this.dataSource.isIncreasedBulkLimitEnabled()) { - filteredUsers = this.dataSource.limitAndUncheckExcess( - allInvitedUsers, - CloudBulkReinviteLimit, - ); - } else { - filteredUsers = allInvitedUsers; - } - - if (filteredUsers.length <= 0) { - this.toastService.showToast({ - variant: "error", - title: this.i18nService.t("errorOccurred"), - message: this.i18nService.t("noSelectedUsersApplicable"), - }); - return; - } - - try { - const result = await this.memberActionsService.bulkReinvite(organization, filteredUsers); - - if (result.successful.length === 0) { - throw new Error(); - } - - // When feature flag is enabled, show toast instead of dialog - if (this.dataSource.isIncreasedBulkLimitEnabled()) { - const selectedCount = originalInvitedCount; - const invitedCount = filteredUsers.length; - - if (selectedCount > CloudBulkReinviteLimit) { - const excludedCount = selectedCount - CloudBulkReinviteLimit; - this.toastService.showToast({ - variant: "success", - message: this.i18nService.t( - "bulkReinviteLimitedSuccessToast", - CloudBulkReinviteLimit.toLocaleString(), - selectedCount.toLocaleString(), - excludedCount.toLocaleString(), - ), - }); - } else { - this.toastService.showToast({ - variant: "success", - message: - invitedCount === 1 - ? this.i18nService.t("reinviteSuccessToast") - : this.i18nService.t("bulkReinviteSentToast", invitedCount.toString()), - }); - } - } else { - // Feature flag disabled - show legacy dialog - await this.memberDialogManager.openBulkStatusDialog( - users, - filteredUsers, - Promise.resolve(result.successful), - this.i18nService.t("bulkReinviteMessage"), - ); - } - } catch (e) { - this.validationService.showError(e); - } - this.actionPromise = undefined; - } - - async bulkConfirm(organization: Organization) { - if (this.actionPromise != null) { - return; - } - - const users = this.dataSource.getCheckedUsersWithLimit(MaxCheckedCount); - - await this.memberDialogManager.openBulkConfirmDialog(organization, users); - await this.load(organization); - } - - async bulkEnableSM(organization: Organization) { - const users = this.dataSource.getCheckedUsersWithLimit(MaxCheckedCount); - - await this.memberDialogManager.openBulkEnableSecretsManagerDialog(organization, users); - - this.dataSource.uncheckAllUsers(); - await this.load(organization); - } - - openEventsDialog(user: OrganizationUserView, organization: Organization) { - this.memberDialogManager.openEventsDialog(user, organization); - } - - async resetPassword(user: OrganizationUserView, organization: Organization) { - if (!user || !user.email || !user.id) { - this.toastService.showToast({ - variant: "error", - title: this.i18nService.t("errorOccurred"), - message: this.i18nService.t("orgUserDetailsNotFound"), - }); - this.logService.error("Org user details not found when attempting account recovery"); - - return; - } - - const result = await this.memberDialogManager.openAccountRecoveryDialog(user, organization); - if (result === AccountRecoveryDialogResultType.Ok) { - await this.load(organization); - } - - return; - } - - protected async removeUserConfirmationDialog(user: OrganizationUserView) { - return await this.memberDialogManager.openRemoveUserConfirmationDialog(user); - } - - protected async revokeUserConfirmationDialog(user: OrganizationUserView) { - return await this.memberDialogManager.openRevokeUserConfirmationDialog(user); - } - - async deleteUser(user: OrganizationUserView, organization: Organization) { - const confirmed = await this.memberDialogManager.openDeleteUserConfirmationDialog( - user, - organization, - ); - - if (!confirmed) { - return false; - } - - this.actionPromise = this.memberActionsService.deleteUser(organization, user.id); - try { - const result = await this.actionPromise; - if (!result.success) { - throw new Error(result.error); - } - this.toastService.showToast({ - variant: "success", - message: this.i18nService.t("organizationUserDeleted", this.userNamePipe.transform(user)), - }); - this.dataSource.removeUser(user); - } catch (e) { - this.validationService.showError(e); - } - this.actionPromise = undefined; - } - - get showBulkRestoreUsers(): boolean { - return this.dataSource - .getCheckedUsers() - .every((member) => member.status == this.userStatusType.Revoked); - } - - get showBulkRevokeUsers(): boolean { - return this.dataSource - .getCheckedUsers() - .every((member) => member.status != this.userStatusType.Revoked); - } - - get showBulkRemoveUsers(): boolean { - return this.dataSource.getCheckedUsers().every((member) => !member.managedByOrganization); - } - - get showBulkDeleteUsers(): boolean { - const validStatuses = [ - this.userStatusType.Accepted, - this.userStatusType.Confirmed, - this.userStatusType.Revoked, - ]; - - return this.dataSource - .getCheckedUsers() - .every((member) => member.managedByOrganization && validStatuses.includes(member.status)); - } - - get selectedInvitedCount(): number { - return this.dataSource - .getCheckedUsers() - .filter((member) => member.status === this.userStatusType.Invited).length; - } - - get isSingleInvite(): boolean { - return this.selectedInvitedCount === 1; - } - - exportMembers = () => { - const result = this.memberExportService.getMemberExport(this.dataSource.data); - if (result.success) { - this.toastService.showToast({ - variant: "success", - title: undefined, - message: this.i18nService.t("dataExportSuccess"), - }); - } - - if (result.error != null) { - this.validationService.showError(result.error.message); - } - }; -} diff --git a/apps/web/src/app/admin-console/organizations/members/members-routing.module.ts b/apps/web/src/app/admin-console/organizations/members/members-routing.module.ts index 2f22b9871b7..153a2f3a956 100644 --- a/apps/web/src/app/admin-console/organizations/members/members-routing.module.ts +++ b/apps/web/src/app/admin-console/organizations/members/members-routing.module.ts @@ -1,30 +1,23 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; -import { featureFlaggedRoute } from "@bitwarden/angular/platform/utils/feature-flagged-route"; import { canAccessMembersTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { FreeBitwardenFamiliesComponent } from "../../../billing/members/free-bitwarden-families.component"; import { organizationPermissionsGuard } from "../guards/org-permissions.guard"; import { canAccessSponsoredFamilies } from "./../../../billing/guards/can-access-sponsored-families.guard"; -import { MembersComponent } from "./deprecated_members.component"; -import { vNextMembersComponent } from "./members.component"; +import { MembersComponent } from "./members.component"; const routes: Routes = [ - ...featureFlaggedRoute({ - defaultComponent: MembersComponent, - flaggedComponent: vNextMembersComponent, - featureFlag: FeatureFlag.MembersComponentRefactor, - routeOptions: { - path: "", - canActivate: [organizationPermissionsGuard(canAccessMembersTab)], - data: { - titleId: "members", - }, + { + path: "", + component: MembersComponent, + canActivate: [organizationPermissionsGuard(canAccessMembersTab)], + data: { + titleId: "members", }, - }), + }, { path: "sponsored-families", component: FreeBitwardenFamiliesComponent, diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.spec.ts b/apps/web/src/app/admin-console/organizations/members/members.component.spec.ts index 9a371de1acd..72c12fd4d79 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.spec.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.component.spec.ts @@ -36,7 +36,7 @@ import { OrganizationUserView } from "../core/views/organization-user.view"; import { AccountRecoveryDialogResultType } from "./components/account-recovery/account-recovery-dialog.component"; import { MemberDialogResult } from "./components/member-dialog"; -import { vNextMembersComponent } from "./members.component"; +import { MembersComponent } from "./members.component"; import { MemberDialogManagerService, MemberExportService, @@ -48,9 +48,9 @@ import { MemberActionResult, } from "./services/member-actions/member-actions.service"; -describe("vNextMembersComponent", () => { - let component: vNextMembersComponent; - let fixture: ComponentFixture; +describe("MembersComponent", () => { + let component: MembersComponent; + let fixture: ComponentFixture; let mockApiService: MockProxy; let mockI18nService: MockProxy; @@ -172,7 +172,7 @@ describe("vNextMembersComponent", () => { mockFileDownloadService = mock(); await TestBed.configureTestingModule({ - declarations: [vNextMembersComponent], + declarations: [MembersComponent], providers: [ { provide: ApiService, useValue: mockApiService }, { provide: I18nService, useValue: mockI18nService }, @@ -211,13 +211,13 @@ describe("vNextMembersComponent", () => { ], schemas: [NO_ERRORS_SCHEMA], }) - .overrideComponent(vNextMembersComponent, { + .overrideComponent(MembersComponent, { remove: { imports: [] }, add: { template: "
    " }, }) .compileComponents(); - fixture = TestBed.createComponent(vNextMembersComponent); + fixture = TestBed.createComponent(MembersComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.ts b/apps/web/src/app/admin-console/organizations/members/members.component.ts index 826bdfb5f69..6b93edc8c6b 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.component.ts @@ -82,7 +82,7 @@ interface BulkMemberFlags { templateUrl: "members.component.html", standalone: false, }) -export class vNextMembersComponent { +export class MembersComponent { protected i18nService = inject(I18nService); protected validationService = inject(ValidationService); protected logService = inject(LogService); diff --git a/apps/web/src/app/admin-console/organizations/members/members.module.ts b/apps/web/src/app/admin-console/organizations/members/members.module.ts index 54e2d1b6373..92ae71123cc 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.module.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.module.ts @@ -19,9 +19,8 @@ import { BulkRemoveDialogComponent } from "./components/bulk/bulk-remove-dialog. import { BulkRestoreRevokeComponent } from "./components/bulk/bulk-restore-revoke.component"; import { BulkStatusComponent } from "./components/bulk/bulk-status.component"; import { UserDialogModule } from "./components/member-dialog"; -import { MembersComponent } from "./deprecated_members.component"; import { MembersRoutingModule } from "./members-routing.module"; -import { vNextMembersComponent } from "./members.component"; +import { MembersComponent } from "./members.component"; import { UserStatusPipe } from "./pipes"; import { OrganizationMembersService, @@ -52,7 +51,6 @@ import { BulkProgressDialogComponent, BulkReinviteFailureDialogComponent, MembersComponent, - vNextMembersComponent, BulkDeleteDialogComponent, UserStatusPipe, ], diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.html deleted file mode 100644 index 5478601e72c..00000000000 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.html +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - -
    - - - {{ "all" | i18n }} - - {{ allCount }} - - - - {{ "invited" | i18n }} - - {{ invitedCount }} - - - - {{ "needsConfirmation" | i18n }} - - {{ acceptedCount }} - - - -
    - - - - {{ "loading" | i18n }} - - - -

    {{ "noMembersInList" | i18n }}

    - - - {{ "providerUsersNeedConfirmed" | i18n }} - - - - - - - - - - {{ "name" | i18n }} - {{ "role" | i18n }} - - - - - - - - - - - - - - - - -
    - -
    -
    - - - {{ "invited" | i18n }} - - - {{ "needsConfirmation" | i18n }} - - - {{ "revoked" | i18n }} - -
    -
    - {{ user.email }} -
    -
    -
    - - - {{ "providerAdmin" | i18n }} - {{ "serviceUser" | i18n }} - - - - - - - - - - - -
    -
    -
    -
    -
    diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.ts deleted file mode 100644 index 464b9982689..00000000000 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/deprecated_members.component.ts +++ /dev/null @@ -1,351 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Component } from "@angular/core"; -import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; -import { ActivatedRoute, Router } from "@angular/router"; -import { combineLatest, firstValueFrom, lastValueFrom, switchMap } from "rxjs"; -import { first, map } from "rxjs/operators"; - -import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service"; -import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service"; -import { ProviderUserStatusType, ProviderUserType } from "@bitwarden/common/admin-console/enums"; -import { ProviderUserBulkRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-bulk.request"; -import { ProviderUserConfirmRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-confirm.request"; -import { ProviderUserUserDetailsResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user.response"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { assertNonNullish } from "@bitwarden/common/auth/utils"; -import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; -import { ListResponse } from "@bitwarden/common/models/response/list.response"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; -import { ProviderId } from "@bitwarden/common/types/guid"; -import { DialogRef, DialogService, ToastService } from "@bitwarden/components"; -import { KeyService } from "@bitwarden/key-management"; -import { BaseMembersComponent } from "@bitwarden/web-vault/app/admin-console/common/base-members.component"; -import { - CloudBulkReinviteLimit, - MaxCheckedCount, - peopleFilter, - PeopleTableDataSource, -} from "@bitwarden/web-vault/app/admin-console/common/people-table-data-source"; -import { openEntityEventsDialog } from "@bitwarden/web-vault/app/admin-console/organizations/manage/entity-events.component"; -import { BulkStatusComponent } from "@bitwarden/web-vault/app/admin-console/organizations/members/components/bulk/bulk-status.component"; -import { MemberActionResult } from "@bitwarden/web-vault/app/admin-console/organizations/members/services/member-actions/member-actions.service"; - -import { - AddEditMemberDialogComponent, - AddEditMemberDialogParams, - AddEditMemberDialogResultType, -} from "./dialogs/add-edit-member-dialog.component"; -import { BulkConfirmDialogComponent } from "./dialogs/bulk-confirm-dialog.component"; -import { BulkRemoveDialogComponent } from "./dialogs/bulk-remove-dialog.component"; - -type ProviderUser = ProviderUserUserDetailsResponse; - -class MembersTableDataSource extends PeopleTableDataSource { - protected statusType = ProviderUserStatusType; -} - -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection -@Component({ - templateUrl: "deprecated_members.component.html", - standalone: false, -}) -export class MembersComponent extends BaseMembersComponent { - accessEvents = false; - dataSource: MembersTableDataSource; - loading = true; - providerId: string; - rowHeight = 70; - rowHeightClass = `tw-h-[70px]`; - status: ProviderUserStatusType = null; - - userStatusType = ProviderUserStatusType; - userType = ProviderUserType; - - constructor( - apiService: ApiService, - keyService: KeyService, - dialogService: DialogService, - i18nService: I18nService, - logService: LogService, - organizationManagementPreferencesService: OrganizationManagementPreferencesService, - toastService: ToastService, - userNamePipe: UserNamePipe, - validationService: ValidationService, - private encryptService: EncryptService, - private activatedRoute: ActivatedRoute, - private providerService: ProviderService, - private router: Router, - private accountService: AccountService, - private environmentService: EnvironmentService, - ) { - super( - apiService, - i18nService, - keyService, - validationService, - logService, - userNamePipe, - dialogService, - organizationManagementPreferencesService, - toastService, - ); - - this.dataSource = new MembersTableDataSource(this.environmentService); - - combineLatest([ - this.activatedRoute.parent.params, - this.activatedRoute.queryParams.pipe(first()), - ]) - .pipe( - switchMap(async ([urlParams, queryParams]) => { - this.searchControl.setValue(queryParams.search); - this.dataSource.filter = peopleFilter(queryParams.search, null); - - this.providerId = urlParams.providerId; - const provider = await firstValueFrom( - this.accountService.activeAccount$.pipe( - getUserId, - switchMap((userId) => this.providerService.get$(this.providerId, userId)), - ), - ); - - if (!provider || !provider.canManageUsers) { - return await this.router.navigate(["../"], { relativeTo: this.activatedRoute }); - } - this.accessEvents = provider.useEvents; - await this.load(); - - if (queryParams.viewEvents != null) { - const user = this.dataSource.data.find((user) => user.id === queryParams.viewEvents); - if (user && user.status === ProviderUserStatusType.Confirmed) { - this.openEventsDialog(user); - } - } - }), - takeUntilDestroyed(), - ) - .subscribe(); - } - - async bulkConfirm(): Promise { - if (this.actionPromise != null) { - return; - } - - const users = this.dataSource.getCheckedUsersWithLimit(MaxCheckedCount); - - const dialogRef = BulkConfirmDialogComponent.open(this.dialogService, { - data: { - providerId: this.providerId, - users: users, - }, - }); - - await lastValueFrom(dialogRef.closed); - await this.load(); - } - - async bulkReinvite(): Promise { - if (this.actionPromise != null) { - return; - } - - let users: ProviderUser[]; - if (this.dataSource.isIncreasedBulkLimitEnabled()) { - users = this.dataSource.getCheckedUsersInVisibleOrder(); - } else { - users = this.dataSource.getCheckedUsers(); - } - - const allInvitedUsers = users.filter((user) => user.status === ProviderUserStatusType.Invited); - - // Capture the original count BEFORE enforcing the limit - const originalInvitedCount = allInvitedUsers.length; - - // When feature flag is enabled, limit invited users and uncheck the excess - let checkedInvitedUsers: ProviderUser[]; - if (this.dataSource.isIncreasedBulkLimitEnabled()) { - checkedInvitedUsers = this.dataSource.limitAndUncheckExcess( - allInvitedUsers, - CloudBulkReinviteLimit, - ); - } else { - checkedInvitedUsers = allInvitedUsers; - } - - if (checkedInvitedUsers.length <= 0) { - this.toastService.showToast({ - variant: "error", - title: this.i18nService.t("errorOccurred"), - message: this.i18nService.t("noSelectedUsersApplicable"), - }); - return; - } - - try { - // When feature flag is enabled, show toast instead of dialog - if (this.dataSource.isIncreasedBulkLimitEnabled()) { - await this.apiService.postManyProviderUserReinvite( - this.providerId, - new ProviderUserBulkRequest(checkedInvitedUsers.map((user) => user.id)), - ); - - const selectedCount = originalInvitedCount; - const invitedCount = checkedInvitedUsers.length; - - if (selectedCount > CloudBulkReinviteLimit) { - const excludedCount = selectedCount - CloudBulkReinviteLimit; - this.toastService.showToast({ - variant: "success", - message: this.i18nService.t( - "bulkReinviteLimitedSuccessToast", - CloudBulkReinviteLimit.toLocaleString(), - selectedCount.toLocaleString(), - excludedCount.toLocaleString(), - ), - }); - } else { - this.toastService.showToast({ - variant: "success", - message: - invitedCount === 1 - ? this.i18nService.t("reinviteSuccessToast") - : this.i18nService.t("bulkReinviteSentToast", invitedCount.toString()), - }); - } - } else { - // Feature flag disabled - show legacy dialog - const request = this.apiService - .postManyProviderUserReinvite( - this.providerId, - new ProviderUserBulkRequest(checkedInvitedUsers.map((user) => user.id)), - ) - .then((response) => response.data); - - const dialogRef = BulkStatusComponent.open(this.dialogService, { - data: { - users: users, - filteredUsers: checkedInvitedUsers, - request, - successfulMessage: this.i18nService.t("bulkReinviteMessage"), - }, - }); - await lastValueFrom(dialogRef.closed); - } - } catch (error) { - this.validationService.showError(error); - } - } - - async invite() { - await this.edit(null); - } - - async bulkRemove(): Promise { - if (this.actionPromise != null) { - return; - } - - const users = this.dataSource.getCheckedUsersWithLimit(MaxCheckedCount); - - const dialogRef = BulkRemoveDialogComponent.open(this.dialogService, { - data: { - providerId: this.providerId, - users: users, - }, - }); - - await lastValueFrom(dialogRef.closed); - await this.load(); - } - - async confirmUser(user: ProviderUser, publicKey: Uint8Array): Promise { - try { - const providerKey = await firstValueFrom( - this.accountService.activeAccount$.pipe( - getUserId, - switchMap((userId) => this.keyService.providerKeys$(userId)), - map((providerKeys) => providerKeys?.[this.providerId as ProviderId] ?? null), - ), - ); - assertNonNullish(providerKey, "Provider key not found"); - - const key = await this.encryptService.encapsulateKeyUnsigned(providerKey, publicKey); - const request = new ProviderUserConfirmRequest(key.encryptedString); - await this.apiService.postProviderUserConfirm(this.providerId, user.id, request); - return { success: true }; - } catch (error) { - return { success: false, error: error.message }; - } - } - - removeUser = async (id: string): Promise => { - try { - await this.apiService.deleteProviderUser(this.providerId, id); - return { success: true }; - } catch (error) { - return { success: false, error: error.message }; - } - }; - - edit = async (user: ProviderUser | null): Promise => { - const data: AddEditMemberDialogParams = { - providerId: this.providerId, - user, - }; - - const dialogRef = AddEditMemberDialogComponent.open(this.dialogService, { - data, - }); - - const result = await lastValueFrom(dialogRef.closed); - - switch (result) { - case AddEditMemberDialogResultType.Saved: - case AddEditMemberDialogResultType.Deleted: - await this.load(); - break; - } - }; - - openEventsDialog = (user: ProviderUser): DialogRef => - openEntityEventsDialog(this.dialogService, { - data: { - name: this.userNamePipe.transform(user), - providerId: this.providerId, - entityId: user.id, - showUser: false, - entity: "user", - }, - }); - - getUsers = (): Promise> => - this.apiService.getProviderUsers(this.providerId); - - reinviteUser = async (id: string): Promise => { - try { - await this.apiService.postProviderUserReinvite(this.providerId, id); - return { success: true }; - } catch (error) { - return { success: false, error: error.message }; - } - }; - - get selectedInvitedCount(): number { - return this.dataSource - .getCheckedUsers() - .filter((member) => member.status === this.userStatusType.Invited).length; - } - - get isSingleInvite(): boolean { - return this.selectedInvitedCount === 1; - } -} diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/members.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/members.component.ts index 308b93ac2e3..d4a6ba92451 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/members.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/members.component.ts @@ -61,7 +61,7 @@ interface BulkProviderFlags { templateUrl: "members.component.html", standalone: false, }) -export class vNextMembersComponent { +export class MembersComponent { protected apiService = inject(ApiService); protected dialogService = inject(DialogService); protected i18nService = inject(I18nService); diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-routing.module.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-routing.module.ts index 447481a8bcb..5fadc935644 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-routing.module.ts @@ -2,9 +2,7 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; import { authGuard } from "@bitwarden/angular/auth/guards"; -import { featureFlaggedRoute } from "@bitwarden/angular/platform/utils/feature-flagged-route"; import { Provider } from "@bitwarden/common/admin-console/models/domain/provider"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { AnonLayoutWrapperComponent } from "@bitwarden/components"; import { FrontendLayoutComponent } from "@bitwarden/web-vault/app/layouts/frontend-layout.component"; import { UserLayoutComponent } from "@bitwarden/web-vault/app/layouts/user-layout.component"; @@ -17,9 +15,8 @@ import { ProviderSubscriptionComponent } from "../../billing/providers/subscript import { ManageClientsComponent } from "./clients/manage-clients.component"; import { providerPermissionsGuard } from "./guards/provider-permissions.guard"; import { AcceptProviderComponent } from "./manage/accept-provider.component"; -import { MembersComponent } from "./manage/deprecated_members.component"; import { EventsComponent } from "./manage/events.component"; -import { vNextMembersComponent } from "./manage/members.component"; +import { MembersComponent } from "./manage/members.component"; import { ProvidersLayoutComponent } from "./providers-layout.component"; import { ProvidersComponent } from "./providers.component"; import { AccountComponent } from "./settings/account.component"; @@ -95,20 +92,16 @@ const routes: Routes = [ pathMatch: "full", redirectTo: "members", }, - ...featureFlaggedRoute({ - defaultComponent: MembersComponent, - flaggedComponent: vNextMembersComponent, - featureFlag: FeatureFlag.MembersComponentRefactor, - routeOptions: { - path: "members", - canActivate: [ - providerPermissionsGuard((provider: Provider) => provider.canManageUsers), - ], - data: { - titleId: "members", - }, + { + path: "members", + component: MembersComponent, + canActivate: [ + providerPermissionsGuard((provider: Provider) => provider.canManageUsers), + ], + data: { + titleId: "members", }, - }), + }, { path: "events", component: EventsComponent, diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts index 44e2e51637f..abdd35c5e61 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts @@ -27,12 +27,11 @@ import { CreateClientDialogComponent } from "./clients/create-client-dialog.comp import { ManageClientNameDialogComponent } from "./clients/manage-client-name-dialog.component"; import { ManageClientSubscriptionDialogComponent } from "./clients/manage-client-subscription-dialog.component"; import { AcceptProviderComponent } from "./manage/accept-provider.component"; -import { MembersComponent } from "./manage/deprecated_members.component"; import { AddEditMemberDialogComponent } from "./manage/dialogs/add-edit-member-dialog.component"; import { BulkConfirmDialogComponent } from "./manage/dialogs/bulk-confirm-dialog.component"; import { BulkRemoveDialogComponent } from "./manage/dialogs/bulk-remove-dialog.component"; import { EventsComponent } from "./manage/events.component"; -import { vNextMembersComponent } from "./manage/members.component"; +import { MembersComponent } from "./manage/members.component"; import { ProviderActionsService } from "./manage/services/provider-actions/provider-actions.service"; import { ProvidersLayoutComponent } from "./providers-layout.component"; import { ProvidersRoutingModule } from "./providers-routing.module"; @@ -67,7 +66,6 @@ import { VerifyRecoverDeleteProviderComponent } from "./verify-recover-delete-pr BulkConfirmDialogComponent, BulkRemoveDialogComponent, EventsComponent, - vNextMembersComponent, MembersComponent, SetupComponent, SetupProviderComponent, diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/shared/security-tasks.service.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/shared/security-tasks.service.ts index 65a31896341..2307eab04fe 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/shared/security-tasks.service.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/shared/security-tasks.service.ts @@ -1,8 +1,10 @@ import { BehaviorSubject, combineLatest, Observable } from "rxjs"; import { map, shareReplay } from "rxjs/operators"; -import { RiskInsightsDataService } from "@bitwarden/bit-common/dirt/reports/risk-insights"; -import { SecurityTasksApiService } from "@bitwarden/bit-common/dirt/reports/risk-insights"; +import { + RiskInsightsDataService, + SecurityTasksApiService, +} from "@bitwarden/bit-common/dirt/reports/risk-insights"; import { CipherId, OrganizationId } from "@bitwarden/common/types/guid"; import { SecurityTask, SecurityTaskStatus, SecurityTaskType } from "@bitwarden/common/vault/tasks"; diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 4db9ff37d42..05fded6bcaf 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -13,7 +13,6 @@ export enum FeatureFlag { /* Admin Console Team */ AutoConfirm = "pm-19934-auto-confirm-organization-users", DefaultUserCollectionRestore = "pm-30883-my-items-restored-users", - MembersComponentRefactor = "pm-29503-refactor-members-inheritance", BulkReinviteUI = "pm-28416-bulk-reinvite-ux-improvements", /* Auth */ @@ -109,7 +108,6 @@ export const DefaultFeatureFlagValue = { /* Admin Console Team */ [FeatureFlag.AutoConfirm]: FALSE, [FeatureFlag.DefaultUserCollectionRestore]: FALSE, - [FeatureFlag.MembersComponentRefactor]: FALSE, [FeatureFlag.BulkReinviteUI]: FALSE, /* Autofill */ From fa40de92b140822b640587c9ff6436ede419ebf7 Mon Sep 17 00:00:00 2001 From: Isaiah Inuwa Date: Fri, 13 Feb 2026 11:01:27 -0600 Subject: [PATCH 04/23] Remove unneeded workaround to get credential ID from request (#18784) --- .../services/desktop-autofill.service.ts | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/apps/desktop/src/autofill/services/desktop-autofill.service.ts b/apps/desktop/src/autofill/services/desktop-autofill.service.ts index e5cd85aa7a3..ae3c75d6f01 100644 --- a/apps/desktop/src/autofill/services/desktop-autofill.service.ts +++ b/apps/desktop/src/autofill/services/desktop-autofill.service.ts @@ -16,7 +16,6 @@ import { import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { getOptionalUserId } from "@bitwarden/common/auth/services/account.service"; import { DeviceType } from "@bitwarden/common/enums"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service"; @@ -31,7 +30,6 @@ import { import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { parseCredentialId } from "@bitwarden/common/platform/services/fido2/credential-id-utils"; import { getCredentialsForAutofill } from "@bitwarden/common/platform/services/fido2/fido2-autofill-utils"; import { Fido2Utils } from "@bitwarden/common/platform/services/fido2/fido2-utils"; import { UserId } from "@bitwarden/common/types/guid"; @@ -258,39 +256,6 @@ export class DesktopAutofillService implements OnDestroy { const controller = new AbortController(); try { - // For some reason the credentialId is passed as an empty array in the request, so we need to - // get it from the cipher. For that we use the recordIdentifier, which is the cipherId. - if (request.recordIdentifier && request.credentialId.length === 0) { - const activeUserId = await firstValueFrom( - this.accountService.activeAccount$.pipe(getOptionalUserId), - ); - if (!activeUserId) { - this.logService.error("listenPasskeyAssertion error", "Active user not found"); - callback(new Error("Active user not found"), null); - return; - } - - const cipher = await this.cipherService.get(request.recordIdentifier, activeUserId); - if (!cipher) { - this.logService.error("listenPasskeyAssertion error", "Cipher not found"); - callback(new Error("Cipher not found"), null); - return; - } - - const decrypted = await this.cipherService.decrypt(cipher, activeUserId); - - const fido2Credential = decrypted.login.fido2Credentials?.[0]; - if (!fido2Credential) { - this.logService.error("listenPasskeyAssertion error", "Fido2Credential not found"); - callback(new Error("Fido2Credential not found"), null); - return; - } - - request.credentialId = Array.from( - new Uint8Array(parseCredentialId(decrypted.login.fido2Credentials?.[0].credentialId)), - ); - } - const response = await this.fido2AuthenticatorService.getAssertion( this.convertAssertionRequest(request, true), { windowXy: normalizePosition(request.windowXy) }, From ab702e3a1aeac20d777eb131cc9953a0f89a9b24 Mon Sep 17 00:00:00 2001 From: Isaiah Inuwa Date: Fri, 13 Feb 2026 11:01:42 -0600 Subject: [PATCH 05/23] Don't sync invalid password ciphers to autofill (#18783) --- .../desktop/src/autofill/services/desktop-autofill.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/autofill/services/desktop-autofill.service.ts b/apps/desktop/src/autofill/services/desktop-autofill.service.ts index ae3c75d6f01..cca0097d65e 100644 --- a/apps/desktop/src/autofill/services/desktop-autofill.service.ts +++ b/apps/desktop/src/autofill/services/desktop-autofill.service.ts @@ -150,11 +150,13 @@ export class DesktopAutofillService implements OnDestroy { passwordCredentials = cipherViews .filter( (cipher) => + !cipher.isDeleted && cipher.type === CipherType.Login && cipher.login.uris?.length > 0 && cipher.login.uris.some((uri) => uri.match !== UriMatchStrategy.Never) && cipher.login.uris.some((uri) => !Utils.isNullOrWhitespace(uri.uri)) && - !Utils.isNullOrWhitespace(cipher.login.username), + !Utils.isNullOrWhitespace(cipher.login.username) && + !Utils.isNullOrWhitespace(cipher.login.password), ) .map((cipher) => ({ type: "password", From ab0739b693761e11979386c2d85ef0553ed15ff0 Mon Sep 17 00:00:00 2001 From: John Harrington <84741727+harr1424@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:23:25 -0700 Subject: [PATCH 06/23] rename flag to emails (#18955) --- .../send/commands/create.command.spec.ts | 8 ++--- .../src/tools/send/commands/create.command.ts | 2 +- .../tools/send/commands/edit.command.spec.ts | 8 ++--- .../src/tools/send/commands/edit.command.ts | 2 +- apps/cli/src/tools/send/send.program.ts | 32 +++++++++++-------- 5 files changed, 29 insertions(+), 23 deletions(-) diff --git a/apps/cli/src/tools/send/commands/create.command.spec.ts b/apps/cli/src/tools/send/commands/create.command.spec.ts index d3702689812..20f4d3e722e 100644 --- a/apps/cli/src/tools/send/commands/create.command.spec.ts +++ b/apps/cli/src/tools/send/commands/create.command.spec.ts @@ -62,7 +62,7 @@ describe("SendCreateCommand", () => { }; const cmdOptions = { - email: ["test@example.com"], + emails: ["test@example.com"], }; sendService.encrypt.mockResolvedValue([ @@ -155,7 +155,7 @@ describe("SendCreateCommand", () => { }; const cmdOptions = { - email: ["test@example.com"], + emails: ["test@example.com"], password: "testPassword123", }; @@ -246,7 +246,7 @@ describe("SendCreateCommand", () => { }; const cmdOptions = { - email: ["cli@example.com"], + emails: ["cli@example.com"], }; const response = await command.run(requestJson, cmdOptions); @@ -282,7 +282,7 @@ describe("SendCreateCommand", () => { }; const cmdOptions = { - email: ["cli@example.com"], + emails: ["cli@example.com"], }; sendService.encrypt.mockResolvedValue([ diff --git a/apps/cli/src/tools/send/commands/create.command.ts b/apps/cli/src/tools/send/commands/create.command.ts index ad4ff9c4e18..41cf5143acc 100644 --- a/apps/cli/src/tools/send/commands/create.command.ts +++ b/apps/cli/src/tools/send/commands/create.command.ts @@ -173,7 +173,7 @@ class Options { this.file = passedOptions?.file; this.text = passedOptions?.text; this.password = passedOptions?.password; - this.emails = passedOptions?.email; + this.emails = passedOptions?.emails; this.hidden = CliUtils.convertBooleanOption(passedOptions?.hidden); this.maxAccessCount = passedOptions?.maxAccessCount != null ? parseInt(passedOptions.maxAccessCount, null) : null; diff --git a/apps/cli/src/tools/send/commands/edit.command.spec.ts b/apps/cli/src/tools/send/commands/edit.command.spec.ts index 5bac63d3821..b72e9fdd512 100644 --- a/apps/cli/src/tools/send/commands/edit.command.spec.ts +++ b/apps/cli/src/tools/send/commands/edit.command.spec.ts @@ -81,7 +81,7 @@ describe("SendEditCommand", () => { const requestJson = encodeRequest(requestData); const cmdOptions = { - email: ["test@example.com"], + emails: ["test@example.com"], }; sendService.encrypt.mockResolvedValue([ @@ -155,7 +155,7 @@ describe("SendEditCommand", () => { const requestJson = encodeRequest(requestData); const cmdOptions = { - email: ["test@example.com"], + emails: ["test@example.com"], password: "testPassword123", }; @@ -239,7 +239,7 @@ describe("SendEditCommand", () => { const requestJson = encodeRequest(requestData); const cmdOptions = { - email: ["cli@example.com"], + emails: ["cli@example.com"], }; const response = await command.run(requestJson, cmdOptions); @@ -277,7 +277,7 @@ describe("SendEditCommand", () => { const requestJson = encodeRequest(requestData); const cmdOptions = { - email: ["cli@example.com"], + emails: ["cli@example.com"], }; sendService.encrypt.mockResolvedValue([ diff --git a/apps/cli/src/tools/send/commands/edit.command.ts b/apps/cli/src/tools/send/commands/edit.command.ts index 0709a33b88f..f3828784979 100644 --- a/apps/cli/src/tools/send/commands/edit.command.ts +++ b/apps/cli/src/tools/send/commands/edit.command.ts @@ -124,6 +124,6 @@ class Options { constructor(passedOptions: Record) { this.itemId = passedOptions?.itemId || passedOptions?.itemid; this.password = passedOptions.password; - this.emails = passedOptions.email; + this.emails = passedOptions.emails; } } diff --git a/apps/cli/src/tools/send/send.program.ts b/apps/cli/src/tools/send/send.program.ts index e40cea4daa9..a2f43bc2df8 100644 --- a/apps/cli/src/tools/send/send.program.ts +++ b/apps/cli/src/tools/send/send.program.ts @@ -57,11 +57,11 @@ export class SendProgram extends BaseProgram { new Option( "--password ", "optional password to access this Send. Can also be specified in JSON.", - ).conflicts("email"), + ).conflicts("emails"), ) .addOption( new Option( - "--email ", + "--emails ", "optional emails to access this Send. Can also be specified in JSON.", ).argParser(parseEmail), ) @@ -85,9 +85,11 @@ export class SendProgram extends BaseProgram { .addCommand(this.removePasswordCommand()) .addCommand(this.deleteCommand()) .action(async (data: string, options: OptionValues) => { - if (options.email) { + if (options.emails) { if (!emailAuthEnabled) { - this.processResponse(Response.error("The --email feature is not currently available.")); + this.processResponse( + Response.error("The --emails feature is not currently available."), + ); return; } } @@ -225,11 +227,13 @@ export class SendProgram extends BaseProgram { }) .action(async (encodedJson: string, options: OptionValues, args: { parent: Command }) => { // subcommands inherit flags from their parent; they cannot override them - const { fullObject = false, email = undefined, password = undefined } = args.parent.opts(); + const { fullObject = false, emails = undefined, password = undefined } = args.parent.opts(); - if (email) { + if (emails) { if (!emailAuthEnabled) { - this.processResponse(Response.error("The --email feature is not currently available.")); + this.processResponse( + Response.error("The --emails feature is not currently available."), + ); return; } } @@ -237,7 +241,7 @@ export class SendProgram extends BaseProgram { const mergedOptions = { ...options, fullObject: fullObject, - email, + emails, password, }; @@ -262,10 +266,12 @@ export class SendProgram extends BaseProgram { }) .action(async (encodedJson: string, options: OptionValues, args: { parent: Command }) => { await this.exitIfLocked(); - const { email = undefined, password = undefined } = args.parent.opts(); - if (email) { + const { emails = undefined, password = undefined } = args.parent.opts(); + if (emails) { if (!emailAuthEnabled) { - this.processResponse(Response.error("The --email feature is not currently available.")); + this.processResponse( + Response.error("The --emails feature is not currently available."), + ); return; } } @@ -288,7 +294,7 @@ export class SendProgram extends BaseProgram { const mergedOptions = { ...options, - email, + emails, password, }; @@ -353,7 +359,7 @@ export class SendProgram extends BaseProgram { file: sendFile, text: sendText, type: type, - emails: options.email ?? undefined, + emails: options.emails ?? undefined, }); return Buffer.from(JSON.stringify(template), "utf8").toString("base64"); From f46511b3e86b6d7c2ae4d995d464b00f52177c4b Mon Sep 17 00:00:00 2001 From: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:56:35 +0100 Subject: [PATCH 07/23] [PM-30908]Correct Premium subscription status handling (#18475) * Implement the required changes * Fix the family plan creation for expired sub * Resolve the pr comments * resolve the resubscribe issue * Removed redirectOnCompletion: true from the resubscribe * Display the Change payment method dialog on the subscription page * adjust the page reload time * revert payment method open in subscription page * Enable cancel premium see the subscription page * Revert the removal of hasPremiumPersonally * remove extra space * Add can view subscription * Use the canViewSubscription * Resolve the tab default to premium * use the subscription Instead of hasPremium * Revert the changes on user-subscription * Use the flag to redirect to subscription page * revert the canViewSubscription change * resolve the route issue with premium * Change the path to * Revert the previous iteration changes * Fix the build error --- .../billing/clients/account-billing.client.ts | 17 +++-- .../individual-billing-routing.module.ts | 2 +- .../individual/subscription.component.ts | 23 ++++++- .../account-subscription.component.ts | 32 +++++++++- apps/web/src/locales/en/messages.json | 9 +++ .../subscription-card.component.mdx | 5 +- .../subscription-card.component.spec.ts | 63 ++++++++++++++++--- .../subscription-card.component.stories.ts | 7 ++- .../subscription-card.component.ts | 20 ++++-- 9 files changed, 153 insertions(+), 25 deletions(-) diff --git a/apps/web/src/app/billing/clients/account-billing.client.ts b/apps/web/src/app/billing/clients/account-billing.client.ts index 1334ff643dd..6864e1de981 100644 --- a/apps/web/src/app/billing/clients/account-billing.client.ts +++ b/apps/web/src/app/billing/clients/account-billing.client.ts @@ -4,6 +4,8 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ProductTierType } from "@bitwarden/common/billing/enums"; import { BitwardenSubscriptionResponse } from "@bitwarden/common/billing/models/response/bitwarden-subscription.response"; import { SubscriptionCadence } from "@bitwarden/common/billing/types/subscription-pricing-tier"; +import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; +import { Maybe } from "@bitwarden/pricing"; import { BitwardenSubscription } from "@bitwarden/subscription"; import { @@ -23,11 +25,18 @@ export class AccountBillingClient { return this.apiService.send("GET", path, null, true, true); }; - getSubscription = async (): Promise => { + getSubscription = async (): Promise> => { const path = `${this.endpoint}/subscription`; - const json = await this.apiService.send("GET", path, null, true, true); - const response = new BitwardenSubscriptionResponse(json); - return response.toDomain(); + try { + const json = await this.apiService.send("GET", path, null, true, true); + const response = new BitwardenSubscriptionResponse(json); + return response.toDomain(); + } catch (error: any) { + if (error instanceof ErrorResponse && error.statusCode === 404) { + return null; + } + throw error; + } }; purchaseSubscription = async ( diff --git a/apps/web/src/app/billing/individual/individual-billing-routing.module.ts b/apps/web/src/app/billing/individual/individual-billing-routing.module.ts index f85dab54fe7..8d9c999caec 100644 --- a/apps/web/src/app/billing/individual/individual-billing-routing.module.ts +++ b/apps/web/src/app/billing/individual/individual-billing-routing.module.ts @@ -19,7 +19,7 @@ const routes: Routes = [ component: SubscriptionComponent, data: { titleId: "subscription" }, children: [ - { path: "", pathMatch: "full", redirectTo: "premium" }, + { path: "", pathMatch: "full", redirectTo: "user-subscription" }, ...featureFlaggedRoute({ defaultComponent: UserSubscriptionComponent, flaggedComponent: AccountSubscriptionComponent, diff --git a/apps/web/src/app/billing/individual/subscription.component.ts b/apps/web/src/app/billing/individual/subscription.component.ts index 37fb2baf3a6..4f52f3c2ea2 100644 --- a/apps/web/src/app/billing/individual/subscription.component.ts +++ b/apps/web/src/app/billing/individual/subscription.component.ts @@ -1,17 +1,22 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { Component, OnInit } from "@angular/core"; -import { Observable, switchMap } from "rxjs"; +import { combineLatest, from, map, Observable, switchMap } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { AccountBillingClient } from "../clients/account-billing.client"; + // FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush // eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @Component({ templateUrl: "subscription.component.html", standalone: false, + providers: [AccountBillingClient], }) export class SubscriptionComponent implements OnInit { hasPremium$: Observable; @@ -21,9 +26,21 @@ export class SubscriptionComponent implements OnInit { private platformUtilsService: PlatformUtilsService, billingAccountProfileStateService: BillingAccountProfileStateService, accountService: AccountService, + configService: ConfigService, + private accountBillingClient: AccountBillingClient, ) { - this.hasPremium$ = accountService.activeAccount$.pipe( - switchMap((account) => billingAccountProfileStateService.hasPremiumPersonally$(account.id)), + this.hasPremium$ = combineLatest([ + configService.getFeatureFlag$(FeatureFlag.PM29594_UpdateIndividualSubscriptionPage), + accountService.activeAccount$, + ]).pipe( + switchMap(([isFeatureFlagEnabled, account]) => { + if (isFeatureFlagEnabled) { + return from(accountBillingClient.getSubscription()).pipe( + map((subscription) => !!subscription), + ); + } + return billingAccountProfileStateService.hasPremiumPersonally$(account.id); + }), ); } diff --git a/apps/web/src/app/billing/individual/subscription/account-subscription.component.ts b/apps/web/src/app/billing/individual/subscription/account-subscription.component.ts index d8e25de7965..7fdc830effd 100644 --- a/apps/web/src/app/billing/individual/subscription/account-subscription.component.ts +++ b/apps/web/src/app/billing/individual/subscription/account-subscription.component.ts @@ -34,6 +34,11 @@ import { AdjustAccountSubscriptionStorageDialogComponent, AdjustAccountSubscriptionStorageDialogParams, } from "@bitwarden/web-vault/app/billing/individual/subscription/adjust-account-subscription-storage-dialog.component"; +import { + UnifiedUpgradeDialogComponent, + UnifiedUpgradeDialogStatus, + UnifiedUpgradeDialogStep, +} from "@bitwarden/web-vault/app/billing/individual/upgrade/unified-upgrade-dialog/unified-upgrade-dialog.component"; import { OffboardingSurveyDialogResultType, openOffboardingSurvey, @@ -93,10 +98,11 @@ export class AccountSubscriptionComponent { if (!this.account()) { return await redirectToPremiumPage(); } - if (!this.hasPremiumPersonally()) { + const subscription = await this.accountBillingClient.getSubscription(); + if (!subscription) { return await redirectToPremiumPage(); } - return await this.accountBillingClient.getSubscription(); + return subscription; }, }); @@ -106,6 +112,7 @@ export class AccountSubscriptionComponent { const subscription = this.subscription.value(); if (subscription) { return ( + subscription.status === SubscriptionStatuses.Incomplete || subscription.status === SubscriptionStatuses.IncompleteExpired || subscription.status === SubscriptionStatuses.Canceled || subscription.status === SubscriptionStatuses.Unpaid @@ -230,6 +237,27 @@ export class AccountSubscriptionComponent { case SubscriptionCardActions.UpdatePayment: await this.router.navigate(["../payment-details"], { relativeTo: this.activatedRoute }); break; + case SubscriptionCardActions.Resubscribe: { + const account = this.account(); + if (!account) { + return; + } + + const dialogRef = UnifiedUpgradeDialogComponent.open(this.dialogService, { + data: { + account, + initialStep: UnifiedUpgradeDialogStep.Payment, + selectedPlan: PersonalSubscriptionPricingTierIds.Premium, + }, + }); + + const result = await lastValueFrom(dialogRef.closed); + + if (result?.status === UnifiedUpgradeDialogStatus.UpgradedToPremium) { + this.subscription.reload(); + } + break; + } case SubscriptionCardActions.UpgradePlan: await this.openUpgradeDialog(); break; diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 59f5bc88419..d70a2d88bae 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, diff --git a/libs/subscription/src/components/subscription-card/subscription-card.component.mdx b/libs/subscription/src/components/subscription-card/subscription-card.component.mdx index c9cc6df7263..d3bad6583f5 100644 --- a/libs/subscription/src/components/subscription-card/subscription-card.component.mdx +++ b/libs/subscription/src/components/subscription-card/subscription-card.component.mdx @@ -78,6 +78,7 @@ type SubscriptionCardAction = | "contact-support" | "manage-invoices" | "reinstate-subscription" + | "resubscribe" | "update-payment" | "upgrade-plan"; ``` @@ -279,7 +280,7 @@ Payment issue expired, subscription has been suspended: ``` -**Actions available:** Contact Support +**Actions available:** Resubscribe ### Past Due @@ -370,7 +371,7 @@ Subscription that has been canceled: ``` -**Note:** Canceled subscriptions display no callout or actions. +**Actions available:** Resubscribe ### Enterprise diff --git a/libs/subscription/src/components/subscription-card/subscription-card.component.spec.ts b/libs/subscription/src/components/subscription-card/subscription-card.component.spec.ts index cdb85360c74..f524c4b5c26 100644 --- a/libs/subscription/src/components/subscription-card/subscription-card.component.spec.ts +++ b/libs/subscription/src/components/subscription-card/subscription-card.component.spec.ts @@ -44,9 +44,11 @@ describe("SubscriptionCardComponent", () => { unpaid: "Unpaid", weCouldNotProcessYourPayment: "We could not process your payment", contactSupportShort: "Contact support", - yourSubscriptionHasExpired: "Your subscription has expired", + yourSubscriptionIsExpired: "Your subscription is expired", + yourSubscriptionIsCanceled: "Your subscription is canceled", yourSubscriptionIsScheduledToCancel: `Your subscription is scheduled to cancel on ${params[0]}`, reinstateSubscription: "Reinstate subscription", + resubscribe: "Resubscribe", upgradeYourPlan: "Upgrade your plan", premiumShareEvenMore: "Premium share even more", upgradeNow: "Upgrade now", @@ -253,7 +255,7 @@ describe("SubscriptionCardComponent", () => { expect(buttons[1].nativeElement.textContent.trim()).toBe("Contact support"); }); - it("should display incomplete_expired callout with contact support action", () => { + it("should display incomplete_expired callout with resubscribe action", () => { setupComponent({ ...baseSubscription, status: "incomplete_expired", @@ -265,18 +267,18 @@ describe("SubscriptionCardComponent", () => { expect(calloutData).toBeTruthy(); expect(calloutData!.type).toBe("danger"); expect(calloutData!.title).toBe("Expired"); - expect(calloutData!.description).toContain("Your subscription has expired"); + expect(calloutData!.description).toContain("Your subscription is expired"); expect(calloutData!.callsToAction?.length).toBe(1); const callout = fixture.debugElement.query(By.css("bit-callout")); expect(callout).toBeTruthy(); const description = callout.query(By.css("p")); - expect(description.nativeElement.textContent).toContain("Your subscription has expired"); + expect(description.nativeElement.textContent).toContain("Your subscription is expired"); const buttons = callout.queryAll(By.css("button")); expect(buttons.length).toBe(1); - expect(buttons[0].nativeElement.textContent.trim()).toBe("Contact support"); + expect(buttons[0].nativeElement.textContent.trim()).toBe("Resubscribe"); }); it("should display pending cancellation callout for active status with cancelAt", () => { @@ -364,15 +366,29 @@ describe("SubscriptionCardComponent", () => { expect(buttons[0].nativeElement.textContent.trim()).toBe("Manage invoices"); }); - it("should not display callout for canceled status", () => { + it("should display canceled callout with resubscribe action", () => { setupComponent({ ...baseSubscription, status: "canceled", canceled: new Date("2025-01-15"), }); + const calloutData = component.callout(); + expect(calloutData).toBeTruthy(); + expect(calloutData!.type).toBe("danger"); + expect(calloutData!.title).toBe("Canceled"); + expect(calloutData!.description).toContain("Your subscription is canceled"); + expect(calloutData!.callsToAction?.length).toBe(1); + const callout = fixture.debugElement.query(By.css("bit-callout")); - expect(callout).toBeFalsy(); + expect(callout).toBeTruthy(); + + const description = callout.query(By.css("p")); + expect(description.nativeElement.textContent).toContain("Your subscription is canceled"); + + const buttons = callout.queryAll(By.css("button")); + expect(buttons.length).toBe(1); + expect(buttons[0].nativeElement.textContent.trim()).toBe("Resubscribe"); }); it("should display unpaid callout with manage invoices action", () => { @@ -489,6 +505,39 @@ describe("SubscriptionCardComponent", () => { expect(emitSpy).toHaveBeenCalledWith("manage-invoices"); }); + + it("should emit resubscribe action when button is clicked for incomplete_expired status", () => { + setupComponent({ + ...baseSubscription, + status: "incomplete_expired", + suspension: new Date("2025-01-15"), + gracePeriod: 7, + }); + + const emitSpy = jest.spyOn(component.callToActionClicked, "emit"); + + const button = fixture.debugElement.query(By.css("bit-callout button")); + button.triggerEventHandler("click", { button: 0 }); + fixture.detectChanges(); + + expect(emitSpy).toHaveBeenCalledWith("resubscribe"); + }); + + it("should emit resubscribe action when button is clicked for canceled status", () => { + setupComponent({ + ...baseSubscription, + status: "canceled", + canceled: new Date("2025-01-15"), + }); + + const emitSpy = jest.spyOn(component.callToActionClicked, "emit"); + + const button = fixture.debugElement.query(By.css("bit-callout button")); + button.triggerEventHandler("click", { button: 0 }); + fixture.detectChanges(); + + expect(emitSpy).toHaveBeenCalledWith("resubscribe"); + }); }); describe("Cart summary header content", () => { diff --git a/libs/subscription/src/components/subscription-card/subscription-card.component.stories.ts b/libs/subscription/src/components/subscription-card/subscription-card.component.stories.ts index 32976c89cc2..3d99ded2e5c 100644 --- a/libs/subscription/src/components/subscription-card/subscription-card.component.stories.ts +++ b/libs/subscription/src/components/subscription-card/subscription-card.component.stories.ts @@ -51,10 +51,13 @@ export default { weCouldNotProcessYourPayment: "We could not process your payment. Please update your payment method or contact the support team for assistance.", contactSupportShort: "Contact Support", - yourSubscriptionHasExpired: - "Your subscription has expired. Please contact the support team for assistance.", + yourSubscriptionIsExpired: + "Your subscription is expired. Please resubscribe to continue using premium features.", + yourSubscriptionIsCanceled: + "Your subscription is canceled. Please resubscribe to continue using premium features.", yourSubscriptionIsScheduledToCancel: `Your subscription is scheduled to cancel on ${args[0]}. You can reinstate it anytime before then.`, reinstateSubscription: "Reinstate subscription", + resubscribe: "Resubscribe", upgradeYourPlan: "Upgrade your plan", premiumShareEvenMore: "Share even more with Families, or get powerful, trusted password security with Teams or Enterprise.", diff --git a/libs/subscription/src/components/subscription-card/subscription-card.component.ts b/libs/subscription/src/components/subscription-card/subscription-card.component.ts index ebfb41df6c2..78d2c40eb3e 100644 --- a/libs/subscription/src/components/subscription-card/subscription-card.component.ts +++ b/libs/subscription/src/components/subscription-card/subscription-card.component.ts @@ -20,6 +20,7 @@ export const SubscriptionCardActions = { ContactSupport: "contact-support", ManageInvoices: "manage-invoices", ReinstateSubscription: "reinstate-subscription", + Resubscribe: "resubscribe", UpdatePayment: "update-payment", UpgradePlan: "upgrade-plan", } as const; @@ -154,12 +155,12 @@ export class SubscriptionCardComponent { return { title: this.i18nService.t("expired"), type: "danger", - description: this.i18nService.t("yourSubscriptionHasExpired"), + description: this.i18nService.t("yourSubscriptionIsExpired"), callsToAction: [ { - text: this.i18nService.t("contactSupportShort"), + text: this.i18nService.t("resubscribe"), buttonType: "unstyled", - action: SubscriptionCardActions.ContactSupport, + action: SubscriptionCardActions.Resubscribe, }, ], }; @@ -218,7 +219,18 @@ export class SubscriptionCardComponent { }; } case SubscriptionStatuses.Canceled: { - return null; + return { + title: this.i18nService.t("canceled"), + type: "danger", + description: this.i18nService.t("yourSubscriptionIsCanceled"), + callsToAction: [ + { + text: this.i18nService.t("resubscribe"), + buttonType: "unstyled", + action: SubscriptionCardActions.Resubscribe, + }, + ], + }; } case SubscriptionStatuses.Unpaid: { return { From 10a20a43a36be6d76f3f1a3bf4d57fa2b56678b1 Mon Sep 17 00:00:00 2001 From: Jason Ng Date: Fri, 13 Feb 2026 13:53:11 -0500 Subject: [PATCH 08/23] [PM-31738] update archive toasts (#18923) * update archive toast for all clients and trash archive restore toast, update archive cipher utilities spec --- apps/browser/src/_locales/en/messages.json | 11 ++++------- .../item-more-options/item-more-options.component.ts | 2 +- .../popup/components/vault/view/view.component.ts | 9 ++++++++- .../src/vault/popup/settings/archive.component.ts | 2 +- apps/desktop/src/locales/en/messages.json | 8 ++++---- .../vault-item-dialog/vault-item-dialog.component.ts | 4 ++-- .../src/app/vault/individual-vault/vault.component.ts | 4 ++-- apps/web/src/locales/en/messages.json | 11 ++++------- .../services/archive-cipher-utilities.service.spec.ts | 4 ++-- .../src/services/archive-cipher-utilities.service.ts | 4 ++-- 10 files changed, 30 insertions(+), 29 deletions(-) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 7944904c44a..e77550b01dc 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/vault/popup/components/vault/item-more-options/item-more-options.component.ts b/apps/browser/src/vault/popup/components/vault/item-more-options/item-more-options.component.ts index ef4c4a111b6..f7fe9ee1494 100644 --- a/apps/browser/src/vault/popup/components/vault/item-more-options/item-more-options.component.ts +++ b/apps/browser/src/vault/popup/components/vault/item-more-options/item-more-options.component.ts @@ -383,7 +383,7 @@ export class ItemMoreOptionsComponent { await this.cipherArchiveService.archiveWithServer(this.cipher.id as CipherId, activeUserId); this.toastService.showToast({ variant: "success", - message: this.i18nService.t("itemWasSentToArchive"), + message: this.i18nService.t("itemArchiveToast"), }); } } diff --git a/apps/browser/src/vault/popup/components/vault/view/view.component.ts b/apps/browser/src/vault/popup/components/vault/view/view.component.ts index d63cd5920a1..48402a957d6 100644 --- a/apps/browser/src/vault/popup/components/vault/view/view.component.ts +++ b/apps/browser/src/vault/popup/components/vault/view/view.component.ts @@ -277,17 +277,24 @@ export class ViewComponent { }; restore = async (): Promise => { + let toastMessage; try { await this.cipherService.restoreWithServer(this.cipher.id, this.activeUserId); } catch (e) { this.logService.error(e); } + if (this.cipher.archivedDate) { + toastMessage = this.i18nService.t("archivedItemRestored"); + } else { + toastMessage = this.i18nService.t("restoredItem"); + } + await this.popupRouterCacheService.back(); this.toastService.showToast({ variant: "success", title: null, - message: this.i18nService.t("restoredItem"), + message: toastMessage, }); }; diff --git a/apps/browser/src/vault/popup/settings/archive.component.ts b/apps/browser/src/vault/popup/settings/archive.component.ts index 336d9be6d16..0d1baa56a21 100644 --- a/apps/browser/src/vault/popup/settings/archive.component.ts +++ b/apps/browser/src/vault/popup/settings/archive.component.ts @@ -213,7 +213,7 @@ export class ArchiveComponent { this.toastService.showToast({ variant: "success", - message: this.i18nService.t("itemUnarchived"), + message: this.i18nService.t("itemUnarchivedToast"), }); } diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 85742db94ab..f444265877d 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts index 4da2d05f12b..2340f74c32d 100644 --- a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts @@ -616,7 +616,7 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { this.toastService.showToast({ variant: "success", - message: this.i18nService.t("itemWasSentToArchive"), + message: this.i18nService.t("itemArchiveToast"), }); } catch { this.toastService.showToast({ @@ -638,7 +638,7 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { this.toastService.showToast({ variant: "success", - message: this.i18nService.t("itemWasUnarchived"), + message: this.i18nService.t("itemUnarchivedToast"), }); } catch { this.toastService.showToast({ diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 4b9d2ed59ee..6fbe3f08912 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -744,7 +744,7 @@ export class VaultComponent implements OnInit, OnDestr await this.cipherArchiveService.archiveWithServer(cipher.id as CipherId, activeUserId); this.toastService.showToast({ variant: "success", - message: this.i18nService.t("itemWasSentToArchive"), + message: this.i18nService.t("itemArchiveToast"), }); this.refresh(); } catch (e) { @@ -801,7 +801,7 @@ export class VaultComponent implements OnInit, OnDestr this.toastService.showToast({ variant: "success", - message: this.i18nService.t("itemUnarchived"), + message: this.i18nService.t("itemUnarchivedToast"), }); this.refresh(); diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index d70a2d88bae..485f1fc07df 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -11905,14 +11905,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/libs/vault/src/services/archive-cipher-utilities.service.spec.ts b/libs/vault/src/services/archive-cipher-utilities.service.spec.ts index ea00f482987..3eff8997177 100644 --- a/libs/vault/src/services/archive-cipher-utilities.service.spec.ts +++ b/libs/vault/src/services/archive-cipher-utilities.service.spec.ts @@ -80,7 +80,7 @@ describe("ArchiveCipherUtilitiesService", () => { ); expect(toastService.showToast).toHaveBeenCalledWith({ variant: "success", - message: "itemWasSentToArchive", + message: "itemArchiveToast", }); }); @@ -106,7 +106,7 @@ describe("ArchiveCipherUtilitiesService", () => { ); expect(toastService.showToast).toHaveBeenCalledWith({ variant: "success", - message: "itemWasUnarchived", + message: "itemUnarchivedToast", }); }); diff --git a/libs/vault/src/services/archive-cipher-utilities.service.ts b/libs/vault/src/services/archive-cipher-utilities.service.ts index b747961a701..751eba96e73 100644 --- a/libs/vault/src/services/archive-cipher-utilities.service.ts +++ b/libs/vault/src/services/archive-cipher-utilities.service.ts @@ -58,7 +58,7 @@ export class ArchiveCipherUtilitiesService { ); this.toastService.showToast({ variant: "success", - message: this.i18nService.t("itemWasSentToArchive"), + message: this.i18nService.t("itemArchiveToast"), }); return cipherResponse; } catch { @@ -90,7 +90,7 @@ export class ArchiveCipherUtilitiesService { ); this.toastService.showToast({ variant: "success", - message: this.i18nService.t("itemWasUnarchived"), + message: this.i18nService.t("itemUnarchivedToast"), }); return cipherResponse; } catch { From 2912bf05e148ef883f07b24d8f5fb357ff77ec8e Mon Sep 17 00:00:00 2001 From: Brandon Treston Date: Fri, 13 Feb 2026 14:36:11 -0500 Subject: [PATCH 09/23] [PM-26901] Add notification handler for auto confirm (#18886) * add notification handler for auto confirm * add missing state check * fix test * isolate angular specific code from shared lib code * clean up * use autoconfirm method * fix test --- .../browser/src/background/main.background.ts | 36 ++++++++++- apps/browser/src/popup/app-routing.module.ts | 2 +- .../components/vault/vault.component.spec.ts | 2 +- .../popup/components/vault/vault.component.ts | 2 +- .../settings/admin-settings.component.ts | 2 +- .../src/services/jslib-services.module.ts | 2 + .../auto-confirm.service.abstraction.ts | 10 +-- ...auto-confirm-extension-dialog.component.ts | 0 ...auto-confirm-warning-dialog.component.html | 0 .../auto-confirm-warning-dialog.component.ts | 0 .../src/{ => angular}/components/index.ts | 0 ...c-user-confirmation-settings.guard.spec.ts | 3 +- ...omatic-user-confirmation-settings.guard.ts | 3 +- .../src/{ => angular}/guards/index.ts | 0 libs/auto-confirm/src/angular/index.ts | 8 +++ libs/auto-confirm/src/index.ts | 2 - .../default-auto-confirm.service.spec.ts | 58 +++++++++++------ .../services/default-auto-confirm.service.ts | 55 ++++++++++------ .../src/enums/notification-type.enum.ts | 1 + .../response/notification.response.spec.ts | 63 +++++++++++++++++++ .../models/response/notification.response.ts | 16 +++++ ...ult-server-notifications.multiuser.spec.ts | 5 ++ ...fault-server-notifications.service.spec.ts | 28 +++++++++ .../default-server-notifications.service.ts | 10 +++ tsconfig.base.json | 1 + 25 files changed, 257 insertions(+), 52 deletions(-) rename libs/auto-confirm/src/{ => angular}/components/auto-confirm-extension-dialog.component.ts (100%) rename libs/auto-confirm/src/{ => angular}/components/auto-confirm-warning-dialog.component.html (100%) rename libs/auto-confirm/src/{ => angular}/components/auto-confirm-warning-dialog.component.ts (100%) rename libs/auto-confirm/src/{ => angular}/components/index.ts (100%) rename libs/auto-confirm/src/{ => angular}/guards/automatic-user-confirmation-settings.guard.spec.ts (97%) rename libs/auto-confirm/src/{ => angular}/guards/automatic-user-confirmation-settings.guard.ts (94%) rename libs/auto-confirm/src/{ => angular}/guards/index.ts (100%) create mode 100644 libs/auto-confirm/src/angular/index.ts create mode 100644 libs/common/src/models/response/notification.response.spec.ts diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 585942d7537..25c7b344982 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -14,7 +14,14 @@ import { timeout, } from "rxjs"; -import { CollectionService, DefaultCollectionService } from "@bitwarden/admin-console/common"; +import { + CollectionService, + DefaultCollectionService, + DefaultOrganizationUserApiService, + DefaultOrganizationUserService, + OrganizationUserApiService, + OrganizationUserService, +} from "@bitwarden/admin-console/common"; import { AuthRequestApiServiceAbstraction, AuthRequestService, @@ -27,6 +34,10 @@ import { LogoutReason, UserDecryptionOptionsService, } from "@bitwarden/auth/common"; +import { + AutomaticUserConfirmationService, + DefaultAutomaticUserConfirmationService, +} from "@bitwarden/auto-confirm"; import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service"; import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; @@ -487,6 +498,9 @@ export default class MainBackground { onUpdatedRan: boolean; onReplacedRan: boolean; loginToAutoFill: CipherView = null; + organizationUserService: OrganizationUserService; + organizationUserApiService: OrganizationUserApiService; + autoConfirmService: AutomaticUserConfirmationService; private commandsBackground: CommandsBackground; private contextMenusBackground: ContextMenusBackground; @@ -763,6 +777,15 @@ export default class MainBackground { { createRequest: (url, request) => new Request(url, request) }, ); + this.organizationUserApiService = new DefaultOrganizationUserApiService(this.apiService); + this.organizationUserService = new DefaultOrganizationUserService( + this.keyService, + this.encryptService, + this.organizationUserApiService, + this.accountService, + this.i18nService, + ); + this.hibpApiService = new HibpApiService(this.apiService); this.fileUploadService = new FileUploadService(this.logService, this.apiService); this.cipherFileUploadService = new CipherFileUploadService( @@ -804,6 +827,16 @@ export default class MainBackground { this.authService, ); + this.autoConfirmService = new DefaultAutomaticUserConfirmationService( + this.configService, + this.apiService, + this.organizationUserService, + this.stateProvider, + this.organizationService, + this.organizationUserApiService, + this.policyService, + ); + const sdkClientFactory = flagEnabled("sdk") ? new DefaultSdkClientFactory() : new NoopSdkClientFactory(); @@ -1219,6 +1252,7 @@ export default class MainBackground { this.authRequestAnsweringService, this.configService, this.policyService, + this.autoConfirmService, ); this.fido2UserInterfaceService = new BrowserFido2UserInterfaceService(this.authService); diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index 4e14d1171fd..0d85743bba7 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -42,7 +42,7 @@ import { TwoFactorAuthComponent, TwoFactorAuthGuard, } from "@bitwarden/auth/angular"; -import { canAccessAutoConfirmSettings } from "@bitwarden/auto-confirm"; +import { canAccessAutoConfirmSettings } from "@bitwarden/auto-confirm/angular"; import { AnonLayoutWrapperComponent, AnonLayoutWrapperData } from "@bitwarden/components"; import { LockComponent, diff --git a/apps/browser/src/vault/popup/components/vault/vault.component.spec.ts b/apps/browser/src/vault/popup/components/vault/vault.component.spec.ts index 70affd73ef3..f48b08566a1 100644 --- a/apps/browser/src/vault/popup/components/vault/vault.component.spec.ts +++ b/apps/browser/src/vault/popup/components/vault/vault.component.spec.ts @@ -12,7 +12,7 @@ import { NudgeType, NudgesService } from "@bitwarden/angular/vault"; import { AutoConfirmExtensionSetupDialogComponent, AutomaticUserConfirmationService, -} from "@bitwarden/auto-confirm"; +} from "@bitwarden/auto-confirm/angular"; import { CurrentAccountComponent } from "@bitwarden/browser/auth/popup/account-switching/current-account.component"; import AutofillService from "@bitwarden/browser/autofill/services/autofill.service"; import { PopOutComponent } from "@bitwarden/browser/platform/popup/components/pop-out.component"; diff --git a/apps/browser/src/vault/popup/components/vault/vault.component.ts b/apps/browser/src/vault/popup/components/vault/vault.component.ts index 281abc5f180..cb3cb5f5eec 100644 --- a/apps/browser/src/vault/popup/components/vault/vault.component.ts +++ b/apps/browser/src/vault/popup/components/vault/vault.component.ts @@ -28,7 +28,7 @@ import { AutoConfirmExtensionSetupDialogComponent, AutoConfirmState, AutomaticUserConfirmationService, -} from "@bitwarden/auto-confirm"; +} from "@bitwarden/auto-confirm/angular"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; diff --git a/apps/browser/src/vault/popup/settings/admin-settings.component.ts b/apps/browser/src/vault/popup/settings/admin-settings.component.ts index e4b676525ed..52da4318047 100644 --- a/apps/browser/src/vault/popup/settings/admin-settings.component.ts +++ b/apps/browser/src/vault/popup/settings/admin-settings.component.ts @@ -16,7 +16,7 @@ import { SpotlightComponent } from "@bitwarden/angular/vault/components/spotligh import { AutoConfirmWarningDialogComponent, AutomaticUserConfirmationService, -} from "@bitwarden/auto-confirm"; +} from "@bitwarden/auto-confirm/angular"; import { PopOutComponent } from "@bitwarden/browser/platform/popup/components/pop-out.component"; import { PopupHeaderComponent } from "@bitwarden/browser/platform/popup/layout/popup-header.component"; import { PopupPageComponent } from "@bitwarden/browser/platform/popup/layout/popup-page.component"; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 0f857e67247..2fbf55bf6c5 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -56,6 +56,7 @@ import { UserDecryptionOptionsService, UserDecryptionOptionsServiceAbstraction, } from "@bitwarden/auth/common"; +import { AutomaticUserConfirmationService } from "@bitwarden/auto-confirm"; import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service"; import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; @@ -1079,6 +1080,7 @@ const safeProviders: SafeProvider[] = [ AuthRequestAnsweringService, ConfigService, InternalPolicyService, + AutomaticUserConfirmationService, ], }), safeProvider({ diff --git a/libs/auto-confirm/src/abstractions/auto-confirm.service.abstraction.ts b/libs/auto-confirm/src/abstractions/auto-confirm.service.abstraction.ts index 9ce6cb9c1a4..1ef3be4ff4e 100644 --- a/libs/auto-confirm/src/abstractions/auto-confirm.service.abstraction.ts +++ b/libs/auto-confirm/src/abstractions/auto-confirm.service.abstraction.ts @@ -1,6 +1,6 @@ import { Observable } from "rxjs"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { OrganizationId } from "@bitwarden/common/types/guid"; import { UserId } from "@bitwarden/user-core"; import { AutoConfirmState } from "../models/auto-confirm-state.model"; @@ -27,12 +27,12 @@ export abstract class AutomaticUserConfirmationService { /** * Calls the API endpoint to initiate automatic user confirmation. * @param userId The userId of the logged in admin performing auto confirmation. This is neccesary to perform the key exchange and for permissions checks. - * @param confirmingUserId The userId of the user being confirmed. - * @param organization the organization the user is being auto confirmed to. + * @param confirmedUserId The userId of the member being confirmed. + * @param organization the organization the member is being auto confirmed to. **/ abstract autoConfirmUser( userId: UserId, - confirmingUserId: UserId, - organization: Organization, + confirmedUserId: UserId, + organization: OrganizationId, ): Promise; } diff --git a/libs/auto-confirm/src/components/auto-confirm-extension-dialog.component.ts b/libs/auto-confirm/src/angular/components/auto-confirm-extension-dialog.component.ts similarity index 100% rename from libs/auto-confirm/src/components/auto-confirm-extension-dialog.component.ts rename to libs/auto-confirm/src/angular/components/auto-confirm-extension-dialog.component.ts diff --git a/libs/auto-confirm/src/components/auto-confirm-warning-dialog.component.html b/libs/auto-confirm/src/angular/components/auto-confirm-warning-dialog.component.html similarity index 100% rename from libs/auto-confirm/src/components/auto-confirm-warning-dialog.component.html rename to libs/auto-confirm/src/angular/components/auto-confirm-warning-dialog.component.html diff --git a/libs/auto-confirm/src/components/auto-confirm-warning-dialog.component.ts b/libs/auto-confirm/src/angular/components/auto-confirm-warning-dialog.component.ts similarity index 100% rename from libs/auto-confirm/src/components/auto-confirm-warning-dialog.component.ts rename to libs/auto-confirm/src/angular/components/auto-confirm-warning-dialog.component.ts diff --git a/libs/auto-confirm/src/components/index.ts b/libs/auto-confirm/src/angular/components/index.ts similarity index 100% rename from libs/auto-confirm/src/components/index.ts rename to libs/auto-confirm/src/angular/components/index.ts diff --git a/libs/auto-confirm/src/guards/automatic-user-confirmation-settings.guard.spec.ts b/libs/auto-confirm/src/angular/guards/automatic-user-confirmation-settings.guard.spec.ts similarity index 97% rename from libs/auto-confirm/src/guards/automatic-user-confirmation-settings.guard.spec.ts rename to libs/auto-confirm/src/angular/guards/automatic-user-confirmation-settings.guard.spec.ts index aca51edb8dc..0261a1a86dc 100644 --- a/libs/auto-confirm/src/guards/automatic-user-confirmation-settings.guard.spec.ts +++ b/libs/auto-confirm/src/angular/guards/automatic-user-confirmation-settings.guard.spec.ts @@ -3,14 +3,13 @@ import { Router, UrlTree } from "@angular/router"; import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject, firstValueFrom, Observable, of } from "rxjs"; +import { AutomaticUserConfirmationService } from "@bitwarden/auto-confirm"; import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { UserId } from "@bitwarden/common/types/guid"; import { ToastService } from "@bitwarden/components"; import { newGuid } from "@bitwarden/guid"; -import { AutomaticUserConfirmationService } from "../abstractions"; - import { canAccessAutoConfirmSettings } from "./automatic-user-confirmation-settings.guard"; describe("canAccessAutoConfirmSettings", () => { diff --git a/libs/auto-confirm/src/guards/automatic-user-confirmation-settings.guard.ts b/libs/auto-confirm/src/angular/guards/automatic-user-confirmation-settings.guard.ts similarity index 94% rename from libs/auto-confirm/src/guards/automatic-user-confirmation-settings.guard.ts rename to libs/auto-confirm/src/angular/guards/automatic-user-confirmation-settings.guard.ts index 77f01ba2801..3ae6b5b4c52 100644 --- a/libs/auto-confirm/src/guards/automatic-user-confirmation-settings.guard.ts +++ b/libs/auto-confirm/src/angular/guards/automatic-user-confirmation-settings.guard.ts @@ -2,13 +2,12 @@ import { inject } from "@angular/core"; import { CanActivateFn, Router } from "@angular/router"; import { map, switchMap } from "rxjs"; +import { AutomaticUserConfirmationService } from "@bitwarden/auto-confirm"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { filterOutNullish } from "@bitwarden/common/vault/utils/observable-utilities"; import { ToastService } from "@bitwarden/components"; -import { AutomaticUserConfirmationService } from "../abstractions"; - export const canAccessAutoConfirmSettings: CanActivateFn = () => { const accountService = inject(AccountService); const autoConfirmService = inject(AutomaticUserConfirmationService); diff --git a/libs/auto-confirm/src/guards/index.ts b/libs/auto-confirm/src/angular/guards/index.ts similarity index 100% rename from libs/auto-confirm/src/guards/index.ts rename to libs/auto-confirm/src/angular/guards/index.ts diff --git a/libs/auto-confirm/src/angular/index.ts b/libs/auto-confirm/src/angular/index.ts new file mode 100644 index 00000000000..ff2d69248b4 --- /dev/null +++ b/libs/auto-confirm/src/angular/index.ts @@ -0,0 +1,8 @@ +// Re-export core auto-confirm functionality for convenience +export * from "../abstractions"; +export * from "../models"; +export * from "../services"; + +// Angular-specific exports +export * from "./components"; +export * from "./guards"; diff --git a/libs/auto-confirm/src/index.ts b/libs/auto-confirm/src/index.ts index 56b9d0b0285..9187ccd39cf 100644 --- a/libs/auto-confirm/src/index.ts +++ b/libs/auto-confirm/src/index.ts @@ -1,5 +1,3 @@ export * from "./abstractions"; -export * from "./components"; -export * from "./guards"; export * from "./models"; export * from "./services"; diff --git a/libs/auto-confirm/src/services/default-auto-confirm.service.spec.ts b/libs/auto-confirm/src/services/default-auto-confirm.service.spec.ts index 1d37378b96c..0ea3ca9c23a 100644 --- a/libs/auto-confirm/src/services/default-auto-confirm.service.spec.ts +++ b/libs/auto-confirm/src/services/default-auto-confirm.service.spec.ts @@ -377,48 +377,70 @@ describe("DefaultAutomaticUserConfirmationService", () => { defaultUserCollectionName: "encrypted-collection", } as OrganizationUserConfirmRequest; - beforeEach(() => { + beforeEach(async () => { const organizations$ = new BehaviorSubject([mockOrganization]); organizationService.organizations$.mockReturnValue(organizations$); configService.getFeatureFlag$.mockReturnValue(of(true)); policyService.policyAppliesToUser$.mockReturnValue(of(true)); + // Enable auto-confirm configuration for the user + const enabledConfig = new AutoConfirmState(); + enabledConfig.enabled = true; + await stateProvider.setUserState( + AUTO_CONFIRM_STATE, + { [mockUserId]: enabledConfig }, + mockUserId, + ); + apiService.getUserPublicKey.mockResolvedValue({ publicKey: mockPublicKey, } as UserKeyResponse); jest.spyOn(Utils, "fromB64ToArray").mockReturnValue(mockPublicKeyArray); organizationUserService.buildConfirmRequest.mockReturnValue(of(mockConfirmRequest)); - organizationUserApiService.postOrganizationUserConfirm.mockResolvedValue(undefined); + organizationUserApiService.postOrganizationUserAutoConfirm.mockResolvedValue(undefined); }); - it("should successfully auto-confirm a user", async () => { - await service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganization); + it("should successfully auto-confirm a user with organizationId", async () => { + await service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganizationId); expect(apiService.getUserPublicKey).toHaveBeenCalledWith(mockUserId); expect(organizationUserService.buildConfirmRequest).toHaveBeenCalledWith( mockOrganization, mockPublicKeyArray, ); - expect(organizationUserApiService.postOrganizationUserConfirm).toHaveBeenCalledWith( + expect(organizationUserApiService.postOrganizationUserAutoConfirm).toHaveBeenCalledWith( mockOrganizationId, mockConfirmingUserId, mockConfirmRequest, ); }); - it("should not confirm user when canManageAutoConfirm returns false", async () => { + it("should return early when canManageAutoConfirm returns false", async () => { configService.getFeatureFlag$.mockReturnValue(of(false)); - await expect( - service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganization), - ).rejects.toThrow("Cannot automatically confirm user (insufficient permissions)"); + await service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganizationId); expect(apiService.getUserPublicKey).not.toHaveBeenCalled(); - expect(organizationUserApiService.postOrganizationUserConfirm).not.toHaveBeenCalled(); + expect(organizationUserApiService.postOrganizationUserAutoConfirm).not.toHaveBeenCalled(); + }); + + it("should return early when auto-confirm is disabled in configuration", async () => { + const disabledConfig = new AutoConfirmState(); + disabledConfig.enabled = false; + await stateProvider.setUserState( + AUTO_CONFIRM_STATE, + { [mockUserId]: disabledConfig }, + mockUserId, + ); + + await service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganizationId); + + expect(apiService.getUserPublicKey).not.toHaveBeenCalled(); + expect(organizationUserApiService.postOrganizationUserAutoConfirm).not.toHaveBeenCalled(); }); it("should build confirm request with organization and public key", async () => { - await service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganization); + await service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganizationId); expect(organizationUserService.buildConfirmRequest).toHaveBeenCalledWith( mockOrganization, @@ -427,10 +449,10 @@ describe("DefaultAutomaticUserConfirmationService", () => { }); it("should call API with correct parameters", async () => { - await service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganization); + await service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganizationId); - expect(organizationUserApiService.postOrganizationUserConfirm).toHaveBeenCalledWith( - mockOrganization.id, + expect(organizationUserApiService.postOrganizationUserAutoConfirm).toHaveBeenCalledWith( + mockOrganizationId, mockConfirmingUserId, mockConfirmRequest, ); @@ -441,10 +463,10 @@ describe("DefaultAutomaticUserConfirmationService", () => { apiService.getUserPublicKey.mockRejectedValue(apiError); await expect( - service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganization), + service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganizationId), ).rejects.toThrow("API Error"); - expect(organizationUserApiService.postOrganizationUserConfirm).not.toHaveBeenCalled(); + expect(organizationUserApiService.postOrganizationUserAutoConfirm).not.toHaveBeenCalled(); }); it("should handle buildConfirmRequest errors gracefully", async () => { @@ -452,10 +474,10 @@ describe("DefaultAutomaticUserConfirmationService", () => { organizationUserService.buildConfirmRequest.mockReturnValue(throwError(() => buildError)); await expect( - service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganization), + service.autoConfirmUser(mockUserId, mockConfirmingUserId, mockOrganizationId), ).rejects.toThrow("Build Error"); - expect(organizationUserApiService.postOrganizationUserConfirm).not.toHaveBeenCalled(); + expect(organizationUserApiService.postOrganizationUserAutoConfirm).not.toHaveBeenCalled(); }); }); }); diff --git a/libs/auto-confirm/src/services/default-auto-confirm.service.ts b/libs/auto-confirm/src/services/default-auto-confirm.service.ts index 109ccb6c9db..821340a0a9c 100644 --- a/libs/auto-confirm/src/services/default-auto-confirm.service.ts +++ b/libs/auto-confirm/src/services/default-auto-confirm.service.ts @@ -8,10 +8,11 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { getById } from "@bitwarden/common/platform/misc"; import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { OrganizationId } from "@bitwarden/common/types/guid"; import { StateProvider } from "@bitwarden/state"; import { UserId } from "@bitwarden/user-core"; @@ -66,26 +67,44 @@ export class DefaultAutomaticUserConfirmationService implements AutomaticUserCon async autoConfirmUser( userId: UserId, - confirmingUserId: UserId, - organization: Organization, + confirmedUserId: UserId, + organizationId: OrganizationId, ): Promise { + const canManage = await firstValueFrom(this.canManageAutoConfirm$(userId)); + + if (!canManage) { + return; + } + + // Only initiate auto confirmation if the local client setting has been turned on + const autoConfirmEnabled = await firstValueFrom( + this.configuration$(userId).pipe(map((state) => state.enabled)), + ); + + if (!autoConfirmEnabled) { + return; + } + + const organization$ = this.organizationService.organizations$(userId).pipe( + getById(organizationId), + map((organization) => { + if (organization == null) { + throw new Error("Organization not found"); + } + return organization; + }), + ); + + const publicKeyResponse = await this.apiService.getUserPublicKey(userId); + const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey); + await firstValueFrom( - this.canManageAutoConfirm$(userId).pipe( - map((canManage) => { - if (!canManage) { - throw new Error("Cannot automatically confirm user (insufficient permissions)"); - } - return canManage; - }), - switchMap(() => this.apiService.getUserPublicKey(userId)), - map((publicKeyResponse) => Utils.fromB64ToArray(publicKeyResponse.publicKey)), - switchMap((publicKey) => - this.organizationUserService.buildConfirmRequest(organization, publicKey), - ), + organization$.pipe( + switchMap((org) => this.organizationUserService.buildConfirmRequest(org, publicKey)), switchMap((request) => - this.organizationUserApiService.postOrganizationUserConfirm( - organization.id, - confirmingUserId, + this.organizationUserApiService.postOrganizationUserAutoConfirm( + organizationId, + confirmedUserId, request, ), ), diff --git a/libs/common/src/enums/notification-type.enum.ts b/libs/common/src/enums/notification-type.enum.ts index a10e6bf4448..d323dda4d74 100644 --- a/libs/common/src/enums/notification-type.enum.ts +++ b/libs/common/src/enums/notification-type.enum.ts @@ -35,4 +35,5 @@ export enum NotificationType { ProviderBankAccountVerified = 24, SyncPolicy = 25, + AutoConfirmMember = 26, } diff --git a/libs/common/src/models/response/notification.response.spec.ts b/libs/common/src/models/response/notification.response.spec.ts new file mode 100644 index 00000000000..91a1390bfdb --- /dev/null +++ b/libs/common/src/models/response/notification.response.spec.ts @@ -0,0 +1,63 @@ +import { NotificationType } from "../../enums"; + +import { AutoConfirmMemberNotification, NotificationResponse } from "./notification.response"; + +describe("NotificationResponse", () => { + describe("AutoConfirmMemberNotification", () => { + it("should parse AutoConfirmMemberNotification payload", () => { + const response = { + ContextId: "context-123", + Type: NotificationType.AutoConfirmMember, + Payload: { + TargetUserId: "target-user-id", + UserId: "user-id", + OrganizationId: "org-id", + }, + }; + + const notification = new NotificationResponse(response); + + expect(notification.type).toBe(NotificationType.AutoConfirmMember); + expect(notification.payload).toBeInstanceOf(AutoConfirmMemberNotification); + expect(notification.payload.targetUserId).toBe("target-user-id"); + expect(notification.payload.userId).toBe("user-id"); + expect(notification.payload.organizationId).toBe("org-id"); + }); + + it("should handle stringified JSON payload", () => { + const response = { + ContextId: "context-123", + Type: NotificationType.AutoConfirmMember, + Payload: JSON.stringify({ + TargetUserId: "target-user-id-2", + UserId: "user-id-2", + OrganizationId: "org-id-2", + }), + }; + + const notification = new NotificationResponse(response); + + expect(notification.type).toBe(NotificationType.AutoConfirmMember); + expect(notification.payload).toBeInstanceOf(AutoConfirmMemberNotification); + expect(notification.payload.targetUserId).toBe("target-user-id-2"); + expect(notification.payload.userId).toBe("user-id-2"); + expect(notification.payload.organizationId).toBe("org-id-2"); + }); + }); + + describe("AutoConfirmMemberNotification constructor", () => { + it("should extract all properties from response", () => { + const response = { + TargetUserId: "target-user-id", + UserId: "user-id", + OrganizationId: "org-id", + }; + + const notification = new AutoConfirmMemberNotification(response); + + expect(notification.targetUserId).toBe("target-user-id"); + expect(notification.userId).toBe("user-id"); + expect(notification.organizationId).toBe("org-id"); + }); + }); +}); diff --git a/libs/common/src/models/response/notification.response.ts b/libs/common/src/models/response/notification.response.ts index 2c0c0aae3f1..27232696d2e 100644 --- a/libs/common/src/models/response/notification.response.ts +++ b/libs/common/src/models/response/notification.response.ts @@ -75,6 +75,9 @@ export class NotificationResponse extends BaseResponse { case NotificationType.SyncPolicy: this.payload = new SyncPolicyNotification(payload); break; + case NotificationType.AutoConfirmMember: + this.payload = new AutoConfirmMemberNotification(payload); + break; default: break; } @@ -210,3 +213,16 @@ export class LogOutNotification extends BaseResponse { this.reason = this.getResponseProperty("Reason"); } } + +export class AutoConfirmMemberNotification extends BaseResponse { + userId: string; + targetUserId: string; + organizationId: string; + + constructor(response: any) { + super(response); + this.targetUserId = this.getResponseProperty("TargetUserId"); + this.userId = this.getResponseProperty("UserId"); + this.organizationId = this.getResponseProperty("OrganizationId"); + } +} diff --git a/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts b/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts index 2795e4c3003..70b93c77f1c 100644 --- a/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts +++ b/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts @@ -3,6 +3,7 @@ import { BehaviorSubject, bufferCount, firstValueFrom, Subject, ObservedValueOf // eslint-disable-next-line no-restricted-imports import { LogoutReason } from "@bitwarden/auth/common"; +import { AutomaticUserConfirmationService } from "@bitwarden/auto-confirm"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AuthRequestAnsweringService } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction"; @@ -36,6 +37,7 @@ describe("DefaultServerNotificationsService (multi-user)", () => { let authRequestAnsweringService: MockProxy; let configService: MockProxy; let policyService: MockProxy; + let autoConfirmService: MockProxy; let activeUserAccount$: BehaviorSubject>; let userAccounts$: BehaviorSubject>; @@ -131,6 +133,8 @@ describe("DefaultServerNotificationsService (multi-user)", () => { policyService = mock(); + autoConfirmService = mock(); + defaultServerNotificationsService = new DefaultServerNotificationsService( mock(), syncService, @@ -145,6 +149,7 @@ describe("DefaultServerNotificationsService (multi-user)", () => { authRequestAnsweringService, configService, policyService, + autoConfirmService, ); }); diff --git a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.spec.ts b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.spec.ts index f058e8794ac..a54509925ef 100644 --- a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.spec.ts +++ b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.spec.ts @@ -4,6 +4,7 @@ import { BehaviorSubject, bufferCount, firstValueFrom, ObservedValueOf, of, Subj // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { LogoutReason } from "@bitwarden/auth/common"; +import { AutomaticUserConfirmationService } from "@bitwarden/auto-confirm"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { AuthRequestAnsweringService } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction"; @@ -45,6 +46,7 @@ describe("NotificationsService", () => { let authRequestAnsweringService: MockProxy; let configService: MockProxy; let policyService: MockProxy; + let autoConfirmService: MockProxy; let activeAccount: BehaviorSubject>; let accounts: BehaviorSubject>; @@ -75,6 +77,7 @@ describe("NotificationsService", () => { authRequestAnsweringService = mock(); configService = mock(); policyService = mock(); + autoConfirmService = mock(); // For these tests, use the active-user implementation (feature flag disabled) configService.getFeatureFlag$.mockImplementation(() => of(true)); @@ -128,6 +131,7 @@ describe("NotificationsService", () => { authRequestAnsweringService, configService, policyService, + autoConfirmService, ); }); @@ -507,5 +511,29 @@ describe("NotificationsService", () => { }); }); }); + + describe("NotificationType.AutoConfirmMember", () => { + it("should call autoConfirmService.autoConfirmUser with correct parameters", async () => { + autoConfirmService.autoConfirmUser.mockResolvedValue(); + + const notification = new NotificationResponse({ + type: NotificationType.AutoConfirmMember, + payload: { + UserId: mockUser1, + TargetUserId: "target-user-id", + OrganizationId: "org-id", + }, + contextId: "different-app-id", + }); + + await sut["processNotification"](notification, mockUser1); + + expect(autoConfirmService.autoConfirmUser).toHaveBeenCalledWith( + mockUser1, + "target-user-id", + "org-id", + ); + }); + }); }); }); diff --git a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts index 83ea12bf154..1a43c0edb09 100644 --- a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts +++ b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts @@ -15,6 +15,7 @@ import { // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { LogoutReason } from "@bitwarden/auth/common"; +import { AutomaticUserConfirmationService } from "@bitwarden/auto-confirm"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.data"; import { AuthRequestAnsweringService } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction"; @@ -49,6 +50,7 @@ export const DISABLED_NOTIFICATIONS_URL = "http://-"; export const AllowedMultiUserNotificationTypes = new Set([ NotificationType.AuthRequest, + NotificationType.AutoConfirmMember, ]); export class DefaultServerNotificationsService implements ServerNotificationsService { @@ -70,6 +72,7 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer private readonly authRequestAnsweringService: AuthRequestAnsweringService, private readonly configService: ConfigService, private readonly policyService: InternalPolicyService, + private autoConfirmService: AutomaticUserConfirmationService, ) { this.notifications$ = this.accountService.accounts$.pipe( map((accounts: Record): Set => { @@ -292,6 +295,13 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer case NotificationType.SyncPolicy: await this.policyService.syncPolicy(PolicyData.fromPolicy(notification.payload.policy)); break; + case NotificationType.AutoConfirmMember: + await this.autoConfirmService.autoConfirmUser( + notification.payload.userId, + notification.payload.targetUserId, + notification.payload.organizationId, + ); + break; default: break; } diff --git a/tsconfig.base.json b/tsconfig.base.json index 68498cfae01..17f8f6d44fc 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -25,6 +25,7 @@ "@bitwarden/auth/angular": ["./libs/auth/src/angular"], "@bitwarden/auth/common": ["./libs/auth/src/common"], "@bitwarden/auto-confirm": ["libs/auto-confirm/src/index.ts"], + "@bitwarden/auto-confirm/angular": ["libs/auto-confirm/src/angular"], "@bitwarden/billing": ["./libs/billing/src"], "@bitwarden/bit-common/*": ["./bitwarden_license/bit-common/src/*"], "@bitwarden/browser/*": ["./apps/browser/src/*"], From 323f30c8e941d3bfb72acb812e6a90e949771a5d Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Fri, 13 Feb 2026 11:36:39 -0800 Subject: [PATCH 10/23] [PM-29892] - fix bulk share in vault (#18601) * fix bulk share in vault * clean up types. * remove unnecessary optional chain * add back defensive programming. update restore * fix searchableCollectionNodes * add back optional chains --- .../collections/vault.component.ts | 14 +- .../vault-item-dialog.component.ts | 2 +- .../vault/individual-vault/vault.component.ts | 145 +++++++++--------- 3 files changed, 81 insertions(+), 80 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts index 073d73f6a50..a641116f4de 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts @@ -472,7 +472,7 @@ export class VaultComponent implements OnInit, OnDestroy { collections, filter.collectionId, ); - searchableCollectionNodes = selectedCollection.children ?? []; + searchableCollectionNodes = selectedCollection?.children ?? []; } let collectionsToReturn: CollectionAdminView[] = []; @@ -962,10 +962,10 @@ export class VaultComponent implements OnInit, OnDestroy { await this.editCipher(cipher, true); } - restore = async (c: CipherViewLike): Promise => { + restore = async (c: CipherViewLike): Promise => { const organization = await firstValueFrom(this.organization$); if (!CipherViewLikeUtils.isDeleted(c)) { - return false; + return; } if ( @@ -974,11 +974,11 @@ export class VaultComponent implements OnInit, OnDestroy { !organization.allowAdminAccessToAllCollectionItems ) { this.showMissingPermissionsError(); - return false; + return; } if (!(await this.repromptCipher([c]))) { - return false; + return; } // Allow restore of an Unassigned Item @@ -996,10 +996,10 @@ export class VaultComponent implements OnInit, OnDestroy { message: this.i18nService.t("restoredItem"), }); this.refresh(); - return true; + return; } catch (e) { this.logService.error(e); - return false; + return; } }; diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts index 2340f74c32d..4c6efdee167 100644 --- a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts @@ -100,7 +100,7 @@ export interface VaultItemDialogParams { /** * Function to restore a cipher from the trash. */ - restore?: (c: CipherViewLike) => Promise; + restore?: (c: CipherViewLike) => Promise; } export const VaultItemDialogResult = { diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 6fbe3f08912..5ff72b0d147 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -1,15 +1,6 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit, ViewChild } from "@angular/core"; +import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit, viewChild } from "@angular/core"; import { ActivatedRoute, Params, Router } from "@angular/router"; -import { - BehaviorSubject, - combineLatest, - firstValueFrom, - lastValueFrom, - Observable, - Subject, -} from "rxjs"; +import { combineLatest, firstValueFrom, lastValueFrom, Observable, of, Subject } from "rxjs"; import { concatMap, debounceTime, @@ -18,6 +9,7 @@ import { first, map, shareReplay, + startWith, switchMap, take, takeUntil, @@ -89,7 +81,6 @@ import { CipherListView } from "@bitwarden/sdk-internal"; import { AddEditFolderDialogComponent, AddEditFolderDialogResult, - AttachmentDialogCloseResult, AttachmentDialogResult, AttachmentsV2Component, CipherFormConfig, @@ -179,14 +170,10 @@ type EmptyStateMap = Record; ], }) export class VaultComponent implements OnInit, OnDestroy { - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @ViewChild("vaultFilter", { static: true }) filterComponent: VaultFilterComponent; - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @ViewChild("vaultItems", { static: false }) vaultItemsComponent: VaultItemsComponent; + readonly filterComponent = viewChild(VaultFilterComponent); + readonly vaultItemsComponent = viewChild(VaultItemsComponent); - trashCleanupWarning: string = null; + trashCleanupWarning: string = ""; activeFilter: VaultFilter = new VaultFilter(); protected deactivatedOrgIcon = DeactivatedOrg; @@ -198,20 +185,20 @@ export class VaultComponent implements OnInit, OnDestr protected refreshing = false; protected processingEvent = false; protected filter: RoutedVaultFilterModel = {}; - protected showBulkMove: boolean; - protected canAccessPremium: boolean; - protected allCollections: CollectionView[]; + protected showBulkMove: boolean = false; + protected canAccessPremium: boolean = false; + protected allCollections: CollectionView[] = []; protected allOrganizations: Organization[] = []; - protected ciphers: C[]; - protected collections: CollectionView[]; - protected isEmpty: boolean; + protected ciphers: C[] = []; + protected collections: CollectionView[] = []; + protected isEmpty: boolean = false; protected selectedCollection: TreeNode | undefined; protected canCreateCollections = false; protected currentSearchText$: Observable = this.route.queryParams.pipe( map((queryParams) => queryParams.search), ); private searchText$ = new Subject(); - private refresh$ = new BehaviorSubject(null); + private refresh$ = new Subject(); private destroy$ = new Subject(); private vaultItemDialogRef?: DialogRef | undefined; @@ -220,7 +207,7 @@ export class VaultComponent implements OnInit, OnDestr organizations$ = this.accountService.activeAccount$ .pipe(map((a) => a?.id)) - .pipe(switchMap((id) => this.organizationService.organizations$(id))); + .pipe(switchMap((id) => (id ? this.organizationService.organizations$(id) : of([])))); emptyState$ = combineLatest([ this.currentSearchText$, @@ -228,7 +215,7 @@ export class VaultComponent implements OnInit, OnDestr this.organizations$, ]).pipe( map(([searchText, filter, organizations]) => { - const selectedOrg = organizations?.find((org) => org.id === filter.organizationId); + const selectedOrg = organizations.find((org) => org.id === filter.organizationId); const isOrgDisabled = selectedOrg && !selectedOrg.enabled; if (isOrgDisabled) { @@ -586,7 +573,7 @@ export class VaultComponent implements OnInit, OnDestr firstSetup$ .pipe( - switchMap(() => this.refresh$), + switchMap(() => this.refresh$.pipe(startWith(undefined))), tap(() => (this.refreshing = true)), switchMap(() => combineLatest([ @@ -712,7 +699,6 @@ export class VaultComponent implements OnInit, OnDestr async handleUnknownCipher() { this.toastService.showToast({ variant: "error", - title: null, message: this.i18nService.t("unknownCipher"), }); await this.router.navigate([], { @@ -842,9 +828,13 @@ export class VaultComponent implements OnInit, OnDestr if (orgId == null) { orgId = "MyVault"; } - const orgs = await firstValueFrom(this.filterComponent.filters.organizationFilter.data$); + const data = this.filterComponent()?.filters?.organizationFilter?.data$; + if (data == undefined) { + return; + } + const orgs = await firstValueFrom(data); const orgNode = ServiceUtils.getTreeNodeObject(orgs, orgId) as TreeNode; - await this.filterComponent.filters?.organizationFilter?.action(orgNode); + await this.filterComponent()?.filters?.organizationFilter?.action(orgNode); } addFolder = (): void => { @@ -912,7 +902,10 @@ export class VaultComponent implements OnInit, OnDestr canEditCipher: cipher.edit, }); - const result: AttachmentDialogCloseResult = await lastValueFrom(dialogRef.closed); + const result = await lastValueFrom(dialogRef.closed); + if (result === undefined) { + return; + } if ( result.action === AttachmentDialogResult.Uploaded || @@ -966,7 +959,7 @@ export class VaultComponent implements OnInit, OnDestr */ async addCipher(cipherType?: CipherType) { const type = cipherType ?? this.activeFilter.cipherType; - const cipherFormConfig = await this.cipherFormConfigService.buildConfig("add", null, type); + const cipherFormConfig = await this.cipherFormConfigService.buildConfig("add", undefined, type); const collectionId = this.activeFilter.collectionId !== "AllCollections" && this.activeFilter.collectionId != null ? this.activeFilter.collectionId @@ -994,7 +987,7 @@ export class VaultComponent implements OnInit, OnDestr } async editCipher(cipher: CipherView | CipherListView, cloneMode?: boolean) { - return this.editCipherId(uuidAsString(cipher?.id), cloneMode); + return this.editCipherId(uuidAsString(cipher.id), cloneMode); } /** @@ -1088,6 +1081,9 @@ export class VaultComponent implements OnInit, OnDestr }, }); const result = await lastValueFrom(dialog.closed); + if (result === undefined) { + return; + } if (result.action === CollectionDialogAction.Saved) { if (result.collection) { // Update CollectionService with the new collection @@ -1104,7 +1100,7 @@ export class VaultComponent implements OnInit, OnDestr async editCollection(c: CollectionView, tab: CollectionDialogTabType): Promise { const dialog = openCollectionDialog(this.dialogService, { data: { - collectionId: c?.id, + collectionId: c.id, organizationId: c.organizationId, initialTab: tab, limitNestedCollections: true, @@ -1112,6 +1108,9 @@ export class VaultComponent implements OnInit, OnDestr }); const result = await lastValueFrom(dialog.closed); + if (result === undefined) { + return; + } const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); if (result.action === CollectionDialogAction.Saved) { if (result.collection) { @@ -1163,7 +1162,6 @@ export class VaultComponent implements OnInit, OnDestr this.toastService.showToast({ variant: "success", - title: null, message: this.i18nService.t("deletedCollectionId", collection.name), }); if (navigateAway) { @@ -1196,12 +1194,12 @@ export class VaultComponent implements OnInit, OnDestr let availableCollections: CollectionView[] = []; const orgId = this.activeFilter.organizationId || - ciphers.find((c) => c.organizationId !== null)?.organizationId; + ciphers.find((c) => c.organizationId !== undefined)?.organizationId; if (orgId && orgId !== "MyVault") { const organization = this.allOrganizations.find((o) => o.id === orgId); availableCollections = this.allCollections.filter( - (c) => c.organizationId === organization.id, + (c) => c.organizationId === organization?.id, ); } @@ -1229,7 +1227,7 @@ export class VaultComponent implements OnInit, OnDestr ciphers: ciphersToAssign, organizationId: orgId as OrganizationId, availableCollections, - activeCollection: this.activeFilter?.selectedCollectionNode?.node, + activeCollection: this.activeFilter.selectedCollectionNode?.node, }, }); @@ -1255,7 +1253,7 @@ export class VaultComponent implements OnInit, OnDestr await this.editCipher(cipher, true); } - restore = async (c: C): Promise => { + restore = async (c: CipherViewLike) => { let toastMessage; if (!CipherViewLikeUtils.isDeleted(c)) { return; @@ -1281,13 +1279,14 @@ export class VaultComponent implements OnInit, OnDestr await this.cipherService.restoreWithServer(uuidAsString(c.id), activeUserId); this.toastService.showToast({ variant: "success", - title: null, message: toastMessage, }); this.refresh(); } catch (e) { this.logService.error(e); + return; } + return; }; async bulkRestore(ciphers: C[]) { @@ -1311,7 +1310,6 @@ export class VaultComponent implements OnInit, OnDestr if (selectedCipherIds.length === 0) { this.toastService.showToast({ variant: "error", - title: null, message: this.i18nService.t("nothingSelected"), }); return; @@ -1321,23 +1319,24 @@ export class VaultComponent implements OnInit, OnDestr await this.cipherService.restoreManyWithServer(selectedCipherIds, activeUserId); this.toastService.showToast({ variant: "success", - title: null, message: toastMessage, }); this.refresh(); } private async handleDeleteEvent(items: VaultItem[]) { - const ciphers: C[] = items.filter((i) => i.collection === undefined).map((i) => i.cipher); - const collections = items.filter((i) => i.cipher === undefined).map((i) => i.collection); + const ciphers = items + .filter((i) => i.collection === undefined && i.cipher !== undefined) + .map((i) => i.cipher as C); + const collections = items + .filter((i) => i.collection !== undefined) + .map((i) => i.collection as CollectionView); if (ciphers.length === 1 && collections.length === 0) { await this.deleteCipher(ciphers[0]); } else if (ciphers.length === 0 && collections.length === 1) { await this.deleteCollection(collections[0]); } else { - const orgIds = items - .filter((i) => i.cipher === undefined) - .map((i) => i.collection.organizationId); + const orgIds = collections.map((c) => c.organizationId); const orgs = await firstValueFrom( this.organizations$.pipe(map((orgs) => orgs.filter((o) => orgIds.includes(o.id)))), ); @@ -1345,7 +1344,7 @@ export class VaultComponent implements OnInit, OnDestr } } - async deleteCipher(c: C): Promise { + async deleteCipher(c: C) { if (!(await this.repromptCipher([c]))) { return; } @@ -1364,7 +1363,7 @@ export class VaultComponent implements OnInit, OnDestr }); if (!confirmed) { - return false; + return; } try { @@ -1373,7 +1372,6 @@ export class VaultComponent implements OnInit, OnDestr this.toastService.showToast({ variant: "success", - title: null, message: this.i18nService.t(permanent ? "permanentlyDeletedItem" : "deletedItem"), }); this.refresh(); @@ -1390,7 +1388,6 @@ export class VaultComponent implements OnInit, OnDestr if (ciphers.length === 0 && collections.length === 0) { this.toastService.showToast({ variant: "error", - title: null, message: this.i18nService.t("nothingSelected"), }); return; @@ -1430,7 +1427,6 @@ export class VaultComponent implements OnInit, OnDestr if (selectedCipherIds.length === 0) { this.toastService.showToast({ variant: "error", - title: null, message: this.i18nService.t("nothingSelected"), }); return; @@ -1454,11 +1450,8 @@ export class VaultComponent implements OnInit, OnDestr const login = CipherViewLikeUtils.getLogin(cipher); if (!login) { - this.toastService.showToast({ - variant: "error", - title: null, - message: this.i18nService.t("unexpectedError"), - }); + this.showErrorToast(); + return; } if (field === "username") { @@ -1471,15 +1464,15 @@ export class VaultComponent implements OnInit, OnDestr typeI18nKey = "password"; } else if (field === "totp") { aType = "TOTP"; + if (!login.totp) { + this.showErrorToast(); + return; + } const totpResponse = await firstValueFrom(this.totpService.getCode$(login.totp)); value = totpResponse.code; typeI18nKey = "verificationCodeTotp"; } else { - this.toastService.showToast({ - variant: "error", - title: null, - message: this.i18nService.t("unexpectedError"), - }); + this.showErrorToast(); return; } @@ -1494,10 +1487,13 @@ export class VaultComponent implements OnInit, OnDestr return; } + if (!value) { + this.showErrorToast(); + return; + } this.platformUtilsService.copyToClipboard(value, { window: window }); this.toastService.showToast({ variant: "info", - title: null, message: this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)), }); @@ -1514,6 +1510,13 @@ export class VaultComponent implements OnInit, OnDestr } } + showErrorToast() { + this.toastService.showToast({ + variant: "error", + message: this.i18nService.t("unexpectedError"), + }); + } + /** * Toggles the favorite status of the cipher and updates it on the server. */ @@ -1525,7 +1528,6 @@ export class VaultComponent implements OnInit, OnDestr this.toastService.showToast({ variant: "success", - title: null, message: this.i18nService.t( cipherFullView.favorite ? "itemAddedToFavorites" : "itemRemovedFromFavorites", ), @@ -1540,15 +1542,15 @@ export class VaultComponent implements OnInit, OnDestr : this.cipherService.softDeleteWithServer(id, userId); } - protected async repromptCipher(ciphers: C[]) { + protected async repromptCipher(ciphers: CipherViewLike[]) { const notProtected = !ciphers.find((cipher) => cipher.reprompt !== CipherRepromptType.None); return notProtected || (await this.passwordRepromptService.showPasswordPrompt()); } private refresh() { - this.refresh$.next(); - this.vaultItemsComponent?.clearSelection(); + this.refresh$.next(undefined); + this.vaultItemsComponent()?.clearSelection(); } private async go(queryParams: any = null) { @@ -1573,7 +1575,6 @@ export class VaultComponent implements OnInit, OnDestr private showMissingPermissionsError() { this.toastService.showToast({ variant: "error", - title: null, message: this.i18nService.t("missingPermissions"), }); } @@ -1584,13 +1585,13 @@ export class VaultComponent implements OnInit, OnDestr */ private async getPasswordFromCipherViewLike(cipher: C): Promise { if (!CipherViewLikeUtils.isCipherListView(cipher)) { - return Promise.resolve(cipher.login?.password); + return Promise.resolve(cipher?.login?.password); } const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); const _cipher = await this.cipherService.get(uuidAsString(cipher.id), activeUserId); const cipherView = await this.cipherService.decrypt(_cipher, activeUserId); - return cipherView.login?.password; + return cipherView.login.password; } } From bd9734c14c349d54982b909aa4ee8111768e9d08 Mon Sep 17 00:00:00 2001 From: John Harrington <84741727+harr1424@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:14:06 -0700 Subject: [PATCH 11/23] reorder form fields to match design specs (#18964) --- .../send-details/send-details.component.html | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libs/tools/send/send-ui/src/send-form/components/send-details/send-details.component.html b/libs/tools/send/send-ui/src/send-form/components/send-details/send-details.component.html index dc1894b0935..62fa65ae1e0 100644 --- a/libs/tools/send/send-ui/src/send-form/components/send-details/send-details.component.html +++ b/libs/tools/send/send-ui/src/send-form/components/send-details/send-details.component.html @@ -21,20 +21,6 @@ [originalSendView]="originalSendView" > - - {{ "sendLink" | i18n }} - - - - {{ "deletionDate" | i18n }} {{ "enterMultipleEmailsSeparatedByComma" | i18n }} } + + + {{ "sendLink" | i18n }} + + + From f5b1be7e62a0df1fd3f4e473e73b90c138c66d7d Mon Sep 17 00:00:00 2001 From: John Harrington <84741727+harr1424@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:14:31 -0700 Subject: [PATCH 12/23] add dynamic EV headers (#18949) --- .../send/send-access/send-auth.component.ts | 23 ++++++++++++++++++- .../send/send-access/send-view.component.ts | 3 +++ apps/web/src/locales/en/messages.json | 4 ++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/tools/send/send-access/send-auth.component.ts b/apps/web/src/app/tools/send/send-access/send-auth.component.ts index 9ed8106ad40..22ab04bd9dd 100644 --- a/apps/web/src/app/tools/send/send-access/send-auth.component.ts +++ b/apps/web/src/app/tools/send/send-access/send-auth.component.ts @@ -26,7 +26,7 @@ import { SendAccessResponse } from "@bitwarden/common/tools/send/models/response import { SEND_KDF_ITERATIONS } from "@bitwarden/common/tools/send/send-kdf"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { AuthType } from "@bitwarden/common/tools/send/types/auth-type"; -import { ToastService } from "@bitwarden/components"; +import { AnonLayoutWrapperDataService, ToastService } from "@bitwarden/components"; import { SharedModule } from "../../../shared"; @@ -69,9 +69,11 @@ export class SendAuthComponent implements OnInit { private formBuilder: FormBuilder, private configService: ConfigService, private sendTokenService: SendTokenService, + private anonLayoutWrapperDataService: AnonLayoutWrapperDataService, ) {} ngOnInit() { + this.updatePageTitle(); void this.onSubmit(); } @@ -160,8 +162,10 @@ export class SendAuthComponent implements OnInit { this.expiredAuthAttempts = 0; if (emailRequired(response.error)) { this.sendAuthType.set(AuthType.Email); + this.updatePageTitle(); } else if (emailAndOtpRequired(response.error)) { this.enterOtp.set(true); + this.updatePageTitle(); } else if (otpInvalid(response.error)) { this.toastService.showToast({ variant: "error", @@ -170,6 +174,7 @@ export class SendAuthComponent implements OnInit { }); } else if (passwordHashB64Required(response.error)) { this.sendAuthType.set(AuthType.Password); + this.updatePageTitle(); } else if (passwordHashB64Invalid(response.error)) { this.toastService.showToast({ variant: "error", @@ -207,4 +212,20 @@ export class SendAuthComponent implements OnInit { ); return Utils.fromBufferToB64(passwordHash) as SendHashedPasswordB64; } + + private updatePageTitle(): void { + const authType = this.sendAuthType(); + + if (authType === AuthType.Email) { + if (this.enterOtp()) { + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { key: "enterTheCodeSentToYourEmail" }, + }); + } else { + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { key: "verifyYourEmailToViewThisSend" }, + }); + } + } + } } diff --git a/apps/web/src/app/tools/send/send-access/send-view.component.ts b/apps/web/src/app/tools/send/send-access/send-view.component.ts index 1ab9a121ace..923a749db92 100644 --- a/apps/web/src/app/tools/send/send-access/send-view.component.ts +++ b/apps/web/src/app/tools/send/send-access/send-view.component.ts @@ -69,6 +69,9 @@ export class SendViewComponent implements OnInit { ) {} ngOnInit() { + this.layoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { key: "sendAccessContentTitle" }, + }); void this.load(); } diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 485f1fc07df..e43b266de4b 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -6438,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." From 2297082b1aa8341a59280e3f8f5e565582c1dc70 Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Fri, 13 Feb 2026 16:46:29 -0500 Subject: [PATCH 13/23] [PM-31668] Race condition in cipher cache clearing causes stale failed decryption state after leaving organization (#18941) * Refactored the search index to index with the cipherlistview * Fixed comment * clear encrypted cipher state to prevent stale emissions during sync * skip decrypt call when cipher arry is emoty during sync --- .../src/platform/sync/default-sync.service.ts | 2 + .../src/vault/abstractions/search.service.ts | 3 +- .../src/vault/services/cipher.service.ts | 26 ++- .../src/vault/services/search.service.ts | 120 ++++++----- .../utils/cipher-view-like-utils.spec.ts | 194 ++++++++++++++++++ .../src/vault/utils/cipher-view-like-utils.ts | 66 ++++++ 6 files changed, 350 insertions(+), 61 deletions(-) diff --git a/libs/common/src/platform/sync/default-sync.service.ts b/libs/common/src/platform/sync/default-sync.service.ts index 68c03503e8d..a25b1b3c210 100644 --- a/libs/common/src/platform/sync/default-sync.service.ts +++ b/libs/common/src/platform/sync/default-sync.service.ts @@ -183,6 +183,8 @@ export class DefaultSyncService extends CoreSyncService { const response = await this.inFlightApiCalls.sync; + await this.cipherService.clear(response.profile.id); + await this.syncUserDecryption(response.profile.id, response.userDecryption); await this.syncProfile(response.profile); await this.syncFolders(response.folders, response.profile.id); diff --git a/libs/common/src/vault/abstractions/search.service.ts b/libs/common/src/vault/abstractions/search.service.ts index 29575ec3af9..b4dfc015efe 100644 --- a/libs/common/src/vault/abstractions/search.service.ts +++ b/libs/common/src/vault/abstractions/search.service.ts @@ -2,7 +2,6 @@ import { Observable } from "rxjs"; import { SendView } from "../../tools/send/models/view/send.view"; import { IndexedEntityId, UserId } from "../../types/guid"; -import { CipherView } from "../models/view/cipher.view"; import { CipherViewLike } from "../utils/cipher-view-like-utils"; export abstract class SearchService { @@ -20,7 +19,7 @@ export abstract class SearchService { abstract isSearchable(userId: UserId, query: string | null): Promise; abstract indexCiphers( userId: UserId, - ciphersToIndex: CipherView[], + ciphersToIndex: CipherViewLike[], indexedEntityGuid?: string, ): Promise; abstract searchCiphers( diff --git a/libs/common/src/vault/services/cipher.service.ts b/libs/common/src/vault/services/cipher.service.ts index 06c6628f158..e4c4f892b4a 100644 --- a/libs/common/src/vault/services/cipher.service.ts +++ b/libs/common/src/vault/services/cipher.service.ts @@ -173,13 +173,14 @@ export class CipherService implements CipherServiceAbstraction { decryptStartTime = performance.now(); }), switchMap(async (ciphers) => { - const [decrypted, failures] = await this.decryptCiphersWithSdk(ciphers, userId, false); - void this.setFailedDecryptedCiphers(failures, userId); - // Trigger full decryption and indexing in background - void this.getAllDecrypted(userId); - return decrypted; + return await this.decryptCiphersWithSdk(ciphers, userId, false); }), - tap((decrypted) => { + tap(([decrypted, failures]) => { + void Promise.all([ + this.setFailedDecryptedCiphers(failures, userId), + this.searchService.indexCiphers(userId, decrypted), + ]); + this.logService.measure( decryptStartTime, "Vault", @@ -188,10 +189,11 @@ export class CipherService implements CipherServiceAbstraction { [["Items", decrypted.length]], ); }), + map(([decrypted]) => decrypted), ); }), ); - }); + }, this.clearCipherViewsForUser$); /** * Observable that emits an array of decrypted ciphers for the active user. @@ -530,6 +532,10 @@ export class CipherService implements CipherServiceAbstraction { ciphers: Cipher[], userId: UserId, ): Promise<[CipherView[], CipherView[]] | null> { + if (ciphers.length === 0) { + return [[], []]; + } + if (await this.configService.getFeatureFlag(FeatureFlag.PM19941MigrateCipherDomainToSdk)) { const decryptStartTime = performance.now(); @@ -2401,6 +2407,12 @@ export class CipherService implements CipherServiceAbstraction { userId: UserId, fullDecryption: boolean = true, ): Promise<[CipherViewLike[], CipherView[]]> { + // Short-circuit if there are no ciphers to decrypt + // Observables reacting to key changes may attempt to decrypt with a stale SDK reference. + if (ciphers.length === 0) { + return [[], []]; + } + if (fullDecryption) { const [decryptedViews, failedViews] = await this.cipherEncryptionService.decryptManyLegacy( ciphers, diff --git a/libs/common/src/vault/services/search.service.ts b/libs/common/src/vault/services/search.service.ts index feb6a7494b5..e14a66aad6f 100644 --- a/libs/common/src/vault/services/search.service.ts +++ b/libs/common/src/vault/services/search.service.ts @@ -21,7 +21,6 @@ import { IndexedEntityId, UserId } from "../../types/guid"; import { SearchService as SearchServiceAbstraction } from "../abstractions/search.service"; import { FieldType } from "../enums"; import { CipherType } from "../enums/cipher-type"; -import { CipherView } from "../models/view/cipher.view"; import { CipherViewLike, CipherViewLikeUtils } from "../utils/cipher-view-like-utils"; // Time to wait before performing a search after the user stops typing. @@ -169,7 +168,7 @@ export class SearchService implements SearchServiceAbstraction { async indexCiphers( userId: UserId, - ciphers: CipherView[], + ciphers: CipherViewLike[], indexedEntityId?: string, ): Promise { if (await this.getIsIndexing(userId)) { @@ -182,34 +181,47 @@ export class SearchService implements SearchServiceAbstraction { const builder = new lunr.Builder(); builder.pipeline.add(this.normalizeAccentsPipelineFunction); builder.ref("id"); - builder.field("shortid", { boost: 100, extractor: (c: CipherView) => c.id.substr(0, 8) }); + builder.field("shortid", { + boost: 100, + extractor: (c: CipherViewLike) => uuidAsString(c.id).substr(0, 8), + }); builder.field("name", { boost: 10, }); builder.field("subtitle", { boost: 5, - extractor: (c: CipherView) => { - if (c.subTitle != null && c.type === CipherType.Card) { - return c.subTitle.replace(/\*/g, ""); + extractor: (c: CipherViewLike) => { + const subtitle = CipherViewLikeUtils.subtitle(c); + if (subtitle != null && CipherViewLikeUtils.getType(c) === CipherType.Card) { + return subtitle.replace(/\*/g, ""); } - return c.subTitle; + return subtitle; }, }); - builder.field("notes"); + builder.field("notes", { extractor: (c: CipherViewLike) => CipherViewLikeUtils.getNotes(c) }); builder.field("login.username", { - extractor: (c: CipherView) => - c.type === CipherType.Login && c.login != null ? c.login.username : null, + extractor: (c: CipherViewLike) => { + const login = CipherViewLikeUtils.getLogin(c); + return login?.username ?? null; + }, + }); + builder.field("login.uris", { + boost: 2, + extractor: (c: CipherViewLike) => this.uriExtractor(c), + }); + builder.field("fields", { + extractor: (c: CipherViewLike) => this.fieldExtractor(c, false), + }); + builder.field("fields_joined", { + extractor: (c: CipherViewLike) => this.fieldExtractor(c, true), }); - builder.field("login.uris", { boost: 2, extractor: (c: CipherView) => this.uriExtractor(c) }); - builder.field("fields", { extractor: (c: CipherView) => this.fieldExtractor(c, false) }); - builder.field("fields_joined", { extractor: (c: CipherView) => this.fieldExtractor(c, true) }); builder.field("attachments", { - extractor: (c: CipherView) => this.attachmentExtractor(c, false), + extractor: (c: CipherViewLike) => this.attachmentExtractor(c, false), }); builder.field("attachments_joined", { - extractor: (c: CipherView) => this.attachmentExtractor(c, true), + extractor: (c: CipherViewLike) => this.attachmentExtractor(c, true), }); - builder.field("organizationid", { extractor: (c: CipherView) => c.organizationId }); + builder.field("organizationid", { extractor: (c: CipherViewLike) => c.organizationId }); ciphers = ciphers || []; ciphers.forEach((c) => builder.add(c)); const index = builder.build(); @@ -400,37 +412,44 @@ export class SearchService implements SearchServiceAbstraction { return await firstValueFrom(this.searchIsIndexing$(userId)); } - private fieldExtractor(c: CipherView, joined: boolean) { - if (!c.hasFields) { + private fieldExtractor(c: CipherViewLike, joined: boolean) { + const fields = CipherViewLikeUtils.getFields(c); + if (!fields || fields.length === 0) { return null; } - let fields: string[] = []; - c.fields.forEach((f) => { + let fieldStrings: string[] = []; + fields.forEach((f) => { if (f.name != null) { - fields.push(f.name); + fieldStrings.push(f.name); } - if (f.type === FieldType.Text && f.value != null) { - fields.push(f.value); + // For CipherListView, value is only populated for Text fields + // For CipherView, we check the type explicitly + if (f.value != null) { + const fieldType = (f as { type?: FieldType }).type; + if (fieldType === undefined || fieldType === FieldType.Text) { + fieldStrings.push(f.value); + } } }); - fields = fields.filter((f) => f.trim() !== ""); - if (fields.length === 0) { + fieldStrings = fieldStrings.filter((f) => f.trim() !== ""); + if (fieldStrings.length === 0) { return null; } - return joined ? fields.join(" ") : fields; + return joined ? fieldStrings.join(" ") : fieldStrings; } - private attachmentExtractor(c: CipherView, joined: boolean) { - if (!c.hasAttachments) { + private attachmentExtractor(c: CipherViewLike, joined: boolean) { + const attachmentNames = CipherViewLikeUtils.getAttachmentNames(c); + if (!attachmentNames || attachmentNames.length === 0) { return null; } let attachments: string[] = []; - c.attachments.forEach((a) => { - if (a != null && a.fileName != null) { - if (joined && a.fileName.indexOf(".") > -1) { - attachments.push(a.fileName.substr(0, a.fileName.lastIndexOf("."))); + attachmentNames.forEach((fileName) => { + if (fileName != null) { + if (joined && fileName.indexOf(".") > -1) { + attachments.push(fileName.substring(0, fileName.lastIndexOf("."))); } else { - attachments.push(a.fileName); + attachments.push(fileName); } } }); @@ -441,43 +460,39 @@ export class SearchService implements SearchServiceAbstraction { return joined ? attachments.join(" ") : attachments; } - private uriExtractor(c: CipherView) { - if (c.type !== CipherType.Login || c.login == null || !c.login.hasUris) { + private uriExtractor(c: CipherViewLike) { + if (CipherViewLikeUtils.getType(c) !== CipherType.Login) { + return null; + } + const login = CipherViewLikeUtils.getLogin(c); + if (!login?.uris?.length) { return null; } const uris: string[] = []; - c.login.uris.forEach((u) => { + login.uris.forEach((u) => { if (u.uri == null || u.uri === "") { return; } - // Match ports + // Extract port from URI const portMatch = u.uri.match(/:(\d+)(?:[/?#]|$)/); const port = portMatch?.[1]; - let uri = u.uri; - - if (u.hostname !== null) { - uris.push(u.hostname); + const hostname = CipherViewLikeUtils.getUriHostname(u); + if (hostname !== undefined) { + uris.push(hostname); if (port) { - uris.push(`${u.hostname}:${port}`); - uris.push(port); - } - return; - } else { - const slash = uri.indexOf("/"); - const hostPart = slash > -1 ? uri.substring(0, slash) : uri; - uris.push(hostPart); - if (port) { - uris.push(`${hostPart}`); + uris.push(`${hostname}:${port}`); uris.push(port); } } + // Add processed URI (strip protocol and query params for non-regex matches) + let uri = u.uri; if (u.match !== UriMatchStrategy.RegularExpression) { const protocolIndex = uri.indexOf("://"); if (protocolIndex > -1) { - uri = uri.substr(protocolIndex + 3); + uri = uri.substring(protocolIndex + 3); } const queryIndex = uri.search(/\?|&|#/); if (queryIndex > -1) { @@ -486,6 +501,7 @@ export class SearchService implements SearchServiceAbstraction { } uris.push(uri); }); + return uris.length > 0 ? uris : null; } diff --git a/libs/common/src/vault/utils/cipher-view-like-utils.spec.ts b/libs/common/src/vault/utils/cipher-view-like-utils.spec.ts index 56b94fcf3ce..2a7bfac2970 100644 --- a/libs/common/src/vault/utils/cipher-view-like-utils.spec.ts +++ b/libs/common/src/vault/utils/cipher-view-like-utils.spec.ts @@ -651,4 +651,198 @@ describe("CipherViewLikeUtils", () => { expect(CipherViewLikeUtils.decryptionFailure(cipherListView)).toBe(false); }); }); + + describe("getNotes", () => { + describe("CipherView", () => { + it("returns notes when present", () => { + const cipherView = createCipherView(); + cipherView.notes = "This is a test note"; + + expect(CipherViewLikeUtils.getNotes(cipherView)).toBe("This is a test note"); + }); + + it("returns undefined when notes are not present", () => { + const cipherView = createCipherView(); + cipherView.notes = undefined; + + expect(CipherViewLikeUtils.getNotes(cipherView)).toBeUndefined(); + }); + }); + + describe("CipherListView", () => { + it("returns notes when present", () => { + const cipherListView = { + type: "secureNote", + notes: "List view notes", + } as CipherListView; + + expect(CipherViewLikeUtils.getNotes(cipherListView)).toBe("List view notes"); + }); + + it("returns undefined when notes are not present", () => { + const cipherListView = { + type: "secureNote", + } as CipherListView; + + expect(CipherViewLikeUtils.getNotes(cipherListView)).toBeUndefined(); + }); + }); + }); + + describe("getFields", () => { + describe("CipherView", () => { + it("returns fields when present", () => { + const cipherView = createCipherView(); + cipherView.fields = [ + { name: "Field1", value: "Value1" } as any, + { name: "Field2", value: "Value2" } as any, + ]; + + const fields = CipherViewLikeUtils.getFields(cipherView); + + expect(fields).toHaveLength(2); + expect(fields?.[0].name).toBe("Field1"); + expect(fields?.[0].value).toBe("Value1"); + expect(fields?.[1].name).toBe("Field2"); + expect(fields?.[1].value).toBe("Value2"); + }); + + it("returns empty array when fields array is empty", () => { + const cipherView = createCipherView(); + cipherView.fields = []; + + expect(CipherViewLikeUtils.getFields(cipherView)).toEqual([]); + }); + }); + + describe("CipherListView", () => { + it("returns fields when present", () => { + const cipherListView = { + type: { login: {} }, + fields: [ + { name: "Username", value: "user@example.com" }, + { name: "API Key", value: "abc123" }, + ], + } as CipherListView; + + const fields = CipherViewLikeUtils.getFields(cipherListView); + + expect(fields).toHaveLength(2); + expect(fields?.[0].name).toBe("Username"); + expect(fields?.[0].value).toBe("user@example.com"); + expect(fields?.[1].name).toBe("API Key"); + expect(fields?.[1].value).toBe("abc123"); + }); + + it("returns empty array when fields array is empty", () => { + const cipherListView = { + type: "secureNote", + fields: [], + } as unknown as CipherListView; + + expect(CipherViewLikeUtils.getFields(cipherListView)).toEqual([]); + }); + + it("returns undefined when fields are not present", () => { + const cipherListView = { + type: "secureNote", + } as CipherListView; + + expect(CipherViewLikeUtils.getFields(cipherListView)).toBeUndefined(); + }); + }); + }); + + describe("getAttachmentNames", () => { + describe("CipherView", () => { + it("returns attachment filenames when present", () => { + const cipherView = createCipherView(); + const attachment1 = new AttachmentView(); + attachment1.id = "1"; + attachment1.fileName = "document.pdf"; + const attachment2 = new AttachmentView(); + attachment2.id = "2"; + attachment2.fileName = "image.png"; + const attachment3 = new AttachmentView(); + attachment3.id = "3"; + attachment3.fileName = "spreadsheet.xlsx"; + cipherView.attachments = [attachment1, attachment2, attachment3]; + + const attachmentNames = CipherViewLikeUtils.getAttachmentNames(cipherView); + + expect(attachmentNames).toEqual(["document.pdf", "image.png", "spreadsheet.xlsx"]); + }); + + it("filters out null and undefined filenames", () => { + const cipherView = createCipherView(); + const attachment1 = new AttachmentView(); + attachment1.id = "1"; + attachment1.fileName = "valid.pdf"; + const attachment2 = new AttachmentView(); + attachment2.id = "2"; + attachment2.fileName = null as any; + const attachment3 = new AttachmentView(); + attachment3.id = "3"; + attachment3.fileName = undefined; + const attachment4 = new AttachmentView(); + attachment4.id = "4"; + attachment4.fileName = "another.txt"; + cipherView.attachments = [attachment1, attachment2, attachment3, attachment4]; + + const attachmentNames = CipherViewLikeUtils.getAttachmentNames(cipherView); + + expect(attachmentNames).toEqual(["valid.pdf", "another.txt"]); + }); + + it("returns empty array when attachments have no filenames", () => { + const cipherView = createCipherView(); + const attachment1 = new AttachmentView(); + attachment1.id = "1"; + const attachment2 = new AttachmentView(); + attachment2.id = "2"; + cipherView.attachments = [attachment1, attachment2]; + + const attachmentNames = CipherViewLikeUtils.getAttachmentNames(cipherView); + + expect(attachmentNames).toEqual([]); + }); + + it("returns empty array for empty attachments array", () => { + const cipherView = createCipherView(); + cipherView.attachments = []; + + expect(CipherViewLikeUtils.getAttachmentNames(cipherView)).toEqual([]); + }); + }); + + describe("CipherListView", () => { + it("returns attachment names when present", () => { + const cipherListView = { + type: "secureNote", + attachmentNames: ["report.pdf", "photo.jpg", "data.csv"], + } as CipherListView; + + const attachmentNames = CipherViewLikeUtils.getAttachmentNames(cipherListView); + + expect(attachmentNames).toEqual(["report.pdf", "photo.jpg", "data.csv"]); + }); + + it("returns empty array when attachmentNames is empty", () => { + const cipherListView = { + type: "secureNote", + attachmentNames: [], + } as unknown as CipherListView; + + expect(CipherViewLikeUtils.getAttachmentNames(cipherListView)).toEqual([]); + }); + + it("returns undefined when attachmentNames is not present", () => { + const cipherListView = { + type: "secureNote", + } as CipherListView; + + expect(CipherViewLikeUtils.getAttachmentNames(cipherListView)).toBeUndefined(); + }); + }); + }); }); diff --git a/libs/common/src/vault/utils/cipher-view-like-utils.ts b/libs/common/src/vault/utils/cipher-view-like-utils.ts index 04adb8d4832..5359bfb958f 100644 --- a/libs/common/src/vault/utils/cipher-view-like-utils.ts +++ b/libs/common/src/vault/utils/cipher-view-like-utils.ts @@ -10,6 +10,7 @@ import { LoginUriView as LoginListUriView, } from "@bitwarden/sdk-internal"; +import { Utils } from "../../platform/misc/utils"; import { CipherType } from "../enums"; import { Cipher } from "../models/domain/cipher"; import { CardView } from "../models/view/card.view"; @@ -290,6 +291,71 @@ export class CipherViewLikeUtils { static decryptionFailure = (cipher: CipherViewLike): boolean => { return "decryptionFailure" in cipher ? cipher.decryptionFailure : false; }; + + /** + * Returns the notes from the cipher. + * + * @param cipher - The cipher to extract notes from (either `CipherView` or `CipherListView`) + * @returns The notes string if present, or `undefined` if not set + */ + static getNotes = (cipher: CipherViewLike): string | undefined => { + return cipher.notes; + }; + + /** + * Returns the fields from the cipher. + * + * @param cipher - The cipher to extract fields from (either `CipherView` or `CipherListView`) + * @returns Array of field objects with `name` and `value` properties, `undefined` if not set + */ + static getFields = ( + cipher: CipherViewLike, + ): { name?: string | null; value?: string | undefined }[] | undefined => { + if (this.isCipherListView(cipher)) { + return cipher.fields; + } + return cipher.fields; + }; + + /** + * Returns attachment filenames from the cipher. + * + * @param cipher - The cipher to extract attachment names from (either `CipherView` or `CipherListView`) + * @returns Array of attachment filenames, `undefined` if attachments are not present + */ + static getAttachmentNames = (cipher: CipherViewLike): string[] | undefined => { + if (this.isCipherListView(cipher)) { + return cipher.attachmentNames; + } + + return cipher.attachments + ?.map((a) => a.fileName) + .filter((name): name is string => name != null); + }; + + /** + * Extracts hostname from a login URI. + * + * @param uri - The URI object (either `LoginUriView` class or `LoginListUriView`) + * @returns The hostname if available, `undefined` otherwise + * + * @remarks + * - For `LoginUriView` (CipherView): Uses the built-in `hostname` getter + * - For `LoginListUriView` (CipherListView): Computes hostname using `Utils.getHostname()` + * - Returns `undefined` for RegularExpression match types or when hostname cannot be extracted + */ + static getUriHostname = (uri: LoginListUriView | LoginUriView): string | undefined => { + if ("hostname" in uri && typeof uri.hostname !== "undefined") { + return uri.hostname ?? undefined; + } + + if (uri.match !== UriMatchStrategy.RegularExpression && uri.uri) { + const hostname = Utils.getHostname(uri.uri); + return hostname === "" ? undefined : hostname; + } + + return undefined; + }; } /** From 8bd1e5a855700dc1f132ad8fbad2dd03d19364fa Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Fri, 13 Feb 2026 18:13:41 -0500 Subject: [PATCH 14/23] [PM-30580] Add encryptMany to SDK for batch cipher encryption (#18942) * Migrated encrypt many to the sdk * removed comment * updated sdk package --- .../default-cipher-encryption.service.spec.ts | 27 ++++++++++++++----- .../default-cipher-encryption.service.ts | 19 +++++-------- package-lock.json | 16 +++++------ package.json | 4 +-- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/libs/common/src/vault/services/default-cipher-encryption.service.spec.ts b/libs/common/src/vault/services/default-cipher-encryption.service.spec.ts index a0ca4833b92..98b554b5762 100644 --- a/libs/common/src/vault/services/default-cipher-encryption.service.spec.ts +++ b/libs/common/src/vault/services/default-cipher-encryption.service.spec.ts @@ -95,6 +95,7 @@ describe("DefaultCipherEncryptionService", () => { vault: jest.fn().mockReturnValue({ ciphers: jest.fn().mockReturnValue({ encrypt: jest.fn(), + encrypt_list: jest.fn(), encrypt_cipher_for_rotation: jest.fn(), set_fido2_credentials: jest.fn(), decrypt: jest.fn(), @@ -280,10 +281,23 @@ describe("DefaultCipherEncryptionService", () => { name: "encrypted-name-3", } as unknown as Cipher; - mockSdkClient.vault().ciphers().encrypt.mockReturnValue({ - cipher: sdkCipher, - encryptedFor: userId, - }); + mockSdkClient + .vault() + .ciphers() + .encrypt_list.mockReturnValue([ + { + cipher: sdkCipher, + encryptedFor: userId, + }, + { + cipher: sdkCipher, + encryptedFor: userId, + }, + { + cipher: sdkCipher, + encryptedFor: userId, + }, + ]); jest .spyOn(Cipher, "fromSdkCipher") @@ -299,7 +313,8 @@ describe("DefaultCipherEncryptionService", () => { expect(results[1].cipher).toEqual(expectedCipher2); expect(results[2].cipher).toEqual(expectedCipher3); - expect(mockSdkClient.vault().ciphers().encrypt).toHaveBeenCalledTimes(3); + expect(mockSdkClient.vault().ciphers().encrypt_list).toHaveBeenCalledTimes(1); + expect(mockSdkClient.vault().ciphers().encrypt).not.toHaveBeenCalled(); expect(results[0].encryptedFor).toBe(userId); expect(results[1].encryptedFor).toBe(userId); @@ -311,7 +326,7 @@ describe("DefaultCipherEncryptionService", () => { expect(results).toBeDefined(); expect(results.length).toBe(0); - expect(mockSdkClient.vault().ciphers().encrypt).not.toHaveBeenCalled(); + expect(mockSdkClient.vault().ciphers().encrypt_list).not.toHaveBeenCalled(); }); }); diff --git a/libs/common/src/vault/services/default-cipher-encryption.service.ts b/libs/common/src/vault/services/default-cipher-encryption.service.ts index 588265846e0..45542091618 100644 --- a/libs/common/src/vault/services/default-cipher-encryption.service.ts +++ b/libs/common/src/vault/services/default-cipher-encryption.service.ts @@ -65,21 +65,14 @@ export class DefaultCipherEncryptionService implements CipherEncryptionService { using ref = sdk.take(); - const results: EncryptionContext[] = []; - - // TODO: https://bitwarden.atlassian.net/browse/PM-30580 - // Replace this loop with a native SDK encryptMany method for better performance. - for (const model of models) { - const sdkCipherView = this.toSdkCipherView(model, ref.value); - const encryptionContext = ref.value.vault().ciphers().encrypt(sdkCipherView); - - results.push({ + return ref.value + .vault() + .ciphers() + .encrypt_list(models.map((model) => this.toSdkCipherView(model, ref.value))) + .map((encryptionContext) => ({ cipher: Cipher.fromSdkCipher(encryptionContext.cipher)!, encryptedFor: uuidAsString(encryptionContext.encryptedFor) as UserId, - }); - } - - return results; + })); }), catchError((error: unknown) => { this.logService.error(`Failed to encrypt ciphers in batch: ${error}`); diff --git a/package-lock.json b/package-lock.json index dbdcd6d083d..789a63c07b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,8 +23,8 @@ "@angular/platform-browser": "20.3.16", "@angular/platform-browser-dynamic": "20.3.16", "@angular/router": "20.3.16", - "@bitwarden/commercial-sdk-internal": "0.2.0-main.522", - "@bitwarden/sdk-internal": "0.2.0-main.522", + "@bitwarden/commercial-sdk-internal": "0.2.0-main.527", + "@bitwarden/sdk-internal": "0.2.0-main.527", "@electron/fuses": "1.8.0", "@emotion/css": "11.13.5", "@koa/multer": "4.0.0", @@ -4936,9 +4936,9 @@ "link": true }, "node_modules/@bitwarden/commercial-sdk-internal": { - "version": "0.2.0-main.522", - "resolved": "https://registry.npmjs.org/@bitwarden/commercial-sdk-internal/-/commercial-sdk-internal-0.2.0-main.522.tgz", - "integrity": "sha512-2wAbg30cGlDhSj14LaK2/ISuT91XPVeNgL/PU+eoxLhAehGKjAXdvZN3PSwFaAuaMbEFzlESvqC1pzzO4p/1zw==", + "version": "0.2.0-main.527", + "resolved": "https://registry.npmjs.org/@bitwarden/commercial-sdk-internal/-/commercial-sdk-internal-0.2.0-main.527.tgz", + "integrity": "sha512-4C4lwOgA2v184G2axUR5Jdb4UMXMhF52a/3c0lAZYbD/8Nid6jziE89nCa9hdfdazuPgWXhVFa3gPrhLZ4uTUQ==", "license": "BITWARDEN SOFTWARE DEVELOPMENT KIT LICENSE AGREEMENT", "dependencies": { "type-fest": "^4.41.0" @@ -5041,9 +5041,9 @@ "link": true }, "node_modules/@bitwarden/sdk-internal": { - "version": "0.2.0-main.522", - "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.522.tgz", - "integrity": "sha512-E+YqqX/FvGF0vGx6sNJfYaMj88C+rVo51fQPMSHoOePdryFcKQSJX706Glv86OMLMXE7Ln5Lua8LJRftlF/EFQ==", + "version": "0.2.0-main.527", + "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.527.tgz", + "integrity": "sha512-dxPh4XjEGFDBASRBEd/JwUdoMAz10W/0QGygYkPwhKKGzJncfDEAgQ/KrT9wc36ycrDrOOspff7xs/vmmzI0+A==", "license": "GPL-3.0", "dependencies": { "type-fest": "^4.41.0" diff --git a/package.json b/package.json index bc1553c4622..7499a69f99c 100644 --- a/package.json +++ b/package.json @@ -161,8 +161,8 @@ "@angular/platform-browser": "20.3.16", "@angular/platform-browser-dynamic": "20.3.16", "@angular/router": "20.3.16", - "@bitwarden/commercial-sdk-internal": "0.2.0-main.522", - "@bitwarden/sdk-internal": "0.2.0-main.522", + "@bitwarden/commercial-sdk-internal": "0.2.0-main.527", + "@bitwarden/sdk-internal": "0.2.0-main.527", "@electron/fuses": "1.8.0", "@emotion/css": "11.13.5", "@koa/multer": "4.0.0", From 470f91ae57a6af12026d5b1539d12d3ae89b2910 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 04:10:07 -0600 Subject: [PATCH 15/23] [deps]: Update dtolnay/rust-toolchain digest to efa25f7 (#18997) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/lint.yml | 4 ++-- .github/workflows/test.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index efc8c25fc5e..b50db6e08b6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -100,13 +100,13 @@ jobs: persist-credentials: false - name: Install Rust - uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # stable + uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # stable with: toolchain: stable components: rustfmt, clippy - name: Install Rust nightly - uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # stable + uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # stable with: toolchain: nightly components: rustfmt diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a0f783bbb36..c2fd4b7c32b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -210,7 +210,7 @@ jobs: persist-credentials: false - name: Install rust - uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # stable + uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # stable with: toolchain: stable components: llvm-tools From 8620a2d7e412119ec75a9d5e2df256f54fc96a87 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 04:36:42 -0600 Subject: [PATCH 16/23] Autosync the updated translations (#19008) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/ar/messages.json | 11 +- apps/browser/src/_locales/az/messages.json | 9 +- apps/browser/src/_locales/be/messages.json | 11 +- apps/browser/src/_locales/bg/messages.json | 11 +- apps/browser/src/_locales/bn/messages.json | 11 +- apps/browser/src/_locales/bs/messages.json | 11 +- apps/browser/src/_locales/ca/messages.json | 11 +- apps/browser/src/_locales/cs/messages.json | 9 +- apps/browser/src/_locales/cy/messages.json | 11 +- apps/browser/src/_locales/da/messages.json | 11 +- apps/browser/src/_locales/de/messages.json | 15 +- apps/browser/src/_locales/el/messages.json | 11 +- apps/browser/src/_locales/en_GB/messages.json | 11 +- apps/browser/src/_locales/en_IN/messages.json | 11 +- apps/browser/src/_locales/es/messages.json | 13 +- apps/browser/src/_locales/et/messages.json | 11 +- apps/browser/src/_locales/eu/messages.json | 143 +++++++++--------- apps/browser/src/_locales/fa/messages.json | 11 +- apps/browser/src/_locales/fi/messages.json | 11 +- apps/browser/src/_locales/fil/messages.json | 11 +- apps/browser/src/_locales/fr/messages.json | 11 +- apps/browser/src/_locales/gl/messages.json | 11 +- apps/browser/src/_locales/he/messages.json | 11 +- apps/browser/src/_locales/hi/messages.json | 11 +- apps/browser/src/_locales/hr/messages.json | 11 +- apps/browser/src/_locales/hu/messages.json | 9 +- apps/browser/src/_locales/id/messages.json | 11 +- apps/browser/src/_locales/it/messages.json | 11 +- apps/browser/src/_locales/ja/messages.json | 11 +- apps/browser/src/_locales/ka/messages.json | 11 +- apps/browser/src/_locales/km/messages.json | 11 +- apps/browser/src/_locales/kn/messages.json | 11 +- apps/browser/src/_locales/ko/messages.json | 11 +- apps/browser/src/_locales/lt/messages.json | 11 +- apps/browser/src/_locales/lv/messages.json | 11 +- apps/browser/src/_locales/ml/messages.json | 11 +- apps/browser/src/_locales/mr/messages.json | 11 +- apps/browser/src/_locales/my/messages.json | 11 +- apps/browser/src/_locales/nb/messages.json | 11 +- apps/browser/src/_locales/ne/messages.json | 11 +- apps/browser/src/_locales/nl/messages.json | 11 +- apps/browser/src/_locales/nn/messages.json | 11 +- apps/browser/src/_locales/or/messages.json | 11 +- apps/browser/src/_locales/pl/messages.json | 15 +- apps/browser/src/_locales/pt_BR/messages.json | 11 +- apps/browser/src/_locales/pt_PT/messages.json | 11 +- apps/browser/src/_locales/ro/messages.json | 11 +- apps/browser/src/_locales/ru/messages.json | 11 +- apps/browser/src/_locales/si/messages.json | 11 +- apps/browser/src/_locales/sk/messages.json | 7 +- apps/browser/src/_locales/sl/messages.json | 11 +- apps/browser/src/_locales/sr/messages.json | 11 +- apps/browser/src/_locales/sv/messages.json | 11 +- apps/browser/src/_locales/ta/messages.json | 11 +- apps/browser/src/_locales/te/messages.json | 11 +- apps/browser/src/_locales/th/messages.json | 11 +- apps/browser/src/_locales/tr/messages.json | 9 +- apps/browser/src/_locales/uk/messages.json | 11 +- apps/browser/src/_locales/vi/messages.json | 11 +- apps/browser/src/_locales/zh_CN/messages.json | 11 +- apps/browser/src/_locales/zh_TW/messages.json | 57 ++++--- 61 files changed, 332 insertions(+), 515 deletions(-) diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 78cf90c3555..7334362d446 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 6a43475da32..6168f7cf2dd 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -573,13 +573,10 @@ "noItemsInArchiveDesc": { "message": "Arxivlənmiş elementlər burada görünəcək, ümumi axtarış nəticələrindən və avto-doldurma təkliflərindən xaric ediləcək." }, - "itemWasSentToArchive": { - "message": "Element arxivə göndərildi" + "itemArchiveToast": { + "message": "Element arxivləndi" }, - "itemWasUnarchived": { - "message": "Element arxivdən çıxarıldı" - }, - "itemUnarchived": { + "itemUnarchivedToast": { "message": "Element arxivdən çıxarıldı" }, "archiveItem": { diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index 9f4a65e3072..ea569cabdf4 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index a46ad75065e..e5d68bce366 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Архивираните елементи ще се показват тук и ще бъдат изключени от общите резултати при търсене и от предложенията за автоматично попълване." }, - "itemWasSentToArchive": { - "message": "Елементът беше преместен в архива" + "itemArchiveToast": { + "message": "Елементът е преместен в архива" }, - "itemWasUnarchived": { - "message": "Елементът беше изваден от архива" - }, - "itemUnarchived": { - "message": "Елементът беше изваден от архива" + "itemUnarchivedToast": { + "message": "Елементът е изваден от архива" }, "archiveItem": { "message": "Архивиране на елемента" diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index b46d0664231..533b12ab0a5 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index e81fc637b5c..35c4177e5eb 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 2bd53876953..8e82fc34be4 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 1501c7d7c4a..ed1b37134e1 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -573,13 +573,10 @@ "noItemsInArchiveDesc": { "message": "Zde se zobrazí archivované položky a budou vyloučeny z obecných výsledků vyhledávání a návrhů automatického vyplňování." }, - "itemWasSentToArchive": { - "message": "Položka byla přesunuta do archivu" + "itemArchiveToast": { + "message": "Položka archivována" }, - "itemWasUnarchived": { - "message": "Položka byla odebrána z archivu" - }, - "itemUnarchived": { + "itemUnarchivedToast": { "message": "Položka byla odebrána z archivu" }, "archiveItem": { diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index 6910fe2efb3..165cd05de8e 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index faf4fc855ec..615cc6a2a0b 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index ad5b45159df..8f2b023bc00 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archivierte Einträge werden hier angezeigt und von allgemeinen Suchergebnissen sowie Vorschlägen zum automatischen Ausfüllen ausgeschlossen." }, - "itemWasSentToArchive": { - "message": "Eintrag wurde archiviert" + "itemArchiveToast": { + "message": "Eintrag archiviert" }, - "itemWasUnarchived": { - "message": "Eintrag wird nicht mehr archiviert" - }, - "itemUnarchived": { - "message": "Eintrag wird nicht mehr archiviert" + "itemUnarchivedToast": { + "message": "Eintrag nicht mehr archiviert" }, "archiveItem": { "message": "Eintrag archivieren" @@ -5964,7 +5961,7 @@ "message": "Kartennummer" }, "errorCannotDecrypt": { - "message": "Error: Cannot decrypt" + "message": "Fehler: Entschlüsselung nicht möglich" }, "removeMasterPasswordForOrgUserKeyConnector": { "message": "Deine Organisation verwendet keine Master-Passwörter mehr, um sich bei Bitwarden anzumelden. Verifiziere die Organisation und Domain, um fortzufahren." @@ -6128,7 +6125,7 @@ "message": "benutzer@bitwarden.com, benutzer@acme.com" }, "downloadBitwardenApps": { - "message": "Download Bitwarden apps" + "message": "Bitwarden-Apps herunterladen" }, "emailProtected": { "message": "E-Mail-Adresse geschützt" diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 59f757008f2..68f7267825d 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Το στοιχείο στάλθηκε στην αρχειοθήκη" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Το στοιχείο επαναφέρθηκε από την αρχειοθήκη" - }, - "itemUnarchived": { - "message": "Το στοιχείο επαναφέρθηκε από την αρχειοθήκη" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Αρχειοθέτηση στοιχείου" diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index e34e20844e6..d61774df145 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 9fd388a80d3..3622ffce241 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index ab5fad7e3af..131263ea4d9 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Los elementos archivados aparecerán aquí y se excluirán de los resultados de búsqueda generales y de sugerencias de autocompletado." }, - "itemWasSentToArchive": { - "message": "El elemento fue archivado" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "El elemento fue desarchivado" - }, - "itemUnarchived": { - "message": "El elemento fue desarchivado" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archivar elemento" @@ -6113,7 +6110,7 @@ "message": "Resize side navigation" }, "whoCanView": { - "message": "Quien puede ver" + "message": "Quién puede ver" }, "specificPeople": { "message": "Personas específicas" diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index e8efd12b1e2..cd78c444c89 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index e7fcd4998e0..3e4382a3d3b 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -3,14 +3,14 @@ "message": "Bitwarden" }, "appLogoLabel": { - "message": "Bitwarden logo" + "message": "Bitwardenen logoa" }, "extName": { "message": "Bitwarden pasahitz kudeatzailea", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information", + "message": "Etxean, lanean edo bidean, Bitwardenek zure pasahitz, giltz orokor edo informazio delikatua erraz gordetzen du", "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { @@ -23,19 +23,19 @@ "message": "Sortu kontua" }, "newToBitwarden": { - "message": "New to Bitwarden?" + "message": "Berria Bitwardenen?" }, "logInWithPasskey": { - "message": "Log in with passkey" + "message": "Sartu giltz orokorrarekin" }, "unlockWithPasskey": { - "message": "Unlock with passkey" + "message": "Ireki giltz orokorrarekin" }, "useSingleSignOn": { - "message": "Use single sign-on" + "message": "Erabili SSO" }, "yourOrganizationRequiresSingleSignOn": { - "message": "Your organization requires single sign-on." + "message": "Zure erakundeak SSO erabiltzera behartzen du." }, "welcomeBack": { "message": "Ongi etorri berriro ere" @@ -71,7 +71,7 @@ "message": "Pasahitz nagusia ahazten baduzu, pista batek pasahitza gogoratzen lagunduko dizu." }, "masterPassHintText": { - "message": "If you forget your password, the password hint can be sent to your email. $CURRENT$/$MAXIMUM$ character maximum.", + "message": "Zure pasahitza ahazten bazaizu, pasahitzaren pista emailez bidal dezakegu. Gehienez $CURRENT$/$MAXIMUM$ karaktere.", "placeholders": { "current": { "content": "$1", @@ -90,7 +90,7 @@ "message": "Pasahitz nagusirako pista (aukerakoa)" }, "passwordStrengthScore": { - "message": "Password strength score $SCORE$", + "message": "Pasahitzaren sendotasun puntuazioa $SCORE$", "placeholders": { "score": { "content": "$1", @@ -99,10 +99,10 @@ } }, "joinOrganization": { - "message": "Join organization" + "message": "Erakundearen kide egin" }, "joinOrganizationName": { - "message": "Join $ORGANIZATIONNAME$", + "message": "$ORGANIZATIONNAME$-ren kide egin", "placeholders": { "organizationName": { "content": "$1", @@ -111,7 +111,7 @@ } }, "finishJoiningThisOrganizationBySettingAMasterPassword": { - "message": "Finish joining this organization by setting a master password." + "message": "Bukatu erakunde honen kide egitea pasahitz nagusi bat ezarriz." }, "tab": { "message": "Fitxak" @@ -138,7 +138,7 @@ "message": "Kopiatu pasahitza" }, "copyPassphrase": { - "message": "Copy passphrase" + "message": "Kopiatu esaldi-gakoa" }, "copyNote": { "message": "Kopiatu oharra" @@ -159,28 +159,28 @@ "message": "Izena kopiatu" }, "copyCompany": { - "message": "Copy company" + "message": "Kopiatu enpresa" }, "copySSN": { - "message": "Copy Social Security number" + "message": "Kopiatu segurtasun sozialaren zenbakia" }, "copyPassportNumber": { - "message": "Copy passport number" + "message": "Kopiatu pasaporte zenbakia" }, "copyLicenseNumber": { - "message": "Copy license number" + "message": "Kopiatu lizentzia zenbakia" }, "copyPrivateKey": { - "message": "Copy private key" + "message": "Kopiatu gako pribatua" }, "copyPublicKey": { - "message": "Copy public key" + "message": "Kopiatu gako publikoa" }, "copyFingerprint": { - "message": "Copy fingerprint" + "message": "Kopiatu hatz-marka" }, "copyCustomField": { - "message": "Copy $FIELD$", + "message": "Kopiatu $FIELD$", "placeholders": { "field": { "content": "$1", @@ -189,7 +189,7 @@ } }, "copyWebsite": { - "message": "Copy website" + "message": "Kopiatu webgunea" }, "copyNotes": { "message": "Kopiatu oharrak" @@ -206,7 +206,7 @@ "message": "Auto-betetzea" }, "autoFillLogin": { - "message": "Autofill login" + "message": "Saio-hasiera autobetetzea" }, "autoFillCard": { "message": "Auto-bete txartela" @@ -261,16 +261,16 @@ "message": "Gehitu elementua" }, "accountEmail": { - "message": "Account email" + "message": "Kontuaren e-maila" }, "requestHint": { - "message": "Request hint" + "message": "Argibidea eskatu" }, "requestPasswordHint": { - "message": "Request password hint" + "message": "Pasahitz-laguntza eskatu" }, "enterYourAccountEmailAddressAndYourPasswordHintWillBeSentToYou": { - "message": "Enter your account email address and your password hint will be sent to you" + "message": "Idatzi zure kontuaren e-maila eta pasahitzaren argibidea bidaliko dizugu" }, "getMasterPasswordHint": { "message": "Jaso pasahitz nagusiaren pista" @@ -297,10 +297,10 @@ "message": "Aldatu pasahitz nagusia" }, "continueToWebApp": { - "message": "Continue to web app?" + "message": "Web aplikaziora jarraitu?" }, "continueToWebAppDesc": { - "message": "Explore more features of your Bitwarden account on the web app." + "message": "Esploratu zure Bitwarden kontuaren funtzio gehiago web-aplikazioan." }, "continueToHelpCenter": { "message": "Continue to Help Center?" @@ -332,7 +332,7 @@ "message": "Itxi saioa" }, "aboutBitwarden": { - "message": "About Bitwarden" + "message": "Bitwardeni buruz" }, "about": { "message": "Honi buruz" @@ -398,10 +398,10 @@ } }, "newFolder": { - "message": "New folder" + "message": "Karpeta berria" }, "folderName": { - "message": "Folder name" + "message": "Karpetaren izena" }, "folderHintText": { "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" @@ -440,7 +440,7 @@ "message": "Sinkronizatu" }, "syncNow": { - "message": "Sync now" + "message": "Sinkronizatu orain" }, "lastSync": { "message": "Azken sinkronizazioa:" @@ -456,7 +456,7 @@ "message": "Automatikoki pasahitz sendo eta bakarrak sortzen ditu zure saio-hasieratarako." }, "bitWebVaultApp": { - "message": "Bitwarden web app" + "message": "Bitwarden web aplikazioa" }, "select": { "message": "Hautatu" @@ -489,11 +489,11 @@ "message": "Luzera" }, "include": { - "message": "Include", + "message": "Sartu", "description": "Card header for password generator include block" }, "uppercaseDescription": { - "message": "Include uppercase characters", + "message": "Sartu letra maiuskulak", "description": "Tooltip for the password generator uppercase character checkbox" }, "uppercaseLabel": { @@ -501,7 +501,7 @@ "description": "Label for the password generator uppercase character checkbox" }, "lowercaseDescription": { - "message": "Include lowercase characters", + "message": "Sartu letra minuskulak", "description": "Full description for the password generator lowercase character checkbox" }, "lowercaseLabel": { @@ -509,7 +509,7 @@ "description": "Label for the password generator lowercase character checkbox" }, "numbersDescription": { - "message": "Include numbers", + "message": "Sartu zenbakiak", "description": "Full description for the password generator numbers checkbox" }, "numbersLabel": { @@ -517,7 +517,7 @@ "description": "Label for the password generator numbers checkbox" }, "specialCharactersDescription": { - "message": "Include special characters", + "message": "Sartu karaktere bereziak", "description": "Full description for the password generator special characters checkbox" }, "numWords": { @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" @@ -607,16 +604,16 @@ "message": "Erakutsi" }, "viewAll": { - "message": "View all" + "message": "Ikusi denak" }, "showAll": { - "message": "Show all" + "message": "Dena erakutsi" }, "viewLess": { "message": "View less" }, "viewLogin": { - "message": "View login" + "message": "Ikusi saio-hasiera" }, "noItemsInList": { "message": "Ez dago erakusteko elementurik." @@ -946,16 +943,16 @@ "message": "Saioa amaitu da." }, "logIn": { - "message": "Log in" + "message": "Hasi saioa" }, "logInToBitwarden": { - "message": "Log in to Bitwarden" + "message": "Sartu Bitwardenera" }, "enterTheCodeSentToYourEmail": { - "message": "Enter the code sent to your email" + "message": "Sartu e-mailera bidali dizugun kodea" }, "enterTheCodeFromYourAuthenticatorApp": { - "message": "Enter the code from your authenticator app" + "message": "Sartu zure egiaztapenerako aplikazioko kodea" }, "pressYourYubiKeyToAuthenticate": { "message": "Press your YubiKey to authenticate" @@ -1344,11 +1341,11 @@ "message": "Export from" }, "exportVerb": { - "message": "Export", + "message": "Esportatu", "description": "The verb form of the word Export" }, "exportNoun": { - "message": "Export", + "message": "Esportatu", "description": "The noun form of the word Export" }, "importNoun": { @@ -1768,7 +1765,7 @@ "description": "Represents the message for allowing the user to enable the autofill overlay" }, "autofillSuggestionsSectionTitle": { - "message": "Autofill suggestions" + "message": "Autobetetzeko iradokizunak" }, "autofillSpotlightTitle": { "message": "Easily find autofill suggestions" @@ -2165,7 +2162,7 @@ "description": "Header for edit file send" }, "viewItemHeaderLogin": { - "message": "View Login", + "message": "Ikusi saio-hasiera", "description": "Header for view login item type" }, "viewItemHeaderCard": { @@ -2203,7 +2200,7 @@ "message": "Bildumak" }, "nCollections": { - "message": "$COUNT$ collections", + "message": "$COUNT$ bilduma", "placeholders": { "count": { "content": "$1", @@ -2928,7 +2925,7 @@ } }, "send": { - "message": "Send", + "message": "Bidali", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDetails": { @@ -4019,7 +4016,7 @@ "message": "required" }, "search": { - "message": "Search" + "message": "Bilatu" }, "inputMinLength": { "message": "Input must be at least $COUNT$ characters long.", @@ -4346,7 +4343,7 @@ "message": "Select a folder" }, "selectImportCollection": { - "message": "Select a collection" + "message": "Bilduma bat aukeratu" }, "importTargetHintCollection": { "message": "Select this option if you want the imported file contents moved to a collection" @@ -4525,7 +4522,7 @@ "message": "Try again or look for an email from LastPass to verify it's you." }, "collection": { - "message": "Collection" + "message": "Bilduma" }, "lastPassYubikeyDesc": { "message": "Insert the YubiKey associated with your LastPass account into your computer's USB port, then touch its button." @@ -4686,7 +4683,7 @@ "message": "Passkey removed" }, "autofillSuggestions": { - "message": "Autofill suggestions" + "message": "Autobetetzeko proposamenak" }, "itemSuggestions": { "message": "Suggested items" @@ -4812,7 +4809,7 @@ "message": "No values to copy" }, "assignToCollections": { - "message": "Assign to collections" + "message": "Esleitu bildumetan" }, "copyEmail": { "message": "Copy email" @@ -4904,7 +4901,7 @@ } }, "new": { - "message": "New" + "message": "Berria" }, "removeItem": { "message": "Remove $NAME$", @@ -4942,10 +4939,10 @@ "message": "Additional information" }, "itemHistory": { - "message": "Item history" + "message": "Aldaketen historia" }, "lastEdited": { - "message": "Last edited" + "message": "Azken edizioa" }, "ownerYou": { "message": "Owner: You" @@ -5029,7 +5026,7 @@ "message": "Filters" }, "filterVault": { - "message": "Filter vault" + "message": "Iragazi kutxa gotorra" }, "filterApplied": { "message": "One filter applied" @@ -5066,13 +5063,13 @@ "description": "Used within the inline menu to provide an aria description when users are attempting to fill a card cipher." }, "loginCredentials": { - "message": "Login credentials" + "message": "Saio-hasierako kredentzialak" }, "authenticatorKey": { "message": "Authenticator key" }, "autofillOptions": { - "message": "Autofill options" + "message": "Autobetetzeko aukerak" }, "websiteUri": { "message": "Website (URI)" @@ -5866,7 +5863,7 @@ "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, "generatorNudgeTitle": { - "message": "Quickly create passwords" + "message": "Sortu pasahitzak azkar" }, "generatorNudgeBodyOne": { "message": "Easily create strong and unique passwords by clicking on", @@ -5879,7 +5876,7 @@ "example": "Easily create strong and unique passwords by clicking on {icon} to help you keep your logins secure." }, "generatorNudgeBodyAria": { - "message": "Easily create strong and unique passwords by clicking on the Generate password button to help you keep your logins secure.", + "message": "Sortu erraz pasahitz sendo eta bakarrak Sortu pasahitza botoian klik eginez, zure saio-hasierak seguru mantentzen laguntzeko.", "description": "Aria label for the body content of the generator nudge" }, "aboutThisSetting": { @@ -6107,7 +6104,7 @@ "message": "Items" }, "searchResults": { - "message": "Search results" + "message": "Bilaketaren emaitzak" }, "resizeSideNavigation": { "message": "Resize side navigation" diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index bca4ad20d52..5bb22dc6292 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 2997ed6c128..2f5b1ec4932 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arkistoi kohde" diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 11da450cc0f..abb06f0f19f 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index face33e0087..596315c4d3f 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Les éléments archivés apparaîtront ici et seront exclus des résultats de recherche généraux et des suggestions de remplissage automatique." }, - "itemWasSentToArchive": { - "message": "L'élément a été envoyé à l'archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "L'élément a été désarchivé" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archiver l'élément" diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index 69ef54f78eb..e710a489f9a 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 22939259639..a76cbb711a9 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "פריטים בארכיון יופיעו כאן ויוחרגו מתוצאות חיפוש כללי והצעות למילוי אוטומטי." }, - "itemWasSentToArchive": { - "message": "הפריט נשלח לארכיון" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "הפריט שוחזר מהארכיב" - }, - "itemUnarchived": { - "message": "הפריט הוסר מהארכיון" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "העבר פריט לארכיון" diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 298f0312be7..d30cbd2cc6e 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index d7814a22da0..98fdee3b657 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Arhivirane stavke biti će prikazane ovdje i biti će izuzete iz rezultata općih pretraga i preporuka auto-ispune." }, - "itemWasSentToArchive": { - "message": "Stavka poslana u arhivu" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Stavka vraćena iz arhive" - }, - "itemUnarchived": { - "message": "Stavka vraćena iz arhive" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arhiviraj stavku" diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index ec4b2d405bf..e6765219f15 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -573,15 +573,12 @@ "noItemsInArchiveDesc": { "message": "Az archivált elemek itt jelennek meg és kizárásra kerülnek az általános keresési eredményekből és az automatikus kitöltési javaslatokból." }, - "itemWasSentToArchive": { - "message": "Az elem az archivumba került." + "itemArchiveToast": { + "message": "Az elem archiválásra került." }, - "itemWasUnarchived": { + "itemUnarchivedToast": { "message": "Az elem visszavételre került az archivumból." }, - "itemUnarchived": { - "message": "Az elemek visszavéelre kerültek az archivumból." - }, "archiveItem": { "message": "Elem archiválása" }, diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index f364b2f7540..ccf35569f36 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Butir yang diarsipkan akan muncul di sini dan akan dikecualikan dari hasil pencarian umum dan saran isi otomatis." }, - "itemWasSentToArchive": { - "message": "Butir dikirim ke arsip" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arsipkan butir" diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 9c4ce6a0369..42efa025207 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Gli elementi archiviati compariranno qui e saranno esclusi dai risultati di ricerca e suggerimenti di autoriempimento." }, - "itemWasSentToArchive": { - "message": "Elemento archiviato" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Elemento rimosso dall'archivio" - }, - "itemUnarchived": { - "message": "Elemento rimosso dall'archivio" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archivia elemento" diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index c8a963fc744..915308cec13 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "アーカイブされたアイテムはここに表示され、通常の検索結果および自動入力の候補から除外されます。" }, - "itemWasSentToArchive": { - "message": "アイテムはアーカイブに送信されました" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "アイテムはアーカイブから解除されました" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "アイテムをアーカイブ" diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index cb6129ed2bb..791664e6eec 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index 336e8783b75..c28007c3838 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index e97ce2a95a4..faef7703a66 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 9f570d62abb..b4a04e75e43 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "보관된 항목은 여기에 표시되며 일반 검색 결과 및 자동 완성 제안에서 제외됩니다." }, - "itemWasSentToArchive": { - "message": "항목이 보관함으로 이동되었습니다" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "항목이 보관 해제되었습니다" - }, - "itemUnarchived": { - "message": "항목 보관 해제됨" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "항목 보관" diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index 6e105f044f3..68eb11aa234 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 8c86d7040fe..6eaf545e390 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Šeit parādīsies arhivētie vienumi, un tie netiks iekļauti vispārējās meklēšanas iznākumos un automātiskās aizpildes ieteikumos." }, - "itemWasSentToArchive": { - "message": "Vienums tika ievietots arhīvā" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Vienums tika izņemts no arhīva" - }, - "itemUnarchived": { - "message": "Vienums tika izņemts no arhīva" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arhivēt vienumu" diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index 61f69ffe22b..db48220ffbb 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index 5cc614c5df7..abf2f7db968 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index 336e8783b75..c28007c3838 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index ce6c8d5a7d4..4689cb23b7a 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index 336e8783b75..c28007c3838 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 44522727429..044b3cfaa64 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Gearchiveerde items verschijnen hier en worden uitgesloten van algemene zoekresultaten en automatisch invulsuggesties." }, - "itemWasSentToArchive": { - "message": "Item naar archief verzonden" + "itemArchiveToast": { + "message": "Item gearchiveerd" }, - "itemWasUnarchived": { - "message": "Item uit het archief gehaald" - }, - "itemUnarchived": { - "message": "Item uit het archief gehaald" + "itemUnarchivedToast": { + "message": "Item gedearchiveerd" }, "archiveItem": { "message": "Item archiveren" diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index 336e8783b75..c28007c3838 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index 336e8783b75..c28007c3838 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 44c7d9e6d47..44c7b5fb6dd 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -440,7 +440,7 @@ "message": "Synchronizacja" }, "syncNow": { - "message": "Sync now" + "message": "Synchronizuj teraz" }, "lastSync": { "message": "Ostatnia synchronizacja:" @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Zarchiwizowane elementy pojawią się tutaj i zostaną wykluczone z wyników wyszukiwania i sugestii autouzupełniania." }, - "itemWasSentToArchive": { - "message": "Element został przeniesiony do archiwum" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Element został usunięty z archiwum" - }, - "itemUnarchived": { - "message": "Element został usunięty z archiwum" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archiwizuj element" @@ -6128,7 +6125,7 @@ "message": "user@bitwarden.com , user@acme.com" }, "downloadBitwardenApps": { - "message": "Download Bitwarden apps" + "message": "Pobierz aplikacje Bitwarden" }, "emailProtected": { "message": "Email protected" diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index 5ad95b480db..679173205b1 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Os itens arquivados aparecerão aqui e serão excluídos dos resultados gerais de busca e das sugestões de preenchimento automático." }, - "itemWasSentToArchive": { - "message": "O item foi enviado para o arquivo" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "O item foi desarquivado" - }, - "itemUnarchived": { - "message": "O item foi desarquivado" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arquivar item" diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 604bf054707..9094e04094d 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Os itens arquivados aparecerão aqui e serão excluídos dos resultados gerais da pesquisa e das sugestões de preenchimento automático." }, - "itemWasSentToArchive": { - "message": "O item foi movido para o arquivo" + "itemArchiveToast": { + "message": "Item arquivado" }, - "itemWasUnarchived": { - "message": "O item foi desarquivado" - }, - "itemUnarchived": { - "message": "O item foi desarquivado" + "itemUnarchivedToast": { + "message": "Item desarquivado" }, "archiveItem": { "message": "Arquivar item" diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index 12706943e83..47f7ae9cae3 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index dab9a22f03a..d1fb3de89a6 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Архивированные элементы появятся здесь и будут исключены из общих результатов поиска и предложений автозаполнения." }, - "itemWasSentToArchive": { - "message": "Элемент был отправлен в архив" + "itemArchiveToast": { + "message": "Элемент архивирован" }, - "itemWasUnarchived": { - "message": "Элемент был разархивирован" - }, - "itemUnarchived": { - "message": "Элемент был разархивирован" + "itemUnarchivedToast": { + "message": "Элемент разархивирован" }, "archiveItem": { "message": "Архивировать элемент" diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index d228cdb512a..e70c620eaf8 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index db7efcd8b9f..e1886098a31 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -573,13 +573,10 @@ "noItemsInArchiveDesc": { "message": "Tu sa zobrazia archivované položky, ktoré budú vylúčené zo všeobecného vyhľadávania a z návrhov automatického vypĺňania." }, - "itemWasSentToArchive": { + "itemArchiveToast": { "message": "Položka bola archivovaná" }, - "itemWasUnarchived": { - "message": "Položka bola odobraná z archívu" - }, - "itemUnarchived": { + "itemUnarchivedToast": { "message": "Položka bola odobraná z archívu" }, "archiveItem": { diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 07ee84ab810..100a04a3012 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 0ad71788514..e91e003c8e0 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Архивиране ставке ће се овде појавити и бити искључени из општих резултата претраге и сугестија о ауто-пуњењу." }, - "itemWasSentToArchive": { - "message": "Ставка је послата у архиву" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Ставка враћена из архиве" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Архивирај ставку" diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index 08cec673d27..484817b0210 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Arkiverade objekt kommer att visas här och kommer att uteslutas från allmänna sökresultat och förslag för autofyll." }, - "itemWasSentToArchive": { - "message": "Objektet skickades till arkivet" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Objektet har avarkiverats" - }, - "itemUnarchived": { - "message": "Objektet har avarkiverats" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arkivera objekt" diff --git a/apps/browser/src/_locales/ta/messages.json b/apps/browser/src/_locales/ta/messages.json index 374c0968d2c..3e76c0ab0d1 100644 --- a/apps/browser/src/_locales/ta/messages.json +++ b/apps/browser/src/_locales/ta/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "காப்பகப்படுத்தப்பட்ட உருப்படிகள் இங்கே தோன்றும், மேலும் அவை பொதுவான தேடல் முடிவுகள் மற்றும் தானியங்குநிரப்பு பரிந்துரைகளிலிருந்து விலக்கப்படும்." }, - "itemWasSentToArchive": { - "message": "ஆவணம் காப்பகத்திற்கு அனுப்பப்பட்டது" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "காப்பகம் மீட்டெடுக்கப்பட்டது" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "உருப்படியைக் காப்பகப்படுத்து" diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index 336e8783b75..c28007c3838 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 5af1c742f45..5ec728189a8 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "รายการที่จัดเก็บถาวรจะปรากฏที่นี่ และจะไม่ถูกรวมในผลการค้นหาทั่วไปหรือคำแนะนำการป้อนอัตโนมัติ" }, - "itemWasSentToArchive": { - "message": "ย้ายรายการไปที่จัดเก็บถาวรแล้ว" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "เลิกจัดเก็บถาวรรายการแล้ว" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "จัดเก็บรายการถาวร" diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index 33f600fb7a7..7d5b31a9aba 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -573,13 +573,10 @@ "noItemsInArchiveDesc": { "message": "Arşivlenmiş kayıtlar burada görünecek ve genel arama sonuçlarından ile otomatik doldurma önerilerinden hariç tutulacaktır." }, - "itemWasSentToArchive": { - "message": "Kayıt arşive gönderildi" + "itemArchiveToast": { + "message": "Kayıt arşivlendi" }, - "itemWasUnarchived": { - "message": "Kayıt arşivden çıkarıldı" - }, - "itemUnarchived": { + "itemUnarchivedToast": { "message": "Kayıt arşivden çıkarıldı" }, "archiveItem": { diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index b703cfeefce..49a0c9de25b 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -573,13 +573,10 @@ "noItemsInArchiveDesc": { "message": "Архівовані записи з'являтимуться тут і будуть виключені з результатів звичайного пошуку та пропозицій автозаповнення." }, - "itemWasSentToArchive": { + "itemArchiveToast": { "message": "Запис архівовано" }, - "itemWasUnarchived": { - "message": "Запис розархівовано" - }, - "itemUnarchived": { + "itemUnarchivedToast": { "message": "Запис розархівовано" }, "archiveItem": { @@ -5964,7 +5961,7 @@ "message": "Номер картки" }, "errorCannotDecrypt": { - "message": "Error: Cannot decrypt" + "message": "Помилка: неможливо розшифрувати" }, "removeMasterPasswordForOrgUserKeyConnector": { "message": "Ваша організація більше не використовує головні паролі для входу в Bitwarden. Щоб продовжити, підтвердіть організацію та домен." @@ -6128,7 +6125,7 @@ "message": "user@bitwarden.com , user@acme.com" }, "downloadBitwardenApps": { - "message": "Download Bitwarden apps" + "message": "Завантажити програми Bitwarden" }, "emailProtected": { "message": "Е-пошту захищено" diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index 0082ee1ece7..4f1165835cc 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "Các mục đã lưu trữ sẽ hiển thị ở đây và sẽ bị loại khỏi kết quả tìm kiếm và gợi ý tự động điền." }, - "itemWasSentToArchive": { - "message": "Mục đã được chuyển vào kho lưu trữ" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Mục đã được bỏ lưu trữ" - }, - "itemUnarchived": { - "message": "Mục đã được bỏ lưu trữ" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Lưu trữ mục" diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index 860a8c09f27..c9dd30ab08e 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "已归档的项目将显示在此处,并将被排除在一般搜索结果和自动填充建议之外。" }, - "itemWasSentToArchive": { - "message": "项目已发送到归档" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "项目已取消归档" - }, - "itemUnarchived": { - "message": "项目已取消归档" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "归档项目" diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 3f387d935d4..8da1b2ad08f 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -228,7 +228,7 @@ "message": "複製自訂欄位名稱" }, "noMatchingLogins": { - "message": "沒有符合的登入資料" + "message": "沒有相符的登入項目" }, "noCards": { "message": "沒有付款卡" @@ -252,7 +252,7 @@ "message": "登入您的密碼庫" }, "autoFillInfo": { - "message": "沒有可以在目前瀏覽器分頁自動填入的登入資訊。" + "message": "目前瀏覽器分頁沒有可自動填入的登入項目。" }, "addLogin": { "message": "新增登入資料" @@ -453,10 +453,10 @@ "description": "Short for 'credential generator'." }, "passGenInfo": { - "message": "為您的登入資料自動產生高強度且唯一的密碼。" + "message": "為您的登入項目自動產生高強度且唯一的密碼。" }, "bitWebVaultApp": { - "message": "Bitwarden 網頁應用程式" + "message": "Bitwarden Web 應用程式" }, "select": { "message": "選擇" @@ -468,16 +468,16 @@ "message": "產生密碼短語" }, "passwordGenerated": { - "message": "已產生密碼" + "message": "密碼已產生" }, "passphraseGenerated": { - "message": "已產生密碼" + "message": "密碼短語已產生" }, "usernameGenerated": { - "message": "已產生使用者名稱" + "message": "使用者名稱已產生" }, "emailGenerated": { - "message": "已產生電子郵件" + "message": "電子郵件已產生" }, "regeneratePassword": { "message": "重新產生密碼" @@ -573,14 +573,11 @@ "noItemsInArchiveDesc": { "message": "封存的項目會顯示在此處,且不會出現在一般搜尋結果或自動填入建議中。" }, - "itemWasSentToArchive": { - "message": "項目已移至封存" + "itemArchiveToast": { + "message": "項目已封存" }, - "itemWasUnarchived": { - "message": "已取消封存項目" - }, - "itemUnarchived": { - "message": "項目取消封存" + "itemUnarchivedToast": { + "message": "項目已取消封存" }, "archiveItem": { "message": "封存項目" @@ -598,7 +595,7 @@ "message": "需要進階版會員才能使用封存功能。" }, "itemRestored": { - "message": "已還原項目" + "message": "項目已還原" }, "edit": { "message": "編輯" @@ -1215,7 +1212,7 @@ "description": "Button text for saving login details as a new entry." }, "updateLoginAction": { - "message": "更新登入資料", + "message": "更新登入項目", "description": "Button text for updating an existing login entry." }, "unlockToSave": { @@ -1223,7 +1220,7 @@ "description": "User prompt to take action in order to save the login they just entered." }, "saveLogin": { - "message": "儲存登入資料", + "message": "儲存登入項目", "description": "Prompt asking the user if they want to save their login details." }, "updateLogin": { @@ -1231,7 +1228,7 @@ "description": "Prompt asking the user if they want to update an existing login entry." }, "loginSaveSuccess": { - "message": "登入資訊已儲存", + "message": "登入項目已儲存", "description": "Message displayed when login details are successfully saved." }, "loginUpdateSuccess": { @@ -1305,7 +1302,7 @@ "message": "解鎖" }, "additionalOptions": { - "message": "額外選項" + "message": "其他選項" }, "enableContextMenuItem": { "message": "顯示內容選單選項" @@ -1567,7 +1564,7 @@ "message": "提供密碼健全性、帳戶健康狀態及資料外洩報告,確保您的密碼庫安全。" }, "ppremiumSignUpTotp": { - "message": "為密碼庫中的登入資料產生 TOTP 驗證碼(2FA)。" + "message": "為密碼庫中的登入項目產生 TOTP 驗證碼(2FA)。" }, "ppremiumSignUpSupport": { "message": "優先客戶支援。" @@ -1801,7 +1798,7 @@ "message": "Bitwarden 如何保護您的資料免於網路釣魚攻擊?" }, "currentWebsite": { - "message": "目網站" + "message": "目前網站" }, "autofillAndAddWebsite": { "message": "自動填充並新增此網站" @@ -2091,7 +2088,7 @@ "message": "登入資料" }, "typeLogins": { - "message": "登入資料" + "message": "登入項目" }, "typeSecureNote": { "message": "安全筆記" @@ -2227,7 +2224,7 @@ "message": "身分" }, "logins": { - "message": "登入資料" + "message": "登入項目" }, "secureNotes": { "message": "安全筆記" @@ -2513,7 +2510,7 @@ "message": "項目已自動填入並且已儲存統一資源標識符(URI)" }, "autoFillSuccess": { - "message": "項目已自動填入 " + "message": "項目已自動填入" }, "insecurePageWarning": { "message": "警告:此為不安全的 HTTP 頁面,您送出的任何資訊都可能被他人查看並修改。此登入資料原本儲存在安全的(HTTPS)頁面上。" @@ -2773,10 +2770,10 @@ } }, "atRiskPassword": { - "message": "具有風險的密碼" + "message": "有風險的密碼" }, "atRiskPasswords": { - "message": "具有風險的密碼" + "message": "有風險的密碼" }, "atRiskPasswordDescSingleOrg": { "message": "$ORGANIZATION$ 要求你變更一組有風險的密碼。", @@ -2848,7 +2845,7 @@ "message": "更新你的設定,以便能快速自動填入密碼並產生新密碼" }, "reviewAtRiskLogins": { - "message": "檢視有風險的登入資訊" + "message": "檢視有風險的登入項目" }, "reviewAtRiskPasswords": { "message": "檢視有風險的密碼" @@ -5749,7 +5746,7 @@ "message": "設定生物辨識解鎖及自動填入,不需要輸入任何字元就可以登入。" }, "secureUser": { - "message": "升級您的登入體驗" + "message": "讓您的登入項目更升級" }, "secureUserBody": { "message": "使用密碼產生器來建立及儲存高強度、唯一的密碼,來保護您所有的帳號。" @@ -5964,7 +5961,7 @@ "message": "付款卡號碼" }, "errorCannotDecrypt": { - "message": "Error: Cannot decrypt" + "message": "錯誤:無法解密" }, "removeMasterPasswordForOrgUserKeyConnector": { "message": "您的組織已不再使用主密碼登入 Bitwarden。若要繼續,請驗證組織與網域。" From eb4b5721a6c64256342685f791c72c4ac89cde28 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 10:36:54 +0000 Subject: [PATCH 17/23] Autosync the updated translations (#19007) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/af/messages.json | 8 ++-- apps/desktop/src/locales/ar/messages.json | 8 ++-- apps/desktop/src/locales/az/messages.json | 8 ++-- apps/desktop/src/locales/be/messages.json | 8 ++-- apps/desktop/src/locales/bg/messages.json | 8 ++-- apps/desktop/src/locales/bn/messages.json | 8 ++-- apps/desktop/src/locales/bs/messages.json | 8 ++-- apps/desktop/src/locales/ca/messages.json | 8 ++-- apps/desktop/src/locales/cs/messages.json | 6 +-- apps/desktop/src/locales/cy/messages.json | 8 ++-- apps/desktop/src/locales/da/messages.json | 8 ++-- apps/desktop/src/locales/de/messages.json | 10 ++--- apps/desktop/src/locales/el/messages.json | 8 ++-- apps/desktop/src/locales/en_GB/messages.json | 8 ++-- apps/desktop/src/locales/en_IN/messages.json | 8 ++-- apps/desktop/src/locales/eo/messages.json | 8 ++-- apps/desktop/src/locales/es/messages.json | 46 ++++++++++---------- apps/desktop/src/locales/et/messages.json | 8 ++-- apps/desktop/src/locales/eu/messages.json | 8 ++-- apps/desktop/src/locales/fa/messages.json | 8 ++-- apps/desktop/src/locales/fi/messages.json | 8 ++-- apps/desktop/src/locales/fil/messages.json | 8 ++-- apps/desktop/src/locales/fr/messages.json | 8 ++-- apps/desktop/src/locales/gl/messages.json | 8 ++-- apps/desktop/src/locales/he/messages.json | 8 ++-- apps/desktop/src/locales/hi/messages.json | 8 ++-- apps/desktop/src/locales/hr/messages.json | 8 ++-- apps/desktop/src/locales/hu/messages.json | 8 ++-- apps/desktop/src/locales/id/messages.json | 8 ++-- apps/desktop/src/locales/it/messages.json | 8 ++-- apps/desktop/src/locales/ja/messages.json | 8 ++-- apps/desktop/src/locales/ka/messages.json | 8 ++-- apps/desktop/src/locales/km/messages.json | 8 ++-- apps/desktop/src/locales/kn/messages.json | 8 ++-- apps/desktop/src/locales/ko/messages.json | 8 ++-- apps/desktop/src/locales/lt/messages.json | 8 ++-- apps/desktop/src/locales/lv/messages.json | 8 ++-- apps/desktop/src/locales/me/messages.json | 8 ++-- apps/desktop/src/locales/ml/messages.json | 8 ++-- apps/desktop/src/locales/mr/messages.json | 8 ++-- apps/desktop/src/locales/my/messages.json | 8 ++-- apps/desktop/src/locales/nb/messages.json | 8 ++-- apps/desktop/src/locales/ne/messages.json | 8 ++-- apps/desktop/src/locales/nl/messages.json | 8 ++-- apps/desktop/src/locales/nn/messages.json | 8 ++-- apps/desktop/src/locales/or/messages.json | 8 ++-- apps/desktop/src/locales/pl/messages.json | 10 ++--- apps/desktop/src/locales/pt_BR/messages.json | 8 ++-- apps/desktop/src/locales/pt_PT/messages.json | 8 ++-- apps/desktop/src/locales/ro/messages.json | 8 ++-- apps/desktop/src/locales/ru/messages.json | 8 ++-- apps/desktop/src/locales/si/messages.json | 8 ++-- apps/desktop/src/locales/sk/messages.json | 4 +- apps/desktop/src/locales/sl/messages.json | 8 ++-- apps/desktop/src/locales/sr/messages.json | 8 ++-- apps/desktop/src/locales/sv/messages.json | 8 ++-- apps/desktop/src/locales/ta/messages.json | 8 ++-- apps/desktop/src/locales/te/messages.json | 8 ++-- apps/desktop/src/locales/th/messages.json | 8 ++-- apps/desktop/src/locales/tr/messages.json | 6 +-- apps/desktop/src/locales/uk/messages.json | 8 ++-- apps/desktop/src/locales/vi/messages.json | 8 ++-- apps/desktop/src/locales/zh_CN/messages.json | 8 ++-- apps/desktop/src/locales/zh_TW/messages.json | 8 ++-- 64 files changed, 273 insertions(+), 273 deletions(-) diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index ef221f96878..c0824c61d03 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index bcac0529a8c..3e668c327b0 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index f94ff2417cf..4e5d414eb1c 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -4387,10 +4387,10 @@ "noItemsInArchiveDesc": { "message": "Arxivlənmiş elementlər burada görünəcək, ümumi axtarış nəticələrindən və avto-doldurma təkliflərindən xaric ediləcək." }, - "itemWasSentToArchive": { - "message": "Element arxivə göndərildi" + "itemArchiveToast": { + "message": "Element arxivləndi" }, - "itemWasUnarchived": { + "itemUnarchivedToast": { "message": "Element arxivdən çıxarıldı" }, "archiveItem": { @@ -4487,7 +4487,7 @@ "message": "Vaxt bitmə əməliyyatı" }, "errorCannotDecrypt": { - "message": "Error: Cannot decrypt" + "message": "Xəta: Şifrəsi açıla bilmir" }, "sessionTimeoutHeader": { "message": "Sessiya vaxt bitməsi" diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index 3467fe20ae8..f2f9d0a736d 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index cab21191e37..ea0355ad7f6 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Архивираните елементи ще се показват тук и ще бъдат изключени от общите резултати при търсене и от предложенията за автоматично попълване." }, - "itemWasSentToArchive": { - "message": "Елементът беше преместен в архива" + "itemArchiveToast": { + "message": "Елементът е преместен в архива" }, - "itemWasUnarchived": { - "message": "Елементът беше изваден от архива" + "itemUnarchivedToast": { + "message": "Елементът е изваден от архива" }, "archiveItem": { "message": "Архивиране на елемента" diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index 544d88a72a6..6a211c93052 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index 289554a237f..4ca3aa8ffc2 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index 7b8d32a798c..3b8562814fd 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index 478343b7e7d..75136c41831 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -4387,10 +4387,10 @@ "noItemsInArchiveDesc": { "message": "Zde se zobrazí archivované položky a budou vyloučeny z obecných výsledků vyhledávání a návrhů automatického vyplňování." }, - "itemWasSentToArchive": { - "message": "Položka byla přesunuta do archivu" + "itemArchiveToast": { + "message": "Položka archivována" }, - "itemWasUnarchived": { + "itemUnarchivedToast": { "message": "Položka byla odebrána z archivu" }, "archiveItem": { diff --git a/apps/desktop/src/locales/cy/messages.json b/apps/desktop/src/locales/cy/messages.json index 4feb0181431..46df0aca8c5 100644 --- a/apps/desktop/src/locales/cy/messages.json +++ b/apps/desktop/src/locales/cy/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index bd6a6f4379a..f6abcd51740 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index 205c8e95435..a2c346896ac 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archivierte Einträge werden hier angezeigt und von allgemeinen Suchergebnissen sowie Auto-Ausfüllen-Vorschlägen ausgeschlossen." }, - "itemWasSentToArchive": { - "message": "Eintrag wurde archiviert" + "itemArchiveToast": { + "message": "Eintrag archiviert" }, - "itemWasUnarchived": { - "message": "Eintrag wird nicht mehr archiviert" + "itemUnarchivedToast": { + "message": "Eintrag nicht mehr archiviert" }, "archiveItem": { "message": "Eintrag archivieren" @@ -4487,7 +4487,7 @@ "message": "Timeout-Aktion" }, "errorCannotDecrypt": { - "message": "Error: Cannot decrypt" + "message": "Fehler: Entschlüsselung nicht möglich" }, "sessionTimeoutHeader": { "message": "Sitzungs-Timeout" diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 97371668dca..624560f5888 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index 22b482ed04d..aaf1e12955c 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index 42a63ff0db1..1dca7070bfc 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index ae37e15d84c..cefd462e99f 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index d6210f940b5..d9fb17907aa 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -773,7 +773,7 @@ "message": "Añadir adjunto" }, "itemsTransferred": { - "message": "Items transferred" + "message": "Elementos transferidos" }, "fixEncryption": { "message": "Corregir cifrado" @@ -2089,7 +2089,7 @@ "message": "Elemento eliminado de forma permanente" }, "archivedItemRestored": { - "message": "Archived item restored" + "message": "Elemento archivado restaurado" }, "restoredItem": { "message": "Elemento restaurado" @@ -4009,7 +4009,7 @@ "message": "No, no lo tengo" }, "newDeviceVerificationNoticePageOneEmailAccessYes": { - "message": "Yes, I can reliably access my email" + "message": "Sí, puedo acceder a mi correo electrónico de forma fiable" }, "turnOnTwoStepLogin": { "message": "Turn on two-step login" @@ -4075,10 +4075,10 @@ "message": "This login is at-risk and missing a website. Add a website and change the password for stronger security." }, "vulnerablePassword": { - "message": "Vulnerable password." + "message": "Contraseña vulnerable." }, "changeNow": { - "message": "Change now" + "message": "Cambiar ahora" }, "missingWebsite": { "message": "Missing website" @@ -4109,7 +4109,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsTitleNoSearchResults": { - "message": "No search results returned" + "message": "Ningún resultado de búsqueda devuelto" }, "sendsBodyNoItems": { "message": "Comparte archivos y datos de forma segura con cualquiera, en cualquier plataforma. Tu información permanecerá encriptada de extremo a extremo, limitando su exposición.", @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Los elementos archivados aparecerán aquí y se excluirán de los resultados de búsqueda generales y de sugerencias de autocompletado." }, - "itemWasSentToArchive": { - "message": "El elemento fue archivado" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "El elemento fue desarchivado" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archivar elemento" @@ -4403,7 +4403,7 @@ "message": "Desarchivar y guardar" }, "restartPremium": { - "message": "Restart Premium" + "message": "Reiniciar Premium" }, "premiumSubscriptionEnded": { "message": "Tu suscripción Premium ha terminado" @@ -4537,10 +4537,10 @@ "message": "Set an unlock method to change your timeout action" }, "upgrade": { - "message": "Upgrade" + "message": "Actualizar" }, "leaveConfirmationDialogTitle": { - "message": "Are you sure you want to leave?" + "message": "¿Estás seguro de que quieres salir?" }, "leaveConfirmationDialogContentOne": { "message": "By declining, your personal items will stay in your account, but you'll lose access to shared items and organization features." @@ -4558,10 +4558,10 @@ } }, "howToManageMyVault": { - "message": "How do I manage my vault?" + "message": "¿Cómo gestiono mi caja fuerte?" }, "transferItemsToOrganizationTitle": { - "message": "Transfer items to $ORGANIZATION$", + "message": "Transferir elementos a $ORGANIZATION$", "placeholders": { "organization": { "content": "$1", @@ -4579,13 +4579,13 @@ } }, "acceptTransfer": { - "message": "Accept transfer" + "message": "Aceptar transferencia" }, "declineAndLeave": { - "message": "Decline and leave" + "message": "Rechazar y salir" }, "whyAmISeeingThis": { - "message": "Why am I seeing this?" + "message": "¿Por qué estoy viendo esto?" }, "sendPasswordHelperText": { "message": "Individuals will need to enter the password to view this Send", @@ -4595,25 +4595,25 @@ "message": "Email protected" }, "emails": { - "message": "Emails" + "message": "Correos electrónicos" }, "noAuth": { - "message": "Anyone with the link" + "message": "Cualquiera con el enlace" }, "anyOneWithPassword": { "message": "Anyone with a password set by you" }, "whoCanView": { - "message": "Who can view" + "message": "Quién puede ver" }, "specificPeople": { - "message": "Specific people" + "message": "Personas específicas" }, "emailVerificationDesc": { "message": "After sharing this Send link, individuals will need to verify their email with a code to view this Send." }, "enterMultipleEmailsSeparatedByComma": { - "message": "Enter multiple emails by separating with a comma." + "message": "Introduce varios correos electrónicos separándolos con una coma." }, "emailPlaceholder": { "message": "user@bitwarden.com , user@acme.com" diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index 8c9476cc69e..ba930db8961 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index 75c33286fb7..e03da9ef685 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index 4136edbde06..a443cc8c2e7 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "آیتم‌های بایگانی‌شده در اینجا نمایش داده می‌شوند و از نتایج جستجوی عمومی و پیشنهاد ها پر کردن خودکار حذف خواهند شد." }, - "itemWasSentToArchive": { - "message": "آیتم به بایگانی فرستاده شد" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "آیتم از بایگانی خارج شد" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "بایگانی آیتم" diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index b04b741bd3b..c7b51def9b2 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index c503efc39f9..5835821f526 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index f04807aaeb9..e8d07e28d2d 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Les éléments archivés apparaîtront ici et seront exclus des résultats de recherche généraux et des suggestions de remplissage automatique." }, - "itemWasSentToArchive": { - "message": "L'élément a été envoyé à l'archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "L'élément a été désarchivé" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archiver l'élément" diff --git a/apps/desktop/src/locales/gl/messages.json b/apps/desktop/src/locales/gl/messages.json index 76904276732..6d0922bd680 100644 --- a/apps/desktop/src/locales/gl/messages.json +++ b/apps/desktop/src/locales/gl/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index dbb2533e03e..763401ac6fe 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "פריטים בארכיון יופיעו כאן ויוחרגו מתוצאות חיפוש כללי והצעות למילוי אוטומטי." }, - "itemWasSentToArchive": { - "message": "הפריט נשלח לארכיון" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "הפריט הוסר מהארכיון" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "העבר פריט לארכיון" diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index 1bfc0674ffe..33b69ac1519 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index 5ef663ab52b..2dc081fa3c7 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Arhivirane stavke biti će prikazane ovdje i biti će izuzete iz rezultata općih pretraga i preporuka auto-ispune." }, - "itemWasSentToArchive": { - "message": "Stavka poslana u arhivu" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Stavka vraćena iz arhive" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arhiviraj stavku" diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index 5440b53e93d..3ec097c2a7a 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Az archivált elemek itt jelennek meg és kizárásra kerülnek az általános keresési eredményekből és az automatikus kitöltési javaslatokból." }, - "itemWasSentToArchive": { - "message": "Az elem az archivumba került." + "itemArchiveToast": { + "message": "Az elem archiválásra került." }, - "itemWasUnarchived": { - "message": "Az elem visszavéelre került az archivumból." + "itemUnarchivedToast": { + "message": "Az elem visszavételre került az archivumból." }, "archiveItem": { "message": "Elem archiválása" diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index f4de0deff33..7648f4bb99b 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index 9cd4783407d..eb2ade245a0 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Gli elementi archiviati appariranno qui e saranno esclusi dai risultati di ricerca e dal riempimento automatico." }, - "itemWasSentToArchive": { - "message": "Elemento archiviato" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Elemento estratto dall'archivio" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archivia elemento" diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index 1d46532a980..a9b05f728d8 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index 4618fd024a9..68bba7fcb27 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index 76904276732..6d0922bd680 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index 3bb7f513701..3c6aced3a73 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index 70ffd234941..8932f0efb48 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/lt/messages.json b/apps/desktop/src/locales/lt/messages.json index f703b1f5d53..a19856a776e 100644 --- a/apps/desktop/src/locales/lt/messages.json +++ b/apps/desktop/src/locales/lt/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index e82a4b91487..8a863256ed1 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Šeit parādīsies arhivētie vienumi, un tie netiks iekļauti vispārējās meklēšanas iznākumos un automātiskās aizpildes ieteikumos." }, - "itemWasSentToArchive": { - "message": "Vienums tika ievietots arhīvā" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Vienums tika izņemts no arhīva" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arhivēt vienumu" diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index 25bb0cbc816..773a596a10d 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index 43e0dc85fb0..3bddc3baa5b 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/mr/messages.json b/apps/desktop/src/locales/mr/messages.json index 76904276732..6d0922bd680 100644 --- a/apps/desktop/src/locales/mr/messages.json +++ b/apps/desktop/src/locales/mr/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/my/messages.json b/apps/desktop/src/locales/my/messages.json index ddc8bef0241..22f4a30329a 100644 --- a/apps/desktop/src/locales/my/messages.json +++ b/apps/desktop/src/locales/my/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index 792c95eb1ec..b2b1631fe04 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/ne/messages.json b/apps/desktop/src/locales/ne/messages.json index 89c3d3ba231..b9eba55d8bd 100644 --- a/apps/desktop/src/locales/ne/messages.json +++ b/apps/desktop/src/locales/ne/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index e4b1d6d8abc..306bf31efe2 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Gearchiveerde items verschijnen hier en worden uitgesloten van algemene zoekresultaten en automatisch invulsuggesties." }, - "itemWasSentToArchive": { - "message": "Item naar archief verzonden" + "itemArchiveToast": { + "message": "Item gearchiveerd" }, - "itemWasUnarchived": { - "message": "Item uit het archief gehaald" + "itemUnarchivedToast": { + "message": "Item gedearchiveerd" }, "archiveItem": { "message": "Item archiveren" diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index 850696f8fcf..dc62d73a236 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/or/messages.json b/apps/desktop/src/locales/or/messages.json index b63a970e9c2..e8ea506a873 100644 --- a/apps/desktop/src/locales/or/messages.json +++ b/apps/desktop/src/locales/or/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index e2d9fbce4a2..0cee8d6683d 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Zarchiwizowane elementy pojawią się tutaj i zostaną wykluczone z wyników wyszukiwania i sugestii autouzupełniania." }, - "itemWasSentToArchive": { - "message": "Element został przeniesiony do archiwum" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Element został usunięty z archiwum" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archiwizuj element" @@ -4487,7 +4487,7 @@ "message": "Timeout action" }, "errorCannotDecrypt": { - "message": "Error: Cannot decrypt" + "message": "Błąd: Nie można odszyfrować" }, "sessionTimeoutHeader": { "message": "Session timeout" diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index 3a055bdb03d..817e9de0c50 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Os itens arquivados aparecerão aqui e serão excluídos dos resultados gerais de busca e das sugestões de preenchimento automático." }, - "itemWasSentToArchive": { - "message": "O item foi enviado para o arquivo" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "O item foi desarquivado" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arquivar item" diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index bb99678bde6..3076291a4a3 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Os itens arquivados aparecerão aqui e serão excluídos dos resultados gerais da pesquisa e das sugestões de preenchimento automático." }, - "itemWasSentToArchive": { - "message": "O item foi movido para o arquivo" + "itemArchiveToast": { + "message": "Item arquivado" }, - "itemWasUnarchived": { - "message": "O item foi desarquivado" + "itemUnarchivedToast": { + "message": "Item desarquivado" }, "archiveItem": { "message": "Arquivar item" diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index 6b51cb9fecd..b8fc25b4105 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index 389f4b37dfd..089e815fefe 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Архивированные элементы появятся здесь и будут исключены из общих результатов поиска и предложений автозаполнения." }, - "itemWasSentToArchive": { - "message": "Элемент был отправлен в архив" + "itemArchiveToast": { + "message": "Элемент архивирован" }, - "itemWasUnarchived": { - "message": "Элемент был разархивирован" + "itemUnarchivedToast": { + "message": "Элемент разархивирован" }, "archiveItem": { "message": "Архивировать элемент" diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index 9e8a727ad5d..a1a84b8ba15 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index 471984785d8..2876361bbf0 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -4387,10 +4387,10 @@ "noItemsInArchiveDesc": { "message": "Tu sa zobrazia archivované položky, ktoré budú vylúčené zo všeobecného vyhľadávania a z návrhov automatického vypĺňania." }, - "itemWasSentToArchive": { + "itemArchiveToast": { "message": "Položka bola archivovaná" }, - "itemWasUnarchived": { + "itemUnarchivedToast": { "message": "Položka bola odobraná z archívu" }, "archiveItem": { diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index 23d9f18fadb..82e0a20b29e 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 1a68810bca3..633d3123242 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Архивиране ставке ће се овде појавити и бити искључени из општих резултата претраге и сугестија о ауто-пуњењу." }, - "itemWasSentToArchive": { - "message": "Ставка је послата у архиву" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Ставка враћена из архиве" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Архивирај ставку" diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index 1dd66c409c0..ed9e62e8319 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Arkiverade objekt kommer att visas här och kommer att uteslutas från allmänna sökresultat och förslag för autofyll." }, - "itemWasSentToArchive": { - "message": "Objektet skickades till arkivet" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Objektet har avarkiverats" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Arkivera objekt" diff --git a/apps/desktop/src/locales/ta/messages.json b/apps/desktop/src/locales/ta/messages.json index 3a7fc795668..53e155874f6 100644 --- a/apps/desktop/src/locales/ta/messages.json +++ b/apps/desktop/src/locales/ta/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/te/messages.json b/apps/desktop/src/locales/te/messages.json index 76904276732..6d0922bd680 100644 --- a/apps/desktop/src/locales/te/messages.json +++ b/apps/desktop/src/locales/te/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index bcff8d0849e..b7117a7ccad 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Archive item" diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index 936a68516bd..96bb11c7a35 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -4387,10 +4387,10 @@ "noItemsInArchiveDesc": { "message": "Arşivlenmiş kayıtlar burada görünecek ve genel arama sonuçları ile otomatik doldurma önerilerinden hariç tutulacaktır." }, - "itemWasSentToArchive": { - "message": "Kayıt arşive gönderildi" + "itemArchiveToast": { + "message": "Kayıt arşivlendi" }, - "itemWasUnarchived": { + "itemUnarchivedToast": { "message": "Kayıt arşivden çıkarıldı" }, "archiveItem": { diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index 2b4cfcb7c22..abcdbea0b1f 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Архівовані записи з'являтимуться тут і будуть виключені з результатів звичайного пошуку та пропозицій автозаповнення." }, - "itemWasSentToArchive": { - "message": "Запис архівовано" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Запис розархівовано" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Архівувати запис" diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index 56c9d9a5c6e..f06556568a1 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "Các mục đã lưu trữ sẽ hiển thị ở đây và sẽ bị loại khỏi kết quả tìm kiếm và gợi ý tự động điền." }, - "itemWasSentToArchive": { - "message": "Mục đã được chuyển vào kho lưu trữ" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Mục đã được bỏ lưu trữ" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "Lưu trữ mục" diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index cf42adba294..9941e296da3 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "已归档的项目将显示在此处,并将被排除在一般搜索结果和自动填充建议之外。" }, - "itemWasSentToArchive": { - "message": "项目已发送到归档" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "项目已取消归档" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "归档项目" diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index 3157e929e8f..461eb031068 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -4387,11 +4387,11 @@ "noItemsInArchiveDesc": { "message": "封存的項目會顯示在此處,且不會出現在一般搜尋結果或自動填入建議中。" }, - "itemWasSentToArchive": { - "message": "項目已移至封存" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "項目取消封存" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "archiveItem": { "message": "封存項目" From 22a6fb1e6d468b04f86e7297066ac2b9106524b9 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 11:42:43 +0100 Subject: [PATCH 18/23] Autosync the updated translations (#19009) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/af/messages.json | 24 +++++-- apps/web/src/locales/ar/messages.json | 24 +++++-- apps/web/src/locales/az/messages.json | 84 +++++++++++++----------- apps/web/src/locales/be/messages.json | 24 +++++-- apps/web/src/locales/bg/messages.json | 24 +++++-- apps/web/src/locales/bn/messages.json | 24 +++++-- apps/web/src/locales/bs/messages.json | 24 +++++-- apps/web/src/locales/ca/messages.json | 24 +++++-- apps/web/src/locales/cs/messages.json | 22 +++++-- apps/web/src/locales/cy/messages.json | 24 +++++-- apps/web/src/locales/da/messages.json | 24 +++++-- apps/web/src/locales/de/messages.json | 26 +++++--- apps/web/src/locales/el/messages.json | 24 +++++-- apps/web/src/locales/en_GB/messages.json | 24 +++++-- apps/web/src/locales/en_IN/messages.json | 24 +++++-- apps/web/src/locales/eo/messages.json | 24 +++++-- apps/web/src/locales/es/messages.json | 24 +++++-- apps/web/src/locales/et/messages.json | 24 +++++-- apps/web/src/locales/eu/messages.json | 24 +++++-- apps/web/src/locales/fa/messages.json | 24 +++++-- apps/web/src/locales/fi/messages.json | 24 +++++-- apps/web/src/locales/fil/messages.json | 24 +++++-- apps/web/src/locales/fr/messages.json | 24 +++++-- apps/web/src/locales/gl/messages.json | 24 +++++-- apps/web/src/locales/he/messages.json | 24 +++++-- apps/web/src/locales/hi/messages.json | 24 +++++-- apps/web/src/locales/hr/messages.json | 24 +++++-- apps/web/src/locales/hu/messages.json | 26 +++++--- apps/web/src/locales/id/messages.json | 24 +++++-- apps/web/src/locales/it/messages.json | 24 +++++-- apps/web/src/locales/ja/messages.json | 24 +++++-- apps/web/src/locales/ka/messages.json | 24 +++++-- apps/web/src/locales/km/messages.json | 24 +++++-- apps/web/src/locales/kn/messages.json | 24 +++++-- apps/web/src/locales/ko/messages.json | 24 +++++-- apps/web/src/locales/lv/messages.json | 24 +++++-- apps/web/src/locales/ml/messages.json | 24 +++++-- apps/web/src/locales/mr/messages.json | 24 +++++-- apps/web/src/locales/my/messages.json | 24 +++++-- apps/web/src/locales/nb/messages.json | 24 +++++-- apps/web/src/locales/ne/messages.json | 24 +++++-- apps/web/src/locales/nl/messages.json | 24 +++++-- apps/web/src/locales/nn/messages.json | 24 +++++-- apps/web/src/locales/or/messages.json | 24 +++++-- apps/web/src/locales/pl/messages.json | 24 +++++-- apps/web/src/locales/pt_BR/messages.json | 24 +++++-- apps/web/src/locales/pt_PT/messages.json | 24 +++++-- apps/web/src/locales/ro/messages.json | 24 +++++-- apps/web/src/locales/ru/messages.json | 24 +++++-- apps/web/src/locales/si/messages.json | 24 +++++-- apps/web/src/locales/sk/messages.json | 24 +++++-- apps/web/src/locales/sl/messages.json | 24 +++++-- apps/web/src/locales/sr_CS/messages.json | 24 +++++-- apps/web/src/locales/sr_CY/messages.json | 24 +++++-- apps/web/src/locales/sv/messages.json | 24 +++++-- apps/web/src/locales/ta/messages.json | 24 +++++-- apps/web/src/locales/te/messages.json | 24 +++++-- apps/web/src/locales/th/messages.json | 24 +++++-- apps/web/src/locales/tr/messages.json | 22 +++++-- apps/web/src/locales/uk/messages.json | 24 +++++-- apps/web/src/locales/vi/messages.json | 24 +++++-- apps/web/src/locales/zh_CN/messages.json | 24 +++++-- apps/web/src/locales/zh_TW/messages.json | 24 +++++-- 63 files changed, 1101 insertions(+), 471 deletions(-) diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index 7b6c7778d70..eb983fc3512 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Die Bitwarden-gebruiker wat hierdie Send geskep het, het gekies om hul e-posadres te verberg. U moet verseker dat u die bron van hierdie skakel vertrou voordat u die inhoud gebruik of aflaai.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index 65b8578a206..647c4602c17 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 6c2150ec158..fec06600593 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -48,7 +48,7 @@ "message": "Bu bəndə düzəliş etmə icazəniz yoxdur" }, "reviewAccessIntelligence": { - "message": "Review security reports to find and fix credential risks before they escalate." + "message": "Kimlik məlumatları riskləri artmazdan əvvəl onları tapıb düzəltmək üçün təhlükəsizlik hesabatlarını incələyin." }, "reviewAtRiskLoginsPrompt": { "message": "Risk altında olan girişi nəzərdən keçirin" @@ -269,7 +269,7 @@ } }, "numCriticalApplicationsMarkedSuccess": { - "message": "$COUNT$ applications marked critical", + "message": "$COUNT$ tətbiq kritik olaraq işarələndi", "placeholders": { "count": { "content": "$1", @@ -278,7 +278,7 @@ } }, "numApplicationsUnmarkedCriticalSuccess": { - "message": "$COUNT$ applications marked not critical", + "message": "$COUNT$ tətbiq kritik deyil olaraq işarələndi", "placeholders": { "count": { "content": "$1", @@ -287,7 +287,7 @@ } }, "markAppCountAsCritical": { - "message": "Mark $COUNT$ as critical", + "message": "$COUNT$ tətbiqi kritik olaraq işarələ", "placeholders": { "count": { "content": "$1", @@ -296,7 +296,7 @@ } }, "markAppCountAsNotCritical": { - "message": "Mark $COUNT$ as not critical", + "message": "$COUNT$ tətbiqi kritik deyil olaraq işarələ", "placeholders": { "count": { "content": "$1", @@ -1438,7 +1438,7 @@ "message": "Keçidə sahib olan hər kəs" }, "anyOneWithPassword": { - "message": "Sizin təyin etdiyiniz parola sahib hər kəs" + "message": "Ayarladığınız parola sahib hər kəs" }, "location": { "message": "Yerləşmə" @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Abunəliyiniz əvvəlki halına qaytarıldı." }, + "resubscribe": { + "message": "Təkrar abunə ol" + }, + "yourSubscriptionIsExpired": { + "message": "Abunəliyiniz bitib" + }, + "yourSubscriptionIsCanceled": { + "message": "Abunəliyiniz ləğv edilib" + }, "cancelConfirmation": { "message": "İmtina etmək istədiyinizə əminsiniz? Bu faktura dövrünün sonunda bu abunəliyin bütün özəlliklərinə erişimi itirəcəksiniz." }, @@ -5431,7 +5440,7 @@ "message": "Minimum söz sayı" }, "passwordTypePolicyOverride": { - "message": "Password type", + "message": "Parol növü", "description": "Name of the password generator policy that overrides the user's password/passphrase selection." }, "userPreference": { @@ -5704,7 +5713,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendCreatedDescriptionV2": { - "message": "Copy and share this Send link. The Send will be available to anyone with the link for the next $TIME$.", + "message": "Bu Send keçidini kopyala və paylaş. Send, keçidə sahib olan hər kəs üçün növbəti $TIME$ ərzində əlçatan olacaq.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.", "placeholders": { "time": { @@ -5714,7 +5723,7 @@ } }, "sendCreatedDescriptionPassword": { - "message": "Bu Send keçidini kopyala və paylaş. Send, təyin etdiyiniz keçidə və parola sahib olan hər kəs üçün növbəti $TIME$ ərzində əlçatan olacaq.", + "message": "Bu Send keçidini kopyala və paylaş. Send, keçidə və ayarladığınız parola sahib olan hər kəs üçün növbəti $TIME$ ərzində əlçatan olacaq.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.", "placeholders": { "time": { @@ -6429,6 +6438,10 @@ "message": "\"Send\"ə bax", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Bu \"Send\"i yaradan Bitwarden istifadəçisi e-poçt ünvanını gizlətməyi seçib. İstifadə etməzdən və ya endirməzdən əvvəl bu keçidin mənbəyinin etibarlı olduğuna əmin olmalısınız.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -6596,7 +6609,7 @@ "message": "Yeni istifadəçiləri avtomatik qeydiyyata al" }, "resetPasswordAutoEnrollInviteWarning": { - "message": "Bu təşkilat, sizi \"parol sıfırlama\"da avtomatik olaraq qeydiyyata alan müəssisə siyasətinə sahibdir. Qeydiyyat, təşkilat administratorlarına ana parolunuzu dəyişdirmə icazəsi verəcək." + "message": "Bu təşkilat, sizi \"parol sıfırlama\"da avtomatik olaraq qeydiyyata alan Enterprise siyasətinə sahibdir. Qeydiyyat, təşkilat inzibatçılarına ana parolunuzu dəyişdirmə icazəsi verəcək." }, "resetPasswordOrgKeysError": { "message": "\"Təşkilat açarları\" cavabı boşdur" @@ -6674,10 +6687,10 @@ } }, "reinviteSuccessToast": { - "message": "1 invitation sent" + "message": "1 dəvət göndərilib" }, "bulkReinviteSentToast": { - "message": "$COUNT$ invitations sent", + "message": "$COUNT$ dəvət göndərilib", "placeholders": { "count": { "content": "$1", @@ -6703,7 +6716,7 @@ } }, "bulkReinviteProgressTitle": { - "message": "$COUNT$ of $TOTAL$ invitations sent...", + "message": "$COUNT$/$TOTAL$ dəvət göndərilib...", "placeholders": { "count": { "content": "$1", @@ -6716,10 +6729,10 @@ } }, "bulkReinviteProgressSubtitle": { - "message": "Keep this page open until all are sent." + "message": "Hamısı göndərilənə qədər bu səhifəni açıq saxlayın." }, "bulkReinviteFailuresTitle": { - "message": "$COUNT$ invitations didn't send", + "message": "$COUNT$ dəvət göndərilməyib", "placeholders": { "count": { "content": "$1", @@ -6728,10 +6741,10 @@ } }, "bulkReinviteFailureTitle": { - "message": "1 invitation didn't send" + "message": "1 dəvət göndərilməyib" }, "bulkReinviteFailureDescription": { - "message": "An error occurred while sending invitations to $COUNT$ of $TOTAL$ members. Try sending again, and if the problem continues,", + "message": "$COUNT$/$TOTAL$ üzvə dəvət göndərərkən xəta baş verdi. Yenidən göndərməyə çalışın, problem davam edərsə,", "placeholders": { "count": { "content": "$1", @@ -6744,7 +6757,7 @@ } }, "bulkResendInvitations": { - "message": "Try sending again" + "message": "Yenidən göndərməyə çalış" }, "bulkRemovedMessage": { "message": "Uğurla çıxarıldı" @@ -10185,7 +10198,7 @@ "message": "Tapşırıq təyin et" }, "allTasksAssigned": { - "message": "All tasks have been assigned" + "message": "Bütün tapşırıqlar təyin edilib" }, "assignSecurityTasksToMembers": { "message": "Parol dəyişdirmə bildirişlərini göndər" @@ -11896,13 +11909,10 @@ "noItemsInArchiveDesc": { "message": "Arxivlənmiş elementlər burada görünəcək, ümumi axtarış nəticələrindən və avto-doldurma təkliflərindən xaric ediləcək." }, - "itemWasSentToArchive": { - "message": "Element arxivə göndərildi" + "itemArchiveToast": { + "message": "Element arxivləndi" }, - "itemWasUnarchived": { - "message": "Element arxivdən çıxarıldı" - }, - "itemUnarchived": { + "itemUnarchivedToast": { "message": "Element arxivdən çıxarıldı" }, "bulkArchiveItems": { @@ -12583,7 +12593,7 @@ "message": "Davam etmək istədiyinizə əminsiniz?" }, "errorCannotDecrypt": { - "message": "Error: Cannot decrypt" + "message": "Xəta: Şifrəsi açıla bilmir" }, "userVerificationFailed": { "message": "İstifadəçi doğrulaması uğursuz oldu." @@ -12891,22 +12901,22 @@ "message": "bir istifadəçi üçün" }, "upgradeToTeams": { - "message": "Upgrade to Teams" + "message": "\"Teams\"ə yüksəlt" }, "upgradeToEnterprise": { - "message": "Upgrade to Enterprise" + "message": "\"Enterprise\"a yüksəlt" }, "upgradeShareEvenMore": { - "message": "Share even more with Families, or get powerful, trusted password security with Teams or Enterprise" + "message": "Ailələr planı ilə daha çoxunu paylaşın, ya da Komandalar və ya Müəssisə planı ilə daha güclü və etibarlı parol təhlükəsizliyi əldə edin." }, "organizationUpgradeTaxInformationMessage": { - "message": "Prices exclude tax and are billed annually." + "message": "Qiymətə vergi daxil deyildir və illik hesablanır." }, "invoicePreviewErrorMessage": { - "message": "Encountered an error while generating the invoice preview." + "message": "Faktura önizləməsini yaradan zaman xəta ilə üzləşildi." }, "planProratedMembershipInMonths": { - "message": "Prorated $PLAN$ membership ($NUMOFMONTHS$)", + "message": "Proporsional $PLAN$ üzvlüyü ($NUMOFMOONTHS$)", "placeholders": { "plan": { "content": "$1", @@ -12919,16 +12929,16 @@ } }, "premiumSubscriptionCredit": { - "message": "Premium subscription credit" + "message": "Premium abunəlik krediti" }, "enterpriseMembership": { - "message": "Enterprise membership" + "message": "Enterprise üzvlüyü" }, "teamsMembership": { - "message": "Teams membership" + "message": "Teams üzvlüyü" }, "plansUpdated": { - "message": "You've upgraded to $PLAN$!", + "message": "$PLAN$ planına yüksəltmisiniz!", "placeholders": { "plan": { "content": "$1", @@ -12937,6 +12947,6 @@ } }, "paymentMethodUpdateError": { - "message": "There was an error updating your payment method." + "message": "Ödəniş üsulunuzu güncəlləyərkən xəta baş verdi." } } diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index ef00d46b4c0..4d6fe96c6d2 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Падпіска была адноўлена." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Вы сапраўды хочаце скасаваць? Вы страціце доступ да ўсіх функцый падпіскі ў канцы гэтага плацежнага перыяду." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Карыстальнік Bitwarden, які стварыў гэты Send, вырашыў схаваць сваю электронную пошту. Пераканайцеся, што гэта спасылка атрымана з надзейных крыніц і толькі пасля гэтага выкарыстоўвайце або пампуйце дадзенае змесціва.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index e32b2b3d5f1..7b5ee07efe1 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Абонаментът е подновен." }, + "resubscribe": { + "message": "Подновявана на абонамента" + }, + "yourSubscriptionIsExpired": { + "message": "Абонаментът Ви е изтекъл" + }, + "yourSubscriptionIsCanceled": { + "message": "Абонаментът Ви е прекратен" + }, "cancelConfirmation": { "message": "Уверени ли сте, че искате да прекратите абонамента? След края на последно платения период ще загубите всички допълнителни преимущества." }, @@ -6429,6 +6438,10 @@ "message": "Преглед на изпращането", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Потвърдете е-пощата си, за да видите това Изпращане", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Потребителят, който е създал това изпращане, е избрал да скрие адреса на своята е-поща. Уверете се, че източникът на тази връзка е достоверен, преди да я последвате или да свалите съдържание чрез нея.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Архивираните елементи ще се показват тук и ще бъдат изключени от общите резултати при търсене и от предложенията за автоматично попълване." }, - "itemWasSentToArchive": { - "message": "Елементът беше преместен в архива" + "itemArchiveToast": { + "message": "Елементът е преместен в архива" }, - "itemWasUnarchived": { - "message": "Елементът беше изваден от архива" - }, - "itemUnarchived": { - "message": "Елементът беше изваден от архива" + "itemUnarchivedToast": { + "message": "Елементът е изваден от архива" }, "bulkArchiveItems": { "message": "Елементите са архивирани" diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index 53f29d874e7..9935cc538a1 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index 1ae5523c9ac..dda9249b383 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index 88e4b0569d6..642ae65228e 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "S'ha restablert la subscripció." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Esteu segur que voleu cancel·lar? Perdreu l'accés a totes les característiques d'aquesta subscripció al final d'aquest cicle de facturació." }, @@ -6429,6 +6438,10 @@ "message": "Veure Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "L'usuari Bitwarden que ha creat aquest Send ha decidit amagar la seua adreça de correu electrònic. Heu d’assegurar-vos que confieu en la font d’aquest enllaç abans d’utilitzar o descarregar el seu contingut.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index d85f3fada18..ae41eeebfef 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Předplatné bylo obnoveno." }, + "resubscribe": { + "message": "Obnovit odběr" + }, + "yourSubscriptionIsExpired": { + "message": "Vaše předplatné vypršelo" + }, + "yourSubscriptionIsCanceled": { + "message": "Vaše předplatné je zrušeno" + }, "cancelConfirmation": { "message": "Opravdu chcete zrušit předplatné? Na konci fakturačního období přijdete o veškeré výhody plynoucí z vybraného plánu." }, @@ -6429,6 +6438,10 @@ "message": "Zobrazit Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Ověřte svůj e-mail pro zobrazení tohoto Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Uživatel Bitwardenu, který vytvořil tento Send, se rozhodl skrýt svou e-mailovou adresu. Před použitím nebo stažením jeho obsahu byste se měli ujistit, že zdroji tohoto odkazu důvěřujete.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,13 +11909,10 @@ "noItemsInArchiveDesc": { "message": "Zde se zobrazí archivované položky a budou vyloučeny z obecných výsledků vyhledávání a návrhů automatického vyplňování." }, - "itemWasSentToArchive": { - "message": "Položka byla přesunuta do archivu" + "itemArchiveToast": { + "message": "Položka archivována" }, - "itemWasUnarchived": { - "message": "Položka byla odebrána z archivu" - }, - "itemUnarchived": { + "itemUnarchivedToast": { "message": "Položka byla odebrána z archivu" }, "bulkArchiveItems": { diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index c566ffaf831..10639a60017 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index 42fbf0cf7c4..2943127dbb8 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Abonnementet er gentegnet." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Er du sikker på at du vil opsige? Du vil miste adgangen til alle abonnementsfunktionerne ved afslutningen af denne faktureringsperiode." }, @@ -6429,6 +6438,10 @@ "message": "Vis Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Bitwarden-brugeren, der oprettede denne Send, har valgt at skjule sin e-mailadresse. Du bør sikre dig, at du stoler på kilden til dette link, inden dets indhold downloades/benyttes.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index 89672d615dc..a89e10c8d45 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Das Abo wurde wieder aufgenommen." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Sind Sie sicher, dass Sie kündigen wollen? Am Ende dieses Abrechnungszyklus verlieren Sie den Zugriff auf alle Funktionen dieses Abos." }, @@ -6429,6 +6438,10 @@ "message": "Sends anzeigen", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Der Bitwarden Benutzer, der dieses Send erstellt hat, hat sich entschieden, seine E-Mail-Adresse zu verstecken. Du solltest sicherstellen, dass du der Quelle dieses Links vertraust, bevor du dessen Inhalt verwendest oder herunterlädst.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archivierte Einträge werden hier angezeigt und von allgemeinen Suchergebnissen und Auto-Ausfüllen-Vorschlägen ausgeschlossen." }, - "itemWasSentToArchive": { - "message": "Eintrag wurde ins Archiv verschoben" + "itemArchiveToast": { + "message": "Eintrag archiviert" }, - "itemWasUnarchived": { - "message": "Eintrag wird nicht mehr archiviert" - }, - "itemUnarchived": { - "message": "Eintrag wird nicht mehr archiviert" + "itemUnarchivedToast": { + "message": "Eintrag nicht mehr archiviert" }, "bulkArchiveItems": { "message": "Einträge archiviert" @@ -12583,7 +12593,7 @@ "message": "Bist du sicher, dass du fortfahren möchtest?" }, "errorCannotDecrypt": { - "message": "Error: Cannot decrypt" + "message": "Fehler: Entschlüsselung nicht möglich" }, "userVerificationFailed": { "message": "Benutzerverifizierung fehlgeschlagen." diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index 0aef25ee9cb..e084687382a 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Η συνδρομή έχει αποκατασταθεί." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Είστε βέβαιοι ότι θέλετε να ακυρώσετε; Θα χάσετε την πρόσβαση σε όλες τις λειτουργίες αυτής της συνδρομής στο τέλος αυτού του κύκλου χρέωσης." }, @@ -6429,6 +6438,10 @@ "message": "Προβολή Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Ο χρήστης Bitwarden που δημιούργησε αυτό το send έχει επιλέξει να κρύψει τη διεύθυνση email του. Πρέπει να διασφαλίσετε ότι εμπιστεύεστε την πηγή αυτού του συνδέσμου πριν χρησιμοποιήσετε ή κατεβάσετε το περιεχόμενό του.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index 1617bfb4580..78242ac88dd 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription has expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is cancelled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 8845ef9f042..5d1bf31a336 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription has expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is cancelled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index 1e289a324fe..1c9f0473adf 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "La abono estis reinstalita." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Ĉu vi certas, ke vi volas nuligi? Vi perdos aliron al ĉiuj funkcioj de ĉi tiu abono fine de ĉi tiu faktura ciklo." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index 2d85309144f..7e8f62b6a3c 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "La suscripción ha sido restablecida." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "¿Estás seguro de que quieres cancelar? Perderá el acceso a todas las funciones de esta suscripción al final de este ciclo de facturación." }, @@ -6429,6 +6438,10 @@ "message": "Ver Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "El usuario Bitwarden que creó este Send ha elegido ocultar su dirección de correo electrónico. Deberías asegurarte de que confías en la fuente de este enlace antes de usar o descargar su contenido.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 60a2690785c..e101d49d3cf 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Tellimus on uuesti aktiveeritud." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Oled kindel, et soovid tellimuse tühistada? Kaotad sellega arveperioodi lõpus kõik tellimisega kaasnevad eelised." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Selle Sendi looja ei soovi oma e-posti aadressi avaldada. Palun veendu, et see pärineb usaldusväärsest allikast, enne kui asud selle sisu kasutama või faile alla laadima.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index a75f95994c0..75f55a0d0f0 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Harpidetza berrezarri da." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Ziur zaude ezeztatu nahi duzula? Harpidetza honen ezaugarri guztiak galduko dituzu fakturazio ziklo honen amaieran." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Send hau sortu duen Bitwarden erabiltzaileak emaileko helbidea ezkutatzea erabaki du. Ziurtatu lotura honen iturrian konfiantza duzula edukia erabili edo deskargatu aurretik.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index 5c046211648..d1efb2a239f 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "اشتراک دوباره برقرار شده است." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "آیا مطمئنید که می‌خواهید لغو کنید؟ در پایان این چرخه صورتحساب، دسترسی به همه ویژگی‌های این اشتراک را از دست خواهید داد." }, @@ -6429,6 +6438,10 @@ "message": "مشاهده ارسال", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "کاربر Bitwarden که این ارسال را ایجاد کرده است انتخاب کرده که نشانی ایمیل خود را پنهان کند. قبل از استفاده یا دانلود محتوای این پیوند، باید مطمئن شوید که به منبع این پیوند اعتماد دارید.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index 7cc931fd9f8..4c6b3ef62d8 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Tilaus palautettiin." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Haluatko varmasti irtisanoa tilauksen? Menetät pääsyn kaikkiin tilauksen tarjoamiin ominaisuuksiin kuluvan laskutuskauden lopussa." }, @@ -6429,6 +6438,10 @@ "message": "Näytä Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Sendin luonut Bitwarden-käyttäjä on piilottanut sähköpostiosoitteensa. Varmista, että linkin lähde on luotettava ennen kuin käytät tai lataat sen sisältöä.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index 415793a4b98..e94c5b4fea6 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Naibalik na ang subscription." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Sigurado ka bang gusto mong kanselahin? Mawawala ang access mo sa lahat ng tampok ng subscription na ito sa pagtatapos ng siklo ng pagsingil na ito." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Ang gumagamit ng Bitwarden na lumikha ng Send na ito ay piniling itago ang kanilang email address. Dapat mong tiyakin na pinagkakatiwalaan mo ang pinagmulan ng link na ito bago gamitin o i download ang nilalaman nito.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index eb9b2d1c915..e4183ff5692 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Votre abonnement a été rétabli." }, + "resubscribe": { + "message": "Se réabonner" + }, + "yourSubscriptionIsExpired": { + "message": "Votre abonnement a expiré" + }, + "yourSubscriptionIsCanceled": { + "message": "Votre abonnement est annulé" + }, "cancelConfirmation": { "message": "Êtes-vous sûr de vouloir annuler ? Vous perdrez l’accès à toutes les fonctionnalités de l’abonnement à la fin de ce cycle de facturation." }, @@ -6429,6 +6438,10 @@ "message": "Voir le Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Vérifiez votre courriel pour afficher ce Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "L'utilisateur de Bitwarden qui a créé ce Send a choisi de masquer son adresse électronique. Vous devriez vous assurer que vous faites confiance à la source de ce lien avant d'utiliser ou de télécharger son contenu.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Les éléments archivés apparaîtront ici et seront exclus des résultats de recherche généraux et des suggestions de remplissage automatique." }, - "itemWasSentToArchive": { - "message": "L'élément a été envoyé à l'archive" + "itemArchiveToast": { + "message": "Élément archivé" }, - "itemWasUnarchived": { - "message": "L'élément a été désarchivé" - }, - "itemUnarchived": { - "message": "L'élément a été désarchivé" + "itemUnarchivedToast": { + "message": "Élément désarchivé" }, "bulkArchiveItems": { "message": "Éléments archivés" diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index 8357f5d0747..de6c7782c6d 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index b075b91a860..8829ed90e65 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "המנוי הופעל מחדש." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "האם אתה בטוח שברצונך לבטל? ביטול המנוי יגרום לאיבוד כל האפשרויות השמורות למנויים בסיום מחזור החיוב הנוכחי." }, @@ -6429,6 +6438,10 @@ "message": "הצג סֵנְד", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "משתמש ה־Bitwarden שיצר את סֵנְד זה בחר להסתיר את כתובת הדוא\"ל שלו. עליך לוודא שאתה בוטח במקור של קישור זה לפני שימוש או הורדה של התוכן שלו.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "פריטים בארכיון יופיעו כאן ויוחרגו מתוצאות חיפוש כללי והצעות למילוי אוטומטי." }, - "itemWasSentToArchive": { - "message": "הפריט נשלח לארכיון" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "הפריט הוסר מהארכיון" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "הפריטים הועברו לארכיון" diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 4e261d672bb..41d32fb9587 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index ced4fc03b1c..41eac503c59 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Pretplata je vraćena" }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Sigurno želiš otkazati? Izgubiti ćeš pristup svim ovim pretplatnim značajkama kad istekne rok naplate." }, @@ -6429,6 +6438,10 @@ "message": "Pogledaj Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Bitwarden korisnik koji je stvorio ovaj Send odabrao/la je sakriti svoju e-poštu. Koristi i/ili preuzmi ove podatke samo ako vjeruješ izvoru iz kojeg je primljena ova vezu.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Arhivirane stavke biti će prikazane ovdje i biti će izuzete iz rezultata općih pretraga i preporuka auto-ispune." }, - "itemWasSentToArchive": { - "message": "Stavka poslana u arhivu" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Stavka vraćena iz arhive" - }, - "itemUnarchived": { - "message": "Stavka vraćena iz arhive" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Stavke arhivirane" diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index f4c9144cc6d..9b8a98e5625 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Az előfizetés visszaállításra került." }, + "resubscribe": { + "message": "Feliratkozás ismét" + }, + "yourSubscriptionIsExpired": { + "message": "Az előfizetés lejárt." + }, + "yourSubscriptionIsCanceled": { + "message": "Az előfizetés törlésre került." + }, "cancelConfirmation": { "message": "Biztosan törlésre kerüljön? A számlázási időszak végén az összes előfizetési hozzáférés elveszik." }, @@ -6429,6 +6438,10 @@ "message": "Send megtekintése", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Ellenőrizzük az email címet a Send elem megtekintéséhez.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Az ezt a Send elemet létrehozó Bitwarden felhasználó úgy döntött, hogy elrejti email címét. Mielőtt felhasználnánk vagy letöltenénk a tartalmát, ellenőrizzük a hivatkozás megbízhatóságát.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -10906,7 +10919,7 @@ "message": "A biztonsági kockázatok azonosítása a tagok hozzáférésének ellenőrzésével" }, "onlyAvailableForEnterpriseOrganization": { - "message": "Vállalati tervre frissítéssel gyorsan megtekinthető a tagok hozzáférése a szervezetben." + "message": "Vállalati csomagra frissítéssel gyorsan megtekinthető a tagok hozzáférése a szervezetben." }, "date": { "message": "Dátum" @@ -11896,20 +11909,17 @@ "noItemsInArchiveDesc": { "message": "Az archivált elemek itt jelennek meg és kizárásra kerülnek az általános keresési eredményekből és az automatikus kitöltési javaslatokból." }, - "itemWasSentToArchive": { - "message": "Az elem az archivumba került." + "itemArchiveToast": { + "message": "Az elem archiválásra került." }, - "itemWasUnarchived": { + "itemUnarchivedToast": { "message": "Az elem visszavételre került az archivumból." }, - "itemUnarchived": { - "message": "Az elemek visszavéelre kerültek az archivumból." - }, "bulkArchiveItems": { "message": "Az elemek archiválásra kerültek." }, "bulkUnarchiveItems": { - "message": "Az elemek visszavéelre kerültek az archivumból." + "message": "Az elemek visszavételre kerültek az archivumból." }, "archiveItem": { "message": "Elem archiválása", diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index 270b8624c24..30746054e41 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Langganan telah dipulihkan." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Anda yakin ingin membatalkan? Anda akan kehilangan akses ke semua fitur langganan ini di akhir siklus penagihan ini." }, @@ -6429,6 +6438,10 @@ "message": "Lihat Kirim", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Pengguna Bitwarden yang membuat Send ini memilih untuk menyembunyikan alamat emailnya. Kamu harus yakin bahwa kamu mempercayai sumber dari link it sebelum mengunduh isinya.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index c2fb3effdf0..1e89c1624f6 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "L'abbonamento è stato ripristinato." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Sei sicuro di voler annullare il tuo abbonamento? Alla fine di questo ciclo di fatturazione perderai l'accesso a tutte le funzionalità aggiuntive date dall'abbonamento." }, @@ -6429,6 +6438,10 @@ "message": "Visualizza Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "L'utente Bitwarden che ha creato questo Send ha nascosto il suo indirizzo email. Devi essere sicuro di fidarti della fonte di questo link prima di usare o scaricare il suo contenuto.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Gli elementi archiviati appariranno qui e saranno esclusi dai risultati di ricerca e dall'auto-riempimento." }, - "itemWasSentToArchive": { - "message": "Elemento archiviato" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Elemento estratto dall'archivio" - }, - "itemUnarchived": { - "message": "Elemento estratto dall'archivio" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Elementi archiviati" diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index cd78e0a269a..d86a7dce648 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "契約が再開されました。" }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "本当にキャンセルしますか?契約していたすべての追加機能が請求期間の終期で利用できなくなります。" }, @@ -6429,6 +6438,10 @@ "message": "Send を表示", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "この Send を作成した Bitwarden ユーザーが、自身のメールアドレスを非表示にしました。 コンテンツを使用またはダウンロードする前に、このリンクのソースが信頼できるかどうか確認する必要があります。", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index 6de5179793d..915ca5d6cba 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index b95256dfacd..bc0e3b74cb6 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index 7a378184a39..bd77a975193 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "ಚಂದಾದಾರಿಕೆಯನ್ನು ಪುನಃ ಸ್ಥಾಪಿಸಲಾಗಿದೆ." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "ನೀವು ರದ್ದು ಮಾಡಲು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ? ಈ ಬಿಲ್ಲಿಂಗ್ ಚಕ್ರದ ಕೊನೆಯಲ್ಲಿ ಈ ಎಲ್ಲಾ ಚಂದಾದಾರಿಕೆಯ ವೈಶಿಷ್ಟ್ಯಗಳಿಗೆ ನೀವು ಪ್ರವೇಶವನ್ನು ಕಳೆದುಕೊಳ್ಳುತ್ತೀರಿ." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "ಈ ಕಳುಹಿಸುವಿಕೆಯನ್ನು ರಚಿಸಿದ ಬಿಟ್‌ವಾರ್ಡೆನ್ ಬಳಕೆದಾರರು ತಮ್ಮ ಇಮೇಲ್ ವಿಳಾಸವನ್ನು ಮರೆಮಾಡಲು ಆಯ್ಕೆ ಮಾಡಿದ್ದಾರೆ. ಈ ಲಿಂಕ್‌ನ ವಿಷಯವನ್ನು ಬಳಸುವ ಅಥವಾ ಡೌನ್‌ಲೋಡ್ ಮಾಡುವ ಮೊದಲು ಅದರ ಮೂಲವನ್ನು ನೀವು ನಂಬಿದ್ದೀರಿ ಎಂದು ನೀವು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಬೇಕು.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index ad9b80b9f6a..0af228dd821 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "구독을 복원했습니다." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "정말로 취소하시겠습니까? 청구 주기 후에 이 구독의 모든 기능에 대한 접근을 잃게 됩니다." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "이 Send를 생성한 Bitwarden 사용자가 자신의 이메일 주소를 숨겼습니다. 이 링크에 접속하거나 내용을 다운로드하기 전에, 이 링크의 출처를 신뢰하는지 확인하십시오.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index 4875dc4fe31..f12dda40ea3 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Abonements tika atjaunots." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Vai tiešām atcelt? Tiks zaudēta piekļuve visām abonementa iespējām pēc pašreizējā norēķinu laika posma beigām." }, @@ -6429,6 +6438,10 @@ "message": "Apskatīt Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Bitwarden lietotājs, kurš izveidoja šo Send, ir izvēlējies slēpt savu e-pasta adresi. Ir jāpārliecinās par šīs saites avota uzticamību, pirms saturs tiek izmantots vai lejupielādēts.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Šeit parādīsies arhivētie vienumi, un tie netiks iekļauti vispārējās meklēšanas iznākumos un automātiskās aizpildes ieteikumos." }, - "itemWasSentToArchive": { - "message": "Vienums tika ievietots arhīvā" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Vienums tika izņemts no arhīva" - }, - "itemUnarchived": { - "message": "Vienums tika izņemts no arhīva" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Vienumi tika arhivēti" diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index f0173da95e5..e68e7d25b85 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/mr/messages.json b/apps/web/src/locales/mr/messages.json index 35031280ec3..2abd88c1169 100644 --- a/apps/web/src/locales/mr/messages.json +++ b/apps/web/src/locales/mr/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index b95256dfacd..bc0e3b74cb6 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index 07db562d56b..de97b70a119 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Abonnementet har blitt gjeninnført." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Er du sikker på at du vil avbryte? Du vil miste tilgang til alle funksjonene til dette abonnementet etter den inneværende regningsperioden." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Bitwarden-brukeren som opprettet denne sendingen, har valgt å skjule deres e-postadresse. Du bør forsikre deg om at du stoler på kilden til denne lenken før du bruker eller laster ned innholdet.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index cd5e07cc33e..26c942795b6 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index 6754c7a0c51..2748009dba8 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Het abonnement is opnieuw geactiveerd." }, + "resubscribe": { + "message": "Opnieuw abonneren" + }, + "yourSubscriptionIsExpired": { + "message": "Je abonnement is verlopen" + }, + "yourSubscriptionIsCanceled": { + "message": "Je abonnement is geannuleerd" + }, "cancelConfirmation": { "message": "Weet je zeker dat je wilt opzeggen? Je verliest toegang tot alle functionaliteiten van dit abonnement aan het einde van deze betalingscyclus." }, @@ -6429,6 +6438,10 @@ "message": "Send weergeven", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verifieer je e-mailadres om deze Send te bekijken", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "De Bitwarden-gebruiker die deze Send heeft gemaakt heeft ervoor gekozen het e-mailadres te verbergen. Je moet je ervan verzekeren dat je de bron van deze link vertrouwt voordat je de inhoud gebruikt of downloadt.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Gearchiveerde items verschijnen hier en worden uitgesloten van algemene zoekresultaten en automatisch invulsuggesties." }, - "itemWasSentToArchive": { - "message": "Item naar archief verzonden" + "itemArchiveToast": { + "message": "Item gearchiveerd" }, - "itemWasUnarchived": { - "message": "Item uit het archief gehaald" - }, - "itemUnarchived": { - "message": "Item uit het archief gehaald" + "itemUnarchivedToast": { + "message": "Item gedearchiveerd" }, "bulkArchiveItems": { "message": "Items gearchiveerd" diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 7987b4077d1..78a638ee05a 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index b95256dfacd..bc0e3b74cb6 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index 9736337ee0c..40ba151b7ad 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Subskrypcja została przywrócona." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Czy na pewno chcesz anulować? Dostęp do wszystkich funkcji związanych z tą subskrypcją zostanie wyłączony na koniec tego okresu rozliczeniowego." }, @@ -6429,6 +6438,10 @@ "message": "Zobacz Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Użytkownik Bitwarden, który utworzył wysyłkę, zdecydował ukryć swój adres e-mail. Przed użyciem lub pobraniem treści wysyłki upewnij się, że ufasz źródłu tego linku.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index f29637803f0..f78d39715cc 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "A assinatura foi restabelecida." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Você tem certeza que deseja cancelar? Você perderá o acesso a todos os recursos dessa assinatura no final deste ciclo de faturamento." }, @@ -6429,6 +6438,10 @@ "message": "Ver Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "O usuário Bitwarden que criou este Send optou por ocultar seu endereço de e-mail. Você deve certificar-se de que confia na fonte deste link antes de usar ou baixar seu conteúdo.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Os itens arquivados aparecerão aqui e serão excluídos dos resultados gerais de busca e das sugestões de preenchimento automático." }, - "itemWasSentToArchive": { - "message": "O item foi enviado para o arquivo" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "O item foi desarquivado" - }, - "itemUnarchived": { - "message": "O item foi desarquivado" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Itens arquivados" diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index e0626be7255..a20d884c321 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "A subscrição foi restabelecida." }, + "resubscribe": { + "message": "Renovar a subscrição" + }, + "yourSubscriptionIsExpired": { + "message": "A sua subscrição expirou" + }, + "yourSubscriptionIsCanceled": { + "message": "A sua subscrição foi cancelada" + }, "cancelConfirmation": { "message": "Tem a certeza de que pretende cancelar? Perderá o acesso a todas as funcionalidades desta subscrição no final deste ciclo de faturação." }, @@ -6429,6 +6438,10 @@ "message": "Ver Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Confirme o seu e-mail para ver este Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "O utilizador Bitwarden que criou este Send optou por ocultar o seu endereço de e-mail. Deve certificar-se de que confia na fonte deste link antes de utilizar ou descarregar o seu conteúdo.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Os itens arquivados aparecerão aqui e serão excluídos dos resultados gerais da pesquisa e das sugestões de preenchimento automático." }, - "itemWasSentToArchive": { - "message": "O item foi movido para o arquivo" + "itemArchiveToast": { + "message": "Item arquivado" }, - "itemWasUnarchived": { - "message": "O item foi desarquivado" - }, - "itemUnarchived": { - "message": "O item foi desarquivado" + "itemUnarchivedToast": { + "message": "Item desarquivado" }, "bulkArchiveItems": { "message": "Itens arquivados" diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index 0b567f2f969..6dca68fa932 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Abonamentul a fost restabilit." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Sigur doriți să anulați? Veți pierde accesul la toate funcționalitățile acestui abonament la sfârșitul acestui ciclu de facturare." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Utilizatorul Bitwarden care a creat acest Send a ales să-și ascundă adresa de e-mail. Ar trebui să vă asigurați că aveți încredere în sursa acestui link înainte de utilizarea sau descărcarea conținutului acestuia.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 5433c0ac312..13aec65ba3e 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Подписка восстановлена." }, + "resubscribe": { + "message": "Возобновить подписку" + }, + "yourSubscriptionIsExpired": { + "message": "Срок действия вашей подписки истек" + }, + "yourSubscriptionIsCanceled": { + "message": "Ваша подписка отменена" + }, "cancelConfirmation": { "message": "Вы действительно хотите отменить? Вы потеряете доступ ко всем возможностям этой подписки в конце этого платежного периода." }, @@ -6429,6 +6438,10 @@ "message": "Просмотр Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Подтвердите свой адрес email, чтобы просмотреть эту Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Пользователь Bitwarden, создавший эту Send, решил скрыть свой адрес email. Вы должны убедиться, что доверяете источнику этой ссылки, прежде чем использовать или скачивать ее содержимое.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Архивированные элементы появятся здесь и будут исключены из общих результатов поиска и предложений автозаполнения." }, - "itemWasSentToArchive": { - "message": "Элемент был отправлен в архив" + "itemArchiveToast": { + "message": "Элемент архивирован" }, - "itemWasUnarchived": { - "message": "Элемент был разархивирован" - }, - "itemUnarchived": { - "message": "Элемент был разархивирован" + "itemUnarchivedToast": { + "message": "Элемент разархивирован" }, "bulkArchiveItems": { "message": "Элементы архивированы" diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index ac073315340..ab7c7e30566 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index dffa3975792..b1f38615a99 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Predplatné bolo obnovené." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Naozaj chcete zrušiť? Stratíte prístup k všetkým funkciám, ktoré vám predplatné ponúka na konci fakturačného obdobia." }, @@ -6429,6 +6438,10 @@ "message": "Zobraziť Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Používateľ Bitwardenu, ktorý vytvoril tento Send, skryl e-mailové adresy pred príjemcami. Mali by ste zvážiť, či dôverujete zdrojovému odkazu pred jeho použitím alebo stiahnutím jeho obsahu.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Tu sa zobrazia archivované položky, ktoré budú vylúčené zo všeobecného vyhľadávania a z návrhov automatického vypĺňania." }, - "itemWasSentToArchive": { - "message": "Položka bola archivovaná" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Položka bola odobraná z archívu" - }, - "itemUnarchived": { - "message": "Položka bola odobraná z archívu" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Položky archivované" diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index aef3a8ca3ac..db65260f9b1 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Naročnina je bila ponovno vzpostavljena." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Ste prepričani, da želite odpovedati? Ob koncu plačilnega obdobja boste izgubili dostop do vseh ugodnosti naročnine." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 7e7bcbd97b1..fd18cb42a06 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/sr_CY/messages.json b/apps/web/src/locales/sr_CY/messages.json index d457b16f44e..eb6484db8df 100644 --- a/apps/web/src/locales/sr_CY/messages.json +++ b/apps/web/src/locales/sr_CY/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Претплата је враћена." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Јесте ли сигурни да хоћете да откажете? На крају овог обрачунског циклуса изгубићете приступ свим функцијама ове претплате." }, @@ -6429,6 +6438,10 @@ "message": "Видети Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Bitwarden корисник који је створио овај „Send“ је изабрао да сакрије своју е-адресу. Требате да се осигурате да верујете извору ове везе пре употребе или преузимања његовог садржаја.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Архивиране ставке ће се овде појавити и бити искључени из општих резултата претраге и сугестија о ауто-пуњењу." }, - "itemWasSentToArchive": { - "message": "Ставка је послата у архиву" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Ставка враћена из архиве" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Ставке у архиви" diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index f4bab640104..3cb3116b684 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Abonnemanget har återupptagits." }, + "resubscribe": { + "message": "Prenumerera igen" + }, + "yourSubscriptionIsExpired": { + "message": "Din prenumeration har löpt ut" + }, + "yourSubscriptionIsCanceled": { + "message": "Din prenumeration är avbruten" + }, "cancelConfirmation": { "message": "Är du säker på att du vill avsluta? Du kommer förlora tillgång till alla funktioner som abonnemanget erbjuder vid slutet av den nuvarande faktureringsperioden." }, @@ -6429,6 +6438,10 @@ "message": "Visa Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Bitwarden-användaren som skapade denna Send har valt att dölja sin e-postadress. Du bör se till att du litar på källan till denna länk innan du använder eller hämtar innehållet.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Arkiverade objekt visas här och undantas från allmänna sökresultat och autofyllförslag." }, - "itemWasSentToArchive": { - "message": "Objektet skickades till arkivet" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Objektet har avarkiverats" - }, - "itemUnarchived": { - "message": "Objektet har avarkiverats" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Objekt arkiverade" diff --git a/apps/web/src/locales/ta/messages.json b/apps/web/src/locales/ta/messages.json index b93591182db..3789574201c 100644 --- a/apps/web/src/locales/ta/messages.json +++ b/apps/web/src/locales/ta/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "சந்தா மீட்டெடுக்கப்பட்டது." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "நீங்கள் ரத்துசெய்ய விரும்புகிறீர்களா? இந்த பில்லிங் சுழற்சியின் முடிவில் இந்தச் சந்தாவின் அனைத்து அம்சங்களுக்கான அணுகலையும் நீங்கள் இழப்பீர்கள்." }, @@ -6429,6 +6438,10 @@ "message": "Send ஐப் பார்க்கவும்", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "இந்த Send-ஐ உருவாக்கிய Bitwarden பயனர் தங்கள் மின்னஞ்சல் முகவரியை மறைக்கத் தேர்ந்தெடுத்துள்ளார். இதன் உள்ளடக்கத்தைப் பயன்படுத்துவதற்கு அல்லது பதிவிறக்குவதற்கு முன், இந்த இணைப்பின் மூலத்தை நீங்கள் நம்புகிறீர்கள் என்பதை உறுதிப்படுத்த வேண்டும்.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index b95256dfacd..bc0e3b74cb6 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index e5e449038ac..eb6fa9011fc 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "The subscription has been reinstated." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle." }, @@ -6429,6 +6438,10 @@ "message": "View Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Archived items will appear here and will be excluded from general search results and autofill suggestions." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 97a29756a89..53348da8697 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Abonelik sürdürüldü." }, + "resubscribe": { + "message": "Yeniden abone ol" + }, + "yourSubscriptionIsExpired": { + "message": "Aboneliğiniz sona erdi" + }, + "yourSubscriptionIsCanceled": { + "message": "Aboneliğiniz iptal edildi" + }, "cancelConfirmation": { "message": "İptal etmek istediğinden emin misin? Bu fatura döneminin sonunda bu aboneliğin tüm özelliklerine erişiminizi kaybedeceksiniz." }, @@ -6429,6 +6438,10 @@ "message": "Send'i görüntüle", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Bu Send'i görmek için e-posta adresinizi doğrulayın", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Bu Send'i oluşturan Bitwarden kullanıcısı e-posta adresini gizlemeyi seçti. Kullanmadan veya içeriğini indirmeden önce bu bağlantının kaynağının güvenilir olduğundan emin olun.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,13 +11909,10 @@ "noItemsInArchiveDesc": { "message": "Arşivlenmiş kayıtlar burada görünür ve genel arama sonuçları ile otomatik doldurma önerilerinden hariç tutulur." }, - "itemWasSentToArchive": { - "message": "Kayıt arşive gönderildi" + "itemArchiveToast": { + "message": "Kayıt arşivlendi" }, - "itemWasUnarchived": { - "message": "Kayıt arşivden çıkarıldı" - }, - "itemUnarchived": { + "itemUnarchivedToast": { "message": "Kayıt arşivden çıkarıldı" }, "bulkArchiveItems": { diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index 6fc3db5d64e..dcb5d26aa1f 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Передплату було відновлено." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Ви справді хочете скасувати? Ви втратите доступ до всіх можливостей, пов'язаних з нею після завершення поточного періоду передплати." }, @@ -6429,6 +6438,10 @@ "message": "Переглянути відправлення", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Користувач Bitwarden, який створив це відправлення, вирішив приховати свою адресу електронної пошти. Вам слід упевнитися в надійності джерела цього посилання перед його використанням чи завантаженням вмісту.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Архівовані записи з'являтимуться тут і будуть виключені з результатів звичайного пошуку та пропозицій автозаповнення." }, - "itemWasSentToArchive": { - "message": "Item was sent to archive" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Item was unarchived" - }, - "itemUnarchived": { - "message": "Item was unarchived" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Items archived" diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index d54ae1933a7..64d0703bc07 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "Đã kích hoạt lại gói." }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "Bạn có chắc muốn hủy không? Bạn sẽ mất hết quyền truy cập tất cả các tính năng của thuê bao này khi kì thanh toán kết thúc." }, @@ -6429,6 +6438,10 @@ "message": "Xem Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "Người dùng Bitwarden đã tạo Send này đã chọn ẩn địa chỉ email của họ. Bạn nên đảm bảo rằng bạn tin tưởng nguồn của liên kết này trước khi sử dụng hoặc tải xuống nội dung của nó.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "Các mục đã lưu trữ sẽ hiển thị ở đây và sẽ bị loại khỏi kết quả tìm kiếm và gợi ý tự động điền." }, - "itemWasSentToArchive": { - "message": "Mục đã được chuyển vào kho lưu trữ" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "Mục đã được bỏ lưu trữ" - }, - "itemUnarchived": { - "message": "Mục đã được bỏ lưu trữ" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "Các mục đã được lưu trữ" diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index 76b95446091..47c732a5a32 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "您的订阅已恢复。" }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "确定要取消吗?在本次计费周期结束后,您将无法使用此订阅的所有功能。" }, @@ -6429,6 +6438,10 @@ "message": "查看 Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "创建此 Send 的 Bitwarden 用户已选择隐藏他们的电子邮箱地址。在使用或下载其内容之前,您应确保信任此链接的来源。", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "已归档的项目将显示在此处,并将被排除在一般搜索结果和自动填充建议之外。" }, - "itemWasSentToArchive": { - "message": "项目已发送到归档" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "项目已取消归档" - }, - "itemUnarchived": { - "message": "项目已取消归档" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "项目已归档" diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 8056e49b08a..c006b37d612 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -3338,6 +3338,15 @@ "reinstated": { "message": "已重新開始訂閱。" }, + "resubscribe": { + "message": "Resubscribe" + }, + "yourSubscriptionIsExpired": { + "message": "Your subscription is expired" + }, + "yourSubscriptionIsCanceled": { + "message": "Your subscription is canceled" + }, "cancelConfirmation": { "message": "您確定要取消訂閱嗎?在本次計費週期結束後,您將無法再使用此訂閱的所有功能。" }, @@ -6429,6 +6438,10 @@ "message": "檢視 Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, + "verifyYourEmailToViewThisSend": { + "message": "Verify your email to view this Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "viewSendHiddenEmailWarning": { "message": "建立此 Send 的 Bitwarden 使用者已選擇隱藏他們的電子郵件地址。在使用或下載此連結的內容之前,應確保您信任此連結的來源。", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -11896,14 +11909,11 @@ "noItemsInArchiveDesc": { "message": "封存的項目會顯示在此處,且不會出現在一般搜尋結果或自動填入建議中。" }, - "itemWasSentToArchive": { - "message": "項目已移至封存" + "itemArchiveToast": { + "message": "Item archived" }, - "itemWasUnarchived": { - "message": "已取消封存項目" - }, - "itemUnarchived": { - "message": "項目取消封存" + "itemUnarchivedToast": { + "message": "Item unarchived" }, "bulkArchiveItems": { "message": "項目已封存" From 460b9ccb6730a3879061b49ccbee46c02080fac7 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Mon, 16 Feb 2026 12:42:56 +0100 Subject: [PATCH 19/23] Fix high CPU usage on flatpak (#19006) --- apps/desktop/resources/com.bitwarden.desktop.devel.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/desktop/resources/com.bitwarden.desktop.devel.yaml b/apps/desktop/resources/com.bitwarden.desktop.devel.yaml index 0f6e3ea370d..b708c07206b 100644 --- a/apps/desktop/resources/com.bitwarden.desktop.devel.yaml +++ b/apps/desktop/resources/com.bitwarden.desktop.devel.yaml @@ -53,4 +53,8 @@ modules: - export TMPDIR="$XDG_RUNTIME_DIR/app/$FLATPAK_ID" - export ZYPAK_LD_PRELOAD="/app/bin/libprocess_isolation.so" - export PROCESS_ISOLATION_LD_PRELOAD="/app/bin/libprocess_isolation.so" - - exec zypak-wrapper /app/bin/bitwarden-app "$@" + - PARAMS="--enable-features=UseOzonePlatform,WaylandWindowDecorations --ozone-platform-hint=auto" + - if [ "$USE_X11" != "false" ]; then + - PARAMS="--ozone-platform=x11" + - fi + - exec zypak-wrapper /app/bin/bitwarden-app "$@" "$PARAMS" From c415beb653b16d87e6ea6f989550cce3a494dac3 Mon Sep 17 00:00:00 2001 From: John Harrington <84741727+harr1424@users.noreply.github.com> Date: Mon, 16 Feb 2026 15:53:46 -0700 Subject: [PATCH 20/23] add password specific header (#18988) --- .../src/app/tools/send/send-access/send-auth.component.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/tools/send/send-access/send-auth.component.ts b/apps/web/src/app/tools/send/send-access/send-auth.component.ts index 22ab04bd9dd..8c630ce5315 100644 --- a/apps/web/src/app/tools/send/send-access/send-auth.component.ts +++ b/apps/web/src/app/tools/send/send-access/send-auth.component.ts @@ -73,7 +73,6 @@ export class SendAuthComponent implements OnInit { ) {} ngOnInit() { - this.updatePageTitle(); void this.onSubmit(); } @@ -226,6 +225,10 @@ export class SendAuthComponent implements OnInit { pageTitle: { key: "verifyYourEmailToViewThisSend" }, }); } + } else if (authType === AuthType.Password) { + this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ + pageTitle: { key: "sendAccessPasswordTitle" }, + }); } } } From 5623568a2f67c98deef45820bf98b3c02ea463a4 Mon Sep 17 00:00:00 2001 From: John Harrington <84741727+harr1424@users.noreply.github.com> Date: Mon, 16 Feb 2026 15:54:22 -0700 Subject: [PATCH 21/23] [PM-31620] Browser - Incorrect "Copy link" message when Send is shared with specific people (#18982) * add existing Send creation messages to browser * remove unused method and associated tests --- apps/browser/src/_locales/en/messages.json | 39 +++++++++ .../send-created/send-created.component.html | 8 +- .../send-created.component.spec.ts | 82 ++++++++++++++----- .../send-created/send-created.component.ts | 15 ++-- 4 files changed, 116 insertions(+), 28 deletions(-) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index e77550b01dc..a221dc4f338 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -3080,6 +3080,45 @@ } } }, + "durationTimeHours": { + "message": "$HOURS$ hours", + "placeholders": { + "hours": { + "content": "$1", + "example": "5" + } + } + }, + "sendCreatedDescriptionV2": { + "message": "Copy and share this Send link. The Send will be available to anyone with the link for the next $TIME$.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.", + "placeholders": { + "time": { + "content": "$1", + "example": "7 days, 1 hour, 1 day" + } + } + }, + "sendCreatedDescriptionPassword": { + "message": "Copy and share this Send link. The Send will be available to anyone with the link and password you set for the next $TIME$.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.", + "placeholders": { + "time": { + "content": "$1", + "example": "7 days, 1 hour, 1 day" + } + } + }, + "sendCreatedDescriptionEmail": { + "message": "Copy and share this Send link. It can be viewed by the people you specified for the next $TIME$.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.", + "placeholders": { + "time": { + "content": "$1", + "example": "7 days, 1 hour, 1 day" + } + } + }, "sendLinkCopied": { "message": "Send link copied", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." diff --git a/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.html b/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.html index 94c1df46eea..38ef7a4f1df 100644 --- a/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.html +++ b/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.html @@ -20,7 +20,13 @@ {{ "createdSendSuccessfully" | i18n }}

    - {{ formatExpirationDate() }} + @let translationKey = + send.authType === AuthType.Email + ? "sendCreatedDescriptionEmail" + : send.authType === AuthType.Password + ? "sendCreatedDescriptionPassword" + : "sendCreatedDescriptionV2"; + {{ translationKey | i18n: formattedExpirationTime }}