Commit 54d8cf1a authored by Victor Hugo Vianna Silva's avatar Victor Hugo Vianna Silva Committed by Commit Bot

[b4p/Settings] Add strings for duplicated passwords

For the case of passwords duplicated in the account and on the device,
this CL adds the correct strings in the edit dialog and the removal
notification. The text in the edit dialog is also modified to match
the updated mocks.

Mock for removal notification:
https://screenshot.googleplex.com/W7RAXUM8Eeo

Mock for edit dialog:
https://screenshot.googleplex.com/6SGSG6oNPNv

Bug: 1049141
Change-Id: Ib472319eb320811e9f22032d6ee16bcfc0c29b0e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2218118Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Reviewed-by: default avatarFriedrich [CET] <fhorschig@chromium.org>
Commit-Queue: Victor Vianna <victorvianna@google.com>
Cr-Commit-Position: refs/heads/master@{#773180}
parent 0ec00ebe
......@@ -459,11 +459,15 @@
</message>
<!-- TODO(crbug.com/1062344): Make it translateable and add translation screenshots once final mocks are available. -->
<message translateable="false" name="IDS_SETTINGS_PASSWORD_STORED_ON_DEVICE" desc="Message displayed in the edit dialog for a password stored on the device.">
Your password is stored &lt;b&gt;on this device&lt;/b&gt;.
Your password is saved on this device.
</message>
<!-- TODO(crbug.com/1062344): Make it translateable and add translation screenshots once final mocks are available. -->
<message translateable="false" name="IDS_SETTINGS_PASSWORD_STORED_IN_ACCOUNT" desc="Message displayed in the edit dialog for a password stored in the account.">
Your password is stored &lt;b&gt;in your Google Account&lt;/b&gt;.
Your password is saved in your Google Account.
</message>
<!-- TODO(crbug.com/1062344): Make it translateable and add translation screenshots once final mocks are available. -->
<message translateable="false" name="IDS_SETTINGS_PASSWORD_STORED_IN_ACCOUNT_AND_ON_DEVICE" desc="Message displayed in the edit dialog for a password stored both on the device and in the account.">
Your password is saved on this device and in your Google Account.
</message>
<!-- TODO(crbug.com/1062344): Make it translateable and add translation screenshots once final mocks are available. -->
<message translateable="false" name="IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_ACCOUNT" desc="Label for an undo tooltip following deletion of a password from the account.">
......@@ -473,6 +477,10 @@
<message translateable="false" name="IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_DEVICE" desc="Label for an undo tooltip following deletion of a password from the device.">
Password deleted from this device
</message>
<!-- TODO(crbug.com/1062344): Make it translateable and add translation screenshots once final mocks are available. -->
<message translateable="false" name="IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_ACCOUNT_AND_DEVICE" desc="Label for an undo tooltip following deletion of a password from the account and the device.">
Password deleted from your Google Account and this device
</message>
<message name="IDS_SETTINGS_PASSWORDS_MANAGE_PASSWORDS" desc="Shown in the passwords section of settings. Descriptive text to inform that passwords can be accessed online. Has a link.">
View and manage saved passwords in your <ph name="BEGIN_LINK">&lt;a is="action-link" href="$1" target="_blank"&gt;</ph>Google Account<ph name="END_LINK">&lt;/a&gt;</ph>
</message>
......
......@@ -33,8 +33,9 @@
<cr-dialog id="dialog" close-text="$i18n{close}">
<div slot="title">$i18n{passwordDetailsTitle}</div>
<div slot="body">
<div hidden="[[!shouldShowStorageDetails]]" id="storageDetails"
inner-h-t-m-l="[[getStorageDetailsMessage_()]]"></div>
<div hidden="[[!shouldShowStorageDetails]]" id="storageDetails">
[[getStorageDetailsMessage_()]]
</div>
<cr-input id="websiteInput" label="$i18n{editPasswordWebsiteLabel}"
value="[[entry.urls.link]]" on-blur="onInputBlur_" readonly>
</cr-input>
......
......@@ -63,10 +63,11 @@ Polymer({
* is stored.
*/
getStorageDetailsMessage_() {
// TODO(crbug.com/1049141): Add support and tests for the multi-store case
// when dedup is being done.
if (this.entry.isPresentInAccount() && this.entry.isPresentOnDevice()) {
return this.i18n('passwordStoredInAccountAndOnDevice');
}
return this.entry.isPresentInAccount() ?
this.i18nAdvanced('passwordStoredInAccount', {tags: ['b']}) :
this.i18nAdvanced('passwordStoredOnDevice', {tags: ['b']});
this.i18n('passwordStoredInAccount') :
this.i18n('passwordStoredOnDevice');
}
});
......@@ -555,19 +555,23 @@ Polymer({
/** @type {!RemovalResult} */
const result = this.activePassword.requestRemove();
if (result.removedFromDevice || result.removedFromAccount) {
let text = this.i18n('passwordDeleted');
if (this.eligibleForAccountStorage_ && this.isOptedInForAccountStorage_) {
// TODO(crbug.com/1049141): Style the text according to mocks.
// TODO(crbug.com/1049141): Adapt the string when the user can delete
// from both account and device.
text = result.removedFromAccount ?
this.i18n('passwordDeletedFromAccount') :
this.i18n('passwordDeletedFromDevice');
if (!result.removedFromDevice && !result.removedFromAccount) {
/** @type {CrActionMenuElement} */ (this.$.menu).close();
return;
}
let text = this.i18n('passwordDeleted');
if (this.eligibleForAccountStorage_ && this.isOptedInForAccountStorage_) {
if (result.removedFromAccount && result.removedFromDevice) {
text = this.i18n('passwordDeletedFromAccountAndDevice');
} else if (result.removedFromAccount) {
text = this.i18n('passwordDeletedFromAccount');
} else {
text = this.i18n('passwordDeletedFromDevice');
}
getToastManager().show(text);
this.fire('iron-announce', {text: this.i18n('undoDescription')});
}
getToastManager().show(text);
this.fire('iron-announce', {text: this.i18n('undoDescription')});
/** @type {CrActionMenuElement} */ (this.$.menu).close();
},
......
......@@ -887,6 +887,8 @@ void AddAutofillStrings(content::WebUIDataSource* html_source,
{"copyPassword", IDS_SETTINGS_PASSWORD_COPY},
{"passwordStoredOnDevice", IDS_SETTINGS_PASSWORD_STORED_ON_DEVICE},
{"passwordStoredInAccount", IDS_SETTINGS_PASSWORD_STORED_IN_ACCOUNT},
{"passwordStoredInAccountAndOnDevice",
IDS_SETTINGS_PASSWORD_STORED_IN_ACCOUNT_AND_ON_DEVICE},
{"editPasswordWebsiteLabel", IDS_SETTINGS_PASSWORDS_WEBSITE},
{"editPasswordUsernameLabel", IDS_SETTINGS_PASSWORDS_USERNAME},
{"editPasswordPasswordLabel", IDS_SETTINGS_PASSWORDS_PASSWORD},
......@@ -905,6 +907,8 @@ void AddAutofillStrings(content::WebUIDataSource* html_source,
IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_DEVICE},
{"passwordDeletedFromAccount",
IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_ACCOUNT},
{"passwordDeletedFromAccountAndDevice",
IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_ACCOUNT_AND_DEVICE},
{"passwordRowMoreActionsButton", IDS_SETTINGS_PASSWORD_ROW_MORE_ACTIONS},
{"passwordRowFederatedMoreActionsButton",
IDS_SETTINGS_PASSWORD_ROW_FEDERATED_MORE_ACTIONS},
......
......@@ -303,12 +303,12 @@ export class PasswordSectionElementFactory {
/**
* Helper method used to create a password editing dialog.
* @param {!chrome.passwordsPrivate.PasswordUiEntry} passwordEntry
* @param {!MultiStorePasswordUiEntry} passwordEntry
* @return {!Object}
*/
createPasswordEditDialog(passwordEntry) {
const passwordDialog = this.document.createElement('password-edit-dialog');
passwordDialog.entry = new MultiStorePasswordUiEntry(passwordEntry);
passwordDialog.entry = passwordEntry;
passwordDialog.password = '';
this.document.body.appendChild(passwordDialog);
flush();
......
......@@ -704,8 +704,8 @@ suite('PasswordsSection', function() {
});
test('verifyFederatedPassword', function() {
const item = createPasswordEntry(
{url: 'goo.gl', username: 'bart', federationText: 'with chromium.org'});
const item = createMultiStorePasswordEntry(
{federationText: 'with chromium.org', username: 'bart', deviceId: 42});
const passwordDialog = elementFactory.createPasswordEditDialog(item);
flush();
......@@ -716,9 +716,11 @@ suite('PasswordsSection', function() {
assertTrue(passwordDialog.$.showPasswordButton.hidden);
});
// Test verifies that the edit dialog informs the password is stored in the
// account.
test('verifyStorageDetailsInEditDialogForAccountPassword', function() {
const accountPassword = createPasswordEntry(
{url: 'goo.gl', username: 'bart', fromAccountStore: true});
const accountPassword = createMultiStorePasswordEntry(
{url: 'goo.gl', username: 'bart', accountId: 42});
const accountPasswordDialog =
elementFactory.createPasswordEditDialog(accountPassword);
flush();
......@@ -731,14 +733,15 @@ suite('PasswordsSection', function() {
flush();
assertFalse(accountPasswordDialog.$.storageDetails.hidden);
assertEquals(
accountPasswordDialog.i18nAdvanced(
'passwordStoredInAccount', {tags: ['b']}),
accountPasswordDialog.$.storageDetails.innerHTML);
accountPasswordDialog.i18n('passwordStoredInAccount'),
accountPasswordDialog.$.storageDetails.innerText);
});
// Test verifies that the edit dialog informs the password is stored on the
// device.
test('verifyStorageDetailsInEditDialogForDevicePassword', function() {
const devicePassword = createPasswordEntry(
{url: 'goo.gl', username: 'bart', fromAccountStore: false});
const devicePassword = createMultiStorePasswordEntry(
{url: 'goo.gl', username: 'bart', deviceId: 42});
const devicePasswordDialog =
elementFactory.createPasswordEditDialog(devicePassword);
flush();
......@@ -751,14 +754,37 @@ suite('PasswordsSection', function() {
flush();
assertFalse(devicePasswordDialog.$.storageDetails.hidden);
assertEquals(
devicePasswordDialog.i18nAdvanced(
'passwordStoredOnDevice', {tags: ['b']}),
devicePasswordDialog.$.storageDetails.innerHTML);
devicePasswordDialog.i18n('passwordStoredOnDevice'),
devicePasswordDialog.$.storageDetails.innerText);
});
// Test verifies that the edit dialog informs the password is stored both on
// the device and in the account.
test(
'verifyStorageDetailsInEditDialogForPasswordInBothLocations', function() {
const accountAndDevicePassword = createMultiStorePasswordEntry(
{url: 'goo.gl', username: 'bart', deviceId: 42, accountId: 43});
const accountAndDevicePasswordDialog =
elementFactory.createPasswordEditDialog(accountAndDevicePassword);
flush();
// By default no message is displayed.
assertTrue(accountAndDevicePasswordDialog.$.storageDetails.hidden);
// Display the message.
accountAndDevicePasswordDialog.shouldShowStorageDetails = true;
flush();
assertFalse(accountAndDevicePasswordDialog.$.storageDetails.hidden);
assertEquals(
accountAndDevicePasswordDialog.i18n(
'passwordStoredInAccountAndOnDevice'),
accountAndDevicePasswordDialog.$.storageDetails.innerText);
});
test('showSavedPasswordEditDialog', function() {
const PASSWORD = 'bAn@n@5';
const item = createPasswordEntry({url: 'goo.gl', username: 'bart'});
const item = createMultiStorePasswordEntry(
{url: 'goo.gl', username: 'bart', deviceId: 42});
const passwordDialog = elementFactory.createPasswordEditDialog(item);
assertFalse(passwordDialog.$.showPasswordButton.hidden);
......@@ -796,8 +822,8 @@ suite('PasswordsSection', function() {
// Tests that invoking the plaintext password sets the corresponding
// password.
test('onShowSavedPasswordEditDialog', function() {
const expectedItem =
createPasswordEntry({url: 'goo.gl', username: 'bart', id: 1});
const expectedItem = createMultiStorePasswordEntry(
{url: 'goo.gl', username: 'bart', deviceId: 1});
const passwordDialog =
elementFactory.createPasswordEditDialog(expectedItem);
assertEquals('', passwordDialog.password);
......@@ -1025,19 +1051,36 @@ suite('PasswordsSection', function() {
isDisplayed(passwordsSection.$.accountStorageButtonsContainer));
});
// Test verifies that the notification displayed after removing a password
// informs whether the password was stored on the device, in the account or
// in both, for users in account storage mode.
test(
'passwordDeletionMessageSpecifiesStoreIfAccountStorageIsEnabled',
function() {
// Feature flag enabled.
loadTimeData.overrideValues({enableAccountStorage: true});
// Create array with one account-only password, one device-only, and
// two duplicates that will be merged.
const passwordsSection = elementFactory.createPasswordsSection(
passwordManager,
[
createPasswordEntry(
{username: 'account', id: 0, fromAccountStore: true}),
createPasswordEntry(
{username: 'local', id: 1, fromAccountStore: false})
{username: 'local', id: 1, fromAccountStore: false}),
createPasswordEntry({
username: 'both',
frontendId: 2,
id: 21,
fromAccountStore: false
}),
createPasswordEntry({
username: 'both',
frontendId: 2,
id: 22,
fromAccountStore: true
}),
],
[]);
......@@ -1054,19 +1097,28 @@ suite('PasswordsSection', function() {
const passwordListItems =
passwordsSection.root.querySelectorAll('password-list-item');
// No removal actually happens, so all passwords keep their position.
// The merged entry comes last.
passwordListItems[0].$$('#passwordMenu').click();
passwordsSection.$.menuRemovePassword.click();
assertEquals(
passwordsSection.i18n('passwordDeletedFromAccount'),
getToastManager().$.content.textContent);
// The account password was not really removed, so the local one is
// still at index 1.
passwordListItems[1].$$('#passwordMenu').click();
passwordsSection.$.menuRemovePassword.click();
assertEquals(
passwordsSection.i18n('passwordDeletedFromDevice'),
getToastManager().$.content.textContent);
// TODO(crbug.com/1049141): Update the test when the removal dialog
// is introduced.
passwordListItems[2].$$('#passwordMenu').click();
passwordsSection.$.menuRemovePassword.click();
assertEquals(
passwordsSection.i18n('passwordDeletedFromAccountAndDevice'),
getToastManager().$.content.textContent);
});
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment