chrome-devtools-frontend 1.0.1541552 → 1.0.1542501

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 (39) hide show
  1. package/docs/get_the_code.md +9 -0
  2. package/front_end/Tests.js +1 -0
  3. package/front_end/core/common/Settings.ts +38 -15
  4. package/front_end/core/host/UserMetrics.ts +5 -0
  5. package/front_end/core/sdk/IOModel.ts +1 -4
  6. package/front_end/core/sdk/ServerSentEventsProtocol.ts +4 -0
  7. package/front_end/entrypoints/main/MainImpl.ts +6 -3
  8. package/front_end/foundation/Universe.ts +2 -10
  9. package/front_end/generated/SupportedCSSProperties.js +42 -42
  10. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +72 -31
  11. package/front_end/models/har/Importer.ts +14 -0
  12. package/front_end/models/issues_manager/IssuesManager.ts +0 -5
  13. package/front_end/models/javascript_metadata/NativeFunctions.js +0 -4
  14. package/front_end/models/trace/handlers/ScriptsHandler.ts +26 -0
  15. package/front_end/models/trace/types/TraceEvents.ts +1 -1
  16. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +117 -103
  17. package/front_end/panels/ai_assistance/components/ChatView.ts +7 -31
  18. package/front_end/panels/ai_assistance/components/chatView.css +1 -1
  19. package/front_end/panels/console/ConsoleInsightTeaser.ts +5 -0
  20. package/front_end/panels/console/ConsolePrompt.ts +8 -1
  21. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +17 -1
  22. package/front_end/third_party/chromium/README.chromium +1 -1
  23. package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +0 -4
  24. package/front_end/ui/components/markdown_view/MarkdownView.docs.ts +95 -0
  25. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +246 -13
  26. package/front_end/ui/components/text_editor/config.ts +1 -1
  27. package/front_end/ui/legacy/Widget.ts +13 -4
  28. package/front_end/ui/visual_logging/KnownContextValues.ts +11 -0
  29. package/package.json +1 -1
  30. package/front_end/models/issues_manager/UserReidentificationIssue.ts +0 -72
  31. package/front_end/models/issues_manager/descriptions/userReidentificationBlocked.md +0 -5
  32. package/front_end/ui/components/docs/markdown_image/basic.html +0 -19
  33. package/front_end/ui/components/docs/markdown_image/basic.ts +0 -38
  34. package/front_end/ui/components/docs/markdown_link/basic.html +0 -17
  35. package/front_end/ui/components/docs/markdown_link/basic.ts +0 -19
  36. package/front_end/ui/components/docs/markdown_view/basic.html +0 -25
  37. package/front_end/ui/components/docs/markdown_view/basic.ts +0 -67
  38. package/front_end/ui/components/docs/markdown_view/code-block.html +0 -30
  39. package/front_end/ui/components/docs/markdown_view/code-block.ts +0 -71
@@ -5,7 +5,7 @@
5
5
  import * as Common from '../../../core/common/common.js';
6
6
  import * as Host from '../../../core/host/host.js';
7
7
  import * as i18n from '../../../core/i18n/i18n.js';
8
- import * as Root from '../../../core/root/root.js';
8
+ import * as AiCodeCompletion from '../../../models/ai_code_completion/ai_code_completion.js';
9
9
  import * as PanelCommon from '../../../panels/common/common.js';
10
10
  import * as CodeMirror from '../../../third_party/codemirror.next/codemirror.next.js';
11
11
  import * as UI from '../../legacy/legacy.js';
@@ -13,9 +13,12 @@ import * as VisualLogging from '../../visual_logging/visual_logging.js';
13
13
 
14
14
  import {AiCodeCompletionTeaserPlaceholder} from './AiCodeCompletionTeaserPlaceholder.js';
15
15
  import {
16
+ acceptAiAutoCompleteSuggestion,
16
17
  aiAutoCompleteSuggestion,
17
18
  aiAutoCompleteSuggestionState,
19
+ hasActiveAiSuggestion,
18
20
  setAiAutoCompleteSuggestion,
21
+ showCompletionHint,
19
22
  } from './config.js';
