chrome-devtools-frontend 1.0.1581708 → 1.0.1583146

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 (73) hide show
  1. package/front_end/core/root/Runtime.ts +0 -5
  2. package/front_end/core/sdk/NetworkManager.ts +63 -115
  3. package/front_end/core/sdk/RemoteObject.ts +7 -1
  4. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +9 -24
  5. package/front_end/entrypoints/greendev_floaty/floaty.css +1 -1
  6. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +1 -1
  7. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  8. package/front_end/generated/SupportedCSSProperties.js +2 -0
  9. package/front_end/generated/protocol.ts +0 -6
  10. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +6 -6
  11. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +17 -9
  12. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +2 -6
  13. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +66 -2
  14. package/front_end/models/greendev/Prototypes.ts +1 -10
  15. package/front_end/models/issues_manager/ConnectionAllowlistIssue.ts +75 -0
  16. package/front_end/models/issues_manager/FederatedAuthRequestIssue.ts +0 -30
  17. package/front_end/models/issues_manager/IssuesManager.ts +5 -0
  18. package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidAllowlistItemType.md +12 -0
  19. package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidHeader.md +12 -0
  20. package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidUrlPattern.md +8 -0
  21. package/front_end/models/issues_manager/descriptions/connectionAllowlistItemNotInnerList.md +12 -0
  22. package/front_end/models/issues_manager/descriptions/connectionAllowlistMoreThanOneList.md +7 -0
  23. package/front_end/models/issues_manager/descriptions/connectionAllowlistReportingEndpointNotToken.md +10 -0
  24. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  25. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +22 -4
  26. package/front_end/panels/ai_assistance/components/ChatInput.ts +7 -3
  27. package/front_end/panels/ai_assistance/components/ChatMessage.ts +4 -2
  28. package/front_end/panels/application/preloading/PreloadingView.ts +8 -1
  29. package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +4 -1
  30. package/front_end/panels/application/preloading/components/PreloadingGrid.ts +2 -1
  31. package/front_end/panels/application/preloading/components/PreloadingString.ts +12 -3
  32. package/front_end/panels/application/preloading/helper/PreloadingForward.ts +14 -0
  33. package/front_end/panels/autofill/AutofillView.ts +4 -8
  34. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +37 -3
  35. package/front_end/panels/changes/ChangesSidebar.ts +2 -6
  36. package/front_end/panels/common/AiCodeGenerationTeaser.ts +27 -8
  37. package/front_end/panels/console/ConsoleSidebar.ts +3 -11
  38. package/front_end/panels/elements/ComputedStyleWidget.ts +41 -29
  39. package/front_end/panels/elements/ElementStatePaneWidget.ts +1 -1
  40. package/front_end/panels/elements/ElementsTreeElement.ts +487 -426
  41. package/front_end/panels/elements/EventListenersWidget.ts +2 -4
  42. package/front_end/panels/elements/PropertiesWidget.ts +1 -2
  43. package/front_end/panels/elements/StylePropertyTreeElement.ts +18 -2
  44. package/front_end/panels/elements/computedStyleWidget.css +30 -0
  45. package/front_end/panels/lighthouse/LighthouseStartView.ts +3 -5
  46. package/front_end/panels/lighthouse/lighthouseStartView.css +6 -0
  47. package/front_end/panels/network/NetworkLogView.ts +67 -108
  48. package/front_end/panels/network/RequestConditionsDrawer.ts +40 -131
  49. package/front_end/panels/network/RequestInitiatorView.ts +19 -8
  50. package/front_end/panels/network/network-meta.ts +4 -27
  51. package/front_end/panels/settings/AISettingsTab.ts +1 -5
  52. package/front_end/panels/settings/SettingsScreen.ts +0 -51
  53. package/front_end/panels/settings/WorkspaceSettingsTab.ts +1 -1
  54. package/front_end/panels/sources/CallStackSidebarPane.ts +2 -2
  55. package/front_end/panels/timeline/AnimationsTrackAppender.ts +4 -1
  56. package/front_end/panels/timeline/InteractionsTrackAppender.ts +1 -1
  57. package/front_end/panels/timeline/TimelineUIUtils.ts +13 -16
  58. package/front_end/third_party/chromium/README.chromium +1 -1
  59. package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +5 -1
  60. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +8 -0
  61. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +8 -0
  62. package/front_end/ui/components/text_editor/config.ts +6 -0
  63. package/front_end/ui/legacy/Toolbar.ts +16 -8
  64. package/front_end/ui/legacy/Treeoutline.ts +4 -4
  65. package/front_end/ui/legacy/UIUtils.ts +35 -4
  66. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +6 -11
  67. package/front_end/ui/legacy/components/utils/Linkifier.ts +4 -7
  68. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  69. package/package.json +1 -1
  70. package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataHttpNotFound.md +0 -1
  71. package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataInvalidResponse.md +0 -1
  72. package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataNoResponse.md +0 -1
  73. package/front_end/panels/elements/computedStyleSidebarPane.css +0 -18
