[Extensions] Add "Warnings" text button on chrome://extensions
Previously, the "Errors" button was shown even for benign manifest key
warnings, which confused developers. This change updates the button to
display "Warnings" if only unrecognized manifest key warnings are
present, and "Errors" otherwise. Adds an i18n string and updates the UI
logic accordingly.
Bug: 406497235
Change-Id: I5736992b5ae81c5949e3da952f8e909ea171def4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6639214
Commit-Queue: Oliver Dunk <oliverdunk@chromium.org>
Reviewed-by: Solomon Kinard <solomonkinard@chromium.org>
Reviewed-by: Oliver Dunk <oliverdunk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1502187}
diff --git a/AUTHORS b/AUTHORS
index 48c474c..ecf43c26 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -102,6 +102,7 @@
Ambarish Rapte <ambarish.r@samsung.com>
Ameen Basha <ameenbasha111@gmail.com>
Amey Jahagirdar <jahagird@amazon.com>
+Amit P <ponnan2112@gmail.com>
Amit Paul <a.paul@samsung.com>
Amit Sarkar <amit.srkr@samsung.com>
Amogh Bihani <amogh.bihani@samsung.com>
diff --git a/chrome/app/extensions_strings.grdp b/chrome/app/extensions_strings.grdp
index 5a998d679..fe1eed5e 100644
--- a/chrome/app/extensions_strings.grdp
+++ b/chrome/app/extensions_strings.grdp
@@ -157,6 +157,9 @@
<message name="IDS_EXTENSIONS_ITEM_ERRORS" desc="The label of the button to bring the user to the page showing an extension's errors.">
Errors
</message>
+ <message name="IDS_EXTENSIONS_ITEM_WARNINGS" desc="The label of the button to bring the user to the page showing an extension's warnings.">
+ Warnings
+ </message>
<message name="IDS_EXTENSIONS_ITEM_HOST_PERMISSIONS_HEADING" desc="The heading above the details of which websites an extension is allowed to run on.">
Allow this extension to read and change all your data on websites you visit:
</message>
diff --git a/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_ITEM_WARNINGS.png.sha1 b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_ITEM_WARNINGS.png.sha1
new file mode 100644
index 0000000..7e3f43a
--- /dev/null
+++ b/chrome/app/extensions_strings_grdp/IDS_EXTENSIONS_ITEM_WARNINGS.png.sha1
@@ -0,0 +1 @@
+1782dd8063811ec7b499713413a2c3ce409dd8e0
\ No newline at end of file
diff --git a/chrome/browser/resources/extensions/item.css b/chrome/browser/resources/extensions/item.css
index 2088c42..02ce9fa 100644
--- a/chrome/browser/resources/extensions/item.css
+++ b/chrome/browser/resources/extensions/item.css
@@ -183,8 +183,12 @@
--paper-tooltip-min-width: 0;
}
-#errors-button {
- color: var(--error-color);
+#errors-button.error {
+ --cr-button-text-color: var(--error-color);
+}
+
+#errors-button.warning {
+ --cr-button-text-color: var(--warning-text-color);
}
#account-upload-button {
diff --git a/chrome/browser/resources/extensions/item.html.ts b/chrome/browser/resources/extensions/item.html.ts
index 3455370..bbbac27 100644
--- a/chrome/browser/resources/extensions/item.html.ts
+++ b/chrome/browser/resources/extensions/item.html.ts
@@ -147,9 +147,13 @@
$i18n{remove}
</cr-button>
${this.shouldShowErrorsButton_() ? html`
- <cr-button id="errors-button" @click="${this.onErrorsClick_}"
+ <cr-button id="errors-button"
+ class="${this.showErrorsAsWarningsButtonLabel_()
+ ? 'warning' : 'error'}"
+ @click="${this.onErrorsClick_}"
aria-describedby="a11yAssociation">
- $i18n{itemErrors}
+ ${this.showErrorsAsWarningsButtonLabel_()
+ ? '$i18n{itemWarnings}' : '$i18n{itemErrors}'}
</cr-button>` : ''}
</div>
${this.showAccountUploadButton_() ? html`
diff --git a/chrome/browser/resources/extensions/item.ts b/chrome/browser/resources/extensions/item.ts
index e6c51df..1a788a75 100644
--- a/chrome/browser/resources/extensions/item.ts
+++ b/chrome/browser/resources/extensions/item.ts
@@ -433,6 +433,17 @@
return this.hasAllowlistWarning_() && !this.hasSevereWarnings_() &&
!this.hasMv2DeprecationWarning_();
}
+
+ protected showErrorsAsWarningsButtonLabel_(): boolean {
+ // If there are runtime errors or install warnings, show as errors.
+ if (this.data.runtimeErrors?.length || this.data.installWarnings?.length) {
+ return false;
+ }
+
+ // All manifest errors are considered warnings, so if there are no
+ // runtime/install issues, label is 'Warnings'.
+ return true;
+ }
}
// Exported to be used in the autogenerated Lit template file
diff --git a/chrome/browser/resources/extensions/shared_vars.css b/chrome/browser/resources/extensions/shared_vars.css
index 861490f..2c4ab40 100644
--- a/chrome/browser/resources/extensions/shared_vars.css
+++ b/chrome/browser/resources/extensions/shared_vars.css
@@ -13,6 +13,8 @@
--error-color: var(--google-red-700);
/* Copied from 'ui/gfx/color_palette.h' kGoogleYellow700 (#f29900) */
--warning-color: rgb(242, 153, 0);
+ /* Warning text color with sufficient contrast against white background */
+ --warning-text-color: #B16300;
--extensions-card-height: 160px;
--separator-gap: 9px;
--sidebar-width: 256px;
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 7f00cde..9e73d41c 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -185,6 +185,7 @@
{"itemDetailsBackButtonRoleDescription",
IDS_EXTENSIONS_DETAILS_BACK_BUTTON_ARIA_ROLE_DESCRIPTION},
{"itemErrors", IDS_EXTENSIONS_ITEM_ERRORS},
+ {"itemWarnings", IDS_EXTENSIONS_ITEM_WARNINGS},
{"accessibilityErrorLine", IDS_EXTENSIONS_ACCESSIBILITY_ERROR_LINE},
{"accessibilityErrorMultiLine",
IDS_EXTENSIONS_ACCESSIBILITY_ERROR_MULTI_LINE},
diff --git a/chrome/test/data/webui/extensions/extensions_browsertest.cc b/chrome/test/data/webui/extensions/extensions_browsertest.cc
index 547d188..342a609 100644
--- a/chrome/test/data/webui/extensions/extensions_browsertest.cc
+++ b/chrome/test/data/webui/extensions/extensions_browsertest.cc
@@ -258,6 +258,10 @@
RunTestCase("CanUploadAsAccountExtension");
}
+IN_PROC_BROWSER_TEST_F(CrExtensionsItemsTest, ShowErrorAsWarningsButtonLabel) {
+ RunTestCase("ShowErrorAsWarningsButtonLabel");
+}
+
class CrExtensionsDetailViewTest : public ExtensionsBrowserTest {
protected:
void RunTestCase(const std::string& testCase) {
diff --git a/chrome/test/data/webui/extensions/item_test.ts b/chrome/test/data/webui/extensions/item_test.ts
index 50c46cfa..6680bd8f 100644
--- a/chrome/test/data/webui/extensions/item_test.ts
+++ b/chrome/test/data/webui/extensions/item_test.ts
@@ -67,6 +67,47 @@
testElementsVisibility(item, devElements, false);
}
+/**
+ * Helper to create a runtime error object with default values.
+ */
+function createRuntimeError(
+ extensionId: string,
+ customFields?: Partial<chrome.developerPrivate.RuntimeError>):
+ chrome.developerPrivate.RuntimeError {
+ return {
+ type: chrome.developerPrivate.ErrorType.RUNTIME,
+ extensionId: extensionId,
+ fromIncognito: false,
+ source: '',
+ message: 'Some runtime error',
+ id: 1,
+ severity: chrome.developerPrivate.ErrorLevel.ERROR,
+ contextUrl: '',
+ occurrences: 1,
+ renderViewId: 0,
+ renderProcessId: 0,
+ canInspect: false,
+ stackTrace: [],
+ ...customFields,
+ };
+}
+
+/**
+ * Helper to check if errors button exists and what type it is.
+ */
+function getErrorsButtonInfo(item: HTMLElement):
+ {exists: boolean, isWarning: boolean, isError: boolean} {
+ const btn = item.shadowRoot!.querySelector('#errors-button');
+ if (!btn) {
+ return {exists: false, isWarning: false, isError: false};
+ }
+ return {
+ exists: true,
+ isWarning: btn.classList.contains('warning'),
+ isError: btn.classList.contains('error'),
+ };
+}
+
suite('ExtensionItemTest', function() {
/**
* Extension item created before each test.
@@ -696,4 +737,65 @@
item.shadowRoot.querySelector<HTMLElement>('#account-upload-button')!,
'uploadItemToAccount', [item.data.id]);
});
+
+ test('ShowErrorAsWarningsButtonLabel', async () => {
+ // 1. No runtime errors, no install warnings: button should show "Warnings"
+ // label.
+ let data = createExtensionInfo(item.data);
+ data.runtimeErrors = [];
+ data.installWarnings = [];
+ data.manifestErrors = [{
+ type: chrome.developerPrivate.ErrorType.MANIFEST,
+ extensionId: data.id,
+ fromIncognito: false,
+ source: 'manifest.json',
+ message: 'Some manifest error',
+ id: 1,
+ manifestKey: 'background',
+ }];
+ item.data = data;
+ await microtasksFinished();
+ let buttonInfo = getErrorsButtonInfo(item);
+ assertTrue(buttonInfo.exists, 'Errors button should exist');
+ assertTrue(
+ buttonInfo.isWarning,
+ 'Button should have warning class when no errors or install warnings');
+
+ // 2. Has runtime errors: button should show "Errors" label.
+ data = createExtensionInfo(item.data);
+ data.runtimeErrors = [createRuntimeError(data.id)];
+ data.installWarnings = [];
+ item.data = data;
+ await microtasksFinished();
+ buttonInfo = getErrorsButtonInfo(item);
+ assertTrue(buttonInfo.exists, 'Errors button should exist');
+ assertTrue(
+ buttonInfo.isError,
+ 'Button should have error class when runtime errors exist');
+
+ // 3. Has install warnings: button should show "Errors" label.
+ data = createExtensionInfo(item.data);
+ data.runtimeErrors = [];
+ data.installWarnings = ['Some install warning'];
+ item.data = data;
+ await microtasksFinished();
+ buttonInfo = getErrorsButtonInfo(item);
+ assertTrue(buttonInfo.exists, 'Errors button should exist');
+ assertTrue(
+ buttonInfo.isError,
+ 'Button should have error class when install warnings exist');
+
+ // 4. Has both runtime errors and install warnings: button should show
+ // "Errors" label.
+ data = createExtensionInfo(item.data);
+ data.runtimeErrors = [createRuntimeError(data.id, {id: 2})];
+ data.installWarnings = ['Some install warning'];
+ item.data = data;
+ await microtasksFinished();
+ buttonInfo = getErrorsButtonInfo(item);
+ assertTrue(buttonInfo.exists, 'Errors button should exist');
+ assertTrue(
+ buttonInfo.isError,
+ 'Button should have error class when both errors and warnings exist');
+ });
});