chrome-devtools-frontend 1.0.1530564 → 1.0.1531367

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.
@@ -531,7 +531,7 @@ export const Fast4GConditions: Conditions = {
531
531
  targetLatency: fast4GTargetLatency,
532
532
  };
533
533
 
534
- const MAX_EAGER_POST_REQUEST_BODY_LENGTH = 64 * 1024; // bytes
534
+ const MAX_EAGER_POST_REQUEST_BODY_LENGTH = 64 * 1024; // bytes
535
535
  const MAX_RESPONSE_BODY_TOTAL_BUFFER_LENGTH = 250 * 1024 * 1024; // bytes
536
536
 
537
537
  export class FetchDispatcher implements ProtocolProxyApi.FetchDispatcher {
@@ -1566,11 +1566,12 @@ export class NetworkDispatcher implements ProtocolProxyApi.NetworkDispatcher {
1566
1566
  }
1567
1567
  }
1568
1568
 
1569
- type RequestConditionsSetting = {
1569
+ export type RequestConditionsSetting = {
1570
1570
  url: string,
1571
1571
  enabled: boolean,
1572
1572
  }|{
1573
1573
  urlPattern: URLPatternConstructorString,
1574
+ conditions: ThrottlingConditionKey,
1574
1575
  enabled: boolean,
1575
1576
  };
1576
1577
 
@@ -1648,21 +1649,40 @@ export class RequestURLPattern {
1648
1649
  export class RequestCondition extends Common.ObjectWrapper.ObjectWrapper<RequestCondition.EventTypes> {
1649
1650
  #pattern: RequestURLPattern|{wildcardURL: string, upgradedPattern?: RequestURLPattern};
1650
1651
  #enabled: boolean;
1652
+ #conditions: ThrottlingConditions;
1651
1653
 
1652
- constructor(setting: RequestConditionsSetting) {
1653
- super();
1654
+ static createFromSetting(setting: RequestConditionsSetting): RequestCondition {
1654
1655
  if ('urlPattern' in setting) {
1655
- this.#pattern = RequestURLPattern.create(setting.urlPattern) ?? {
1656
+ const pattern = RequestURLPattern.create(setting.urlPattern) ?? {
1656
1657
  wildcardURL: setting.urlPattern,
1657
1658
  upgradedPattern: RequestURLPattern.upgradeFromWildcard(setting.urlPattern) ?? undefined,
1658
1659
  };
1659
- } else {
1660
- this.#pattern = {
1661
- wildcardURL: setting.url,
1662
- upgradedPattern: RequestURLPattern.upgradeFromWildcard(setting.url) ?? undefined
1663
- };
1660
+
1661
+ const conditions = getPredefinedOrBlockingCondition(setting.conditions) ??
1662
+ customUserNetworkConditionsSetting().get().find(condition => condition.key === setting.conditions) ??
1663
+ NoThrottlingConditions;
1664
+
1665
+ return new this(pattern, setting.enabled, conditions);
1664
1666
  }
1665
- this.#enabled = setting.enabled;
1667
+
1668
+ const pattern = {
1669
+ wildcardURL: setting.url,
1670
+ upgradedPattern: RequestURLPattern.upgradeFromWildcard(setting.url) ?? undefined
1671
+ };
1672
+ return new this(pattern, setting.enabled, BlockingConditions);
1673
+ }
1674
+
1675
+ static create(pattern: RequestURLPattern, conditions: ThrottlingConditions): RequestCondition {
1676
+ return new this(pattern, /* enabled=*/ true, conditions);
1677
+ }
1678
+
1679
+ private constructor(
1680
+ pattern: RequestURLPattern|{wildcardURL: string, upgradedPattern?: RequestURLPattern}, enabled: boolean,
1681
+ conditions: ThrottlingConditions) {
1682
+ super();
1683
+ this.#pattern = pattern;
1684
+ this.#enabled = enabled;
1685
+ this.#conditions = conditions;
1666
1686
  }
1667
1687
 
1668
1688
  get constructorString(): string|undefined {
@@ -1705,10 +1725,24 @@ export class RequestCondition extends Common.ObjectWrapper.ObjectWrapper<Request
1705
1725
  this.dispatchEventToListeners(RequestCondition.Events.REQUEST_CONDITION_CHANGED);
1706
1726
  }
1707
1727
 
1728
+ get conditions(): ThrottlingConditions {
1729
+ return this.#conditions;
1730
+ }
1731
+
1732
+ set conditions(conditions: ThrottlingConditions) {
1733
+ this.#conditions = conditions;
1734
+ this.dispatchEventToListeners(RequestCondition.Events.REQUEST_CONDITION_CHANGED);
1735
+ }
1736
+
1708
1737
  toSetting(): RequestConditionsSetting {
1709
1738
  const enabled = this.enabled;
1710
- return this.#pattern instanceof RequestURLPattern ? {enabled, urlPattern: this.#pattern.constructorString} :
1711
- {enabled, url: this.#pattern.wildcardURL};
1739
+ if (this.#pattern instanceof RequestURLPattern) {
1740
+ return {enabled, urlPattern: this.#pattern.constructorString, conditions: this.#conditions.key};
1741
+ }
1742
+ if (this.#conditions !== BlockingConditions && this.#pattern.upgradedPattern) {
1743
+ return {enabled, urlPattern: this.#pattern.upgradedPattern.constructorString, conditions: this.#conditions.key};
1744
+ }
1745
+ return {enabled, url: this.#pattern.wildcardURL};
1712
1746
  }
1713
1747
 
1714
1748
  get originalOrUpgradedURLPattern(): URLPattern|undefined {
@@ -1729,20 +1763,41 @@ export namespace RequestCondition {
1729
1763
  export class RequestConditions extends Common.ObjectWrapper.ObjectWrapper<RequestConditions.EventTypes> {
1730
1764
  readonly #setting =
1731
1765
  Common.Settings.Settings.instance().createSetting<RequestConditionsSetting[]>('network-blocked-patterns', []);
1732
- readonly #conditions: RequestCondition[];
1766
+ readonly #conditionsEnabledSetting =
1767
+ Common.Settings.Settings.instance().moduleSetting<boolean>('request-blocking-enabled');
1768
+ readonly #conditions: RequestCondition[] = [];
1733
1769
 
1734
1770
  constructor() {
1735
1771
  super();
1736
- this.#conditions = this.#setting.get().map(condition => new RequestCondition(condition));
1772
+ for (const condition of this.#setting.get()) {
1773
+ try {
1774
+ this.#conditions.push(RequestCondition.createFromSetting(condition));
1775
+ } catch (e) {
1776
+ console.error('Error loading throttling settings: ', e);
1777
+ }
1778
+ }
1737
1779
  for (const condition of this.#conditions) {
1738
1780
  condition.addEventListener(RequestCondition.Events.REQUEST_CONDITION_CHANGED, this.#conditionsChanged, this);
1739
1781
  }
1782
+ this.#conditionsEnabledSetting.addChangeListener(
1783
+ () => this.dispatchEventToListeners(RequestConditions.Events.REQUEST_CONDITIONS_CHANGED));
1740
1784
  }
1741
1785
 
1742
1786
  get count(): number {
1743
1787
  return this.#conditions.length;
1744
1788
  }
1745
1789
 
1790
+ get conditionsEnabled(): boolean {
1791
+ return this.#conditionsEnabledSetting.get();
1792
+ }
1793
+
1794
+ set conditionsEnabled(enabled: boolean) {
1795
+ if (this.#conditionsEnabledSetting.get() === enabled) {
1796
+ return;
1797
+ }
1798
+ this.#conditionsEnabledSetting.set(enabled);
1799
+ }
1800
+
1746
1801
  findCondition(pattern: string): RequestCondition|undefined {
1747
1802
  if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
1748
1803
  return this.#conditions.find(condition => condition.constructorString === pattern);
@@ -1756,6 +1811,9 @@ export class RequestConditions extends Common.ObjectWrapper.ObjectWrapper<Reques
1756
1811
 
1757
1812
  add(...conditions: RequestCondition[]): void {
1758
1813
  this.#conditions.push(...conditions);
1814
+ for (const condition of conditions) {
1815
+ condition.addEventListener(RequestCondition.Events.REQUEST_CONDITION_CHANGED, this.#conditionsChanged, this);
1816
+ }
1759
1817
  this.#conditionsChanged();
1760
1818
  }
1761
1819
 
@@ -1765,7 +1823,7 @@ export class RequestConditions extends Common.ObjectWrapper.ObjectWrapper<Reques
1765
1823
  return;
1766
1824
  }
1767
1825
  condition.removeEventListener(RequestCondition.Events.REQUEST_CONDITION_CHANGED, this.#conditionsChanged, this);
1768
- this.#conditions.splice(index);
1826
+ this.#conditions.splice(index, 1);
1769
1827
  this.#conditionsChanged();
1770
1828
  }
1771
1829
 
@@ -1786,18 +1844,69 @@ export class RequestConditions extends Common.ObjectWrapper.ObjectWrapper<Reques
1786
1844
  return this.#conditions.values();
1787
1845
  }
1788
1846
 
1789
- applyConditions(...agents: ProtocolProxyApi.NetworkApi[]): boolean {
1847
+ applyConditions(offline: boolean, globalConditions: Conditions|null, ...agents: ProtocolProxyApi.NetworkApi[]):
1848
+ boolean {
1849
+ function isNonBlockingCondition(condition: ThrottlingConditions): condition is Conditions {
1850
+ return !('block' in condition);
1851
+ }
1790
1852
  if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
1791
- const urlPatterns = this.#conditions.filter(condition => condition.enabled && condition.constructorString)
1792
- .map(condition => ({urlPattern: condition.constructorString as string, block: true}));
1853
+ const urlPatterns: Protocol.Network.BlockPattern[] = [];
1854
+ const matchedNetworkConditions: Protocol.Network.NetworkConditions[] = [];
1855
+ if (this.conditionsEnabled) {
1856
+ for (const condition of this.#conditions) {
1857
+ const urlPattern = condition.constructorString;
1858
+ const conditions = condition.conditions;
1859
+ if (!condition.enabled || !urlPattern || conditions === NoThrottlingConditions) {
1860
+ continue;
1861
+ }
1862
+ const block = !isNonBlockingCondition(conditions);
1863
+ urlPatterns.push({urlPattern, block});
1864
+ if (!block) {
1865
+ matchedNetworkConditions.push({
1866
+ urlPattern,
1867
+ latency: conditions.latency,
1868
+ downloadThroughput: conditions.download < 0 ? 0 : conditions.download,
1869
+ uploadThroughput: conditions.upload < 0 ? 0 : conditions.upload,
1870
+ packetLoss: (conditions.packetLoss ?? 0) < 0 ? 0 : conditions.packetLoss,
1871
+ packetQueueLength: conditions.packetQueueLength,
1872
+ packetReordering: conditions.packetReordering,
1873
+ connectionType: NetworkManager.connectionType(conditions),
1874
+ });
1875
+ }
1876
+ }
1877
+
1878
+ if (globalConditions) {
1879
+ matchedNetworkConditions.push({
1880
+ urlPattern: '',
1881
+ latency: globalConditions.latency,
1882
+ downloadThroughput: globalConditions.download < 0 ? 0 : globalConditions.download,
1883
+ uploadThroughput: globalConditions.upload < 0 ? 0 : globalConditions.upload,
1884
+ packetLoss: (globalConditions.packetLoss ?? 0) < 0 ? 0 : globalConditions.packetLoss,
1885
+ packetQueueLength: globalConditions.packetQueueLength,
1886
+ packetReordering: globalConditions.packetReordering,
1887
+ connectionType: NetworkManager.connectionType(globalConditions),
1888
+ });
1889
+ }
1890
+ }
1793
1891
 
1794
1892
  for (const agent of agents) {
1795
1893
  void agent.invoke_setBlockedURLs({urlPatterns});
1894
+ void agent.invoke_emulateNetworkConditionsByRule({offline, matchedNetworkConditions});
1895
+ void agent.invoke_overrideNetworkState({
1896
+ offline,
1897
+ latency: globalConditions?.latency ?? 0,
1898
+ downloadThroughput: !globalConditions || globalConditions.download < 0 ? 0 : globalConditions.download,
1899
+ uploadThroughput: !globalConditions || globalConditions.upload < 0 ? 0 : globalConditions.upload,
1900
+ });
1796
1901
  }
1797
1902
  return urlPatterns.length > 0;
1798
1903
  }
1799
- const urls = this.#conditions.filter(condition => condition.enabled && condition.wildcardURL)
1800
- .map(condition => condition.wildcardURL as string);
1904
+
1905
+ const urls = this.conditionsEnabled ?
1906
+ this.#conditions.filter(condition => condition.enabled && condition.wildcardURL)
1907
+ .map(condition => condition.wildcardURL as string) :
1908
+ [];
1909
+
1801
1910
  for (const agent of agents) {
1802
1911
  void agent.invoke_setBlockedURLs({urls});
1803
1912
  }
@@ -1826,8 +1935,6 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1826
1935
  readonly inflightMainResourceRequests = new Map<string, NetworkRequest>();
1827
1936
  #networkConditions: Conditions = NoThrottlingConditions;
1828
1937
  #updatingInterceptionPatternsPromise: Promise<void>|null = null;
1829
- readonly #blockingEnabledSetting =
1830
- Common.Settings.Settings.instance().moduleSetting<boolean>('request-blocking-enabled');
1831
1938
  readonly #requestConditions = new RequestConditions();
1832
1939
  readonly #urlsForRequestInterceptor:
1833
1940
  Platform.MapUtilities.Multimap<(arg0: InterceptedRequest) => Promise<void>, InterceptionPattern> =
@@ -1844,7 +1951,6 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1844
1951
  this.updateBlockedPatterns();
1845
1952
  this.dispatchEventToListeners(MultitargetNetworkManager.Events.BLOCKED_PATTERNS_CHANGED);
1846
1953
  };
1847
- this.#blockingEnabledSetting.addChangeListener(blockedPatternChanged);
1848
1954
  this.#requestConditions.addEventListener(
1849
1955
  RequestConditions.Events.REQUEST_CONDITIONS_CHANGED, blockedPatternChanged);
1850
1956
  this.updateBlockedPatterns();
@@ -1914,7 +2020,8 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1914
2020
  void networkAgent.invoke_setUserAgentOverride(
1915
2021
  {userAgent: this.currentUserAgent(), userAgentMetadata: this.#userAgentMetadataOverride || undefined});
1916
2022
  }
1917
- this.#requestConditions.applyConditions(networkAgent);
2023
+ this.#requestConditions.applyConditions(
2024
+ this.isOffline(), this.isThrottling() ? this.#networkConditions : null, networkAgent);
1918
2025
  if (this.isIntercepting()) {
1919
2026
  void fetchAgent.invoke_enable({patterns: this.#urlsForRequestInterceptor.valuesArray()});
1920
2027
  }
@@ -1925,7 +2032,7 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1925
2032
  }
1926
2033
  this.#networkAgents.add(networkAgent);
1927
2034
  this.#fetchAgents.add(fetchAgent);
1928
- if (this.isThrottling()) {
2035
+ if (this.isThrottling() && !Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
1929
2036
  this.updateNetworkConditions(networkAgent);
1930
2037
  }
1931
2038
  }
@@ -1953,8 +2060,13 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1953
2060
 
1954
2061
  setNetworkConditions(conditions: Conditions): void {
1955
2062
  this.#networkConditions = conditions;
1956
- for (const agent of this.#networkAgents) {
1957
- this.updateNetworkConditions(agent);
2063
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
2064
+ this.#requestConditions.applyConditions(
2065
+ this.isOffline(), this.isThrottling() ? this.#networkConditions : null, ...this.#networkAgents);
2066
+ } else {
2067
+ for (const agent of this.#networkAgents) {
2068
+ this.updateNetworkConditions(agent);
2069
+ }
1958
2070
  }
1959
2071
  this.dispatchEventToListeners(MultitargetNetworkManager.Events.CONDITIONS_CHANGED);
1960
2072
  }
@@ -2058,12 +2170,16 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
2058
2170
  return this.#requestConditions;
2059
2171
  }
2060
2172
 
2061
- blockingEnabled(): boolean {
2062
- return this.#blockingEnabledSetting.get();
2173
+ isBlocking(): boolean {
2174
+ return this.#isBlocking && this.requestConditions.conditionsEnabled;
2063
2175
  }
2064
2176
 
2065
- isBlocking(): boolean {
2066
- return this.#isBlocking && this.blockingEnabled();
2177
+ /**
2178
+ * @deprecated Kept for layout tests
2179
+ * TODO(pfaffe) remove
2180
+ */
2181
+ private setBlockingEnabled(enabled: boolean): void {
2182
+ this.requestConditions.conditionsEnabled = enabled;
2067
2183
  }
2068
2184
 
2069
2185
  /**
@@ -2072,18 +2188,12 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
2072
2188
  */
2073
2189
  private setBlockedPatterns(patterns: Array<{url: string, enabled: boolean}>): void {
2074
2190
  this.requestConditions.clear();
2075
- this.requestConditions.add(...patterns.map(pattern => new RequestCondition(pattern)));
2076
- }
2077
-
2078
- setBlockingEnabled(enabled: boolean): void {
2079
- if (this.#blockingEnabledSetting.get() === enabled) {
2080
- return;
2081
- }
2082
- this.#blockingEnabledSetting.set(enabled);
2191
+ this.requestConditions.add(...patterns.map(pattern => RequestCondition.createFromSetting(pattern)));
2083
2192
  }
2084
2193
 
2085
2194
  private updateBlockedPatterns(): void {
2086
- this.#isBlocking = this.#requestConditions.applyConditions(...this.#networkAgents);
2195
+ this.#isBlocking = this.#requestConditions.applyConditions(
2196
+ this.isOffline(), this.isThrottling() ? this.#networkConditions : null, ...this.#networkAgents);
2087
2197
  }
2088
2198
 
2089
2199
  isIntercepting(): boolean {
@@ -2544,6 +2654,10 @@ export function getPredefinedCondition(key: ThrottlingConditionKey): Conditions|
2544
2654
  return THROTTLING_CONDITIONS_LOOKUP.get(key) ?? null;
2545
2655
  }
2546
2656
 
2657
+ export function getPredefinedOrBlockingCondition(key: ThrottlingConditionKey): ThrottlingConditions|null {
2658
+ return key === PredefinedThrottlingConditionKey.BLOCKING ? BlockingConditions : getPredefinedCondition(key);
2659
+ }
2660
+
2547
2661
  export type ThrottlingConditions = Conditions|{
2548
2662
  readonly key: ThrottlingConditionKey,
2549
2663
  block: true,
@@ -12,7 +12,7 @@ import type {CallFrame, ScopeChainEntry} from './DebuggerModel.js';
12
12
  import {scopeTreeForScript} from './ScopeTreeCache.js';
13
13
  import type {Script} from './Script.js';
14
14
  import {buildOriginalScopes, decodePastaRanges, type NamedFunctionRange} from './SourceMapFunctionRanges.js';
15
- import {SourceMapScopesInfo} from './SourceMapScopesInfo.js';
15
+ import {SourceMapScopesInfo, type TranslatedFrame} from './SourceMapScopesInfo.js';
16
16
 
17
17
  /**
18
18
  * Type of the base source map JSON object, which contains the sources and the mappings at the very least, plus
@@ -789,6 +789,11 @@ export class SourceMap {
789
789
  this.#ensureSourceMapProcessed();
790
790
  return this.#scopesInfo?.hasInlinedFrames(generatedLine, generatedColumn) ?? false;
791
791
  }
792
+
793
+ translateCallSite(generatedLine: number, generatedColumn: number): TranslatedFrame[] {
794
+ this.#ensureSourceMapProcessed();
795
+ return this.#scopesInfo?.translateCallSite(generatedLine, generatedColumn) ?? [];
796
+ }
792
797
  }
793
798
 
794
799
  const VLQ_BASE_SHIFT = 5;
@@ -113,6 +113,10 @@ export class SourceMapScopesInfo {
113
113
  */
114
114
  isOutlinedFrame(generatedLine: number, generatedColumn: number): boolean {
115
115
  const rangeChain = this.#findGeneratedRangeChain(generatedLine, generatedColumn);
116
+ return this.#isOutlinedFrame(rangeChain);
117
+ }
118
+
119
+ #isOutlinedFrame(rangeChain: ScopesCodec.GeneratedRange[]): boolean {
116
120
  for (let i = rangeChain.length - 1; i >= 0; --i) {
117
121
  if (rangeChain[i].isStackFrame) {
118
122
  return rangeChain[i].isHidden;
@@ -372,13 +376,7 @@ export class SourceMapScopesInfo {
372
376
  .at(-1);
373
377
  }
374
378
 
375
- // Walk the original scope chain outwards until we find a function.
376
- for (let originalScope = originalInnerMostScope; originalScope; originalScope = originalScope.parent) {
377
- if (originalScope.isStackFrame) {
378
- return originalScope.name ?? '';
379
- }
380
- }
381
- return null;
379
+ return this.#findFunctionNameInOriginalScopeChain(originalInnerMostScope) ?? null;
382
380
  }
383
381
 
384
382
  /**
@@ -404,6 +402,74 @@ export class SourceMapScopesInfo {
404
402
 
405
403
  return result;
406
404
  }
405
+
406
+ #findFunctionNameInOriginalScopeChain(innerOriginalScope: ScopesCodec.OriginalScope|undefined): string|null {
407
+ for (let originalScope = innerOriginalScope; originalScope; originalScope = originalScope.parent) {
408
+ if (originalScope.isStackFrame) {
409
+ return originalScope.name ?? '';
410
+ }
411
+ }
412
+ return null;
413
+ }
414
+
415
+ /**
416
+ * Returns one or more original stack frames for this single "raw frame" or call-site.
417
+ *
418
+ * @returns An empty array if no mapping at the call-site was found, or the resulting frames
419
+ * in top-to-bottom order in case of inlining.
420
+ * @throws If this range is marked "hidden". Outlining needs to be handled externally as
421
+ * outlined function segments in stack traces can span across bundles.
422
+ */
423
+ translateCallSite(generatedLine: number, generatedColumn: number): TranslatedFrame[] {
424
+ const rangeChain = this.#findGeneratedRangeChain(generatedLine, generatedColumn);
425
+ if (this.#isOutlinedFrame(rangeChain)) {
426
+ throw new Error('SourceMapScopesInfo is unable to translate an outlined function by itself');
427
+ }
428
+
429
+ const mapping = this.#sourceMap.findEntry(generatedLine, generatedColumn);
430
+ if (mapping?.sourceIndex === undefined) {
431
+ return [];
432
+ }
433
+
434
+ // The top-most frame is translated the same even if we have inlined functions.
435
+ const result: TranslatedFrame[] = [{
436
+ line: mapping.sourceLineNumber,
437
+ column: mapping.sourceColumnNumber,
438
+ name: this.findOriginalFunctionName({line: generatedLine, column: generatedColumn}) ?? undefined,
439
+ url: mapping.sourceURL,
440
+ }];
441
+
442
+ // Walk the range chain inside out until we find a generated function and for each inlined function add a frame.
443
+ for (let i = rangeChain.length - 1; i >= 0 && !rangeChain[i].isStackFrame; --i) {
444
+ const range = rangeChain[i];
445
+ if (!range.callSite) {
446
+ continue;
447
+ }
448
+
449
+ const originalScopeChain = this.#findOriginalScopeChain(range.callSite);
450
+ result.push({
451
+ line: range.callSite.line,
452
+ column: range.callSite.column,
453
+ name: this.#findFunctionNameInOriginalScopeChain(originalScopeChain.at(-1)) ?? undefined,
454
+ url: this.#sourceMap.sourceURLForSourceIndex(range.callSite.sourceIndex),
455
+ });
456
+ }
457
+
458
+ return result;
459
+ }
460
+ }
461
+
462
+ /**
463
+ * Represents a stack frame in original terms. It closely aligns with StackTrace.StackTrace.Frame,
464
+ * but since we can't import that type here we mirror it here somewhat.
465
+ *
466
+ * Equivalent to Pick<StackTrace.StackTrace.Frame, 'line'|'column'|'name'|'url'>.
467
+ */
468
+ export interface TranslatedFrame {
469
+ line: number;
470
+ column: number;
471
+ name?: string;
472
+ url?: Platform.DevToolsPath.UrlString;
407
473
  }
408
474
 
409
475
  /**
@@ -0,0 +1,4 @@
1
+ Title: PerformanceTraceFormatter serializeBounds works
2
+ Content:
3
+ {min: 1, max: 2}
4
+ === end content
@@ -296,28 +296,30 @@ export class CompilerScriptMapping implements DebuggerSourceMapping {
296
296
  const {sourceMap, script} = sourceMapAndScript;
297
297
  const {lineNumber, columnNumber} = script.relativeLocationToRawLocation(frame);
298
298
 
299
- if (!sourceMap.hasInlinedFrames(lineNumber, columnNumber) && !sourceMap.isOutlinedFrame(lineNumber, columnNumber)) {
300
- // No outlining or inlining: Get the original function name and map the call-site.
301
- const mapping = sourceMap.findEntry(lineNumber, columnNumber);
302
- if (!mapping?.sourceURL) {
299
+ if (!sourceMap.isOutlinedFrame(lineNumber, columnNumber)) {
300
+ const frames = sourceMap.translateCallSite(lineNumber, columnNumber);
301
+ if (!frames.length) {
303
302
  return false;
304
303
  }
305
304
 
306
- const originalName = sourceMap.findOriginalFunctionName({line: lineNumber, column: columnNumber});
307
305
  rawFrames.shift();
306
+ const result: typeof translatedFrames[0] = [];
307
+ translatedFrames.push(result);
308
+
308
309
  const project = this.#sourceMapToProject.get(sourceMap);
309
- const uiSourceCode = project?.uiSourceCodeForURL(mapping.sourceURL);
310
- translatedFrames.push([{
311
- line: mapping.sourceLineNumber,
312
- column: mapping.sourceColumnNumber,
313
- name: originalName ?? undefined,
314
- uiSourceCode: uiSourceCode ?? undefined,
315
- url: uiSourceCode ? undefined : mapping.sourceURL
316
- }]);
310
+ for (const frame of frames) {
311
+ // Switch out url for UISourceCode where we have it.
312
+ const uiSourceCode = frame.url ? project?.uiSourceCodeForURL(frame.url) : undefined;
313
+ result.push({
314
+ ...frame,
315
+ url: uiSourceCode ? undefined : frame.url,
316
+ uiSourceCode: uiSourceCode ?? undefined,
317
+ });
318
+ }
319
+
317
320
  return true;
318
321
  }
319
322
 
320
- // TODO(crbug.com/433162438): Expand inlined frames.
321
323
  // TODO(crbug.com/433162438): Consolidate outlined frames.
322
324
  return false;
323
325
  }
@@ -6041,7 +6041,13 @@ export const NativeFunctions = [
6041
6041
  },
6042
6042
  {
6043
6043
  name: "waitUntil",
6044
- signatures: [["f"]]
6044
+ signatures: [["f"]],
6045
+ receivers: ["ExtendableEvent"]
6046
+ },
6047
+ {
6048
+ name: "waitUntil",
6049
+ signatures: [["promise"]],
6050
+ receivers: ["ViewTransition"]
6045
6051
  },
6046
6052
  {
6047
6053
  name: "respondWith",
@@ -1187,7 +1187,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1187
1187
 
1188
1188
  contextMenu.defaultSection().appendCheckboxItem(title, () => {
1189
1189
  void this.#openHistoricConversation(conversation);
1190
- }, {checked: (this.#conversation === conversation)});
1190
+ }, {checked: (this.#conversation === conversation), jslogContext: 'freestyler.history-item'});
1191
1191
  }
1192
1192
 
1193
1193
  const historyEmpty = contextMenu.defaultSection().items.length === 0;
@@ -61,6 +61,10 @@ const UIStringsNotTranslate = {
61
61
  * @description Header text during loading state while an AI summary is being generated
62
62
  */
63
63
  summarizing: 'Summarizing…',
64
+ /**
65
+ * @description Header text during longer lasting loading state while an AI summary is being generated
66
+ */
67
+ summarizingTakesABitLonger: 'Summarizing takes a bit longer…',
64
68
  /**
65
69
  * @description Label for an animation shown while an AI response is being generated
66
70
  */
@@ -77,6 +81,10 @@ const UIStringsNotTranslate = {
77
81
  * @description Aria-label for an infor-button triggering a tooltip with more info about data usage
78
82
  */
79
83
  learnDataUsage: 'Learn more about how your data is used',
84
+ /**
85
+ * @description Header text if there was an error during AI summary generation
86
+ */
87
+ summaryNotAvailable: 'Summary not available',
80
88
  } as const;
81
89
 
82
90
  const lockedString = i18n.i18n.lockedString;
@@ -84,6 +92,7 @@ const lockedString = i18n.i18n.lockedString;
84
92
  const CODE_SNIPPET_WARNING_URL = 'https://support.google.com/legal/answer/13505487';
85
93
  const DATA_USAGE_URL = 'https://developer.chrome.com/docs/devtools/ai-assistance/get-started#data-use';
86
94
  const EXPLAIN_TEASER_ACTION_ID = 'explain.console-message.teaser';
95
+ const SLOW_GENERATION_CUTOFF_MILLISECONDS = 3500;
87
96
 
88
97
  interface ViewInput {
89
98
  onTellMeMoreClick: (event: Event) => void;
@@ -95,6 +104,8 @@ interface ViewInput {
95
104
  isInactive: boolean;
96
105
  dontShowChanged: (e: Event) => void;
97
106
  hasTellMeMoreButton: boolean;
107
+ isSlowGeneration: boolean;
108
+ isError: boolean;
98
109
  }
99
110
 
100
111
  export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLElement): void => {
@@ -104,6 +115,51 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
104
115
  }
105
116
 
106
117
  const showPlaceholder = !Boolean(input.mainText);
118
+ const renderFooter = (): Lit.LitTemplate => {
119
+ // clang-format off
120
+ return html`
121
+ <div class="tooltip-footer">
122
+ ${input.hasTellMeMoreButton ? html`
123
+ <devtools-button
124
+ title=${lockedString(UIStringsNotTranslate.tellMeMore)}
125
+ .jslogContext=${'insights-teaser-tell-me-more'},
126
+ .variant=${Buttons.Button.Variant.PRIMARY}
127
+ @click=${input.onTellMeMoreClick}
128
+ >
129
+ <devtools-icon class="lightbulb-icon" name="lightbulb-spark"></devtools-icon>
130
+ ${lockedString(UIStringsNotTranslate.tellMeMore)}
131
+ </devtools-button>
132
+ ` : Lit.nothing}
133
+ ${showPlaceholder ? Lit.nothing : html`
134
+ <devtools-button
135
+ .iconName=${'info'}
136
+ .variant=${Buttons.Button.Variant.ICON}
137
+ aria-details=${'teaser-info-tooltip-' + input.uuid}
138
+ aria-label=${lockedString(UIStringsNotTranslate.learnDataUsage)}
139
+ ></devtools-button>
140
+ <devtools-tooltip id=${'teaser-info-tooltip-' + input.uuid} variant="rich">
141
+ <div class="info-tooltip-text">${lockedString(UIStringsNotTranslate.infoTooltipText)}</div>
142
+ <div class="learn-more">
143
+ <x-link
144
+ class="devtools-link"
145
+ title=${lockedString(UIStringsNotTranslate.learnMoreAboutAiSummaries)}
146
+ href=${DATA_USAGE_URL}
147
+ jslog=${VisualLogging.link().track({click: true, keydown:'Enter|Space'}).context('explain.teaser.learn-more')}
148
+ >${lockedString(UIStringsNotTranslate.learnMoreAboutAiSummaries)}</x-link>
149
+ </div>
150
+ </devtools-tooltip>
151
+ `}
152
+ <devtools-checkbox
153
+ aria-label=${lockedString(UIStringsNotTranslate.dontShow)}
154
+ @change=${input.dontShowChanged}
155
+ jslog=${VisualLogging.toggle('explain.teaser.dont-show').track({ change: true })}>
156
+ ${lockedString(UIStringsNotTranslate.dontShow)}
157
+ </devtools-checkbox>
158
+ </div>
159
+ `;
160
+ // clang-format on
161
+ };
162
+
107
163
  // clang-format off
108
164
  render(html`
109
165
  <style>${consoleInsightTeaserStyles}</style>
@@ -115,64 +171,36 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
115
171
  prefer-span-left
116
172
  >
117
173
  <div class="teaser-tooltip-container">
118
- ${showPlaceholder ? html`
119
- <h2>${lockedString(UIStringsNotTranslate.summarizing)}</h2>
120
- <div
121
- role="presentation"
122
- aria-label=${lockedString(UIStringsNotTranslate.loading)}
123
- class="loader"
124
- style="clip-path: url(${'#clipPath-' + input.uuid});"
125
- >
126
- <svg width="100%" height="52">
127
- <defs>
128
- <clipPath id=${'clipPath-' + input.uuid}>
129
- <rect x="0" y="0" width="100%" height="12" rx="8"></rect>
130
- <rect x="0" y="20" width="100%" height="12" rx="8"></rect>
131
- <rect x="0" y="40" width="100%" height="12" rx="8"></rect>
132
- </clipPath>
133
- </defs>
134
- </svg>
135
- </div>
136
- ` : html`
137
- <h2>${input.headerText}</h2>
138
- <div>${input.mainText}</div>
139
- <div class="tooltip-footer">
140
- ${input.hasTellMeMoreButton ? html`
141
- <devtools-button
142
- title=${lockedString(UIStringsNotTranslate.tellMeMore)}
143
- .jslogContext=${'insights-teaser-tell-me-more'},
144
- .variant=${Buttons.Button.Variant.PRIMARY}
145
- @click=${input.onTellMeMoreClick}
146
- >
147
- <devtools-icon class="lightbulb-icon" name="lightbulb-spark"></devtools-icon>
148
- ${lockedString(UIStringsNotTranslate.tellMeMore)}
149
- </devtools-button>
150
- ` : Lit.nothing}
151
- <devtools-button
152
- .iconName=${'info'}
153
- .variant=${Buttons.Button.Variant.ICON}
154
- aria-details=${'teaser-info-tooltip-' + input.uuid}
155
- aria-label=${lockedString(UIStringsNotTranslate.learnDataUsage)}
156
- ></devtools-button>
157
- <devtools-tooltip id=${'teaser-info-tooltip-' + input.uuid} variant="rich">
158
- <div class="info-tooltip-text">${lockedString(UIStringsNotTranslate.infoTooltipText)}</div>
159
- <div class="learn-more">
160
- <x-link
161
- class="devtools-link"
162
- title=${lockedString(UIStringsNotTranslate.learnMoreAboutAiSummaries)}
163
- href=${DATA_USAGE_URL}
164
- jslog=${VisualLogging.link().track({click: true, keydown:'Enter|Space'}).context('explain.teaser.learn-more')}
165
- >${lockedString(UIStringsNotTranslate.learnMoreAboutAiSummaries)}</x-link>
166
- </div>
167
- </devtools-tooltip>
168
- <devtools-checkbox
169
- aria-label=${lockedString(UIStringsNotTranslate.dontShow)}
170
- @change=${input.dontShowChanged}
171
- jslog=${VisualLogging.toggle('explain.teaser.dont-show').track({ change: true })}>
172
- ${lockedString(UIStringsNotTranslate.dontShow)}
173
- </devtools-checkbox>
174
- </div>
175
- `}
174
+ ${input.isError ? html`
175
+ <h2>${lockedString(UIStringsNotTranslate.summaryNotAvailable)}</h2>
176
+ ` :
177
+ showPlaceholder ? html`
178
+ <h2>${input.isSlowGeneration ?
179
+ lockedString(UIStringsNotTranslate.summarizingTakesABitLonger) :
180
+ lockedString(UIStringsNotTranslate.summarizing)
181
+ }</h2>
182
+ <div
183
+ role="presentation"
184
+ aria-label=${lockedString(UIStringsNotTranslate.loading)}
185
+ class="loader"
186
+ style="clip-path: url(${'#clipPath-' + input.uuid});"
187
+ >
188
+ <svg width="100%" height="52">
189
+ <defs>
190
+ <clipPath id=${'clipPath-' + input.uuid}>
191
+ <rect x="0" y="0" width="100%" height="12" rx="8"></rect>
192
+ <rect x="0" y="20" width="100%" height="12" rx="8"></rect>
193
+ <rect x="0" y="40" width="100%" height="12" rx="8"></rect>
194
+ </clipPath>
195
+ </defs>
196
+ </svg>
197
+ </div>
198
+ ` : html`
199
+ <h2>${input.headerText}</h2>
200
+ <div>${input.mainText}</div>
201
+ `
202
+ }
203
+ ${input.isError || input.isSlowGeneration || !showPlaceholder ? renderFooter() : Lit.nothing}
176
204
  </div>
177
205
  </devtools-tooltip>
178
206
  `, target);
@@ -192,6 +220,9 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
192
220
  #consoleViewMessage: ConsoleViewMessage;
193
221
  #isInactive = false;
194
222
  #abortController: null|AbortController = null;
223
+ #isSlow = false;
224
+ #timeoutId: ReturnType<typeof setTimeout>|null = null;
225
+ #isError = false;
195
226
 
196
227
  constructor(uuid: string, consoleViewMessage: ConsoleViewMessage, element?: HTMLElement, view?: View) {
197
228
  super(element);
@@ -285,6 +316,9 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
285
316
  this.#abortController.abort();
286
317
  }
287
318
  this.#isGenerating = false;
319
+ if (this.#timeoutId) {
320
+ clearTimeout(this.#timeoutId);
321
+ }
288
322
  }
289
323
 
290
324
  setInactive(isInactive: boolean): void {
@@ -295,8 +329,14 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
295
329
  this.requestUpdate();
296
330
  }
297
331
 
332
+ #setSlow(): void {
333
+ this.#isSlow = true;
334
+ this.requestUpdate();
335
+ }
336
+
298
337
  async #generateTeaserText(): Promise<void> {
299
338
  this.#isGenerating = true;
339
+ this.#timeoutId = setTimeout(this.#setSlow.bind(this), SLOW_GENERATION_CUTOFF_MILLISECONDS);
300
340
  let teaserText = '';
301
341
  try {
302
342
  for await (const chunk of this.#getOnDeviceInsight()) {
@@ -306,12 +346,16 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
306
346
  // Ignore `AbortError` errors, which are thrown on mouse leave.
307
347
  if (err.name !== 'AbortError') {
308
348
  console.error(err.name, err.message);
349
+ this.#isError = true;
309
350
  }
310
351
  this.#isGenerating = false;
352
+ clearTimeout(this.#timeoutId);
353
+ this.requestUpdate();
311
354
  return;
312
355
  }
313
356
 
314
- // TODO(crbug.com/443618746): Add user-facing error message instead of staying in loading state
357
+ clearTimeout(this.#timeoutId);
358
+ this.#isGenerating = false;
315
359
  let responseObject = {
316
360
  header: null,
317
361
  explanation: null,
@@ -320,10 +364,15 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
320
364
  responseObject = JSON.parse(teaserText);
321
365
  } catch (err) {
322
366
  console.error(err.name, err.message);
367
+ this.#isError = true;
368
+ this.requestUpdate();
369
+ return;
323
370
  }
324
371
  this.#headerText = responseObject.header || '';
325
372
  this.#mainText = responseObject.explanation || '';
326
- this.#isGenerating = false;
373
+ if (!this.#headerText || !this.#mainText) {
374
+ this.#isError = true;
375
+ }
327
376
  this.requestUpdate();
328
377
  }
329
378
 
@@ -373,6 +422,8 @@ export class ConsoleInsightTeaser extends UI.Widget.Widget {
373
422
  !Common.Settings.Settings.instance().moduleSetting('console-insight-teasers-enabled').get(),
374
423
  dontShowChanged: this.#dontShowChanged.bind(this),
375
424
  hasTellMeMoreButton: this.#hasTellMeMoreButton(),
425
+ isSlowGeneration: this.#isSlow,
426
+ isError: this.#isError,
376
427
  },
377
428
  undefined, this.contentElement);
378
429
  }
@@ -52,7 +52,7 @@ const str_ = i18n.i18n.registerUIStrings('panels/console/ConsoleSidebar.ts', UIS
52
52
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
53
53
  const {render, html, nothing, Directives} = Lit;
54
54
 
55
- const enum GroupName {
55
+ export const enum GroupName {
56
56
  CONSOLE_API = 'user message',
57
57
  ALL = 'message',
58
58
  ERROR = 'error',
@@ -112,7 +112,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
112
112
  <ul role="group" hidden>
113
113
  ${group.urlGroups.values().map(urlGroup => html`
114
114
  <li
115
- ${Directives.ref(element => element && nodeFilterMap.set(element, group.filter))}
115
+ ${Directives.ref(element => element && nodeFilterMap.set(element, urlGroup.filter))}
116
116
  role="treeitem"
117
117
  ?selected=${urlGroup.filter === input.selectedFilter}
118
118
  title=${urlGroup.url ?? ''}>
@@ -126,7 +126,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
126
126
  target);
127
127
  };
128
128
 
129
- class ConsoleFilterGroup {
129
+ export class ConsoleFilterGroup {
130
130
  readonly urlGroups = new Map<string|null, {filter: ConsoleFilter, url: string|null, count: number}>();
131
131
  messageCount = 0;
132
132
  readonly name: GroupName;
@@ -17,6 +17,7 @@ import * as Buttons from '../../ui/components/buttons/buttons.js';
17
17
  import * as UI from '../../ui/legacy/legacy.js';
18
18
  import {Directives, html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
19
19
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
20
+ import * as MobileThrottling from '../mobile_throttling/mobile_throttling.js';
20
21
 
21
22
  import blockedURLsPaneStyles from './blockedURLsPane.css.js';
22
23
 
@@ -192,7 +193,7 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
192
193
  }
193
194
 
194
195
  override performUpdate(): void {
195
- const enabled = this.manager.blockingEnabled();
196
+ const enabled = this.manager.requestConditions.conditionsEnabled;
196
197
  this.list.element.classList.toggle('blocking-disabled', !enabled && Boolean(this.manager.requestConditions.count));
197
198
 
198
199
  const input: ViewInput = {
@@ -205,9 +206,11 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
205
206
  }
206
207
 
207
208
  addPattern(): void {
208
- this.manager.setBlockingEnabled(true);
209
+ this.manager.requestConditions.conditionsEnabled = true;
209
210
  this.list.addNewItem(
210
- 0, new SDK.NetworkManager.RequestCondition({url: Platform.DevToolsPath.EmptyUrlString, enabled: true}));
211
+ 0,
212
+ SDK.NetworkManager.RequestCondition.createFromSetting(
213
+ {url: Platform.DevToolsPath.EmptyUrlString, enabled: true}));
211
214
  }
212
215
 
213
216
  removeAllPatterns(): void {
@@ -224,6 +227,11 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
224
227
  condition.enabled = !condition.enabled;
225
228
  }
226
229
  };
230
+ const onConditionsChanged = (conditions: SDK.NetworkManager.ThrottlingConditions): void => {
231
+ if (editable) {
232
+ condition.conditions = conditions;
233
+ }
234
+ };
227
235
 
228
236
  const {enabled, originalOrUpgradedURLPattern, constructorStringOrWildcardURL, wildcardURL} = condition;
229
237
 
@@ -237,6 +245,17 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
237
245
  ?checked=${enabled}
238
246
  ?disabled=${!editable || !originalOrUpgradedURLPattern}
239
247
  .jslog=${VisualLogging.toggle().track({ change: true })}>
248
+ <devtools-widget
249
+ class=conditions-selector
250
+ ?disabled=${!editable}
251
+ .widgetConfig=${UI.Widget.widgetConfig(
252
+ MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelectorWidget, {
253
+ variant:
254
+ MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelect.Variant.INDIVIDUAL_REQUEST_CONDITIONS,
255
+ jslogContext: 'request-conditions',
256
+ onConditionsChanged,
257
+ currentConditions: condition.conditions,
258
+ })}></devtools-widget>
240
259
  ${originalOrUpgradedURLPattern ? html`
241
260
  <devtools-tooltip variant=rich jslogcontext=url-pattern id=url-pattern-${index}>
242
261
  <div>hash: ${originalOrUpgradedURLPattern.hash}</div>
@@ -267,7 +286,12 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
267
286
  : i18nString(UIStrings.patternFailedToParse)}
268
287
  ${learnMore()}
269
288
  </devtools-tooltip>`: nothing}
270
- <div @click=${toggle} class=blocked-url-label aria-details=url-pattern-${index}>${constructorStringOrWildcardURL}</div>
289
+ <div
290
+ @click=${toggle}
291
+ class=blocked-url-label
292
+ aria-details=url-pattern-${index}>
293
+ ${constructorStringOrWildcardURL}
294
+ </div>
271
295
  <div class=blocked-url-count>${i18nString(UIStrings.dBlocked, {PH1: count})}</div>`,
272
296
  // clang-format on
273
297
  element);
@@ -290,7 +314,7 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
290
314
  }
291
315
 
292
316
  private toggleEnabled(): void {
293
- this.manager.setBlockingEnabled(!this.manager.blockingEnabled());
317
+ this.manager.requestConditions.conditionsEnabled = !this.manager.requestConditions.conditionsEnabled;
294
318
  this.update();
295
319
  }
296
320
 
@@ -368,7 +392,7 @@ export class BlockedURLsPane extends UI.Widget.VBox implements
368
392
  }
369
393
 
370
394
  update(): void {
371
- const enabled = this.manager.blockingEnabled();
395
+ const enabled = this.manager.requestConditions.conditionsEnabled;
372
396
  this.list.clear();
373
397
  for (const pattern of this.manager.requestConditions.conditions) {
374
398
  if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled || pattern.wildcardURL) {
@@ -432,6 +432,27 @@ const UIStrings = {
432
432
  * @description A context menu item in the Network Log View of the Network panel
433
433
  */
434
434
  clearBrowserCookies: 'Clear browser cookies',
435
+ /**
436
+ * @description A context menu item in the Network Log View of the Network panel
437
+ */
438
+ throttleRequests: 'Throttle requests',
439
+ /**
440
+ * @description A context menu item in the Network Log View of the Network panel
441
+ */
442
+ throttleRequestUrl: 'Throttle request URL',
443
+ /**
444
+ * @description A context menu item in the Network Log View of the Network panel
445
+ * @example {example.com} PH1
446
+ */
447
+ unthrottleS: 'Stop throttling {PH1}',
448
+ /**
449
+ * @description A context menu item in the Network Log View of the Network panel
450
+ */
451
+ throttleRequestDomain: 'Throttle request domain',
452
+ /**
453
+ * @description A context menu item in the Network Log View of the Network panel
454
+ */
455
+ blockRequests: 'Block requests',
435
456
  /**
436
457
  * @description A context menu item in the Network Log View of the Network panel
437
458
  */
@@ -1849,43 +1870,124 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
1849
1870
  const maxBlockedURLLength = 20;
1850
1871
  const manager = SDK.NetworkManager.MultitargetNetworkManager.instance();
1851
1872
 
1852
- function addBlockedURL(url: string): void {
1853
- manager.requestConditions.add(
1854
- new SDK.NetworkManager.RequestCondition({enabled: true, url: url as Platform.DevToolsPath.UrlString}));
1855
- manager.setBlockingEnabled(true);
1856
- void UI.ViewManager.ViewManager.instance().showView('network.blocked-urls');
1857
- }
1873
+ if (!Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
1874
+ function addBlockedURL(url: string): void {
1875
+ manager.requestConditions.add(SDK.NetworkManager.RequestCondition.createFromSetting(
1876
+ {enabled: true, url: url as Platform.DevToolsPath.UrlString}));
1877
+ manager.requestConditions.conditionsEnabled = true;
1878
+ void UI.ViewManager.ViewManager.instance().showView('network.blocked-urls');
1879
+ }
1858
1880
 
1859
- function removeBlockedURL(url: string): void {
1860
- const entry = manager.requestConditions.findCondition(url);
1861
- if (entry) {
1862
- manager.requestConditions.delete(entry);
1881
+ function removeBlockedURL(url: string): void {
1882
+ const entry = manager.requestConditions.findCondition(url);
1883
+ if (entry) {
1884
+ manager.requestConditions.delete(entry);
1885
+ }
1886
+ void UI.ViewManager.ViewManager.instance().showView('network.blocked-urls');
1863
1887
  }
1864
- void UI.ViewManager.ViewManager.instance().showView('network.blocked-urls');
1865
- }
1866
1888
 
1867
- const urlWithoutScheme = request.parsedURL.urlWithoutScheme();
1868
- if (urlWithoutScheme && !manager.requestConditions.has(urlWithoutScheme)) {
1869
- contextMenu.debugSection().appendItem(
1870
- i18nString(UIStrings.blockRequestUrl), addBlockedURL.bind(null, urlWithoutScheme),
1871
- {jslogContext: 'block-request-url'});
1872
- } else if (urlWithoutScheme) {
1873
- const croppedURL = Platform.StringUtilities.trimMiddle(urlWithoutScheme, maxBlockedURLLength);
1874
- contextMenu.debugSection().appendItem(
1875
- i18nString(UIStrings.unblockS, {PH1: croppedURL}), removeBlockedURL.bind(null, urlWithoutScheme),
1876
- {jslogContext: 'unblock'});
1877
- }
1889
+ const urlWithoutScheme = request.parsedURL.urlWithoutScheme();
1890
+ if (urlWithoutScheme && !manager.requestConditions.has(urlWithoutScheme)) {
1891
+ contextMenu.debugSection().appendItem(
1892
+ i18nString(UIStrings.blockRequestUrl), addBlockedURL.bind(null, urlWithoutScheme),
1893
+ {jslogContext: 'block-request-url'});
1894
+ } else if (urlWithoutScheme) {
1895
+ const croppedURL = Platform.StringUtilities.trimMiddle(urlWithoutScheme, maxBlockedURLLength);
1896
+ contextMenu.debugSection().appendItem(
1897
+ i18nString(UIStrings.unblockS, {PH1: croppedURL}), removeBlockedURL.bind(null, urlWithoutScheme),
1898
+ {jslogContext: 'unblock'});
1899
+ }
1878
1900
 
1879
- const domain = request.parsedURL.domain();
1880
- if (domain && !manager.requestConditions.has(domain)) {
1881
- contextMenu.debugSection().appendItem(
1882
- i18nString(UIStrings.blockRequestDomain), addBlockedURL.bind(null, domain),
1883
- {jslogContext: 'block-request-domain'});
1884
- } else if (domain) {
1885
- const croppedDomain = Platform.StringUtilities.trimMiddle(domain, maxBlockedURLLength);
1886
- contextMenu.debugSection().appendItem(
1887
- i18nString(UIStrings.unblockS, {PH1: croppedDomain}), removeBlockedURL.bind(null, domain),
1888
- {jslogContext: 'unblock'});
1901
+ const domain = request.parsedURL.domain();
1902
+ if (domain && !manager.requestConditions.has(domain)) {
1903
+ contextMenu.debugSection().appendItem(
1904
+ i18nString(UIStrings.blockRequestDomain), addBlockedURL.bind(null, domain),
1905
+ {jslogContext: 'block-request-domain'});
1906
+ } else if (domain) {
1907
+ const croppedDomain = Platform.StringUtilities.trimMiddle(domain, maxBlockedURLLength);
1908
+ contextMenu.debugSection().appendItem(
1909
+ i18nString(UIStrings.unblockS, {PH1: croppedDomain}), removeBlockedURL.bind(null, domain),
1910
+ {jslogContext: 'unblock'});
1911
+ }
1912
+ } else {
1913
+ function removeRequestCondition(pattern: SDK.NetworkManager.RequestURLPattern): void {
1914
+ const entry = manager.requestConditions.findCondition(pattern.constructorString);
1915
+ if (entry) {
1916
+ manager.requestConditions.delete(entry);
1917
+ void UI.ViewManager.ViewManager.instance().showView('network.blocked-urls');
1918
+ }
1919
+ }
1920
+
1921
+ function addRequestCondition(
1922
+ pattern: SDK.NetworkManager.RequestURLPattern,
1923
+ conditions: SDK.NetworkManager.ThrottlingConditions,
1924
+ ): void {
1925
+ const entry = manager.requestConditions.findCondition(pattern.constructorString);
1926
+ if (entry) {
1927
+ entry.conditions = conditions;
1928
+ } else {
1929
+ manager.requestConditions.add(SDK.NetworkManager.RequestCondition.create(pattern, conditions));
1930
+ }
1931
+ manager.requestConditions.conditionsEnabled = true;
1932
+ void UI.ViewManager.ViewManager.instance().showView('network.blocked-urls');
1933
+ }
1934
+
1935
+ const blockingMenu =
1936
+ contextMenu.debugSection().appendSubMenuItem(i18nString(UIStrings.blockRequests), /* disabled=*/ true);
1937
+ const throttlingMenu =
1938
+ contextMenu.debugSection().appendSubMenuItem(i18nString(UIStrings.throttleRequests), /* disabled=*/ true);
1939
+
1940
+ const urlWithoutScheme = request.parsedURL.urlWithoutScheme();
1941
+ const urlPattern = urlWithoutScheme &&
1942
+ SDK.NetworkManager.RequestURLPattern.create(
1943
+ `*://${urlWithoutScheme}` as SDK.NetworkManager.URLPatternConstructorString);
1944
+ if (urlPattern) {
1945
+ throttlingMenu.setEnabled(true);
1946
+ blockingMenu.setEnabled(true);
1947
+ const existingConditions = manager.requestConditions.findCondition(urlPattern.constructorString);
1948
+ const isBlocking = existingConditions?.conditions === SDK.NetworkManager.BlockingConditions;
1949
+ const isThrottling = existingConditions &&
1950
+ existingConditions.conditions !== SDK.NetworkManager.BlockingConditions &&
1951
+ existingConditions.conditions !== SDK.NetworkManager.NoThrottlingConditions;
1952
+ blockingMenu.debugSection().appendItem(
1953
+ isBlocking ? i18nString(UIStrings.unblockS, {PH1: urlPattern.constructorString}) :
1954
+ i18nString(UIStrings.blockRequestUrl),
1955
+ () => isBlocking ? removeRequestCondition(urlPattern) :
1956
+ addRequestCondition(urlPattern, SDK.NetworkManager.BlockingConditions),
1957
+ {jslogContext: 'block-request-url'});
1958
+ throttlingMenu.debugSection().appendItem(
1959
+ isThrottling ? i18nString(UIStrings.unthrottleS, {PH1: urlPattern.constructorString}) :
1960
+ i18nString(UIStrings.throttleRequestUrl),
1961
+ () => isThrottling ? removeRequestCondition(urlPattern) :
1962
+ addRequestCondition(urlPattern, SDK.NetworkManager.Slow3GConditions),
1963
+ {jslogContext: 'throttle-request-url'});
1964
+ }
1965
+
1966
+ const domain = request.parsedURL.domain();
1967
+ const domainPattern = domain &&
1968
+ SDK.NetworkManager.RequestURLPattern.create(
1969
+ `*://${domain}` as SDK.NetworkManager.URLPatternConstructorString);
1970
+ if (domainPattern) {
1971
+ throttlingMenu.setEnabled(true);
1972
+ blockingMenu.setEnabled(true);
1973
+ const existingConditions = manager.requestConditions.findCondition(domainPattern.constructorString);
1974
+ const isBlocking = existingConditions?.conditions === SDK.NetworkManager.BlockingConditions;
1975
+ const isThrottling = existingConditions &&
1976
+ existingConditions.conditions !== SDK.NetworkManager.BlockingConditions &&
1977
+ existingConditions.conditions !== SDK.NetworkManager.NoThrottlingConditions;
1978
+ blockingMenu.debugSection().appendItem(
1979
+ isBlocking ? i18nString(UIStrings.unblockS, {PH1: domainPattern.constructorString}) :
1980
+ i18nString(UIStrings.blockRequestDomain),
1981
+ () => isBlocking ? removeRequestCondition(domainPattern) :
1982
+ addRequestCondition(domainPattern, SDK.NetworkManager.BlockingConditions),
1983
+ {jslogContext: 'block-request-domain'});
1984
+ throttlingMenu.debugSection().appendItem(
1985
+ isThrottling ? i18nString(UIStrings.unthrottleS, {PH1: domainPattern.constructorString}) :
1986
+ i18nString(UIStrings.throttleRequestDomain),
1987
+ () => isThrottling ? removeRequestCondition(domainPattern) :
1988
+ addRequestCondition(domainPattern, SDK.NetworkManager.Slow3GConditions),
1989
+ {jslogContext: 'throttle-request-domain'});
1990
+ }
1889
1991
  }
1890
1992
 
1891
1993
  if (SDK.NetworkManager.NetworkManager.canReplayRequest(request)) {
@@ -74,3 +74,8 @@
74
74
  text-align: inherit;
75
75
  height: 22px;
76
76
  }
77
+
78
+ .conditions-selector {
79
+ max-width: 120px;
80
+ margin: var(--sys-size-3);
81
+ }
@@ -516,6 +516,7 @@ UI.ViewManager.registerViewExtension({
516
516
  title: i18nLazyString(UIStrings.workspace),
517
517
  order: 3,
518
518
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
519
+ condition: () => !Root.Runtime.Runtime.isTraceApp(),
519
520
  async loadView() {
520
521
  const Sources = await loadSourcesModule();
521
522
  return new Sources.SourcesNavigator.FilesNavigatorView();
@@ -1,7 +1,7 @@
1
1
  Name: Dependencies sourced from the upstream `chromium` repository
2
2
  URL: https://source.chromium.org/chromium/chromium/src/+/main:components/variations/proto/devtools/
3
3
  Version: N/A
4
- Revision: b8cee13d6f07e8bccc83905ddeccf1865b86b5e4
4
+ Revision: 8e79193039bf1dd9a37c1b3c443dd8159e02c194
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE
@@ -575,6 +575,7 @@ export const knownContextValues = new Set([
575
575
  'black-berry-play-book-2.1',
576
576
  'blackbox',
577
577
  'ble',
578
+ 'block',
578
579
  'block-ellipsis',
579
580
  'block-request-domain',
580
581
  'block-request-url',
@@ -1688,6 +1689,7 @@ export const knownContextValues = new Set([
1688
1689
  'freestyler.feedback',
1689
1690
  'freestyler.help',
1690
1691
  'freestyler.history',
1692
+ 'freestyler.history-item',
1691
1693
  'freestyler.main-menu',
1692
1694
  'freestyler.new-chat',
1693
1695
  'freestyler.send-feedback',
@@ -3082,6 +3084,7 @@ export const knownContextValues = new Set([
3082
3084
  'request-animation-frame.callback',
3083
3085
  'request-blocking-enabled',
3084
3086
  'request-blocking-enabled-true',
3087
+ 'request-conditions',
3085
3088
  'request-details',
3086
3089
  'request-header',
3087
3090
  'request-header-accept',
@@ -3745,6 +3748,8 @@ export const knownContextValues = new Set([
3745
3748
  'third-party-tree',
3746
3749
  'third-property',
3747
3750
  'this-origin',
3751
+ 'throttle-request-domain',
3752
+ 'throttle-request-url',
3748
3753
  'throttling-conditions',
3749
3754
  'throttling.calibrate',
3750
3755
  'throttling.calibrate-cancel',
package/package.json CHANGED
@@ -102,5 +102,5 @@
102
102
  "flat-cache": "6.1.12"
103
103
  }
104
104
  },
105
- "version": "1.0.1530564"
105
+ "version": "1.0.1531367"
106
106
  }