Bug 1919665 - Account Hub Sync Calendars and Address Books. r=freaktechnik
**How To Test** - Get through to the sync accounts view - Hit continue - Close the modal and go to your address books and calendars - Check if they are there and synced Differential Revision: https://phabricator.services.mozilla.com/D228906 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
a0a1895609
Коммит
d6a66505f4
|
@ -154,6 +154,31 @@ class EmailSyncAccountsForm extends AccountHubStep {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the chosen address books and calendars
|
||||
*
|
||||
* @returns {SyncAccounts} The sync accounts selected.
|
||||
*/
|
||||
captureState() {
|
||||
const checkedAddressBookUrls = Array.from(
|
||||
this.querySelectorAll("#addressBooks input:checked:enabled"),
|
||||
checkedAddressBook => checkedAddressBook.dataset.url
|
||||
);
|
||||
const checkedCalendarsUrls = Array.from(
|
||||
this.querySelectorAll("#calendars input:checked:enabled"),
|
||||
checkedCalendar => checkedCalendar.dataset.url
|
||||
);
|
||||
|
||||
return {
|
||||
calendars: this.#availableSyncAccounts.calendars.filter(calendar =>
|
||||
checkedCalendarsUrls.includes(calendar.uri?.spec)
|
||||
),
|
||||
addressBooks: this.#availableSyncAccounts.addressBooks.filter(
|
||||
addressBook => checkedAddressBookUrls.includes(addressBook.url.href)
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of the input labels and resets #availableSyncAccounts.
|
||||
*/
|
||||
|
@ -187,10 +212,15 @@ class EmailSyncAccountsForm extends AccountHubStep {
|
|||
input.type = "checkbox";
|
||||
input.checked = true;
|
||||
input.disabled = syncAccount.existing;
|
||||
input.dataset.url =
|
||||
inputClass === "address-book-input"
|
||||
? syncAccount.url.href
|
||||
: syncAccount.uri?.spec;
|
||||
const title = document.createElement("span");
|
||||
title.textContent = syncAccount.name;
|
||||
label.append(input);
|
||||
label.append(title);
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
|
@ -212,6 +242,7 @@ class EmailSyncAccountsForm extends AccountHubStep {
|
|||
? 0
|
||||
: this.#availableSyncAccounts[type].length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update strings associated with the sync account type.
|
||||
*
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
<label class="toggle-container-with-text">
|
||||
<input id="rememberPassword"
|
||||
class="check-button"
|
||||
type="checkbox"
|
||||
disabled="disabled" />
|
||||
type="checkbox" />
|
||||
<span class="checkbox-label"
|
||||
data-l10n-id="account-setup-remember-password"
|
||||
data-l10n-attrs="accesskey">
|
||||
|
|
|
@ -318,7 +318,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
this.#clearNotifications();
|
||||
this.#currentState = subview;
|
||||
await this.#loadTemplateScript(this.#states[subview].templateId);
|
||||
this.#states[subview].subview.hidden = false;
|
||||
this.#currentSubview.hidden = false;
|
||||
this.#setFooterButtons();
|
||||
}
|
||||
|
||||
|
@ -357,8 +357,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
*/
|
||||
#clearNotifications() {
|
||||
if (this.#currentState) {
|
||||
const stateDetails = this.#states[this.#currentState];
|
||||
stateDetails.subview.clearNotifications();
|
||||
this.#currentSubview.clearNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,7 +431,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
this.#hasCancelled ? this.#currentState : stateDetails.previousStep
|
||||
);
|
||||
} catch (error) {
|
||||
stateDetails.subview.showNotification({
|
||||
this.#currentSubview.showNotification({
|
||||
title: error.cause.code,
|
||||
description: error.cause.text,
|
||||
error,
|
||||
|
@ -449,7 +448,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
case "forward":
|
||||
try {
|
||||
this.#hasCancelled = false;
|
||||
const stateData = stateDetails.subview.captureState();
|
||||
const stateData = this.#currentSubview.captureState();
|
||||
await this.#handleForwardAction(this.#currentState, stateData);
|
||||
} catch (error) {
|
||||
this.#handleAbortable();
|
||||
|
@ -464,7 +463,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
try {
|
||||
await this.#handleCustomAction(this.#currentState, event);
|
||||
} catch (error) {
|
||||
stateDetails.subview.showNotification({
|
||||
this.#currentSubview.showNotification({
|
||||
title: error.title,
|
||||
description: error.text,
|
||||
error,
|
||||
|
@ -474,7 +473,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
break;
|
||||
case "edit-configuration":
|
||||
this.#currentConfig = this.#fillAccountConfig(
|
||||
stateDetails.subview.captureState()
|
||||
this.#currentSubview.captureState()
|
||||
);
|
||||
// The edit configuration button was pressed.
|
||||
await this.#initUI("incomingConfigSubview");
|
||||
|
@ -485,7 +484,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
try {
|
||||
this.#emailFooter.toggleForwardDisabled(!event.detail.completed);
|
||||
} catch (error) {
|
||||
stateDetails.subview.showNotification({
|
||||
this.#currentSubview.showNotification({
|
||||
title: error.title,
|
||||
description: error.text,
|
||||
error,
|
||||
|
@ -504,7 +503,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
stateData = this.#fillAccountConfig(stateData);
|
||||
await this.#advancedSetup(stateData);
|
||||
} catch (error) {
|
||||
stateDetails.subview.showNotification({
|
||||
this.#currentSubview.showNotification({
|
||||
title: error.title,
|
||||
description: error.text,
|
||||
error,
|
||||
|
@ -524,7 +523,6 @@ class AccountHubEmail extends HTMLElement {
|
|||
* @param {string} currentState - The current state of the email flow.
|
||||
*/
|
||||
#handleBackAction(currentState) {
|
||||
const stateDetails = this.#states[this.#currentState];
|
||||
switch (currentState) {
|
||||
case "autoConfigSubview":
|
||||
this.#hasCancelled = true;
|
||||
|
@ -536,7 +534,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
case "outgoingConfigSubview":
|
||||
// Set the currentConfig outgoing to the updated fields in this form.
|
||||
this.#currentConfig.outgoing =
|
||||
stateDetails.subview.captureState().outgoing;
|
||||
this.#currentSubview.captureState().outgoing;
|
||||
break;
|
||||
case "emailPasswordSubview":
|
||||
break;
|
||||
|
@ -580,6 +578,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
});
|
||||
}
|
||||
this.#hasCancelled = false;
|
||||
this.#stopLoading();
|
||||
this.#setCurrentConfigForSubview();
|
||||
break;
|
||||
}
|
||||
|
@ -604,7 +603,6 @@ class AccountHubEmail extends HTMLElement {
|
|||
break;
|
||||
case "incomingConfigSubview":
|
||||
await this.#initUI(this.#states[this.#currentState].nextStep);
|
||||
|
||||
this.#currentConfig.incoming = stateData.config.incoming;
|
||||
this.#setCurrentConfigForSubview();
|
||||
|
||||
|
@ -674,10 +672,24 @@ class AccountHubEmail extends HTMLElement {
|
|||
});
|
||||
break;
|
||||
case "emailSyncAccountsSubview":
|
||||
this.#currentSubview.showNotification({
|
||||
fluentTitleId: "account-hub-email-added-success",
|
||||
type: "success",
|
||||
});
|
||||
try {
|
||||
// Add the selected sync address books and calendars.
|
||||
this.#addSyncAccounts(stateData);
|
||||
|
||||
// TODO: Show the account added page when it's finished.
|
||||
// await this.#initUI(this.#states[this.#currentState].nextStep);
|
||||
|
||||
// this.#currentSubview.showNotification({
|
||||
// fluentTitleId: "account-hub-email-added-success",
|
||||
// type: "success",
|
||||
// });
|
||||
} catch (error) {
|
||||
this.#currentSubview.showNotification({
|
||||
fluentTitleId: "account-hub-unable-to-sync-accounts",
|
||||
type: "error",
|
||||
error,
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "emailAddedSubview":
|
||||
break;
|
||||
|
@ -711,7 +723,7 @@ class AccountHubEmail extends HTMLElement {
|
|||
|
||||
if (config.isComplete()) {
|
||||
this.#stopLoading();
|
||||
this.#states[this.#currentState].subview.showNotification({
|
||||
this.#currentSubview.showNotification({
|
||||
fluentTitleId: "account-setup-success-half-manual",
|
||||
type: "success",
|
||||
});
|
||||
|
@ -1144,6 +1156,27 @@ class AccountHubEmail extends HTMLElement {
|
|||
return cals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} SyncAccounts
|
||||
* @property {Array} calendars - The selected calendars.
|
||||
* @property {Array} addressBooks - The selected address books.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds selected calendars and address books to Thunderbird.
|
||||
*
|
||||
* @type {SyncAccounts} syncAccounts - The sync accounts for the user.
|
||||
*/
|
||||
#addSyncAccounts(syncAccounts) {
|
||||
for (const calendar of syncAccounts.calendars) {
|
||||
cal.manager.registerCalendar(calendar);
|
||||
}
|
||||
|
||||
for (const addressBook of syncAccounts.addressBooks) {
|
||||
addressBook.create();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the opening of the account manager after the creation of a new
|
||||
* account and reset any leftover data in the current setup flow.
|
||||
|
|
|
@ -174,6 +174,8 @@ account-hub-sync-success = Thunderbird found some connected services
|
|||
|
||||
account-hub-sync-failure = Thunderbird was unable to find connected services
|
||||
|
||||
account-hub-unable-to-sync-accounts = Thunderbird was unable to connect the selected services
|
||||
|
||||
account-hub-email-added-success = Email account connected successfully
|
||||
|
||||
account-hub-config-test-success = Configuration settings valid
|
||||
|
|
|
@ -13,6 +13,10 @@ const { MailServices } = ChromeUtils.importESModule(
|
|||
);
|
||||
const { DNS } = ChromeUtils.importESModule("resource:///modules/DNS.sys.mjs");
|
||||
|
||||
const { cal } = ChromeUtils.importESModule(
|
||||
"resource:///modules/calendar/calUtils.sys.mjs"
|
||||
);
|
||||
|
||||
let emailUser;
|
||||
const PREF_NAME = "mailnews.auto_config_url";
|
||||
const PREF_VALUE = Services.prefs.getCharPref(PREF_NAME);
|
||||
|
@ -835,8 +839,14 @@ add_task(async function test_account_enter_password_imap_account() {
|
|||
"The email password subview should be hidden."
|
||||
);
|
||||
|
||||
const imapAccount = MailServices.accounts.accounts.find(
|
||||
account => account.identities[0].email === emailUser.email
|
||||
let imapAccount;
|
||||
|
||||
await TestUtils.waitForCondition(
|
||||
() =>
|
||||
(imapAccount = MailServices.accounts.accounts.find(
|
||||
account => account.identities[0]?.email === emailUser.email
|
||||
)),
|
||||
"The imap account should be created."
|
||||
);
|
||||
|
||||
Assert.ok(imapAccount, "IMAP account should be created");
|
||||
|
@ -913,11 +923,15 @@ add_task(async function test_account_load_sync_accounts_imap_account() {
|
|||
"The email password subview should be hidden."
|
||||
);
|
||||
|
||||
const imapAccount = MailServices.accounts.accounts.find(
|
||||
account => account.identities[0].email === emailUser.email
|
||||
);
|
||||
let imapAccount;
|
||||
|
||||
Assert.ok(imapAccount, "IMAP account should be created");
|
||||
await TestUtils.waitForCondition(
|
||||
() =>
|
||||
(imapAccount = MailServices.accounts.accounts.find(
|
||||
account => account.identities[0]?.email === emailUser.email
|
||||
)),
|
||||
"The imap account should be created."
|
||||
);
|
||||
|
||||
await TestUtils.waitForCondition(
|
||||
() =>
|
||||
|
@ -988,7 +1002,7 @@ add_task(async function test_account_load_sync_accounts_imap_account() {
|
|||
"There should 1 checked address book."
|
||||
);
|
||||
Assert.equal(
|
||||
addressBooks.item(0).textContent,
|
||||
addressBooks[0].textContent,
|
||||
"You found me!",
|
||||
"The address book found should have the name - You found me!"
|
||||
);
|
||||
|
@ -1001,26 +1015,26 @@ add_task(async function test_account_load_sync_accounts_imap_account() {
|
|||
"There should 2 checked calendars."
|
||||
);
|
||||
Assert.equal(
|
||||
calendars.item(0).textContent,
|
||||
calendars[0].textContent,
|
||||
"You found me!",
|
||||
"The first calendar found should have the name - You found me!"
|
||||
);
|
||||
Assert.equal(
|
||||
calendars.item(1).textContent,
|
||||
calendars[1].textContent,
|
||||
"Röda dagar",
|
||||
"The second calendar found should have the name - Röda dagar"
|
||||
);
|
||||
|
||||
// Unchecking an input should update the count label, and the select toggle
|
||||
// fluent id.
|
||||
const checkEvent = BrowserTestUtils.waitForEvent(
|
||||
addressBooks.item(0).querySelector("input"),
|
||||
let checkEvent = BrowserTestUtils.waitForEvent(
|
||||
addressBooks[0].querySelector("input"),
|
||||
"change",
|
||||
true,
|
||||
event => event.target.checked === false
|
||||
event => !event.target.checked
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
addressBooks.item(0).querySelector("input"),
|
||||
addressBooks[0].querySelector("input"),
|
||||
{}
|
||||
);
|
||||
await checkEvent;
|
||||
|
@ -1054,6 +1068,75 @@ add_task(async function test_account_load_sync_accounts_imap_account() {
|
|||
"Calendars count should be 0."
|
||||
);
|
||||
|
||||
// Select the first calendar and address book and click continue to add
|
||||
// the selected calendar and address book.
|
||||
checkEvent = BrowserTestUtils.waitForEvent(
|
||||
addressBooks[0].querySelector("input"),
|
||||
"change",
|
||||
true,
|
||||
event => event.target.checked
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
addressBooks[0].querySelector("input"),
|
||||
{}
|
||||
);
|
||||
await checkEvent;
|
||||
checkEvent = BrowserTestUtils.waitForEvent(
|
||||
calendars[0].querySelector("input"),
|
||||
"change",
|
||||
true,
|
||||
event => event.target.checked
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(calendars[0].querySelector("input"), {});
|
||||
await checkEvent;
|
||||
|
||||
Assert.equal(
|
||||
syncAccountsTemplate.l10n.getAttributes(selectedAddressBooks).args.count,
|
||||
1,
|
||||
"Address books count should be 1."
|
||||
);
|
||||
Assert.equal(
|
||||
syncAccountsTemplate.l10n.getAttributes(selectedCalendars).args.count,
|
||||
1,
|
||||
"Calendars count should be 1."
|
||||
);
|
||||
const calendarPromise = new Promise(resolve => {
|
||||
const observer = {
|
||||
onCalendarRegistered(calendar) {
|
||||
cal.manager.removeObserver(this);
|
||||
resolve(calendar);
|
||||
},
|
||||
onCalendarUnregistering() {},
|
||||
onCalendarDeleting() {},
|
||||
};
|
||||
cal.manager.addObserver(observer);
|
||||
});
|
||||
const addressBookDirectoryPromise = TestUtils.topicObserved(
|
||||
"addrbook-directory-synced"
|
||||
);
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(footerForward, {});
|
||||
|
||||
// Check existance of address book and calendar.
|
||||
const [addressBookDirectory] = await addressBookDirectoryPromise;
|
||||
Assert.equal(addressBookDirectory.dirName, "You found me!");
|
||||
Assert.equal(
|
||||
addressBookDirectory.dirType,
|
||||
Ci.nsIAbManager.CARDDAV_DIRECTORY_TYPE
|
||||
);
|
||||
Assert.equal(
|
||||
addressBookDirectory.getStringValue("carddav.url", ""),
|
||||
"https://example.org/browser/comm/mail/components/addrbook/test/browser/data/addressbook.sjs"
|
||||
);
|
||||
|
||||
const calendar = await calendarPromise;
|
||||
Assert.equal(calendar.name, "You found me!");
|
||||
Assert.equal(calendar.type, "caldav");
|
||||
|
||||
// Remove the address book and calendar.
|
||||
MailServices.ab.deleteAddressBook(addressBookDirectory.URI);
|
||||
cal.manager.removeCalendar(calendar);
|
||||
|
||||
MailServices.accounts.removeAccount(imapAccount);
|
||||
Services.logins.removeAllLogins();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче