chrome-devtools-frontend 1.0.1662289 → 1.0.1662965
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/.agents/skills/devtools-unicode-escaping/SKILL.md +64 -0
- package/.agents/skills/migrate-chromium-test/SKILL.md +29 -4
- package/front_end/core/common/SettingRegistration.ts +0 -5
- package/front_end/core/common/Settings.ts +69 -3
- package/front_end/core/platform/StringUtilities.ts +38 -6
- package/front_end/core/sdk/ServiceWorkerCacheModel.ts +0 -10
- package/front_end/core/sdk/StorageBucketsModel.ts +0 -10
- package/front_end/core/sdk/sdk-meta.ts +0 -1
- package/front_end/entrypoints/inspector_main/OutermostTargetSelector.ts +0 -13
- package/front_end/entrypoints/inspector_main/RenderingOptions.ts +8 -3
- package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +3 -3
- package/front_end/entrypoints/main/MainImpl.ts +7 -2
- package/front_end/foundation/Universe.ts +16 -0
- package/front_end/generated/InspectorBackendCommands.ts +2 -14
- package/front_end/generated/protocol-mapping.d.ts +0 -53
- package/front_end/generated/protocol-proxy-api.d.ts +0 -46
- package/front_end/generated/protocol.ts +0 -148
- package/front_end/models/ai_assistance/AiAgent2.ts +3 -3
- package/front_end/models/ai_assistance/AiConversation.ts +21 -10
- package/front_end/models/ai_assistance/AiHistoryStorage.ts +21 -10
- package/front_end/models/ai_assistance/ChangeManager.ts +2 -2
- package/front_end/models/ai_assistance/ExtensionScope.ts +6 -2
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +1 -1
- package/front_end/models/ai_assistance/agents/AiAgent.ts +8 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
- package/front_end/models/badges/UserBadges.ts +31 -17
- package/front_end/models/bindings/NetworkProject.ts +16 -4
- package/front_end/models/emulation/DeviceModeModel.ts +67 -5
- package/front_end/models/extensions/RecorderPluginManager.ts +10 -6
- package/front_end/models/har/Log.snapshot.txt +193 -0
- package/front_end/models/har/Log.ts +3 -2
- package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +7 -5
- package/front_end/models/source_map_scopes/NamesResolver.ts +36 -30
- package/front_end/models/stack_trace/StackTrace.ts +17 -0
- package/front_end/panels/application/IndexedDBModel.ts +0 -10
- package/front_end/panels/application/IndexedDBViews.ts +240 -164
- package/front_end/panels/application/SharedStorageModel.ts +0 -10
- package/front_end/panels/application/components/AdsView.ts +23 -0
- package/front_end/panels/application/components/SharedStorageAccessGrid.ts +1 -1
- package/front_end/panels/application/components/adsView.css +21 -1
- package/front_end/panels/application/indexedDBViews.css +1 -1
- package/front_end/panels/network/NetworkDataGridNode.ts +43 -1
- package/front_end/panels/network/RequestInitiatorView.ts +24 -2
- package/front_end/panels/network/networkLogView.css +5 -0
- package/front_end/panels/network/requestInitiatorViewTree.css +5 -0
- package/front_end/panels/profiler/HeapProfileView.ts +198 -79
- package/front_end/panels/recorder/README.md +1 -2
- package/front_end/panels/recorder/RecorderPanel.ts +1749 -17
- package/front_end/panels/recorder/recorder.ts +0 -2
- package/front_end/panels/settings/AISettingsTab.ts +13 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/spinners/Spinner.ts +29 -32
- package/front_end/ui/components/spinners/spinner.css +32 -84
- package/front_end/ui/legacy/Treeoutline.ts +14 -6
- package/front_end/ui/legacy/UIUtils.ts +25 -10
- package/front_end/ui/legacy/Widget.ts +17 -10
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +36 -7
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +63 -68
- package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +1 -1
- package/front_end/ui/legacy/components/object_ui/objectValue.css +2 -1
- package/front_end/ui/legacy/inspectorCommon.css +4 -4
- package/front_end/ui/lit/lit.ts +1 -0
- package/front_end/ui/lit/render.ts +44 -10
- package/front_end/ui/lit/strip-whitespace.ts +23 -2
- package/package.json +1 -1
- package/front_end/panels/recorder/RecorderController.ts +0 -1759
- /package/front_end/panels/recorder/{recorderController.css → recorderPanel.css} +0 -0
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
-
import * as Common from '../../core/common/common.js';
|
|
6
5
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
7
6
|
import * as Protocol from '../../generated/protocol.js';
|
|
8
7
|
import * as Bindings from '../bindings/bindings.js';
|
|
@@ -190,7 +189,11 @@ const enum Punctuation {
|
|
|
190
189
|
|
|
191
190
|
const resolveDebuggerScope = async(scope: SDK.DebuggerModel.ScopeChainEntry):
|
|
192
191
|
Promise<{variableMapping: Map<string, string>, thisMapping: string | null}> => {
|
|
193
|
-
if (!
|
|
192
|
+
if (!scope.callFrame()
|
|
193
|
+
.debuggerModel.target()
|
|
194
|
+
.targetManager()
|
|
195
|
+
.settings.moduleSetting('js-source-maps-enabled')
|
|
196
|
+
.get()) {
|
|
194
197
|
return {variableMapping: new Map(), thisMapping: null};
|
|
195
198
|
}
|
|
196
199
|
const script = scope.callFrame().script;
|
|
@@ -278,16 +281,17 @@ const resolveScope = async(script: SDK.Script.Script, scopeChain: Formatter.Form
|
|
|
278
281
|
|
|
279
282
|
async function resolveSourceName(
|
|
280
283
|
script: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap, name: string,
|
|
281
|
-
position: {lineNumber: number, columnNumber: number}
|
|
284
|
+
position: {lineNumber: number, columnNumber: number},
|
|
285
|
+
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding =
|
|
286
|
+
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()): Promise<string|null> {
|
|
282
287
|
const ranges = sourceMap.findEntryRanges(position.lineNumber, position.columnNumber);
|
|
283
288
|
if (!ranges) {
|
|
284
289
|
return null;
|
|
285
290
|
}
|
|
286
291
|
// Extract the underlying text from the compiled code's range and make sure that
|
|
287
292
|
// it starts with the identifier |name|.
|
|
288
|
-
const uiSourceCode =
|
|
289
|
-
|
|
290
|
-
script.debuggerModel, ranges.sourceURL, script.isContentScript());
|
|
293
|
+
const uiSourceCode = debuggerWorkspaceBinding.uiSourceCodeForSourceMapSourceURL(
|
|
294
|
+
script.debuggerModel, ranges.sourceURL, script.isContentScript());
|
|
291
295
|
if (!uiSourceCode) {
|
|
292
296
|
return null;
|
|
293
297
|
}
|
|
@@ -363,24 +367,27 @@ const resolveScope = async(script: SDK.Script.Script, scopeChain: Formatter.Form
|
|
|
363
367
|
};
|
|
364
368
|
|
|
365
369
|
export const resolveScopeChain =
|
|
366
|
-
async function(callFrame: SDK.DebuggerModel.CallFrame
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
370
|
+
async function(callFrame: SDK.DebuggerModel.CallFrame,
|
|
371
|
+
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding =
|
|
372
|
+
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()):
|
|
373
|
+
Promise<SDK.DebuggerModel.ScopeChainEntry[]> {
|
|
374
|
+
const {pluginManager} = debuggerWorkspaceBinding;
|
|
375
|
+
const scopeChain: SDK.DebuggerModel.ScopeChainEntry[]|null|undefined =
|
|
376
|
+
await pluginManager.resolveScopeChain(callFrame);
|
|
377
|
+
if (scopeChain) {
|
|
378
|
+
return scopeChain;
|
|
379
|
+
}
|
|
373
380
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
381
|
+
// TODO(crbug.com/465968290): Re-enable creating the scope chain from the source map once:
|
|
382
|
+
// 1) We have a flag indicating whether the source map contained variable/binding information.
|
|
383
|
+
// 2) We have a chrome feature flag.
|
|
377
384
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
};
|
|
385
|
+
if (callFrame.script.isWasm()) {
|
|
386
|
+
return callFrame.scopeChain();
|
|
387
|
+
}
|
|
388
|
+
const thisObject = await resolveThisObject(callFrame);
|
|
389
|
+
return callFrame.scopeChain().map(scope => new ScopeWithSourceMappedVariables(scope, thisObject));
|
|
390
|
+
};
|
|
384
391
|
|
|
385
392
|
/**
|
|
386
393
|
* @returns A mapping from original name -> compiled name. If the orignal name is unavailable (e.g. because the compiled name was
|
|
@@ -388,7 +395,7 @@ export const resolveScopeChain =
|
|
|
388
395
|
*/
|
|
389
396
|
export const allVariablesInCallFrame =
|
|
390
397
|
async(callFrame: SDK.DebuggerModel.CallFrame): Promise<Map<string, string|null>> => {
|
|
391
|
-
if (!
|
|
398
|
+
if (!callFrame.debuggerModel.target().targetManager().settings.moduleSetting('js-source-maps-enabled').get()) {
|
|
392
399
|
return new Map<string, string|null>();
|
|
393
400
|
}
|
|
394
401
|
const cachedMap = cachedMapByCallFrame.get(callFrame);
|
|
@@ -424,13 +431,13 @@ export const allVariablesInCallFrame =
|
|
|
424
431
|
export const allVariablesAtPosition =
|
|
425
432
|
async(location: SDK.DebuggerModel.Location): Promise<Map<string, string|null>> => {
|
|
426
433
|
const reverseMapping = new Map<string, string|null>();
|
|
427
|
-
if (!Common.Settings.Settings.instance().moduleSetting('js-source-maps-enabled').get()) {
|
|
428
|
-
return reverseMapping;
|
|
429
|
-
}
|
|
430
434
|
const script = location.script();
|
|
431
435
|
if (!script) {
|
|
432
436
|
return reverseMapping;
|
|
433
437
|
}
|
|
438
|
+
if (!script.debuggerModel.target().targetManager().settings.moduleSetting('js-source-maps-enabled').get()) {
|
|
439
|
+
return reverseMapping;
|
|
440
|
+
}
|
|
434
441
|
|
|
435
442
|
const scopeTreeAndText = await computeScopeTree(script);
|
|
436
443
|
if (!scopeTreeAndText) {
|
|
@@ -727,8 +734,9 @@ export async function resolveDebuggerFrameFunctionName(frame: SDK.DebuggerModel.
|
|
|
727
734
|
}
|
|
728
735
|
|
|
729
736
|
export async function resolveProfileFrameFunctionName(
|
|
730
|
-
{scriptId, lineNumber, columnNumber}: Partial<Protocol.Runtime.CallFrame>,
|
|
731
|
-
|
|
737
|
+
{scriptId, lineNumber, columnNumber}: Partial<Protocol.Runtime.CallFrame>, target: SDK.Target.Target|null,
|
|
738
|
+
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding =
|
|
739
|
+
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()): Promise<string|null> {
|
|
732
740
|
if (!target || lineNumber === undefined || columnNumber === undefined || scriptId === undefined) {
|
|
733
741
|
return null;
|
|
734
742
|
}
|
|
@@ -738,8 +746,6 @@ export async function resolveProfileFrameFunctionName(
|
|
|
738
746
|
if (!debuggerModel || !script) {
|
|
739
747
|
return null;
|
|
740
748
|
}
|
|
741
|
-
|
|
742
|
-
const debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
|
|
743
749
|
const location = new SDK.DebuggerModel.Location(debuggerModel, scriptId, lineNumber, columnNumber);
|
|
744
750
|
const functionInfoFromPlugin = await debuggerWorkspaceBinding.pluginManager.getFunctionInfo(script, location);
|
|
745
751
|
if (functionInfoFromPlugin && 'frames' in functionInfoFromPlugin) {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type * as Common from '../../core/common/common.js';
|
|
6
6
|
import type * as SDK from '../../core/sdk/sdk.js';
|
|
7
|
+
import type * as Protocol from '../../generated/protocol.js';
|
|
7
8
|
import type * as Workspace from '../workspace/workspace.js';
|
|
8
9
|
|
|
9
10
|
export type StackTrace = BaseStackTrace<Fragment>;
|
|
@@ -131,3 +132,19 @@ export class DebuggableFrameFlavor {
|
|
|
131
132
|
return DebuggableFrameFlavor.#last;
|
|
132
133
|
}
|
|
133
134
|
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Returns whether the given stack trace originated from a direct console
|
|
138
|
+
* invocation. A console-originated stack trace has exactly one frame with
|
|
139
|
+
* no url and no function name.
|
|
140
|
+
*
|
|
141
|
+
* TODO(crbug.com/40726969): Accept a translated `StackTrace` instead of a raw `Protocol.Runtime.StackTrace`.
|
|
142
|
+
*/
|
|
143
|
+
export function isConsoleOriginated(stackTrace: Protocol.Runtime.StackTrace): boolean {
|
|
144
|
+
const callFrames = stackTrace.callFrames;
|
|
145
|
+
if (callFrames.length !== 1) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const frame = callFrames[0];
|
|
149
|
+
return frame.url === '' && frame.functionName === '';
|
|
150
|
+
}
|
|
@@ -423,16 +423,6 @@ export class IndexedDBModel extends SDK.SDKModel.SDKModel<EventTypes> implements
|
|
|
423
423
|
cacheStorageContentUpdated(_event: Protocol.Storage.CacheStorageContentUpdatedEvent): void {
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
-
interestGroupAccessed(_event: Protocol.Storage.InterestGroupAccessedEvent): void {
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
interestGroupAuctionEventOccurred(_event: Protocol.Storage.InterestGroupAuctionEventOccurredEvent): void {
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
interestGroupAuctionNetworkRequestCreated(_event: Protocol.Storage.InterestGroupAuctionNetworkRequestCreatedEvent):
|
|
433
|
-
void {
|
|
434
|
-
}
|
|
435
|
-
|
|
436
426
|
sharedStorageAccessed(_event: Protocol.Storage.SharedStorageAccessedEvent): void {
|
|
437
427
|
}
|
|
438
428
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Copyright 2012 The Chromium Authors
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
|
-
/* eslint-disable @devtools/no-imperative-dom-api */
|
|
5
4
|
|
|
6
5
|
import '../../ui/components/report_view/report_view.js';
|
|
7
6
|
import '../../ui/legacy/legacy.js';
|
|
@@ -234,6 +233,178 @@ declare global {
|
|
|
234
233
|
'devtools-idb-database-view': IDBDatabaseView;
|
|
235
234
|
}
|
|
236
235
|
}
|
|
236
|
+
export interface IndexedDBDataViewInput {
|
|
237
|
+
isIndex: boolean;
|
|
238
|
+
index: Index|null;
|
|
239
|
+
objectStore: ObjectStore;
|
|
240
|
+
entries: Entry[];
|
|
241
|
+
skipCount: number;
|
|
242
|
+
selectedRowNumber: number;
|
|
243
|
+
clearButtonEnabled: boolean;
|
|
244
|
+
hasMore: boolean;
|
|
245
|
+
keyFilter: string;
|
|
246
|
+
needsRefreshVisible: boolean;
|
|
247
|
+
metadata: ObjectStoreMetadata|null;
|
|
248
|
+
|
|
249
|
+
refreshButtonClicked: () => void;
|
|
250
|
+
clearButtonClicked: () => Promise<void>;
|
|
251
|
+
deleteButtonClicked: () => Promise<void>;
|
|
252
|
+
pageBackButtonClicked: () => void;
|
|
253
|
+
pageForwardButtonClicked: () => void;
|
|
254
|
+
onKeyFilterChange: (value: string) => void;
|
|
255
|
+
onRowSelected: (rowNumber: number) => void;
|
|
256
|
+
deleteEntry: (entry: Entry) => Promise<void>;
|
|
257
|
+
populateContextMenu: (e: CustomEvent<UI.ContextMenu.ContextMenu>, entry: Entry) => void;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const renderKeyPathString = (keyPathString: string): LitTemplate => {
|
|
261
|
+
return html`"<span class="source-code indexed-db-key-path">${keyPathString}</span>"`;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const renderKeyColumnHeader = (prefix: string, keyPath: string|string[]|null|undefined): LitTemplate => {
|
|
265
|
+
if (keyPath === undefined || keyPath === null || keyPath === '') {
|
|
266
|
+
return html`${prefix}`;
|
|
267
|
+
}
|
|
268
|
+
return html`
|
|
269
|
+
${prefix} (${i18nString(UIStrings.keyPath)}${
|
|
270
|
+
Array.isArray(keyPath) ?
|
|
271
|
+
html`[${keyPath.map((path, i) => html`${i > 0 ? ', ' : ''}${renderKeyPathString(path)}`)}]` :
|
|
272
|
+
renderKeyPathString(keyPath)})`;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
const renderDataGrid = (input: IndexedDBDataViewInput): LitTemplate => {
|
|
276
|
+
const keyPath = input.isIndex && input.index ? input.index.keyPath : input.objectStore.keyPath;
|
|
277
|
+
// clang-format off
|
|
278
|
+
return html`<devtools-data-grid striped style="flex: auto;" name=${i18nString(UIStrings.indexedDb)} .template=${html`
|
|
279
|
+
<style>${indexedDBViewsStyles}</style>
|
|
280
|
+
<table>
|
|
281
|
+
<tr>
|
|
282
|
+
<th id="number" fixed width="50px">#</th>
|
|
283
|
+
<th id="key">${renderKeyColumnHeader(i18nString(UIStrings.keyString), keyPath)}</th>
|
|
284
|
+
${input.isIndex ? html`<th id="primary-key">${renderKeyColumnHeader(i18nString(UIStrings.primaryKey), input.objectStore.keyPath)}</th>` : nothing}
|
|
285
|
+
<th id="value">${i18nString(UIStrings.valueString)}</th>
|
|
286
|
+
</tr>
|
|
287
|
+
${repeat(input.entries, (_entry, index) => index, (entry, index) => html`
|
|
288
|
+
<tr ?selected=${index + input.skipCount === input.selectedRowNumber}
|
|
289
|
+
@select=${() => input.onRowSelected(index + input.skipCount)}
|
|
290
|
+
@delete=${() => input.deleteEntry(entry)}
|
|
291
|
+
@contextmenu=${(e: CustomEvent<UI.ContextMenu.ContextMenu>) => input.populateContextMenu(e, entry)}>
|
|
292
|
+
<td>${index + input.skipCount}</td>
|
|
293
|
+
<td>${widget(ObjectPropertiesSectionWidget, {value: entry.key})}</td>
|
|
294
|
+
${input.isIndex ? html`<td>${widget(ObjectPropertiesSectionWidget, {value: entry.primaryKey})}</td>` : nothing}
|
|
295
|
+
<td class="value-column">${widget(ObjectPropertiesSectionWidget, {value: entry.value})}</td>
|
|
296
|
+
</tr>`
|
|
297
|
+
)}
|
|
298
|
+
</table>`}>
|
|
299
|
+
</devtools-data-grid>`;
|
|
300
|
+
// clang-format on
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const renderToolbar = (input: IndexedDBDataViewInput): LitTemplate => {
|
|
304
|
+
// clang-format off
|
|
305
|
+
return html`
|
|
306
|
+
<devtools-toolbar class="data-view-toolbar" jslog=${VisualLogging.toolbar()}>
|
|
307
|
+
<devtools-button
|
|
308
|
+
class="toolbar-button"
|
|
309
|
+
.iconName=${'refresh'}
|
|
310
|
+
.title=${i18nString(UIStrings.refresh)}
|
|
311
|
+
jslog=${VisualLogging.action('refresh').track({click: true})}
|
|
312
|
+
@click=${input.refreshButtonClicked}
|
|
313
|
+
.variant=${Buttons.Button.Variant.TOOLBAR}
|
|
314
|
+
></devtools-button>
|
|
315
|
+
<devtools-button
|
|
316
|
+
class="toolbar-button"
|
|
317
|
+
.iconName=${'clear'}
|
|
318
|
+
.title=${i18nString(UIStrings.clearObjectStore)}
|
|
319
|
+
jslog=${VisualLogging.action('clear-all').track({click: true})}
|
|
320
|
+
@click=${input.clearButtonClicked}
|
|
321
|
+
.disabled=${input.isIndex || !input.clearButtonEnabled}
|
|
322
|
+
.variant=${Buttons.Button.Variant.TOOLBAR}>
|
|
323
|
+
</devtools-button>
|
|
324
|
+
<devtools-button
|
|
325
|
+
class="toolbar-button"
|
|
326
|
+
.iconName=${'bin'}
|
|
327
|
+
.title=${i18nString(UIStrings.deleteSelected)}
|
|
328
|
+
jslog=${VisualLogging.action('delete-selected').track({click: true})}
|
|
329
|
+
@click=${input.deleteButtonClicked}
|
|
330
|
+
.disabled=${input.selectedRowNumber < 0 || input.entries.length === 0}
|
|
331
|
+
.variant=${Buttons.Button.Variant.TOOLBAR}>
|
|
332
|
+
</devtools-button>
|
|
333
|
+
|
|
334
|
+
<div class="toolbar-divider"></div>
|
|
335
|
+
|
|
336
|
+
<devtools-button
|
|
337
|
+
class="toolbar-button"
|
|
338
|
+
.iconName=${'triangle-left'}
|
|
339
|
+
.title=${i18nString(UIStrings.showPreviousPage)}
|
|
340
|
+
.disabled=${input.skipCount <= 0}
|
|
341
|
+
@click=${input.pageBackButtonClicked}
|
|
342
|
+
.variant=${Buttons.Button.Variant.TOOLBAR}>
|
|
343
|
+
</devtools-button>
|
|
344
|
+
<devtools-button
|
|
345
|
+
class="toolbar-button"
|
|
346
|
+
.iconName=${'triangle-right'}
|
|
347
|
+
.title=${i18nString(UIStrings.showNextPage)}
|
|
348
|
+
.disabled=${!input.hasMore}
|
|
349
|
+
@click=${input.pageForwardButtonClicked}
|
|
350
|
+
.variant=${Buttons.Button.Variant.TOOLBAR}>
|
|
351
|
+
</devtools-button>
|
|
352
|
+
|
|
353
|
+
<devtools-toolbar-input
|
|
354
|
+
type="filter"
|
|
355
|
+
placeholder=${i18nString(UIStrings.filterByKey)}
|
|
356
|
+
class="key-filter-input"
|
|
357
|
+
.value=${input.keyFilter}
|
|
358
|
+
@change=${(e: CustomEvent<string>) => {
|
|
359
|
+
input.onKeyFilterChange(e.detail);
|
|
360
|
+
}}>
|
|
361
|
+
</devtools-toolbar-input>
|
|
362
|
+
|
|
363
|
+
${input.needsRefreshVisible ? html`
|
|
364
|
+
<div class="toolbar-divider"></div>
|
|
365
|
+
<div class="toolbar-item stale-data-warning" title=${
|
|
366
|
+
i18nString(
|
|
367
|
+
UIStrings
|
|
368
|
+
.someEntriesMayHaveBeenModified)}>
|
|
369
|
+
<devtools-icon name="warning" class="warning-icon"></devtools-icon>
|
|
370
|
+
<span>${i18nString(UIStrings.dataMayBeStale)}</span>
|
|
371
|
+
</div>
|
|
372
|
+
` : nothing}
|
|
373
|
+
</devtools-toolbar>`;
|
|
374
|
+
// clang-format on
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
const renderSummaryBar = (input: IndexedDBDataViewInput): LitTemplate => {
|
|
378
|
+
const metadata = input.metadata;
|
|
379
|
+
if (!metadata) {
|
|
380
|
+
return nothing;
|
|
381
|
+
}
|
|
382
|
+
// clang-format off
|
|
383
|
+
return html`
|
|
384
|
+
<div class="object-store-summary-bar">
|
|
385
|
+
<span>${i18nString(UIStrings.totalEntriesS, { PH1: String(metadata.entriesCount)})}</span>
|
|
386
|
+
${input.objectStore.autoIncrement ? html`
|
|
387
|
+
<span class="separator">\u2758</span>
|
|
388
|
+
<span>${i18nString(UIStrings.keyGeneratorValueS, {PH1: String(metadata.keyGeneratorValue)})}</span>`
|
|
389
|
+
: nothing}
|
|
390
|
+
</div>`;
|
|
391
|
+
// clang-format on
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
export type IDBDataViewView = (input: IndexedDBDataViewInput, output: undefined, target: HTMLElement) => void;
|
|
395
|
+
|
|
396
|
+
// clang-format off
|
|
397
|
+
export const IDB_DATA_VIEW_DEFAULT_VIEW: IDBDataViewView = (input, _output, target) => {
|
|
398
|
+
render(html`
|
|
399
|
+
${renderToolbar(input)}
|
|
400
|
+
<div class="data-grid-container">
|
|
401
|
+
${renderDataGrid(input)}
|
|
402
|
+
</div>
|
|
403
|
+
${renderSummaryBar(input)}
|
|
404
|
+
`, target, {container: {classes: ['indexed-db-data-view', 'storage-view']}});
|
|
405
|
+
};
|
|
406
|
+
// clang-format on
|
|
407
|
+
|
|
237
408
|
export class IDBDataView extends UI.View.SimpleView {
|
|
238
409
|
private readonly model: IndexedDBModel;
|
|
239
410
|
private readonly databaseId: DatabaseId;
|
|
@@ -259,14 +430,16 @@ export class IDBDataView extends UI.View.SimpleView {
|
|
|
259
430
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
|
260
431
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
261
432
|
private lastKey?: any;
|
|
433
|
+
readonly #view: IDBDataViewView;
|
|
262
434
|
|
|
263
435
|
constructor(model: IndexedDBModel, databaseId: DatabaseId, objectStore: ObjectStore, index: Index|null,
|
|
264
|
-
refreshObjectStoreCallback: () => void) {
|
|
436
|
+
refreshObjectStoreCallback: () => void, view = IDB_DATA_VIEW_DEFAULT_VIEW) {
|
|
265
437
|
super({
|
|
266
438
|
title: i18nString(UIStrings.idb),
|
|
267
439
|
viewId: 'idb',
|
|
268
440
|
jslog: `${VisualLogging.pane('indexed-db-data-view')}`,
|
|
269
441
|
});
|
|
442
|
+
this.#view = view;
|
|
270
443
|
this.registerRequiredCSS(indexedDBViewsStyles);
|
|
271
444
|
this.registerRequiredCSS(DataGrid.dataGridStyles);
|
|
272
445
|
|
|
@@ -275,8 +448,6 @@ export class IDBDataView extends UI.View.SimpleView {
|
|
|
275
448
|
this.isIndex = Boolean(index);
|
|
276
449
|
this.refreshObjectStoreCallback = refreshObjectStoreCallback;
|
|
277
450
|
|
|
278
|
-
this.element.classList.add('indexed-db-data-view', 'storage-view');
|
|
279
|
-
|
|
280
451
|
this.clearingObjectStore = false;
|
|
281
452
|
|
|
282
453
|
this.pageSize = 50;
|
|
@@ -286,124 +457,6 @@ export class IDBDataView extends UI.View.SimpleView {
|
|
|
286
457
|
this.update(objectStore, index);
|
|
287
458
|
}
|
|
288
459
|
|
|
289
|
-
private renderDataGrid(): LitTemplate {
|
|
290
|
-
const keyPath = this.isIndex && this.index ? this.index.keyPath : this.objectStore.keyPath;
|
|
291
|
-
// clang-format off
|
|
292
|
-
return html`<devtools-data-grid striped style="flex: auto;" name=${i18nString(UIStrings.indexedDb)} .template=${html`
|
|
293
|
-
<style>${indexedDBViewsStyles}</style>
|
|
294
|
-
<table>
|
|
295
|
-
<tr>
|
|
296
|
-
<th id="number" fixed width="50px">#</th>
|
|
297
|
-
<th id="key">${this.renderKeyColumnHeader(i18nString(UIStrings.keyString), keyPath)}</th>
|
|
298
|
-
${this.isIndex ? html`<th id="primary-key">${this.renderKeyColumnHeader(i18nString(UIStrings.primaryKey), this.objectStore.keyPath)}</th>` : nothing}
|
|
299
|
-
<th id="value">${i18nString(UIStrings.valueString)}</th>
|
|
300
|
-
</tr>
|
|
301
|
-
${repeat(this.entries, (_entry, index) => index, (entry, index) => html`
|
|
302
|
-
<tr ?selected=${index + this.skipCount === this.#selectedRowNumber}
|
|
303
|
-
@select=${() => this.onRowSelected(index + this.skipCount)}
|
|
304
|
-
@delete=${() => this.deleteEntry(entry)}
|
|
305
|
-
@contextmenu=${(e: CustomEvent<UI.ContextMenu.ContextMenu>) => this.populateContextMenu(e, entry)}>
|
|
306
|
-
<td>${index + this.skipCount}</td>
|
|
307
|
-
<td>${widget(ObjectPropertiesSectionWidget, {value: entry.key})}</td>
|
|
308
|
-
${this.isIndex ? html`<td>${widget(ObjectPropertiesSectionWidget, {value: entry.primaryKey})}</td>` : nothing}
|
|
309
|
-
<td class="value-column">${widget(ObjectPropertiesSectionWidget, {value: entry.value})}</td>
|
|
310
|
-
</tr>`
|
|
311
|
-
)}
|
|
312
|
-
</table>`}>
|
|
313
|
-
</devtools-data-grid>`;
|
|
314
|
-
// clang-format on
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
private renderKeyColumnHeader(prefix: string, keyPath: string|string[]|null|undefined): LitTemplate {
|
|
318
|
-
if (keyPath === undefined || keyPath === null || keyPath === '') {
|
|
319
|
-
return html`${prefix}`;
|
|
320
|
-
}
|
|
321
|
-
return html`
|
|
322
|
-
${prefix} (${i18nString(UIStrings.keyPath)}${
|
|
323
|
-
Array.isArray(keyPath) ?
|
|
324
|
-
html`[${keyPath.map((path, i) => html`${i > 0 ? ', ' : ''}${this.renderKeyPathString(path)}`)}]` :
|
|
325
|
-
this.renderKeyPathString(keyPath)})`;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
private renderKeyPathString(keyPathString: string): LitTemplate {
|
|
329
|
-
return html`"<span class="source-code indexed-db-key-path">${keyPathString}</span>"`;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
private renderToolbar(): LitTemplate {
|
|
333
|
-
// clang-format off
|
|
334
|
-
return html`
|
|
335
|
-
<devtools-toolbar class="data-view-toolbar" jslog=${VisualLogging.toolbar()}>
|
|
336
|
-
<devtools-button
|
|
337
|
-
class="toolbar-button"
|
|
338
|
-
.iconName=${'refresh'}
|
|
339
|
-
.title=${i18nString(UIStrings.refresh)}
|
|
340
|
-
jslog=${VisualLogging.action('refresh').track({click: true})}
|
|
341
|
-
@click=${() => this.refreshButtonClicked()}
|
|
342
|
-
.variant=${Buttons.Button.Variant.TOOLBAR}
|
|
343
|
-
></devtools-button>
|
|
344
|
-
<devtools-button
|
|
345
|
-
class="toolbar-button"
|
|
346
|
-
.iconName=${'clear'}
|
|
347
|
-
.title=${i18nString(UIStrings.clearObjectStore)}
|
|
348
|
-
jslog=${VisualLogging.action('clear-all').track({click: true})}
|
|
349
|
-
@click=${() => this.clearButtonClicked()}
|
|
350
|
-
.disabled=${this.isIndex || !this.#clearButtonEnabled}
|
|
351
|
-
.variant=${Buttons.Button.Variant.TOOLBAR}>
|
|
352
|
-
</devtools-button>
|
|
353
|
-
<devtools-button
|
|
354
|
-
class="toolbar-button"
|
|
355
|
-
.iconName=${'bin'}
|
|
356
|
-
.title=${i18nString(UIStrings.deleteSelected)}
|
|
357
|
-
jslog=${VisualLogging.action('delete-selected').track({click: true})}
|
|
358
|
-
@click=${() => this.deleteButtonClicked()}
|
|
359
|
-
.disabled=${this.#selectedRowNumber < 0 || this.entries.length === 0}
|
|
360
|
-
.variant=${Buttons.Button.Variant.TOOLBAR}>
|
|
361
|
-
</devtools-button>
|
|
362
|
-
|
|
363
|
-
<div class="toolbar-divider"></div>
|
|
364
|
-
|
|
365
|
-
<devtools-button
|
|
366
|
-
class="toolbar-button"
|
|
367
|
-
.iconName=${'triangle-left'}
|
|
368
|
-
.title=${i18nString(UIStrings.showPreviousPage)}
|
|
369
|
-
.disabled=${this.skipCount <= 0}
|
|
370
|
-
@click=${() => this.pageBackButtonClicked()}
|
|
371
|
-
.variant=${Buttons.Button.Variant.TOOLBAR}>
|
|
372
|
-
</devtools-button>
|
|
373
|
-
<devtools-button
|
|
374
|
-
class="toolbar-button"
|
|
375
|
-
.iconName=${'triangle-right'}
|
|
376
|
-
.title=${i18nString(UIStrings.showNextPage)}
|
|
377
|
-
.disabled=${!this.#hasMore}
|
|
378
|
-
@click=${() => this.pageForwardButtonClicked()}
|
|
379
|
-
.variant=${Buttons.Button.Variant.TOOLBAR}>
|
|
380
|
-
</devtools-button>
|
|
381
|
-
|
|
382
|
-
<devtools-toolbar-input
|
|
383
|
-
type="filter"
|
|
384
|
-
placeholder=${i18nString(UIStrings.filterByKey)}
|
|
385
|
-
class="key-filter-input"
|
|
386
|
-
.value=${this.#keyFilter}
|
|
387
|
-
@change=${(e: CustomEvent<string>) => {
|
|
388
|
-
this.#keyFilter = e.detail;
|
|
389
|
-
this.updateData(false);
|
|
390
|
-
}}>
|
|
391
|
-
</devtools-toolbar-input>
|
|
392
|
-
|
|
393
|
-
${this.#needsRefreshVisible ? html`
|
|
394
|
-
<div class="toolbar-divider"></div>
|
|
395
|
-
<div class="toolbar-item stale-data-warning" title=${
|
|
396
|
-
i18nString(
|
|
397
|
-
UIStrings
|
|
398
|
-
.someEntriesMayHaveBeenModified)}>
|
|
399
|
-
<devtools-icon name="warning" class="warning-icon"></devtools-icon>
|
|
400
|
-
<span>${i18nString(UIStrings.dataMayBeStale)}</span>
|
|
401
|
-
</div>
|
|
402
|
-
` : nothing}
|
|
403
|
-
</devtools-toolbar>`;
|
|
404
|
-
// clang-format on
|
|
405
|
-
}
|
|
406
|
-
|
|
407
460
|
private pageBackButtonClicked(): void {
|
|
408
461
|
this.skipCount = Math.max(0, this.skipCount - this.pageSize);
|
|
409
462
|
this.updateData(false);
|
|
@@ -519,23 +572,6 @@ export class IDBDataView extends UI.View.SimpleView {
|
|
|
519
572
|
});
|
|
520
573
|
}
|
|
521
574
|
|
|
522
|
-
private renderSummaryBar(): LitTemplate {
|
|
523
|
-
const metadata = this.#metadata;
|
|
524
|
-
if (!metadata) {
|
|
525
|
-
return nothing;
|
|
526
|
-
}
|
|
527
|
-
// clang-format off
|
|
528
|
-
return html`
|
|
529
|
-
<div class="object-store-summary-bar">
|
|
530
|
-
<span>${i18nString(UIStrings.totalEntriesS, { PH1: String(metadata.entriesCount)})}</span>
|
|
531
|
-
${this.objectStore.autoIncrement ? html`
|
|
532
|
-
<span class="separator">\u2758</span>
|
|
533
|
-
<span>${i18nString(UIStrings.keyGeneratorValueS, {PH1: String(metadata.keyGeneratorValue)})}</span>`
|
|
534
|
-
: nothing}
|
|
535
|
-
</div>`;
|
|
536
|
-
// clang-format on
|
|
537
|
-
}
|
|
538
|
-
|
|
539
575
|
private updatedDataForTests(): void {
|
|
540
576
|
// Sniffed in tests.
|
|
541
577
|
}
|
|
@@ -548,6 +584,8 @@ export class IDBDataView extends UI.View.SimpleView {
|
|
|
548
584
|
const ok =
|
|
549
585
|
await UI.UIUtils.ConfirmDialog.show(i18nString(UIStrings.objectStoreWillBeCleared),
|
|
550
586
|
i18nString(UIStrings.confirmClearObjectStore, {PH1: this.objectStore.name}),
|
|
587
|
+
// TODO(b/407750537): Fix the linter false positive
|
|
588
|
+
// eslint-disable-next-line @devtools/no-imperative-dom-api
|
|
551
589
|
this.element, {jslogContext: 'clear-object-store-confirmation'});
|
|
552
590
|
if (ok) {
|
|
553
591
|
this.#clearButtonEnabled = false;
|
|
@@ -622,22 +660,72 @@ export class IDBDataView extends UI.View.SimpleView {
|
|
|
622
660
|
}
|
|
623
661
|
|
|
624
662
|
override performUpdate(): void {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
663
|
+
this.#view({
|
|
664
|
+
isIndex: this.isIndex,
|
|
665
|
+
index: this.index,
|
|
666
|
+
objectStore: this.objectStore,
|
|
667
|
+
entries: this.entries,
|
|
668
|
+
skipCount: this.skipCount,
|
|
669
|
+
selectedRowNumber: this.#selectedRowNumber,
|
|
670
|
+
clearButtonEnabled: this.#clearButtonEnabled,
|
|
671
|
+
hasMore: this.#hasMore,
|
|
672
|
+
keyFilter: this.#keyFilter,
|
|
673
|
+
needsRefreshVisible: this.#needsRefreshVisible,
|
|
674
|
+
metadata: this.#metadata,
|
|
675
|
+
refreshButtonClicked: this.refreshButtonClicked.bind(this),
|
|
676
|
+
clearButtonClicked: this.clearButtonClicked.bind(this),
|
|
677
|
+
deleteButtonClicked: this.deleteButtonClicked.bind(this),
|
|
678
|
+
pageBackButtonClicked: this.pageBackButtonClicked.bind(this),
|
|
679
|
+
pageForwardButtonClicked: this.pageForwardButtonClicked.bind(this),
|
|
680
|
+
onKeyFilterChange: (value: string) => {
|
|
681
|
+
this.#keyFilter = value;
|
|
682
|
+
this.updateData(false);
|
|
683
|
+
},
|
|
684
|
+
onRowSelected: this.onRowSelected.bind(this),
|
|
685
|
+
deleteEntry: this.deleteEntry.bind(this),
|
|
686
|
+
populateContextMenu: this.populateContextMenu.bind(this),
|
|
687
|
+
},
|
|
688
|
+
undefined, this.element);
|
|
635
689
|
}
|
|
636
690
|
}
|
|
637
691
|
|
|
692
|
+
interface ObjectPropertiesSectionWidgetInput {
|
|
693
|
+
value: SDK.RemoteObject.RemoteObject|null;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
interface ObjectPropertiesSectionWidgetOutput {
|
|
697
|
+
objectPropSection: ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection|null;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
type ObjectPropertiesSectionWidgetView = (
|
|
701
|
+
input: ObjectPropertiesSectionWidgetInput,
|
|
702
|
+
output: ObjectPropertiesSectionWidgetOutput,
|
|
703
|
+
target: HTMLElement,
|
|
704
|
+
) => void;
|
|
705
|
+
|
|
706
|
+
const OBJECT_PROPERTIES_SECTION_WIDGET_DEFAULT_VIEW: ObjectPropertiesSectionWidgetView = (input, output, target) => {
|
|
707
|
+
if (!input.value) {
|
|
708
|
+
output.objectPropSection = null;
|
|
709
|
+
render(nothing, target);
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
const objectPropSection = ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection.defaultObjectPropertiesSection(
|
|
713
|
+
input.value, undefined /* linkifier */, true /* skipProto */, true /* readOnly */);
|
|
714
|
+
output.objectPropSection = objectPropSection;
|
|
715
|
+
|
|
716
|
+
const element = input.value.hasChildren ? objectPropSection.element : objectPropSection.titleElement;
|
|
717
|
+
render(html`${element}`, target);
|
|
718
|
+
};
|
|
719
|
+
|
|
638
720
|
class ObjectPropertiesSectionWidget extends UI.Widget.Widget {
|
|
639
721
|
#value: SDK.RemoteObject.RemoteObject|null = null;
|
|
640
722
|
#objectPropSection: ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection|null = null;
|
|
723
|
+
readonly #view: ObjectPropertiesSectionWidgetView;
|
|
724
|
+
|
|
725
|
+
constructor(element?: HTMLElement, view = OBJECT_PROPERTIES_SECTION_WIDGET_DEFAULT_VIEW) {
|
|
726
|
+
super(element);
|
|
727
|
+
this.#view = view;
|
|
728
|
+
}
|
|
641
729
|
|
|
642
730
|
set value(value: SDK.RemoteObject.RemoteObject|null) {
|
|
643
731
|
if (this.#value === value) {
|
|
@@ -652,20 +740,8 @@ class ObjectPropertiesSectionWidget extends UI.Widget.Widget {
|
|
|
652
740
|
}
|
|
653
741
|
|
|
654
742
|
override performUpdate(): void {
|
|
655
|
-
const
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
this.#objectPropSection = null;
|
|
659
|
-
return;
|
|
660
|
-
}
|
|
661
|
-
this.contentElement.removeChildren();
|
|
662
|
-
this.#objectPropSection = ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection.defaultObjectPropertiesSection(
|
|
663
|
-
value, undefined /* linkifier */, true /* skipProto */, true /* readOnly */);
|
|
664
|
-
|
|
665
|
-
if (value.hasChildren) {
|
|
666
|
-
this.contentElement.appendChild(this.#objectPropSection.element);
|
|
667
|
-
} else {
|
|
668
|
-
this.contentElement.appendChild(this.#objectPropSection.titleElement);
|
|
669
|
-
}
|
|
743
|
+
const output: ObjectPropertiesSectionWidgetOutput = {objectPropSection: null};
|
|
744
|
+
this.#view({value: this.#value}, output, this.contentElement);
|
|
745
|
+
this.#objectPropSection = output.objectPropSection;
|
|
670
746
|
}
|
|
671
747
|
}
|
|
@@ -227,16 +227,6 @@ export class SharedStorageModel extends SDK.SDKModel.SDKModel<EventTypes> implem
|
|
|
227
227
|
cacheStorageContentUpdated(_event: Protocol.Storage.CacheStorageContentUpdatedEvent): void {
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
interestGroupAccessed(_event: Protocol.Storage.InterestGroupAccessedEvent): void {
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
interestGroupAuctionEventOccurred(_event: Protocol.Storage.InterestGroupAuctionEventOccurredEvent): void {
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
interestGroupAuctionNetworkRequestCreated(_event: Protocol.Storage.InterestGroupAuctionNetworkRequestCreatedEvent):
|
|
237
|
-
void {
|
|
238
|
-
}
|
|
239
|
-
|
|
240
230
|
storageBucketCreatedOrUpdated(_event: Protocol.Storage.StorageBucketCreatedOrUpdatedEvent): void {
|
|
241
231
|
}
|
|
242
232
|
|