20
23
  import type {TextEditor} from './TextEditor.js';
21
24
 
@@ -45,15 +48,18 @@ export interface AiCodeCompletionConfig {
45
48
  onFeatureDisabled: () => void;
46
49
  onSuggestionAccepted: () => void;
47
50
  onRequestTriggered: () => void;
51
+ // TODO(b/445394511): Move exposing citations to onSuggestionAccepted
48
52
  onResponseReceived: (citations: Host.AidaClient.Citation[]) => void;
53
+ panel: AiCodeCompletion.AiCodeCompletion.ContextFlavor;
49
54
  }
50
55
 
51
56
  export const DELAY_BEFORE_SHOWING_RESPONSE_MS = 500;
52
57
  export const AIDA_REQUEST_DEBOUNCE_TIMEOUT_MS = 200;
58
+ const MAX_PREFIX_SUFFIX_LENGTH = 20_000;
53
59
 
54
- // TODO(samiyac): Add code relevant to AiCodeCompletion and for triggering requests
55
60
  export class AiCodeCompletionProvider {
56
61
  #aidaClient?: Host.AidaClient.AidaClient;
62
+ #aiCodeCompletion?: AiCodeCompletion.AiCodeCompletion.AiCodeCompletion;
57
63
  #aiCodeCompletionSetting = Common.Settings.Settings.instance().createSetting('ai-code-completion-enabled', false);
58
64
  #aiCodeCompletionTeaserDismissedSetting =
59
65
  Common.Settings.Settings.instance().createSetting('ai-code-completion-teaser-dismissed', false);
@@ -66,7 +72,8 @@ export class AiCodeCompletionProvider {
66
72
  #boundOnUpdateAiCodeCompletionState = this.#updateAiCodeCompletionState.bind(this);
67
73
 
68
74
  constructor(aiCodeCompletionConfig: AiCodeCompletionConfig) {
69
- if (!this.#isAiCodeCompletionEnabled()) {
75
+ const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
76
+ if (!AiCodeCompletion.AiCodeCompletion.AiCodeCompletion.isAiCodeCompletionEnabled(devtoolsLocale.locale)) {
70
77
  throw new Error('AI code completion feature is not enabled.');
71
78
  }
72
79
  this.#aiCodeCompletionConfig = aiCodeCompletionConfig;
@@ -74,10 +81,12 @@ export class AiCodeCompletionProvider {
74
81
 
75
82
  extension(): CodeMirror.Extension[] {
76
83
  return [
84
+ CodeMirror.EditorView.updateListener.of(update => this.#triggerAiCodeCompletion(update)),
77
85
  this.#teaserCompartment.of([]),
78
86
  aiAutoCompleteSuggestion,
79
87
  aiCodeCompletionTeaserModeState,
80
88
  aiAutoCompleteSuggestionState,
89
+ CodeMirror.Prec.highest(CodeMirror.keymap.of(this.#editorKeymap())),
81
90
  ];
82
91
  }
83
92
 
@@ -105,6 +114,10 @@ export class AiCodeCompletionProvider {
105
114
  void this.#updateAiCodeCompletionState();
106
115
  }
107
116
 
117
+ clearCache(): void {
118
+ this.#aiCodeCompletion?.clearCachedRequest();
119
+ }
120
+
108
121
  #setupAiCodeCompletion(): void {
109
122
  if (!this.#editor || !this.#aiCodeCompletionConfig) {
110
123
  return;
@@ -112,6 +125,11 @@ export class AiCodeCompletionProvider {
112
125
  if (!this.#aidaClient) {
113
126
  this.#aidaClient = new Host.AidaClient.AidaClient();
114
127
  }
128
+ if (!this.#aiCodeCompletion) {
129
+ this.#aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion(
130
+ {aidaClient: this.#aidaClient}, this.#aiCodeCompletionConfig.panel, undefined,
131
+ this.#aiCodeCompletionConfig.completionContext.stopSequences);
132
+ }
115
133
  this.#aiCodeCompletionConfig.onFeatureEnabled();
116
134
  }
117
135
 
@@ -123,6 +141,7 @@ export class AiCodeCompletionProvider {
123
141
  this.#editor?.dispatch({
124
142
  effects: setAiAutoCompleteSuggestion.of(null),
125
143
  });
144
+ this.#aiCodeCompletion = undefined;
126
145
  this.#aiCodeCompletionConfig?.onFeatureDisabled();
127
146
  }
128
147
 
@@ -145,6 +164,40 @@ export class AiCodeCompletionProvider {
145
164
  }
146
165
  }
147
166
 
167
+ #editorKeymap(): readonly CodeMirror.KeyBinding[] {
168
+ return [
169
+ {
170
+ key: 'Escape',
171
+ run: (): boolean => {
172
+ if (!this.#aiCodeCompletion || !this.#editor || !hasActiveAiSuggestion(this.#editor.state)) {
173
+ return false;
174
+ }
175
+ this.#editor.dispatch({
176
+ effects: setAiAutoCompleteSuggestion.of(null),
177
+ });
178
+ return true;
179
+ },
180
+ },
181
+ {
182
+ key: 'Tab',
183
+ run: (): boolean => {
184
+ if (!this.#aiCodeCompletion || !this.#editor || !hasActiveAiSuggestion(this.#editor.state)) {
185
+ return false;
186
+ }
187
+ const {accepted, suggestion} = acceptAiAutoCompleteSuggestion(this.#editor.editor);
188
+ if (!accepted) {
189
+ return false;
190
+ }
191
+ if (suggestion?.rpcGlobalId) {
192
+ this.#aiCodeCompletion?.registerUserAcceptance(suggestion.rpcGlobalId, suggestion.sampleId);
193
+ }
194
+ this.#aiCodeCompletionConfig?.onSuggestionAccepted();
195
+ return true;
196
+ },
197
+ },
198
+ ];
199
+ }
200
+
148
201
  #detachTeaser(): void {
149
202
  if (!this.#teaser) {
150
203
  return;
@@ -152,18 +205,198 @@ export class AiCodeCompletionProvider {
152
205
  this.#editor?.editor.dispatch({effects: this.#teaserCompartment.reconfigure([])});
153
206
  }
154
207
 
155
- // TODO(samiyac): Define static method in AiCodeCompletion and use that instead
156
- #isAiCodeCompletionEnabled(): boolean {
157
- const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
158
- const aidaAvailability = Root.Runtime.hostConfig.aidaAvailability;
159
- if (!devtoolsLocale.locale.startsWith('en-')) {
160
- return false;
208
+ #triggerAiCodeCompletion(update: CodeMirror.ViewUpdate): void {
209
+ if (!update.docChanged || !this.#editor || !this.#aiCodeCompletion) {
210
+ return;
211
+ }
212
+ const {doc, selection} = update.state;
213
+ const query = doc.toString();
214
+ const cursor = selection.main.head;
215
+
216
+ let prefix = query.substring(0, cursor);
217
+ if (prefix.trim().length === 0) {
218
+ return;
219
+ }
220
+ const completionContextPrefix = this.#aiCodeCompletionConfig?.completionContext.getPrefix?.();
221
+ if (completionContextPrefix) {
222
+ prefix = completionContextPrefix + prefix;
161
223
  }
162
- if (!aidaAvailability || aidaAvailability.blockedByGeo || aidaAvailability.blockedByAge ||
163
- aidaAvailability.blockedByEnterprisePolicy) {
164
- return false;
224
+ if (prefix.length > MAX_PREFIX_SUFFIX_LENGTH) {
225
+ prefix = prefix.substring(prefix.length - MAX_PREFIX_SUFFIX_LENGTH);
226
+ }
227
+
228
+ const suffix = query.substring(cursor, cursor + MAX_PREFIX_SUFFIX_LENGTH);
229
+
230
+ this.#debouncedRequestAidaSuggestion(
231
+ prefix, suffix, cursor, this.#aiCodeCompletionConfig?.completionContext.inferenceLanguage,
232
+ this.#aiCodeCompletionConfig?.completionContext.additionalFiles);
233
+ }
234
+
235
+ #debouncedRequestAidaSuggestion = Common.Debouncer.debounce(
236
+ (prefix: string, suffix: string, cursorPositionAtRequest: number,
237
+ inferenceLanguage?: Host.AidaClient.AidaInferenceLanguage,
238
+ additionalFiles?: Host.AidaClient.AdditionalFile[]) => {
239
+ void this.#requestAidaSuggestion(prefix, suffix, cursorPositionAtRequest, inferenceLanguage, additionalFiles);
240
+ },
241
+ AIDA_REQUEST_DEBOUNCE_TIMEOUT_MS);
242
+
243
+ async #requestAidaSuggestion(
244
+ prefix: string, suffix: string, cursorPositionAtRequest: number,
245
+ inferenceLanguage?: Host.AidaClient.AidaInferenceLanguage,
246
+ additionalFiles?: Host.AidaClient.AdditionalFile[]): Promise<void> {
247
+ if (!this.#aiCodeCompletion) {
248
+ AiCodeCompletion.debugLog('Ai Code Completion is not initialized');
249
+ this.#aiCodeCompletionConfig?.onResponseReceived([]);
250
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionError);
251
+ return;
252
+ }
253
+
254
+ const startTime = performance.now();
255
+ this.#aiCodeCompletionConfig?.onRequestTriggered();
256
+ // Registering AiCodeCompletionRequestTriggered metric even if the request is served from cache
257
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionRequestTriggered);
258
+
259
+ try {
260
+ const completionResponse = await this.#aiCodeCompletion.completeCode(
261
+ prefix, suffix, cursorPositionAtRequest, inferenceLanguage, additionalFiles);
262
+
263
+ if (!completionResponse) {
264
+ this.#aiCodeCompletionConfig?.onResponseReceived([]);
265
+ return;
266
+ }
267
+
268
+ const {response, fromCache} = completionResponse;
269
+
270
+ if (!response) {
271
+ this.#aiCodeCompletionConfig?.onResponseReceived([]);
272
+ return;
273
+ }
274
+
275
+ const sampleResponse = await this.#generateSampleForRequest(response, prefix, suffix);
276
+ if (!sampleResponse) {
277
+ this.#aiCodeCompletionConfig?.onResponseReceived([]);
278
+ return;
279
+ }
280
+
281
+ const {
282
+ suggestionText,
283
+ sampleId,
284
+ citations,
285
+ rpcGlobalId,
286
+ } = sampleResponse;
287
+ const remainingDelay = Math.max(
288
+ AiCodeCompletion.AiCodeCompletion.DELAY_BEFORE_SHOWING_RESPONSE_MS - (performance.now() - startTime), 0);
289
+ this.#suggestionRenderingTimeout = window.setTimeout(() => {
290
+ const currentCursorPosition = this.#editor?.editor.state.selection.main.head;
291
+ if (currentCursorPosition !== cursorPositionAtRequest) {
292
+ this.#aiCodeCompletionConfig?.onResponseReceived([]);
293
+ return;
294
+ }
295
+ if (this.#aiCodeCompletion) {
296
+ this.#editor?.dispatch({
297
+ effects: setAiAutoCompleteSuggestion.of({
298
+ text: suggestionText,
299
+ from: cursorPositionAtRequest,
300
+ rpcGlobalId,
301
+ sampleId,
302
+ startTime,
303
+ clearCachedRequest: this.clearCache.bind(this),
304
+ onImpression: this.#aiCodeCompletion?.registerUserImpression.bind(this.#aiCodeCompletion),
305
+ })
306
+ });
307
+ }
308
+ if (fromCache) {
309
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionResponseServedFromCache);
310
+ }
311
+
312
+ AiCodeCompletion.debugLog(
313
+ 'Suggestion dispatched to the editor', suggestionText, 'at cursor position', cursorPositionAtRequest);
314
+ this.#aiCodeCompletionConfig?.onResponseReceived(citations);
315
+ }, remainingDelay);
316
+ } catch (e) {
317
+ AiCodeCompletion.debugLog('Error while fetching code completion suggestions from AIDA', e);
318
+ this.#aiCodeCompletionConfig?.onResponseReceived([]);
319
+ Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiCodeCompletionError);
320
+ }
321
+ }
322
+
323
+ async #generateSampleForRequest(response: Host.AidaClient.CompletionResponse, prefix: string, suffix?: string):
324
+ Promise<{
325
+ suggestionText: string,
326
+ citations: Host.AidaClient.Citation[],
327
+ rpcGlobalId?: Host.AidaClient.RpcGlobalId,
328
+ sampleId?: number,
329
+ }|null> {
330
+ const suggestionSample = this.#pickSampleFromResponse(response);
331
+ if (!suggestionSample) {
332
+ return null;
333
+ }
334
+
335
+ const shouldBlock =
336
+ suggestionSample.attributionMetadata?.attributionAction === Host.AidaClient.RecitationAction.BLOCK;
337
+ if (shouldBlock) {
338
+ return null;
339
+ }
340
+
341
+ const isRepetitive = this.#checkIfSuggestionRepeatsExistingText(suggestionSample.generationString, prefix, suffix);
342
+ if (isRepetitive) {
343
+ return null;
344
+ }
345
+
346
+ const suggestionText = this.#trimSuggestionOverlap(suggestionSample.generationString, suffix);
347
+ if (suggestionText.length === 0) {
348
+ return null;
349
+ }
350
+
351
+ return {
352
+ suggestionText,
353
+ sampleId: suggestionSample.sampleId,
354
+ citations: suggestionSample.attributionMetadata?.citations ?? [],
355
+ rpcGlobalId: response.metadata.rpcGlobalId,
356
+ };
357
+ }
358
+
359
+ #pickSampleFromResponse(response: Host.AidaClient.CompletionResponse): Host.AidaClient.GenerationSample|null {
360
+ if (!response.generatedSamples.length) {
361
+ return null;
362
+ }
363
+
364
+ // `currentHint` is the portion of a standard autocomplete suggestion that the user has not yet typed.
365
+ // For example, if the user types `document.queryS` and the autocomplete suggests `document.querySelector`,
366
+ // the `currentHint` is `elector`.
367
+ const currentHintInMenu = this.#editor?.editor.plugin(showCompletionHint)?.currentHint;
368
+ if (!currentHintInMenu) {
369
+ return response.generatedSamples[0];
370
+ }
371
+
372
+ // TODO(ergunsh): This does not handle looking for `selectedCompletion`. The `currentHint` is `null`
373
+ // for the Sources panel case.
374
+ // Even though there is no match, we still return the first suggestion which will be displayed
375
+ // when the traditional autocomplete menu is closed.
376
+ return response.generatedSamples.find(sample => sample.generationString.startsWith(currentHintInMenu)) ??
377
+ response.generatedSamples[0];
378
+ }
379
+
380
+ #checkIfSuggestionRepeatsExistingText(generationString: string, prefix: string, suffix?: string): boolean {
381
+ return Boolean(prefix.includes(generationString.trim()) || suffix?.includes(generationString.trim()));
382
+ }
383
+
384
+ /**
385
+ * Removes the end of a suggestion if it overlaps with the start of the suffix.
386
+ */
387
+ #trimSuggestionOverlap(generationString: string, suffix?: string): string {
388
+ if (!suffix) {
389
+ return generationString;
390
+ }
391
+
392
+ // Iterate from the longest possible overlap down to the shortest
393
+ for (let i = Math.min(generationString.length, suffix.length); i > 0; i--) {
394
+ const overlapCandidate = suffix.substring(0, i);
395
+ if (generationString.endsWith(overlapCandidate)) {
396
+ return generationString.slice(0, -i);
397
+ }
165
398
  }
