chrome-devtools-frontend 1.0.1668390 → 1.0.1669021

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.
Files changed (192) hide show
  1. package/.agents/skills/devtools-ci/SKILL.md +65 -0
  2. package/.agents/skills/gerrit-cli/SKILL.md +59 -0
  3. package/.agents/skills/gerrit-cli/references/commands.md +93 -0
  4. package/.agents/skills/gerrit-cli/references/workflows.md +56 -0
  5. package/.agents/skills/gerrit-cli/scripts/gerrit_client_wrapper.py +47 -0
  6. package/.agents/skills/gerrit-cli/scripts/import_upstream.py +230 -0
  7. package/docs/contributing/infrastructure.md +7 -1
  8. package/front_end/core/host/AidaClient.ts +66 -47
  9. package/front_end/core/host/GcaClient.ts +4 -6
  10. package/front_end/core/host/ResourceLoader.ts +4 -2
  11. package/front_end/core/root/Runtime.ts +0 -5
  12. package/front_end/core/sdk/ConsoleModel.ts +3 -2
  13. package/front_end/core/sdk/DebuggerModel.ts +14 -6
  14. package/front_end/core/sdk/SDKSettings.ts +19 -0
  15. package/front_end/core/sdk/sdk-meta.ts +0 -58
  16. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  17. package/front_end/generated/protocol.ts +11 -3
  18. package/front_end/models/ai_assistance/AiUtils.ts +67 -4
  19. package/front_end/models/ai_assistance/StorageItem.ts +26 -5
  20. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +2 -19
  21. package/front_end/models/ai_code_generation/AiCodeGeneration.ts +2 -3
  22. package/front_end/models/trace/handlers/RendererHandler.ts +20 -4
  23. package/front_end/models/trace/types/File.ts +1 -0
  24. package/front_end/models/workspace/UISourceCode.ts +0 -10
  25. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +61 -182
  26. package/front_end/panels/ai_assistance/components/ChatInput.ts +25 -8
  27. package/front_end/panels/ai_assistance/components/ChatMessage.ts +13 -69
  28. package/front_end/panels/ai_assistance/components/ChatView.ts +14 -8
  29. package/front_end/panels/ai_assistance/components/chatMessage.css +2 -20
  30. package/front_end/panels/application/ApplicationPanelSidebar.ts +2 -2
  31. package/front_end/panels/application/ApplicationPanelTreeElement.ts +41 -3
  32. package/front_end/panels/application/ServiceWorkerUpdateCycleView.ts +116 -79
  33. package/front_end/panels/application/ServiceWorkersView.ts +8 -8
  34. package/front_end/panels/application/application.ts +2 -0
  35. package/front_end/panels/application/components/AdsView.ts +10 -6
  36. package/front_end/panels/application/preloading/PreloadingView.ts +53 -45
  37. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +111 -119
  38. package/front_end/panels/application/preloading/components/preloadingDetailsReportView.css +21 -23
  39. package/front_end/panels/application/serviceWorkerUpdateCycleView.css +105 -102
  40. package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +107 -96
  41. package/front_end/panels/common/AiCodeCompletionSummaryToolbar.ts +17 -19
  42. package/front_end/panels/common/AiCodeCompletionTeaser.ts +6 -6
  43. package/front_end/panels/common/AiCodeGenerationTeaser.ts +28 -26
  44. package/front_end/panels/common/common.ts +1 -1
  45. package/front_end/panels/console/ConsoleInsightTeaser.ts +3 -6
  46. package/front_end/panels/console/ConsoleView.ts +6 -4
  47. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  48. package/front_end/panels/console/console-meta.ts +28 -0
  49. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +1 -1
  50. package/front_end/panels/elements/StylesSidebarPane.ts +3 -2
  51. package/front_end/panels/emulation/DeviceModeWrapper.ts +18 -4
  52. package/front_end/panels/explain/components/ConsoleInsight.ts +4 -6
  53. package/front_end/panels/explain/explain-meta.ts +7 -49
  54. package/front_end/panels/network/NetworkDataGridNode.ts +1 -1
  55. package/front_end/panels/network/NetworkLogView.ts +1 -0
  56. package/front_end/panels/network/OriginalResourceChunkView.ts +340 -0
  57. package/front_end/panels/network/ResourceChunkView.ts +72 -46
  58. package/front_end/panels/network/ResourceDirectSocketChunkView.ts +3 -2
  59. package/front_end/panels/network/ResourceWebSocketFrameView.ts +3 -3
  60. package/front_end/panels/network/originalResourceChunkView.css +49 -0
  61. package/front_end/panels/screencast/ScreencastView.ts +401 -260
  62. package/front_end/panels/screencast/screencastView.css +113 -100
  63. package/front_end/panels/sensors/LocationsSettingsTab.ts +106 -122
  64. package/front_end/panels/sensors/locationsSettingsTab.css +4 -4
  65. package/front_end/panels/settings/AISettingsTab.ts +17 -100
  66. package/front_end/panels/snippets/ScriptSnippetFileSystem.ts +2 -2
  67. package/front_end/panels/snippets/SnippetsQuickOpen.ts +4 -4
  68. package/front_end/panels/sources/AddSourceMapURLDialog.ts +3 -3
  69. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +4 -3
  70. package/front_end/panels/sources/BreakpointEditDialog.ts +14 -14
  71. package/front_end/panels/sources/BreakpointsView.ts +14 -14
  72. package/front_end/panels/sources/CallStackSidebarPane.ts +6 -6
  73. package/front_end/panels/sources/CategorizedBreakpointL10n.ts +18 -18
  74. package/front_end/panels/sources/CoveragePlugin.ts +7 -7
  75. package/front_end/panels/sources/DebuggerPausedMessage.ts +23 -23
  76. package/front_end/panels/sources/DebuggerPlugin.ts +29 -29
  77. package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +2 -2
  78. package/front_end/panels/sources/GoToLineQuickOpen.ts +10 -10
  79. package/front_end/panels/sources/NavigatorView.ts +34 -27
  80. package/front_end/panels/sources/OutlineQuickOpen.ts +3 -3
  81. package/front_end/panels/sources/PersistenceActions.ts +9 -9
  82. package/front_end/panels/sources/ProfilePlugin.ts +1 -1
  83. package/front_end/panels/sources/ScopeChainSidebarPane.ts +5 -5
  84. package/front_end/panels/sources/SnippetsPlugin.ts +2 -2
  85. package/front_end/panels/sources/SourcesNavigator.ts +20 -18
  86. package/front_end/panels/sources/SourcesPanel.ts +26 -25
  87. package/front_end/panels/sources/SourcesView.ts +5 -6
  88. package/front_end/panels/sources/TabbedEditorContainer.ts +3 -3
  89. package/front_end/panels/sources/ThreadsSidebarPane.ts +1 -1
  90. package/front_end/panels/sources/UISourceCodeFrame.ts +0 -2
  91. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +7 -7
  92. package/front_end/panels/sources/components/HeadersView.ts +2 -2
  93. package/front_end/panels/sources/sources-meta.ts +109 -71
  94. package/front_end/panels/sources/sources.ts +0 -2
  95. package/front_end/panels/timeline/TimelineHistoryManager.ts +14 -3
  96. package/front_end/panels/timeline/TimelineLoader.ts +72 -42
  97. package/front_end/panels/timeline/TimelinePanel.ts +29 -4
  98. package/front_end/panels/timeline/timelineHistoryManager.css +4 -0
  99. package/front_end/third_party/chromium/README.chromium +1 -1
  100. package/front_end/third_party/puppeteer/README.chromium +2 -2
  101. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +187 -1
  102. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +91 -38
  103. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.d.ts +145 -2
  104. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.d.ts.map +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.js +0 -2
  106. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Browser.js.map +1 -1
  107. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.d.ts +0 -2
  108. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.d.ts.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.js +0 -2
  110. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/BrowserContext.js.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Dialog.d.ts +3 -2
  112. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Dialog.d.ts.map +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Dialog.js +8 -2
  114. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Dialog.js.map +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/JSHandle.d.ts +0 -2
  116. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/JSHandle.d.ts.map +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/JSHandle.js +0 -2
  118. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/JSHandle.js.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts +1 -3
  120. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.d.ts.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js +0 -2
  122. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Page.js.map +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.d.ts +0 -1
  124. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.d.ts.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.js +0 -1
  126. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/Realm.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.d.ts.map +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.js +2 -2
  129. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/BidiOverCdp.js.map +1 -1
  130. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Browser.d.ts +5 -1
  131. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Browser.d.ts.map +1 -1
  132. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Browser.js +12 -0
  133. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/Browser.js.map +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPResponse.d.ts.map +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPResponse.js +4 -1
  136. package/front_end/third_party/puppeteer/package/lib/puppeteer/bidi/HTTPResponse.js.map +1 -1
  137. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts +5 -1
  138. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.d.ts.map +1 -1
  139. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js +49 -0
  140. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Browser.js.map +1 -1
  141. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/EventEmitter.d.ts +0 -6
  142. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/EventEmitter.d.ts.map +1 -1
  143. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/EventEmitter.js +0 -6
  144. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/EventEmitter.js.map +1 -1
  145. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts +1 -1
  146. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.d.ts.map +1 -1
  147. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js +1 -1
  148. package/front_end/third_party/puppeteer/package/lib/puppeteer/generated/injected.js.map +1 -1
  149. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/util.d.ts.map +1 -1
  150. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/util.js +3 -0
  151. package/front_end/third_party/puppeteer/package/lib/puppeteer/injected/util.js.map +1 -1
  152. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.d.ts +0 -3
  153. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.d.ts.map +1 -1
  154. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.js +0 -3
  155. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/ScreenRecorder.js.map +1 -1
  156. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  157. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  158. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/disposable.d.ts +2 -2
  159. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/disposable.js +2 -2
  160. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  161. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  162. package/front_end/third_party/puppeteer/package/lib/types.d.ts +187 -1
  163. package/front_end/third_party/puppeteer/package/package.json +5 -5
  164. package/front_end/third_party/puppeteer/package/src/api/Browser.ts +155 -2
  165. package/front_end/third_party/puppeteer/package/src/api/BrowserContext.ts +0 -2
  166. package/front_end/third_party/puppeteer/package/src/api/Dialog.ts +10 -2
  167. package/front_end/third_party/puppeteer/package/src/api/JSHandle.ts +0 -2
  168. package/front_end/third_party/puppeteer/package/src/api/Page.ts +1 -3
  169. package/front_end/third_party/puppeteer/package/src/api/Realm.ts +0 -1
  170. package/front_end/third_party/puppeteer/package/src/bidi/BidiOverCdp.ts +4 -2
  171. package/front_end/third_party/puppeteer/package/src/bidi/Browser.ts +17 -0
  172. package/front_end/third_party/puppeteer/package/src/bidi/HTTPResponse.ts +5 -4
  173. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +66 -0
  174. package/front_end/third_party/puppeteer/package/src/common/EventEmitter.ts +0 -6
  175. package/front_end/third_party/puppeteer/package/src/generated/injected.ts +1 -1
  176. package/front_end/third_party/puppeteer/package/src/injected/util.ts +4 -1
  177. package/front_end/third_party/puppeteer/package/src/node/ScreenRecorder.ts +0 -3
  178. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  179. package/front_end/third_party/puppeteer/package/src/util/disposable.ts +2 -2
  180. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  181. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +9 -7
  182. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +7 -8
  183. package/front_end/ui/legacy/Dialog.ts +12 -2
  184. package/front_end/ui/legacy/TabbedPane.ts +7 -2
  185. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +40 -24
  186. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +1 -0
  187. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +8 -4
  188. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +14 -7
  189. package/front_end/ui/legacy/components/quick_open/CommandMenu.ts +11 -1
  190. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -0
  191. package/package.json +1 -1
  192. package/front_end/panels/sources/AiWarningInfobarPlugin.ts +0 -78
