Skip to content

Commit

Permalink
[Password Manager] Displaying PasswordUiEntry
Browse files Browse the repository at this point in the history
This change allows to display individual PasswordUiEntry in the
password details section. None of the buttons work yet. Notes aren't
supported as well.

Impl: https://screenshot.googleplex.com/7oQ8oWEvWhtRhsN
Mock: https://screenshot.googleplex.com/74qPwqnR6VQXUiW
Note: username, password and note fields background color looks darker
compared to mocks, but the UX designer was okay with it since this is
the default color for input fields.

Bug: 1350947
Change-Id: Iab6f0f2f620f45cce0b489849519bf29fe2d4fef
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4026045
Commit-Queue: Viktor Semeniuk <vsemeniuk@google.com>
Reviewed-by: Mohamed Amir Yosef <mamir@chromium.org>
Reviewed-by: John Lee <johntlee@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1078052}
  • Loading branch information
Viktor Semeniuk authored and Chromium LUCI CQ committed Dec 1, 2022
1 parent d46a7fc commit 6ace9ed
Show file tree
Hide file tree
Showing 23 changed files with 339 additions and 20 deletions.
27 changes: 27 additions & 0 deletions chrome/app/password_manager_ui_strings.grdp
Expand Up @@ -119,4 +119,31 @@
=1 {{COUNT} account}
other {{COUNT} accounts}}
</message>
<message name="IDS_PASSWORD_MANAGER_UI_USERNAME_LABEL" desc="Label for the username.">
Username
</message>
<message name="IDS_PASSWORD_MANAGER_UI_SITES_LABEL" desc="Label for the password value.">
Sites
</message>
<message name="IDS_PASSWORD_MANAGER_UI_PASSWORD_LABEL" desc="Label for the sites for which the password is used.">
Password
</message>
<message name="IDS_PASSWORD_MANAGER_UI_NOTES_LABEL" desc="Label for the password notes.">
Notes
</message>
<message name="IDS_PASSWORD_MANAGER_UI_NO_NOTE_SAVED" desc="Label for the password note when the note is empty.">
No notes saved
</message>
<message name="IDS_PASSWORD_MANAGER_UI_COPY_PASSWORD" desc="Label for the button which allows to copy a password.">
Copy password
</message>
<message name="IDS_PASSWORD_MANAGER_UI_COPY_USERNAME" desc="Label for the button which allows to copy a username.">
Copy username
</message>
<message name="IDS_PASSWORD_MANAGER_UI_SHOW_PASSWORD" desc="Label for the button which shows password in plain text.">
Show password
</message>
<message name="IDS_PASSWORD_MANAGER_UI_HIDE_PASSWORD" desc="Label for the button which hides password value.">
Hide password
</message>
</grit-part>
@@ -0,0 +1 @@
d486fd43a668c183c27ce625b0d86b1fdd22e21b
@@ -0,0 +1 @@
2ca62e78b57cb4cd435e4c4b6d9c4ca8ddcfbdba
@@ -0,0 +1 @@
c8946628b903696d52c48c4c820f8a5cf9fd3256
@@ -0,0 +1 @@
2d957ab6bdbaafe89daa0ea6ceddebb71179267e
@@ -0,0 +1 @@
2d957ab6bdbaafe89daa0ea6ceddebb71179267e
@@ -0,0 +1 @@
2d957ab6bdbaafe89daa0ea6ceddebb71179267e
@@ -0,0 +1 @@
0e0716bb5967138076f88a03234b0a683a9126e7
@@ -0,0 +1 @@
2d957ab6bdbaafe89daa0ea6ceddebb71179267e
@@ -0,0 +1 @@
2d957ab6bdbaafe89daa0ea6ceddebb71179267e
15 changes: 8 additions & 7 deletions chrome/browser/resources/password_manager/BUILD.gn
Expand Up @@ -21,28 +21,29 @@ build_webui("build") {
]
web_component_files = [
"checkup_section.ts",
"password_manager_app.ts",
"password_details_card.ts",
"password_details_section.ts",
"password_list_item.ts",
"password_manager_app.ts",
"passwords_section.ts",
"password_details_section.ts",
"prefs/pref_toggle_button.ts",
"settings_section.ts",
"side_bar.ts",
"site_favicon.ts",
"toolbar.ts",
]
non_web_component_files = [
"password_manager_proxy.ts",
"password_manager.ts",
"router.ts",
"prefs/prefs_browser_proxy.ts",
"password_manager_proxy.ts",
"prefs/pref_mixin.ts",
"prefs/prefs_browser_proxy.ts",
"router.ts",
]

