1
0
mirror of https://github.com/bitwarden/web synced 2025-12-15 15:53:18 +00:00

Compare commits

..

6 Commits

Author SHA1 Message Date
github-actions[bot]
b7cee309ba Bumped version to 2022.5.2 (#1730)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
(cherry picked from commit ee4afdd0f2)
2022-06-07 13:05:47 -07:00
Daniel James Smith
d886a056fa Fix expanding/collapsing of nested collections (#1722) 2022-06-07 16:04:09 -04:00
github-actions[bot]
06227f27ab Bumped version to 2022.5.1 (#1727)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
(cherry picked from commit 6da0925374)
2022-06-07 11:49:51 -07:00
Addison Beck
66391b4376 [fix] Pull org admin vault collections directly from the API (#1700) (#1726)
* [fix] Pull org admin vault collections directly from the API

* [refactor] Establish pattern for interfaces in module scoped services

* [fix] Remove access modifiers from constructor params for an extended service

* [fix] Rename skipFilterCollectionRefresh to firstLoaded

* [fix] Simplify hiding unwanted filters in the org vault

* Revert "[refactor] Establish pattern for interfaces in module scoped services"

This reverts commit f1edae5a3e.

* Update src/app/modules/vault-filter/vault-filter.component.ts

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

* Update src/app/modules/vault-filter/organization-vault-filter.component.ts

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

* [fix] Ran prettier

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2022-06-06 13:42:57 -04:00
Kyle Spearrin
1c09629bbc Allow firefox relay service in generator (#1723)
* Allow firefox relay service in generator

* Update generator.component.ts

* Update generator.component.ts

* make pretty
2022-06-02 14:01:33 -04:00
Jake Fink
e2d9498167 add better error handling to tax call (#1666) 2022-06-02 10:02:31 -04:00
13 changed files with 141 additions and 74 deletions

2
jslib

Submodule jslib updated: 1cc4bed671...6f117b9901

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@bitwarden/web-vault",
"version": "2022.05.0",
"version": "2022.5.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@bitwarden/web-vault",
"version": "2022.05.0",
"version": "2022.5.2",
"hasInstallScript": true,
"license": "GPL-3.0",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@bitwarden/web-vault",
"version": "2022.05.0",
"version": "2022.5.2",
"license": "GPL-3.0",
"repository": "https://github.com/bitwarden/web",
"scripts": {

View File

@@ -31,7 +31,7 @@
<button
class="toggle-button"
*ngIf="c.children.length"
(click)="collapse(c.node)"
(click)="toggleCollapse(c.node)"
title="{{ 'toggleCollapse' | i18n }}"
[attr.aria-expanded]="!isCollapsed(c.node)"
[attr.aria-controls]="c.node.name + '_children'"

View File

@@ -0,0 +1,28 @@
import { Component, Input } from "@angular/core";
import { Organization } from "jslib-common/models/domain/organization";
import { VaultFilterComponent } from "./vault-filter.component";
@Component({
selector: "app-organization-vault-filter",
templateUrl: "vault-filter.component.html",
})
export class OrganizationVaultFilterComponent extends VaultFilterComponent {
hideOrganizations = true;
hideFavorites = true;
hideFolders = true;
organization: Organization;
async initCollections() {
if (this.organization.canEditAnyCollection) {
return await this.vaultFilterService.buildAdminCollections(this.organization.id);
}
return await this.vaultFilterService.buildCollections(this.organization.id);
}
async reloadCollectionsAndFolders() {
this.collections = await this.initCollections();
}
}

View File

@@ -27,7 +27,6 @@
appAutofocus
/>
<app-organization-filter
*ngIf="showOrgFilter"
[hide]="hideOrganizations"
[activeFilter]="activeFilter"
[collapsedFilterNodes]="collapsedFilterNodes"
@@ -39,7 +38,7 @@
></app-organization-filter>
<div class="filter">
<app-status-filter
[hideFavorites]="!showFavorites"
[hideFavorites]="hideFavorites"
[hideTrash]="hideTrash"
[activeFilter]="activeFilter"
(onFilterChange)="applyFilter($event)"
@@ -55,7 +54,7 @@
</div>
<div class="filter">
<app-folder-filter
[hide]="!showFolders"
[hide]="hideFolders"
[activeFilter]="activeFilter"
[collapsedFilterNodes]="collapsedFilterNodes"
[folderNodes]="folders"

View File

@@ -1,26 +1,22 @@
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { Component, EventEmitter, Output } from "@angular/core";
import { VaultFilterComponent as BaseVaultFilterComponent } from "jslib-angular/modules/vault-filter/vault-filter.component";
import { VaultFilterService } from "jslib-angular/modules/vault-filter/vault-filter.service";
import { Organization } from "jslib-common/models/domain/organization";
import { VaultFilterService } from "./vault-filter.service";
@Component({
selector: "app-vault-filter",
templateUrl: "vault-filter.component.html",
})
export class VaultFilterComponent extends BaseVaultFilterComponent {
@Input() showOrgFilter = true;
@Input() showFolders = true;
@Input() showFavorites = true;
@Output() onSearchTextChanged = new EventEmitter<string>();
searchPlaceholder: string;
searchText = "";
organization: Organization;
constructor(vaultFilterService: VaultFilterService) {
constructor(protected vaultFilterService: VaultFilterService) {
// This empty constructor is required to provide the web vaultFilterService subclass to super()
// TODO: refactor this to use proper dependency injection
super(vaultFilterService);
}
@@ -37,8 +33,4 @@ export class VaultFilterComponent extends BaseVaultFilterComponent {
this.activeSingleOrganizationPolicy =
await this.vaultFilterService.checkForSingleOrganizationPolicy();
}
async initCollections() {
return await this.vaultFilterService.buildCollections(this.organization?.id);
}
}

View File

@@ -1,13 +1,5 @@
import { NgModule } from "@angular/core";
import { VaultFilterService } from "jslib-angular/modules/vault-filter/vault-filter.service";
import { CipherService } from "jslib-common/abstractions/cipher.service";
import { CollectionService } from "jslib-common/abstractions/collection.service";
import { FolderService } from "jslib-common/abstractions/folder.service";
import { OrganizationService } from "jslib-common/abstractions/organization.service";
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { SharedModule } from "../shared.module";
import { CollectionFilterComponent } from "./components/collection-filter.component";
@@ -17,7 +9,9 @@ import { OrganizationFilterComponent } from "./components/organization-filter.co
import { OrganizationOptionsComponent } from "./components/organization-options.component";
import { StatusFilterComponent } from "./components/status-filter.component";
import { TypeFilterComponent } from "./components/type-filter.component";
import { OrganizationVaultFilterComponent } from "./organization-vault-filter.component";
import { VaultFilterComponent } from "./vault-filter.component";
import { VaultFilterService } from "./vault-filter.service";
@NgModule({
imports: [SharedModule],
@@ -29,22 +23,10 @@ import { VaultFilterComponent } from "./vault-filter.component";
OrganizationOptionsComponent,
StatusFilterComponent,
TypeFilterComponent,
OrganizationVaultFilterComponent,
LinkSsoComponent,
],
exports: [VaultFilterComponent],
providers: [
{
provide: VaultFilterService,
useClass: VaultFilterService,
deps: [
StateService,
OrganizationService,
FolderService,
CipherService,
CollectionService,
PolicyService,
],
},
],
exports: [VaultFilterComponent, OrganizationVaultFilterComponent],
providers: [VaultFilterService],
})
export class VaultFilterModule {}

View File

@@ -1,3 +1,54 @@
import { VaultFilterService as BaseVaultFilterService } from "jslib-angular/modules/vault-filter/vault-filter.service";
import { Injectable } from "@angular/core";
export class VaultFilterService extends BaseVaultFilterService {}
import { DynamicTreeNode } from "jslib-angular/modules/vault-filter/models/dynamic-tree-node.model";
import { VaultFilterService as BaseVaultFilterService } from "jslib-angular/modules/vault-filter/vault-filter.service";
import { ApiService } from "jslib-common/abstractions/api.service";
import { CipherService } from "jslib-common/abstractions/cipher.service";
import { CollectionService } from "jslib-common/abstractions/collection.service";
import { FolderService } from "jslib-common/abstractions/folder.service";
import { OrganizationService } from "jslib-common/abstractions/organization.service";
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { CollectionData } from "jslib-common/models/data/collectionData";
import { Collection } from "jslib-common/models/domain/collection";
import { CollectionDetailsResponse } from "jslib-common/models/response/collectionResponse";
import { CollectionView } from "jslib-common/models/view/collectionView";
@Injectable()
export class VaultFilterService extends BaseVaultFilterService {
constructor(
stateService: StateService,
organizationService: OrganizationService,
folderService: FolderService,
cipherService: CipherService,
collectionService: CollectionService,
policyService: PolicyService,
protected apiService: ApiService
) {
super(
stateService,
organizationService,
folderService,
cipherService,
collectionService,
policyService
);
}
async buildAdminCollections(organizationId: string) {
let result: CollectionView[] = [];
const collectionResponse = await this.apiService.getCollections(organizationId);
if (collectionResponse?.data != null && collectionResponse.data.length) {
const collectionDomains = collectionResponse.data.map(
(r: CollectionDetailsResponse) => new Collection(new CollectionData(r))
);
result = await this.collectionService.decryptMany(collectionDomains);
}
const nestedCollections = await this.collectionService.getAllNested(result);
return new DynamicTreeNode<CollectionView>({
fullList: result,
nestedList: nestedCollections,
});
}
}

View File

@@ -4,15 +4,12 @@
<div class="groupings">
<div class="content">
<div class="inner-content">
<app-vault-filter
<app-organization-vault-filter
#vaultFilter
[showFolders]="false"
[showFavorites]="false"
[activeFilter]="activeFilter"
[showOrgFilter]="false"
(onFilterChange)="applyVaultFilter($event)"
(onSearchTextChanged)="filterSearchText($event)"
></app-vault-filter>
></app-organization-vault-filter>
</div>
</div>
</div>

View File

@@ -29,7 +29,7 @@ import { AddEditComponent } from "../../../../organizations/vault/add-edit.compo
import { AttachmentsComponent } from "../../../../organizations/vault/attachments.component";
import { CiphersComponent } from "../../../../organizations/vault/ciphers.component";
import { CollectionsComponent } from "../../../../organizations/vault/collections.component";
import { VaultFilterComponent } from "../../../vault-filter/vault-filter.component";
import { OrganizationVaultFilterComponent } from "../../../vault-filter/organization-vault-filter.component";
import { VaultService } from "../../vault.service";
const BroadcasterSubscriptionId = "OrgVaultComponent";
@@ -39,7 +39,8 @@ const BroadcasterSubscriptionId = "OrgVaultComponent";
templateUrl: "organization-vault.component.html",
})
export class OrganizationVaultComponent implements OnInit, OnDestroy {
@ViewChild("vaultFilter", { static: true }) vaultFilterComponent: VaultFilterComponent;
@ViewChild("vaultFilter", { static: true })
vaultFilterComponent: OrganizationVaultFilterComponent;
@ViewChild(CiphersComponent, { static: true }) ciphersComponent: CiphersComponent;
@ViewChild("attachments", { read: ViewContainerRef, static: true })
attachmentsModalRef: ViewContainerRef;
@@ -57,6 +58,11 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy {
trashCleanupWarning: string = null;
activeFilter: VaultFilter = new VaultFilter();
// This is a hack to avoid redundant api calls that fetch OrganizationVaultFilterComponent collections
// When it makes sense to do so we should leverage some other communication method for change events that isn't directly tied to the query param for organizationId
// i.e. exposing the VaultFiltersService to the OrganizationSwitcherComponent to make relevant updates from a change event instead of just depending on the router
firstLoaded = true;
constructor(
private route: ActivatedRoute,
private organizationService: OrganizationService,
@@ -95,11 +101,7 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy {
case "syncCompleted":
if (message.successfully) {
await Promise.all([
this.vaultFilterComponent.reloadCollectionsAndFolders(
new VaultFilter({
selectedOrganizationId: this.organization.id,
} as Partial<VaultFilter>)
),
this.vaultFilterComponent.reloadCollectionsAndFolders(),
this.ciphersComponent.refresh(),
]);
this.changeDetectorRef.detectChanges();
@@ -109,9 +111,12 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy {
});
});
}
await this.vaultFilterComponent.reloadCollectionsAndFolders(
new VaultFilter({ selectedOrganizationId: this.organization.id } as Partial<VaultFilter>)
);
if (!this.firstLoaded) {
await this.vaultFilterComponent.reloadCollectionsAndFolders();
}
this.firstLoaded = false;
await this.ciphersComponent.reload();
if (qParams.viewEvents != null) {

View File

@@ -73,10 +73,14 @@ export class TaxInfoComponent {
this.logService.error(e);
}
} else {
const taxInfo = await this.apiService.getTaxInfo();
if (taxInfo) {
this.taxInfo.postalCode = taxInfo.postalCode;
this.taxInfo.country = taxInfo.country || "US";
try {
const taxInfo = await this.apiService.getTaxInfo();
if (taxInfo) {
this.taxInfo.postalCode = taxInfo.postalCode;
this.taxInfo.country = taxInfo.country || "US";
}
} catch (e) {
this.logService.error(e);
}
}
this.pristine = Object.assign({}, this.taxInfo);
@@ -86,9 +90,16 @@ export class TaxInfoComponent {
}
});
const taxRates = await this.apiService.getTaxRates();
this.taxRates = taxRates.data;
this.loading = false;
try {
const taxRates = await this.apiService.getTaxRates();
if (taxRates) {
this.taxRates = taxRates.data;
}
} catch (e) {
this.logService.error(e);
} finally {
this.loading = false;
}
}
get taxRate() {

View File

@@ -40,11 +40,13 @@ export class GeneratorComponent extends BaseGeneratorComponent {
route,
window
);
// Cannot use Firefox Relay on the web vault yet due to CORS issues with Firefox Relay API
this.forwardOptions.splice(
this.forwardOptions.findIndex((o) => o.value === "firefoxrelay"),
1
);
if (platformUtilsService.isSelfHost()) {
// Cannot use Firefox Relay on self hosted web vaults due to CORS issues with Firefox Relay API
this.forwardOptions.splice(
this.forwardOptions.findIndex((o) => o.value === "firefoxrelay"),
1
);
}
}
async history() {