@@ -4,104 +4,117 @@
4
4
  * found in the LICENSE file.
5
5
  */
6
6
 
7
- .screencast {
8
- overflow: hidden;
9
- }
10
-
11
- .screencast-navigation {
12
- flex-direction: row;
13
- display: flex;
14
- align-items: center;
15
- position: relative;
16
- padding-left: 1px;
17
- border-bottom: 1px solid var(--sys-color-divider);
18
- background-origin: padding-box;
19
- background-clip: padding-box;
20
- }
21
-
22
- .screencast-navigation button {
23
- border-width: 0;
24
- padding: 5px;
25
- width: 28px;
26
- height: 26px;
27
- background: none;
28
- }
29
-
30
- .screencast-navigation button devtools-icon {
31
- width: 100%;
32
- height: 100%;
33
- }
34
-
35
- .screencast-navigation button[disabled].navigation {
36
- opacity: 50%;
37
- }
38
-
39
- .screencast-navigation input {
40
- flex: 1;
41
- margin: 2px;
42
- max-height: 19px;
43
- }
44
-
45
- .screencast-navigation .progress {
46
- background-color: var(--sys-color-primary-bright);
47
- height: 3px;
48
- left: 0;
49
- position: absolute;
50
- top: 100%; /* Align with the bottom edge of the parent. */
51
- width: 0;
52
- z-index: 2; /* Above .screencast-glasspane. */
53
- }
54
-
55
- .screencast-viewport {
56
- display: flex;
57
- border: 1px solid var(--sys-color-divider);
58
- border-radius: 20px;
59
- flex: none;
60
- padding: 20px;
61
- margin: auto;
62
- background-color: var(--sys-color-surface-variant);
63
- }
64
-
65
- .screencast-canvas-container {
66
- flex: auto;
67
- display: flex;
68
- border: 1px solid var(--sys-color-divider);
69
- position: relative;
70
- }
71
-
72
- .screencast-canvas-container.touchable {
73
- /* stylelint-disable-next-line custom-property-pattern */
74
- cursor: image-set(var(--image-file-touchCursor) 1x, var(--image-file-touchCursor_2x) 2x), default;
75
- }
76
-
77
- .screencast canvas {
78
- flex: auto;
79
- position: relative;
80
- }
81
-
82
- .screencast-element-title {
83
- position: absolute;
84
- z-index: 10;
85
- }
86
-
87
- .screencast-tag-name {
88
- color: var(--sys-color-token-tag);
89
- }
90
-
91
- .screencast-attribute {
92
- color: var(--sys-color-token-attribute);
93
- }
94
-
95
- .screencast-dimension {
96
- /* Keep this in sync with tool_highlight.css (.dimensions) */
97
- color: var(--sys-color-outline);
98
- }
99
-
100
- .screencast-glasspane {
101
- background-color: var(--color-background-opacity-80);
102
- font-size: 30px;
103
- z-index: 100;
104
- display: flex;
105
- justify-content: center;
106
- align-items: center;
7
+ @scope to (devtools-widget > *) {
8
+ :scope {
9
+ overflow: hidden;
10
+ display: flex;
11
+ flex-direction: column;
12
+ }
13
+
14
+ .screencast-navigation {
15
+ flex-direction: row;
16
+ display: flex;
17
+ align-items: center;
18
+ position: relative;
19
+ padding-left: 1px;
20
+ border-bottom: 1px solid var(--sys-color-divider);
21
+ background-origin: padding-box;
22
+ background-clip: padding-box;
23
+ }
24
+
25
+ .screencast-navigation devtools-button {
26
+ padding: 2px;
27
+ }
28
+
29
+ .screencast-navigation input {
30
+ flex: 1;
31
+ margin: 2px;
32
+ max-height: 19px;
33
+ }
34
+
35
+ .screencast-navigation .progress {
36
+ background-color: var(--sys-color-primary-bright);
37
+ height: 3px;
38
+ left: 0;
39
+ position: absolute;
40
+ top: 100%; /* Align with the bottom edge of the parent. */
41
+ width: 0;
42
+ z-index: 2; /* Above .screencast-glasspane. */
43
+ }
44
+
45
+ .screencast-viewport {
46
+ display: flex;
47
+ border: 1px solid var(--sys-color-divider);
48
+ border-radius: 20px;
49
+ flex: none;
50
+ padding: 20px;
51
+ margin: auto;
52
+ background-color: var(--sys-color-surface-variant);
53
+ }
54
+
55
+ .screencast-canvas-container {
56
+ flex: auto;
57
+ display: flex;
58
+ border: 1px solid var(--sys-color-divider);
59
+ position: relative;
60
+ }
61
+
62
+ .screencast-canvas-container.touchable {
63
+ /* stylelint-disable-next-line custom-property-pattern */
64
+ cursor: image-set(var(--image-file-touchCursor) 1x, var(--image-file-touchCursor_2x) 2x), default;
65
+ }
66
+
67
+ canvas {
68
+ flex: auto;
69
+ position: relative;
70
+ }
71
+
72
+ .screencast-element-title {
73
+ position: absolute;
74
+ z-index: 10;
75
+ background-color: var(--sys-color-yellow-container);
76
+ border: 1px solid var(--sys-color-outline);
77
+ padding: 2px 4px;
78
+ white-space: nowrap;
79
+ }
80
+
81
+ .screencast-element-title.arrow-up::before {
82
+ content: "";
83
+ position: absolute;
84
+ bottom: 100%;
85
+ left: 14px;
86
+ border: 7px solid transparent;
87
+ border-bottom-color: var(--sys-color-yellow-container);
88
+ }
89
+
90
+ .screencast-element-title.arrow-down::after {
91
+ content: "";
92
+ position: absolute;
93
+ top: 100%;
94
+ left: 14px;
95
+ border: 7px solid transparent;
96
+ border-top-color: var(--sys-color-yellow-container);
97
+ }
98
+
99
+ .screencast-tag-name {
100
+ color: var(--sys-color-token-tag);
101
+ }
102
+
103
+ .screencast-attribute {
104
+ color: var(--sys-color-token-attribute);
105
+ }
106
+
107
+ .screencast-dimension {
108
+ /* Keep this in sync with tool_highlight.css (.dimensions) */
109
+ color: var(--sys-color-outline);
110
+ }
111
+
112
+ .screencast-glasspane {
113
+ background-color: var(--color-background-opacity-80);
114
+ font-size: 30px;
115
+ z-index: 100;
116
+ display: flex;
117
+ justify-content: center;
118
+ align-items: center;
119
+ }
107
120
  }
@@ -3,11 +3,13 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import '../../ui/kit/kit.js';
6
+ import '../../ui/components/lists/lists.js';
6
7
 
7
8
  import * as Common from '../../core/common/common.js';
8
9
  import * as i18n from '../../core/i18n/i18n.js';
9
10
  import * as SDK from '../../core/sdk/sdk.js';
10
11
  import * as Buttons from '../../ui/components/buttons/buttons.js';
12
+ import type * as Lists from '../../ui/components/lists/lists.js';
11
13
  import * as UI from '../../ui/legacy/legacy.js';
12
14
  import {Directives, html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
13
15
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
@@ -163,27 +165,21 @@ export interface EditorInputControls {
163
165
  accuracyInput: LitTemplate|Element;
164
166
  }
165
167
 
168
+ export interface LocationValidationErrors {
169
+ title?: string|null;
170
+ lat?: string|null;
171
+ long?: string|null;
172
+ timezoneId?: string|null;
173
+ locale?: string|null;
174
+ accuracy?: string|null;
175
+ }
166
176
  export interface LocationDialogInput {
167
177
  location: LocationDescription;
168
178
  isNew: boolean;
169
- errors?: {
170
- title?: string|null,
171
- lat?: string|null,
172
- long?: string|null,
173
- timezoneId?: string|null,
174
- locale?: string|null,
175
- accuracy?: string|null,
176
- };
179
+ errors?: LocationValidationErrors;
177
180
  onSave: (location: LocationDescription) => void;
178
181
  onCancel: () => void;
179
- onValidateErrors: (errors: {
180
- title?: string|null,
181
- lat?: string|null,
182
- long?: string|null,
183
- timezoneId?: string|null,
184
- locale?: string|null,
185
- accuracy?: string|null,
186
- }) => void;
182
+ onValidateErrors: (errors: LocationValidationErrors) => void;
187
183
  }
188
184
 
189
185
  export function renderEditorView(controls: EditorInputControls, errors?: LocationDialogInput['errors'],
@@ -273,7 +269,7 @@ export function renderEditorView(controls: EditorInputControls, errors?: Locatio
273
269
  // clang-format on
274
270
  }
275
271
 
276
- export function renderLocationDialog(input: LocationDialogInput, target: HTMLElement): void {
272
+ export function renderLocationDialog(input: LocationDialogInput): LitTemplate {
277
273
  const titleInputRef = createRef<HTMLInputElement>();
278
274
  const latInputRef = createRef<HTMLInputElement>();
279
275
  const longInputRef = createRef<HTMLInputElement>();
@@ -333,7 +329,7 @@ export function renderLocationDialog(input: LocationDialogInput, target: HTMLEle
333
329
  i18nString(UIStrings.locale)} .value=${input.location.locale} ${ref(localeInputRef)}>`,
334
330
  accuracyInput: html`<input id="location-accuracy" aria-label=${
335
331
  i18nString(UIStrings.accuracy)} type="text" placeholder=${i18nString(UIStrings.accuracy)} .value=${
336
- String(input.location.accuracy || SDK.EmulationModel.Location.DEFAULT_ACCURACY)} ${ref(accuracyInputRef)}>`,
332
+ String(input.location.accuracy ?? SDK.EmulationModel.Location.DEFAULT_ACCURACY)} ${ref(accuracyInputRef)}>`,
337
333
  };
338
334
 
339
335
  // clang-format off
@@ -371,24 +367,28 @@ export function renderLocationDialog(input: LocationDialogInput, target: HTMLEle
371
367
  </div>
372
368
  `;
373
369
 
374
- // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
375
- render(html`
370
+ return html`
376
371
  <style>${locationsSettingsTabStyles}</style>
377
372
  <devtools-widget
378
373
  class="location-dialog-widget"
379
374
  ${UI.Widget.widget(UI.Dialog.DialogWidget, {
380
375
  open: true,
381
376
  jslogContext: 'location-dialog',
377
+ dialogStack: true,
382
378
  content: dialogContent,
383
379
  })}
384
380
  @hidden=${input.onCancel}>
385
381
  </devtools-widget>
386
- `, target);
382
+ `;
387
383
  // clang-format on
388
384
  }
389
385
 
390
386
  interface LocationsViewInput {
387
+ locations: LocationDescription[];
391
388
  onAddLocation: () => void;
389
+ onEditLocation: (index: number) => void;
390
+ onRemoveLocation: (index: number) => void;
391
+ activeDialog?: LocationDialogInput;
392
392
  }
393
393
 
394
394
  export type ViewOutput = undefined;
@@ -400,7 +400,18 @@ export const DEFAULT_VIEW = (input: LocationsViewInput, _output: ViewOutput, tar
400
400
  <div class="settings-card-container-wrapper">
401
401
  <div class="settings-card-container">
402
402
  <devtools-card .heading=${i18nString(UIStrings.locations)}>
403
- <div class="list-container"></div>
403
+ <div>
404
+ ${input.locations.length > 0 ? html`
405
+ <devtools-list
406
+ class="locations-list square-corners"
407
+ .editable=${true}
408
+ .deletable=${true}
409
+ @edit=${(e: Lists.List.ItemEditEvent) => input.onEditLocation(e.detail.index)}
410
+ @delete=${(e: Lists.List.ItemRemoveEvent) => input.onRemoveLocation(e.detail.index)}>
411
+ ${input.locations.map(location => renderItemView(location))}
412
+ </devtools-list>
413
+ ` : nothing}
414
+ </div>
404
415
  <devtools-button
405
416
  class="add-locations-button"
406
417
  .variant=${Buttons.Button.Variant.OUTLINED}
@@ -411,16 +422,22 @@ export const DEFAULT_VIEW = (input: LocationsViewInput, _output: ViewOutput, tar
411
422
  </devtools-button>
412
423
  </devtools-card>
413
424
  </div>
414
- </div>`, target);
425
+ </div>
426
+ ${input.activeDialog ? renderLocationDialog(input.activeDialog) : nothing}
427
+ `, target);
415
428
  // clang-format on
416
429
  };
417
430
 
418
431
  export type View = typeof DEFAULT_VIEW;
419
- export class LocationsSettingsTab extends UI.Widget.VBox implements UI.ListWidget.Delegate<LocationDescription> {
420
- private readonly list: UI.ListWidget.ListWidget<LocationDescription>;
432
+ export class LocationsSettingsTab extends UI.Widget.VBox {
421
433
  private readonly customSetting: Common.Settings.Setting<LocationDescription[]>;
422
- private editor?: UI.ListWidget.Editor<LocationDescription>;
423
434
  #view: View;
435
+ #activeDialogState?: {
436
+ location: LocationDescription,
437
+ isNew: boolean,
438
+ index?: number,
439
+ errors?: LocationValidationErrors,
440
+ };
424
441
 
425
442
  constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
426
443
  super(element, {
@@ -429,9 +446,6 @@ export class LocationsSettingsTab extends UI.Widget.VBox implements UI.ListWidge
429
446
  });
430
447
  this.#view = view;
431
448
 
432
- this.list = new UI.ListWidget.ListWidget(this, undefined, true);
433
- this.list.element.classList.add('locations-list');
434
- this.list.registerRequiredCSS(locationsSettingsTabStyles);
435
449
  this.customSetting =
436
450
  Common.Settings.Settings.instance().moduleSetting<LocationDescription[]>('emulation.locations');
437
451
  const list =
@@ -468,127 +482,93 @@ export class LocationsSettingsTab extends UI.Widget.VBox implements UI.ListWidge
468
482
  }
469
483
 
470
484
  override performUpdate(): void {
471
- const viewInput = {
485
+ let activeDialogInput: LocationDialogInput|undefined;
486
+ if (this.#activeDialogState) {
487
+ const state = this.#activeDialogState;
488
+ activeDialogInput = {
489
+ location: state.location,
490
+ isNew: state.isNew,
491
+ errors: state.errors,
492
+ onSave: (updatedLocation: LocationDescription) => this.saveDialog(updatedLocation),
493
+ onCancel: () => this.closeDialog(),
494
+ onValidateErrors: (errors: LocationValidationErrors) => this.updateDialogErrors(errors),
495
+ };
496
+ }
497
+
498
+ const viewInput: LocationsViewInput = {
499
+ locations: this.customSetting.get(),
472
500
  onAddLocation: () => this.addButtonClicked(),
501
+ onEditLocation: (index: number) => this.editLocationClicked(index),
502
+ onRemoveLocation: (index: number) => this.removeLocationClicked(index),
503
+ activeDialog: activeDialogInput,
473
504
  };
474
505
  this.#view(viewInput, undefined, this.contentElement as HTMLElement);
475
506
 
476
- const listContainer = this.contentElement.querySelector('.list-container');
477
- if (listContainer) {
478
- this.list.show(listContainer);
479
507
  }
480
- }
481
508
  private locationsUpdated(): void {
482
- this.list.clear();
483
-
484
- const conditions = this.customSetting.get();
485
- for (const condition of conditions) {
486
- this.list.appendItem(condition, true);
487
- }
488
-
489
- this.list.appendSeparator();
490
509
  this.requestUpdate();
491
510
  }
492
511
 
493
512
  private addButtonClicked(): void {
494
- this.list.addNewItem(this.customSetting.get().length, {
495
- title: '',
496
- lat: 0,
497
- long: 0,
498
- timezoneId: '',
499
- locale: '',
500
- accuracy: SDK.EmulationModel.Location.DEFAULT_ACCURACY,
501
- });
513
+ this.#activeDialogState = {
514
+ location: {
515
+ title: '',
516
+ lat: 0,
517
+ long: 0,
518
+ timezoneId: '',
519
+ locale: '',
520
+ accuracy: SDK.EmulationModel.Location.DEFAULT_ACCURACY,
521
+ },
522
+ isNew: true,
523
+ };
524
+ this.requestUpdate();
502
525
  }
503
526
 
504
- renderItem(location: LocationDescription, _editable: boolean): Element {
505
- const fragment = document.createDocumentFragment();
506
- // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
507
- render(renderItemView(location), fragment);
508
- return fragment.firstElementChild as Element;
527
+ private editLocationClicked(index: number): void {
528
+ const list = this.customSetting.get();
529
+ const location = list[index];
530
+ if (!location) {
531
+ return;
532
+ }
533
+ this.#activeDialogState = {
534
+ location: {...location},
535
+ isNew: false,
536
+ index,
537
+ };
538
+ this.requestUpdate();
509
539
  }
510
540
 
511
- removeItemRequested(_item: LocationDescription, index: number): void {
541
+ private removeLocationClicked(index: number): void {
512
542
  const list = this.customSetting.get();
513
543
  list.splice(index, 1);
514
544
  this.customSetting.set(list);
515
545
  }
516
546
 
517
- commitEdit(location: LocationDescription, editor: UI.ListWidget.Editor<LocationDescription>, isNew: boolean): void {
518
- location.title = editor.control('title').value.trim();
519
- const lat = editor.control('lat').value.trim();
520
- location.lat = lat ? parseFloat(lat) : 0;
521
- const long = editor.control('long').value.trim();
522
- location.long = long ? parseFloat(long) : 0;
523
- const timezoneId = editor.control('timezone-id').value.trim();
524
- location.timezoneId = timezoneId;
525
- const locale = editor.control('locale').value.trim();
526
- location.locale = locale;
527
- const accuracy = editor.control('accuracy').value.trim();
528
- location.accuracy = accuracy ? parseFloat(accuracy) : SDK.EmulationModel.Location.DEFAULT_ACCURACY;
547
+ private saveDialog(updatedLocation: LocationDescription): void {
548
+ if (!this.#activeDialogState) {
549
+ return;
550
+ }
529
551
 
530
552
  const list = this.customSetting.get();
531
- if (isNew) {
532
- list.push(location);
553
+ if (this.#activeDialogState.isNew) {
554
+ list.push(updatedLocation);
555
+ } else if (this.#activeDialogState.index !== undefined) {
556
+ list[this.#activeDialogState.index] = updatedLocation;
533
557
  }
558
+ this.#activeDialogState = undefined;
534
559
  this.customSetting.set(list);
535
560
  }
536
561
 
537
- beginEdit(location: LocationDescription): UI.ListWidget.Editor<LocationDescription> {
538
- const editor = this.createEditor();
539
- editor.control('title').value = location.title;
540
- editor.control('lat').value = String(location.lat);
541
- editor.control('long').value = String(location.long);
542
- editor.control('timezone-id').value = location.timezoneId;
543
- editor.control('locale').value = location.locale;
544
- editor.control('accuracy').value = String(location.accuracy ?? SDK.EmulationModel.Location.DEFAULT_ACCURACY);
545
- return editor;
562
+ private closeDialog(): void {
563
+ this.#activeDialogState = undefined;
564
+ this.requestUpdate();
546
565
  }
547
566
 
548
- private createEditor(): UI.ListWidget.Editor<LocationDescription> {
549
- if (this.editor) {
550
- return this.editor;
567
+ private updateDialogErrors(errors: LocationValidationErrors): void {
568
+ if (this.#activeDialogState) {
569
+ this.#activeDialogState.errors = errors;
570
+ this.requestUpdate();
551
571
  }
552
-
553
- const editor = new UI.ListWidget.Editor<LocationDescription>();
554
- this.editor = editor;
555
- const content = editor.contentElement();
556
-
557
- const createValidator = (validator: (value: string) => string | null) =>
558
- (_item: LocationDescription, _index: number,
559
- input: UI.ListWidget.EditorControl): UI.ListWidget.ValidatorResult => {
560
- const errorMessage = validator(input.value);
561
- if (errorMessage) {
562
- return {valid: false, errorMessage};
563
- }
564
- return {valid: true};
565
- };
566
-
567
- const titleInput =
568
- editor.createInput('title', 'text', i18nString(UIStrings.locationName), createValidator(validateTitle));
569
- const latInput =
570
- editor.createInput('lat', 'text', i18nString(UIStrings.latitude), createValidator(validateLatitude));
571
- const longInput =
572
- editor.createInput('long', 'text', i18nString(UIStrings.longitude), createValidator(validateLongitude));
573
- const timezoneIdInput = editor.createInput('timezone-id', 'text', i18nString(UIStrings.timezoneId),
574
- createValidator(validateTimezoneId));
575
- const localeInput =
576
- editor.createInput('locale', 'text', i18nString(UIStrings.locale), createValidator(validateLocale));
577
- const accuracyInput =
578
- editor.createInput('accuracy', 'text', i18nString(UIStrings.accuracy), createValidator(validateAccuracy));
579
-
580
- // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
581
- render(renderEditorView({
582
- titleInput,
583
- latInput,
584
- longInput,
585
- timezoneIdInput,
586
- localeInput,
587
- accuracyInput,
588
- }),
589
- content as HTMLElement);
590
-
591
- return editor;
592
572
  }
593
573
  }
594
574
  export interface LocationDescription {
@@ -607,6 +587,7 @@ export function validateTitle(value: string): string|null {
607
587
  if (!trimmedValue.length) {
608
588
  return i18nString(UIStrings.locationNameCannotBeEmpty);
609
589
  }
590
+
610
591
  if (trimmedValue.length > maxLength) {
611
592
  return i18nString(UIStrings.locationNameMustBeLessThanS, {PH1: maxLength});
612
593
  }
@@ -622,6 +603,7 @@ export function validateLatitude(value: string): string|null {
622
603
  if (!trimmedValue) {
623
604
  return null;
624
605
  }
606
+
625
607
  if (Number.isNaN(parsedValue)) {
626
608
  return i18nString(UIStrings.latitudeMustBeANumber);
627
609
  }
@@ -643,6 +625,7 @@ export function validateLongitude(value: string): string|null {
643
625
  if (!trimmedValue) {
644
626
  return null;
645
627
  }
628
+
646
629
  if (Number.isNaN(parsedValue)) {
647
630
  return i18nString(UIStrings.longitudeMustBeANumber);
648
631
  }
@@ -692,6 +675,7 @@ export function validateAccuracy(value: string): string|null {
692
675
  if (!trimmedValue) {
693
676
  return null;
694
677
  }
678
+
695
679
  if (Number.isNaN(parsedValue)) {
696
680
  return i18nString(UIStrings.accuracyMustBeANumber);
697
681
  }
@@ -4,18 +4,18 @@
4
4
  * found in the LICENSE file.
5
5
  */
6
6
 
7
- * {
8
- font-family: var(--default-font-family);
9
- }
10
-
7
+ devtools-button.add-locations-button:not(:first-child),
11
8
  .add-locations-button {
12
9
  margin-bottom: var(--sys-size-5);
13
10
  border: none;
14
11
  }
15
12
 
13
+ devtools-list.locations-list,
16
14
  .locations-list {
17
15
  margin-top: var(--sys-size-3);
18
16
  flex: auto;
17
+ display: flex;
18
+ border: 1px solid var(--sys-color-divider);
19
19
  }
20
20
 
21
21
  .locations-list-item {