# Files that are passed as input to css_to_wrapper().
css_files = [
"shared_style.css",
"shared_vars.css",
"shared_style.css",
]

icons_html_files = [ "icons.html" ]
Expand All @@ -51,10 +52,10 @@ build_webui("build") {

ts_definitions = [
"//tools/typescript/definitions/chrome_event.d.ts",
"//tools/typescript/definitions/chrome_send.d.ts",
"//tools/typescript/definitions/metrics_private.d.ts",
"//tools/typescript/definitions/passwords_private.d.ts",
"//tools/typescript/definitions/runtime.d.ts",
"//tools/typescript/definitions/chrome_send.d.ts",
"//tools/typescript/definitions/settings_private.d.ts",
"//tools/typescript/definitions/tabs.d.ts",
]
Expand Down
113 changes: 113 additions & 0 deletions chrome/browser/resources/password_manager/password_details_card.html
@@ -0,0 +1,113 @@
<style include="shared-style cr-shared-style">
.card {
margin-bottom: 44px;
}

.credential-container {
padding: 12px var(--cr-form-field-bottom-spacing) var(--cr-section-padding);
}

.row-container {
display: flex;
margin-top: 16px;
}

.column-container {
flex: 50%;
}

.button-container {
border-top: var(--cr-separator-line);
margin-top: 12px;
padding: var(--cr-form-field-bottom-spacing) var(--cr-section-padding);
}

.input-field {
margin-inline-end: 34px;
--cr-input-padding-start: 20px;
--cr-input-min-height: 40px;
--cr-input-error-display: none;
--cr-input-border-radius: 10px;
--cr-icon-button-margin-start: 0;
--cr-icon-button-margin-end: 0;
}

.site-link {
color: var(--cr-primary-text-color);
display: block;
height: 20px;
max-width: 324px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.cr-form-field-label {
margin-bottom: 6px;
}

#passwordButtons {
display: flex;
}

#editButton {
margin-inline-end: var(--cr-button-edge-spacing);
}
</style>
<div class="card">
<div class="credential-container">
<div class="row-container">
<div class="column-container">
<cr-input id="usernameValue" value="[[password.username]]" readonly
class="input-field" label="$i18n{usernameLabel}">
<cr-icon-button id="copyUsernameButton" class="icon-copy-content"
slot="inline-suffix" title="$i18n{copyUsername}">
</cr-icon-button>
</cr-input>
</div>
<div class="column-container">
<!-- TODO(crbug.com/1350947): Support displaying apps. -->
<!-- TODO(crbug.com/1350947): Support displaying multiple sites. -->
<div class="cr-form-field-label">$i18n{sitesLabel}</div>
<a id="linkValue" href="[[password.urls.link]]" class="site-link">
<span class="elide-left">
<span>[[password.urls.shown]]</span>
</span>
</a>
</div>
</div>
<div class="row-container">
<div class="column-container">
<!-- TODO(crbug.com/1350947): Support federated credentials. -->
<cr-input id="passwordValue" value="[[password.password]]"
type="password" readonly class="input-field"
label="$i18n{passwordLabel}">
<div id="passwordButtons" slot="inline-suffix">
<cr-icon-button id="showPasswordButton" class="icon-visibility"
title="$i18n{showPassword}">
</cr-icon-button>
<cr-icon-button id="copyPasswordButton" class="icon-copy-content"
title="$i18n{copyPassword}">
</cr-icon-button>
</div>
</cr-input>
</div>
<div class="column-container">
<!-- TODO(crbug.com/1350947): Support displaying notes. -->
<cr-input id="noteValue" value="$i18n{emptyNote}"
readonly class="input-field" label="$i18n{notesLabel}">
</cr-input>
</div>
</div>
</div>
<div class="button-container">
<!-- TODO(crbug.com/1350947): Support editing. -->
<cr-button id="editButton">
$i18n{editPassword}
</cr-button>
<!-- TODO(crbug.com/1350947): Support deleting. -->
<cr-button id="deleteButton">
$i18n{deletePassword}
</cr-button>
</div>
</div>
58 changes: 58 additions & 0 deletions chrome/browser/resources/password_manager/password_details_card.ts
@@ -0,0 +1,58 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'chrome://resources/cr_elements/cr_input/cr_input.js';
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/cr_elements/cr_icons.css.js';
import 'chrome://resources/cr_elements/cr_shared_style.css.js';
import './shared_style.css.js';

