diff --git a/jslib b/jslib index 8e377050e9b..2f510a79885 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 8e377050e9bfddae46fa0a167771b670593eca16 +Subproject commit 2f510a798853ef3adfed7e8285c9d3f54eba493c diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 0d45642d3a5..7cda81e830d 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -43,12 +43,14 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe'; import { AddEditComponent } from './vault/add-edit.component'; import { AttachmentsComponent } from './vault/attachments.component'; import { CiphersComponent } from './vault/ciphers.component'; +import { CollectionsComponent } from './vault/collections.component'; import { ExportComponent } from './vault/export.component'; import { FolderAddEditComponent } from './vault/folder-add-edit.component'; import { GroupingsComponent } from './vault/groupings.component'; import { PasswordGeneratorHistoryComponent } from './vault/password-generator-history.component'; import { PasswordGeneratorComponent } from './vault/password-generator.component'; import { PasswordHistoryComponent } from './vault/password-history.component'; +import { ShareComponent } from './vault/share.component'; import { VaultComponent } from './vault/vault.component'; import { ViewComponent } from './vault/view.component'; @@ -138,6 +140,7 @@ registerLocaleData(localeZhTw, 'zh-TW'); BlurClickDirective, BoxRowDirective, CiphersComponent, + CollectionsComponent, EnvironmentComponent, ExportComponent, FallbackSrcDirective, @@ -156,6 +159,7 @@ registerLocaleData(localeZhTw, 'zh-TW'); RegisterComponent, SearchCiphersPipe, SettingsComponent, + ShareComponent, StopClickDirective, StopPropDirective, TrueFalseValueDirective, @@ -166,6 +170,7 @@ registerLocaleData(localeZhTw, 'zh-TW'); ], entryComponents: [ AttachmentsComponent, + CollectionsComponent, EnvironmentComponent, ExportComponent, FolderAddEditComponent, @@ -175,6 +180,7 @@ registerLocaleData(localeZhTw, 'zh-TW'); PasswordHistoryComponent, PremiumComponent, SettingsComponent, + ShareComponent, TwoFactorOptionsComponent, ], providers: [], diff --git a/src/app/vault/add-edit.component.html b/src/app/vault/add-edit.component.html index 08ffb4b7aea..78a2dbe9618 100644 --- a/src/app/vault/add-edit.component.html +++ b/src/app/vault/add-edit.component.html @@ -240,6 +240,11 @@
{{'attachments' | i18n}}
+ +
{{'collections' | i18n}}
+ +
@@ -309,6 +314,10 @@ {{'cancel' | i18n}}
+ + +
+ +
+ diff --git a/src/app/vault/collections.component.ts b/src/app/vault/collections.component.ts new file mode 100644 index 00000000000..ded2139ce58 --- /dev/null +++ b/src/app/vault/collections.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; + +import { CipherService } from 'jslib/abstractions/cipher.service'; +import { CollectionService } from 'jslib/abstractions/collection.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; +import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; + +import { CollectionsComponent as BaseCollectionsComponent } from 'jslib/angular/components/collections.component'; + +@Component({ + selector: 'app-vault-collections', + templateUrl: 'collections.component.html', +}) +export class CollectionsComponent extends BaseCollectionsComponent { + constructor(cipherService: CipherService, i18nService: I18nService, + collectionService: CollectionService, platformUtilsService: PlatformUtilsService) { + super(collectionService, platformUtilsService, i18nService, cipherService); + } +} diff --git a/src/app/vault/share.component.html b/src/app/vault/share.component.html new file mode 100644 index 00000000000..d5668370cb8 --- /dev/null +++ b/src/app/vault/share.component.html @@ -0,0 +1,52 @@ + diff --git a/src/app/vault/share.component.ts b/src/app/vault/share.component.ts new file mode 100644 index 00000000000..3e73aa81327 --- /dev/null +++ b/src/app/vault/share.component.ts @@ -0,0 +1,21 @@ +import { Component } from '@angular/core'; + +import { CipherService } from 'jslib/abstractions/cipher.service'; +import { CollectionService } from 'jslib/abstractions/collection.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; +import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; +import { UserService } from 'jslib/abstractions/user.service'; + +import { ShareComponent as BaseShareComponent } from 'jslib/angular/components/share.component'; + +@Component({ + selector: 'app-vault-share', + templateUrl: 'share.component.html', +}) +export class ShareComponent extends BaseShareComponent { + constructor(cipherService: CipherService, i18nService: I18nService, + collectionService: CollectionService, userService: UserService, + platformUtilsService: PlatformUtilsService) { + super(collectionService, platformUtilsService, i18nService, userService, cipherService); + } +} diff --git a/src/app/vault/vault.component.html b/src/app/vault/vault.component.html index a5ab83c876a..ce441ae8163 100644 --- a/src/app/vault/vault.component.html +++ b/src/app/vault/vault.component.html @@ -30,6 +30,8 @@ (onDeletedCipher)="deletedCipher($event)" (onEditAttachments)="editCipherAttachments($event)" (onCancelled)="cancelledAddEdit($event)" + (onShareCipher)="shareCipher($event)" + (onEditCollections)="cipherCollections($event)" (onGeneratePassword)="openPasswordGenerator(true)"> + + diff --git a/src/app/vault/vault.component.ts b/src/app/vault/vault.component.ts index 651dbf03cad..6794e118806 100644 --- a/src/app/vault/vault.component.ts +++ b/src/app/vault/vault.component.ts @@ -26,11 +26,13 @@ import { ModalComponent } from 'jslib/angular/components/modal.component'; import { AddEditComponent } from './add-edit.component'; import { AttachmentsComponent } from './attachments.component'; import { CiphersComponent } from './ciphers.component'; +import { CollectionsComponent } from './collections.component'; import { ExportComponent } from './export.component'; import { FolderAddEditComponent } from './folder-add-edit.component'; import { GroupingsComponent } from './groupings.component'; import { PasswordGeneratorComponent } from './password-generator.component'; import { PasswordHistoryComponent } from './password-history.component'; +import { ShareComponent } from './share.component'; import { CipherType } from 'jslib/enums/cipherType'; @@ -58,6 +60,8 @@ export class VaultComponent implements OnInit, OnDestroy { @ViewChild('folderAddEdit', { read: ViewContainerRef }) folderAddEditModalRef: ViewContainerRef; @ViewChild('passwordHistory', { read: ViewContainerRef }) passwordHistoryModalRef: ViewContainerRef; @ViewChild('exportVault', { read: ViewContainerRef }) exportVaultModalRef: ViewContainerRef; + @ViewChild('share', { read: ViewContainerRef }) shareModalRef: ViewContainerRef; + @ViewChild('collections', { read: ViewContainerRef }) collectionsModalRef: ViewContainerRef; action: string; cipherId: string = null; @@ -353,6 +357,45 @@ export class VaultComponent implements OnInit, OnDestroy { }); } + shareCipher(cipher: CipherView) { + if (this.modal != null) { + this.modal.close(); + } + + const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); + this.modal = this.shareModalRef.createComponent(factory).instance; + const childComponent = this.modal.show(ShareComponent, this.shareModalRef); + childComponent.cipherId = cipher.id; + + childComponent.onSharedCipher.subscribe(async () => { + this.modal.close(); + this.viewCipher(cipher); + await this.ciphersComponent.refresh(); + }); + this.modal.onClosed.subscribe(async () => { + this.modal = null; + }); + } + + cipherCollections(cipher: CipherView) { + if (this.modal != null) { + this.modal.close(); + } + + const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); + this.modal = this.collectionsModalRef.createComponent(factory).instance; + const childComponent = this.modal.show(CollectionsComponent, this.collectionsModalRef); + childComponent.cipherId = cipher.id; + + childComponent.onSavedCollections.subscribe(() => { + this.modal.close(); + this.viewCipher(cipher); + }); + this.modal.onClosed.subscribe(async () => { + this.modal = null; + }); + } + viewCipherPasswordHistory(cipher: CipherView) { if (this.modal != null) { this.modal.close(); diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 311249b1a81..32ee5891b71 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -38,6 +38,18 @@ "shared": { "message": "Shared" }, + "share": { + "message": "Share" + }, + "shareItem": { + "message": "Share Item" + }, + "sharedItem": { + "message": "Shared Item" + }, + "shareDesc": { + "message": "Choose an organization that you wish to share this item with. Sharing transfers ownership of the item to the organization. You will no longer be the direct owner of this item once it has been shared." + }, "attachments": { "message": "Attachments" }, @@ -1100,5 +1112,11 @@ }, "exportMasterPassword": { "message": "Enter your master password to export your vault data." + }, + "noOrganizationsList": { + "message": "You do not belong to any organizations. Organizations allow you to securely share items with other users." + }, + "noCollectionsInList": { + "message": "There are no collections to list." } }