chrome-devtools-frontend 1.0.1528866 → 1.0.1529904

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 (46) hide show
  1. package/front_end/core/common/Gzip.ts +10 -8
  2. package/front_end/core/host/UserMetrics.ts +2 -1
  3. package/front_end/core/root/Runtime.ts +10 -0
  4. package/front_end/core/sdk/NetworkManager.ts +85 -35
  5. package/front_end/core/sdk/SourceMap.ts +14 -0
  6. package/front_end/core/sdk/SourceMapScopesInfo.ts +32 -2
  7. package/front_end/entrypoints/main/MainImpl.ts +23 -4
  8. package/front_end/generated/SupportedCSSProperties.js +9 -0
  9. package/front_end/models/ai_assistance/BuiltInAi.ts +1 -1
  10. package/front_end/models/ai_assistance/ConversationHandler.ts +15 -14
  11. package/front_end/models/bindings/CompilerScriptMapping.ts +54 -4
  12. package/front_end/models/javascript_metadata/NativeFunctions.js +8 -0
  13. package/front_end/models/persistence/NetworkPersistenceManager.ts +3 -5
  14. package/front_end/models/persistence/PersistenceImpl.ts +0 -5
  15. package/front_end/models/persistence/persistence-meta.ts +0 -31
  16. package/front_end/models/persistence/persistence.ts +0 -6
  17. package/front_end/{models/persistence → panels/common}/PersistenceUtils.ts +15 -17
  18. package/front_end/panels/common/common.ts +1 -0
  19. package/front_end/panels/console/ConsoleInsightTeaser.ts +285 -22
  20. package/front_end/panels/console/ConsolePrompt.ts +10 -2
  21. package/front_end/panels/console/ConsoleViewMessage.ts +18 -1
  22. package/front_end/panels/console/console-meta.ts +14 -0
  23. package/front_end/panels/console/consoleInsightTeaser.css +28 -0
  24. package/front_end/panels/console/consolePrompt.css +3 -2
  25. package/front_end/panels/console/consoleView.css +10 -5
  26. package/front_end/panels/explain/ActionDelegate.ts +3 -0
  27. package/front_end/panels/explain/explain-meta.ts +7 -0
  28. package/front_end/panels/network/BlockedURLsPane.ts +139 -36
  29. package/front_end/panels/network/NetworkLogView.ts +1 -1
  30. package/front_end/{models/persistence → panels/settings}/EditFileSystemView.ts +2 -6
  31. package/front_end/panels/settings/WorkspaceSettingsTab.ts +2 -1
  32. package/front_end/panels/settings/settings.ts +2 -0
  33. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +9 -4
  34. package/front_end/{models/persistence → panels/sources}/PersistenceActions.ts +8 -12
  35. package/front_end/panels/sources/TabbedEditorContainer.ts +2 -1
  36. package/front_end/panels/sources/sources-meta.ts +15 -0
  37. package/front_end/panels/sources/sources.ts +2 -0
  38. package/front_end/panels/timeline/TimelinePanel.ts +2 -3
  39. package/front_end/panels/utils/utils.ts +2 -1
  40. package/front_end/third_party/chromium/README.chromium +1 -1
  41. package/front_end/third_party/diff/diff_match_patch.js +1 -1
  42. package/front_end/ui/legacy/ListWidget.ts +2 -2
  43. package/front_end/ui/legacy/components/object_ui/objectPropertiesSection.css +1 -1
  44. package/front_end/ui/visual_logging/KnownContextValues.ts +9 -0
  45. package/package.json +1 -1
  46. /package/front_end/{models/persistence → panels/settings}/editFileSystemView.css +0 -0
@@ -1343,6 +1343,17 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1343
1343
  return this.contentElementInternal;
1344
1344
  }
1345
1345
 
