mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 06:13:38 +00:00
[EC-474] Add hidden char count toggle to web and desktop (#3262)
* feat-web: add hidden char count toggle * Added toggle char count for desktop * Use Tailwind and Component Library, add i18n * Hide char count when password is hidden * Initial proposal * Update colors per design spec for all clients Also make variable names consistent across clients * Remove unused scss * Add styling * Set fixed with for password count elements * Add separate wrapped stories * Fix alignment of first char when wrapped * Minor refactors * Make naming consistent * Add Figma url * add barrel files * Use CL component * Fix template * Remove duplicate style * Use ColorPasswordComponent in web, remove old pipe Also remove styling and move pipe out of jslib-module given that it's no longer shared by all Angular clients * Run prettier * Remove unused scss vars * Undo unnecessary changes * Remove unnecessary changes * Fix styling * Fix selector * Collect show password event * Fix incorrect background in dark mode * Fix linting * Use color password for password history * Add char count to hidden custom fields in desktop * Fix char count background in web: take 2 * Update service name * Add missing label toggleCharacterCount for desktop Co-authored-by: Daniel James Smith <djsmith@web.de> Co-authored-by: Thomas Rittson <trittson@bitwarden.com>
This commit is contained in:
committed by
GitHub
parent
87f2908e3e
commit
35b33335fb
@@ -64,6 +64,8 @@ import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
|||||||
|
|
||||||
import { BitwardenToastModule } from "@bitwarden/angular/components/toastr.component";
|
import { BitwardenToastModule } from "@bitwarden/angular/components/toastr.component";
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
|
import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe";
|
||||||
|
import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe";
|
||||||
|
|
||||||
import { EnvironmentComponent } from "./accounts/environment.component";
|
import { EnvironmentComponent } from "./accounts/environment.component";
|
||||||
import { HintComponent } from "./accounts/hint.component";
|
import { HintComponent } from "./accounts/hint.component";
|
||||||
@@ -202,6 +204,8 @@ registerLocaleData(localeZhTw, "zh-TW");
|
|||||||
CipherRowComponent,
|
CipherRowComponent,
|
||||||
VaultItemsComponent,
|
VaultItemsComponent,
|
||||||
CollectionsComponent,
|
CollectionsComponent,
|
||||||
|
ColorPasswordPipe,
|
||||||
|
ColorPasswordCountPipe,
|
||||||
CurrentTabComponent,
|
CurrentTabComponent,
|
||||||
EnvironmentComponent,
|
EnvironmentComponent,
|
||||||
ExcludedDomainsComponent,
|
ExcludedDomainsComponent,
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ p.lead {
|
|||||||
font-size: 8px;
|
font-size: 8px;
|
||||||
|
|
||||||
@include themify($themes) {
|
@include themify($themes) {
|
||||||
color: themed("mutedColor") !important;
|
color: themed("passwordCountText") !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ $themes: (
|
|||||||
logoSuffix: "dark",
|
logoSuffix: "dark",
|
||||||
passwordNumberColor: #007fde,
|
passwordNumberColor: #007fde,
|
||||||
passwordSpecialColor: #c40800,
|
passwordSpecialColor: #c40800,
|
||||||
|
passwordCountText: #212529,
|
||||||
calloutBorderColor: $border-color-dark,
|
calloutBorderColor: $border-color-dark,
|
||||||
calloutBackgroundColor: $box-background-color,
|
calloutBackgroundColor: $box-background-color,
|
||||||
toastTextColor: #ffffff,
|
toastTextColor: #ffffff,
|
||||||
@@ -170,6 +171,7 @@ $themes: (
|
|||||||
logoSuffix: "white",
|
logoSuffix: "white",
|
||||||
passwordNumberColor: #6f9df1,
|
passwordNumberColor: #6f9df1,
|
||||||
passwordSpecialColor: #ff8d85,
|
passwordSpecialColor: #ff8d85,
|
||||||
|
passwordCountText: #ffffff,
|
||||||
calloutBorderColor: #4c525f,
|
calloutBorderColor: #4c525f,
|
||||||
calloutBackgroundColor: #3c424e,
|
calloutBackgroundColor: #3c424e,
|
||||||
toastTextColor: #1f242e,
|
toastTextColor: #1f242e,
|
||||||
@@ -230,6 +232,7 @@ $themes: (
|
|||||||
logoSuffix: "white",
|
logoSuffix: "white",
|
||||||
passwordNumberColor: $nord8,
|
passwordNumberColor: $nord8,
|
||||||
passwordSpecialColor: $nord12,
|
passwordSpecialColor: $nord12,
|
||||||
|
passwordCountText: $nord5,
|
||||||
calloutBorderColor: $nord0,
|
calloutBorderColor: $nord0,
|
||||||
calloutBackgroundColor: $nord2,
|
calloutBackgroundColor: $nord2,
|
||||||
toastTextColor: #ffffff,
|
toastTextColor: #ffffff,
|
||||||
@@ -290,6 +293,7 @@ $themes: (
|
|||||||
logoSuffix: "white",
|
logoSuffix: "white",
|
||||||
passwordNumberColor: $solarizedDarkCyan,
|
passwordNumberColor: $solarizedDarkCyan,
|
||||||
passwordSpecialColor: $solarizedDarkYellow,
|
passwordSpecialColor: $solarizedDarkYellow,
|
||||||
|
passwordCountText: $solarizedDarkBase2,
|
||||||
calloutBorderColor: $solarizedDarkBase03,
|
calloutBorderColor: $solarizedDarkBase03,
|
||||||
calloutBackgroundColor: $solarizedDarkBase01,
|
calloutBackgroundColor: $solarizedDarkBase01,
|
||||||
toastTextColor: #ffffff,
|
toastTextColor: #ffffff,
|
||||||
|
|||||||
@@ -13,9 +13,10 @@
|
|||||||
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<div class="row-main-content">
|
<div class="row-main-content">
|
||||||
<span class="text monospaced no-ellipsis">
|
<span
|
||||||
{{ h.password }}
|
class="text monospaced no-ellipsis"
|
||||||
</span>
|
[innerHTML]="h.password | colorPassword"
|
||||||
|
></span>
|
||||||
<span class="detail">{{ h.lastUsedDate | date: "medium" }}</span>
|
<span class="detail">{{ h.lastUsedDate | date: "medium" }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ import localeZhCn from "@angular/common/locales/zh-Hans";
|
|||||||
import localeZhTw from "@angular/common/locales/zh-Hant";
|
import localeZhTw from "@angular/common/locales/zh-Hant";
|
||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
|
|
||||||
|
import { ColorPasswordCountPipe } from "@bitwarden/angular/pipes/color-password-count.pipe";
|
||||||
|
import { ColorPasswordPipe } from "@bitwarden/angular/pipes/color-password.pipe";
|
||||||
|
|
||||||
import { AccessibilityCookieComponent } from "./accounts/accessibility-cookie.component";
|
import { AccessibilityCookieComponent } from "./accounts/accessibility-cookie.component";
|
||||||
import { DeleteAccountComponent } from "./accounts/delete-account.component";
|
import { DeleteAccountComponent } from "./accounts/delete-account.component";
|
||||||
import { EnvironmentComponent } from "./accounts/environment.component";
|
import { EnvironmentComponent } from "./accounts/environment.component";
|
||||||
@@ -170,6 +173,8 @@ registerLocaleData(localeZhTw, "zh-TW");
|
|||||||
AttachmentsComponent,
|
AttachmentsComponent,
|
||||||
VaultItemsComponent,
|
VaultItemsComponent,
|
||||||
CollectionsComponent,
|
CollectionsComponent,
|
||||||
|
ColorPasswordPipe,
|
||||||
|
ColorPasswordCountPipe,
|
||||||
DeleteAccountComponent,
|
DeleteAccountComponent,
|
||||||
EnvironmentComponent,
|
EnvironmentComponent,
|
||||||
ExportComponent,
|
ExportComponent,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<div
|
<div
|
||||||
class="generated-wrapper monospaced"
|
class="password-wrapper monospaced"
|
||||||
appSelectCopy
|
appSelectCopy
|
||||||
[innerHTML]="h.password | colorPassword"
|
[innerHTML]="h.password | colorPassword"
|
||||||
></div>
|
></div>
|
||||||
|
|||||||
@@ -9,9 +9,7 @@
|
|||||||
<div class="box-content condensed">
|
<div class="box-content condensed">
|
||||||
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<span class="text monospaced">
|
<span class="text monospaced" [innerHTML]="h.password | colorPassword"></span>
|
||||||
{{ h.password }}
|
|
||||||
</span>
|
|
||||||
<span class="detail">{{ h.lastUsedDate | date: "medium" }}</span>
|
<span class="detail">{{ h.lastUsedDate | date: "medium" }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
|
|||||||
@@ -17,12 +17,16 @@
|
|||||||
{{ field.value || " " }}
|
{{ field.value || " " }}
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="field.type === fieldType.Hidden">
|
<div *ngIf="field.type === fieldType.Hidden">
|
||||||
|
<span *ngIf="!field.showValue" class="monospaced">{{ field.maskedValue }}</span>
|
||||||
<span
|
<span
|
||||||
*ngIf="field.showValue"
|
*ngIf="field.showValue && !field.showCount"
|
||||||
class="monospaced show-whitespace"
|
class="monospaced show-whitespace"
|
||||||
[innerHTML]="field.value | colorPassword"
|
[innerHTML]="field.value | colorPassword"
|
||||||
></span>
|
></span>
|
||||||
<span *ngIf="!field.showValue" class="monospaced">{{ field.maskedValue }}</span>
|
<span
|
||||||
|
*ngIf="field.showValue && field.showCount"
|
||||||
|
[innerHTML]="field.value | colorPasswordCount"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="field.type === fieldType.Boolean">
|
<div *ngIf="field.type === fieldType.Boolean">
|
||||||
<i class="bwi bwi-check-square" *ngIf="field.value === 'true'" aria-hidden="true"></i>
|
<i class="bwi bwi-check-square" *ngIf="field.value === 'true'" aria-hidden="true"></i>
|
||||||
@@ -41,7 +45,18 @@
|
|||||||
<span>{{ cipher.linkedFieldI18nKey(field.linkedId) | i18n }}</span>
|
<span>{{ cipher.linkedFieldI18nKey(field.linkedId) | i18n }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons action-buttons-fixed">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="row-btn"
|
||||||
|
appStopClick
|
||||||
|
appA11yTitle="{{ 'toggleCharacterCount' | i18n }}"
|
||||||
|
*ngIf="field.type === fieldType.Hidden && cipher.viewPassword && field.showValue"
|
||||||
|
(click)="toggleFieldCount(field)"
|
||||||
|
[attr.aria-pressed]="field.showCount"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-numbered-list" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
|
|||||||
@@ -50,11 +50,15 @@
|
|||||||
{{ cipher.login.maskedPassword }}
|
{{ cipher.login.maskedPassword }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
*ngIf="showPassword"
|
*ngIf="showPassword && !showPasswordCount"
|
||||||
class="monospaced generated-wrapper"
|
class="monospaced password-wrapper"
|
||||||
appSelectCopy
|
appSelectCopy
|
||||||
[innerHTML]="cipher.login.password | colorPassword"
|
[innerHTML]="cipher.login.password | colorPassword"
|
||||||
></div>
|
></div>
|
||||||
|
<div
|
||||||
|
*ngIf="showPassword && showPasswordCount"
|
||||||
|
[innerHTML]="cipher.login.password | colorPasswordCount"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-buttons" *ngIf="cipher.viewPassword">
|
<div class="action-buttons" *ngIf="cipher.viewPassword">
|
||||||
<button
|
<button
|
||||||
@@ -77,6 +81,18 @@
|
|||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="row-btn"
|
||||||
|
appStopClick
|
||||||
|
attr.aria-label="{{ 'toggleCharacterCount' | i18n }} {{ 'password' | i18n }}"
|
||||||
|
appA11yTitle="{{ 'toggleCharacterCount' | i18n }}"
|
||||||
|
(click)="togglePasswordCount()"
|
||||||
|
*ngIf="showPassword"
|
||||||
|
[attr.aria-pressed]="showPasswordCount"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-numbered-list" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="row-btn"
|
class="row-btn"
|
||||||
|
|||||||
@@ -2057,5 +2057,9 @@
|
|||||||
},
|
},
|
||||||
"logInWithAnotherDevice": {
|
"logInWithAnotherDevice": {
|
||||||
"message": "Log in with another device"
|
"message": "Log in with another device"
|
||||||
|
},
|
||||||
|
"toggleCharacterCount": {
|
||||||
|
"message": "Toggle character count",
|
||||||
|
"description": "'Character count' describes a feature that displays a number next to each character of the password."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,6 +366,11 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
|
|
||||||
|
&.action-buttons-fixed {
|
||||||
|
align-self: start;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.row-btn {
|
.row-btn {
|
||||||
@extend .icon-btn;
|
@extend .icon-btn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,8 +215,8 @@ p.lead {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.generated-wrapper {
|
.password-wrapper {
|
||||||
word-break: break-all;
|
overflow-wrap: break-word;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
@@ -233,6 +233,30 @@ p.lead {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.password-character {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 30px;
|
||||||
|
height: 36px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
@include themify($themes) {
|
||||||
|
background-color: themed("backgroundColorAlt2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-count {
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 8px;
|
||||||
|
|
||||||
|
@include themify($themes) {
|
||||||
|
color: themed("passwordCountText") !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#duo-frame {
|
#duo-frame {
|
||||||
background: url("../images/loading.svg") 0 0 no-repeat;
|
background: url("../images/loading.svg") 0 0 no-repeat;
|
||||||
height: 330px;
|
height: 330px;
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ $themes: (
|
|||||||
logoSuffix: "dark",
|
logoSuffix: "dark",
|
||||||
passwordNumberColor: #007fde,
|
passwordNumberColor: #007fde,
|
||||||
passwordSpecialColor: #c40800,
|
passwordSpecialColor: #c40800,
|
||||||
|
passwordCountText: #212529,
|
||||||
calloutBorderColor: $border-color-dark,
|
calloutBorderColor: $border-color-dark,
|
||||||
calloutBackgroundColor: $background-color,
|
calloutBackgroundColor: $background-color,
|
||||||
accountSwitcherBackgroundColor: $background-color,
|
accountSwitcherBackgroundColor: $background-color,
|
||||||
@@ -142,6 +143,7 @@ $themes: (
|
|||||||
logoSuffix: "white",
|
logoSuffix: "white",
|
||||||
passwordNumberColor: #52bdfb,
|
passwordNumberColor: #52bdfb,
|
||||||
passwordSpecialColor: #ff7c70,
|
passwordSpecialColor: #ff7c70,
|
||||||
|
passwordCountText: #ffffff,
|
||||||
calloutBorderColor: #2f2f2f,
|
calloutBorderColor: #2f2f2f,
|
||||||
calloutBackgroundColor: #363636,
|
calloutBackgroundColor: #363636,
|
||||||
accountSwitcherBackgroundColor: #2f2f2f,
|
accountSwitcherBackgroundColor: #2f2f2f,
|
||||||
@@ -196,6 +198,7 @@ $themes: (
|
|||||||
logoSuffix: "white",
|
logoSuffix: "white",
|
||||||
passwordNumberColor: $nord8,
|
passwordNumberColor: $nord8,
|
||||||
passwordSpecialColor: $nord12,
|
passwordSpecialColor: $nord12,
|
||||||
|
passwordCountText: $nord5,
|
||||||
calloutBorderColor: $nord1,
|
calloutBorderColor: $nord1,
|
||||||
calloutBackgroundColor: $nord2,
|
calloutBackgroundColor: $nord2,
|
||||||
accountSwitcherBackgroundColor: $nord0,
|
accountSwitcherBackgroundColor: $nord0,
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ import {
|
|||||||
IconButtonModule,
|
IconButtonModule,
|
||||||
IconModule,
|
IconModule,
|
||||||
MenuModule,
|
MenuModule,
|
||||||
|
LinkModule,
|
||||||
NavigationModule,
|
NavigationModule,
|
||||||
TableModule,
|
TableModule,
|
||||||
TabsModule,
|
TabsModule,
|
||||||
|
ColorPasswordModule,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
|
|
||||||
// Register the locales for the application
|
// Register the locales for the application
|
||||||
@@ -58,6 +60,8 @@ import "./locales";
|
|||||||
NavigationModule,
|
NavigationModule,
|
||||||
TableModule,
|
TableModule,
|
||||||
TabsModule,
|
TabsModule,
|
||||||
|
LinkModule,
|
||||||
|
ColorPasswordModule,
|
||||||
|
|
||||||
// Web specific
|
// Web specific
|
||||||
],
|
],
|
||||||
@@ -85,6 +89,8 @@ import "./locales";
|
|||||||
NavigationModule,
|
NavigationModule,
|
||||||
TableModule,
|
TableModule,
|
||||||
TabsModule,
|
TabsModule,
|
||||||
|
LinkModule,
|
||||||
|
ColorPasswordModule,
|
||||||
|
|
||||||
// Web specific
|
// Web specific
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -6,18 +6,10 @@
|
|||||||
</app-callout>
|
</app-callout>
|
||||||
<div class="card card-generated bg-light my-4">
|
<div class="card card-generated bg-light my-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div
|
<bit-color-password
|
||||||
*ngIf="type === 'password'"
|
[password]="type === 'password' ? password : username"
|
||||||
class="generated-wrapper"
|
|
||||||
[innerHTML]="password | colorPassword"
|
|
||||||
appSelectCopy
|
appSelectCopy
|
||||||
></div>
|
></bit-color-password>
|
||||||
<div
|
|
||||||
*ngIf="type === 'username'"
|
|
||||||
class="generated-wrapper"
|
|
||||||
[innerHTML]="username | colorPassword"
|
|
||||||
appSelectCopy
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" role="radiogroup" aria-labelledby="typeHeading">
|
<div class="form-group" role="radiogroup" aria-labelledby="typeHeading">
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
<div class="modal-body" *ngIf="history.length">
|
<div class="modal-body" *ngIf="history.length">
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
<li class="list-group-item d-flex" *ngFor="let h of history">
|
<li class="list-group-item d-flex" *ngFor="let h of history">
|
||||||
<div class="password-row">
|
<div class="tw-min-w-0">
|
||||||
<div
|
<bit-color-password
|
||||||
class="text-monospace generated-wrapper"
|
[password]="h.password"
|
||||||
[innerHTML]="h.password | colorPassword"
|
class="tw-block tw-font-mono"
|
||||||
appSelectCopy
|
appSelectCopy
|
||||||
></div>
|
></bit-color-password>
|
||||||
<small class="text-muted">{{ h.date | date: "medium" }}</small>
|
<small class="text-muted">{{ h.date | date: "medium" }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-auto">
|
<div class="ml-auto">
|
||||||
|
|||||||
@@ -128,6 +128,15 @@
|
|||||||
title="{{ 'loading' | i18n }}"
|
title="{{ 'loading' | i18n }}"
|
||||||
></i>
|
></i>
|
||||||
</a>
|
</a>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="d-block bwi-icon-above-input"
|
||||||
|
appStopClick
|
||||||
|
[appA11yTitle]="'toggleCharacterCount' | i18n"
|
||||||
|
(click)="togglePasswordCount()"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-fw bwi-numbered-list" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
@@ -169,6 +178,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="showPasswordCount" class="tw-mb-4">
|
||||||
|
<label>{{ "passwordCharacterCount" | i18n }}</label>
|
||||||
|
<div class="tw-flex tw-justify-between">
|
||||||
|
<bit-color-password
|
||||||
|
[password]="cipher.login.password"
|
||||||
|
[showCount]="true"
|
||||||
|
></bit-color-password>
|
||||||
|
<button type="button" bitLink (click)="togglePasswordCount()">
|
||||||
|
{{ "hide" | i18n }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="tw-flex tw-flex-row">
|
<div class="tw-flex tw-flex-row">
|
||||||
<div class="tw-mb-4 tw-w-1/2">
|
<div class="tw-mb-4 tw-w-1/2">
|
||||||
<label for="loginTotp">{{ "authenticatorKeyTotp" | i18n }}</label>
|
<label for="loginTotp">{{ "authenticatorKeyTotp" | i18n }}</label>
|
||||||
@@ -870,7 +891,7 @@
|
|||||||
<div class="ml-3" *ngIf="viewingPasswordHistory">
|
<div class="ml-3" *ngIf="viewingPasswordHistory">
|
||||||
<div *ngFor="let ph of cipher.passwordHistory">
|
<div *ngFor="let ph of cipher.passwordHistory">
|
||||||
{{ ph.lastUsedDate | date: "short" }} -
|
{{ ph.lastUsedDate | date: "short" }} -
|
||||||
<span class="generated-wrapper text-monospace ml-2">{{ ph.password }}</span>
|
<bit-color-password [password]="ph.password"></bit-color-password>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On
|
|||||||
hasPasswordHistory = false;
|
hasPasswordHistory = false;
|
||||||
viewingPasswordHistory = false;
|
viewingPasswordHistory = false;
|
||||||
viewOnly = false;
|
viewOnly = false;
|
||||||
|
showPasswordCount = false;
|
||||||
|
|
||||||
protected totpInterval: number;
|
protected totpInterval: number;
|
||||||
protected override componentName = "app-vault-add-edit";
|
protected override componentName = "app-vault-add-edit";
|
||||||
@@ -104,6 +105,26 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On
|
|||||||
this.cipher.favorite = !this.cipher.favorite;
|
this.cipher.favorite = !this.cipher.favorite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
togglePassword() {
|
||||||
|
super.togglePassword();
|
||||||
|
|
||||||
|
// Hide password count when password is hidden to be safe
|
||||||
|
if (!this.showPassword && this.showPasswordCount) {
|
||||||
|
this.togglePasswordCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
togglePasswordCount() {
|
||||||
|
this.showPasswordCount = !this.showPasswordCount;
|
||||||
|
|
||||||
|
if (this.editMode && this.showPasswordCount) {
|
||||||
|
this.eventCollectionService.collect(
|
||||||
|
EventType.Cipher_ClientToggledPasswordVisible,
|
||||||
|
this.cipherId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
launch(uri: LoginUriView) {
|
launch(uri: LoginUriView) {
|
||||||
if (!uri.canLaunch) {
|
if (!uri.canLaunch) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -5487,6 +5487,17 @@
|
|||||||
"multiSelectClearAll": {
|
"multiSelectClearAll": {
|
||||||
"message": "Clear all"
|
"message": "Clear all"
|
||||||
},
|
},
|
||||||
|
"toggleCharacterCount": {
|
||||||
|
"message": "Toggle character count",
|
||||||
|
"description": "'Character count' describes a feature that displays a number next to each character of the password."
|
||||||
|
},
|
||||||
|
"passwordCharacterCount": {
|
||||||
|
"message": "Password character count",
|
||||||
|
"description": "'Character count' describes a feature that displays a number next to each character of the password."
|
||||||
|
},
|
||||||
|
"hide": {
|
||||||
|
"message": "Hide"
|
||||||
|
},
|
||||||
"projects":{
|
"projects":{
|
||||||
"message": "Projects"
|
"message": "Projects"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,31 +1,3 @@
|
|||||||
.generated-wrapper {
|
|
||||||
min-width: 0;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.password-row {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.password-letter {
|
|
||||||
@include themify($themes) {
|
|
||||||
color: themed("pwLetter");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.password-number {
|
|
||||||
@include themify($themes) {
|
|
||||||
color: themed("pwNumber");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.password-special {
|
|
||||||
@include themify($themes) {
|
|
||||||
color: themed("pwSpecial");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app-generator {
|
app-generator {
|
||||||
#lengthRange {
|
#lengthRange {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -201,9 +201,6 @@ $themes: (
|
|||||||
navBackgroundAlt: $secondary-alt,
|
navBackgroundAlt: $secondary-alt,
|
||||||
navOrgBackgroundColor: #fbfbfb,
|
navOrgBackgroundColor: #fbfbfb,
|
||||||
navWeight: 600,
|
navWeight: 600,
|
||||||
pwLetter: $body-color,
|
|
||||||
pwNumber: #007fde,
|
|
||||||
pwSpecial: #c40800,
|
|
||||||
pwStrengthBackground: #e9ecef,
|
pwStrengthBackground: #e9ecef,
|
||||||
separator: $secondary,
|
separator: $secondary,
|
||||||
separatorHr: rgb(0, 0, 0, 0.1),
|
separatorHr: rgb(0, 0, 0, 0.1),
|
||||||
@@ -313,9 +310,6 @@ $themes: (
|
|||||||
navBackgroundAlt: $darkDarkBlue1,
|
navBackgroundAlt: $darkDarkBlue1,
|
||||||
navOrgBackgroundColor: #161c26,
|
navOrgBackgroundColor: #161c26,
|
||||||
navWeight: 400,
|
navWeight: 400,
|
||||||
pwLetter: $white,
|
|
||||||
pwNumber: #52bdfb,
|
|
||||||
pwSpecial: #ff7c70,
|
|
||||||
pwStrengthBackground: $darkBlue2,
|
pwStrengthBackground: $darkBlue2,
|
||||||
separator: $darkBlue1,
|
separator: $darkBlue1,
|
||||||
separatorHr: $darkBlue1,
|
separatorHr: $darkBlue1,
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ import { SelectCopyDirective } from "./directives/select-copy.directive";
|
|||||||
import { StopClickDirective } from "./directives/stop-click.directive";
|
import { StopClickDirective } from "./directives/stop-click.directive";
|
||||||
import { StopPropDirective } from "./directives/stop-prop.directive";
|
import { StopPropDirective } from "./directives/stop-prop.directive";
|
||||||
import { TrueFalseValueDirective } from "./directives/true-false-value.directive";
|
import { TrueFalseValueDirective } from "./directives/true-false-value.directive";
|
||||||
import { ColorPasswordCountPipe } from "./pipes/color-password-count.pipe";
|
|
||||||
import { ColorPasswordPipe } from "./pipes/color-password.pipe";
|
|
||||||
import { CreditCardNumberPipe } from "./pipes/credit-card-number.pipe";
|
import { CreditCardNumberPipe } from "./pipes/credit-card-number.pipe";
|
||||||
import { EllipsisPipe } from "./pipes/ellipsis.pipe";
|
import { EllipsisPipe } from "./pipes/ellipsis.pipe";
|
||||||
import { I18nPipe } from "./pipes/i18n.pipe";
|
import { I18nPipe } from "./pipes/i18n.pipe";
|
||||||
@@ -49,8 +47,6 @@ import { PasswordStrengthComponent } from "./shared/components/password-strength
|
|||||||
AutofocusDirective,
|
AutofocusDirective,
|
||||||
BoxRowDirective,
|
BoxRowDirective,
|
||||||
CalloutComponent,
|
CalloutComponent,
|
||||||
ColorPasswordCountPipe,
|
|
||||||
ColorPasswordPipe,
|
|
||||||
CreditCardNumberPipe,
|
CreditCardNumberPipe,
|
||||||
EllipsisPipe,
|
EllipsisPipe,
|
||||||
ExportScopeCalloutComponent,
|
ExportScopeCalloutComponent,
|
||||||
@@ -79,8 +75,6 @@ import { PasswordStrengthComponent } from "./shared/components/password-strength
|
|||||||
BitwardenToastModule,
|
BitwardenToastModule,
|
||||||
BoxRowDirective,
|
BoxRowDirective,
|
||||||
CalloutComponent,
|
CalloutComponent,
|
||||||
ColorPasswordCountPipe,
|
|
||||||
ColorPasswordPipe,
|
|
||||||
CreditCardNumberPipe,
|
CreditCardNumberPipe,
|
||||||
EllipsisPipe,
|
EllipsisPipe,
|
||||||
ExportScopeCalloutComponent,
|
ExportScopeCalloutComponent,
|
||||||
|
|||||||
@@ -48,12 +48,12 @@ export class ColorPasswordComponent {
|
|||||||
|
|
||||||
if (this.showCount) {
|
if (this.showCount) {
|
||||||
return charClass.concat([
|
return charClass.concat([
|
||||||
"tw-inline-flex",
|
|
||||||
"tw-flex-col",
|
"tw-flex-col",
|
||||||
"tw-items-center",
|
"tw-items-center",
|
||||||
"tw-w-7",
|
"tw-w-7",
|
||||||
"tw-py-1",
|
"tw-py-1",
|
||||||
"odd:tw-bg-secondary-100",
|
"odd:tw-bg-secondary-100",
|
||||||
|
"even:tw-bg-background",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user