Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 34 additions & 14 deletions browser/extensions/felt/content/felt.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -180,22 +180,42 @@
</span>
</div>
<div class="felt-browser-error is-hidden">
<div
<moz-message-bar
class="felt-browser-error-multiple-crashes is-hidden"
data-l10n-id="felt-browser-error-multiple-crashes"
></div>
<div class="felt-browser-error-connection is-hidden">
<span data-l10n-id="felt-browser-error-connection"></span>
<span class="felt-browser-error-details"></span>
</div>
<div
data-l10n-id="felt-browser-error-multiple-crashes2"
type="error"
dismissable="true"
></moz-message-bar>
<moz-message-bar
class="felt-browser-error-no-network is-hidden"
data-l10n-id="felt-browser-error-no-network"
type="error"
dismissable="true"
>
<span slot="message" class="felt-browser-error-details"></span>
</moz-message-bar>
<moz-message-bar
class="felt-browser-error-connection is-hidden"
data-l10n-id="felt-browser-error-connection2"
type="error"
dismissable="true"
>
<span slot="message" class="felt-browser-error-details"></span>
</moz-message-bar>
<moz-message-bar
class="felt-browser-error-sso-timeout is-hidden"
data-l10n-id="felt-browser-error-sso-timeout"
></div>
<div class="felt-updates-error-messages is-hidden">
<span data-l10n-id="felt-updates-error-messages"></span>
<span class="felt-browser-error-details"></span>
</div>
data-l10n-id="felt-browser-error-sso-timeout2"
type="error"
dismissable="true"
></moz-message-bar>
<moz-message-bar
class="felt-updates-error-messages is-hidden"
data-l10n-id="felt-error-updates"
type="error"
dismissable="true"
>
<span slot="message" class="felt-browser-error-details"></span>
</moz-message-bar>
</div>
<span
class="felt-powered-by text-deemphasized"
Expand Down
19 changes: 7 additions & 12 deletions browser/extensions/felt/content/styles/felt.css
Original file line number Diff line number Diff line change
Expand Up @@ -246,19 +246,14 @@ body:has(#notification-popup-box[open]) .felt:not(#notification-popup-box .felt)
.felt-browser-error {
position: absolute;
/* stylelint-disable-next-line */
bottom: 32px;
top: 16px;
/* stylelint-disable-next-line */
left: 8px;
font-size: medium;
color: var(--text-color-error);
font-weight: var(--font-weight-bold);
}

.felt-browser-error-details {
display: block;
font-weight: normal;
font-size: small;
margin-top: var(--space-xsmall);
right: 16px;
/* stylelint-disable-next-line */
left: 16px;
display: flex;
flex-direction: column;
gap: var(--space-small);
}

.felt-updates-message {
Expand Down
32 changes: 25 additions & 7 deletions browser/extensions/felt/content/window.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ const ErrorReport = {
"chrome://global/locale/appstrings.properties"
);
});

this._wrapper.addEventListener("message-bar:user-dismissed", e => {
e.preventDefault();
e.target.classList.add("is-hidden");
});
},

reset() {
Expand All @@ -43,10 +48,9 @@ const ErrorReport = {
return;
}
this._wrapper.classList.add("is-hidden");
const errors = this._wrapper.querySelectorAll(
".felt-browser-error > div:not(.is-hidden)"
);
errors.forEach(e => e.classList.add("is-hidden"));
for (const bar of this._wrapper.querySelectorAll("moz-message-bar")) {
bar.classList.add("is-hidden");
}
Comment thread
jporter-dev marked this conversation as resolved.
},

