1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-27 12:36:14 +01:00

Adding personal item cloning capability (#371)

This commit is contained in:
Vincent Salucci 2020-01-31 10:07:32 -06:00 committed by GitHub
parent e79e126fba
commit 337f4ad987
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 7 deletions

View File

@ -350,11 +350,11 @@
</button> </button>
<div class="right"> <div class="right">
<button appBlurClick type="button" (click)="share()" appA11yTitle="{{'shareItem' | i18n}}" <button appBlurClick type="button" (click)="share()" appA11yTitle="{{'shareItem' | i18n}}"
*ngIf="editMode && cipher && !cipher.organizationId"> *ngIf="editMode && cipher && !cipher.organizationId && !cloneMode">
<i class="fa fa-share-alt fa-lg fa-fw" aria-hidden="true"></i> <i class="fa fa-share-alt fa-lg fa-fw" aria-hidden="true"></i>
</button> </button>
<button #deleteBtn appBlurClick type="button" (click)="delete()" class="danger" <button #deleteBtn appBlurClick type="button" (click)="delete()" class="danger"
appA11yTitle="{{'delete' | i18n}}" *ngIf="editMode" [disabled]="deleteBtn.loading" appA11yTitle="{{'delete' | i18n}}" *ngIf="editMode && !cloneMode" [disabled]="deleteBtn.loading"
[appApiAction]="deletePromise"> [appApiAction]="deletePromise">
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading" aria-hidden="true"></i> <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" aria-hidden="true"></i> <i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading" aria-hidden="true"></i>

View File

@ -9,19 +9,21 @@
(onAddCipherOptions)="addCipherOptions()"> (onAddCipherOptions)="addCipherOptions()">
</app-vault-ciphers> </app-vault-ciphers>
<app-vault-view id="details" *ngIf="cipherId && action === 'view'" [cipherId]="cipherId" <app-vault-view id="details" *ngIf="cipherId && action === 'view'" [cipherId]="cipherId"
(onEditCipher)="editCipher($event)" (onViewCipherPasswordHistory)="viewCipherPasswordHistory($event)"> (onCloneCipher)="cloneCipher($event)" (onEditCipher)="editCipher($event)"
(onViewCipherPasswordHistory)="viewCipherPasswordHistory($event)">
</app-vault-view> </app-vault-view>
<app-vault-add-edit id="details" *ngIf="action === 'add' || action === 'edit'" <app-vault-add-edit id="details" *ngIf="action === 'add' || action === 'edit' || action === 'clone'"
[cloneMode]="action === 'clone'"
[folderId]="action === 'add' && folderId !== 'none' ? folderId : null" [folderId]="action === 'add' && folderId !== 'none' ? folderId : null"
[organizationId]="action === 'add' ? addOrganizationId : null" [organizationId]="action === 'add' ? addOrganizationId : null"
[collectionIds]="action === 'add' ? addCollectionIds : null" [collectionIds]="action === 'add' ? addCollectionIds : null"
[type]="action === 'add' ? (addType ? addType : type) : null" [cipherId]="action === 'edit' ? cipherId : null" [type]="action === 'add' ? (addType ? addType : type) : null" [cipherId]="(action === 'edit' || action === 'clone') ? cipherId : null"
(onSavedCipher)="savedCipher($event)" (onDeletedCipher)="deletedCipher($event)" (onSavedCipher)="savedCipher($event)" (onDeletedCipher)="deletedCipher($event)"
(onEditAttachments)="editCipherAttachments($event)" (onCancelled)="cancelledAddEdit($event)" (onEditAttachments)="editCipherAttachments($event)" (onCancelled)="cancelledAddEdit($event)"
(onShareCipher)="shareCipher($event)" (onEditCollections)="cipherCollections($event)" (onShareCipher)="shareCipher($event)" (onEditCollections)="cipherCollections($event)"
(onGeneratePassword)="openPasswordGenerator(true)"> (onGeneratePassword)="openPasswordGenerator(true)">
</app-vault-add-edit> </app-vault-add-edit>
<div id="logo" *ngIf="action !== 'add' && action !== 'edit' && action !== 'view'"> <div id="logo" *ngIf="action !== 'add' && action !== 'edit' && action !== 'view' && action !== 'clone'">
<div class="content"> <div class="content">
<div class="inner-content"> <div class="inner-content">
<img class="logo-image" alt="Bitwarden" aria-hidden="true" /> <img class="logo-image" alt="Bitwarden" aria-hidden="true" />

View File

@ -189,7 +189,9 @@ export class VaultComponent implements OnInit, OnDestroy {
if (params.cipherId) { if (params.cipherId) {
const cipherView = new CipherView(); const cipherView = new CipherView();
cipherView.id = params.cipherId; cipherView.id = params.cipherId;
if (params.action === 'edit') { if (params.action === 'clone') {
await this.cloneCipher(cipherView);
} else if (params.action === 'edit') {
await this.editCipher(cipherView); await this.editCipher(cipherView);
} else { } else {
await this.viewCipher(cipherView); await this.viewCipher(cipherView);
@ -249,6 +251,12 @@ export class VaultComponent implements OnInit, OnDestroy {
this.editCipher(cipher); this.editCipher(cipher);
}), }),
})); }));
menu.append(new remote.MenuItem({
label: this.i18nService.t('clone'),
click: () => this.functionWithChangeDetection(() => {
this.cloneCipher(cipher);
}),
}));
switch (cipher.type) { switch (cipher.type) {
case CipherType.Login: case CipherType.Login:
@ -315,6 +323,18 @@ export class VaultComponent implements OnInit, OnDestroy {
this.go(); this.go();
} }
async cloneCipher(cipher: CipherView) {
if (this.action === 'clone' && this.cipherId === cipher.id) {
return;
} else if (this.dirtyInput() && await this.wantsToSaveChanges()) {
return;
}
this.cipherId = cipher.id;
this.action = 'clone';
this.go();
}
async addCipher(type: CipherType = null) { async addCipher(type: CipherType = null) {
if (this.action === 'add') { if (this.action === 'add') {
return; return;

View File

@ -276,4 +276,7 @@
<button appBlurClick class="primary" (click)="edit()" appA11yTitle="{{'edit' | i18n}}"> <button appBlurClick class="primary" (click)="edit()" appA11yTitle="{{'edit' | i18n}}">
<i class="fa fa-pencil fa-fw fa-lg" aria-hidden="true"></i> <i class="fa fa-pencil fa-fw fa-lg" aria-hidden="true"></i>
</button> </button>
<button appBlurClick class="primary" *ngIf="!cipher?.organizationId" (click)="clone()" appA11yTitle="{{'clone' | i18n}}">
<i class="fa fa-clone fa-fw fa-lg" aria-hidden="true"></i>
</button>
</div> </div>

View File

@ -1273,5 +1273,8 @@
}, },
"unsavedChangesTitle": { "unsavedChangesTitle": {
"message": "Unsaved Changes" "message": "Unsaved Changes"
},
"clone": {
"message": "Clone"
} }
} }