Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions apps/browser/src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -550,10 +550,15 @@
"resetSearch": {
"message": "Reset search"
},
"archive": {
"message": "Archive"
"archiveVerb": {
"message": "Archive",
"descripton": "Verb"
},
"unarchive": {
"archiveNoun": {
"message": "Archive",
"descripton": "Noun"
},
"unArchive": {
"message": "Unarchive"
},
"itemsInArchive": {
Expand All @@ -565,11 +570,11 @@
"noItemsInArchiveDesc": {
"message": "Archived items will appear here and will be excluded from general search results and autofill suggestions."
},
"itemSentToArchive": {
"message": "Item sent to archive"
"itemWasSentToArchive": {
"message": "Item was sent to archive"
},
"itemRemovedFromArchive": {
"message": "Item removed from archive"
"itemUnarchived": {
"message": "Item was unarchived"
},
"archiveItem": {
"message": "Archive item"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</ng-container>
@if (canArchive$ | async) {
<button type="button" bitMenuItem (click)="archive()" *ngIf="canArchive$ | async">
{{ "archive" | i18n }}
{{ "archiveVerb" | i18n }}
</button>
}
</bit-menu>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export class ItemMoreOptionsComponent {
await this.cipherArchiveService.archiveWithServer(this.cipher.id as CipherId, activeUserId);
this.toastService.showToast({
variant: "success",
message: this.i18nService.t("itemSentToArchive"),
message: this.i18nService.t("itemWasSentToArchive"),
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ <h2 bitTypography="h6">
{{ "clone" | i18n }}
</button>
<button type="button" bitMenuItem (click)="unarchive(cipher)">
{{ "unarchive" | i18n }}
{{ "unArchive" | i18n }}
</button>
<button
type="button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export class ArchiveComponent {

this.toastService.showToast({
variant: "success",
message: this.i18nService.t("itemRemovedFromArchive"),
message: this.i18nService.t("itemUnarchived"),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
@if (userCanArchive() || showArchiveFilter()) {
<bit-item>
<a bit-item-content routerLink="/archive">
{{ "archive" | i18n }}
{{ "archiveNoun" | i18n }}
<i slot="end" class="bwi bwi-angle-right" aria-hidden="true"></i>
</a>
</bit-item>
Expand Down
19 changes: 12 additions & 7 deletions apps/desktop/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -4114,10 +4114,15 @@
"editShortcut": {
"message": "Edit shortcut"
},
"archive": {
"message": "Archive"
"archiveVerb": {
"message": "Archive",
"descripton": "Verb"
},
"unarchive": {
"archiveNoun": {
"message": "Archive",
"descripton": "Noun"
},
"unArchive": {
"message": "Unarchive"
},
"itemsInArchive": {
Expand All @@ -4129,11 +4134,11 @@
"noItemsInArchiveDesc": {
"message": "Archived items will appear here and will be excluded from general search results and autofill suggestions."
},
"itemSentToArchive": {
"message": "Item sent to archive"
"itemWasSentToArchive": {
"message": "Item was sent to archive"
},
"itemRemovedFromArchive": {
"message": "Item removed from archive"
"itemUnarchived": {
"message": "Item was unarchived"
},
"archiveItem": {
"message": "Archive item"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,20 @@
<i class="bwi bwi-fw bwi-file-text" aria-hidden="true"></i>
{{ "eventLogs" | i18n }}
</button>
@if (showArchiveButton) {
<button bitMenuItem (click)="archive()" type="button">
<i class="bwi bwi-fw bwi-archive" aria-hidden="true"></i>
{{ "archiveVerb" | i18n }}
</button>
}

@if (showUnArchiveButton) {
<button bitMenuItem (click)="unarchive()" type="button">
<i class="bwi bwi-fw bwi-archive" aria-hidden="true"></i>
{{ "unArchive" | i18n }}
</button>
}

<button bitMenuItem (click)="restore()" type="button" *ngIf="isDeleted && canRestoreCipher">
<i class="bwi bwi-fw bwi-undo" aria-hidden="true"></i>
{{ "restore" | i18n }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ export class VaultCipherRowComponent<C extends CipherViewLike> implements OnInit
* uses new permission restore logic from PM-15493
*/
@Input() canRestoreCipher: boolean;
/**
* user has archive permissions
*/
@Input() userCanArchive: boolean;
/**
* Enforge Org Data Ownership Policy Status
*/
@Input() enforceOrgDataOwnershipPolicy: boolean;

@Output() onEvent = new EventEmitter<VaultItemEvent<C>>();

Expand Down Expand Up @@ -76,6 +84,19 @@ export class VaultCipherRowComponent<C extends CipherViewLike> implements OnInit
}
}

protected get showArchiveButton() {
return (
this.userCanArchive &&
!CipherViewLikeUtils.isArchived(this.cipher) &&
!this.cipher.organizationId
);
}

// If item is archived always show unarchive button, even if user is not premium
protected get showUnArchiveButton() {
return CipherViewLikeUtils.isArchived(this.cipher);
}

protected get clickAction() {
if (this.decryptionFailure) {
return "showFailedToDecrypt";
Expand All @@ -100,7 +121,12 @@ export class VaultCipherRowComponent<C extends CipherViewLike> implements OnInit
return CipherViewLikeUtils.hasAttachments(this.cipher);
}

// Do not show attachments button if:
// item is archived AND user is not premium user
protected get showAttachments() {
if (CipherViewLikeUtils.isArchived(this.cipher) && !this.userCanArchive) {
return false;
}
return this.canEditCipher || this.hasAttachments;
}

Expand Down Expand Up @@ -132,7 +158,16 @@ export class VaultCipherRowComponent<C extends CipherViewLike> implements OnInit
);
}

// Do NOT show clone button if:
// item is archived AND user is not premium user
// item is archived AND enforce org data ownership policy is on
protected get showClone() {
if (
CipherViewLikeUtils.isArchived(this.cipher) &&
(!this.userCanArchive || this.enforceOrgDataOwnershipPolicy)
) {
return false;
}
return this.cloneable && !CipherViewLikeUtils.isDeleted(this.cipher);
}

Expand Down Expand Up @@ -236,6 +271,14 @@ export class VaultCipherRowComponent<C extends CipherViewLike> implements OnInit
this.onEvent.emit({ type: "viewEvents", item: this.cipher });
}

protected archive() {
this.onEvent.emit({ type: "archive", items: [this.cipher] });
}

protected unarchive() {
this.onEvent.emit({ type: "unarchive", items: [this.cipher] });
}

protected restore() {
this.onEvent.emit({ type: "restore", items: [this.cipher] });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ export type VaultItemEvent<C extends CipherViewLike> =
| { type: "delete"; items: VaultItem<C>[] }
| { type: "copyField"; item: C; field: "username" | "password" | "totp" }
| { type: "moveToFolder"; items: C[] }
| { type: "assignToCollections"; items: C[] };
| { type: "assignToCollections"; items: C[] }
| { type: "archive"; items: C[] }
| { type: "unarchive"; items: C[] };
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,22 @@
<i class="bwi bwi-fw bwi-collection-shared" aria-hidden="true"></i>
{{ "assignToCollections" | i18n }}
</button>

<button *ngIf="bulkArchiveAllowed" type="button" bitMenuItem (click)="bulkArchive()">
<i class="bwi bwi-fw bwi-archive" aria-hidden="true"></i>
{{ "archiveVerb" | i18n }}
</button>

<button
*ngIf="bulkUnarchiveAllowed"
type="button"
bitMenuItem
(click)="bulkUnarchive()"
>
<i class="bwi bwi-fw bwi-archive" aria-hidden="true"></i>
{{ "unArchive" | i18n }}
</button>

<button
*ngIf="canRestoreSelected$ | async"
type="button"
Expand Down Expand Up @@ -161,6 +177,8 @@
"
(checkedToggled)="selection.toggle(item)"
(onEvent)="event($event)"
[userCanArchive]="userCanArchive"
[enforceOrgDataOwnershipPolicy]="enforceOrgDataOwnershipPolicy"
></tr>
</ng-container>
</ng-template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export class VaultItemsComponent<C extends CipherViewLike> {
@Input() addAccessStatus: number;
@Input() addAccessToggle: boolean;
@Input() activeCollection: CollectionView | undefined;
@Input() userCanArchive: boolean;
@Input() enforceOrgDataOwnershipPolicy: boolean;

private restrictedPolicies = toSignal(this.restrictedItemTypesService.restricted$);

Expand Down Expand Up @@ -190,6 +192,30 @@ export class VaultItemsComponent<C extends CipherViewLike> {
);
}

get bulkArchiveAllowed() {
if (this.selection.selected.length === 0 || !this.userCanArchive) {
return false;
}

return (
this.userCanArchive &&
!this.selection.selected.find(
(item) => item.cipher.organizationId || item.cipher.archivedDate,
)
);
}

// Bulk Unarchive button should appear for Archive vault even if user does not have archive permissions
get bulkUnarchiveAllowed() {
if (this.selection.selected.length === 0) {
return false;
}

return !this.selection.selected.find(
(item) => !item.cipher.archivedDate || item.cipher.organizationId,
);
}

//@TODO: remove this function when removing the limitItemDeletion$ feature flag.
get showDelete(): boolean {
if (this.selection.selected.length === 0) {
Expand Down Expand Up @@ -269,6 +295,24 @@ export class VaultItemsComponent<C extends CipherViewLike> {
});
}

protected bulkArchive() {
this.event({
type: "archive",
items: this.selection.selected
.filter((item) => item.cipher !== undefined)
.map((item) => item.cipher),
});
}

protected bulkUnarchive() {
this.event({
type: "unarchive",
items: this.selection.selected
.filter((item) => item.cipher !== undefined)
.map((item) => item.cipher),
});
}

protected bulkRestore() {
this.event({
type: "restore",
Expand Down
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to put this question here because it is related to filters but not the code changes here. Should it be possible to select an organization and archive filter? This will always result in the empty state as organization ciphers cannot be archived but also could imply that the user can have archived org ciphers.

Image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point. Will bubble this question up. If any further implementation I'll add it in another ticket.

Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,13 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
};

async buildAllFilters(): Promise<VaultFilterList> {
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
const hasArchiveFlag = await firstValueFrom(this.cipherArchiveService.hasArchiveFlagEnabled$());
const builderFilter = {} as VaultFilterList;
builderFilter.organizationFilter = await this.addOrganizationFilter();
builderFilter.typeFilter = await this.addTypeFilter();
builderFilter.folderFilter = await this.addFolderFilter();
builderFilter.collectionFilter = await this.addCollectionFilter();
if (
(await firstValueFrom(this.cipherArchiveService.userCanArchive$(userId))) ||
(await firstValueFrom(this.cipherArchiveService.showArchiveVault$(userId)))
) {
if (hasArchiveFlag) {
builderFilter.archiveFilter = await this.addArchiveFilter();
}
builderFilter.trashFilter = await this.addTrashFilter();
Expand Down Expand Up @@ -424,7 +421,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
[
{
id: "archive",
name: this.i18nService.t("archive"),
name: this.i18nService.t("archiveNoun"),
type: "archive",
icon: "bwi-archive",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export class VaultHeaderComponent {
}

if (this.filter.type === "archive") {
return this.i18nService.t("archive");
return this.i18nService.t("archiveNoun");
}

const activeOrganization = this.activeOrganization;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
[useEvents]="false"
[showAdminActions]="false"
[showBulkAddToCollections]="true"
[userCanArchive]="userCanArchive$ | async"
[enforceOrgDataOwnershipPolicy]="enforceOrgDataOwnershipPolicy$ | async"
(onEvent)="onVaultItemsEvent($event)"
>
</app-vault-items>
Expand Down
Loading
Loading