1346
+ #onMouseEnter(_event: MouseEvent): void {
1347
+ if (this.#teaser &&
1348
+ Common.Settings.Settings.instance().moduleSetting('console-insight-teasers-enabled').getIfNotDisabled()) {
1349
+ this.#teaser.maybeGenerateTeaser();
1350
+ }
1351
+ }
1352
+
1353
+ #onMouseLeave(): void {
1354
+ this.#teaser?.abortTeaserGeneration();
1355
+ }
1356
+
1346
1357
  toMessageElement(): HTMLElement {
1347
1358
  if (this.elementInternal) {
1348
1359
  return this.elementInternal;
@@ -1350,6 +1361,8 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1350
1361
  this.elementInternal = document.createElement('div');
1351
1362
  this.elementInternal.tabIndex = -1;
1352
1363
  this.elementInternal.addEventListener('keydown', (this.onKeyDown.bind(this) as EventListener));
1364
+ this.elementInternal.addEventListener('mouseenter', this.#onMouseEnter.bind(this));
1365
+ this.elementInternal.addEventListener('mouseleave', this.#onMouseLeave.bind(this));
1353
1366
  this.updateMessageElement();
1354
1367
  this.elementInternal.classList.toggle('console-adjacent-user-command-result', this.#adjacentUserCommandResult);
1355
1368
  return this.elementInternal;
@@ -1447,7 +1460,11 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1447
1460
  }
1448
1461
 
1449
1462
  shouldShowTeaser(): boolean {
1450
- if (!this.shouldShowInsights() || !AiAssistanceModel.BuiltInAi.BuiltInAi.cachedIsAvailable()) {
1463
+ if (!this.shouldShowInsights()) {
1464
+ return false;
1465
+ }
1466
+ if (!Common.Settings.Settings.instance().moduleSetting('console-insight-teasers-enabled').getIfNotDisabled() ||
1467
+ !AiAssistanceModel.BuiltInAi.BuiltInAi.cachedIsAvailable()) {
1451
1468
  return false;
1452
1469
  }
1453
1470
  const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
@@ -133,6 +133,11 @@ const UIStrings = {
133
133
  * @description Title of a setting under the Console category in Settings that controls whether `console.trace()` messages appear collapsed by default.
134
134
  */
135
135
  collapseConsoleTraceMessagesByDefault: 'Do not automatically expand `console.trace()` messages',
136
+ /**
137
+ * @description Title of a setting under the Console category in Settings that controls whether AI summaries should
138
+ * be shown for console warnings/errors.
139
+ */
140
+ showConsoleInsightTeasers: 'Show AI summaries for console messages',
136
141
  } as const;
137
142
  const str_ = i18n.i18n.registerUIStrings('panels/console/console-meta.ts', UIStrings);
138
143
  const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
@@ -437,6 +442,15 @@ Common.Settings.registerSettingExtension({
437
442
  ],
438
443
  });
439
444
 
445
+ Common.Settings.registerSettingExtension({
446
+ category: Common.Settings.SettingCategory.CONSOLE,
447
+ storageType: Common.Settings.SettingStorageType.SYNCED,
448
+ title: i18nLazyString(UIStrings.showConsoleInsightTeasers),
449
+ settingName: 'console-insight-teasers-enabled',
450
+ settingType: Common.Settings.SettingType.BOOLEAN,
451
+ defaultValue: true,
452
+ });
453
+
440
454
  Common.Revealer.registerRevealer({
441
455
  contextTypes() {
442
456
  return [
@@ -52,4 +52,32 @@
52
52
  font: var(--sys-typescale-body4-bold);
53
53
  margin: 0 0 var(--sys-size-3);
54
54
  }
55
+
56
+ .lightbulb-icon {
57
+ color: var(--sys-color-on-primary);
58
+ height: var(--sys-size-7);
59
+ margin-left: calc(-1 * var(--sys-size-4));
60
+ }
61
+
62
+ .learn-more {
63
+ padding-top: 7px;
64
+ }
65
+
66
+ .info-tooltip-text {
67
+ max-width: var(--sys-size-26);
68
+ }
69
+
70
+ .tooltip-footer {
71
+ padding: var(--sys-size-5) 0 0;
72
+ display: flex;
73
+ align-items: center;
74
+
75
+ .info-icon {
76
+ margin-left: var(--sys-size-4);
77
+ }
78
+
79
+ devtools-checkbox {
80
+ margin-left: auto;
81
+ }
82
+ }
55
83
  }
@@ -18,13 +18,14 @@
18
18
 
19
19
  #console-prompt .console-prompt-icon {
20
20
  position: absolute;
21
- left: -13px;
22
- top: 2px;
21
+ left: -9px;
22
+ top: 4px;
23
23
  user-select: none;
24
24
  }
25
25
 
26
26
  .console-eager-preview {
27
27
  padding-bottom: 2px;
28
+ margin-left: 4px;
28
29
  opacity: 60%;
29
30
  position: relative;
30
31
  }
@@ -1,4 +1,7 @@
1
- /*
1
+ /* Copyright 2021 The Chromium Authors
2
+ * Use of this source code is governed by a BSD-style license that can be
3
+ * found in the LICENSE file.
4
+ *
2
5
  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3
6
  * Copyright (C) 2009 Anthony Ricaud <rik@webkit.org>
4
7
  *
@@ -90,17 +93,20 @@
90
93
 
91
94
  .console-prompt-editor-container {
92
95
  min-height: 21px;
96
+ padding-left: 2px;
97
+ padding-top: 1px;
93
98
  }
94
99
 
95
100
  .console-message,
96
101
  .console-user-command {
97
102
  clear: right;
98
103
  position: relative;
99
- padding: 3px 22px 1px 0;
104
+ padding: 1px 22px 1px 0;
100
105
  margin-left: 24px;
101
- min-height: 17px; /* Sync with ConsoleViewMessage.js */
106
+ min-height: 18px;
102
107
  flex: auto;
103
108
  display: flex;
109
+ align-items: flex-end;
104
110
  }
105
111
 
106
112
  .console-message > * {
@@ -215,7 +221,7 @@
215
221
  --console-color-white: #fff;
216
222
 
217
223
  &.console-selected {
218
- background-color: var(--sys-color-tonal-container);
224
+ background-color: var(--sys-color-state-focus-highlight);
219
225
  }
220
226
  }
221
227
 
@@ -329,7 +335,6 @@
329
335
  display: inline-block;
330
336
  overflow-wrap: break-word;
331
337
  max-width: 100%;
332
- vertical-align: top;
333
338
  margin-top: -1.5px;
334
339
  }
335
340
 
@@ -15,11 +15,14 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
15
15
  case 'explain.console-message.context.error':
16
16
  case 'explain.console-message.context.warning':
17
17
  case 'explain.console-message.context.other':
18
+ case 'explain.console-message.teaser':
18
19
  case 'explain.console-message.hover': {
19
20
  const consoleViewMessage = context.flavor(Console.ConsoleViewMessage.ConsoleViewMessage);
20
21
  if (consoleViewMessage) {
21
22
  if (actionId.startsWith('explain.console-message.context')) {
22
23
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightRequestedViaContextMenu);
24
+ } else if (actionId === 'explain.console-message.teaser') {
25
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightRequestedViaTeaser);
23
26
  } else if (actionId === 'explain.console-message.hover') {
24
27
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.InsightRequestedViaHoverButton);
25
28
  }
@@ -57,6 +57,13 @@ const actions = [
57
57
  return [Console.ConsoleViewMessage.ConsoleViewMessage];
58
58
  },
59
59
  },
60
+ {
61
+ actionId: 'explain.console-message.teaser',
62
+ title: i18nLazyString(UIStrings.explainThisMessage),
63
+ contextTypes(): [] {
64
+ return [];
65
+ },
66
+ },
60
67
  {
61
68
  actionId: 'explain.console-message.context.error',
62
69
  title: i18nLazyString(UIStrings.explainThisError),
@@ -5,15 +5,17 @@
5
5
  /* eslint-disable rulesdir/no-imperative-dom-api */
6
6
 
7
7
  import '../../ui/legacy/legacy.js';
8
+ import '../../ui/components/tooltips/tooltips.js';
8
9
 
9
10
  import type * as Common from '../../core/common/common.js';
10
11
  import * as i18n from '../../core/i18n/i18n.js';
11
12
  import * as Platform from '../../core/platform/platform.js';
13
+ import * as Root from '../../core/root/root.js';
12
14
  import * as SDK from '../../core/sdk/sdk.js';
13
15
  import * as Logs from '../../models/logs/logs.js';
14
16
  import * as Buttons from '../../ui/components/buttons/buttons.js';
15
17
  import * as UI from '../../ui/legacy/legacy.js';
16
- import {Directives, html, render} from '../../ui/lit/lit.js';
18
+ import {Directives, html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
17
19
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
18
20
 
19
21
  import blockedURLsPaneStyles from './blockedURLsPane.css.js';
@@ -51,6 +53,10 @@ const UIStrings = {
51
53
  * @description Text in Blocked URLs Pane of the Network panel
52
54
  */
53
55
  textPatternToBlockMatching: 'Text pattern to block matching requests; use * for wildcard',
56
+ /**
57
+ * @description Text in Blocked URLs Pane of the Network panel
58
+ */
59
+ textPatternToBlockMatchingURLPatterns: 'Text pattern to block matching requests; use URLPattern syntax.',
54
60
  /**
55
61
  * @description Error text for empty list widget input in Request Blocking tool
56
62
  */
@@ -59,6 +65,19 @@ const UIStrings = {
59
65
  * @description Error text for duplicate list widget input in Request Blocking tool
60
66
  */
61
67
  patternAlreadyExists: 'Pattern already exists.',
68
+ /**
69
+ * @description Tooltip message when a pattern failed to parse as a URLPattern
70
+ */
71
+ patternFailedToParse: 'This pattern failed to parse as a URLPattern',
72
+ /**
73
+ * @description Tooltip message when a pattern failed to parse as a URLPattern because it contains RegExp groups
74
+ */
75
+ patternFailedWithRegExpGroups: 'RegExp groups are not allowed',
76
+ /**
77
+ * @description Tooltip message when a pattern was converted to a URLPattern
78
+ * @example {example.com} PH1
79
+ */
80
+ patternWasUpgraded: 'This pattern was upgraded from "{PH1}"',
62
81
  /**
63
82
  * @description Message to be announced for a when list item is removed from list widget
64
83
  */
@@ -73,6 +92,8 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
73
92
 
74
93
  const NETWORK_REQUEST_BLOCKING_EXPLANATION_URL =
75
94
  'https://developer.chrome.com/docs/devtools/network-request-blocking' as Platform.DevToolsPath.UrlString;
95
+ const PATTERN_API_DOCS_URL =
96
+ 'https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API' as Platform.DevToolsPath.UrlString;
76
97
 
77
98
  const {bindToAction} = UI.UIUtils;
78
99
 
@@ -126,12 +147,22 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
126
147
  target);
127
148
  };
128
149
 
150
+ function learnMore(): LitTemplate {
151
+ return html`<x-link
152
+ href=${NETWORK_REQUEST_BLOCKING_EXPLANATION_URL}
153
+ tabindex=0
154
+ class=devtools-link
155
+ jslog=${VisualLogging.link().track({click: true, keydown: 'Enter|Space'}).context('learn-more')}>
156
+ ${i18nString(UIStrings.learnMore)}
157
+ </x-link>`;
158
+ }
159
+
129
160
  export class BlockedURLsPane extends UI.Widget.VBox implements
130
161
  UI.ListWidget.Delegate<SDK.NetworkManager.RequestCondition> {
131
162
  private manager: SDK.NetworkManager.MultitargetNetworkManager;
132
163
  private readonly list: UI.ListWidget.ListWidget<SDK.NetworkManager.RequestCondition>;
133
164
  private editor: UI.ListWidget.Editor<SDK.NetworkManager.RequestCondition>|null;
134
- private blockedCountForUrl: Map<string, number>;
165
+ private blockedCountForUrl: Map<Platform.DevToolsPath.UrlString, number>;
135
166
  #view: View;
136
167
 
137
168
  constructor(target?: HTMLElement, view = DEFAULT_VIEW) {
@@ -183,8 +214,8 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
183
214
  this.manager.requestConditions.clear();
184
215
  }
185
216
 
186
- renderItem(condition: SDK.NetworkManager.RequestCondition, editable: boolean): Element {
187
- const count = this.blockedRequestsCount(condition.url);
217
+ renderItem(condition: SDK.NetworkManager.RequestCondition, editable: boolean, index: number): Element {
218
+ const count = this.blockedRequestsCount(condition);
188
219
  const element = document.createElement('div');
189
220
  element.classList.add('blocked-url');
190
221
  const toggle = (e: Event): void => {
@@ -193,8 +224,56 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
193
224
  condition.enabled = !condition.enabled;
194
225
  }
195
226
  };
196
- render(
197
- // clang-format off
227
+
228
+ const {enabled, originalOrUpgradedURLPattern, constructorStringOrWildcardURL, wildcardURL} = condition;
229
+
230
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
231
+ render(
232
+ // clang-format off
233
+ html`
234
+ <input class=blocked-url-checkbox
235
+ @click=${toggle}
236
+ type=checkbox
237
+ ?checked=${enabled}
238
+ ?disabled=${!editable || !originalOrUpgradedURLPattern}
239
+ .jslog=${VisualLogging.toggle().track({ change: true })}>
240
+ ${originalOrUpgradedURLPattern ? html`
241
+ <devtools-tooltip variant=rich jslogcontext=url-pattern id=url-pattern-${index}>
242
+ <div>hash: ${originalOrUpgradedURLPattern.hash}</div>
243
+ <div>hostname: ${originalOrUpgradedURLPattern.hostname}</div>
244
+ <div>password: ${originalOrUpgradedURLPattern.password}</div>
245
+ <div>pathname: ${originalOrUpgradedURLPattern.pathname}</div>
246
+ <div>port: ${originalOrUpgradedURLPattern.port}</div>
247
+ <div>protocol: ${originalOrUpgradedURLPattern.protocol}</div>
248
+ <div>search: ${originalOrUpgradedURLPattern.search}</div>
249
+ <div>username: ${originalOrUpgradedURLPattern.username}</div>
250
+ <hr />
251
+ ${learnMore()}
252
+ </devtools-tooltip>` : nothing}
253
+ ${wildcardURL ? html`
254
+ <devtools-icon name=warning-filled class="small warning" aria-details=url-pattern-warning-${index}>
255
+ </devtools-icon>
256
+ <devtools-tooltip variant=rich jslogcontext=url-pattern-warning id=url-pattern-warning-${index}>
257
+ ${i18nString(UIStrings.patternWasUpgraded, {PH1: wildcardURL})}
258
+ </devtools-tooltip>
259
+ `: nothing}
260
+ ${!originalOrUpgradedURLPattern ? html`
261
+ <devtools-icon name=cross-circle-filled class=small aria-details=url-pattern-error-${index}>
262
+ </devtools-icon>
263
+ <devtools-tooltip variant=rich jslogcontext=url-pattern-warning id=url-pattern-error-${index}>
264
+ ${SDK.NetworkManager.RequestURLPattern.isValidPattern(constructorStringOrWildcardURL) ===
265
+ SDK.NetworkManager.RequestURLPatternValidity.HAS_REGEXP_GROUPS
266
+ ? i18nString(UIStrings.patternFailedWithRegExpGroups)
267
+ : i18nString(UIStrings.patternFailedToParse)}
268
+ ${learnMore()}
269
+ </devtools-tooltip>`: nothing}
270
+ <div @click=${toggle} class=blocked-url-label aria-details=url-pattern-${index}>${constructorStringOrWildcardURL}</div>
271
+ <div class=blocked-url-count>${i18nString(UIStrings.dBlocked, {PH1: count})}</div>`,
272
+ // clang-format on
273
+ element);
274
+ } else {
275
+ render(
276
+ // clang-format off
198
277
  html`
199
278
  <input class=blocked-url-checkbox
200
279
  @click=${toggle}
@@ -202,10 +281,11 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
202
281
  ?checked=${condition.enabled}
203
282
  ?disabled=${!editable}
204
283
  .jslog=${VisualLogging.toggle().track({ change: true })}>
205
- <div @click=${toggle} class=blocked-url-label>${condition.url}</div>
284
+ <div @click=${toggle} class=blocked-url-label>${wildcardURL}</div>
206
285
  <div class=blocked-url-count>${i18nString(UIStrings.dBlocked, {PH1: count})}</div>`,
207
- // clang-format off
208
- element);
286
+ // clang-format on
287
+ element);
288
+ }
209
289
  return element;
210
290
  }
211
291
 
@@ -215,21 +295,29 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
215
295
  }
216
296
 
217
297
  removeItemRequested(condition: SDK.NetworkManager.RequestCondition): void {
218
- this.manager.requestConditions.delete(condition);
298
+ this.manager.requestConditions.delete(condition);
219
299
  UI.ARIAUtils.LiveAnnouncer.alert(UIStrings.itemDeleted);
220
300
  }
221
301
 
222
302
  beginEdit(pattern: SDK.NetworkManager.RequestCondition): UI.ListWidget.Editor<SDK.NetworkManager.RequestCondition> {
223
303
  this.editor = this.createEditor();
224
- this.editor.control('url').value = pattern.url;
304
+ this.editor.control('url').value = Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled ?
305
+ pattern.constructorStringOrWildcardURL :
306
+ pattern.wildcardURL ?? '';
225
307
  return this.editor;
226
308
  }
227
309
 
228
310
  commitEdit(
229
311
  item: SDK.NetworkManager.RequestCondition, editor: UI.ListWidget.Editor<SDK.NetworkManager.RequestCondition>,
230
312
  isNew: boolean): void {
231
- item.url =
232
- editor.control('url').value as Platform.DevToolsPath.UrlString;
313
+ const constructorString = editor.control('url').value as SDK.NetworkManager.URLPatternConstructorString;
314
+ const pattern = Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled ?
315
+ SDK.NetworkManager.RequestURLPattern.create(constructorString) :
316
+ constructorString;
317
+ if (!pattern) {
318
+ throw new Error('Failed to parse pattern');
319
+ }
320
+ item.pattern = pattern;
233
321
  if (isNew) {
234
322
  this.manager.requestConditions.add(item);
235
323
  }
@@ -243,23 +331,37 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
243
331
  const editor = new UI.ListWidget.Editor<SDK.NetworkManager.RequestCondition>();
244
332
  const content = editor.contentElement();
245
333
  const titles = content.createChild('div', 'blocked-url-edit-row');
246
- titles.createChild('div').textContent = i18nString(UIStrings.textPatternToBlockMatching);
334
+ const label = titles.createChild('div');
335
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
336
+ label.textContent = i18nString(UIStrings.textPatternToBlockMatchingURLPatterns);
337
+ label.append(UI.XLink.XLink.create(
338
+ PATTERN_API_DOCS_URL, i18nString(UIStrings.learnMore), undefined, undefined, 'learn-more'));
339
+ } else {
340
+ label.textContent = i18nString(UIStrings.textPatternToBlockMatching);
341
+ }
247
342
  const fields = content.createChild('div', 'blocked-url-edit-row');
248
- const validator = (_item: SDK.NetworkManager.RequestCondition, _index: number, input: UI.ListWidget.EditorControl): {
249
- valid: boolean,
250
- errorMessage: Common.UIString.LocalizedString|undefined,
251
- } => {
252
- let valid = true;
253
- let errorMessage;
254
- if (!input.value) {
255
- errorMessage = i18nString(UIStrings.patternInputCannotBeEmpty);
256
- valid = false;
257
- } else if (this.manager.requestConditions.has(input.value)) {
258
- errorMessage = i18nString(UIStrings.patternAlreadyExists);
259
- valid = false;
260
- }
261
- return {valid, errorMessage};
262
- };
343
+ const validator =
344
+ (_item: SDK.NetworkManager.RequestCondition, _index: number, input: UI.ListWidget.EditorControl): {
345
+ valid: boolean,
346
+ errorMessage: Common.UIString.LocalizedString|undefined,
347
+ } => {
348
+ if (!input.value) {
349
+ return {errorMessage: i18nString(UIStrings.patternInputCannotBeEmpty), valid: false};
350
+ }
351
+ if (this.manager.requestConditions.has(input.value)) {
352
+ return {errorMessage: i18nString(UIStrings.patternAlreadyExists), valid: false};
353
+ }
354
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
355
+ const isValid = SDK.NetworkManager.RequestURLPattern.isValidPattern(input.value);
356
+ switch (isValid) {
357
+ case SDK.NetworkManager.RequestURLPatternValidity.FAILED_TO_PARSE:
358
+ return {errorMessage: i18nString(UIStrings.patternFailedToParse), valid: false};
359
+ case SDK.NetworkManager.RequestURLPatternValidity.HAS_REGEXP_GROUPS:
360
+ return {errorMessage: i18nString(UIStrings.patternFailedWithRegExpGroups), valid: false};
361
+ }
362
+ }
363
+ return {valid: true, errorMessage: undefined};
364
+ };
263
365
  const urlInput = editor.createInput('url', 'text', '', validator);
264
366
  fields.createChild('div', 'blocked-url-edit-value').appendChild(urlInput);
265
367
  return editor;
@@ -269,19 +371,20 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
269
371
  const enabled = this.manager.blockingEnabled();
270
372
  this.list.clear();
271
373
  for (const pattern of this.manager.requestConditions.conditions) {
272
- this.list.appendItem(pattern, enabled);
374
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled || pattern.wildcardURL) {
375
+ this.list.appendItem(pattern, enabled);
376
+ }
273
377
  }
274
378
  this.requestUpdate();
275
379
  }
