Implement personal item cloning capability (#1129)

* Initial pass of clone item

* Updated npm sub:pull script to include target branches

* Made requested changes

* Formatting changes

* Fixed lint warnings
This commit is contained in:
Vincent Salucci 2020-02-04 15:08:13 -06:00 committed by GitHub
parent a00fa10214
commit c57340c4f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 61 additions and 11 deletions

View File

@ -4,7 +4,7 @@
"scripts": {
"sub:init": "git submodule update --init --recursive",
"sub:update": "git submodule update --remote",
"sub:pull": "git submodule foreach git pull",
"sub:pull": "git submodule foreach git pull origin master",
"postinstall": "npm run sub:init && gulp postinstall",
"symlink:win": "rm -rf ./jslib && cmd /c mklink /J .\\jslib ..\\jslib",
"symlink:mac": "npm run symlink:lin",

View File

@ -1238,5 +1238,11 @@
},
"selectOneCollection": {
"message": "You must select at least one collection."
},
"cloneItem": {
"message": "Clone Item"
},
"clone": {
"message": "Clone"
}
}

View File

@ -106,14 +106,16 @@ export function ciphersToView(fromState: string, toState: string) {
if (fromState == null || toState === null) {
return false;
}
return fromState.indexOf('ciphers_') === 0 && (toState === 'view-cipher' || toState === 'add-cipher');
return fromState.indexOf('ciphers_') === 0 &&
(toState === 'view-cipher' || toState === 'add-cipher' || toState === 'clone-cipher');
}
export function viewToCiphers(fromState: string, toState: string) {
if (fromState == null || toState === null) {
return false;
}
return (fromState === 'view-cipher' || fromState === 'add-cipher') && toState.indexOf('ciphers_') === 0;
return (fromState === 'view-cipher' || fromState === 'add-cipher' || fromState === 'clone-cipher') &&
toState.indexOf('ciphers_') === 0;
}
export const routerTransition = trigger('routerTransition', [
@ -145,14 +147,17 @@ export const routerTransition = trigger('routerTransition', [
transition('view-cipher => edit-cipher, view-cipher => cipher-password-history', inSlideUp),
transition('edit-cipher => view-cipher, cipher-password-history => view-cipher, edit-cipher => tabs', outSlideDown),
transition('view-cipher => clone-cipher', inSlideUp),
transition('clone-cipher => view-cipher, clone-cipher => tabs', outSlideDown),
transition('tabs => add-cipher', inSlideUp),
transition('add-cipher => tabs', outSlideDown),
transition('generator => generator-history, tabs => generator-history', inSlideLeft),
transition('generator-history => generator, generator-history => tabs', outSlideRight),
transition('add-cipher => generator, edit-cipher => generator', inSlideUp),
transition('generator => add-cipher, generator => edit-cipher', outSlideDown),
transition('add-cipher => generator, edit-cipher => generator, clone-cipher => generator', inSlideUp),
transition('generator => add-cipher, generator => edit-cipher, generator => clone-cipher', outSlideDown),
transition('edit-cipher => share-cipher', inSlideUp),
transition('share-cipher => edit-cipher, share-cipher => view-cipher', outSlideDown),
@ -160,6 +165,9 @@ export const routerTransition = trigger('routerTransition', [
transition('edit-cipher => attachments, edit-cipher => collections', inSlideLeft),
transition('attachments => edit-cipher, collections => edit-cipher', outSlideRight),
transition('clone-cipher => attachments, clone-cipher => collections', inSlideLeft),
transition('attachments => clone-cipher, collections => clone-cipher', outSlideRight),
transition('tabs => export', inSlideLeft),
transition('export => tabs', outSlideRight),

View File

@ -204,6 +204,12 @@ const routes: Routes = [
component: PrivateModeComponent,
data: { state: 'private-mode' },
},
{
path: 'clone-cipher',
component: AddEditComponent,
canActivate: [AuthGuardService],
data: { state: 'clone-cipher' },
},
{
path: 'tabs',
component: TabsComponent,

View File

@ -256,7 +256,7 @@
<i class="fa fa-chevron-right row-sub-icon" aria-hidden="true"></i>
</a>
<a class="box-content-row box-content-row-flex text-default" href="#" appStopClick appBlurClick
(click)="editCollections()" *ngIf="editMode && cipher.organizationId">
(click)="editCollections()" *ngIf="editMode && cipher.organizationId && !cloneMode">
<div class="row-main">{{'collections' | i18n}}</div>
<i class="fa fa-chevron-right row-sub-icon" aria-hidden="true"></i>
</a>
@ -320,7 +320,7 @@
</div>
</div>
</div>
<div class="box" *ngIf="!editMode && ownershipOptions && ownershipOptions.length > 1">
<div class="box" *ngIf="(!editMode || cloneMode) && ownershipOptions && ownershipOptions.length > 1">
<div class="box-header">
{{'ownership' | i18n}}
</div>
@ -334,7 +334,7 @@
</div>
</div>
</div>
<div class="box" *ngIf="!editMode && cipher.organizationId">
<div class="box" *ngIf="(!editMode || cloneMode )&& cipher.organizationId">
<div class="box-header">
{{'collections' | i18n}}
</div>
@ -352,7 +352,7 @@
</div>
</div>
</div>
<div class="box list" *ngIf="editMode">
<div class="box list" *ngIf="editMode && !cloneMode">
<div class="box-content single-line">
<a class="box-content-row" href="#" appStopClick appBlurClick (click)="share()"
*ngIf="!cipher.organizationId">

View File

@ -58,6 +58,10 @@ export class AddEditComponent extends BaseAddEditComponent {
this.type = type;
}
this.editMode = !params.cipherId;
if (params.cloneMode != null) {
this.cloneMode = params.cloneMode === true;
}
await this.load();
if (!this.editMode) {
@ -86,7 +90,11 @@ export class AddEditComponent extends BaseAddEditComponent {
async submit(): Promise<boolean> {
if (await super.submit()) {
this.location.back();
if (this.cloneMode) {
this.router.navigate(['/tabs/vault']);
} else {
this.location.back();
}
return true;
}

View File

@ -259,6 +259,18 @@
</a>
</div>
</div>
<div class="box list" *ngIf="!cipher.organizationId">
<div class="box-content single-line">
<a class="box-content-row" href="#" appStopClick appBlurClick (click)="clone()">
<div class="row-main text-primary">
<div class="icon text-primary" aria-hidden="true">
<i class="fa fa-clone fa-lg fa-fw"></i>
</div>
<span>{{'cloneItem' | i18n}}</span>
</div>
</a>
</div>
</div>
<div class="box">
<div class="box-footer">
<div>

View File

@ -64,6 +64,16 @@ export class ViewComponent extends BaseViewComponent {
this.router.navigate(['/edit-cipher'], { queryParams: { cipherId: this.cipher.id } });
}
clone() {
super.clone();
this.router.navigate(['/clone-cipher'], {
queryParams: {
cloneMode: true,
cipherId: this.cipher.id,
},
});
}
close() {
this.location.back();
}