Skip to content

Commit

Permalink
Merge branch 'main' into vault/ac-2555/collection-dialog-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
shane-melton committed May 7, 2024
2 parents 9e2e873 + be51f19 commit 61db4f9
Show file tree
Hide file tree
Showing 23 changed files with 409 additions and 33 deletions.
1 change: 1 addition & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import remarkGfm from "remark-gfm";

const config: StorybookConfig = {
stories: [
"../libs/auth/src/**/*.mdx",
"../libs/auth/src/**/*.stories.@(js|jsx|ts|tsx)",
"../libs/components/src/**/*.mdx",
"../libs/components/src/**/*.stories.@(js|jsx|ts|tsx)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export class ReportsHomeComponent implements OnInit {
ngOnInit() {
this.homepage$ = this.router.events.pipe(
filter((event) => event instanceof NavigationEnd),
map((event) => (event as NavigationEnd).urlAfterRedirects.endsWith("/reports")),
startWith(true),
map((event) => this.isReportsHomepageRouteUrl((event as NavigationEnd).urlAfterRedirects)),
startWith(this.isReportsHomepageRouteUrl(this.router.url)),
);

this.reports$ = this.route.params.pipe(
Expand Down Expand Up @@ -61,4 +61,8 @@ export class ReportsHomeComponent implements OnInit {
},
];
}

private isReportsHomepageRouteUrl(url: string): boolean {
return url.endsWith("/reports");
}
}
4 changes: 4 additions & 0 deletions apps/web/src/app/auth/anon-layout-wrapper.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<auth-anon-layout [title]="pageTitle" [subtitle]="pageSubtitle" [icon]="pageIcon">
<router-outlet></router-outlet>
<router-outlet slot="secondary" name="secondary"></router-outlet>
</auth-anon-layout>
34 changes: 34 additions & 0 deletions apps/web/src/app/auth/anon-layout-wrapper.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, RouterModule } from "@angular/router";

import { AnonLayoutComponent } from "@bitwarden/auth/angular";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Icon } from "@bitwarden/components";

@Component({
standalone: true,
templateUrl: "anon-layout-wrapper.component.html",
imports: [AnonLayoutComponent, RouterModule],
})
export class AnonLayoutWrapperComponent implements OnInit, OnDestroy {
protected pageTitle: string;
protected pageSubtitle: string;
protected pageIcon: Icon;

constructor(
private route: ActivatedRoute,
private i18nService: I18nService,
) {
this.pageTitle = this.i18nService.t(this.route.snapshot.firstChild.data["pageTitle"]);
this.pageSubtitle = this.i18nService.t(this.route.snapshot.firstChild.data["pageSubtitle"]);
this.pageIcon = this.route.snapshot.firstChild.data["pageIcon"]; // don't translate
}

ngOnInit() {
document.body.classList.add("layout_frontend");
}

ngOnDestroy() {
document.body.classList.remove("layout_frontend");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,23 @@
bitLink
[disabled]="disabled"
type="button"
class="tw-w-full tw-truncate tw-text-start tw-leading-snug"
class="tw-flex tw-w-full tw-text-start tw-leading-snug"
linkType="secondary"
title="{{ 'viewCollectionWithName' | i18n: collection.name }}"
[routerLink]="[]"
[queryParams]="{ collectionId: collection.id }"
queryParamsHandling="merge"
appStopProp
>
{{ collection.name }}
<span class="tw-truncate tw-mr-1">{{ collection.name }}</span>
<div>
<span
*ngIf="collection.addAccess && collection.id !== Unassigned"
bitBadge
variant="warning"
>{{ "addAccess" | i18n }}</span
>
</div>
</button>
</td>
<td bitCell [ngClass]="RowHeightClass" *ngIf="showOwner">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { RowHeightClass } from "./vault-items.component";
})
export class VaultCollectionRowComponent {
protected RowHeightClass = RowHeightClass;
protected Unassigned = "unassigned";

@Input() disabled: boolean;
@Input() collection: CollectionView;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,12 @@
(checkedToggled)="selection.toggle(item)"
(onEvent)="event($event)"
></tr>
<!--
addAccessStatus check here so ciphers do not show if user
has filtered for collections with addAccess
-->
<tr
*ngIf="item.cipher"
*ngIf="item.cipher && (!addAccessToggle || (addAccessToggle && addAccessStatus !== 1))"
bitRow
appVaultCipherRow
alignContent="middle"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SelectionModel } from "@angular/cdk/collections";
import { Component, EventEmitter, Input, Output } from "@angular/core";

