1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-14 07:23:45 +00:00

refactor(change-password-component): Change Password Update [18720] - Just about done with changes. Need to get the filtering working.

This commit is contained in:
Patrick Pimentel
2025-05-05 09:57:32 -04:00
parent c6d88928a2
commit 31a3694746
10 changed files with 171 additions and 15 deletions

View File

@@ -1948,6 +1948,12 @@
"permanentlyDeletedItem": {
"message": "Item permanently deleted"
},
"archiveItem": {
"message": "Item archived"
},
"unarchiveItem": {
"message": "Item unarchived"
},
"restoredItem": {
"message": "Item restored"
},

View File

@@ -7,7 +7,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { CollectionId, UserId } from "@bitwarden/common/types/guid";
import { CipherId, CollectionId, UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherRepromptType } from "@bitwarden/common/vault/enums";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
@@ -28,6 +28,8 @@ export class ItemFooterComponent implements OnInit {
@Input() isSubmitting: boolean = false;
@Output() onEdit = new EventEmitter<CipherView>();
@Output() onClone = new EventEmitter<CipherView>();
@Output() onArchive = new EventEmitter<CipherView>();
@Output() onUnarchive = new EventEmitter<CipherView>();
@Output() onDelete = new EventEmitter<CipherView>();
@Output() onRestore = new EventEmitter<CipherView>();
@Output() onCancel = new EventEmitter<CipherView>();
@@ -85,6 +87,58 @@ export class ItemFooterComponent implements OnInit {
this.onCancel.emit(this.cipher);
}
async archive(): Promise<boolean> {
if (!(await this.promptPassword())) {
return false;
}
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "archiveItem" },
content: {
key: "archiveItemConfirmation",
},
type: "warning",
});
if (!confirmed) {
return false;
}
try {
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
await this.cipherService.archiveWithServer(this.cipher.id as CipherId, activeUserId);
this.toastService.showToast({
variant: "success",
message: this.i18nService.t("archivedItem"),
});
this.onArchive.emit(this.cipher);
} catch (e) {
this.logService.error(e);
}
return true;
}
async unarchive(): Promise<boolean> {
if (!this.cipher.isArchived) {
return false;
}
try {
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
await this.cipherService.unarchiveWithServer(this.cipher.id as CipherId, activeUserId)
this.toastService.showToast({
variant: "success",
message: this.i18nService.t("unarchivedItem"),
});
this.onUnarchive.emit(this.cipher);
} catch (e) {
this.logService.error(e);
}
return true;
}
async delete(): Promise<boolean> {
if (!(await this.promptPassword())) {
return false;

View File

@@ -29,6 +29,7 @@
</button>
</span>
</li>
<!-- What is going on here? -->
<li
class="filter-option"
*ngIf="!hideArchive"

View File

@@ -15,9 +15,11 @@
[cipher]="cipher"
[action]="action"
(onEdit)="editCipher($event)"
(onArchive)="archiveCipher()"
(onUnarchive)="unarchiveCipher()"
(onDelete)="deleteCipher()"
(onRestore)="restoreCipher()"
(onClone)="cloneCipher($event)"
(onDelete)="deleteCipher()"
(onCancel)="cancelCipher($event)"
></app-vault-item-footer>
<div class="content">

View File

@@ -73,6 +73,7 @@ import { ItemFooterComponent } from "./item-footer.component";
import { VaultFilterComponent } from "./vault-filter/vault-filter.component";
import { VaultFilterModule } from "./vault-filter/vault-filter.module";
import { VaultItemsV2Component } from "./vault-items-v2.component";
import { CipherStatus } from "@bitwarden/angular/vault/vault-filter/models/cipher-status.model";
const BroadcasterSubscriptionId = "VaultComponent";
@@ -299,7 +300,7 @@ export class VaultV2Component implements OnInit, OnDestroy {
this.cipherService
.failedToDecryptCiphers$(this.activeUserId)
.pipe(
map((ciphers) => ciphers?.filter((c) => !c.isDeleted) ?? []),
map((ciphers) => ciphers?.filter((c) => !c.isDeleted || !c.isArchived) ?? []),
filter((ciphers) => ciphers.length > 0),
take(1),
takeUntil(this.componentIsDestroyed$),
@@ -336,8 +337,18 @@ export class VaultV2Component implements OnInit, OnDestroy {
await this.addCipher(this.addType).catch(() => {});
}
let cipherStatus: CipherStatus = "all";
if (params.deleted) {
cipherStatus = "trash";
} else if (params.archived){
cipherStatus = "archive";
} else if (params.favorites){
cipherStatus = "favorites";
}
this.activeFilter = new VaultFilter({
status: params.deleted ? "trash" : params.favorites ? "favorites" : "all",
status: cipherStatus,
cipherType:
params.action === "add" || params.type == null
? undefined
@@ -558,6 +569,21 @@ export class VaultV2Component implements OnInit, OnDestroy {
await this.vaultItemsComponent?.refresh().catch(() => {});
}
async archiveCipher() {
this.cipherId = null;
this.cipher = null;
this.action = null;
await this.go().catch(() => {});
await this.vaultItemsComponent?.refresh().catch(() => {});
}
async unarchiveCipher() {
this.cipherId = null;
this.action = null;
await this.go().catch(() => {});
await this.vaultItemsComponent?.refresh().catch(() => {});
}
async deleteCipher() {
this.cipherId = null;
this.cipher = null;

View File

@@ -18,6 +18,8 @@
(onCloneCipher)="cloneCipherWithoutPasswordPrompt($event)"
(onEditCipher)="editCipher($event)"
(onViewCipherPasswordHistory)="viewCipherPasswordHistory($event)"
(onArchivedCipher)="archivedCipher($event)"
(onUnarchivedCipher)="unarchivedCipher($event)"
(onRestoredCipher)="restoredCipher($event)"
(onDeletedCipher)="deletedCipher($event)"
>

View File

@@ -51,6 +51,7 @@ import { ShareComponent } from "./share.component";
import { VaultFilterComponent } from "./vault-filter/vault-filter.component";
import { VaultItemsComponent } from "./vault-items.component";
import { ViewComponent } from "./view.component";
import { CipherStatus } from "@bitwarden/angular/vault/vault-filter/models/cipher-status.model";
const BroadcasterSubscriptionId = "VaultComponent";
@@ -247,7 +248,7 @@ export class VaultComponent implements OnInit, OnDestroy {
this.cipherService
.failedToDecryptCiphers$(this.activeUserId)
.pipe(
map((ciphers) => ciphers?.filter((c) => !c.isDeleted) ?? []),
map((ciphers) => ciphers?.filter((c) => !c.isDeleted || !c.isArchived) ?? []),
filter((ciphers) => ciphers.length > 0),
take(1),
takeUntil(this.componentIsDestroyed$),
@@ -286,8 +287,18 @@ export class VaultComponent implements OnInit, OnDestroy {
this.addCipher(this.addType);
}
let cipherStatus: CipherStatus = "all";
if (params.deleted) {
cipherStatus = "trash";
} else if (params.archived){
cipherStatus = "archive";
} else if (params.favorites){
cipherStatus = "favorites";
}
this.activeFilter = new VaultFilter({
status: params.deleted ? "trash" : params.favorites ? "favorites" : "all",
status: cipherStatus,
cipherType:
params.action === "add" || params.type == null ? null : parseInt(params.type, null),
selectedFolderId: params.folderId,
@@ -524,6 +535,20 @@ export class VaultComponent implements OnInit, OnDestroy {
await this.vaultItemsComponent.refresh();
}
async archivedCipher(cipher: CipherView) {
this.cipherId = null;
this.action = null;
this.go();
await this.vaultItemsComponent.refresh();
}
async unarchivedCipher(cipher: CipherView) {
this.cipherId = null;
this.action = null;
this.go();
await this.vaultItemsComponent.refresh();
}
async restoredCipher(cipher: CipherView) {
this.cipherId = null;
this.action = null;

View File

@@ -651,6 +651,15 @@
>
<i class="bwi bwi-pencil bwi-fw bwi-lg" aria-hidden="true"></i>
</button>
<button
type="button"
(click)="unarchive()"
class="primary"
[appA11yTitle]="'archive' | i18n"
*ngIf="cipher.isArchived"
>
<i class="bwi bwi-undo bwi-lg bwi-fw" aria-hidden="true"></i>
</button>
<button
type="button"
class="primary"
@@ -675,16 +684,20 @@
</button>
</ng-container>
<div class="right">
<button type="button" (click)="archive()" class="danger" [appA11yTitle]="'archive' | i18n">
<button
type="button"
(click)="archive()"
class="danger"
[appA11yTitle]="'archive' | i18n"
>
<i class="bwi bwi-archive bwi-lg bwi-fw" aria-hidden="true"></i>
</button>
</div>
<div class="right" *ngIf="canDeleteCipher$ | async">
<button
type="button"
(click)="delete()"
class="danger"
appA11yTitle="{{ (cipher.isDeleted ? 'permanentlyDelete' : 'delete') | i18n }}"
*ngIf="canDeleteCipher$ | async"
>
<i class="bwi bwi-trash bwi-lg bwi-fw" aria-hidden="true"></i>
</button>

View File

@@ -40,7 +40,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { EncArrayBuffer } from "@bitwarden/common/platform/models/domain/enc-array-buffer";
import { CollectionId, UserId } from "@bitwarden/common/types/guid";
import { CipherId, CollectionId, UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
@@ -76,6 +76,8 @@ export class ViewComponent implements OnDestroy, OnInit {
@Output() onEditCipher = new EventEmitter<CipherView>();
@Output() onCloneCipher = new EventEmitter<CipherView>();
@Output() onShareCipher = new EventEmitter<CipherView>();
@Output() onArchivedCipher = new EventEmitter<CipherView>();
@Output() onUnarchivedCipher = new EventEmitter<CipherView>();
@Output() onDeletedCipher = new EventEmitter<CipherView>();
@Output() onRestoredCipher = new EventEmitter<CipherView>();
@@ -231,15 +233,34 @@ export class ViewComponent implements OnDestroy, OnInit {
try {
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
await this.deleteCipher(activeUserId);
await this.cipherService.archiveWithServer(this.cipher.id as CipherId, activeUserId);
this.toastService.showToast({
variant: "success",
title: null,
message: this.i18nService.t(
this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem",
),
message: this.i18nService.t("archivedItem"),
});
this.onDeletedCipher.emit(this.cipher);
this.onArchivedCipher.emit(this.cipher);
} catch (e) {
this.logService.error(e);
}
return true;
}
async unarchive(): Promise<boolean> {
if (!this.cipher.isArchived) {
return false;
}
try {
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
await this.cipherService.unarchiveWithServer(this.cipher.id as CipherId, activeUserId)
this.toastService.showToast({
variant: "success",
title: null,
message: this.i18nService.t("unarchivedItem"),
});
this.onUnarchivedCipher.emit(this.cipher);
} catch (e) {
this.logService.error(e);
}

View File

@@ -39,10 +39,16 @@ export class VaultFilter {
buildFilter(): VaultFilterFunction {
return (cipher) => {
console.log(cipher);
console.log(this.status);
let cipherPassesFilter = true;
if (this.status === "favorites" && cipherPassesFilter) {
cipherPassesFilter = cipher.favorite;
}
if (this.status === "archive" && cipherPassesFilter) {
cipherPassesFilter = cipher.isArchived;
}
if (this.status === "trash" && cipherPassesFilter) {
cipherPassesFilter = cipher.isDeleted;
}