166
- return Boolean(aidaAvailability.enabled && Root.Runtime.hostConfig.devToolsAiCodeCompletion?.enabled);
399
+ return generationString;
167
400
  }
168
401
  }
169
402
 
@@ -483,7 +483,7 @@ export function contentIncludingHint(view: CM.EditorView): string {
483
483
 
484
484
  export const setAiAutoCompleteSuggestion = CM.StateEffect.define<ActiveSuggestion|null>();
485
485
 
486
- interface ActiveSuggestion {
486
+ export interface ActiveSuggestion {
487
487
  text: string;
488
488
  from: number;
489
489
  sampleId?: number;
@@ -113,8 +113,10 @@ function cancelUpdate(widget: Widget): void {
113
113
 
114
114
  function runNextUpdate(): void {
115
115
  pendingAnimationFrame = null;
116
- currentUpdateQueue = nextUpdateQueue;
117
- nextUpdateQueue = new Map();
116
+ if (!currentUpdateQueue) {
117
+ currentUpdateQueue = nextUpdateQueue;
118
+ nextUpdateQueue = new Map();
119
+ }
118
120
  for (const [widget, {resolve}] of currentUpdateQueue) {
119
121
  currentlyProcessed.add(widget);
120
122
  void (async () => {
@@ -122,8 +124,15 @@ function runNextUpdate(): void {
122
124
  resolve();
123
125
  })();
124
126
  }
125
- currentUpdateQueue = null;
126
- currentlyProcessed.clear();
127
+ currentUpdateQueue.clear();
128
+ queueMicrotask(() => {
129
+ if (currentUpdateQueue && currentUpdateQueue.size > 0) {
130
+ runNextUpdate();
131
+ } else {
132
+ currentUpdateQueue = null;
133
+ currentlyProcessed.clear();
134
+ }
135
+ });
127
136
  }
128
137
 
129
138
  export class WidgetElement<WidgetT extends Widget> extends HTMLElement {
@@ -809,9 +809,14 @@ export const knownContextValues = new Set([
809
809
  'column-rule',
810
810
  'column-rule-break',
811
811
  'column-rule-color',
812
+ 'column-rule-edge-end-inset',
812
813
  'column-rule-edge-end-outset',
814
+ 'column-rule-edge-start-inset',
813
815
  'column-rule-edge-start-outset',
816
+ 'column-rule-inset',
817
+ 'column-rule-interior-end-inset',
814
818
  'column-rule-interior-end-outset',
819
+ 'column-rule-interior-start-inset',
815
820
  'column-rule-interior-start-outset',
816
821
  'column-rule-outset',
817
822
  'column-rule-style',
@@ -3167,9 +3172,14 @@ export const knownContextValues = new Set([
3167
3172
  'row-rule',
3168
3173
  'row-rule-break',
3169
3174
  'row-rule-color',
3175
+ 'row-rule-edge-end-inset',
3170
3176
  'row-rule-edge-end-outset',
3177
+ 'row-rule-edge-start-inset',
3171
3178
  'row-rule-edge-start-outset',
3179
+ 'row-rule-inset',
3180
+ 'row-rule-interior-end-inset',
3172
3181
  'row-rule-interior-end-outset',
3182
+ 'row-rule-interior-start-inset',
3173
3183
  'row-rule-interior-start-outset',
3174
3184
  'row-rule-outset',
3175
3185
  'row-rule-style',
@@ -3184,6 +3194,7 @@ export const knownContextValues = new Set([
3184
3194
  'rule',
3185
3195
  'rule-break',
3186
3196
  'rule-color',
3197
+ 'rule-inset',
3187
3198
  'rule-outset',
3188
3199
  'rule-set',
3189
3200
  'rule-set-details',
package/package.json CHANGED
@@ -103,5 +103,5 @@
103
103
  "flat-cache": "6.1.12"
104
104
  }
105
105
  },
106
- "version": "1.0.1541552"
106
+ "version": "1.0.1542501"
107
107
  }
@@ -1,72 +0,0 @@
1
- // Copyright 2025 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 type * as SDK from '../../core/sdk/sdk.js';
6
- import type * as Protocol from '../../generated/protocol.js';
7
-
8
- import {Issue, IssueCategory, IssueKind} from './Issue.js';
9
- import {
10
- type LazyMarkdownIssueDescription,
11
- type MarkdownIssueDescription,
12
- resolveLazyDescription,
13
- } from './MarkdownIssueDescription.js';
14
-
15
- export class UserReidentificationIssue extends Issue {
16
- #issueDetails: Protocol.Audits.UserReidentificationIssueDetails;
17
-
18
- constructor(
19
- issueDetails: Protocol.Audits.UserReidentificationIssueDetails, issuesModel: SDK.IssuesModel.IssuesModel|null) {
20
- super('UserReidentificationIssue', issuesModel);
21
- this.#issueDetails = issueDetails;
22
- }
23
-
24
- primaryKey(): string {
25
- const requestId = this.#issueDetails.request ? this.#issueDetails.request.requestId : 'no-request';
26
- return `${this.code()}-(${requestId})`;
27
- }
28
-
29
- override requests(): Iterable<Protocol.Audits.AffectedRequest> {
30
- return this.#issueDetails.request ? [this.#issueDetails.request] : [];
31
- }
32
-
33
- getCategory(): IssueCategory {
34
- return IssueCategory.OTHER;
35
- }
36
-
37
- getDescription(): MarkdownIssueDescription|null {
38
- const description = issueDescriptions.get(this.code());
39
- if (!description) {
40
- return null;
41
- }
42
- return resolveLazyDescription(description);
43
- }
44
-
45
- getKind(): IssueKind {
46
- return IssueKind.IMPROVEMENT;
47
- }
48
-
49
- static fromInspectorIssue(
50
- issuesModel: SDK.IssuesModel.IssuesModel|null,
51
- inspectorIssue: Protocol.Audits.InspectorIssue): UserReidentificationIssue[] {
52
- const userReidentificationIssueDetails = inspectorIssue.details.userReidentificationIssueDetails;
53
- if (!userReidentificationIssueDetails) {
54
- console.warn('User Reidentification issue without details received.');
55
- return [];
56
- }
57
- return [new UserReidentificationIssue(userReidentificationIssueDetails, issuesModel)];
58
- }
59
- }
60
-
61
- // Add new issue types to this map (with a unique code per type).
62
- const issueDescriptions = new Map<string, LazyMarkdownIssueDescription>([
63
- [
64
- 'UserReidentificationIssue',
65
- {
66
- file: 'userReidentificationBlocked.md',
67
- // TODO(https://g-issues.chromium.org/issues/409596758): Add
68
- // internationalized learn more link text.
69
- links: [],
70
- },
71
- ],
72
- ]);
@@ -1,5 +0,0 @@
1
- # Resources suspected of tracking users are blocked
2
-
3
- This is currently an experimental feature. In case of site breakage, you can disable it for this page via the eye icon in the URL bar or completely disable it via chrome://settings/incognito. You may also report bugs [here](userReidentificationBugReports).
4
-
5
- Chrome identifies domains known to serve content which misuses web platform APIs to re-identify users across sites. Resources from these domains are blocked when users express a preference for additional privacy. Consider removing the following resources from your site:
@@ -1,19 +0,0 @@
1
- <!--
2
- Copyright 2021 The Chromium Authors
3
- Use of this source code is governed by a BSD-style license that can be
4
- found in the LICENSE file.
5
- -->
6
- <!DOCTYPE html>
7
- <html>
8
- <head>
9
- <meta charset="UTF-8" />
10
- <meta name="viewport" content="width=device-width" />
11
- <title>Basic Markdown Image example</title>
12
- </head>
13
- <body>
14
- <div id="icon"></div>
15
- <div id="image"></div>
16
-
17
- <script type="module" src="./basic.js"></script>
18
- </body>
19
- </html>
@@ -1,38 +0,0 @@
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
-
5
- import * as FrontendHelpers from '../../../../testing/EnvironmentHelpers.js';
6
- import * as ComponentHelpers from '../../helpers/helpers.js';
7
- import * as MarkdownView from '../../markdown_view/markdown_view.js';
8
-
9
- await ComponentHelpers.ComponentServerSetup.setup();
10
- await FrontendHelpers.initializeGlobalVars();
11
-
12
- // Adding a couple image keys to the image map.
13
- MarkdownView.MarkdownImagesMap.markdownImages.set('test-icon', {
14
- src: '../../Images/issue-text-filled.svg',
15
- isIcon: true,
16
- width: '20px',
17
- height: '20px',
18
- });
19
- MarkdownView.MarkdownImagesMap.markdownImages.set('test-image', {
20
- src: '../../Images/lighthouse_logo.svg',
21
- width: '200px',
22
- height: '200px',
23
- isIcon: false,
24
- });
25
-
26
- const iconComponent = new MarkdownView.MarkdownImage.MarkdownImage();
27
- document.getElementById('icon')?.appendChild(iconComponent);
28
- iconComponent.data = {
29
- key: 'test-icon',
30
- title: 'Test icon title',
31
- };
32
-
33
- const imageComponent = new MarkdownView.MarkdownImage.MarkdownImage();
34
- document.getElementById('image')?.appendChild(imageComponent);
35
- imageComponent.data = {
36
- key: 'test-image',
37
- title: 'Test image title',
38
- };
@@ -1,17 +0,0 @@
1
- <!--
2
- Copyright 2021 The Chromium Authors
3
- Use of this source code is governed by a BSD-style license that can be
4
- found in the LICENSE file.
5
- -->
6
- <!DOCTYPE html>
7
- <html>
8
- <head>
9
- <meta charset="UTF-8" />
10
- <meta name="viewport" content="width=device-width" />
11
- <title>Basic Markdown Link example</title>
12
- </head>
13
- <body>
14
- <div id="target"></div>
15
- <script type="module" src="./basic.js"></script>
16
- </body>
17
- </html>
@@ -1,19 +0,0 @@
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
-
5
- import * as FrontendHelpers from '../../../../testing/EnvironmentHelpers.js';
6
- import * as ComponentHelpers from '../../helpers/helpers.js';
7
- import * as MarkdownView from '../../markdown_view/markdown_view.js';
8
-
9
- await ComponentHelpers.ComponentServerSetup.setup();
10
- await FrontendHelpers.initializeGlobalVars();
11
-
12
- MarkdownView.MarkdownLinksMap.markdownLinks.set('textLink', 'https://example.com/');
13
-
14
- const link = new MarkdownView.MarkdownLink.MarkdownLink();
15
- document.getElementById('target')?.appendChild(link);
16
- link.data = {
17
- key: 'textLink',
18
- title: 'Test link title',
19
- };
@@ -1,25 +0,0 @@
1
- <!--
2
- Copyright 2021 The Chromium Authors
3
- Use of this source code is governed by a BSD-style license that can be
4
- found in the LICENSE file.
5
- -->
6
- <!DOCTYPE html>
7
- <html>
8
- <head>
9
- <meta charset="UTF-8" />
10
- <meta name="viewport" content="width=device-width" />
11
- <title>Basic Markdown View example</title>
12
- <style>
13
- #container {
14
- border: 1px solid;
15
- width: 400px;
16
- padding: 1em;
17
- }
18
- </style>
19
- </head>
20
- <body>
21
- <div id="container"></div>
22
-
23
- <script type="module" src="./basic.js"></script>
24
- </body>
25
- </html>