Remove the desktop-specific Archived badge from ItemDetailsV2Component (#20239) (#20277)

(cherry picked from commit f7475d8ad2)
This commit is contained in:
SmithThe4th 2026-04-20 14:56:09 -04:00 committed by GitHub
parent c80cc3f363
commit ed839b3c5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 28 deletions

View File

@ -2,12 +2,14 @@ import { ComponentRef } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { mock, MockProxy } from "jest-mock-extended";
import { of } from "rxjs";
import { BehaviorSubject, of } from "rxjs";
import { CollectionView } from "@bitwarden/common/admin-console/models/collections";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { ClientType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@ -21,6 +23,7 @@ describe("ItemDetailsV2Component", () => {
let fixture: ComponentFixture<ItemDetailsV2Component>;
let componentRef: ComponentRef<ItemDetailsV2Component>;
let mockPlatformUtilsService: MockProxy<PlatformUtilsService>;
let desktopMilestone3Flag$: BehaviorSubject<boolean>;
const cipher = {
id: "cipher1",
@ -52,18 +55,28 @@ describe("ItemDetailsV2Component", () => {
beforeEach(async () => {
mockPlatformUtilsService = mock<PlatformUtilsService>();
mockPlatformUtilsService.getClientType.mockReturnValue(ClientType.Web);
desktopMilestone3Flag$ = new BehaviorSubject<boolean>(false);
await TestBed.configureTestingModule({
imports: [ItemDetailsV2Component],
providers: [
{ provide: I18nService, useValue: { t: (key: string) => key } },
{ provide: PlatformUtilsService, useValue: { getClientType: () => ClientType.Web } },
{ provide: PlatformUtilsService, useValue: mockPlatformUtilsService },
{
provide: ConfigService,
useValue: {
getFeatureFlag$: (flag: FeatureFlag) =>
flag === FeatureFlag.DesktopUiMigrationMilestone3
? desktopMilestone3Flag$.asObservable()
: of(false),
},
},
{
provide: EnvironmentService,
useValue: { environment$: of({ getIconsUrl: () => "https://icons.example.com" }) },
},
{ provide: DomainSettingsService, useValue: { showFavicons$: of(true) } },
{ provide: PlatformUtilsService, useValue: mockPlatformUtilsService },
],
}).compileComponents();
});
@ -102,30 +115,37 @@ describe("ItemDetailsV2Component", () => {
expect(owner).toBeNull();
});
it("should show archive badge when cipher is archived and client is Desktop", () => {
jest.spyOn(mockPlatformUtilsService, "getClientType").mockReturnValue(ClientType.Desktop);
describe("showArchiveBadge", () => {
it("is true when cipher is archived on Desktop and DesktopUiMigrationMilestone3 is off", () => {
mockPlatformUtilsService.getClientType.mockReturnValue(ClientType.Desktop);
desktopMilestone3Flag$.next(false);
componentRef.setInput("cipher", { ...cipher, isArchived: true });
const archivedCipher = { ...cipher, isArchived: true };
componentRef.setInput("cipher", archivedCipher);
expect((component as any).showArchiveBadge()).toBe(true);
});
expect((component as any).showArchiveBadge()).toBe(true);
});
it("is false when DesktopUiMigrationMilestone3 is on (dialog renders its own badge)", () => {
mockPlatformUtilsService.getClientType.mockReturnValue(ClientType.Desktop);
desktopMilestone3Flag$.next(true);
componentRef.setInput("cipher", { ...cipher, isArchived: true });
it("should not show archive badge when cipher is not archived", () => {
jest.spyOn(mockPlatformUtilsService, "getClientType").mockReturnValue(ClientType.Desktop);
expect((component as any).showArchiveBadge()).toBe(false);
});
const unarchivedCipher = { ...cipher, isArchived: false };
componentRef.setInput("cipher", unarchivedCipher);
it("is false when cipher is not archived", () => {
mockPlatformUtilsService.getClientType.mockReturnValue(ClientType.Desktop);
desktopMilestone3Flag$.next(false);
componentRef.setInput("cipher", { ...cipher, isArchived: false });
expect((component as any).showArchiveBadge()).toBe(false);
});
expect((component as any).showArchiveBadge()).toBe(false);
});
it("should not show archive badge when client is not Desktop", () => {
jest.spyOn(mockPlatformUtilsService, "getClientType").mockReturnValue(ClientType.Web);
it("is false when client is not Desktop", () => {
mockPlatformUtilsService.getClientType.mockReturnValue(ClientType.Web);
desktopMilestone3Flag$.next(false);
componentRef.setInput("cipher", { ...cipher, isArchived: true });
const archivedCipher = { ...cipher, isArchived: true };
componentRef.setInput("cipher", archivedCipher);
expect((component as any).showArchiveBadge()).toBe(false);
expect((component as any).showArchiveBadge()).toBe(false);
});
});
});

View File

@ -1,10 +1,10 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { Component, computed, input, signal } from "@angular/core";
import { Component, computed, inject, input, signal } from "@angular/core";
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
import { toSignal } from "@angular/core/rxjs-interop";
import { fromEvent, map, startWith } from "rxjs";
import { fromEvent, map, of, startWith } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { ClientType } from "@bitwarden/client-type";
@ -13,6 +13,8 @@ import {
CollectionTypes,
} from "@bitwarden/common/admin-console/models/collections";
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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
@ -91,16 +93,23 @@ export class ItemDetailsV2Component {
}
});
private readonly platformUtilsService = inject(PlatformUtilsService);
private readonly configService = inject(ConfigService);
private readonly desktopMilestone3Enabled = toSignal(
this.configService.getFeatureFlag$(FeatureFlag.DesktopUiMigrationMilestone3) ?? of(false),
);
protected readonly showArchiveBadge = computed(() => {
return (
this.cipher().isArchived && this.platformUtilsService.getClientType() === ClientType.Desktop
this.cipher().isArchived &&
this.platformUtilsService.getClientType() === ClientType.Desktop &&
!this.desktopMilestone3Enabled()
);
});
constructor(
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService,
) {}
constructor(private i18nService: I18nService) {}
toggleShowMore() {
this.showAllDetails.update((value) => !value);

View File

@ -33,6 +33,7 @@ import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values";
import { CipherViewLike } from "@bitwarden/common/vault/utils/cipher-view-like-utils";
import {
AsyncActionsModule,
BadgeModule,
BitIconButtonComponent,
ButtonModule,
CenterPositionStrategy,
@ -130,6 +131,7 @@ export type VaultItemDialogResult = UnionOfValues<typeof VaultItemDialogResult>;
CommonModule,
CipherFormModule,
AsyncActionsModule,
BadgeModule,
ItemModule,
PremiumBadgeComponent,
I18nPipe,