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.
- package/docs/get_the_code.md +9 -0
- package/front_end/Tests.js +1 -0
- package/front_end/core/common/Settings.ts +38 -15
- package/front_end/core/host/UserMetrics.ts +5 -0
- package/front_end/core/sdk/IOModel.ts +1 -4
- package/front_end/core/sdk/ServerSentEventsProtocol.ts +4 -0
- package/front_end/entrypoints/main/MainImpl.ts +6 -3
- package/front_end/foundation/Universe.ts +2 -10
- package/front_end/generated/SupportedCSSProperties.js +42 -42
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +72 -31
- package/front_end/models/har/Importer.ts +14 -0
- package/front_end/models/issues_manager/IssuesManager.ts +0 -5
- package/front_end/models/javascript_metadata/NativeFunctions.js +0 -4
- package/front_end/models/trace/handlers/ScriptsHandler.ts +26 -0
- package/front_end/models/trace/types/TraceEvents.ts +1 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +117 -103
- package/front_end/panels/ai_assistance/components/ChatView.ts +7 -31
- package/front_end/panels/ai_assistance/components/chatView.css +1 -1
- package/front_end/panels/console/ConsoleInsightTeaser.ts +5 -0
- package/front_end/panels/console/ConsolePrompt.ts +8 -1
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +17 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +0 -4
- package/front_end/ui/components/markdown_view/MarkdownView.docs.ts +95 -0
- package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +246 -13
- package/front_end/ui/components/text_editor/config.ts +1 -1
- package/front_end/ui/legacy/Widget.ts +13 -4
- package/front_end/ui/visual_logging/KnownContextValues.ts +11 -0
- package/package.json +1 -1
- package/front_end/models/issues_manager/UserReidentificationIssue.ts +0 -72
- package/front_end/models/issues_manager/descriptions/userReidentificationBlocked.md +0 -5
- package/front_end/ui/components/docs/markdown_image/basic.html +0 -19
- package/front_end/ui/components/docs/markdown_image/basic.ts +0 -38
- package/front_end/ui/components/docs/markdown_link/basic.html +0 -17
- package/front_end/ui/components/docs/markdown_link/basic.ts +0 -19
- package/front_end/ui/components/docs/markdown_view/basic.html +0 -25
- package/front_end/ui/components/docs/markdown_view/basic.ts +0 -67
- package/front_end/ui/components/docs/markdown_view/code-block.html +0 -30
- 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
|
|
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
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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 (
|
|
163
|
-
|
|
164
|
-
|
|
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
|
|
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
|
|
117
|
-
|
|
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
|
|
126
|
-
|
|
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
|
@@ -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>
|