mirror of
https://github.com/bitwarden/browser
synced 2026-02-22 12:24:01 +00:00
Merge branch 'main' into nathan/fix-autofill-signing
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bitwarden/browser",
|
||||
"version": "2025.1.4",
|
||||
"version": "2025.1.3",
|
||||
"scripts": {
|
||||
"build": "npm run build:chrome",
|
||||
"build:chrome": "cross-env BROWSER=chrome MANIFEST_VERSION=3 NODE_OPTIONS=\"--max-old-space-size=8192\" webpack",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 2,
|
||||
"name": "__MSG_extName__",
|
||||
"short_name": "__MSG_appName__",
|
||||
"version": "2025.1.4",
|
||||
"version": "2025.1.3",
|
||||
"description": "__MSG_extDesc__",
|
||||
"default_locale": "en",
|
||||
"author": "Bitwarden Inc.",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"minimum_chrome_version": "102.0",
|
||||
"name": "__MSG_extName__",
|
||||
"short_name": "__MSG_appName__",
|
||||
"version": "2025.1.4",
|
||||
"version": "2025.1.3",
|
||||
"description": "__MSG_extDesc__",
|
||||
"default_locale": "en",
|
||||
"author": "Bitwarden Inc.",
|
||||
|
||||
@@ -26,61 +26,47 @@
|
||||
{{ "nonCompliantMembersError" | i18n }}
|
||||
</bit-callout>
|
||||
|
||||
<ng-template #userDisplay let-user>
|
||||
<div class="tw-flex tw-items-center">
|
||||
<div class="tw-mr-6">
|
||||
<bit-avatar [text]="user | userName" [id]="user.id" size="small"></bit-avatar>
|
||||
</div>
|
||||
<ng-container *ngIf="user.name; else emailOnly">
|
||||
<div class="tw-truncate" [title]="user.name + ' ' + user.email">
|
||||
{{ user.name }}
|
||||
<small class="tw-block tw-text-muted tw-truncate">
|
||||
{{ user.email }}
|
||||
</small>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-template #emailOnly>
|
||||
<div class="tw-truncate" [title]="user.email">{{ user.email }}</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-container *ngIf="!done">
|
||||
<bit-callout type="warning" *ngIf="users.length > 0 && !error && isRevoking">
|
||||
<p>{{ "revokeUsersWarning" | i18n }}</p>
|
||||
</bit-callout>
|
||||
|
||||
<bit-table *ngIf="accountDeprovisioning.enabled">
|
||||
<bit-table>
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell class="tw-w-1/2">{{ "member" | i18n }}</th>
|
||||
<th bitCell *ngIf="this.showNoMasterPasswordWarning">{{ "details" | i18n }}</th>
|
||||
<th bitCell>{{ (accountDeprovisioning.enabled ? "member" : "user") | i18n }}</th>
|
||||
<th bitCell class="tw-w-1/2" *ngIf="this.showNoMasterPasswordWarning">
|
||||
{{ "details" | i18n }}
|
||||
</th>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<ng-template body>
|
||||
<tr bitRow *ngFor="let user of users">
|
||||
<td bitCell width="30">
|
||||
<div class="tw-flex tw-items-center">
|
||||
<div class="tw-flex tw-items-center tw-mr-6">
|
||||
<bit-avatar [text]="user | userName" [id]="user.id" size="small"></bit-avatar>
|
||||
</div>
|
||||
<div>
|
||||
{{ user.email }}
|
||||
<small class="tw-block tw-text-muted" *ngIf="user.name">{{ user.name }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<td bitCell class="tw-max-w-0">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="userDisplay; context: { $implicit: user }"
|
||||
></ng-container>
|
||||
</td>
|
||||
<td bitCell *ngIf="this.showNoMasterPasswordWarning">
|
||||
<span class="tw-block tw-lowercase tw-text-muted">
|
||||
<ng-container *ngIf="user.hasMasterPassword === true"> - </ng-container>
|
||||
<ng-container *ngIf="user.hasMasterPassword === false">
|
||||
<i class="bwi bwi-exclamation-triangle" aria-hidden="true"></i>
|
||||
{{ "noMasterPassword" | i18n }}
|
||||
</ng-container>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</bit-table>
|
||||
|
||||
<bit-table *ngIf="!accountDeprovisioning.enabled">
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell colspan="2">{{ "user" | i18n }}</th>
|
||||
<th bitCell *ngIf="this.showNoMasterPasswordWarning">{{ "details" | i18n }}</th>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<ng-template body>
|
||||
<tr bitRow *ngFor="let user of users">
|
||||
<td bitCell width="30">
|
||||
<bit-avatar [text]="user | userName" [id]="user.id" size="small"></bit-avatar>
|
||||
</td>
|
||||
<td bitCell>
|
||||
{{ user.email }}
|
||||
<small class="tw-block tw-text-muted" *ngIf="user.name">{{ user.name }}</small>
|
||||
</td>
|
||||
<td bitCell *ngIf="this.showNoMasterPasswordWarning">
|
||||
<td bitCell class="tw-w-1/2" *ngIf="this.showNoMasterPasswordWarning">
|
||||
<span class="tw-block tw-lowercase tw-text-muted">
|
||||
<ng-container *ngIf="user.hasMasterPassword === true"> - </ng-container>
|
||||
<ng-container *ngIf="user.hasMasterPassword === false">
|
||||
@@ -95,55 +81,21 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="done">
|
||||
<bit-table *ngIf="accountDeprovisioning.enabled">
|
||||
<bit-table>
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell class="tw-w-1/2">{{ "member" | i18n }}</th>
|
||||
<th bitCell>{{ "status" | i18n }}</th>
|
||||
<th bitCell class="tw-w-1/2">
|
||||
{{ (accountDeprovisioning.enabled ? "member" : "user") | i18n }}
|
||||
</th>
|
||||
<th bitCell class="tw-w-1/2">{{ "status" | i18n }}</th>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<ng-template body>
|
||||
<tr bitRow *ngFor="let user of users">
|
||||
<td bitCell width="30">
|
||||
<div class="tw-flex tw-items-center">
|
||||
<div class="tw-flex tw-items-center tw-mr-6">
|
||||
<bit-avatar [text]="user | userName" [id]="user.id" size="small"></bit-avatar>
|
||||
</div>
|
||||
<div>
|
||||
{{ user.email }}
|
||||
<small class="tw-block tw-text-muted" *ngIf="user.name">{{ user.name }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td bitCell *ngIf="statuses.has(user.id)">
|
||||
{{ statuses.get(user.id) }}
|
||||
</td>
|
||||
<td bitCell *ngIf="!statuses.has(user.id)">
|
||||
{{ "bulkFilteredMessage" | i18n }}
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</bit-table>
|
||||
|
||||
<bit-table *ngIf="!accountDeprovisioning.enabled">
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell class="tw-w-1/2">{{ "member" | i18n }}</th>
|
||||
<th bitCell>{{ "status" | i18n }}</th>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<ng-template body>
|
||||
<tr bitRow *ngFor="let user of users">
|
||||
<td bitCell width="30">
|
||||
<div class="tw-flex tw-items-center">
|
||||
<div class="tw-flex tw-items-center tw-mr-6">
|
||||
<bit-avatar [text]="user | userName" [id]="user.id" size="small"></bit-avatar>
|
||||
</div>
|
||||
<div>
|
||||
{{ user.email }}
|
||||
<small class="tw-block tw-text-muted" *ngIf="user.name">{{ user.name }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<td bitCell class="tw-max-w-0">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="userDisplay; context: { $implicit: user }"
|
||||
></ng-container>
|
||||
</td>
|
||||
<td bitCell *ngIf="statuses.has(user.id)">
|
||||
{{ statuses.get(user.id) }}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ProviderService } from "@bitwarden/common/admin-console/abstractions/pr
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
@@ -24,6 +25,7 @@ describe("ProductSwitcherService", () => {
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let providerService: MockProxy<ProviderService>;
|
||||
let accountService: FakeAccountService;
|
||||
let platformUtilsService: MockProxy<PlatformUtilsService>;
|
||||
let activeRouteParams = convertToParamMap({ organizationId: "1234" });
|
||||
const getLastSync = jest.fn().mockResolvedValue(new Date("2024-05-14"));
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
@@ -43,11 +45,13 @@ describe("ProductSwitcherService", () => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
providerService = mock<ProviderService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
platformUtilsService = mock<PlatformUtilsService>();
|
||||
|
||||
router.url = "/";
|
||||
router.events = of({});
|
||||
organizationService.organizations$.mockReturnValue(of([{}] as Organization[]));
|
||||
providerService.getAll.mockResolvedValue([] as Provider[]);
|
||||
platformUtilsService.isSelfHost.mockReturnValue(false);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
@@ -55,6 +59,7 @@ describe("ProductSwitcherService", () => {
|
||||
{ provide: OrganizationService, useValue: organizationService },
|
||||
{ provide: ProviderService, useValue: providerService },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
{ provide: PlatformUtilsService, useValue: platformUtilsService },
|
||||
{
|
||||
provide: ActivatedRoute,
|
||||
useValue: {
|
||||
@@ -138,11 +143,31 @@ describe("ProductSwitcherService", () => {
|
||||
});
|
||||
|
||||
describe("Admin/Organizations", () => {
|
||||
it("includes Organizations in other when there are organizations", async () => {
|
||||
it("includes Organizations with the internal route in other when there are organizations on cloud", async () => {
|
||||
initiateService();
|
||||
|
||||
const products = await firstValueFrom(service.products$);
|
||||
|
||||
const organizations = products.other.find((p) => p.name === "Organizations");
|
||||
expect(organizations).toBeDefined();
|
||||
expect(organizations.marketingRoute.route).toBe("/create-organization");
|
||||
expect(organizations.marketingRoute.external).toBe(false);
|
||||
|
||||
expect(products.other.find((p) => p.name === "Organizations")).toBeDefined();
|
||||
expect(products.bento.find((p) => p.name === "Admin Console")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("includes Organizations with the external route in other when there are organizations on Self-Host", async () => {
|
||||
platformUtilsService.isSelfHost.mockReturnValue(true);
|
||||
initiateService();
|
||||
|
||||
const products = await firstValueFrom(service.products$);
|
||||
|
||||
const organizations = products.other.find((p) => p.name === "Organizations");
|
||||
expect(organizations).toBeDefined();
|
||||
expect(organizations.marketingRoute.route).toBe("https://bitwarden.com/products/business/");
|
||||
expect(organizations.marketingRoute.external).toBe(true);
|
||||
|
||||
expect(products.other.find((p) => p.name === "Organizations")).toBeDefined();
|
||||
expect(products.bento.find((p) => p.name === "Admin Console")).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
|
||||
export type ProductSwitcherItem = {
|
||||
@@ -101,6 +102,7 @@ export class ProductSwitcherService {
|
||||
private i18n: I18nPipe,
|
||||
private syncService: SyncService,
|
||||
private accountService: AccountService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
) {
|
||||
this.pollUntilSynced();
|
||||
}
|
||||
@@ -151,6 +153,16 @@ export class ProductSwitcherService {
|
||||
// TODO: This should be migrated to an Observable provided by the provider service and moved to the combineLatest above. See AC-2092.
|
||||
const providers = await this.providerService.getAll();
|
||||
|
||||
const orgsMarketingRoute = this.platformUtilsService.isSelfHost()
|
||||
? {
|
||||
route: "https://bitwarden.com/products/business/",
|
||||
external: true,
|
||||
}
|
||||
: {
|
||||
route: "/create-organization",
|
||||
external: false,
|
||||
};
|
||||
|
||||
const products = {
|
||||
pm: {
|
||||
name: "Password Manager",
|
||||
@@ -197,10 +209,7 @@ export class ProductSwitcherService {
|
||||
orgs: {
|
||||
name: "Organizations",
|
||||
icon: "bwi-business",
|
||||
marketingRoute: {
|
||||
route: "https://bitwarden.com/products/business/",
|
||||
external: true,
|
||||
},
|
||||
marketingRoute: orgsMarketingRoute,
|
||||
otherProductOverrides: {
|
||||
name: "Share your passwords",
|
||||
supportingText: this.i18n.transform("protectYourFamilyOrBusiness"),
|
||||
|
||||
Reference in New Issue
Block a user