1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-26 17:43:22 +00:00

Merge branch 'main' into ps/extension-refresh

This commit is contained in:
Merissa Weinstein
2024-10-15 12:37:49 -05:00
84 changed files with 953 additions and 297 deletions

View File

@@ -105,7 +105,7 @@ export class AppComponent implements OnDestroy, OnInit {
.subscribe((supported) => {
if (!supported) {
this.logService.debug("SDK is not supported");
this.sdkService.failedToInitialize().catch(this.logService.error);
this.sdkService.failedToInitialize().catch((e) => this.logService.error(e));
} else {
this.logService.debug("SDK is supported");
}

View File

@@ -14,22 +14,24 @@ describe("freeTrialTextResolver", () => {
it("shows password manager text", () => {
route.queryParams.product = `${ProductType.PasswordManager}`;
expect(freeTrialTextResolver(route, routerStateSnapshot)).toBe(
"continueSettingUpFreeTrialPasswordManager",
);
expect(freeTrialTextResolver(route, routerStateSnapshot)).toEqual({
key: "continueSettingUpFreeTrialPasswordManager",
});
});
it("shows secret manager text", () => {
route.queryParams.product = `${ProductType.SecretsManager}`;
expect(freeTrialTextResolver(route, routerStateSnapshot)).toBe(
"continueSettingUpFreeTrialSecretsManager",
);
expect(freeTrialTextResolver(route, routerStateSnapshot)).toEqual({
key: "continueSettingUpFreeTrialSecretsManager",
});
});
it("shows default text", () => {
route.queryParams.product = `${ProductType.PasswordManager},${ProductType.SecretsManager}`;
expect(freeTrialTextResolver(route, routerStateSnapshot)).toBe("continueSettingUpFreeTrial");
expect(freeTrialTextResolver(route, routerStateSnapshot)).toEqual({
key: "continueSettingUpFreeTrial",
});
});
});

View File

@@ -1,10 +1,11 @@
import { ActivatedRouteSnapshot, ResolveFn } from "@angular/router";
import { ProductType } from "@bitwarden/common/billing/enums";
import { Translation } from "@bitwarden/components";
export const freeTrialTextResolver: ResolveFn<string | null> = (
export const freeTrialTextResolver: ResolveFn<Translation | null> = (
route: ActivatedRouteSnapshot,
): string | null => {
): Translation | null => {
const { product } = route.queryParams;
const products: ProductType[] = (product ?? "").split(",").map((p: string) => parseInt(p));
@@ -13,10 +14,16 @@ export const freeTrialTextResolver: ResolveFn<string | null> = (
switch (true) {
case onlyPasswordManager:
return "continueSettingUpFreeTrialPasswordManager";
return {
key: "continueSettingUpFreeTrialPasswordManager",
};
case onlySecretsManager:
return "continueSettingUpFreeTrialSecretsManager";
return {
key: "continueSettingUpFreeTrialSecretsManager",
};
default:
return "continueSettingUpFreeTrial";
return {
key: "continueSettingUpFreeTrial",
};
}
};

View File

@@ -228,7 +228,9 @@ const routes: Routes = [
path: "signup",
canActivate: [canAccessFeature(FeatureFlag.EmailVerification), unauthGuardFn()],
data: {
pageTitle: "createAccount",
pageTitle: {
key: "createAccount",
},
titleId: "createAccount",
} satisfies RouteDataProperties & AnonLayoutWrapperData,
children: [
@@ -250,8 +252,12 @@ const routes: Routes = [
path: "finish-signup",
canActivate: [canAccessFeature(FeatureFlag.EmailVerification), unauthGuardFn()],
data: {
pageTitle: "setAStrongPassword",
pageSubtitle: "finishCreatingYourAccountBySettingAPassword",
pageTitle: {
key: "setAStrongPassword",
},
pageSubtitle: {
key: "finishCreatingYourAccountBySettingAPassword",
},
titleId: "setAStrongPassword",
} satisfies RouteDataProperties & AnonLayoutWrapperData,
children: [
@@ -264,7 +270,9 @@ const routes: Routes = [
{
path: "send/:sendId/:key",
data: {
pageTitle: "viewSend",
pageTitle: {
key: "viewSend",
},
showReadonlyHostname: true,
} satisfies RouteDataProperties & AnonLayoutWrapperData,
children: [
@@ -284,15 +292,21 @@ const routes: Routes = [
canActivate: [canAccessFeature(FeatureFlag.EmailVerification)],
component: SetPasswordJitComponent,
data: {
pageTitle: "joinOrganization",
pageSubtitle: "finishJoiningThisOrganizationBySettingAMasterPassword",
pageTitle: {
key: "joinOrganization",
},
pageSubtitle: {
key: "finishJoiningThisOrganizationBySettingAMasterPassword",
},
} satisfies AnonLayoutWrapperData,
},
{
path: "signup-link-expired",
canActivate: [canAccessFeature(FeatureFlag.EmailVerification), unauthGuardFn()],
data: {
pageTitle: "expiredLink",
pageTitle: {
key: "expiredLink",
},
} satisfies AnonLayoutWrapperData,
children: [
{
@@ -308,7 +322,9 @@ const routes: Routes = [
path: "sso",
canActivate: [unauthGuardFn()],
data: {
pageTitle: "enterpriseSingleSignOn",
pageTitle: {
key: "enterpriseSingleSignOn",
},
titleId: "enterpriseSingleSignOn",
} satisfies RouteDataProperties & AnonLayoutWrapperData,
children: [
@@ -338,7 +354,9 @@ const routes: Routes = [
},
],
data: {
pageTitle: "logIn",
pageTitle: {
key: "logIn",
},
},
},
...extensionRefreshSwap(
@@ -354,7 +372,9 @@ const routes: Routes = [
},
],
data: {
pageTitle: "yourVaultIsLockedV2",
pageTitle: {
key: "yourVaultIsLockedV2",
},
pageIcon: LockIcon,
showReadonlyHostname: true,
} satisfies AnonLayoutWrapperData,
@@ -369,7 +389,9 @@ const routes: Routes = [
},
],
data: {
pageTitle: "yourAccountIsLocked",
pageTitle: {
key: "yourAccountIsLocked",
},
pageIcon: LockIcon,
showReadonlyHostname: true,
} satisfies AnonLayoutWrapperData,
@@ -390,7 +412,9 @@ const routes: Routes = [
},
],
data: {
pageTitle: "verifyIdentity",
pageTitle: {
key: "verifyIdentity",
},
} satisfies RouteDataProperties & AnonLayoutWrapperData,
},
{
@@ -408,7 +432,9 @@ const routes: Routes = [
},
],
data: {
pageTitle: "recoverAccountTwoStep",
pageTitle: {
key: "recoverAccountTwoStep",
},
titleId: "recoverAccountTwoStep",
} satisfies RouteDataProperties & AnonLayoutWrapperData,
},
@@ -416,7 +442,9 @@ const routes: Routes = [
path: "accept-emergency",
canActivate: [deepLinkGuard()],
data: {
pageTitle: "emergencyAccess",
pageTitle: {
key: "emergencyAccess",
},
titleId: "acceptEmergency",
doNotSaveUrl: false,
} satisfies RouteDataProperties & AnonLayoutWrapperData,
@@ -434,7 +462,9 @@ const routes: Routes = [
path: "recover-delete",
canActivate: [unauthGuardFn()],
data: {
pageTitle: "deleteAccount",
pageTitle: {
key: "deleteAccount",
},
titleId: "deleteAccount",
} satisfies RouteDataProperties & AnonLayoutWrapperData,
children: [
@@ -453,7 +483,9 @@ const routes: Routes = [
path: "verify-recover-delete",
canActivate: [unauthGuardFn()],
data: {
pageTitle: "deleteAccount",
pageTitle: {
key: "deleteAccount",
},
titleId: "deleteAccount",
} satisfies RouteDataProperties & AnonLayoutWrapperData,
children: [
@@ -468,7 +500,9 @@ const routes: Routes = [
component: RemovePasswordComponent,
canActivate: [authGuard],
data: {
pageTitle: "removeMasterPassword",
pageTitle: {
key: "removeMasterPassword",
},
titleId: "removeMasterPassword",
} satisfies RouteDataProperties & AnonLayoutWrapperData,
},

View File

@@ -157,8 +157,8 @@ export class AccessComponent implements OnInit {
if (this.creatorIdentifier != null) {
this.layoutWrapperDataService.setAnonLayoutWrapperData({
pageSubtitle: {
subtitle: this.i18nService.t("sendAccessCreatorIdentifier", this.creatorIdentifier),
translate: false,
key: "sendAccessCreatorIdentifier",
placeholders: [this.creatorIdentifier],
},
});
}

View File

@@ -1,5 +1,6 @@
<td bitCell [ngClass]="RowHeightClass" class="tw-min-w-fit">
<input
*ngIf="showCheckbox"
type="checkbox"
bitCheckbox
appStopProp

View File

@@ -42,6 +42,7 @@ export class VaultCipherRowComponent implements OnInit {
@Output() checkedToggled = new EventEmitter<void>();
protected CipherType = CipherType;
protected organization?: Organization;
constructor(private configService: ConfigService) {}
@@ -53,6 +54,9 @@ export class VaultCipherRowComponent implements OnInit {
this.extensionRefreshEnabled = await firstValueFrom(
this.configService.getFeatureFlag$(FeatureFlag.ExtensionRefresh),
);
if (this.cipher.organizationId != null) {
this.organization = this.organizations.find((o) => o.id === this.cipher.organizationId);
}
}
protected get showTotpCopyButton() {
@@ -138,4 +142,12 @@ export class VaultCipherRowComponent implements OnInit {
protected assignToCollections() {
this.onEvent.emit({ type: "assignToCollections", items: [this.cipher] });
}
protected get showCheckbox() {
if (!this.viewingOrgVault || !this.organization) {
return true; // Always show checkbox in individual vault or for non-org items
}
return this.organization.canEditAllCiphers || this.cipher.edit;
}
}

View File

@@ -103,6 +103,10 @@ export class VaultCollectionRowComponent {
}
protected get showCheckbox() {
return this.collection?.id !== Unassigned;
if (this.collection?.id === Unassigned) {
return false; // Never show checkbox for Unassigned
}
return this.canEditCollection || this.canDeleteCollection;
}
}

View File

@@ -1,7 +1,7 @@
import { SelectionModel } from "@angular/cdk/collections";
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { Unassigned, CollectionView } from "@bitwarden/admin-console/common";
import { CollectionView, Unassigned } from "@bitwarden/admin-console/common";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { TableDataSource } from "@bitwarden/components";
@@ -205,11 +205,12 @@ export class VaultItemsComponent {
this.selection.clear();
// Every item except for the Unassigned collection is selectable, individual bulk actions check the user's permission
// All ciphers are selectable, collections only if they can be edited or deleted
this.editableItems = items.filter(
(item) =>
item.cipher !== undefined ||
(item.collection !== undefined && item.collection.id !== Unassigned),
(item.collection !== undefined &&
(this.canEditCollection(item.collection) || this.canDeleteCollection(item.collection))),
);
this.dataSource.data = items;

View File

@@ -7922,6 +7922,15 @@
"message": "Your organization requires you to set a master password.",
"description": "Used as a card title description on the set password page to explain why the user is there"
},
"cardMetrics": {
"message": "out of $TOTAL$",
"placeholders": {
"total": {
"content": "$1",
"example": "5"
}
}
},
"notFound": {
"message": "$RESOURCE$ not found",
"placeholders": {