Implement Clone item functionality (personal/org) (#457)

* Clone personal/org items

* Removed ability to delete during clone process
This commit is contained in:
Vincent Salucci 2020-02-10 13:03:36 -06:00 committed by GitHub
parent 7e95e44f1d
commit ccf3d49fc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 44 additions and 11 deletions

View File

@ -70,7 +70,7 @@ export class AddEditComponent extends BaseAddEditComponent {
if (!this.organization.isAdmin) {
return super.saveCipher(cipher);
}
if (this.editMode) {
if (this.editMode && !this.cloneMode) {
const request = new CipherRequest(cipher);
return this.apiService.putCipherAdmin(this.cipherId, request);
} else {

View File

@ -24,7 +24,8 @@
</div>
<app-org-vault-ciphers (onCipherClicked)="editCipher($event)"
(onAttachmentsClicked)="editCipherAttachments($event)" (onAddCipher)="addCipher()"
(onCollectionsClicked)="editCipherCollections($event)" (onEventsClicked)="viewEvents($event)">
(onCollectionsClicked)="editCipherCollections($event)" (onEventsClicked)="viewEvents($event)"
(onCloneClicked)="cloneCipher($event)">
</app-org-vault-ciphers>
</div>
</div>
@ -32,4 +33,4 @@
<ng-template #attachments></ng-template>
<ng-template #cipherAddEdit></ng-template>
<ng-template #collections></ng-template>
<ng-template #eventsTemplate></ng-template>
<ng-template #eventsTemplate></ng-template>

View File

@ -263,6 +263,18 @@ export class VaultComponent implements OnInit, OnDestroy {
return childComponent;
}
cloneCipher(cipher: CipherView) {
const component = this.editCipher(cipher);
component.cloneMode = true;
component.organizationId = this.organization.id;
if (this.organization.isAdmin) {
component.collections = this.groupingsComponent.collections.filter((c) => !c.readOnly);
}
// Regardless of Admin state, the collection Ids need to passed manually as they are not assigned value
// in the add-edit componenet
component.collectionIds = cipher.collectionIds;
}
async viewEvents(cipher: CipherView) {
if (this.modal != null) {
this.modal.close();

View File

@ -439,7 +439,8 @@
</select>
</div>
</div>
<ng-container *ngIf="!editMode && !organization && ownershipOptions && ownershipOptions.length > 1">
<ng-container
*ngIf="(!editMode || cloneMode) && !organization && ownershipOptions && ownershipOptions.length > 1">
<h3 class="mt-4">{{'ownership' | i18n}}</h3>
<div class="row">
<div class="col-5">
@ -451,7 +452,7 @@
</div>
</div>
</ng-container>
<ng-container *ngIf="!editMode && cipher.organizationId">
<ng-container *ngIf="(!editMode || cloneMode) && cipher.organizationId">
<h3 class="mt-4">{{'collections' | i18n}}</h3>
<div *ngIf="!collections || !collections.length">
{{'noCollectionsInList' | i18n}}
@ -504,7 +505,7 @@
aria-hidden="true"></i>
</button>
<button #deleteBtn type="button" (click)="delete()" class="btn btn-outline-danger"
appA11yTitle="{{'delete' | i18n}}" *ngIf="editMode" [disabled]="deleteBtn.loading"
appA11yTitle="{{'delete' | i18n}}" *ngIf="editMode && !cloneMode" [disabled]="deleteBtn.loading"
[appApiAction]="deletePromise">
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading" aria-hidden="true"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading"
@ -514,4 +515,4 @@
</div>
</form>
</div>
</div>
</div>

View File

@ -52,6 +52,11 @@
<i class="fa fa-fw fa-paperclip" aria-hidden="true"></i>
{{'attachments' | i18n}}
</a>
<a class="dropdown-item" href="#" appStopClick
*ngIf="(!organization && !c.organizationId) || organization" (click)="clone(c)">
<i class="fa fa-fw fa-clone" aria-hidden="true"></i>
{{'clone' | i18n}}
</a>
<a class="dropdown-item" href="#" appStopClick *ngIf="!organization && !c.organizationId"
(click)="share(c)">
<i class="fa fa-fw fa-share-alt" aria-hidden="true"></i>
@ -88,4 +93,4 @@
<i class="fa fa-plus fa-fw"></i>{{'addItem' | i18n}}</button>
</ng-container>
</div>
</ng-container>
</ng-container>

View File

@ -33,6 +33,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnDestroy
@Output() onAttachmentsClicked = new EventEmitter<CipherView>();
@Output() onShareClicked = new EventEmitter<CipherView>();
@Output() onCollectionsClicked = new EventEmitter<CipherView>();
@Output() onCloneClicked = new EventEmitter<CipherView>();
cipherType = CipherType;
actionPromise: Promise<any>;
@ -91,6 +92,10 @@ export class CiphersComponent extends BaseCiphersComponent implements OnDestroy
this.onCollectionsClicked.emit(c);
}
clone(c: CipherView) {
this.onCloneClicked.emit(c);
}
async delete(c: CipherView): Promise<boolean> {
if (this.actionPromise != null) {
return;

View File

@ -57,7 +57,8 @@
</div>
<app-vault-ciphers (onCipherClicked)="editCipher($event)"
(onAttachmentsClicked)="editCipherAttachments($event)" (onAddCipher)="addCipher()"
(onShareClicked)="shareCipher($event)" (onCollectionsClicked)="editCipherCollections($event)">
(onShareClicked)="shareCipher($event)" (onCollectionsClicked)="editCipherCollections($event)"
(onCloneClicked)="cloneCipher($event)">
</app-vault-ciphers>
</div>
<div class="col-3">
@ -119,4 +120,4 @@
<ng-template #bulkDeleteTemplate></ng-template>
<ng-template #bulkMoveTemplate></ng-template>
<ng-template #bulkShareTemplate></ng-template>
<ng-template #updateKeyTemplate></ng-template>
<ng-template #updateKeyTemplate></ng-template>

View File

@ -366,6 +366,11 @@ export class VaultComponent implements OnInit, OnDestroy {
return childComponent;
}
cloneCipher(cipher: CipherView) {
const component = this.editCipher(cipher);
component.cloneMode = true;
}
bulkDelete() {
const selectedIds = this.ciphersComponent.getSelectedIds();
if (selectedIds.length === 0) {

View File

@ -2956,5 +2956,8 @@
},
"minLength": {
"message": "Minimum Length"
},
"clone": {
"message": "Clone"
}
}
}