import { OrganizationUserType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
Expand Down Expand Up @@ -45,6 +46,8 @@ export class VaultItemsComponent {
@Input() showPermissionsColumn = false;
@Input() viewingOrgVault: boolean;
@Input({ required: true }) flexibleCollectionsV1Enabled = false;
@Input() addAccessStatus: number;
@Input() addAccessToggle: boolean;

private _ciphers?: CipherView[] = [];
@Input() get ciphers(): CipherView[] {
Expand Down Expand Up @@ -101,6 +104,28 @@ export class VaultItemsComponent {
}

const organization = this.allOrganizations.find((o) => o.id === collection.organizationId);

if (this.flexibleCollectionsV1Enabled) {
//Custom user without edit access should not see the Edit option unless that user has "Can Manage" access to a collection
if (
!collection.manage &&
organization?.type === OrganizationUserType.Custom &&
!organization?.permissions.editAnyCollection
) {
return false;
}
//Owner/Admin and Custom Users with Edit can see Edit and Access of Orphaned Collections
if (
collection.addAccess &&
collection.id !== Unassigned &&
((organization?.type === OrganizationUserType.Custom &&
organization?.permissions.editAnyCollection) ||
organization.isAdmin ||
organization.isOwner)
) {
return true;
}
}
return collection.canEdit(organization, this.flexibleCollectionsV1Enabled);
}

Expand All @@ -111,6 +136,32 @@ export class VaultItemsComponent {
}

const organization = this.allOrganizations.find((o) => o.id === collection.organizationId);

if (this.flexibleCollectionsV1Enabled) {
//Custom user with only edit access should not see the Delete button for orphaned collections
if (
collection.addAccess &&
organization?.type === OrganizationUserType.Custom &&
!organization?.permissions.deleteAnyCollection &&
organization?.permissions.editAnyCollection
) {
return false;
}

// Owner/Admin with no access to a collection will not see Delete
if (
!collection.assigned &&
!collection.addAccess &&
(organization.isAdmin || organization.isOwner) &&
!(
organization?.type === OrganizationUserType.Custom &&
organization?.permissions.deleteAnyCollection
)
) {
return false;
}
}

return collection.canDelete(organization);
}

Expand Down
29 changes: 29 additions & 0 deletions apps/web/src/app/vault/core/views/collection-admin.view.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { OrganizationUserUserDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-user/responses";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { CollectionAccessDetailsResponse } from "@bitwarden/common/src/vault/models/response/collection.response";
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
Expand All @@ -7,6 +8,7 @@ import { CollectionAccessSelectionView } from "../../../admin-console/organizati
export class CollectionAdminView extends CollectionView {
groups: CollectionAccessSelectionView[] = [];
users: CollectionAccessSelectionView[] = [];
addAccess: boolean;

/**
* Flag indicating the user has been explicitly assigned to this Collection
Expand All @@ -31,6 +33,33 @@ export class CollectionAdminView extends CollectionView {
this.assigned = response.assigned;
}

groupsCanManage() {
if (this.groups.length === 0) {
return this.groups;
}

const returnedGroups = this.groups.filter((group) => {
if (group.manage) {
return group;
}
});
return returnedGroups;
}

usersCanManage(revokedUsers: OrganizationUserUserDetailsResponse[]) {
if (this.users.length === 0) {
return this.users;
}

const returnedUsers = this.users.filter((user) => {
const isRevoked = revokedUsers.some((revoked) => revoked.id === user.id);
if (user.manage && !isRevoked) {
return user;
}
});
return returnedUsers;
}

/**
* Whether the current user can edit the collection, including user and group access
*/
Expand Down
16 changes: 16 additions & 0 deletions apps/web/src/app/vault/org-vault/vault.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@
</div>
</div>
<div class="col-9">
<bit-toggle-group
*ngIf="showAddAccessToggle && activeFilter.selectedCollectionNode"
[selected]="addAccessStatus$ | async"
(selectedChange)="addAccessToggle($event)"
[attr.aria-label]="'addAccessFilter' | i18n"
>
<bit-toggle [value]="0">
{{ "all" | i18n }}
</bit-toggle>

<bit-toggle [value]="1">
{{ "addAccess" | i18n }}
</bit-toggle>
</bit-toggle-group>
<app-callout type="warning" *ngIf="activeFilter.isDeleted" icon="bwi bwi-exclamation-triangle">
{{ trashCleanupWarning }}
</app-callout>
Expand Down Expand Up @@ -54,6 +68,8 @@
[showBulkAddToCollections]="organization?.flexibleCollections"
[viewingOrgVault]="true"
[flexibleCollectionsV1Enabled]="flexibleCollectionsV1Enabled"
[addAccessStatus]="addAccessStatus$ | async"
[addAccessToggle]="showAddAccessToggle"
>
</app-vault-items>
<ng-container *ngIf="!flexibleCollectionsV1Enabled">
Expand Down
Loading

0 comments on commit 61db4f9

Please sign in to comment.