import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
import {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {getTemplate} from './password_details_card.html.js';

export interface PasswordDetailsCardElement {
$: {
copyPasswordButton: CrIconButtonElement,
copyUsernameButton: CrIconButtonElement,
deleteButton: CrButtonElement,
editButton: CrButtonElement,
linkValue: HTMLElement,
noteValue: CrInputElement,
passwordValue: CrInputElement,
showPasswordButton: CrIconButtonElement,
usernameValue: CrInputElement,
};
}


export class PasswordDetailsCardElement extends PolymerElement {
static get is() {
return 'password-details-card';
}

static get template() {
return getTemplate();
}

static get properties() {
return {
password: Object,
};
}

password: chrome.passwordsPrivate.PasswordUiEntry;
}

declare global {
interface HTMLElementTagNameMap {
'password-details-card': PasswordDetailsCardElement;
}
}

customElements.define(
PasswordDetailsCardElement.is, PasswordDetailsCardElement);
Expand Up @@ -2,6 +2,7 @@
#header {
align-items: center;
display: flex;
margin-bottom: 28px;
}

#backButton {
Expand All @@ -25,3 +26,8 @@
</site-favicon>
<h2 id="title" class="page-title">[[selectedGroup_.name]]</h2>
</div>
<template is="dom-if" if="[[selectedGroup_.name]]">
<template is="dom-repeat" items="[[selectedGroup_.entries]]">
<password-details-card password="[[item]]"></password-details-card>
</template>
</template>
Expand Up @@ -6,6 +6,7 @@ import 'chrome://resources/cr_elements/cr_icons.css.js';
import 'chrome://resources/cr_elements/cr_shared_style.css.js';
import './shared_style.css.js';
import './site_favicon.js';
import './password_details_card.js';

import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
Expand Down
Expand Up @@ -4,6 +4,7 @@

import './password_manager_app.js';

export {PasswordDetailsCardElement} from './password_details_card.js';
export {PasswordDetailsSectionElement} from './password_details_section.js';
export {PasswordListItemElement} from './password_list_item.js';
export {PasswordManagerAppElement} from './password_manager_app.js';
Expand Down
17 changes: 17 additions & 0 deletions chrome/browser/resources/password_manager/shared_style.css
Expand Up @@ -30,3 +30,20 @@
align-items: center;
display: flex;
}

.elide-left {
/* The following non-flex directives allow eliding long originUrls from
* the left. Forcing rtl should not cause an issue for right-to-left
* languages in this case, since valid URL characters are restricted to
* ASCII.
*/
direction: rtl;
}

