mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-08-16 00:36:22 +00:00
Feature: update user profile (#4678)
This commit is contained in:
@@ -1,8 +1,15 @@
|
||||
<div class="mb-3">
|
||||
<label class="form-label" [for]="inputId">{{title}}</label>
|
||||
<input #inputField type="password" class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)">
|
||||
<small *ngIf="hint" class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
|
||||
<div class="input-group" [class.is-invalid]="error">
|
||||
<input #inputField [type]="showReveal && textVisible ? 'text' : 'password'" class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (focus)="onFocus()" (focusout)="onFocusOut()" (change)="onChange(value)" [disabled]="disabled" [autocomplete]="autocomplete">
|
||||
<button *ngIf="showReveal" type="button" class="btn btn-outline-secondary" (click)="toggleVisibility()" i18n-title title="Show password" [disabled]="disabled || disableRevealToggle">
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#eye" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="invalid-feedback">
|
||||
{{error}}
|
||||
</div>
|
||||
<small *ngIf="hint" class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
|
||||
</div>
|
||||
|
@@ -5,6 +5,7 @@ import {
|
||||
NG_VALUE_ACCESSOR,
|
||||
} from '@angular/forms'
|
||||
import { PasswordComponent } from './password.component'
|
||||
import { By } from '@angular/platform-browser'
|
||||
|
||||
describe('PasswordComponent', () => {
|
||||
let component: PasswordComponent
|
||||
@@ -33,4 +34,26 @@ describe('PasswordComponent', () => {
|
||||
// fixture.detectChanges()
|
||||
// expect(component.value).toEqual('foo')
|
||||
})
|
||||
|
||||
it('should support toggling field visibility', () => {
|
||||
expect(input.type).toEqual('password')
|
||||
component.showReveal = true
|
||||
fixture.detectChanges()
|
||||
fixture.debugElement.query(By.css('button')).triggerEventHandler('click')
|
||||
fixture.detectChanges()
|
||||
expect(input.type).toEqual('text')
|
||||
})
|
||||
|
||||
it('should empty field if password is obfuscated on focus', () => {
|
||||
component.value = '*********'
|
||||
component.onFocus()
|
||||
expect(component.value).toEqual('')
|
||||
component.onFocusOut()
|
||||
expect(component.value).toEqual('**********')
|
||||
})
|
||||
|
||||
it('should disable toggle button if no real password', () => {
|
||||
component.value = '*********'
|
||||
expect(component.disableRevealToggle).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, forwardRef } from '@angular/core'
|
||||
import { Component, Input, forwardRef } from '@angular/core'
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||
import { AbstractInputComponent } from '../abstract-input'
|
||||
|
||||
@@ -15,7 +15,32 @@ import { AbstractInputComponent } from '../abstract-input'
|
||||
styleUrls: ['./password.component.scss'],
|
||||
})
|
||||
export class PasswordComponent extends AbstractInputComponent<string> {
|
||||
constructor() {
|
||||
super()
|
||||
@Input()
|
||||
showReveal: boolean = false
|
||||
|
||||
@Input()
|
||||
autocomplete: string
|
||||
|
||||
public textVisible: boolean = false
|
||||
|
||||
public toggleVisibility(): void {
|
||||
this.textVisible = !this.textVisible
|
||||
}
|
||||
|
||||
public onFocus() {
|
||||
if (this.value?.replace(/\*/g, '').length === 0) {
|
||||
this.writeValue('')
|
||||
}
|
||||
}
|
||||
|
||||
public onFocusOut() {
|
||||
if (this.value?.length === 0) {
|
||||
this.writeValue('**********')
|
||||
this.onChange(this.value)
|
||||
}
|
||||
}
|
||||
|
||||
get disableRevealToggle(): boolean {
|
||||
return this.value?.replace(/\*/g, '').length === 0
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="position-relative" [class.col-md-9]="horizontal">
|
||||
<input #inputField type="text" class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" [disabled]="disabled">
|
||||
<input #inputField type="text" class="form-control" [class.is-invalid]="error" [id]="inputId" [(ngModel)]="value" (change)="onChange(value)" [disabled]="disabled" [autocomplete]="autocomplete">
|
||||
<small *ngIf="hint" class="form-text text-muted" [innerHTML]="hint | safeHtml"></small>
|
||||
<div class="invalid-feedback position-absolute top-100">
|
||||
{{error}}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, forwardRef } from '@angular/core'
|
||||
import { Component, Input, forwardRef } from '@angular/core'
|
||||
import { NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||
import { AbstractInputComponent } from '../abstract-input'
|
||||
|
||||
@@ -15,6 +15,9 @@ import { AbstractInputComponent } from '../abstract-input'
|
||||
styleUrls: ['./text.component.scss'],
|
||||
})
|
||||
export class TextComponent extends AbstractInputComponent<string> {
|
||||
@Input()
|
||||
autocomplete: string
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
Reference in New Issue
Block a user