276
380
 
277
- private blockedRequestsCount(url: string): number {
278
- if (!url) {
279
- return 0;
280
- }
281
-
381
+ private blockedRequestsCount(condition: SDK.NetworkManager.RequestCondition): number {
282
382
  let result = 0;
283
383
  for (const blockedUrl of this.blockedCountForUrl.keys()) {
284
- if (this.matches(url, blockedUrl)) {
384
+ const match = Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled ?
385
+ condition.originalOrUpgradedURLPattern?.test(blockedUrl) :
386
+ (condition.wildcardURL && this.matches(condition.wildcardURL, blockedUrl));
387
+ if (match) {
285
388
  result += (this.blockedCountForUrl.get(blockedUrl) as number);
286
389
  }
287
390
  }
@@ -1857,7 +1857,7 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
1857
1857
  }
1858
1858
 
1859
1859
  function removeBlockedURL(url: string): void {
1860
- const entry = manager.requestConditions.conditions.find(condition => condition.url === url);
1860
+ const entry = manager.requestConditions.findCondition(url);
1861
1861
  if (entry) {
1862
1862
  manager.requestConditions.delete(entry);
1863
1863
  }
@@ -6,15 +6,11 @@ import '../../ui/legacy/components/data_grid/data_grid.js';
6
6
 
7
7
  import * as i18n from '../../core/i18n/i18n.js';
8
8
  import * as Platform from '../../core/platform/platform.js';
9
- // TODO(crbug.com/442509324): remove UI dependency
10
- // eslint-disable-next-line rulesdir/no-imports-in-directory
9
+ import type {PlatformFileSystem} from '../../models/persistence/PlatformFileSystem.js';
11
10
  import * as UI from '../../ui/legacy/legacy.js';
12
- // TODO(crbug.com/442509324): remove UI dependency
13
- // eslint-disable-next-line rulesdir/no-imports-in-directory
14
11
  import {Directives, html, render} from '../../ui/lit/lit.js';
15
12
 
16
13
  import editFileSystemViewStyles from './editFileSystemView.css.js';
17
- import type {PlatformFileSystem} from './PlatformFileSystem.js';
18
14
 
19
15
  const {styleMap} = Directives;
20
16
 
@@ -36,7 +32,7 @@ const UIStrings = {
36
32
  */
37
33
  enterAUniquePath: 'Enter a unique path',
38
34
  } as const;
39
- const str_ = i18n.i18n.registerUIStrings('models/persistence/EditFileSystemView.ts', UIStrings);
35
+ const str_ = i18n.i18n.registerUIStrings('panels/settings/EditFileSystemView.ts', UIStrings);
40
36
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
41
37
 
42
38
  export const enum ExcludedFolderStatus {
@@ -14,6 +14,7 @@ import * as UI from '../../ui/legacy/legacy.js';
14
14
  import {html, render} from '../../ui/lit/lit.js';
15
15
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
16
16
 
17
+ import {EditFileSystemView} from './EditFileSystemView.js';
17
18
  import workspaceSettingsTabStyles from './workspaceSettingsTab.css.js';
18
19
 
19
20
  const UIStrings = {
@@ -71,7 +72,7 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
71
72
  <div class="mapping-view-container">
72
73
  <devtools-widget .widgetConfig=${
73
74
  UI.Widget.widgetConfig(
74
- Persistence.EditFileSystemView.EditFileSystemView,
75
+ EditFileSystemView,
75
76
  {fileSystem: fileSystem.fileSystem})}>
76
77
  </devtools-widget>
77
78
  </div>
@@ -5,6 +5,7 @@
5
5
  import './SettingsScreen.js';
6
6
 
7
7
  import * as AISettingsTab from './AISettingsTab.js';
8
+ import * as EditFileSystemView from './EditFileSystemView.js';
8
9
  import * as FrameworkIgnoreListSettingsTab from './FrameworkIgnoreListSettingsTab.js';
9
10
  import * as KeybindsSettingsTab from './KeybindsSettingsTab.js';
10
11
  import * as SettingsScreen from './SettingsScreen.js';
@@ -12,6 +13,7 @@ import * as WorkspaceSettingsTab from './WorkspaceSettingsTab.js';
12
13
 
13
14
  export {
14
15
  AISettingsTab,
16
+ EditFileSystemView,
15
17
  FrameworkIgnoreListSettingsTab,
16
18
  KeybindsSettingsTab,
17
19
  SettingsScreen,
@@ -55,7 +55,6 @@ export class AiCodeCompletionPlugin extends Plugin {
55
55
  this.#boundOnAidaAvailabilityChange = this.#onAidaAvailabilityChange.bind(this);
56
56
  Host.AidaClient.HostConfigTracker.instance().addEventListener(
57
57
  Host.AidaClient.Events.AIDA_AVAILABILITY_CHANGED, this.#boundOnAidaAvailabilityChange);
58
- void this.#onAidaAvailabilityChange();
59
58
  const showTeaser = !this.#aiCodeCompletionSetting.get() && !this.#aiCodeCompletionTeaserDismissedSetting.get();
60
59
  if (showTeaser) {
61
60
  this.#teaser = new PanelCommon.AiCodeCompletionTeaser({onDetach: this.#detachAiCodeCompletionTeaser.bind(this)});
@@ -84,9 +83,7 @@ export class AiCodeCompletionPlugin extends Plugin {
84
83
  this.#editor.addEventListener('keydown', this.#boundEditorKeyDown);
85
84
  this.#aiCodeCompletionSetting.addChangeListener(this.#boundOnAiCodeCompletionSettingChanged);
86
85
  this.#onAiCodeCompletionSettingChanged();
87
- if (editor.state.doc.length === 0) {
88
- this.#addTeaserPluginToCompartmentImmediate(editor.editor);
89
- }
86
+ void this.#onAidaAvailabilityChange();
90
87
  }
91
88
 
92
89
  override editorExtension(): CodeMirror.Extension {
@@ -281,8 +278,16 @@ export class AiCodeCompletionPlugin extends Plugin {
281
278
  this.#aidaAvailability = currentAidaAvailability;
282
279
  if (this.#aidaAvailability === Host.AidaClient.AidaAccessPreconditions.AVAILABLE) {
283
280
  this.#onAiCodeCompletionSettingChanged();
281
+ if (this.#editor?.state.doc.length === 0) {
282
+ this.#addTeaserPluginToCompartmentImmediate(this.#editor?.editor);
283
+ }
284
284
  } else if (this.#aiCodeCompletion) {
285
285
  this.#cleanupAiCodeCompletion();
286
+ if (this.#teaser) {
287
+ this.#editor?.dispatch({
288
+ effects: this.#teaserCompartment.reconfigure([]),
289
+ });
290
+ }
286
291
  }
287
292
  }
288
293
  }
@@ -7,15 +7,11 @@ import * as Host from '../../core/host/host.js';
7
7
  import * as i18n from '../../core/i18n/i18n.js';
8
8
  import type * as Platform from '../../core/platform/platform.js';
9
9
  import * as SDK from '../../core/sdk/sdk.js';
10
- // TODO(crbug.com/442509324): remove UI dependency
11
- // eslint-disable-next-line rulesdir/no-imports-in-directory
10
+ import * as Bindings from '../../models/bindings/bindings.js';
11
+ import * as Persistence from '../../models/persistence/persistence.js';
12
+ import * as TextUtils from '../../models/text_utils/text_utils.js';
13
+ import * as Workspace from '../../models/workspace/workspace.js';
12
14
  import * as UI from '../../ui/legacy/legacy.js';
13
- import * as Bindings from '../bindings/bindings.js';
14
- import * as TextUtils from '../text_utils/text_utils.js';
15
- import * as Workspace from '../workspace/workspace.js';
16
-
17
- import {NetworkPersistenceManager} from './NetworkPersistenceManager.js';
18
- import {PersistenceImpl} from './PersistenceImpl.js';
19
15
 
20
16
  const UIStrings = {
21
17
  /**
@@ -59,7 +55,7 @@ const UIStrings = {
59
55
  */
60
56
  saveWasmFailed: 'Unable to save WASM module to disk. Most likely the module is too large.',
61
57
  } as const;
62
- const str_ = i18n.i18n.registerUIStrings('models/persistence/PersistenceActions.ts', UIStrings);
58
+ const str_ = i18n.i18n.registerUIStrings('panels/sources/PersistenceActions.ts', UIStrings);
63
59
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
64
60
 
65
61
  export class ContextMenuProvider implements
@@ -116,9 +112,9 @@ export class ContextMenuProvider implements
116
112
 
117
113
  // Retrieve uiSourceCode by URL to pick network resources everywhere.
118
114
  const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(contentProvider.contentURL());
119
- const networkPersistenceManager = NetworkPersistenceManager.instance();
115
+ const networkPersistenceManager = Persistence.NetworkPersistenceManager.NetworkPersistenceManager.instance();
120
116
 
121
- const binding = uiSourceCode && PersistenceImpl.instance().binding(uiSourceCode);
117
+ const binding = uiSourceCode && Persistence.Persistence.PersistenceImpl.instance().binding(uiSourceCode);
122
118
  const fileURL = binding ? binding.fileSystem.contentURL() : contentProvider.contentURL();
123
119
 
124
120
  if (Common.ParsedURL.schemeIs(fileURL, 'file:')) {
@@ -164,7 +160,7 @@ export class ContextMenuProvider implements
164
160
  private async handleOverrideContent(
165
161
  uiSourceCode: Workspace.UISourceCode.UISourceCode,
166
162
  contentProvider: TextUtils.ContentProvider.ContentProvider): Promise<void> {
167
- const networkPersistenceManager = NetworkPersistenceManager.instance();
163
+ const networkPersistenceManager = Persistence.NetworkPersistenceManager.NetworkPersistenceManager.instance();
168
164
  const isSuccess = await networkPersistenceManager.setupAndStartLocalOverrides(uiSourceCode);
169
165
  if (isSuccess) {
170
166
  await Common.Revealer.reveal(uiSourceCode);
@@ -16,6 +16,7 @@ import * as Tooltips from '../../ui/components/tooltips/tooltips.js';
16
16
  import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
17
17
  import * as UI from '../../ui/legacy/legacy.js';
18
18
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
19
+ import * as PanelCommon from '../common/common.js';
19
20
  import * as Snippets from '../snippets/snippets.js';
20
21
 
21
22
  import {SourcesView} from './SourcesView.js';
@@ -644,7 +645,7 @@ export class TabbedEditorContainer extends Common.ObjectWrapper.ObjectWrapper<Ev
644
645
  /* eslint-enable rulesdir/no-imperative-dom-api */
645
646
  this.tabbedPane.setSuffixElement(tabId, suffixElement);
646
647
  } else {
647
- const icon = Persistence.PersistenceUtils.PersistenceUtils.iconForUISourceCode(uiSourceCode);
648
+ const icon = PanelCommon.PersistenceUtils.PersistenceUtils.iconForUISourceCode(uiSourceCode);
648
649
  this.tabbedPane.setTrailingTabIcon(tabId, icon);
649
650
  }
650
651
  }