async update(errorType, details = null, cause = null) {
Expand Down Expand Up @@ -93,14 +97,27 @@ const ErrorReport = {
};

async function connectToConsole(email) {
ErrorReport.reset();

let posture;
try {
posture = await lazy.ConsoleClient.sendDevicePosture();
} catch (err) {
console.error(`FeltExtension: Failed to connect to console: ${err}`);
ErrorReport.update("felt-browser-error-connection", err.message, err.cause);

// Show simpler "No Network Connection" only for truly offline scenarios
// netOffline for offline mode, dnsNotFound2 for actual network disconnect
const NETWORK_ERRORS = new Set(["netOffline", "dnsNotFound2"]);
Comment thread
gcp marked this conversation as resolved.
Comment thread
jporter-dev marked this conversation as resolved.
if (NETWORK_ERRORS.has(err.message)) {
ErrorReport.update(
"felt-browser-error-no-network",
"no-network-connection"
);
} else {
ErrorReport.update(
"felt-browser-error-connection",
err.message,
err.cause
);
}
return;
}

Expand Down Expand Up @@ -272,6 +289,7 @@ async function connectToConsole(email) {
Ci.nsIWebProgress.NOTIFY_STATE_NETWORK | Ci.nsIWebProgress.NOTIFY_LOCATION
);

ErrorReport.reset();
document.querySelector(".felt-login__email-pane").classList.add("is-hidden");
document.querySelector(".felt-login__sso").classList.remove("is-hidden");

Expand Down
19 changes: 15 additions & 4 deletions browser/locales/en-US/browser/enterprise/felt.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,32 @@ felt-version =

## Error details when launching the browser crashes

felt-browser-error-multiple-crashes = { -brand-short-name } crashed multiple times.
felt-browser-error-connection = Unable to connect to the console. Please contact your administrator.
felt-browser-error-sso-timeout = Sign-in timed out. Please try again, or contact your administrator if the problem persists.
felt-browser-error-sso-timeout2 =
.heading = Sign-in timed out
.message = Please try again, or contact your administrator if the problem persists.
felt-browser-error-multiple-crashes2 =
.heading = { -brand-short-name } crashed multiple times

## Network error headings

felt-browser-error-connection2 =
.heading = Unable to connect. Please contact your administrator.
felt-browser-error-no-network =
Comment thread
gcp marked this conversation as resolved.
.heading = No network connection

## Network error details.

felt-error-network = Unknown network error
felt-error-no-network-connection = Please check your internet connection and try again.

## Updates messages and related errors messages

felt-updates-title = Good morning
felt-updates-checking = Checking for updates…
felt-updates-application = Applying updates…
felt-updates-uptodate = { -brand-short-name } is up to date
felt-updates-error-messages = An error occurred while applying updates…
felt-error-updates =
.heading = An error occurred while applying updates…
felt-error-contact-admin = Please contact your administrator.
felt-error-unsupported-system-contact-admin = Your current system does not support this new version. Please contact your administrator.
felt-error-checking-failed-contact-admin = Unexpected failure while checking for an update. Please contact your administrator.
67 changes: 55 additions & 12 deletions testing/enterprise/test_felt_browser_console_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,70 @@ def teardown(self):
self._manually_closed_child = True
return super().teardown()

def connection_error_test(self, console_addr, error_msg):
def check_error_bar_message(
self,
console_addr,
selector,
expected_heading,
error_msg=None,
error_msg_contains=None,
):
self.set_string_pref("enterprise.console.address", console_addr)

self.submit_email()

self._driver.set_context("chrome")
error = self.get_elem(".felt-browser-error-connection")
message = error.get_property("textContent").strip()
assert "Unable to connect" in message, f"Unexpected error message: {message}"
error = self.get_elem(selector)
message = error.get_attribute("heading").strip()
assert expected_heading in message, f"Unexpected error message: {message}"

details = self.get_elem(".felt-browser-error-details")
details_text = details.get_property("textContent").strip()
assert details_text == error_msg, f"Correct error message: '{details_text}'"
if error_msg is not None:
details = self.get_elem(f"{selector} .felt-browser-error-details")
details_text = details.get_property("textContent").strip()
assert details_text == error_msg, f"Correct error message: '{details_text}'"

if error_msg_contains is not None:
details = self.get_elem(f"{selector} .felt-browser-error-details")
details_text = details.get_property("textContent").strip()
assert error_msg_contains in details_text, (
f"Expected '{error_msg_contains}' in error details: '{details_text}'"
)

self._driver.set_context("content")

def test_felt_00_connection_error_fluent(self):
return self.connection_error_test("http://127.0.0.1:1", "Unknown network error")
def test_felt_unreachable_ip_shows_connection_error(self):
# Port 1 is on Firefox's blocked-port list, producing a generic "network"
# error key that resolves to "Unknown network error" via the felt-error-network
return self.check_error_bar_message(
"http://127.0.0.1:1",
".felt-browser-error-connection",
"Unable to connect",
"Unknown network error",
)

def test_felt_01_connection_error_bundle(self):
return self.connection_error_test(
def test_felt_nonexistent_domain_shows_no_network_error(self):
# dnsNotFound2 which renders the no-network bar rather than the connection error bar.
return self.check_error_bar_message(
"http://nonexistent.localdomain:80",
"We can’t connect to the server at nonexistent.localdomain.",
".felt-browser-error-no-network",
"No network connection",
"Please check your internet connection and try again.",
)

def test_felt_ssl_mismatch_shows_connection_error(self):
return self.check_error_bar_message(
f"https://localhost:{self.console_port}",
".felt-browser-error-connection",
"Unable to connect",
)

def test_felt_error_details_include_console_address(self):
# connectionFailure with host substitution so the console address appears in details.
refused_port = self.console_port + 20000
console_addr = f"http://localhost:{refused_port}"
return self.check_error_bar_message(
console_addr,
".felt-browser-error-connection",
"Unable to connect",
f"Firefox can’t establish a connection to the server at localhost:{refused_port}.",
)