.elide-left > span {
direction: ltr;
/* This styling is necessary to fix the display of domains starting with
* numbers.
*/
unicode-bidi: bidi-override;
}
27 changes: 19 additions & 8 deletions chrome/browser/ui/webui/password_manager/password_manager_ui.cc
Expand Up @@ -47,43 +47,54 @@ content::WebUIDataSource* CreatePasswordsUIHTMLSource(Profile* profile) {
IDS_PASSWORD_MANAGER_UI_ADD_SHORTCUT_DESCRIPTION},
{"autosigninDescription", IDS_PASSWORD_MANAGER_UI_AUTOSIGNIN_TOGGLE_DESC},
{"autosigninLabel", IDS_PASSWORD_MANAGER_UI_AUTOSIGNIN_TOGGLE_LABEL},
{"blockedSitesDescription",
IDS_PASSWORD_MANAGER_UI_BLOCKED_SITES_DESCRIPTION},
{"blockedSitesEmptyDescription",
IDS_PASSWORD_MANAGER_UI_NO_BLOCKED_SITES_DESCRIPTION},
{"blockedSitesTitle", IDS_PASSWORD_MANAGER_UI_BLOCKED_SITES_TITLE},
{"checkup", IDS_PASSWORD_MANAGER_UI_CHECKUP},
{"checkupTitle", IDS_PASSWORD_MANAGER_UI_CHECKUP_TITLE},
{"clearSearch", IDS_CLEAR_SEARCH},
{"compromisedPasswordsEmpty",
IDS_PASSWORD_MANAGER_UI_NO_COMPROMISED_PASSWORDS},
{"compromisedPasswordsTitle",
IDS_PASSWORD_MANAGER_UI_HAS_COMPROMISED_PASSWORDS},
{"copyPassword", IDS_PASSWORD_MANAGER_UI_COPY_PASSWORD},
{"copyUsername", IDS_PASSWORD_MANAGER_UI_COPY_USERNAME},
{"deletePassword", IDS_DELETE},
{"editPassword", IDS_EDIT},
{"emptyNote", IDS_PASSWORD_MANAGER_UI_NO_NOTE_SAVED},
{"exportPasswords", IDS_PASSWORD_MANAGER_UI_EXPORT_BANNER_TITLE},
{"exportPasswordsDescription",
IDS_PASSWORD_MANAGER_UI_EXPORT_BANNER_DESCRIPTION},
{"hidePassword", IDS_PASSWORD_MANAGER_UI_HIDE_PASSWORD},
{"importPasswords", IDS_PASSWORD_MANAGER_UI_IMPORT_BANNER_TITLE},
{"importPasswordsDescription",
IDS_PASSWORD_MANAGER_UI_IMPORT_BANNER_DESCRIPTION},
{"justNow", IDS_PASSWORD_MANAGER_UI_JUST_NOW},
{"notesLabel", IDS_PASSWORD_MANAGER_UI_NOTES_LABEL},
{"passwordLabel", IDS_PASSWORD_MANAGER_UI_PASSWORD_LABEL},
{"passwords", IDS_PASSWORD_MANAGER_UI_PASSWORDS},
{"reusedPasswordsEmpty", IDS_PASSWORD_MANAGER_UI_NO_REUSED_PASSWORDS},
{"reusedPasswordsTitle", IDS_PASSWORD_MANAGER_UI_HAS_REUSED_PASSWORDS},
{"savePasswordsLabel",
IDS_PASSWORD_MANAGER_UI_SAVE_PASSWORDS_TOGGLE_LABEL},
{"searchPrompt", IDS_PASSWORD_MANAGER_UI_SEARCH_PROMPT},
{"settings", IDS_PASSWORD_MANAGER_UI_SETTINGS},
{"showPassword", IDS_PASSWORD_MANAGER_UI_SHOW_PASSWORD},
{"sitesLabel", IDS_PASSWORD_MANAGER_UI_SITES_LABEL},
{"title", IDS_PASSWORD_MANAGER_UI_TITLE},
{"tryAgain", IDS_PASSWORD_MANAGER_UI_CHECK_PASSWORDS_AFTER_ERROR},
{"trustedVaultBannerLabelOfferOptIn",
IDS_PASSWORD_MANAGER_UI_TRUSTED_VAULT_OPT_IN_TITLE},
{"trustedVaultBannerSubLabelOfferOptIn",
IDS_PASSWORD_MANAGER_UI_RUSTED_VAULT_OPT_IN_DESCRIPTION},
{"tryAgain", IDS_PASSWORD_MANAGER_UI_CHECK_PASSWORDS_AFTER_ERROR},
{"usernameLabel", IDS_PASSWORD_MANAGER_UI_USERNAME_LABEL},
{"weakPasswordsEmpty", IDS_PASSWORD_MANAGER_UI_NO_WEAK_PASSWORDS},
{"weakPasswordsTitle", IDS_PASSWORD_MANAGER_UI_HAS_WEAK_PASSWORDS},
{"blockedSitesTitle", IDS_PASSWORD_MANAGER_UI_BLOCKED_SITES_TITLE},
{"blockedSitesDescription",
IDS_PASSWORD_MANAGER_UI_BLOCKED_SITES_DESCRIPTION},
{"blockedSitesEmptyDescription",
IDS_PASSWORD_MANAGER_UI_NO_BLOCKED_SITES_DESCRIPTION},

};
source->AddLocalizedStrings(kStrings);
for (const auto& str : kStrings)
webui::AddLocalizedString(source, str.name, str.id);

source->AddString(
"passwordsSectionDescription",
Expand Down

0 comments on commit 6ace9ed

Please sign in to comment.