mirror of
https://github.com/bitwarden/browser
synced 2025-12-22 19:23:52 +00:00
[Linked fields] Add Linked Field as custom field type (#1091)
* Add linked fields * Update to use Field.linkedId * Add missing deps * Update jslib
This commit is contained in:
2
jslib
2
jslib
Submodule jslib updated: 24fe836032...2db9e1ce0d
@@ -130,7 +130,7 @@ const passwordGenerationService = new PasswordGenerationService(cryptoService, s
|
|||||||
const totpService = new TotpService(storageService, cryptoFunctionService, logService);
|
const totpService = new TotpService(storageService, cryptoFunctionService, logService);
|
||||||
const containerService = new ContainerService(cryptoService);
|
const containerService = new ContainerService(cryptoService);
|
||||||
const authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService,
|
const authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService,
|
||||||
i18nService, platformUtilsService, messagingService, vaultTimeoutService, logService);
|
i18nService, platformUtilsService, messagingService, vaultTimeoutService, logService, cryptoFunctionService);
|
||||||
const exportService = new ExportService(folderService, cipherService, apiService, cryptoService);
|
const exportService = new ExportService(folderService, cipherService, apiService, cryptoService);
|
||||||
const auditService = new AuditService(cryptoFunctionService, apiService);
|
const auditService = new AuditService(cryptoFunctionService, apiService);
|
||||||
const notificationsService = new NotificationsService(userService, syncService, appIdService,
|
const notificationsService = new NotificationsService(userService, syncService, appIdService,
|
||||||
|
|||||||
@@ -16,13 +16,21 @@
|
|||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<input id="fieldName{{i}}" type="text" name="Field.Name{{i}}" [(ngModel)]="f.name"
|
<input id="fieldName{{i}}" type="text" name="Field.Name{{i}}" [(ngModel)]="f.name"
|
||||||
class="row-label" placeholder="{{'name' | i18n}}">
|
class="row-label" placeholder="{{'name' | i18n}}">
|
||||||
|
<!-- Text -->
|
||||||
<input id="fieldValue{{i}}" type="text" name="Field.Value{{i}}" [(ngModel)]="f.value"
|
<input id="fieldValue{{i}}" type="text" name="Field.Value{{i}}" [(ngModel)]="f.value"
|
||||||
*ngIf="f.type === fieldType.Text" placeholder="{{'value' | i18n}}">
|
*ngIf="f.type === fieldType.Text" placeholder="{{'value' | i18n}}">
|
||||||
|
<!-- Password -->
|
||||||
<input id="fieldValue{{i}}" type="{{f.showValue ? 'text' : 'password'}}"
|
<input id="fieldValue{{i}}" type="{{f.showValue ? 'text' : 'password'}}"
|
||||||
name="Field.Value{{i}}" [(ngModel)]="f.value" class="monospaced"
|
name="Field.Value{{i}}" [(ngModel)]="f.value" class="monospaced"
|
||||||
*ngIf="f.type === fieldType.Hidden" placeholder="{{'value' | i18n}}"
|
*ngIf="f.type === fieldType.Hidden" placeholder="{{'value' | i18n}}"
|
||||||
[disabled]="!cipher.viewPassword && !f.newField">
|
[disabled]="!cipher.viewPassword && !f.newField">
|
||||||
|
<!-- Linked -->
|
||||||
|
<select id="fieldValue{{i}}" name="Field.Value{{i}}" [(ngModel)]="f.linkedId"
|
||||||
|
*ngIf="f.type === fieldType.Linked && cipher.linkedFieldOptions != null">
|
||||||
|
<option *ngFor="let o of linkedFieldOptions" [ngValue]="o.value">{{o.name}}</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Boolean -->
|
||||||
<input id="fieldValue{{i}}" name="Field.Value{{i}}" type="checkbox" [(ngModel)]="f.value"
|
<input id="fieldValue{{i}}" name="Field.Value{{i}}" type="checkbox" [(ngModel)]="f.value"
|
||||||
*ngIf="f.type === fieldType.Boolean" appTrueFalseValue trueValue="true"
|
*ngIf="f.type === fieldType.Boolean" appTrueFalseValue trueValue="true"
|
||||||
falseValue="false">
|
falseValue="false">
|
||||||
@@ -39,6 +47,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Add new custom field -->
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<a href="#" appStopClick (click)="addField()" role="button">
|
<a href="#" appStopClick (click)="addField()" role="button">
|
||||||
<i class="fa fa-plus-circle fa-fw fa-lg" aria-hidden="true"></i> {{'newCustomField' | i18n}}
|
<i class="fa fa-plus-circle fa-fw fa-lg" aria-hidden="true"></i> {{'newCustomField' | i18n}}
|
||||||
@@ -46,6 +55,9 @@
|
|||||||
<label for="addFieldType" class="sr-only">{{'type' | i18n}}</label>
|
<label for="addFieldType" class="sr-only">{{'type' | i18n}}</label>
|
||||||
<select id="addFieldType" name="AddFieldType" [(ngModel)]="addFieldType" class="field-type">
|
<select id="addFieldType" name="AddFieldType" [(ngModel)]="addFieldType" class="field-type">
|
||||||
<option *ngFor="let o of addFieldTypeOptions" [ngValue]="o.value">{{o.name}}</option>
|
<option *ngFor="let o of addFieldTypeOptions" [ngValue]="o.value">{{o.name}}</option>
|
||||||
|
<option *ngIf="cipher.linkedFieldOptions != null" [ngValue]="addFieldLinkedTypeOption.value">
|
||||||
|
{{addFieldLinkedTypeOption.name}}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -281,7 +281,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<app-vault-add-edit-custom-fields [cipher]="cipher" [editMode]="editMode"></app-vault-add-edit-custom-fields>
|
<app-vault-add-edit-custom-fields [cipher]="cipher" [thisCipherType]="cipher.type" [editMode]="editMode">
|
||||||
|
</app-vault-add-edit-custom-fields>
|
||||||
<div class="box" *ngIf="allowOwnershipOptions()">
|
<div class="box" *ngIf="allowOwnershipOptions()">
|
||||||
<div class="box-header">
|
<div class="box-header">
|
||||||
{{'ownership' | i18n}}
|
{{'ownership' | i18n}}
|
||||||
|
|||||||
@@ -18,6 +18,13 @@
|
|||||||
<i class="fa fa-square-o" *ngIf="field.value !== 'true'" aria-hidden="true"></i>
|
<i class="fa fa-square-o" *ngIf="field.value !== 'true'" aria-hidden="true"></i>
|
||||||
<span class="sr-only">{{field.value}}</span>
|
<span class="sr-only">{{field.value}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="field.type === fieldType.Linked" class="box-content-row-flex">
|
||||||
|
<div class="icon icon-small">
|
||||||
|
<i class="fa fa-link" aria-hidden="true" appA11yTitle="{{'linkedValue' | i18n}}"></i>
|
||||||
|
<span class="sr-only">{{'linkedValue' | i18n}}</span>
|
||||||
|
</div>
|
||||||
|
<span>{{cipher.linkedFieldI18nKey(field.linkedId) | i18n}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<a class="row-btn" href="#" appStopClick appA11yTitle="{{'toggleVisibility' | i18n}}"
|
<a class="row-btn" href="#" appStopClick appA11yTitle="{{'toggleVisibility' | i18n}}"
|
||||||
@@ -27,7 +34,8 @@
|
|||||||
[ngClass]="{'fa-eye': !field.showValue, 'fa-eye-slash': field.showValue}"></i>
|
[ngClass]="{'fa-eye': !field.showValue, 'fa-eye-slash': field.showValue}"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="row-btn" href="#" appStopClick appA11yTitle="{{'copyValue' | i18n}}"
|
<a class="row-btn" href="#" appStopClick appA11yTitle="{{'copyValue' | i18n}}"
|
||||||
*ngIf="field.value && field.type !== fieldType.Boolean && !(field.type === fieldType.Hidden && !cipher.viewPassword)"
|
*ngIf="field.value && field.type !== fieldType.Boolean && field.type !== fieldType.Linked &&
|
||||||
|
!(field.type === fieldType.Hidden && !cipher.viewPassword)"
|
||||||
(click)="copy(field.value, 'value', field.type === fieldType.Hidden ? 'H_Field' : 'Field')"
|
(click)="copy(field.value, 'value', field.type === fieldType.Hidden ? 'H_Field' : 'Field')"
|
||||||
role="button">
|
role="button">
|
||||||
<i class="fa fa-lg fa-clone" aria-hidden="true"></i>
|
<i class="fa fa-lg fa-clone" aria-hidden="true"></i>
|
||||||
|
|||||||
@@ -268,6 +268,9 @@
|
|||||||
"lastName": {
|
"lastName": {
|
||||||
"message": "Last Name"
|
"message": "Last Name"
|
||||||
},
|
},
|
||||||
|
"fullName": {
|
||||||
|
"message": "Full Name"
|
||||||
|
},
|
||||||
"address1": {
|
"address1": {
|
||||||
"message": "Address 1"
|
"message": "Address 1"
|
||||||
},
|
},
|
||||||
@@ -328,6 +331,14 @@
|
|||||||
"cfTypeBoolean": {
|
"cfTypeBoolean": {
|
||||||
"message": "Boolean"
|
"message": "Boolean"
|
||||||
},
|
},
|
||||||
|
"cfTypeLinked": {
|
||||||
|
"message": "Linked",
|
||||||
|
"description": "This describes a field that is 'linked' (related) to another field."
|
||||||
|
},
|
||||||
|
"linkedValue": {
|
||||||
|
"message": "Linked value",
|
||||||
|
"description": "This describes a value that is 'linked' (related) to another value."
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -409,4 +409,21 @@
|
|||||||
background-color: $brand-primary;
|
background-color: $brand-primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 34px;
|
||||||
|
height: 100%;
|
||||||
|
margin-left: -5px;
|
||||||
|
|
||||||
|
@include themify($themes) {
|
||||||
|
color: themed('mutedColor');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-small {
|
||||||
|
min-width: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user