chrome-devtools-frontend 1.0.1672557 → 1.0.1675430
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/devtools-ux-writing-refactor/SKILL.md +26 -9
- package/front_end/core/common/ParsedURL.ts +5 -1
- package/front_end/core/common/SettingRegistration.ts +30 -34
- package/front_end/core/common/Settings.ts +4 -64
- package/front_end/core/host/UserMetrics.ts +127 -117
- package/front_end/core/protocol_client/PuppeteerDevToolsConnection.ts +42 -9
- package/front_end/core/root/Runtime.ts +14 -0
- package/front_end/core/sdk/NetworkManager.ts +0 -35
- package/front_end/core/sdk/SourceMap.ts +1 -19
- package/front_end/core/sdk/SourceMapManager.ts +75 -48
- package/front_end/core/sdk/SourceMapScopesInfo.ts +0 -62
- package/front_end/core/sdk/TargetManager.ts +18 -0
- package/front_end/devtools_compatibility.js +1 -1
- package/front_end/entrypoints/main/MainImpl.ts +1 -0
- package/front_end/foundation/Universe.ts +44 -29
- package/front_end/generated/InspectorBackendCommands.ts +4 -3
- package/front_end/generated/SupportedCSSProperties.ts +16 -1
- package/front_end/generated/protocol-mapping.d.ts +8 -0
- package/front_end/generated/protocol-proxy-api.d.ts +6 -0
- package/front_end/generated/protocol.ts +16 -2
- package/front_end/models/ai_assistance/AiSetting.ts +66 -3
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +15 -5
- package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
- package/front_end/models/emulation/DeviceModeModel.ts +82 -102
- package/front_end/models/emulation/EmulatedDevices.ts +18 -66
- package/front_end/models/javascript_metadata/NativeFunctions.js +4 -4
- package/front_end/models/persistence/AutomaticFileSystemManager.ts +2 -2
- package/front_end/models/persistence/IsolatedFileSystemManager.ts +20 -29
- package/front_end/models/trace/ModelImpl.ts +5 -0
- package/front_end/models/trace/Processor.ts +5 -0
- package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +7 -1
- package/front_end/models/trace/handlers/MetaHandler.ts +8 -4
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +11 -0
- package/front_end/models/workspace/FileManager.ts +13 -6
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -10
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +3 -45
- package/front_end/panels/application/BackgroundServiceView.ts +42 -40
- package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
- package/front_end/panels/application/WebMCPView.ts +13 -5
- package/front_end/panels/application/components/AdsView.ts +24 -1
- package/front_end/panels/application/components/adsView.css +27 -21
- package/front_end/panels/autofill/AutofillView.ts +12 -12
- package/front_end/panels/autofill/autofill-meta.ts +2 -2
- package/front_end/panels/common/ExtensionServer.ts +7 -1
- package/front_end/panels/common/common.ts +0 -1
- package/front_end/panels/console/ConsoleInsightTeaser.ts +7 -6
- package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
- package/front_end/panels/elements/ClassesPaneWidget.ts +2 -2
- package/front_end/panels/elements/ElementsTreeElement.ts +602 -327
- package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
- package/front_end/panels/elements/components/AdornerManager.ts +1 -0
- package/front_end/panels/emulation/AdvancedApp.ts +3 -3
- package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -11
- package/front_end/panels/emulation/DeviceModeView.ts +234 -75
- package/front_end/panels/emulation/InspectedPagePlaceholder.ts +1 -1
- package/front_end/panels/emulation/deviceModeView.css +4 -21
- package/front_end/panels/emulation/emulation-meta.ts +4 -30
- package/front_end/panels/emulation/emulation.ts +0 -3
- package/front_end/panels/explain/components/ConsoleInsight.ts +11 -7
- package/front_end/panels/js_timeline/js_timeline-meta.ts +8 -8
- package/front_end/panels/layer_viewer/LayerDetailsView.ts +30 -30
- package/front_end/panels/layer_viewer/LayerTreeOutline.ts +6 -6
- package/front_end/panels/layer_viewer/LayerViewHost.ts +1 -1
- package/front_end/panels/layer_viewer/Layers3DView.ts +11 -11
- package/front_end/panels/layer_viewer/PaintProfilerView.ts +8 -8
- package/front_end/panels/layer_viewer/TransformController.ts +3 -3
- package/front_end/panels/layer_viewer/layer_viewer-meta.ts +11 -11
- package/front_end/panels/layers/LayersPanel.ts +2 -2
- package/front_end/panels/layers/layers-meta.ts +2 -2
- package/front_end/panels/lighthouse/LighthouseController.ts +3 -7
- package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +313 -0
- package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +0 -10
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +21 -10
- package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -58
- package/front_end/panels/mobile_throttling/mobile_throttling.ts +2 -9
- package/front_end/panels/network/NetworkConfigView.ts +1 -71
- package/front_end/panels/network/networkConfigView.css +1 -2
- package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +3 -3
- package/front_end/panels/profiler/HeapDetachedElementsView.ts +5 -5
- package/front_end/panels/profiler/HeapProfileView.ts +32 -32
- package/front_end/panels/profiler/HeapProfilerPanel.ts +2 -2
- package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +33 -37
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +26 -27
- package/front_end/panels/profiler/HeapSnapshotView.ts +48 -48
- package/front_end/panels/profiler/IsolateSelector.ts +10 -10
- package/front_end/panels/profiler/ModuleUIStrings.ts +25 -25
- package/front_end/panels/profiler/ProfileLauncherView.ts +6 -6
- package/front_end/panels/profiler/ProfilesPanel.ts +6 -6
- package/front_end/panels/profiler/WritableProfileHeader.ts +6 -6
- package/front_end/panels/profiler/profiler-meta.ts +7 -7
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +7 -0
- package/front_end/panels/recorder/RecorderPanel.ts +1 -1
- package/front_end/panels/settings/AISettingsTab.ts +27 -23
- package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -2
- package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +12 -17
- package/front_end/panels/timeline/TimelinePanel.ts +20 -35
- package/front_end/panels/timeline/components/LiveMetricsView.ts +27 -6
- package/front_end/panels/timeline/components/NetworkTrackWidget.ts +1 -1
- package/front_end/panels/timeline/components/components.ts +0 -4
- package/front_end/panels/timeline/components/liveMetricsView.css +7 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/LICENSE +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/README.md +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/deno.json +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +2 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +2 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/mod.js +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/mod.js.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/scopes.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/util.js +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/util.js.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/util.ts +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +0 -0
- package/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +0 -0
- package/front_end/ui/comments/CommentAnchorResolver.ts +132 -0
- package/front_end/ui/comments/comments.ts +9 -0
- package/front_end/ui/components/dialogs/ShortcutDialog.ts +2 -0
- package/front_end/ui/components/settings/SettingCheckbox.ts +4 -12
- package/front_end/ui/components/settings/settingCheckbox.css +0 -7
- package/front_end/ui/legacy/Treeoutline.ts +14 -14
- package/front_end/ui/legacy/UIUtils.ts +2 -47
- package/front_end/ui/legacy/Widget.ts +10 -2
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +40 -0
- package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
- package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -0
- package/front_end/ui/lit/Directives.ts +80 -0
- package/front_end/ui/lit/lit.ts +1 -0
- package/front_end/ui/lit/render.ts +8 -0
- package/front_end/ui/settings/SettingUIRegistration.ts +4 -0
- package/front_end/ui/visual_logging/Debugging.ts +1 -5
- package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
- package/front_end/ui/visual_logging/LoggingConfig.ts +21 -0
- package/front_end/ui/visual_logging/visual_logging.ts +9 -0
- package/mcp/mcp.ts +1 -0
- package/package.json +1 -1
- package/front_end/panels/common/ThrottlingUtils.ts +0 -51
- package/front_end/panels/emulation/DeviceModeWrapper.ts +0 -248
- package/front_end/panels/mobile_throttling/MobileThrottlingSelector.ts +0 -92
- package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +0 -235
- package/front_end/panels/timeline/components/NetworkThrottlingSelector.ts +0 -245
- package/front_end/panels/timeline/components/cpuThrottlingSelector.css +0 -30
- package/front_end/panels/timeline/components/networkThrottlingSelector.css +0 -24
|
@@ -59,14 +59,16 @@ Locate all TypeScript files in the target folder that define `const UIStrings =
|
|
|
59
59
|
* For panel names that consist of two words, capitalize only the first word (for example, `Developer resources panel`).
|
|
60
60
|
* When you use the panel name in combination with another word, capitalize the panel name but not the other word, unless it is a proper noun (for example, `Console view` or `DevTools Console`).
|
|
61
61
|
* In some cases, ambiguity exists whether a word refers to a UX element in DevTools (such as a panel name) or a concept (such as developer terminology). For example, this occurs with `console`, `issue`, or `network`. Decide based on the surrounding context and code (for example, `Console view`, `Console sidebar`, and `Console prompt` versus `console message`, `console warning`, `console log`, `copy console`, `clear console`, and `console history`; `Show Network` versus `network log` and `network filter`).
|
|
62
|
+
* **Casing in `@description` comments:** Apply the same capitalization rules to `@description` comments: ONLY panel names use sentence case (for example, `Memory panel`, `Console panel`, `Performance panel`). Feature names, view names, tool names, and sub-components MUST be all lowercase unless they appear at the very start of the description sentence or phrase (for example, `heap profiler`, `heap snapshot view`, `isolate selector`, `allocation sampling`, `command menu`, `summary view`).
|
|
62
63
|
6. **Punctuation and actionability:** Remove trailing periods from single-sentence labels or titles. Ensure that error messages instruct the user how to recover (for example, `Shorten filename to 64 characters or less` instead of `Invalid filename`). Ensure that ARIA labels and multi-sentence tooltips have consistent terminal punctuation.
|
|
63
64
|
7. **Terminology (glossary):** Strictly follow standard DevTools UI terminology and letter casing (`panel`, `tab`, `drawer`, `sidebar`, `datagrid` or `table`, `action bar`, `status bar`, and `live expressions section`). Never use `pane` or call tabs `panes` in UI strings or localization (L10n) comments.
|
|
64
65
|
8. **Localization (L10n) comments:** Ensure that every string in `UIStrings` has a preceding `@description` comment that explains where and when it appears. This information is used for translators who need to understand the context in which the string is used.
|
|
66
|
+
* **Research usage sites:** Before modifying or writing `@description` comments, always research where the string key (for example, `UIStrings.keyName`) is used in the codebase (`grep_search` or view surrounding code). Determine the exact UI element type (for example, button label, tooltip, table column header, context menu item, checkbox label, aria label, status bar message, or dropdown option) and location (panel, view, sidebar, or dialog).
|
|
67
|
+
* **Avoid redundancy and repetition:** Do not simply repeat or restate the UI string value in the description (for example, avoid `@description Text for clear all profiles` for `'Clear all profiles'`). Instead, describe the UI role, element type, and location (for example, `@description Tooltip text for the clear button in the profiles sidebar of the Memory panel.`).
|
|
68
|
+
* **Consistency across similar descriptions:** Ensure consistent phrasing structure across descriptions of similar UI strings in the same module and throughout DevTools (for example, use uniform patterns like `Tooltip text for the <action> button in <location>.` or `Column header in <table_name> datagrid for <purpose>.`).
|
|
69
|
+
* **Casing in descriptions:** Strictly follow the rule that ONLY panel names use sentence case (for example, `Memory panel`, `Console panel`, `Profiles panel`), while feature names, views, tools, and sub-components are ALL LOWERCASE (for example, `heap profiler`, `heap snapshot view`, `isolate selector`, `allocation sampling`, `summary view`), unless appearing at the start of the description sentence or phrase.
|
|
65
70
|
* **Straight apostrophes in comments:** Always use straight apostrophes (`'`) in code comments (such as `@description` comments and L10n annotations), even if the UI string itself uses curly apostrophes (`’`).
|
|
66
|
-
*
|
|
67
|
-
ambiguous, figure out the context by looking at the use site of the
|
|
68
|
-
string and come up with a better description.
|
|
69
|
-
* You must explicitly document all standard placeholders (`{PH1}`, `{url}`, `{index}`) with runtime data examples (for example, `@example {https://example.com} url`).
|
|
71
|
+
* **Placeholders:** You must explicitly document all standard placeholders (`{PH1}`, `{url}`, `{index}`) with runtime data examples (for example, `@example {https://example.com} url`).
|
|
70
72
|
* *ICU plural variables:* The i18n tool automatically parses variables in ICU plural format (such as `n` in `{n, plural, =0 {No issues} ...}`) as numeric counts, so they don’t require an `@example` tag in the `@description` comment.
|
|
71
73
|
* *Terminal punctuation:* Every `@description` comment must end with a period (`.`), even if it is a single phrase or sentence.
|
|
72
74
|
|
|
@@ -74,11 +76,26 @@ Locate all TypeScript files in the target folder that define `const UIStrings =
|
|
|
74
76
|
|
|
75
77
|
Also consult the style guides at `google3/experimental/users/rachelandrew/tools/chrome_writing/knowledge/style/` for applicable guidelines.
|
|
76
78
|
|
|
77
|
-
## 5.
|
|
79
|
+
## 5. Subagent critique of proposed changes
|
|
80
|
+
|
|
81
|
+
Before running tests or pausing for user review, enter an iterative critique loop with a subagent:
|
|
82
|
+
1. **Invoke subagent:** Use `invoke_subagent` with `TypeName: "self"` and `Role: "UX Writing Reviewer"`.
|
|
83
|
+
2. **Prompt instructions:** Provide the subagent with the `git diff` of your changes and instruct it to critique the refactoring against the **8-point UX writing checklist**:
|
|
84
|
+
- Are `@description` comments specific, informative, and non-redundant (not restating string values)?
|
|
85
|
+
- Are usage sites researched so the UI element type and location are accurately described?
|
|
86
|
+
- Do `@description` comments and string values strictly follow the casing rule (ONLY panel names in sentence case, feature/view names in all lowercase unless starting a phrase)?
|
|
87
|
+
- Are contractions, curly apostrophes, ellipses, and placeholders (`{PH1}`) correctly formatted?
|
|
88
|
+
- Were all references in sibling code/tests properly updated?
|
|
89
|
+
3. **Address feedback and loop:**
|
|
90
|
+
- If the subagent raises any feedback, concerns, or suggested fixes, apply the necessary code changes.
|
|
91
|
+
- Re-invoke the subagent with the updated `git diff` to re-critique the changes.
|
|
92
|
+
- **Repeat this loop continuously as long as the subagent has feedback, until the subagent explicitly approves the diff with no remaining issues.**
|
|
93
|
+
|
|
94
|
+
## 6. Pause for confirmation
|
|
78
95
|
|
|
79
96
|
Ask the user for a preliminary review of the proposed changes before proceeding. If the user has feedback, address feedback and pause again for confirmation.
|
|
80
97
|
|
|
81
|
-
##
|
|
98
|
+
## 7. Mandatory verification and testing
|
|
82
99
|
|
|
83
100
|
Don’t finish an edit without running the linter and test suite. In DevTools, i18n placeholder changes or string edits can easily break tests or linter rules.
|
|
84
101
|
|
|
@@ -89,18 +106,18 @@ Don’t finish an edit without running the linter and test suite. In DevTools, i
|
|
|
89
106
|
npm run lint -- <folder_path>
|
|
90
107
|
```
|
|
91
108
|
3. **Run unit tests**
|
|
92
|
-
|
|
109
|
+
You MUST run the full test suite using `npm run test` to verify that no cross-module regressions, e2e test failures, or snapshot regressions occurred. Do not only run a subset of tests:
|
|
93
110
|
```bash
|
|
94
|
-
npm run test -- <folder_path>
|
|
95
111
|
npm run test
|
|
96
112
|
```
|
|
113
|
+
*(Optionally, you may run `npm run test -- <folder_path>` first for rapid initial feedback during iterative development, but running `npm run test` for full test suite coverage is required before completing the task.)*
|
|
97
114
|
4. **Run presubmit checks**
|
|
98
115
|
Ensure that you commit or stage all changes before you run presubmit checks:
|
|
99
116
|
```bash
|
|
100
117
|
git cl presubmit -u
|
|
101
118
|
```
|
|
102
119
|
|
|
103
|
-
##
|
|
120
|
+
## 8. Summarize changes and upload the CL
|
|
104
121
|
|
|
105
122
|
When all tests and presubmit checks pass, commit your changes and upload the CL to Gerrit. Don’t use `[uxw]` as a prefix.
|
|
106
123
|
|
|
@@ -533,7 +533,11 @@ export class ParsedURL {
|
|
|
533
533
|
return 'data:' as Platform.DevToolsPath.UrlString;
|
|
534
534
|
}
|
|
535
535
|
const scheme = this.isBlobURL() ? this.blobInnerScheme : this.scheme;
|
|
536
|
-
|
|
536
|
+
const domain = this.domain();
|
|
537
|
+
if (!scheme && !domain) {
|
|
538
|
+
return '' as Platform.DevToolsPath.UrlString;
|
|
539
|
+
}
|
|
540
|
+
return scheme + '://' + domain as Platform.DevToolsPath.UrlString;
|
|
537
541
|
}
|
|
538
542
|
|
|
539
543
|
urlWithoutScheme(): string {
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import * as i18n from '../i18n/i18n.js';
|
|
6
6
|
import type * as Platform from '../platform/platform.js';
|
|
7
|
-
import * as Root from '../root/root.js';
|
|
8
7
|
|
|
9
8
|
import type {SettingStorageType} from './Settings.js';
|
|
10
9
|
|
|
@@ -78,44 +77,60 @@ const UIStrings = {
|
|
|
78
77
|
* section allows users to see their signed-in account and configure which DevTools data is synced via Chrome Sync.
|
|
79
78
|
*/
|
|
80
79
|
account: 'Account',
|
|
81
|
-
/**
|
|
82
|
-
* @description Title of the Privacy setting category.
|
|
83
|
-
*/
|
|
84
|
-
privacy: 'Privacy',
|
|
85
80
|
} as const;
|
|
86
81
|
const str_ = i18n.i18n.registerUIStrings('core/common/SettingRegistration.ts', UIStrings);
|
|
87
82
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
88
83
|
let registeredSettings: SettingRegistration[] = [];
|
|
89
84
|
const settingNameSet = new Set<string>();
|
|
85
|
+
const orderValuesBySettingCategory = new Map<SettingCategory, Set<number>>();
|
|
86
|
+
|
|
87
|
+
export function registerCategoryOrder(category?: SettingCategory, order?: number): void {
|
|
88
|
+
if (category && typeof order === 'number') {
|
|
89
|
+
let orderValues = orderValuesBySettingCategory.get(category);
|
|
90
|
+
if (!orderValues) {
|
|
91
|
+
orderValues = new Set();
|
|
92
|
+
orderValuesBySettingCategory.set(category, orderValues);
|
|
93
|
+
}
|
|
94
|
+
if (orderValues.has(order)) {
|
|
95
|
+
throw new Error(`Duplicate order value '${order}' for settings category '${category}'`);
|
|
96
|
+
}
|
|
97
|
+
orderValues.add(order);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function removeCategoryOrder(category?: SettingCategory, order?: number): void {
|
|
102
|
+
if (category && typeof order === 'number') {
|
|
103
|
+
orderValuesBySettingCategory.get(category)?.delete(order);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
90
106
|
|
|
91
107
|
export function registerSettingExtension(registration: SettingRegistration): void {
|
|
92
108
|
const settingName = registration.settingName;
|
|
93
109
|
if (settingNameSet.has(settingName)) {
|
|
94
110
|
throw new Error(`Duplicate setting name '${settingName}'`);
|
|
95
111
|
}
|
|
112
|
+
registerCategoryOrder(registration.category, registration.order);
|
|
96
113
|
settingNameSet.add(settingName);
|
|
97
114
|
registeredSettings.push(registration);
|
|
98
115
|
}
|
|
99
116
|
|
|
100
117
|
export function getRegisteredSettings(): SettingRegistration[] {
|
|
101
|
-
return registeredSettings
|
|
118
|
+
return registeredSettings;
|
|
102
119
|
}
|
|
103
120
|
|
|
104
121
|
export function registerSettingsForTest(settings: SettingRegistration[], forceReset = false): void {
|
|
105
122
|
if (registeredSettings.length === 0 || forceReset) {
|
|
106
|
-
|
|
107
|
-
settingNameSet.clear();
|
|
123
|
+
resetSettings();
|
|
108
124
|
for (const setting of settings) {
|
|
109
|
-
|
|
110
|
-
if (settingNameSet.has(settingName)) {
|
|
111
|
-
throw new Error(`Duplicate setting name '${settingName}'`);
|
|
112
|
-
}
|
|
113
|
-
settingNameSet.add(settingName);
|
|
125
|
+
registerSettingExtension(setting);
|
|
114
126
|
}
|
|
115
127
|
}
|
|
116
128
|
}
|
|
117
129
|
|
|
118
130
|
export function resetSettings(): void {
|
|
131
|
+
for (const setting of registeredSettings) {
|
|
132
|
+
removeCategoryOrder(setting.category, setting.order);
|
|
133
|
+
}
|
|
119
134
|
registeredSettings = [];
|
|
120
135
|
settingNameSet.clear();
|
|
121
136
|
}
|
|
@@ -125,7 +140,8 @@ export function maybeRemoveSettingExtension(settingName: string): boolean {
|
|
|
125
140
|
if (settingIndex < 0 || !settingNameSet.delete(settingName)) {
|
|
126
141
|
return false;
|
|
127
142
|
}
|
|
128
|
-
registeredSettings.splice(settingIndex, 1);
|
|
143
|
+
const [removed] = registeredSettings.splice(settingIndex, 1);
|
|
144
|
+
removeCategoryOrder(removed.category, removed.order);
|
|
129
145
|
return true;
|
|
130
146
|
}
|
|
131
147
|
|
|
@@ -149,7 +165,6 @@ export const enum SettingCategory {
|
|
|
149
165
|
EXTENSIONS = 'EXTENSIONS',
|
|
150
166
|
ADORNER = 'ADORNER',
|
|
151
167
|
ACCOUNT = 'ACCOUNT',
|
|
152
|
-
PRIVACY = 'PRIVACY',
|
|
153
168
|
}
|
|
154
169
|
|
|
155
170
|
export function getLocalizedSettingsCategory(category: SettingCategory): Platform.UIString.LocalizedString {
|
|
@@ -192,8 +207,6 @@ export function getLocalizedSettingsCategory(category: SettingCategory): Platfor
|
|
|
192
207
|
return i18n.i18n.lockedString('');
|
|
193
208
|
case SettingCategory.ACCOUNT:
|
|
194
209
|
return i18nString(UIStrings.account);
|
|
195
|
-
case SettingCategory.PRIVACY:
|
|
196
|
-
return i18nString(UIStrings.privacy);
|
|
197
210
|
}
|
|
198
211
|
}
|
|
199
212
|
|
|
@@ -268,19 +281,6 @@ export interface SettingRegistration {
|
|
|
268
281
|
* Determines if the setting value is stored in the global, local or session storage.
|
|
269
282
|
*/
|
|
270
283
|
storageType?: SettingStorageType;
|
|
271
|
-
/**
|
|
272
|
-
* A condition is a function that will make the setting available if it
|
|
273
|
-
* returns true, and not available, otherwise. Make sure that objects you
|
|
274
|
-
* access from inside the condition function are ready at the time when the
|
|
275
|
-
* setting conditions are checked.
|
|
276
|
-
*/
|
|
277
|
-
condition?: Root.Runtime.Condition;
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* A function that returns true if the setting should be disabled, along with
|
|
281
|
-
* the reason why.
|
|
282
|
-
*/
|
|
283
|
-
disabledCondition?: (config?: Root.Runtime.HostConfig) => DisabledConditionResult;
|
|
284
284
|
|
|
285
285
|
/**
|
|
286
286
|
* See {@link LearnMore} for more info.
|
|
@@ -319,7 +319,3 @@ interface RawSettingExtensionOption {
|
|
|
319
319
|
raw: true;
|
|
320
320
|
}
|
|
321
321
|
export type SettingExtensionOption = LocalizedSettingExtensionOption|RawSettingExtensionOption;
|
|
322
|
-
export type DisabledConditionResult = {
|
|
323
|
-
disabled: true,
|
|
324
|
-
reasons: Platform.UIString.LocalizedString[],
|
|
325
|
-
}|{disabled: false};
|
|
@@ -112,7 +112,6 @@ export class Settings {
|
|
|
112
112
|
readonly #settingRegistrations: SettingRegistration[];
|
|
113
113
|
readonly #sessionStorage = new SettingsStorage({});
|
|
114
114
|
settingNameSet = new Set<string>();
|
|
115
|
-
orderValuesBySettingCategory = new Map<SettingCategory, Set<number>>();
|
|
116
115
|
#eventSupport = new ObjectWrapper<GenericEvents>();
|
|
117
116
|
#registry = new Map<string, Setting<unknown>>();
|
|
118
117
|
readonly moduleSettings = new Map<string, Setting<unknown>>();
|
|
@@ -215,19 +214,9 @@ export class Settings {
|
|
|
215
214
|
|
|
216
215
|
private registerModuleSetting(setting: Setting<unknown>): void {
|
|
217
216
|
const settingName = setting.name;
|
|
218
|
-
const category = setting.category();
|
|
219
|
-
const order = setting.order();
|
|
220
217
|
if (this.settingNameSet.has(settingName)) {
|
|
221
218
|
throw new Error(`Duplicate Setting name '${settingName}'`);
|
|
222
219
|
}
|
|
223
|
-
if (category && order) {
|
|
224
|
-
const orderValues = this.orderValuesBySettingCategory.get(category) || new Set();
|
|
225
|
-
if (orderValues.has(order)) {
|
|
226
|
-
throw new Error(`Duplicate order value '${order}' for settings category '${category}'`);
|
|
227
|
-
}
|
|
228
|
-
orderValues.add(order);
|
|
229
|
-
this.orderValuesBySettingCategory.set(category, orderValues);
|
|
230
|
-
}
|
|
231
220
|
this.settingNameSet.add(settingName);
|
|
232
221
|
this.moduleSettings.set(setting.name, setting);
|
|
233
222
|
}
|
|
@@ -499,10 +488,7 @@ export class Setting<V> {
|
|
|
499
488
|
#type: SettingType|null = null;
|
|
500
489
|
#requiresUserAction?: boolean;
|
|
501
490
|
#value?: V;
|
|
502
|
-
// TODO(crbug.com/1172300) Type cannot be inferred without changes to consumers. See above.
|
|
503
|
-
#serializer: Serializer<unknown, V> = JSON;
|
|
504
491
|
#hadUserAction?: boolean;
|
|
505
|
-
#disabled?: boolean;
|
|
506
492
|
#loggedInitialAccess = false;
|
|
507
493
|
#logSettingAccess?: (name: string, value: number|string|boolean) => Promise<void>;
|
|
508
494
|
readonly #console: Console;
|
|
@@ -515,10 +501,6 @@ export class Setting<V> {
|
|
|
515
501
|
this.#logSettingAccess = logSettingAccess;
|
|
516
502
|
}
|
|
517
503
|
|
|
518
|
-
setSerializer(serializer: Serializer<unknown, V>): void {
|
|
519
|
-
this.#serializer = serializer;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
504
|
descriptor(): SettingDescriptor<V> {
|
|
523
505
|
return {
|
|
524
506
|
name: this.name,
|
|
@@ -547,38 +529,11 @@ export class Setting<V> {
|
|
|
547
529
|
this.#requiresUserAction = requiresUserAction;
|
|
548
530
|
}
|
|
549
531
|
|
|
550
|
-
disabled(): boolean {
|
|
551
|
-
if (this.#registration?.disabledCondition) {
|
|
552
|
-
const {disabled} = this.#registration.disabledCondition(Root.Runtime.hostConfig);
|
|
553
|
-
// If registration does not disable it, pass through to #disabled
|
|
554
|
-
// attribute check.
|
|
555
|
-
if (disabled) {
|
|
556
|
-
return true;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
return this.#disabled || false;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
disabledReasons(): Platform.UIString.LocalizedString[] {
|
|
563
|
-
if (this.#registration?.disabledCondition) {
|
|
564
|
-
const result = this.#registration.disabledCondition(Root.Runtime.hostConfig);
|
|
565
|
-
if (result.disabled) {
|
|
566
|
-
return result.reasons;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
return [];
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
setDisabled(disabled: boolean): void {
|
|
573
|
-
this.#disabled = disabled;
|
|
574
|
-
this.eventSupport.dispatchEventToListeners(this.name);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
532
|
#maybeLogAccess(value: V): void {
|
|
578
533
|
try {
|
|
579
534
|
const valueToLog = typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ?
|
|
580
535
|
value :
|
|
581
|
-
|
|
536
|
+
JSON.stringify(value);
|
|
582
537
|
if (valueToLog !== undefined && this.#logSettingAccess) {
|
|
583
538
|
void this.#logSettingAccess(this.name, valueToLog);
|
|
584
539
|
}
|
|
@@ -607,7 +562,7 @@ export class Setting<V> {
|
|
|
607
562
|
this.#value = this.defaultValue;
|
|
608
563
|
if (this.storage.has(this.name)) {
|
|
609
564
|
try {
|
|
610
|
-
this.#value =
|
|
565
|
+
this.#value = JSON.parse(this.storage.get(this.name)) as V;
|
|
611
566
|
} catch {
|
|
612
567
|
this.storage.remove(this.name);
|
|
613
568
|
}
|
|
@@ -616,16 +571,6 @@ export class Setting<V> {
|
|
|
616
571
|
return this.#value;
|
|
617
572
|
}
|
|
618
573
|
|
|
619
|
-
// Prefer this getter for settings which are "disableable". The plain getter returns `this.#value`,
|
|
620
|
-
// even if the setting is disabled, which means the callsite has to explicitly call the `disabled()`
|
|
621
|
-
// getter and add its own logic for the disabled state.
|
|
622
|
-
getIfNotDisabled(): V|undefined {
|
|
623
|
-
if (this.disabled()) {
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
return this.get();
|
|
627
|
-
}
|
|
628
|
-
|
|
629
574
|
async forceGet(): Promise<V> {
|
|
630
575
|
const name = this.name;
|
|
631
576
|
const oldValue = this.storage.get(name);
|
|
@@ -633,7 +578,7 @@ export class Setting<V> {
|
|
|
633
578
|
this.#value = this.defaultValue;
|
|
634
579
|
if (value) {
|
|
635
580
|
try {
|
|
636
|
-
this.#value =
|
|
581
|
+
this.#value = JSON.parse(value) as V;
|
|
637
582
|
} catch {
|
|
638
583
|
this.storage.remove(this.name);
|
|
639
584
|
}
|
|
@@ -652,7 +597,7 @@ export class Setting<V> {
|
|
|
652
597
|
this.#hadUserAction = true;
|
|
653
598
|
this.#value = value;
|
|
654
599
|
try {
|
|
655
|
-
const settingString =
|
|
600
|
+
const settingString = JSON.stringify(value);
|
|
656
601
|
try {
|
|
657
602
|
this.storage.set(this.name, settingString);
|
|
658
603
|
} catch (e) {
|
|
@@ -822,11 +767,6 @@ export {
|
|
|
822
767
|
SettingType,
|
|
823
768
|
};
|
|
824
769
|
|
|
825
|
-
export interface Serializer<I, O> {
|
|
826
|
-
stringify: (value: I) => string;
|
|
827
|
-
parse: (value: string) => O;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
770
|
export interface SimpleSettingOption {
|
|
831
771
|
value: string|boolean;
|
|
832
772
|
title: string;
|