@@ -3,6 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import type * as SDK from '../../../core/sdk/sdk.js';
6
+ import type * as Protocol from '../../../generated/protocol.js';
6
7
  import * as Annotations from '../../annotations/annotations.js';
7
8
  import * as Logs from '../../logs/logs.js';
8
9
  import * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
@@ -75,6 +76,51 @@ export class NetworkRequestFormatter {
75
76
  return '<redacted cross-origin initiator URL>';
76
77
  }
77
78
 
79
+ static formatStatus(status: {
80
+ statusCode: number,
81
+ statusText: string,
82
+ failed: boolean,
83
+ canceled: boolean,
84
+ preserved: boolean,
85
+ finished: boolean,
86
+ }): string {
87
+ let responseStatus = '';
88
+ if (status.statusCode) {
89
+ responseStatus = `Response status: ${status.statusCode} ${status.statusText}\n`;
90
+ }
91
+ const flags = [];
92
+ flags.push(status.finished ? 'finished' : 'pending');
93
+ if (status.failed) {
94
+ flags.push('failed');
95
+ }
96
+ if (status.canceled) {
97
+ flags.push('canceled');
98
+ }
99
+ if (status.preserved) {
100
+ flags.push('preserved');
101
+ }
102
+ const requestStatus = flags.length > 0 ? `Network request status: ${flags.join(', ')}\n` : '';
103
+ return `${responseStatus}${requestStatus}`;
104
+ }
105
+
106
+ static formatFailureReasons(reasons: {
107
+ blockedReason?: Protocol.Network.BlockedReason,
108
+ corsErrorStatus?: Protocol.Network.CorsErrorStatus,
109
+ localizedFailDescription?: string|null,
110
+ }): string {
111
+ const lines = [];
112
+ if (reasons.blockedReason) {
113
+ lines.push(`Blocked reason: ${reasons.blockedReason}`);
114
+ }
115
+ if (reasons.corsErrorStatus) {
116
+ lines.push(`CORS error: ${reasons.corsErrorStatus.corsError} ${reasons.corsErrorStatus.failedParameter}`);
117
+ }
118
+ if (reasons.localizedFailDescription) {
119
+ lines.push(`Fail description: ${reasons.localizedFailDescription}`);
120
+ }
121
+ return lines.length > 0 ? `${lines.join('\n')}\n` : '';
122
+ }
123
+
78
124
  constructor(
79
125
  request: SDK.NetworkRequest.NetworkRequest, calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator) {
80
126
  this.#request = request;
@@ -111,13 +157,31 @@ ${this.formatRequestHeaders()}
111
157
 
112
158
  ${this.formatResponseHeaders()}${responseBody}
113
159
 
114
- Response status: ${this.#request.statusCode} ${this.#request.statusText}
115
-
160
+ ${this.formatStatus()}${this.formatFailureReasons()}
116
161
  Request timing:\n${this.formatNetworkRequestTiming()}
117
162
 
118
163
  Request initiator chain:\n${this.formatRequestInitiatorChain()}`;
119
164
  }
120
165
 
166
+ formatStatus(): string {
167
+ return NetworkRequestFormatter.formatStatus({
168
+ statusCode: this.#request.statusCode,
169
+ statusText: this.#request.statusText,
170
+ failed: this.#request.failed,
171
+ canceled: this.#request.canceled,
172
+ preserved: this.#request.preserved,
173
+ finished: this.#request.finished,
174
+ });
175
+ }
176
+
177
+ formatFailureReasons(): string {
178
+ return NetworkRequestFormatter.formatFailureReasons({
179
+ blockedReason: this.#request.blockedReason(),
180
+ corsErrorStatus: this.#request.corsErrorStatus(),
181
+ localizedFailDescription: this.#request.localizedFailDescription,
182
+ });
183
+ }
184
+
121
185
  /**
122
186
  * Note: nothing here should include information from origins other than
123
187
  * the request's origin.
@@ -9,8 +9,6 @@ let instance: Prototypes|null = null;
9
9
 
10
10
  export interface GreenDevSettings {
11
11
  inDevToolsFloaty: Common.Settings.Setting<boolean>;
12
- inlineWidgets: Common.Settings.Setting<boolean>;
13
- artifactViewer: Common.Settings.Setting<boolean>;
14
12
  aiAnnotations: Common.Settings.Setting<boolean>;
15
13
  copyToGemini: Common.Settings.Setting<boolean>;
16
14
  }
@@ -41,21 +39,14 @@ export class Prototypes {
41
39
  const inDevToolsFloaty =
42
40
  settings.createSetting('greendev-in-devtools-floaty-enabled', false, Common.Settings.SettingStorageType.LOCAL);
43
41
 
44
- const inlineWidgets =
45
- settings.createSetting('greendev-inline-widgets-enabled', false, Common.Settings.SettingStorageType.LOCAL);
46
-
47
42
  const aiAnnotations = settings.createSetting(
48
43
  'greendev-ai-annotations-enabled',
49
44
  false,
50
45
  Common.Settings.SettingStorageType.LOCAL,
51
46
  );
52
-
53
- const artifactViewer =
54
- settings.createSetting('greendev-artifact-viewer-enabled', false, Common.Settings.SettingStorageType.LOCAL);
55
-
56
47
  const copyToGemini =
57
48
  settings.createSetting('greendev-copy-to-gemini-enabled', false, Common.Settings.SettingStorageType.LOCAL);
58
49
 
59
- return {inDevToolsFloaty, inlineWidgets, aiAnnotations, artifactViewer, copyToGemini};
50
+ return {inDevToolsFloaty, aiAnnotations, copyToGemini};
60
51
  }
61
52
  }
@@ -0,0 +1,75 @@
1
+ // Copyright 2026 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
+
5
+ import * as i18n from '../../core/i18n/i18n.js';
6
+ import type * as SDK from '../../core/sdk/sdk.js';
7
+ import * as Protocol from '../../generated/protocol.js';
8
+
9
+ import {Issue, IssueCategory, IssueKind} from './Issue.js';
10
+ import {
11
+ type LazyMarkdownIssueDescription,
12
+ type MarkdownIssueDescription,
13
+ resolveLazyDescription,
14
+ } from './MarkdownIssueDescription.js';
15
+
16
+ const UIStrings = {
17
+ /**
18
+ *@description Title for Connection-Allowlist specification url
19
+ */
20
+ connectionAllowlistHeader: 'Connection-Allowlist specification',
21
+ } as const;
22
+ const str_ = i18n.i18n.registerUIStrings('models/issues_manager/ConnectionAllowlistIssue.ts', UIStrings);
23
+ const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
24
+
25
+ export class ConnectionAllowlistIssue extends Issue<Protocol.Audits.ConnectionAllowlistIssueDetails> {
26
+ constructor(
27
+ issueDetails: Protocol.Audits.ConnectionAllowlistIssueDetails, issuesModel: SDK.IssuesModel.IssuesModel|null) {
28
+ super(
29
+ {
30
+ code: `${Protocol.Audits.InspectorIssueCode.ConnectionAllowlistIssue}::${issueDetails.error}`,
31
+ umaCode: `${Protocol.Audits.InspectorIssueCode.ConnectionAllowlistIssue}::${issueDetails.error}`,
32
+ },
33
+ issueDetails, issuesModel);
34
+ }
35
+
36
+ override primaryKey(): string {
37
+ return JSON.stringify(this.details());
38
+ }
39
+
40
+ override getDescription(): MarkdownIssueDescription|null {
41
+ const description: LazyMarkdownIssueDescription = {
42
+ file: `connectionAllowlist${this.details().error}.md`,
43
+ links: [
44
+ {
45
+ link: 'https://wicg.github.io/private-network-access/#connection-allowlist',
46
+ linkTitle: i18nLazyString(UIStrings.connectionAllowlistHeader),
47
+ },
48
+ ],
49
+ };
50
+ return resolveLazyDescription(description);
51
+ }
52
+
53
+ override getCategory(): IssueCategory {
54
+ return IssueCategory.OTHER;
55
+ }
56
+
57
+ override getKind(): IssueKind {
58
+ return IssueKind.PAGE_ERROR;
59
+ }
60
+
61
+ override requests(): Iterable<Protocol.Audits.AffectedRequest> {
62
+ return this.details().request ? [this.details().request] : [];
63
+ }
64
+
65
+ static fromInspectorIssue(
66
+ issuesModel: SDK.IssuesModel.IssuesModel|null,
67
+ inspectorIssue: Protocol.Audits.InspectorIssue): ConnectionAllowlistIssue[] {
68
+ const details = inspectorIssue.details.connectionAllowlistIssueDetails;
69
+ if (!details) {
70
+ console.warn('Connection-Allowlist issue without details received.');
71
+ return [];
72
+ }
73
+ return [new ConnectionAllowlistIssue(details, issuesModel)];
74
+ }
75
+ }
@@ -109,36 +109,6 @@ const issueDescriptions = new Map<Protocol.Audits.FederatedAuthRequestIssueReaso
109
109
  }],
110
110
  },
111
111
  ],
112
- [
113
- Protocol.Audits.FederatedAuthRequestIssueReason.ClientMetadataHttpNotFound,
114
- {
115
- file: 'federatedAuthRequestClientMetadataHttpNotFound.md',
116
- links: [{
117
- link: 'https://fedidcg.github.io/FedCM/',
118
- linkTitle: i18nLazyString(UIStrings.fedCm),
119
- }],
120
- },
121
- ],
122
- [
123
- Protocol.Audits.FederatedAuthRequestIssueReason.ClientMetadataNoResponse,
124
- {
125
- file: 'federatedAuthRequestClientMetadataNoResponse.md',
126
- links: [{
127
- link: 'https://fedidcg.github.io/FedCM/',
128
- linkTitle: i18nLazyString(UIStrings.fedCm),
129
- }],
130
- },
131
- ],
132
- [
133
- Protocol.Audits.FederatedAuthRequestIssueReason.ClientMetadataInvalidResponse,
134
- {
135
- file: 'federatedAuthRequestClientMetadataInvalidResponse.md',
136
- links: [{
137
- link: 'https://fedidcg.github.io/FedCM/',
138
- linkTitle: i18nLazyString(UIStrings.fedCm),
139
- }],
140
- },
141
- ],
142
112
  [
143
113
  Protocol.Audits.FederatedAuthRequestIssueReason.ErrorFetchingSignin,
144
114
  {
@@ -9,6 +9,7 @@ import * as Protocol from '../../generated/protocol.js';
9
9
  import {AttributionReportingIssue} from './AttributionReportingIssue.js';
10
10
  import {BounceTrackingIssue} from './BounceTrackingIssue.js';
11
11
  import {ClientHintIssue} from './ClientHintIssue.js';
12
+ import {ConnectionAllowlistIssue} from './ConnectionAllowlistIssue.js';
12
13
  import {ContentSecurityPolicyIssue} from './ContentSecurityPolicyIssue.js';
13
14
  import {CookieDeprecationMetadataIssue} from './CookieDeprecationMetadataIssue.js';
14
15
  import {CookieIssue} from './CookieIssue.js';
@@ -144,6 +145,10 @@ const issueCodeHandlers = new Map<
144
145
  Protocol.Audits.InspectorIssueCode.UnencodedDigestIssue,
145
146
  UnencodedDigestIssue.fromInspectorIssue,
146
147
  ],
148
+ [
149
+ Protocol.Audits.InspectorIssueCode.ConnectionAllowlistIssue,
150
+ ConnectionAllowlistIssue.fromInspectorIssue,
151
+ ],
147
152
  [
148
153
  Protocol.Audits.InspectorIssueCode.PermissionElementIssue,
149
154
  PermissionElementIssue.fromInspectorIssue,
@@ -0,0 +1,12 @@
1
+ # An item in the `Connection-Allowlist` header is invalid.
2
+
3
+ Each item in the `Connection-Allowlist`'s header's [Inner List](sfInnerList)
4
+ must be a [String](sfString) representing a [URL Pattern](urlPatternSpec), or
5
+ the [Token](sfToken) `response-origin`.
6
+
7
+ For example, the following header allows connections to (only)
8
+ `https://example.com/` and the origin from which the response was delivered:
9
+
10
+ ```
11
+ Connection-Allowlist: ("https://example.com" response-origin)
12
+ ```
@@ -0,0 +1,12 @@
1
+ # The `Connection-Allowlist` header is not formatted as a Structured Field List.
2
+
3
+ Responses' `Connection-Allowlist` header should be formatted as a [List](sfList)
4
+ containing a single [Inner List](sfInnerList) that declares the allowed set of
5
+ [URL Patterns](urlPatternSpec) for a given context.
6
+
7
+ For example, the following header allows connections to (only)
8
+ `https://example.com/`:
9
+
10
+ ```
11
+ Connection-Allowlist: ("https://example.com")
12
+ ```
@@ -0,0 +1,8 @@
1
+ # An item in the `Connection-Allowlist` header is not a valid URL pattern.
2
+
3
+ Each item in the `Connection-Allowlist` header must be a valid
4
+ [URL Pattern](urlPatternSpec) that can be used to match against the request's
5
+ origin.
6
+
7
+ Note that our current implementation does not allow regular expressions to be
8
+ used as part of the pattern.
@@ -0,0 +1,12 @@
1
+ # An item in the `Connection-Allowlist` header is not an Inner List.
2
+
3
+ Responses' `Connection-Allowlist` header should be formatted as a [List](sfList)
4
+ containing a single [Inner List](sfInnerList) that declares the allowed set of
5
+ [URL Patterns](urlPatternSpec) for a given context.
6
+
7
+ For example, the following header allows connections to (only)
8
+ `https://example.com/`:
9
+
10
+ ```
11
+ Connection-Allowlist: ("https://example.com")
12
+ ```
@@ -0,0 +1,7 @@
1
+ # `Connection-Allowlist` has multiple items.
2
+
3
+ Responses' `Connection-Allowlist` header should be formatted as a [List](sfList)
4
+ containing a single [Inner List](sfInnerList) that declares the allowed set of
5
+ [URL Patterns](urlPatternSpec) for a given context. This response was a
6
+ [List](sfList) containing more than one item: all but the first have been
7
+ ignored.
@@ -0,0 +1,10 @@
1
+ # The `report-to` parameter in the `Connection-Allowlist` header is not a token.
2
+
3
+ If provided, the `report-to` parameter must be a [Token](sfToken)
4
+ naming a reporting endpoint.
5
+
6
+ For example:
7
+
8
+ ```
9
+ Connection-Allowlist: ("https://example.com");report-to=endpoint
10
+ ```
@@ -5,6 +5,7 @@
5
5
  import * as AttributionReportingIssue from './AttributionReportingIssue.js';
6
6
  import * as CheckFormsIssuesTrigger from './CheckFormsIssuesTrigger.js';
7
7
  import * as ClientHintIssue from './ClientHintIssue.js';
8
+ import * as ConnectionAllowlistIssue from './ConnectionAllowlistIssue.js';
8
9
  import * as ContentSecurityPolicyIssue from './ContentSecurityPolicyIssue.js';
9
10
  import * as ContrastCheckTrigger from './ContrastCheckTrigger.js';
10
11
  import * as CookieDeprecationMetadataIssue from './CookieDeprecationMetadataIssue.js';
@@ -39,6 +40,7 @@ export {
39
40
  AttributionReportingIssue,
40
41
  CheckFormsIssuesTrigger,
41
42
  ClientHintIssue,
43
+ ConnectionAllowlistIssue,
42
44
  ContentSecurityPolicyIssue,
43
45
  ContrastCheckTrigger,
44
46
  CookieDeprecationMetadataIssue,
@@ -707,12 +707,24 @@ export class AiAssistancePanel extends UI.Panel.Panel {
707
707
  // We select the default agent based on the open panels if
708
708
  // there isn't any active conversation.
709
709
  #selectDefaultAgentIfNeeded(): void {
710
+ // We don't change the current agent when there is a message in flight.
711
+ if (this.#isLoading) {
712
+ return;
713
+ }
714
+
710
715
  // If there already is an agent and if it is not empty,
711
- // we don't automatically change the agent. In addition to this,
712
- // we don't change the current agent when there is a message in flight.
713
- if ((this.#conversation && !this.#conversation.isEmpty) || this.#isLoading) {
716
+ // we don't automatically change the agent.
717
+ if (this.#conversation && !this.#conversation.isEmpty) {
718
+ // If the context selection agent is enabled,
719
+ // we update the context of the current agent.
720
+ const context = this.#getConversationContext(this.#getDefaultConversationType());
721
+ if (context && isAiAssistanceContextSelectionAgentEnabled()) {
722
+ this.#conversation?.setContext(context);
723
+ this.requestUpdate();
724
+ }
714
725
  return;
715
726
  }
727
+
716
728
  const targetConversationType = this.#getDefaultConversationType();
717
729
  if (this.#conversation?.type === targetConversationType) {
718
730
  // The above if makes sure even if we have an active agent it's empty
@@ -1417,7 +1429,13 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1417
1429
  });
1418
1430
 
1419
1431
  void this.#toggleSearchElementAction.execute();
1420
- return await result;
1432
+ try {
1433
+ return await result;
1434
+ } finally {
1435
+ if (this.#toggleSearchElementAction.toggled()) {
1436
+ void this.#toggleSearchElementAction.execute();
1437
+ }
1438
+ }
1421
1439
  }
1422
1440
 
1423
1441
  async #startConversation(
@@ -42,7 +42,11 @@ const UIStrings = {
42
42
  /**
43
43
  * @description Label added to the button that remove the currently selected context in AI Assistance panel.
44
44
  */
45
- removeContext: 'Remove selected context',
45
+ removeContext: 'Remove from context',
46
+ /**
47
+ * @description Label added to the button that add selected context from the current panel in AI Assistance panel.
48
+ */
49
+ addContext: 'Add selected item as context',
46
50
  } as const;
47
51
 
48
52
  /*
@@ -387,8 +391,8 @@ export const
387
391
  :
388
392
  input.onContextAdd ? html`
389
393
  <devtools-button
390
- title=${i18nString(UIStrings.removeContext)}
391
- aria-label=${i18nString(UIStrings.removeContext)}
394
+ title=${i18nString(UIStrings.addContext)}
395
+ aria-label=${i18nString(UIStrings.addContext)}
392
396
  class="add-context"
393
397
  .iconName=${'plus'}
394
398
  .size=${Buttons.Button.Size.SMALL}
@@ -221,6 +221,7 @@ export interface RatingViewInput {
221
221
  export interface ActionViewInput {
222
222
  onReportClick: () => void;
223
223
  onCopyResponseClick: () => void;
224
+ showActions: boolean;
224
225
  }
225
226
 
226
227
  export interface SuggestionViewInput {
@@ -330,7 +331,7 @@ export const DEFAULT_VIEW = (input: ChatMessageViewInput, output: ViewOutput, ta
330
331
  },
331
332
  )}
332
333
  ${renderError(message)}
333
- ${input.isLastMessage && !input.isLoading ? renderActions(input, output) : Lit.nothing}
334
+ ${input.showActions ? renderActions(input, output) : Lit.nothing}
334
335
  </section>
335
336
  `, target);
336
337
  // clang-format on
@@ -812,8 +813,9 @@ export class ChatMessage extends UI.Widget.Widget {
812
813
  onInputChange: this.#handleInputChange.bind(this),
813
814
  isSubmitButtonDisabled: this.#isSubmitButtonDisabled,
814
815
  // Props for actions logic
816
+ showActions: !(this.isLastMessage && this.isLoading),
815
817
  showRateButtons: this.message.entity === ChatMessageEntity.MODEL && !!this.message.rpcId,
816
- suggestions: (this.message.entity === ChatMessageEntity.MODEL && !this.isReadOnly &&
818
+ suggestions: (this.isLastMessage && this.message.entity === ChatMessageEntity.MODEL && !this.isReadOnly &&
817
819
  this.message.parts.at(-1)?.type === 'answer') ?
818
820
  (this.message.parts.at(-1) as AnswerPart).suggestions :
819
821
  undefined,
@@ -22,7 +22,7 @@ import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
22
22
 
23
23
  import * as PreloadingComponents from './components/components.js';
24
24
  import {ruleSetTagOrLocationShort} from './components/PreloadingString.js';
25
- import type * as PreloadingHelper from './helper/helper.js';
25
+ import * as PreloadingHelper from './helper/helper.js';
26
26
  import preloadingViewStyles from './preloadingView.css.js';
27
27
  import preloadingViewDropDownStyles from './preloadingViewDropDown.css.js';
28
28
 
@@ -501,10 +501,17 @@ export class PreloadingAttemptView extends UI.Widget.VBox {
501
501
  const ruleSet = this.model.getRuleSetById(id);
502
502
  return ruleSet === null ? [] : [ruleSet];
503
503
  });
504
+
505
+ // Lookup status code for prefetch attempts
506
+ const statusCode = attempt.action === Protocol.Preload.SpeculationAction.Prefetch ?
507
+ PreloadingHelper.PreloadingForward.prefetchStatusCode(attempt.requestId) :
508
+ undefined;
509
+
504
510
  return {
505
511
  id,
506
512
  pipeline,
507
513
  ruleSets,
514
+ statusCode,
508
515
  };
509
516
  });
510
517
  this.preloadingGrid.rows = rows;
@@ -349,7 +349,10 @@ export class PreloadingDetailsReportView extends LegacyWrapper.LegacyWrapper.Wra
349
349
  return Lit.nothing;
350
350
  }
351
351
 
352
- const failureDescription = prefetchFailureReason(attempt);
352
+ // Lookup status code for Non2XX failures
353
+ const statusCode = PreloadingHelper.PreloadingForward.prefetchStatusCode(attempt.requestId);
354
+
355
+ const failureDescription = prefetchFailureReason(attempt, statusCode);
353
356
  if (failureDescription === null) {
354
357
  return Lit.nothing;
355
358
  }
@@ -51,6 +51,7 @@ export interface PreloadingGridRow {
51
51
  id: string;
52
52
  pipeline: SDK.PreloadingModel.PreloadPipeline;
53
53
  ruleSets: Protocol.Preload.RuleSet[];
54
+ statusCode?: number;
54
55
  }
55
56
 
56
57
  export interface ViewInput {
@@ -107,7 +108,7 @@ export const PRELOADING_GRID_DEFAULT_VIEW: View = (input, _output, target): void
107
108
  'vertical-align': 'sub',
108
109
  })}
109
110
  ></devtools-icon>` : ''}
110
- ${hasWarning ? i18nString(UIStrings.prefetchFallbackReady) : composedStatus(attempt)}
111
+ ${hasWarning ? i18nString(UIStrings.prefetchFallbackReady) : composedStatus(attempt, row.statusCode)}
111
112
  </div>
112
113
  </td>
113
114
  </tr>`;
@@ -31,6 +31,11 @@ const UIStrings = {
31
31
  * @description Description text for Prefetch status PrefetchFailedNon2XX.
32
32
  */
33
33
  PrefetchFailedNon2XX: 'The prefetch failed because of a non-2xx HTTP response status code.',
34
+ /**
35
+ * @description Description text for Prefetch status PrefetchFailedNon2XX when the HTTP status code is known.
36
+ * @example {404} PH1
37
+ */
38
+ PrefetchFailedNon2XXWithStatusCode: 'The prefetch failed because of a non-2xx HTTP response status code ({PH1}).',
34
39
  /**
35
40
  * @description Description text for Prefetch status PrefetchIneligibleRetryAfter.
36
41
  */
@@ -446,7 +451,8 @@ export const PrefetchReasonDescription: Record<string, {name: () => Platform.UIS
446
451
  };
447
452
 
448
453
  /** Decoding PrefetchFinalStatus prefetchAttempt to failure description. **/
449
- export function prefetchFailureReason({prefetchStatus}: SDK.PreloadingModel.PrefetchAttempt): string|null {
454
+ export function prefetchFailureReason(
455
+ {prefetchStatus}: SDK.PreloadingModel.PrefetchAttempt, statusCode?: number): string|null {
450
456
  // If you face an error on rolling CDP changes, see
451
457
  // https://docs.google.com/document/d/1PnrfowsZMt62PX1EvvTp2Nqs3ji1zrklrAEe1JYbkTk
452
458
  switch (prefetchStatus) {
@@ -478,6 +484,9 @@ export function prefetchFailureReason({prefetchStatus}: SDK.PreloadingModel.Pref
478
484
  case Protocol.Preload.PrefetchStatus.PrefetchFailedNetError:
479
485
  return PrefetchReasonDescription['PrefetchFailedNetError'].name();
480
486
  case Protocol.Preload.PrefetchStatus.PrefetchFailedNon2XX:
487
+ if (statusCode !== undefined) {
488
+ return i18nString(UIStrings.PrefetchFailedNon2XXWithStatusCode, {PH1: String(statusCode)});
489
+ }
481
490
  return PrefetchReasonDescription['PrefetchFailedNon2XX'].name();
482
491
  case Protocol.Preload.PrefetchStatus.PrefetchIneligibleRetryAfter:
483
492
  return PrefetchReasonDescription['PrefetchIneligibleRetryAfter'].name();
@@ -795,7 +804,7 @@ export function status(status: SDK.PreloadingModel.PreloadingStatus): string {
795
804
  }
796
805
  }
797
806
 
798
- export function composedStatus(attempt: SDK.PreloadingModel.PreloadingAttempt): string {
807
+ export function composedStatus(attempt: SDK.PreloadingModel.PreloadingAttempt, statusCode?: number): string {
799
808
  const short = status(attempt.status);
800
809
 
801
810
  if (attempt.status !== SDK.PreloadingModel.PreloadingStatus.FAILURE) {
@@ -804,7 +813,7 @@ export function composedStatus(attempt: SDK.PreloadingModel.PreloadingAttempt):
804
813
 
805
814
  switch (attempt.action) {
806
815
  case Protocol.Preload.SpeculationAction.Prefetch: {
807
- const detail = prefetchFailureReason(attempt) ?? i18n.i18n.lockedString('Internal error');
816
+ const detail = prefetchFailureReason(attempt, statusCode) ?? i18n.i18n.lockedString('Internal error');
808
817
  return short + ' - ' + detail;
809
818
  }
810
819
  case Protocol.Preload.SpeculationAction.Prerender:
@@ -3,6 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import type * as Protocol from '../../../../generated/protocol.js';
6
+ import * as Logs from '../../../../models/logs/logs.js';
6
7
 
7
8
  export class RuleSetView {
8
9
  readonly ruleSetId: Protocol.Preload.RuleSetId|null;
@@ -19,3 +20,16 @@ export class AttemptViewWithFilter {
19
20
  this.ruleSetId = ruleSetId;
20
21
  }
21
22
  }
23
+
24
+ /**
25
+ * Retrieves the HTTP status code for a prefetch attempt by looking up its
26
+ * network request in the network log.
27
+ */
28
+ export function prefetchStatusCode(requestId: Protocol.Network.RequestId): number|undefined {
29
+ const networkLog = Logs.NetworkLog.NetworkLog.instance();
30
+ const requests = networkLog.requestsForId(requestId);
31
+ if (requests.length > 0) {
32
+ return requests[requests.length - 1].statusCode;
33
+ }
34
+ return undefined;
35
+ }
@@ -228,14 +228,12 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: ViewOutput, target: HTMLE
228
228
  <div class="top-left-corner">
229
229
  <devtools-checkbox
230
230
  ${bindToSetting(input.showTestAddressesInAutofillMenuSetting)}
231
- title=${i18nString(UIStrings.showTestAddressesInAutofillMenu)}
232
- jslog=${VisualLogging.toggle(input.showTestAddressesInAutofillMenuSetting.name).track({ change: true })}>
231
+ title=${i18nString(UIStrings.showTestAddressesInAutofillMenu)}>
233
232
  ${i18nString(UIStrings.showTestAddressesInAutofillMenu)}
234
233
  </devtools-checkbox>
235
234
  <devtools-checkbox
236
235
  ${bindToSetting(input.autoOpenViewSetting)}
237
- title=${i18nString(UIStrings.autoShowTooltip)}
238
- jslog=${VisualLogging.toggle(input.autoOpenViewSetting.name).track({ change: true })}>
236
+ title=${i18nString(UIStrings.autoShowTooltip)}>
239
237
  ${i18nString(UIStrings.autoShow)}
240
238
  </devtools-checkbox>
241
239
  <devtools-link href=${AUTOFILL_FEEDBACK_URL} class="feedback link" jslogcontext="feedback">${i18nString(UIStrings.sendFeedback)}</devtools-link>
@@ -267,16 +265,14 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: ViewOutput, target: HTMLE
267
265
  <div class="label-container">
268
266
  <devtools-checkbox
269
267
  ${bindToSetting(input.showTestAddressesInAutofillMenuSetting)}
270
- title=${i18nString(UIStrings.showTestAddressesInAutofillMenu)}
271
- jslog=${VisualLogging.toggle(input.showTestAddressesInAutofillMenuSetting.name).track({ change: true })}>
268
+ title=${i18nString(UIStrings.showTestAddressesInAutofillMenu)}>
272
269
  ${i18nString(UIStrings.showTestAddressesInAutofillMenu)}
273
270
  </devtools-checkbox>
274
271
  </div>
275
272
  <div class="label-container">
276
273
  <devtools-checkbox
277
274
  ${bindToSetting(input.autoOpenViewSetting)}
278
- title=${i18nString(UIStrings.autoShowTooltip)}
279
- jslog=${VisualLogging.toggle(input.autoOpenViewSetting.name).track({ change: true })}>
275
+ title=${i18nString(UIStrings.autoShowTooltip)}>
280
276
  ${i18nString(UIStrings.autoShow)}
281
277
  </devtools-checkbox>
282
278
  </div>