add/edit cipher modal

This commit is contained in:
Kyle Spearrin 2018-06-06 23:23:14 -04:00
parent 0fb66e247a
commit a52aadd37d
5 changed files with 313 additions and 317 deletions

View File

@ -23,6 +23,7 @@ import { RegisterComponent } from './accounts/register.component';
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
import { TwoFactorComponent } from './accounts/two-factor.component';
import { AddEditComponent } from './vault/add-edit.component';
import { AttachmentsComponent } from './vault/attachments.component';
import { CiphersComponent } from './vault/ciphers.component';
import { FolderAddEditComponent } from './vault/folder-add-edit.component';
@ -59,6 +60,7 @@ import { Folder } from 'jslib/models/domain';
ToasterModule,
],
declarations: [
AddEditComponent,
ApiActionDirective,
AppComponent,
AttachmentsComponent,
@ -84,6 +86,7 @@ import { Folder } from 'jslib/models/domain';
VaultComponent,
],
entryComponents: [
AddEditComponent,
AttachmentsComponent,
FolderAddEditComponent,
ModalComponent,

View File

@ -1,309 +1,279 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<div class="content">
<div class="inner-content" *ngIf="cipher">
<div class="box">
<div class="box-header">
{{title}}
</div>
<div class="box-content">
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
<label for="type">{{'type' | i18n}}</label>
<select id="type" name="Type" [(ngModel)]="cipher.type">
<option *ngFor="let o of typeOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row" appBoxRow>
<label for="name">{{'name' | i18n}}</label>
<input id="name" type="text" name="Name" [(ngModel)]="cipher.name" [appAutofocus]="!editMode">
</div>
<!-- Login -->
<div *ngIf="cipher.type === cipherType.Login">
<div class="box-content-row" appBoxRow>
<label for="loginUsername">{{'username' | i18n}}</label>
<input id="loginUsername" type="text" name="Login.Username"
[(ngModel)]="cipher.login.username">
</div>
<div class="box-content-row box-content-row-flex" appBoxRow>
<div class="row-main">
<label for="loginPassword">{{'password' | i18n}}</label>
<input id="loginPassword" class="monospaced"
type="{{showPassword ? 'text' : 'password'}}" name="Login.Password"
[(ngModel)]="cipher.login.password">
<div class="modal fade">
<div class="modal-dialog modal-lg">
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<div class="modal-body">
<div class="content">
<div class="inner-content" *ngIf="cipher">
<div class="box">
<div class="box-header">
{{title}}
</div>
<div class="action-buttons">
<button type="button" #checkPasswordBtn class="row-btn btn" appBlurClick
title="{{'checkPassword' | i18n}}" (click)="checkPassword()"
[appApiAction]="checkPasswordPromise" [disabled]="checkPasswordBtn.loading">
<i class="fa fa-lg fa-check-circle" [hidden]="checkPasswordBtn.loading"></i>
<i class="fa fa-lg fa-spinner fa-spin" [hidden]="!checkPasswordBtn.loading"></i>
</button>
<a class="row-btn" href="#" appStopClick appBlurClick
title="{{'toggleVisibility' | i18n}}" (click)="togglePassword()">
<i class="fa fa-lg"
[ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</a>
<a class="row-btn" href="#" appStopClick appBlurClick
title="{{'generatePassword' | i18n}}" (click)="generatePassword()">
<i class="fa fa-lg fa-refresh"></i>
<div class="box-content">
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
<label for="type">{{'type' | i18n}}</label>
<select id="type" name="Type" [(ngModel)]="cipher.type">
<option *ngFor="let o of typeOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row" appBoxRow>
<label for="name">{{'name' | i18n}}</label>
<input id="name" type="text" name="Name" [(ngModel)]="cipher.name" [appAutofocus]="!editMode">
</div>
<!-- Login -->
<div *ngIf="cipher.type === cipherType.Login">
<div class="box-content-row" appBoxRow>
<label for="loginUsername">{{'username' | i18n}}</label>
<input id="loginUsername" type="text" name="Login.Username" [(ngModel)]="cipher.login.username">
</div>
<div class="box-content-row box-content-row-flex" appBoxRow>
<div class="row-main">
<label for="loginPassword">{{'password' | i18n}}</label>
<input id="loginPassword" class="monospaced" type="{{showPassword ? 'text' : 'password'}}" name="Login.Password" [(ngModel)]="cipher.login.password">
</div>
<div class="action-buttons">
<button type="button" #checkPasswordBtn class="row-btn btn" appBlurClick title="{{'checkPassword' | i18n}}" (click)="checkPassword()"
[appApiAction]="checkPasswordPromise" [disabled]="checkPasswordBtn.loading">
<i class="fa fa-lg fa-check-circle" [hidden]="checkPasswordBtn.loading"></i>
<i class="fa fa-lg fa-spinner fa-spin" [hidden]="!checkPasswordBtn.loading"></i>
</button>
<a class="row-btn" href="#" appStopClick appBlurClick title="{{'toggleVisibility' | i18n}}" (click)="togglePassword()">
<i class="fa fa-lg" [ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</a>
<a class="row-btn" href="#" appStopClick appBlurClick title="{{'generatePassword' | i18n}}" (click)="generatePassword()">
<i class="fa fa-lg fa-refresh"></i>
</a>
</div>
</div>
<div class="box-content-row" appBoxRow>
<label for="loginTotp">{{'authenticatorKeyTotp' | i18n}}</label>
<input id="loginTotp" type="text" name="Login.Totp" class="monospaced" [(ngModel)]="cipher.login.totp">
</div>
</div>
<!-- Card -->
<div *ngIf="cipher.type === cipherType.Card">
<div class="box-content-row" appBoxRow>
<label for="cardCardholderName">{{'cardholderName' | i18n}}</label>
<input id="cardCardholderName" type="text" name="Card.CardCardholderName" [(ngModel)]="cipher.card.cardholderName">
</div>
<div class="box-content-row" appBoxRow>
<label for="cardNumber">{{'number' | i18n}}</label>
<input id="cardNumber" type="text" name="Card.Number" [(ngModel)]="cipher.card.number">
</div>
<div class="box-content-row" appBoxRow>
<label for="cardBrand">{{'brand' | i18n}}</label>
<select id="cardBrand" name="Card.Brand" [(ngModel)]="cipher.card.brand">
<option *ngFor="let o of cardBrandOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row" appBoxRow>
<label for="cardExpMonth">{{'expirationMonth' | i18n}}</label>
<select id="cardExpMonth" name="Card.ExpMonth" [(ngModel)]="cipher.card.expMonth">
<option *ngFor="let o of cardExpMonthOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row" appBoxRow>
<label for="cardExpYear">{{'expirationYear' | i18n}}</label>
<input id="cardExpYear" type="text" name="Card.ExpYear" [(ngModel)]="cipher.card.expYear" placeholder="{{'ex' | i18n}} 2019">
</div>
<div class="box-content-row" appBoxRow>
<label for="cardCode">{{'securityCode' | i18n}}</label>
<input id="cardCode" type="text" name="Card.Code" [(ngModel)]="cipher.card.code">
</div>
</div>
<!-- Identity -->
<div *ngIf="cipher.type === cipherType.Identity">
<div class="box-content-row" appBoxRow>
<label for="idTitle">{{'title' | i18n}}</label>
<select id="idTitle" name="Identity.Title" [(ngModel)]="cipher.identity.title">
<option *ngFor="let o of identityTitleOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row" appBoxRow>
<label for="idFirstName">{{'firstName' | i18n}}</label>
<input id="idFirstName" type="text" name="Identity.FirstName" [(ngModel)]="cipher.identity.firstName">
</div>
<div class="box-content-row" appBoxRow>
<label for="idMiddleName">{{'middleName' | i18n}}</label>
<input id="idMiddleName" type="text" name="Identity.MiddleName" [(ngModel)]="cipher.identity.middleName">
</div>
<div class="box-content-row" appBoxRow>
<label for="idLastName">{{'lastName' | i18n}}</label>
<input id="idLastName" type="text" name="Identity.LastName" [(ngModel)]="cipher.identity.lastName">
</div>
<div class="box-content-row" appBoxRow>
<label for="idUsername">{{'username' | i18n}}</label>
<input id="idUsername" type="text" name="Identity.Username" [(ngModel)]="cipher.identity.username">
</div>
<div class="box-content-row" appBoxRow>
<label for="idCompany">{{'company' | i18n}}</label>
<input id="idCompany" type="text" name="Identity.Company" [(ngModel)]="cipher.identity.company">
</div>
<div class="box-content-row" appBoxRow>
<label for="idSsn">{{'ssn' | i18n}}</label>
<input id="idSsn" type="text" name="Identity.SSN" [(ngModel)]="cipher.identity.ssn">
</div>
<div class="box-content-row" appBoxRow>
<label for="idPassportNumber">{{'passportNumber' | i18n}}</label>
<input id="idPassportNumber" type="text" name="Identity.PassportNumber" [(ngModel)]="cipher.identity.passportNumber">
</div>
<div class="box-content-row" appBoxRow>
<label for="idLicenseNumber">{{'licenseNumber' | i18n}}</label>
<input id="idLicenseNumber" type="text" name="Identity.LicenseNumber" [(ngModel)]="cipher.identity.licenseNumber">
</div>
<div class="box-content-row" appBoxRow>
<label for="idEmail">{{'email' | i18n}}</label>
<input id="idEmail" type="text" name="Identity.Email" [(ngModel)]="cipher.identity.email">
</div>
<div class="box-content-row" appBoxRow>
<label for="idPhone">{{'phone' | i18n}}</label>
<input id="idPhone" type="text" name="Identity.Phone" [(ngModel)]="cipher.identity.phone">
</div>
<div class="box-content-row" appBoxRow>
<label for="idAddress1">{{'address1' | i18n}}</label>
<input id="idAddress1" type="text" name="Identity.Address1" [(ngModel)]="cipher.identity.address1">
</div>
<div class="box-content-row" appBoxRow>
<label for="idAddress2">{{'address2' | i18n}}</label>
<input id="idAddress2" type="text" name="Identity.Address2" [(ngModel)]="cipher.identity.address2">
</div>
<div class="box-content-row" appBoxRow>
<label for="idAddress3">{{'address3' | i18n}}</label>
<input id="idAddress3" type="text" name="Identity.Address3" [(ngModel)]="cipher.identity.address3">
</div>
<div class="box-content-row" appBoxRow>
<label for="idCity">{{'cityTown' | i18n}}</label>
<input id="idCity" type="text" name="Identity.City" [(ngModel)]="cipher.identity.city">
</div>
<div class="box-content-row" appBoxRow>
<label for="idState">{{'stateProvince' | i18n}}</label>
<input id="idState" type="text" name="Identity.State" [(ngModel)]="cipher.identity.state">
</div>
<div class="box-content-row" appBoxRow>
<label for="idPostalCode">{{'zipPostalCode' | i18n}}</label>
<input id="idPostalCode" type="text" name="Identity.PostalCode" [(ngModel)]="cipher.identity.postalCode">
</div>
<div class="box-content-row" appBoxRow>
<label for="idCountry">{{'country' | i18n}}</label>
<input id="idCountry" type="text" name="Identity.Country" [(ngModel)]="cipher.identity.country">
</div>
</div>
</div>
</div>
<div class="box" *ngIf="cipher.type === cipherType.Login">
<div class="box-content">
<ng-container *ngIf="cipher.login.hasUris">
<div class="box-content-row box-content-row-multi" appBoxRow *ngFor="let u of cipher.login.uris; let i = index">
<a href="#" appStopClick (click)="removeUri(u)" title="{{'remove' | i18n}}">
<i class="fa fa-minus-circle fa-lg"></i>
</a>
<div class="row-main">
<label for="loginUri{{i}}">{{'uriPosition' | i18n : (i + 1)}}</label>
<input id="loginUri{{i}}" type="text" name="Login.Uris[{{i}}].Uri" [(ngModel)]="u.uri" placeholder="{{'ex' | i18n}} https://google.com">
<label for="loginUriMatch{{i}}" class="sr-only">
{{'matchDetection' | i18n}} {{(i + 1)}}
</label>
<select id="loginUriMatch{{i}}" name="Login.Uris[{{i}}].Match" [(ngModel)]="u.match" [hidden]="u.showOptions === false || (u.showOptions == null && u.match == null)"
(change)="loginUriMatchChanged(u)">
<option *ngFor="let o of uriMatchOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="action-buttons">
<a class="row-btn" href="#" appStopClick appBlurClick title="{{'toggleOptions' | i18n}}" (click)="toggleUriOptions(u)">
<i class="fa fa-lg fa-cog"></i>
</a>
</div>
</div>
</ng-container>
<a href="#" appStopClick appBlurClick (click)="addUri()" class="box-content-row">
<i class="fa fa-plus-circle fa-fw fa-lg"></i> {{'newUri' | i18n}}
</a>
</div>
</div>
<div class="box-content-row" appBoxRow>
<label for="loginTotp">{{'authenticatorKeyTotp' | i18n}}</label>
<input id="loginTotp" type="text" name="Login.Totp" class="monospaced"
[(ngModel)]="cipher.login.totp">
</div>
</div>
<!-- Card -->
<div *ngIf="cipher.type === cipherType.Card">
<div class="box-content-row" appBoxRow>
<label for="cardCardholderName">{{'cardholderName' | i18n}}</label>
<input id="cardCardholderName" type="text" name="Card.CardCardholderName"
[(ngModel)]="cipher.card.cardholderName">
</div>
<div class="box-content-row" appBoxRow>
<label for="cardNumber">{{'number' | i18n}}</label>
<input id="cardNumber" type="text" name="Card.Number" [(ngModel)]="cipher.card.number">
</div>
<div class="box-content-row" appBoxRow>
<label for="cardBrand">{{'brand' | i18n}}</label>
<select id="cardBrand" name="Card.Brand" [(ngModel)]="cipher.card.brand">
<option *ngFor="let o of cardBrandOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row" appBoxRow>
<label for="cardExpMonth">{{'expirationMonth' | i18n}}</label>
<select id="cardExpMonth" name="Card.ExpMonth" [(ngModel)]="cipher.card.expMonth">
<option *ngFor="let o of cardExpMonthOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row" appBoxRow>
<label for="cardExpYear">{{'expirationYear' | i18n}}</label>
<input id="cardExpYear" type="text" name="Card.ExpYear" [(ngModel)]="cipher.card.expYear"
placeholder="{{'ex' | i18n}} 2019">
</div>
<div class="box-content-row" appBoxRow>
<label for="cardCode">{{'securityCode' | i18n}}</label>
<input id="cardCode" type="text" name="Card.Code" [(ngModel)]="cipher.card.code">
</div>
</div>
<!-- Identity -->
<div *ngIf="cipher.type === cipherType.Identity">
<div class="box-content-row" appBoxRow>
<label for="idTitle">{{'title' | i18n}}</label>
<select id="idTitle" name="Identity.Title" [(ngModel)]="cipher.identity.title">
<option *ngFor="let o of identityTitleOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row" appBoxRow>
<label for="idFirstName">{{'firstName' | i18n}}</label>
<input id="idFirstName" type="text" name="Identity.FirstName"
[(ngModel)]="cipher.identity.firstName">
</div>
<div class="box-content-row" appBoxRow>
<label for="idMiddleName">{{'middleName' | i18n}}</label>
<input id="idMiddleName" type="text" name="Identity.MiddleName"
[(ngModel)]="cipher.identity.middleName">
</div>
<div class="box-content-row" appBoxRow>
<label for="idLastName">{{'lastName' | i18n}}</label>
<input id="idLastName" type="text" name="Identity.LastName"
[(ngModel)]="cipher.identity.lastName">
</div>
<div class="box-content-row" appBoxRow>
<label for="idUsername">{{'username' | i18n}}</label>
<input id="idUsername" type="text" name="Identity.Username"
[(ngModel)]="cipher.identity.username">
</div>
<div class="box-content-row" appBoxRow>
<label for="idCompany">{{'company' | i18n}}</label>
<input id="idCompany" type="text" name="Identity.Company"
[(ngModel)]="cipher.identity.company">
</div>
<div class="box-content-row" appBoxRow>
<label for="idSsn">{{'ssn' | i18n}}</label>
<input id="idSsn" type="text" name="Identity.SSN" [(ngModel)]="cipher.identity.ssn">
</div>
<div class="box-content-row" appBoxRow>
<label for="idPassportNumber">{{'passportNumber' | i18n}}</label>
<input id="idPassportNumber" type="text" name="Identity.PassportNumber"
[(ngModel)]="cipher.identity.passportNumber">
</div>
<div class="box-content-row" appBoxRow>
<label for="idLicenseNumber">{{'licenseNumber' | i18n}}</label>
<input id="idLicenseNumber" type="text" name="Identity.LicenseNumber"
[(ngModel)]="cipher.identity.licenseNumber">
</div>
<div class="box-content-row" appBoxRow>
<label for="idEmail">{{'email' | i18n}}</label>
<input id="idEmail" type="text" name="Identity.Email" [(ngModel)]="cipher.identity.email">
</div>
<div class="box-content-row" appBoxRow>
<label for="idPhone">{{'phone' | i18n}}</label>
<input id="idPhone" type="text" name="Identity.Phone" [(ngModel)]="cipher.identity.phone">
</div>
<div class="box-content-row" appBoxRow>
<label for="idAddress1">{{'address1' | i18n}}</label>
<input id="idAddress1" type="text" name="Identity.Address1"
[(ngModel)]="cipher.identity.address1">
</div>
<div class="box-content-row" appBoxRow>
<label for="idAddress2">{{'address2' | i18n}}</label>
<input id="idAddress2" type="text" name="Identity.Address2"
[(ngModel)]="cipher.identity.address2">
</div>
<div class="box-content-row" appBoxRow>
<label for="idAddress3">{{'address3' | i18n}}</label>
<input id="idAddress3" type="text" name="Identity.Address3"
[(ngModel)]="cipher.identity.address3">
</div>
<div class="box-content-row" appBoxRow>
<label for="idCity">{{'cityTown' | i18n}}</label>
<input id="idCity" type="text" name="Identity.City" [(ngModel)]="cipher.identity.city">
</div>
<div class="box-content-row" appBoxRow>
<label for="idState">{{'stateProvince' | i18n}}</label>
<input id="idState" type="text" name="Identity.State" [(ngModel)]="cipher.identity.state">
</div>
<div class="box-content-row" appBoxRow>
<label for="idPostalCode">{{'zipPostalCode' | i18n}}</label>
<input id="idPostalCode" type="text" name="Identity.PostalCode"
[(ngModel)]="cipher.identity.postalCode">
</div>
<div class="box-content-row" appBoxRow>
<label for="idCountry">{{'country' | i18n}}</label>
<input id="idCountry" type="text" name="Identity.Country"
[(ngModel)]="cipher.identity.country">
</div>
</div>
</div>
</div>
<div class="box" *ngIf="cipher.type === cipherType.Login">
<div class="box-content">
<ng-container *ngIf="cipher.login.hasUris">
<div class="box-content-row box-content-row-multi" appBoxRow
*ngFor="let u of cipher.login.uris; let i = index">
<a href="#" appStopClick (click)="removeUri(u)" title="{{'remove' | i18n}}">
<i class="fa fa-minus-circle fa-lg"></i>
</a>
<div class="row-main">
<label for="loginUri{{i}}">{{'uriPosition' | i18n : (i + 1)}}</label>
<input id="loginUri{{i}}" type="text" name="Login.Uris[{{i}}].Uri" [(ngModel)]="u.uri"
placeholder="{{'ex' | i18n}} https://google.com">
<label for="loginUriMatch{{i}}" class="sr-only">
{{'matchDetection' | i18n}} {{(i + 1)}}
</label>
<select id="loginUriMatch{{i}}" name="Login.Uris[{{i}}].Match" [(ngModel)]="u.match"
[hidden]="u.showOptions === false || (u.showOptions == null && u.match == null)"
(change)="loginUriMatchChanged(u)">
<option *ngFor="let o of uriMatchOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="action-buttons">
<a class="row-btn" href="#" appStopClick appBlurClick
title="{{'toggleOptions' | i18n}}" (click)="toggleUriOptions(u)">
<i class="fa fa-lg fa-cog"></i>
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="folder">{{'folder' | i18n}}</label>
<select id="folder" name="FolderId" [(ngModel)]="cipher.folderId">
<option *ngFor="let f of folders" [ngValue]="f.id">{{f.name}}</option>
</select>
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="favorite">{{'favorite' | i18n}}</label>
<input id="favorite" type="checkbox" name="Favorite" [(ngModel)]="cipher.favorite">
</div>
<a class="box-content-row box-content-row-flex text-default" href="#" appStopClick appBlurClick (click)="attachments()" *ngIf="editMode">
<div class="row-main">{{'attachments' | i18n}}</div>
<i class="fa fa-chevron-right row-sub-icon"></i>
</a>
</div>
</div>
</ng-container>
<a href="#" appStopClick appBlurClick (click)="addUri()" class="box-content-row">
<i class="fa fa-plus-circle fa-fw fa-lg"></i> {{'newUri' | i18n}}
</a>
</div>
</div>
<div class="box">
<div class="box-content">
<div class="box-content-row" appBoxRow>
<label for="folder">{{'folder' | i18n}}</label>
<select id="folder" name="FolderId" [(ngModel)]="cipher.folderId">
<option *ngFor="let f of folders" [ngValue]="f.id">{{f.name}}</option>
</select>
</div>
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="favorite">{{'favorite' | i18n}}</label>
<input id="favorite" type="checkbox" name="Favorite" [(ngModel)]="cipher.favorite">
</div>
<a class="box-content-row box-content-row-flex text-default" href="#" appStopClick appBlurClick
(click)="attachments()" *ngIf="editMode">
<div class="row-main">{{'attachments' | i18n}}</div>
<i class="fa fa-chevron-right row-sub-icon"></i>
</a>
</div>
</div>
<div class="box">
<div class="box-header">
<label for="notes">{{'notes' | i18n}}</label>
</div>
<div class="box-content">
<div class="box-content-row" appBoxRow>
<textarea id="notes" name="Notes" rows="6" [(ngModel)]="cipher.notes"></textarea>
</div>
</div>
</div>
<div class="box">
<div class="box-header">
{{'customFields' | i18n}}
</div>
<div class="box-content">
<ng-container *ngIf="cipher.hasFields">
<div class="box-content-row box-content-row-multi" appBoxRow
*ngFor="let f of cipher.fields; let i = index"
[ngClass]="{'box-content-row-checkbox': f.type === fieldType.Boolean}">
<a href="#" appStopClick (click)="removeField(f)" title="{{'remove' | i18n}}">
<i class="fa fa-minus-circle fa-lg"></i>
</a>
<label for="fieldName{{i}}" class="sr-only">{{'name' | i18n}}</label>
<label for="fieldValue{{i}}" class="sr-only">{{'value' | i18n}}</label>
<div class="row-main">
<input id="fieldName{{i}}" type="text" name="Field.Name{{i}}" [(ngModel)]="f.name"
class="row-label" placeholder="{{'name' | i18n}}">
<input id="fieldValue{{i}}" type="text" name="Field.Value{{i}}" [(ngModel)]="f.value"
*ngIf="f.type === fieldType.Text" placeholder="{{'value' | i18n}}">
<input id="fieldValue{{i}}" type="{{f.showValue ? 'text' : 'password'}}"
name="Field.Value{{i}}" [(ngModel)]="f.value" class="monospaced"
*ngIf="f.type === fieldType.Hidden" placeholder="{{'value' | i18n}}">
<div class="box">
<div class="box-header">
<label for="notes">{{'notes' | i18n}}</label>
</div>
<input id="fieldValue{{i}}" name="Field.Value{{i}}" type="checkbox"
[(ngModel)]="f.value" *ngIf="f.type === fieldType.Boolean"
appTrueFalseValue trueValue="true" falseValue="false">
<div class="action-buttons" *ngIf="f.type === fieldType.Hidden">
<a class="row-btn" href="#" appStopClick appBlurClick
title="{{'toggleVisibility' | i18n}}" (click)="toggleFieldValue(f)">
<i class="fa fa-lg"
[ngClass]="{'fa-eye': !f.showValue, 'fa-eye-slash': f.showValue}"></i>
</a>
<div class="box-content">
<div class="box-content-row" appBoxRow>
<textarea id="notes" name="Notes" rows="6" [(ngModel)]="cipher.notes"></textarea>
</div>
</div>
</div>
</ng-container>
<div class="box-content-row" appBoxRow>
<a href="#" appStopClick (click)="addField()">
<i class="fa fa-plus-circle fa-fw fa-lg"></i> {{'newCustomField' | i18n}}
</a>
<label for="addFieldType" class="sr-only">{{'type' | i18n}}</label>
<select id="addFieldType" name="AddFieldType" [(ngModel)]="addFieldType" class="field-type">
<option *ngFor="let o of addFieldTypeOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
<div class="box">
<div class="box-header">
{{'customFields' | i18n}}
</div>
<div class="box-content">
<ng-container *ngIf="cipher.hasFields">
<div class="box-content-row box-content-row-multi" appBoxRow *ngFor="let f of cipher.fields; let i = index" [ngClass]="{'box-content-row-checkbox': f.type === fieldType.Boolean}">
<a href="#" appStopClick (click)="removeField(f)" title="{{'remove' | i18n}}">
<i class="fa fa-minus-circle fa-lg"></i>
</a>
<label for="fieldName{{i}}" class="sr-only">{{'name' | i18n}}</label>
<label for="fieldValue{{i}}" class="sr-only">{{'value' | i18n}}</label>
<div class="row-main">
<input id="fieldName{{i}}" type="text" name="Field.Name{{i}}" [(ngModel)]="f.name" class="row-label" placeholder="{{'name' | i18n}}">
<input id="fieldValue{{i}}" type="text" name="Field.Value{{i}}" [(ngModel)]="f.value" *ngIf="f.type === fieldType.Text" placeholder="{{'value' | i18n}}">
<input id="fieldValue{{i}}" type="{{f.showValue ? 'text' : 'password'}}" name="Field.Value{{i}}" [(ngModel)]="f.value" class="monospaced"
*ngIf="f.type === fieldType.Hidden" placeholder="{{'value' | i18n}}">
</div>
<input id="fieldValue{{i}}" name="Field.Value{{i}}" type="checkbox" [(ngModel)]="f.value" *ngIf="f.type === fieldType.Boolean"
appTrueFalseValue trueValue="true" falseValue="false">
<div class="action-buttons" *ngIf="f.type === fieldType.Hidden">
<a class="row-btn" href="#" appStopClick appBlurClick title="{{'toggleVisibility' | i18n}}" (click)="toggleFieldValue(f)">
<i class="fa fa-lg" [ngClass]="{'fa-eye': !f.showValue, 'fa-eye-slash': f.showValue}"></i>
</a>
</div>
</div>
</ng-container>
<div class="box-content-row" appBoxRow>
<a href="#" appStopClick (click)="addField()">
<i class="fa fa-plus-circle fa-fw fa-lg"></i> {{'newCustomField' | i18n}}
</a>
<label for="addFieldType" class="sr-only">{{'type' | i18n}}</label>
<select id="addFieldType" name="AddFieldType" [(ngModel)]="addFieldType" class="field-type">
<option *ngFor="let o of addFieldTypeOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<button appBlurClick type="submit" class="primary" title="{{'save' | i18n}}" [disabled]="form.loading">
<i class="fa fa-save fa-lg fa-fw" [hidden]="form.loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!form.loading"></i>
</button>
<button appBlurClick type="button" (click)="cancel()" title="{{'cancel' | i18n}}">
{{'cancel' | i18n}}
</button>
<div class="right">
<button #deleteBtn appBlurClick type="button" (click)="delete()" class="danger" title="{{'delete' | i18n}}" *ngIf="editMode"
[disabled]="deleteBtn.loading" [appApiAction]="deletePromise">
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading"></i>
</button>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="footer">
<button appBlurClick type="submit" class="primary" title="{{'save' | i18n}}" [disabled]="form.loading">
<i class="fa fa-save fa-lg fa-fw" [hidden]="form.loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!form.loading"></i>
</button>
<button appBlurClick type="button" (click)="cancel()" title="{{'cancel' | i18n}}">
{{'cancel' | i18n}}
</button>
<div class="right">
<button #deleteBtn appBlurClick type="button" (click)="delete()" class="danger"
title="{{'delete' | i18n}}" *ngIf="editMode" [disabled]="deleteBtn.loading"
[appApiAction]="deletePromise">
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading"></i>
</button>
</div>
</div>
</form>
</div>

View File

@ -1,6 +1,6 @@
import {
Component,
OnChanges,
OnInit,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
@ -19,7 +19,7 @@ import { AddEditComponent as BaseAddEditComponent } from 'jslib/angular/componen
selector: 'app-vault-add-edit',
templateUrl: 'add-edit.component.html',
})
export class AddEditComponent extends BaseAddEditComponent implements OnChanges {
export class AddEditComponent extends BaseAddEditComponent implements OnInit {
constructor(cipherService: CipherService, folderService: FolderService,
i18nService: I18nService, platformUtilsService: PlatformUtilsService,
analytics: Angulartics2, toasterService: ToasterService,
@ -28,7 +28,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnChanges
toasterService, auditService, stateService);
}
async ngOnChanges() {
async ngOnInit() {
await super.load();
}
}

View File

@ -30,20 +30,17 @@
<div class="container page-content">
<div class="row">
<div class="col-3">
<app-vault-groupings
(onAllClicked)="clearGroupingFilters()"
(onFavoritesClicked)="filterFavorites()"
(onCipherTypeClicked)="filterCipherType($event)"
(onFolderClicked)="filterFolder($event.id)"
(onAddFolder)="addFolder()"
(onEditFolder)="editFolder($event.id)"
(onCollectionClicked)="filterCollection($event.id)"
(onSearchTextChanged)="filterSearchText($event)">
<app-vault-groupings (onAllClicked)="clearGroupingFilters()" (onFavoritesClicked)="filterFavorites()" (onCipherTypeClicked)="filterCipherType($event)"
(onFolderClicked)="filterFolder($event.id)" (onAddFolder)="addFolder()" (onEditFolder)="editFolder($event.id)"
(onCollectionClicked)="filterCollection($event.id)" (onSearchTextChanged)="filterSearchText($event)">
</app-vault-groupings>
</div>
<div class="col-6">
<app-vault-ciphers
(onCipherClicked)="editCipher($event)">
<button type="button" class="btn btn-secondary btn-sm pull-right" (click)="addCipher()">
<i class="fa fa-plus"></i>
</button>
<h1>My Vault</h1>
<app-vault-ciphers (onCipherClicked)="editCipher($event)">
</app-vault-ciphers>
</div>
<div class="col-3">
@ -70,3 +67,4 @@
</div>
<ng-template #attachments></ng-template>
<ng-template #folderAddEdit></ng-template>
<ng-template #cipherAddEdit></ng-template>

View File

@ -18,6 +18,7 @@ import { FolderView } from 'jslib/models/view/folderView';
import { ModalComponent } from '../modal.component';
import { AddEditComponent } from './add-edit.component';
import { AttachmentsComponent } from './attachments.component';
import { CiphersComponent } from './ciphers.component';
import { FolderAddEditComponent } from './folder-add-edit.component';
@ -35,6 +36,7 @@ export class VaultComponent implements OnInit {
@ViewChild(CiphersComponent) ciphersComponent: CiphersComponent;
@ViewChild('attachments', { read: ViewContainerRef }) attachmentsModalRef: ViewContainerRef;
@ViewChild('folderAddEdit', { read: ViewContainerRef }) folderAddEditModalRef: ViewContainerRef;
@ViewChild('cipherAddEdit', { read: ViewContainerRef }) cipherAddEditRef: ViewContainerRef;
cipherId: string = null;
favorites: boolean = false;
@ -80,14 +82,6 @@ export class VaultComponent implements OnInit {
});
}
editCipher(cipher: CipherView) {
console.log(cipher);
}
addCipher(type: CipherType = null) {
//
}
async clearGroupingFilters() {
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchVault');
await this.ciphersComponent.load();
@ -194,6 +188,37 @@ export class VaultComponent implements OnInit {
});
}
addCipher() {
const component = this.editCipher(null);
component.type = this.type;
component.folderId = this.folderId === 'none' ? null : this.folderId;
}
editCipher(cipher: CipherView) {
if (this.modal != null) {
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.cipherAddEditRef.createComponent(factory).instance;
const childComponent = this.modal.show<AddEditComponent>(
AddEditComponent, this.cipherAddEditRef);
childComponent.cipherId = cipher == null ? null : cipher.id;
childComponent.onSavedCipher.subscribe(async (cipher: CipherView) => {
this.modal.close();
});
childComponent.onDeletedCipher.subscribe(async (cipher: CipherView) => {
this.modal.close();
});
this.modal.onClosed.subscribe(() => {
this.modal = null;
});
return childComponent;
}
private clearFilters() {
this.folderId = null;
this.collectionId = null;