@zenfg/inspector 0.1.0-beta.3 → 0.1.0
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/GUIDE.md +182 -0
- package/README.md +61 -89
- package/THEMING.md +124 -0
- package/dist/FrameGraphInspector.d.ts +23 -4
- package/dist/FrameGraphInspector.d.ts.map +1 -1
- package/dist/FrameGraphInspector.js +137 -29
- package/dist/FrameGraphInspector.js.map +1 -1
- package/dist/capture.d.ts +5 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +2 -0
- package/dist/capture.js.map +1 -0
- package/dist/debugCaptureModel.d.ts +19 -0
- package/dist/debugCaptureModel.d.ts.map +1 -1
- package/dist/debugCaptureModel.js +36 -2
- package/dist/debugCaptureModel.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/panelAliasAnalysis.d.ts +1 -0
- package/dist/panelAliasAnalysis.d.ts.map +1 -1
- package/dist/panelAliasAnalysis.js +23 -54
- package/dist/panelAliasAnalysis.js.map +1 -1
- package/dist/panelCytoscapeGraphRenderer.d.ts +15 -2
- package/dist/panelCytoscapeGraphRenderer.d.ts.map +1 -1
- package/dist/panelCytoscapeGraphRenderer.js +145 -23
- package/dist/panelCytoscapeGraphRenderer.js.map +1 -1
- package/dist/panelDetailLayout.d.ts +27 -0
- package/dist/panelDetailLayout.d.ts.map +1 -0
- package/dist/panelDetailLayout.js +174 -0
- package/dist/panelDetailLayout.js.map +1 -0
- package/dist/panelDetailStyles.d.ts +2 -0
- package/dist/panelDetailStyles.d.ts.map +1 -0
- package/dist/panelDetailStyles.js +57 -0
- package/dist/panelDetailStyles.js.map +1 -0
- package/dist/panelDiagnosticsView.d.ts +10 -1
- package/dist/panelDiagnosticsView.d.ts.map +1 -1
- package/dist/panelDiagnosticsView.js +166 -57
- package/dist/panelDiagnosticsView.js.map +1 -1
- package/dist/panelDomHelpers.d.ts.map +1 -1
- package/dist/panelDomHelpers.js +6 -5
- package/dist/panelDomHelpers.js.map +1 -1
- package/dist/panelGraphLayout.d.ts +3 -2
- package/dist/panelGraphLayout.d.ts.map +1 -1
- package/dist/panelGraphLayout.js +6 -5
- package/dist/panelGraphLayout.js.map +1 -1
- package/dist/panelGraphRenderer.d.ts +10 -0
- package/dist/panelGraphRenderer.d.ts.map +1 -1
- package/dist/panelGraphRenderer.js.map +1 -1
- package/dist/panelGraphScene.d.ts +1 -0
- package/dist/panelGraphScene.d.ts.map +1 -1
- package/dist/panelGraphScene.js +69 -32
- package/dist/panelGraphScene.js.map +1 -1
- package/dist/panelGraphSearch.d.ts +16 -0
- package/dist/panelGraphSearch.d.ts.map +1 -0
- package/dist/panelGraphSearch.js +93 -0
- package/dist/panelGraphSearch.js.map +1 -0
- package/dist/panelGraphView.d.ts +82 -0
- package/dist/panelGraphView.d.ts.map +1 -1
- package/dist/panelGraphView.js +15 -4
- package/dist/panelGraphView.js.map +1 -1
- package/dist/panelGraphVisuals.d.ts +14 -6
- package/dist/panelGraphVisuals.d.ts.map +1 -1
- package/dist/panelGraphVisuals.js +126 -51
- package/dist/panelGraphVisuals.js.map +1 -1
- package/dist/panelInspectorView.d.ts +8 -0
- package/dist/panelInspectorView.d.ts.map +1 -1
- package/dist/panelInspectorView.js +242 -48
- package/dist/panelInspectorView.js.map +1 -1
- package/dist/panelListStyles.d.ts +3 -0
- package/dist/panelListStyles.d.ts.map +1 -0
- package/dist/panelListStyles.js +155 -0
- package/dist/panelListStyles.js.map +1 -0
- package/dist/panelMemoryStyles.d.ts +3 -0
- package/dist/panelMemoryStyles.d.ts.map +1 -0
- package/dist/panelMemoryStyles.js +42 -0
- package/dist/panelMemoryStyles.js.map +1 -0
- package/dist/panelMemoryView.d.ts +13 -1
- package/dist/panelMemoryView.d.ts.map +1 -1
- package/dist/panelMemoryView.js +161 -41
- package/dist/panelMemoryView.js.map +1 -1
- package/dist/panelPassesView.d.ts +15 -0
- package/dist/panelPassesView.d.ts.map +1 -1
- package/dist/panelPassesView.js +202 -72
- package/dist/panelPassesView.js.map +1 -1
- package/dist/panelRawView.d.ts +15 -0
- package/dist/panelRawView.d.ts.map +1 -0
- package/dist/panelRawView.js +105 -0
- package/dist/panelRawView.js.map +1 -0
- package/dist/panelResourcesView.d.ts +8 -0
- package/dist/panelResourcesView.d.ts.map +1 -1
- package/dist/panelResourcesView.js +62 -31
- package/dist/panelResourcesView.js.map +1 -1
- package/dist/panelSelection.d.ts +9 -1
- package/dist/panelSelection.d.ts.map +1 -1
- package/dist/panelSelection.js +34 -4
- package/dist/panelSelection.js.map +1 -1
- package/dist/panelTheme.d.ts +13 -0
- package/dist/panelTheme.d.ts.map +1 -0
- package/dist/panelTheme.js +104 -0
- package/dist/panelTheme.js.map +1 -0
- package/dist/panelTypes.d.ts +10 -1
- package/dist/panelTypes.d.ts.map +1 -1
- package/dist/panelTypes.js.map +1 -1
- package/dist/panelVisualTheme.d.ts +147 -50
- package/dist/panelVisualTheme.d.ts.map +1 -1
- package/dist/panelVisualTheme.js +34 -44
- package/dist/panelVisualTheme.js.map +1 -1
- package/dist/panelWorkbenchHelpers.d.ts +12 -1
- package/dist/panelWorkbenchHelpers.d.ts.map +1 -1
- package/dist/panelWorkbenchHelpers.js +62 -1
- package/dist/panelWorkbenchHelpers.js.map +1 -1
- package/dist/panelWorkbenchStyles.d.ts +2 -0
- package/dist/panelWorkbenchStyles.d.ts.map +1 -0
- package/dist/panelWorkbenchStyles.js +101 -0
- package/dist/panelWorkbenchStyles.js.map +1 -0
- package/dist/panelWorkbenchView.d.ts +16 -0
- package/dist/panelWorkbenchView.d.ts.map +1 -1
- package/dist/panelWorkbenchView.js +228 -50
- package/dist/panelWorkbenchView.js.map +1 -1
- package/dist/query.js.map +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +147 -195
- package/dist/styles.js.map +1 -1
- package/dist/theme.d.ts +22 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +10 -0
- package/dist/theme.js.map +1 -0
- package/dist/themeDefinitions.d.ts +251 -0
- package/dist/themeDefinitions.d.ts.map +1 -0
- package/dist/themeDefinitions.js +96 -0
- package/dist/themeDefinitions.js.map +1 -0
- package/dist/themePalette.d.ts +66 -0
- package/dist/themePalette.d.ts.map +1 -0
- package/dist/themePalette.js +37 -0
- package/dist/themePalette.js.map +1 -0
- package/dist/themes.css +165 -0
- package/package.json +44 -10
- package/src/FrameGraphInspector.ts +130 -31
- package/src/capture.ts +4 -0
- package/src/debugCaptureModel.ts +53 -2
- package/src/index.ts +6 -2
- package/src/panelAliasAnalysis.ts +24 -70
- package/src/panelCytoscapeGraphRenderer.ts +140 -23
- package/src/panelDetailLayout.ts +155 -0
- package/src/panelDetailStyles.ts +56 -0
- package/src/panelDiagnosticsView.ts +166 -85
- package/src/panelDomHelpers.ts +4 -5
- package/src/panelGraphLayout.ts +6 -5
- package/src/panelGraphRenderer.ts +7 -0
- package/src/panelGraphScene.ts +68 -30
- package/src/panelGraphSearch.ts +96 -0
- package/src/panelGraphView.ts +14 -4
- package/src/panelGraphVisuals.ts +122 -52
- package/src/panelInspectorView.ts +227 -48
- package/src/panelListStyles.ts +154 -0
- package/src/panelMemoryStyles.ts +41 -0
- package/src/panelMemoryView.ts +178 -53
- package/src/panelPassesView.ts +190 -137
- package/src/panelRawView.ts +99 -0
- package/src/panelResourcesView.ts +69 -56
- package/src/panelSelection.ts +37 -5
- package/src/panelTheme.ts +85 -0
- package/src/panelTypes.ts +7 -1
- package/src/panelVisualTheme.ts +38 -49
- package/src/panelWorkbenchHelpers.ts +60 -2
- package/src/panelWorkbenchStyles.ts +100 -0
- package/src/panelWorkbenchView.ts +201 -52
- package/src/query.ts +11 -11
- package/src/styles.ts +148 -195
- package/src/theme.ts +24 -0
- package/src/themeDefinitions.ts +103 -0
- package/src/themePalette.ts +44 -0
|
@@ -6,12 +6,17 @@ import type {
|
|
|
6
6
|
} from './debugCaptureModel.ts';
|
|
7
7
|
import { labelNode, labelResource } from './panelDomHelpers.ts';
|
|
8
8
|
import { createPanelIcon } from './panelIcons.ts';
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
9
|
+
import { RawDetailView } from './panelRawView.ts';
|
|
10
|
+
import { resolveNodeSelection, resolveSelectedCanonicalDetail } from './panelSelection.ts';
|
|
11
|
+
import type { InspectorTab, Selection, WorkbenchTab } from './panelTypes.ts';
|
|
11
12
|
import {
|
|
12
13
|
createRelationButton,
|
|
13
14
|
formatEstimatedBytes,
|
|
14
15
|
formatResourceDescriptor,
|
|
16
|
+
formatTimingCoverage,
|
|
17
|
+
enableTabKeyboard,
|
|
18
|
+
writeClipboardText,
|
|
19
|
+
selectionKey,
|
|
15
20
|
groupPath,
|
|
16
21
|
resourceLabel,
|
|
17
22
|
type WorkbenchCallbacks,
|
|
@@ -22,21 +27,24 @@ type DetailRelation = readonly [label: string, selection: Selection, description
|
|
|
22
27
|
function formatAccessFacts(access: FrameGraphDebugAccess): string {
|
|
23
28
|
return [
|
|
24
29
|
access.mode, access.access,
|
|
25
|
-
...(access.mode === 'write' ? [access.contents,
|
|
30
|
+
...(access.mode === 'write' ? [access.contents, access.producesValue ? 'produces a value' : 'does not produce a value'] : []),
|
|
26
31
|
...(access.bufferRange ? [`bytes ${access.bufferRange.offset}–${access.bufferRange.size === undefined ? 'end' : access.bufferRange.offset + access.bufferRange.size}`] : []),
|
|
27
|
-
...(access.textureRegion ? [
|
|
32
|
+
...(access.textureRegion ? [formatTextureRegion(access.textureRegion)] : []),
|
|
28
33
|
...(access.textureViewId ? [`view ${access.textureViewId}`] : []),
|
|
29
34
|
].join(' · ');
|
|
30
35
|
}
|
|
31
36
|
|
|
37
|
+
function formatTextureRegion(region: NonNullable<FrameGraphDebugAccess['textureRegion']>): string {
|
|
38
|
+
const end = (start: number | undefined, count: number | undefined) => start === undefined ? 'unknown' : count === undefined ? `${start}–end` : `${start}–${start + count - 1}`;
|
|
39
|
+
return `mip ${end(region.baseMipLevel, region.mipLevelCount)} · ${region.baseDepthSlice === undefined
|
|
40
|
+
? `layers ${end(region.baseArrayLayer, region.arrayLayerCount)}`
|
|
41
|
+
: `depth ${end(region.baseDepthSlice, region.depthSliceCount)}`} · aspect ${region.aspect}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
function formatRootRange(root: FrameGraphDebugRoot): string {
|
|
33
45
|
if (!root.range) return 'Range unavailable';
|
|
34
46
|
if (root.range.kind === 'buffer') return `bytes ${root.range.offset}–${root.range.offset + root.range.size}`;
|
|
35
|
-
return root.range.regions.map((
|
|
36
|
-
`mip ${region.baseMipLevel}+${region.mipLevelCount} · ${region.baseDepthSlice === undefined
|
|
37
|
-
? `layers ${region.baseArrayLayer}+${region.arrayLayerCount}`
|
|
38
|
-
: `depth ${region.baseDepthSlice}+${region.depthSliceCount}`} · ${region.aspect}`,
|
|
39
|
-
).join('; ');
|
|
47
|
+
return root.range.regions.map(formatTextureRegion).join('; ');
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
export class InspectorView {
|
|
@@ -48,8 +56,9 @@ export class InspectorView {
|
|
|
48
56
|
private snapshot: FrameGraphDebugViewModel | undefined;
|
|
49
57
|
private selected: Selection | undefined;
|
|
50
58
|
private activeTab: InspectorTab = 'summary';
|
|
51
|
-
private open =
|
|
59
|
+
private open = false;
|
|
52
60
|
private hoveredLink: HTMLButtonElement | undefined;
|
|
61
|
+
private rawCache: { readonly snapshot: FrameGraphDebugViewModel; readonly key: string; readonly view: RawDetailView } | undefined;
|
|
53
62
|
|
|
54
63
|
constructor(
|
|
55
64
|
private readonly callbacks: WorkbenchCallbacks,
|
|
@@ -86,6 +95,7 @@ export class InspectorView {
|
|
|
86
95
|
this.tabs.set(tab, button);
|
|
87
96
|
this.tabList.appendChild(button);
|
|
88
97
|
}
|
|
98
|
+
enableTabKeyboard(this.tabList);
|
|
89
99
|
this.content.id = `${idPrefix}-inspector-panel`;
|
|
90
100
|
this.content.className = 'zenfg-inspector-inspector-content';
|
|
91
101
|
this.content.setAttribute('role', 'tabpanel');
|
|
@@ -95,15 +105,21 @@ export class InspectorView {
|
|
|
95
105
|
}
|
|
96
106
|
|
|
97
107
|
setSnapshot(snapshot: FrameGraphDebugViewModel): void {
|
|
108
|
+
if (this.snapshot !== snapshot) this.rawCache = undefined;
|
|
98
109
|
this.snapshot = snapshot;
|
|
99
110
|
this.render();
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
setSelection(selected: Selection | undefined, reveal = true): void {
|
|
114
|
+
if (!selected || !this.selected || selectionKey(selected) !== selectionKey(this.selected)) this.rawCache = undefined;
|
|
103
115
|
if (selected?.kind === 'resource'
|
|
104
116
|
&& (this.selected?.kind !== 'resource' || this.selected.id !== selected.id)) this.activeTab = 'summary';
|
|
105
117
|
this.selected = selected;
|
|
106
|
-
if (selected
|
|
118
|
+
if (!selected) this.setOpen(false);
|
|
119
|
+
else if (reveal && !this.open) {
|
|
120
|
+
this.setOpen(true);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
107
123
|
this.render();
|
|
108
124
|
}
|
|
109
125
|
|
|
@@ -112,6 +128,7 @@ export class InspectorView {
|
|
|
112
128
|
if (!open) this.clearLinkHover();
|
|
113
129
|
this.open = open;
|
|
114
130
|
this.updateOpenState();
|
|
131
|
+
if (open) this.render();
|
|
115
132
|
this.onOpenChange(open);
|
|
116
133
|
}
|
|
117
134
|
|
|
@@ -125,11 +142,13 @@ export class InspectorView {
|
|
|
125
142
|
}
|
|
126
143
|
|
|
127
144
|
private render(): void {
|
|
145
|
+
const restoreFocus = this.content.contains(document.activeElement);
|
|
128
146
|
this.clearLinkHover();
|
|
129
147
|
for (const [tab, button] of this.tabs) {
|
|
130
148
|
const active = tab === this.activeTab;
|
|
131
149
|
button.classList.toggle('active', active);
|
|
132
150
|
button.setAttribute('aria-selected', active ? 'true' : 'false');
|
|
151
|
+
button.tabIndex = active ? 0 : -1;
|
|
133
152
|
if (active) this.content.setAttribute('aria-labelledby', button.id);
|
|
134
153
|
}
|
|
135
154
|
const snapshot = this.snapshot;
|
|
@@ -144,32 +163,52 @@ export class InspectorView {
|
|
|
144
163
|
return;
|
|
145
164
|
}
|
|
146
165
|
this.title.textContent = this.selectionTitle(snapshot, selected);
|
|
166
|
+
if (!this.open) return;
|
|
147
167
|
if (this.activeTab === 'raw') {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
168
|
+
const key = selectionKey(selected);
|
|
169
|
+
if (this.rawCache?.snapshot !== snapshot || this.rawCache.key !== key) {
|
|
170
|
+
const detail = resolveSelectedCanonicalDetail(snapshot, selected);
|
|
171
|
+
this.rawCache = detail ? { snapshot, key, view: new RawDetailView(detail, Boolean(snapshot.protocol.capture.migration)) } : undefined;
|
|
172
|
+
}
|
|
173
|
+
if (this.rawCache) this.content.appendChild(this.rawCache.view.root);
|
|
174
|
+
else this.content.textContent = 'Canonical object unavailable in this capture.';
|
|
152
175
|
} else if (this.activeTab === 'relations') {
|
|
153
176
|
this.content.appendChild(this.createRelations(snapshot, selected));
|
|
154
177
|
} else {
|
|
155
|
-
this.content.
|
|
178
|
+
this.content.append(this.createLocationActions(snapshot, selected), this.createSummary(snapshot, selected));
|
|
179
|
+
const identity = this.selectionId(snapshot, selected);
|
|
180
|
+
if (identity) this.content.appendChild(this.summary([['ID', this.copyId(identity)]]));
|
|
181
|
+
const diagnostics = this.createDiagnostics(snapshot, selected);
|
|
182
|
+
if (diagnostics) this.content.appendChild(diagnostics);
|
|
183
|
+
if (selected.kind === 'node' || selected.kind === 'culled') {
|
|
184
|
+
const node = snapshot.nodeById.get(selected.id) ?? snapshot.culledById.get(selected.id)?.node;
|
|
185
|
+
if (node) {
|
|
186
|
+
const accesses = document.createElement('details');
|
|
187
|
+
const heading = document.createElement('summary');
|
|
188
|
+
heading.textContent = `Access facts · ${node.reads.length + node.writes.length}`;
|
|
189
|
+
accesses.append(heading, this.accessRelations('Reads', node.reads), this.accessRelations('Writes', node.writes));
|
|
190
|
+
this.content.appendChild(accesses);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
156
193
|
}
|
|
194
|
+
// Selecting a relation replaces its button. Keep keyboard focus in the pane.
|
|
195
|
+
if (restoreFocus) this.tabs.get(this.activeTab)?.focus();
|
|
157
196
|
}
|
|
158
197
|
|
|
159
198
|
private selectionTitle(snapshot: FrameGraphDebugViewModel, selection: Selection): string {
|
|
160
199
|
switch (selection.kind) {
|
|
161
200
|
case 'node': {
|
|
162
201
|
const node = snapshot.nodeById.get(selection.id);
|
|
163
|
-
return node ? labelNode(node) :
|
|
202
|
+
return node ? labelNode(node) : selection.id;
|
|
164
203
|
}
|
|
165
204
|
case 'group': return snapshot.groupByPathKey.get(selection.pathKey)?.label ?? 'Group';
|
|
166
205
|
case 'resource': {
|
|
167
206
|
const resource = snapshot.resourceById.get(selection.id);
|
|
168
|
-
return resource ? labelResource(resource) :
|
|
207
|
+
return resource ? labelResource(resource) : selection.id;
|
|
169
208
|
}
|
|
170
|
-
case 'allocation': return `Allocation
|
|
209
|
+
case 'allocation': return /^allocation[:#-]/i.test(selection.id) ? selection.id : `Allocation ${selection.id}`;
|
|
171
210
|
case 'root': return 'Output root';
|
|
172
|
-
case 'culled': return
|
|
211
|
+
case 'culled': return `${snapshot.culledById.get(selection.id)?.node.label ?? selection.id} (culled)`;
|
|
173
212
|
case 'segment': return `Segment #${selection.index}`;
|
|
174
213
|
}
|
|
175
214
|
}
|
|
@@ -180,12 +219,21 @@ export class InspectorView {
|
|
|
180
219
|
const node = snapshot.nodeById.get(selection.id);
|
|
181
220
|
if (!node) return this.summary([]);
|
|
182
221
|
const segment = snapshot.segmentByNodeId.get(node.id);
|
|
222
|
+
const roots = snapshot.roots.filter((root) => root.nodeId === node.id || root.resolution?.producerNodeIds.includes(node.id));
|
|
183
223
|
return this.summary([
|
|
224
|
+
['Compile state', 'Retained · compiler included this pass; execution success is not implied'],
|
|
225
|
+
['Retention', roots.length ? roots.map((root) => root.reason).join(', ') : 'No direct output root recorded; inspect dependencies in Relations'],
|
|
184
226
|
['Kind', node.kind],
|
|
185
|
-
['
|
|
227
|
+
['Execution slot', String(node.order)],
|
|
186
228
|
['Group', groupPath(snapshot, node.debugGroupId)],
|
|
187
229
|
['Segment', segment ? `#${segment.index} ${segment.kind}` : '-'],
|
|
188
|
-
['
|
|
230
|
+
['CPU duration', node.cpuDurationMicros === undefined ? 'Not collected' : (node.cpuDurationMicros / 1000).toFixed(3) + ' ms'],
|
|
231
|
+
['CPU scope', 'Synchronous elapsed time; zero may reflect clock precision.' + (node.kind === 'external-submission' ? ' Includes synchronous external submission.' : '')],
|
|
232
|
+
['GPU duration', node.kind === 'external-submission' ? 'Opaque · external work is not measured'
|
|
233
|
+
: node.kind !== 'render' && node.kind !== 'compute' ? 'Not applicable · this pass kind is not timing eligible'
|
|
234
|
+
: node.gpuDurationMicros === undefined ? `Not collected${snapshot.profiling.status === 'unavailable' ? ` · ${snapshot.profiling.reason}` : ''}`
|
|
235
|
+
: `${(node.gpuDurationMicros / 1000).toFixed(3)} ms`],
|
|
236
|
+
['GPU scope', 'GPU timestamp interval for render/compute passes; excludes external work. Zero may reflect timestamp precision.'],
|
|
189
237
|
['Accesses', `${node.reads.length} reads · ${node.writes.length} writes`],
|
|
190
238
|
['Side effect', node.sideEffect ? 'yes' : 'no'],
|
|
191
239
|
]);
|
|
@@ -197,9 +245,12 @@ export class InspectorView {
|
|
|
197
245
|
['Path', group.path.join(' / ')],
|
|
198
246
|
['Retained', String(group.summary.retainedNodeCount)],
|
|
199
247
|
['Culled', String(group.summary.culledNodeCount)],
|
|
200
|
-
['
|
|
201
|
-
['
|
|
202
|
-
['
|
|
248
|
+
['CPU coverage', formatTimingCoverage(group.summary.cpuTimedNodeCount, group.summary.retainedNodeCount)],
|
|
249
|
+
['CPU pass sum', group.summary.cpuTimedNodeCount ? (group.summary.cpuWorkDurationMicros / 1000).toFixed(3) + ' ms' : 'Not collected'],
|
|
250
|
+
['GPU coverage', formatTimingCoverage(group.summary.timedNodeCount, group.summary.timingEligibleNodeCount)],
|
|
251
|
+
['GPU pass sum', group.summary.timingEligibleNodeCount === 0 ? 'Not applicable' : group.summary.timedNodeCount === 0 ? 'Not collected' : (group.summary.gpuWorkDurationMicros / 1000).toFixed(3) + ' ms'],
|
|
252
|
+
['Opaque passes', `${group.summary.externalSubmissionCount} · excluded from GPU pass sum`],
|
|
253
|
+
['Allocations', snapshot.protocol.memory.allocationReport.status === 'available' ? String(group.summary.physicalAllocationCount) : 'Unknown · allocation report unavailable'],
|
|
203
254
|
['Segments', String(group.summary.executionSegmentCount)],
|
|
204
255
|
]);
|
|
205
256
|
}
|
|
@@ -210,9 +261,14 @@ export class InspectorView {
|
|
|
210
261
|
['Kind / origin', `${resource.kind} · ${resource.origin}`],
|
|
211
262
|
['Group', groupPath(snapshot, resource.debugGroupId)],
|
|
212
263
|
['Descriptor', formatResourceDescriptor(resource)],
|
|
213
|
-
['
|
|
214
|
-
['Lifetime', resource.lifetime ?
|
|
215
|
-
['Allocation', resource.physicalResourceId
|
|
264
|
+
['Resource estimate', `${formatEstimatedBytes(resource.estimatedByteSize)} · logical descriptor estimate`],
|
|
265
|
+
['Lifetime', resource.lifetime ? `execution slots ${resource.lifetime.firstUse}–${resource.lifetime.lastUse} (inclusive)` : 'Unavailable'],
|
|
266
|
+
['Allocation', resource.physicalResourceId !== undefined
|
|
267
|
+
? this.createDetailLink(resource.physicalResourceId, { kind: 'allocation', id: resource.physicalResourceId })
|
|
268
|
+
: resource.origin !== 'transient' ? 'Not applicable · externally owned resource'
|
|
269
|
+
: snapshot.protocol.memory.allocationReport.status === 'unavailable' ? 'Unavailable · allocation report not captured'
|
|
270
|
+
: 'Unallocated'],
|
|
271
|
+
['Initial contents', resource.initialContents ?? 'Unknown'],
|
|
216
272
|
['Usage', resource.usageFlags.join(', ') || '-'],
|
|
217
273
|
]);
|
|
218
274
|
}
|
|
@@ -222,7 +278,7 @@ export class InspectorView {
|
|
|
222
278
|
return this.summary([
|
|
223
279
|
['Kind', allocation.kind],
|
|
224
280
|
['Compatibility class', String(allocation.compatibilityClassId)],
|
|
225
|
-
['
|
|
281
|
+
['Physical estimate', `${formatEstimatedBytes(allocation.estimatedByteSize)} · allocation capacity estimate`],
|
|
226
282
|
['Logical resources', String(allocation.resourceIds.length)],
|
|
227
283
|
['Alias', allocation.resourceIds.length > 1 ? `yes · ×${allocation.resourceIds.length}` : 'single'],
|
|
228
284
|
]);
|
|
@@ -231,22 +287,24 @@ export class InspectorView {
|
|
|
231
287
|
const root = snapshot.roots.find((root) => root.key === selection.key);
|
|
232
288
|
return this.summary(root ? [
|
|
233
289
|
['Reason', root.reason],
|
|
234
|
-
['Node', root.nodeId === undefined ? '
|
|
290
|
+
['Node', root.nodeId === undefined ? 'Not applicable' : this.nodeLink(snapshot, root.nodeId)],
|
|
235
291
|
['Resource', root.resource ? this.viewResourceButton(snapshot, root.resource.id) : '-'],
|
|
236
292
|
...(root.reason === 'side-effect' ? [] : [
|
|
237
|
-
['Range', root.range ?
|
|
293
|
+
['Range', root.range ? formatRootRange(root) : 'Unavailable in Legacy capture'],
|
|
238
294
|
['Initial contents', root.resolution ? String(root.resolution.usesInitialContents) : 'Unavailable in Legacy capture'],
|
|
239
295
|
['Producers', root.resolution ? root.resolution.producerNodeIds.join(', ') || 'None' : 'Unavailable in Legacy capture'],
|
|
240
296
|
] as [string, string][]),
|
|
241
297
|
] : []);
|
|
242
298
|
}
|
|
243
299
|
case 'culled': {
|
|
244
|
-
const culled = snapshot.
|
|
300
|
+
const culled = snapshot.culledById.get(selection.id);
|
|
245
301
|
return this.summary(culled ? [
|
|
302
|
+
['Compile state', 'Culled · excluded by the compiler'],
|
|
246
303
|
['Node', labelNode(culled.node)],
|
|
247
304
|
['Kind', culled.node.kind],
|
|
248
305
|
['Group', groupPath(snapshot, culled.node.debugGroupId)],
|
|
249
306
|
['Reason', culled.reason],
|
|
307
|
+
['Execution / segment / CPU / GPU', 'Not applicable · culled passes do not execute'],
|
|
250
308
|
['Accesses', `${culled.node.reads.length} reads · ${culled.node.writes.length} writes`],
|
|
251
309
|
] : []);
|
|
252
310
|
}
|
|
@@ -266,6 +324,7 @@ export class InspectorView {
|
|
|
266
324
|
private createRelations(snapshot: FrameGraphDebugViewModel, selection: Selection): HTMLElement {
|
|
267
325
|
const host = document.createElement('div');
|
|
268
326
|
host.className = 'zenfg-inspector-inspector-relations';
|
|
327
|
+
host.appendChild(this.createLocationActions(snapshot, selection));
|
|
269
328
|
switch (selection.kind) {
|
|
270
329
|
case 'node': {
|
|
271
330
|
const node = snapshot.nodeById.get(selection.id);
|
|
@@ -278,6 +337,18 @@ export class InspectorView {
|
|
|
278
337
|
if (segment) host.appendChild(this.relationGroup('Segment', [
|
|
279
338
|
[`#${segment.index} ${segment.kind}`, { kind: 'segment', index: segment.index }],
|
|
280
339
|
]));
|
|
340
|
+
for (const kind of ['value', 'ordering'] as const) {
|
|
341
|
+
const relations: DetailRelation[] = [];
|
|
342
|
+
for (const edge of snapshot.edges) {
|
|
343
|
+
if (edge.kind !== kind || (edge.fromNodeId !== node.id && edge.toNodeId !== node.id)) continue;
|
|
344
|
+
const upstream = edge.toNodeId === node.id;
|
|
345
|
+
const otherId = upstream ? edge.fromNodeId : edge.toNodeId;
|
|
346
|
+
const other = resolveNodeSelection(snapshot, otherId);
|
|
347
|
+
if (other) relations.push([this.accessNodeLabel(snapshot, otherId), other,
|
|
348
|
+
`${upstream ? 'Upstream' : 'Downstream'} · ${resourceLabel(snapshot, edge.resource.id)} · ${kind} dependency`]);
|
|
349
|
+
}
|
|
350
|
+
if (relations.length) host.appendChild(this.relationGroup(kind === 'value' ? 'Value dependencies' : 'Ordering dependencies', relations));
|
|
351
|
+
}
|
|
281
352
|
}
|
|
282
353
|
break;
|
|
283
354
|
}
|
|
@@ -288,7 +359,7 @@ export class InspectorView {
|
|
|
288
359
|
this.resourceRelations('Inputs', group.summary.inputResources),
|
|
289
360
|
this.resourceRelations('Outputs', group.summary.outputResources),
|
|
290
361
|
this.relationGroup('Output roots', group.summary.outputRoots.map((root) => [
|
|
291
|
-
`${root.resource ? labelResource(root.resource) : '-'} · ${root.reason} · ${
|
|
362
|
+
`${root.resource ? labelResource(root.resource) : '-'} · ${root.reason} · ${formatRootRange(root)}`,
|
|
292
363
|
{ kind: 'root', key: root.key },
|
|
293
364
|
])),
|
|
294
365
|
);
|
|
@@ -313,7 +384,7 @@ export class InspectorView {
|
|
|
313
384
|
`${root.reason} · ${formatRootRange(root)}`, { kind: 'root', key: root.key },
|
|
314
385
|
])));
|
|
315
386
|
if (resource?.physicalResourceId !== undefined) host.appendChild(this.relationGroup('Allocation', [
|
|
316
|
-
[
|
|
387
|
+
[resource.physicalResourceId, { kind: 'allocation', id: resource.physicalResourceId }],
|
|
317
388
|
]));
|
|
318
389
|
break;
|
|
319
390
|
}
|
|
@@ -337,7 +408,7 @@ export class InspectorView {
|
|
|
337
408
|
break;
|
|
338
409
|
}
|
|
339
410
|
case 'culled': {
|
|
340
|
-
const culled = snapshot.
|
|
411
|
+
const culled = snapshot.culledById.get(selection.id);
|
|
341
412
|
if (culled) host.append(
|
|
342
413
|
this.accessRelations('Reads', culled.node.reads),
|
|
343
414
|
this.accessRelations('Writes', culled.node.writes),
|
|
@@ -353,7 +424,7 @@ export class InspectorView {
|
|
|
353
424
|
break;
|
|
354
425
|
}
|
|
355
426
|
}
|
|
356
|
-
if (host.childElementCount ===
|
|
427
|
+
if (host.childElementCount === 1) {
|
|
357
428
|
const empty = document.createElement('p');
|
|
358
429
|
empty.className = 'zenfg-inspector-muted';
|
|
359
430
|
empty.textContent = 'No related objects.';
|
|
@@ -383,17 +454,20 @@ export class InspectorView {
|
|
|
383
454
|
section.appendChild(heading);
|
|
384
455
|
for (const [label, selection, description] of relations) {
|
|
385
456
|
const link = this.createDetailLink(label, selection);
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
457
|
+
const entry = document.createElement('div');
|
|
458
|
+
entry.className = 'zenfg-inspector-relation-entry';
|
|
459
|
+
const links = document.createElement('div');
|
|
460
|
+
links.className = 'zenfg-inspector-relation-links';
|
|
461
|
+
links.appendChild(link);
|
|
462
|
+
if (this.callbacks.onReveal) links.appendChild(this.revealButton(selection, this.primaryPage(selection)));
|
|
463
|
+
entry.appendChild(links);
|
|
464
|
+
if (description !== undefined) {
|
|
391
465
|
const metadata = document.createElement('span');
|
|
392
466
|
metadata.className = 'zenfg-inspector-muted';
|
|
393
467
|
metadata.textContent = description;
|
|
394
|
-
entry.
|
|
395
|
-
section.appendChild(entry);
|
|
468
|
+
entry.appendChild(metadata);
|
|
396
469
|
}
|
|
470
|
+
section.appendChild(entry);
|
|
397
471
|
}
|
|
398
472
|
if (relations.length === 0) {
|
|
399
473
|
const empty = document.createElement('span');
|
|
@@ -453,13 +527,118 @@ export class InspectorView {
|
|
|
453
527
|
private accessNodeLabel(snapshot: FrameGraphDebugViewModel, nodeId: string): string {
|
|
454
528
|
const node = snapshot.nodeById.get(nodeId);
|
|
455
529
|
if (node) return labelNode(node);
|
|
456
|
-
const culled = snapshot.
|
|
457
|
-
return culled ? `${labelNode(culled.node)} (culled)` :
|
|
530
|
+
const culled = snapshot.culledById.get(nodeId);
|
|
531
|
+
return culled ? `${labelNode(culled.node)} (culled)` : nodeId;
|
|
458
532
|
}
|
|
459
533
|
|
|
460
534
|
private accessNodeSelection(snapshot: FrameGraphDebugViewModel, nodeId: string): Selection | undefined {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
535
|
+
return resolveNodeSelection(snapshot, nodeId);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
private nodeLink(snapshot: FrameGraphDebugViewModel, id: string): string | HTMLButtonElement {
|
|
539
|
+
const selected = resolveNodeSelection(snapshot, id);
|
|
540
|
+
return selected ? this.createDetailLink(this.accessNodeLabel(snapshot, id), selected) : id;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
private primaryPage(selection: Selection): WorkbenchTab {
|
|
544
|
+
switch (selection.kind) {
|
|
545
|
+
case 'node': case 'culled': case 'group': return 'passes';
|
|
546
|
+
case 'resource': return 'resources';
|
|
547
|
+
case 'allocation': return 'memory';
|
|
548
|
+
case 'root': case 'segment': return 'diagnostics';
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
private revealButton(selection: Selection, page: WorkbenchTab): HTMLButtonElement {
|
|
553
|
+
const button = document.createElement('button');
|
|
554
|
+
button.type = 'button';
|
|
555
|
+
button.className = 'zenfg-inspector-inline-action';
|
|
556
|
+
button.textContent = `Locate in ${page[0].toUpperCase()}${page.slice(1)}`;
|
|
557
|
+
button.addEventListener('click', () => {
|
|
558
|
+
this.clearLinkHover();
|
|
559
|
+
this.callbacks.onReveal?.(selection, page);
|
|
560
|
+
});
|
|
561
|
+
return button;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
private createLocationActions(snapshot: FrameGraphDebugViewModel, selection: Selection): HTMLElement {
|
|
565
|
+
const actions = document.createElement('div');
|
|
566
|
+
actions.className = 'zenfg-inspector-detail-actions';
|
|
567
|
+
if (!this.callbacks.onReveal) return actions;
|
|
568
|
+
actions.appendChild(this.revealButton(selection, this.primaryPage(selection)));
|
|
569
|
+
if (selection.kind === 'node' || selection.kind === 'group' || selection.kind === 'resource' || selection.kind === 'root') {
|
|
570
|
+
actions.appendChild(this.revealButton(selection, 'graph'));
|
|
571
|
+
}
|
|
572
|
+
if (selection.kind === 'resource' && snapshot.resourceById.get(selection.id)?.origin === 'transient') actions.appendChild(this.revealButton(selection, 'memory'));
|
|
573
|
+
if (selection.kind === 'culled') {
|
|
574
|
+
const note = document.createElement('span');
|
|
575
|
+
note.className = 'zenfg-inspector-muted';
|
|
576
|
+
note.textContent = 'Culled passes are absent from Graph. Locate them in Passes.';
|
|
577
|
+
actions.appendChild(note);
|
|
578
|
+
}
|
|
579
|
+
return actions;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
private selectionId(snapshot: FrameGraphDebugViewModel, selection: Selection): string | undefined {
|
|
583
|
+
if ('id' in selection) return selection.id;
|
|
584
|
+
if (selection.kind === 'group') return snapshot.groupByPathKey.get(selection.pathKey)?.id;
|
|
585
|
+
if (selection.kind === 'segment') return snapshot.segmentByIndex.get(selection.index)?.id;
|
|
586
|
+
return undefined;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
private copyId(id: string): HTMLElement {
|
|
590
|
+
const host = document.createElement('span');
|
|
591
|
+
host.className = 'zenfg-inspector-copy-id';
|
|
592
|
+
const code = document.createElement('code');
|
|
593
|
+
code.textContent = id;
|
|
594
|
+
const button = document.createElement('button');
|
|
595
|
+
button.type = 'button';
|
|
596
|
+
button.textContent = 'Copy ID';
|
|
597
|
+
button.setAttribute('aria-label', 'Copy full object ID');
|
|
598
|
+
button.addEventListener('click', () => {
|
|
599
|
+
void writeClipboardText(id).then(() => { button.textContent = 'Copied'; }, () => { button.textContent = 'Copy failed'; });
|
|
600
|
+
});
|
|
601
|
+
host.append(code, button);
|
|
602
|
+
return host;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
private createDiagnostics(snapshot: FrameGraphDebugViewModel, selection: Selection): HTMLElement | undefined {
|
|
606
|
+
let diagnostics: FrameGraphDebugViewModel['protocol']['diagnostics'] = [];
|
|
607
|
+
if (selection.kind === 'node' || selection.kind === 'culled') diagnostics = snapshot.diagnosticsByNodeId.get(selection.id) ?? [];
|
|
608
|
+
else if (selection.kind === 'resource') diagnostics = snapshot.diagnosticsByResourceId.get(selection.id) ?? [];
|
|
609
|
+
else if (selection.kind === 'allocation') {
|
|
610
|
+
const resourceIds = new Set(snapshot.allocationById.get(selection.id)?.resourceIds);
|
|
611
|
+
diagnostics = snapshot.protocol.diagnostics.filter((diagnostic) => diagnostic.resourceId !== undefined && resourceIds.has(diagnostic.resourceId));
|
|
612
|
+
} else if (selection.kind === 'group') {
|
|
613
|
+
const groupId = snapshot.groupByPathKey.get(selection.pathKey)?.id;
|
|
614
|
+
const groups = new Set(snapshot.debugGroups.filter((group) => groupId !== undefined && group.ancestorIds.includes(groupId)).map((group) => group.id));
|
|
615
|
+
diagnostics = snapshot.protocol.diagnostics.filter((diagnostic) => {
|
|
616
|
+
const nodeGroup = diagnostic.nodeId ? snapshot.canonicalNodeById.get(diagnostic.nodeId)?.groupId : undefined;
|
|
617
|
+
const resourceGroup = diagnostic.resourceId ? snapshot.resourceById.get(diagnostic.resourceId)?.debugGroupId : undefined;
|
|
618
|
+
return (nodeGroup !== undefined && groups.has(nodeGroup)) || (resourceGroup !== undefined && groups.has(resourceGroup));
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
if (!diagnostics.length) return undefined;
|
|
622
|
+
const section = document.createElement('section');
|
|
623
|
+
section.className = 'zenfg-inspector-detail-diagnostics';
|
|
624
|
+
const heading = document.createElement('h3');
|
|
625
|
+
heading.textContent = `Related diagnostics ${diagnostics.length}`;
|
|
626
|
+
section.appendChild(heading);
|
|
627
|
+
for (const diagnostic of diagnostics) {
|
|
628
|
+
const entry = document.createElement('article');
|
|
629
|
+
entry.dataset.severity = diagnostic.severity;
|
|
630
|
+
const label = document.createElement('strong');
|
|
631
|
+
label.textContent = `${diagnostic.severity} · ${diagnostic.code}`;
|
|
632
|
+
const message = document.createElement('p');
|
|
633
|
+
message.textContent = diagnostic.message;
|
|
634
|
+
entry.append(label, message);
|
|
635
|
+
if (diagnostic.nodeId) {
|
|
636
|
+
const node = resolveNodeSelection(snapshot, diagnostic.nodeId);
|
|
637
|
+
if (node) entry.appendChild(this.createDetailLink(this.accessNodeLabel(snapshot, diagnostic.nodeId), node));
|
|
638
|
+
}
|
|
639
|
+
if (diagnostic.resourceId) entry.appendChild(this.viewResourceButton(snapshot, diagnostic.resourceId));
|
|
640
|
+
section.appendChild(entry);
|
|
641
|
+
}
|
|
642
|
+
return section;
|
|
464
643
|
}
|
|
465
644
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/** Content-width layout and message styles for the diagnostic workbench lists. */
|
|
2
|
+
export const PANEL_LIST_CSS = `
|
|
3
|
+
.zenfg-inspector-view-toolbar[hidden],
|
|
4
|
+
.zenfg-inspector-subview[hidden],
|
|
5
|
+
.zenfg-inspector-list-context[hidden] { display: none; }
|
|
6
|
+
.zenfg-inspector-result-count {
|
|
7
|
+
color: var(--fgd-muted);
|
|
8
|
+
white-space: nowrap;
|
|
9
|
+
font: var(--fgd-font-size-small)/1.4 var(--fgd-font-ui);
|
|
10
|
+
}
|
|
11
|
+
.zenfg-inspector-list-context {
|
|
12
|
+
flex: 0 0 auto;
|
|
13
|
+
margin: 0;
|
|
14
|
+
padding: 7px 10px;
|
|
15
|
+
border-bottom: 1px solid var(--fgd-border-subtle);
|
|
16
|
+
color: var(--fgd-muted);
|
|
17
|
+
font: var(--fgd-font-size-small)/1.5 var(--fgd-font-ui);
|
|
18
|
+
}
|
|
19
|
+
.zenfg-inspector-view-toolbar button {
|
|
20
|
+
min-height: var(--fgd-control-height);
|
|
21
|
+
padding: var(--fgd-space-1) var(--fgd-space-2);
|
|
22
|
+
border: 1px solid var(--fgd-border);
|
|
23
|
+
border-radius: var(--fgd-radius-sm);
|
|
24
|
+
background: var(--fgd-panel);
|
|
25
|
+
color: var(--fgd-text-secondary);
|
|
26
|
+
font: var(--fgd-font-size)/1.3 var(--fgd-font-ui);
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
}
|
|
29
|
+
.zenfg-inspector-view-toolbar button:hover { background: var(--fgd-surface-hover); }
|
|
30
|
+
.zenfg-inspector-view-toolbar input,
|
|
31
|
+
.zenfg-inspector-view-toolbar select { font-size: var(--fgd-font-size); }
|
|
32
|
+
.zenfg-inspector-passes-view .zenfg-inspector-workbench-table,
|
|
33
|
+
.zenfg-inspector-resources-view .zenfg-inspector-workbench-table {
|
|
34
|
+
min-width: 580px;
|
|
35
|
+
border-collapse: separate;
|
|
36
|
+
border-spacing: 0;
|
|
37
|
+
font: var(--fgd-font-size-small)/1.5 var(--fgd-font-ui);
|
|
38
|
+
}
|
|
39
|
+
.zenfg-inspector-passes-view .zenfg-inspector-workbench-table [data-column='numeric'],
|
|
40
|
+
.zenfg-inspector-resources-view .zenfg-inspector-workbench-table [data-column='numeric'] {
|
|
41
|
+
font-family: var(--fgd-font-mono);
|
|
42
|
+
}
|
|
43
|
+
.zenfg-inspector-passes-view .zenfg-inspector-workbench-table th:first-child,
|
|
44
|
+
.zenfg-inspector-resources-view .zenfg-inspector-workbench-table th:first-child,
|
|
45
|
+
.zenfg-inspector-passes-view .zenfg-inspector-workbench-table td:first-child,
|
|
46
|
+
.zenfg-inspector-resources-view .zenfg-inspector-workbench-table td:first-child {
|
|
47
|
+
position: sticky;
|
|
48
|
+
left: 0;
|
|
49
|
+
max-width: 290px;
|
|
50
|
+
background: var(--fgd-canvas);
|
|
51
|
+
z-index: 1;
|
|
52
|
+
}
|
|
53
|
+
.zenfg-inspector-passes-view .zenfg-inspector-workbench-table th:first-child,
|
|
54
|
+
.zenfg-inspector-resources-view .zenfg-inspector-workbench-table th:first-child {
|
|
55
|
+
z-index: 3;
|
|
56
|
+
background: var(--fgd-panel);
|
|
57
|
+
}
|
|
58
|
+
.zenfg-inspector-passes-view .zenfg-inspector-workbench-table tr.selected td:first-child,
|
|
59
|
+
.zenfg-inspector-resources-view .zenfg-inspector-workbench-table tr.selected td:first-child {
|
|
60
|
+
background: color-mix(in srgb, var(--fgd-accent) 12%, var(--fgd-canvas));
|
|
61
|
+
}
|
|
62
|
+
.zenfg-inspector-passes-view .zenfg-inspector-workbench-table tbody tr:hover td:first-child,
|
|
63
|
+
.zenfg-inspector-resources-view .zenfg-inspector-workbench-table tbody tr:hover td:first-child {
|
|
64
|
+
background: var(--fgd-surface-hover);
|
|
65
|
+
}
|
|
66
|
+
.zenfg-inspector-passes-view .zenfg-inspector-group-toggle { margin-right: 5px; }
|
|
67
|
+
.zenfg-inspector-diagnostics-view { display: flex; flex-direction: column; }
|
|
68
|
+
.zenfg-inspector-diagnostics-view .zenfg-inspector-diagnostics-scroller {
|
|
69
|
+
flex: 1 1 auto;
|
|
70
|
+
min-height: 0;
|
|
71
|
+
height: auto;
|
|
72
|
+
}
|
|
73
|
+
.zenfg-inspector-diagnostics-sections {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
gap: 14px;
|
|
77
|
+
padding: 14px;
|
|
78
|
+
min-width: 0;
|
|
79
|
+
}
|
|
80
|
+
.zenfg-inspector-diagnostic-messages > h2 { margin: 0; font: 600 14px/1.5 var(--fgd-font-ui); }
|
|
81
|
+
.zenfg-inspector-diagnostic-messages > p,
|
|
82
|
+
.zenfg-inspector-diagnostic-section > p {
|
|
83
|
+
margin: 5px 0 10px;
|
|
84
|
+
color: var(--fgd-muted);
|
|
85
|
+
font: var(--fgd-font-size-small)/1.5 var(--fgd-font-ui);
|
|
86
|
+
}
|
|
87
|
+
.zenfg-inspector-diagnostic-message {
|
|
88
|
+
--diagnostic-color: var(--fgd-accent);
|
|
89
|
+
margin-top: 9px;
|
|
90
|
+
padding: 10px var(--fgd-space-3);
|
|
91
|
+
border-left: 3px solid var(--diagnostic-color);
|
|
92
|
+
background: var(--fgd-surface);
|
|
93
|
+
overflow-wrap: anywhere;
|
|
94
|
+
}
|
|
95
|
+
.zenfg-inspector-diagnostic-message[data-severity='error'] { --diagnostic-color: var(--fgd-danger); }
|
|
96
|
+
.zenfg-inspector-diagnostic-message[data-severity='warning'] { --diagnostic-color: var(--fgd-warning); }
|
|
97
|
+
.zenfg-inspector-diagnostic-message h3 {
|
|
98
|
+
display: flex;
|
|
99
|
+
flex-wrap: wrap;
|
|
100
|
+
gap: var(--fgd-space-2);
|
|
101
|
+
margin: 0;
|
|
102
|
+
font: 600 var(--fgd-font-size-small)/1.5 var(--fgd-font-ui);
|
|
103
|
+
}
|
|
104
|
+
.zenfg-inspector-diagnostic-severity { color: var(--diagnostic-color); text-transform: capitalize; }
|
|
105
|
+
.zenfg-inspector-diagnostic-message code { font: var(--fgd-font-size-small)/1.5 var(--fgd-font-mono); }
|
|
106
|
+
.zenfg-inspector-diagnostic-message p { margin: 6px 0; white-space: pre-wrap; font: var(--fgd-font-size)/1.55 var(--fgd-font-ui); }
|
|
107
|
+
.zenfg-inspector-diagnostic-links {
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: baseline;
|
|
110
|
+
flex-wrap: wrap;
|
|
111
|
+
gap: 5px var(--fgd-space-3);
|
|
112
|
+
min-width: 0;
|
|
113
|
+
margin-top: var(--fgd-space-1);
|
|
114
|
+
}
|
|
115
|
+
.zenfg-inspector-diagnostic-links .zenfg-inspector-relation-button {
|
|
116
|
+
min-width: 0;
|
|
117
|
+
max-width: 100%;
|
|
118
|
+
white-space: normal;
|
|
119
|
+
overflow-wrap: anywhere;
|
|
120
|
+
text-align: left;
|
|
121
|
+
font: var(--fgd-font-size)/1.5 var(--fgd-font-ui);
|
|
122
|
+
}
|
|
123
|
+
.zenfg-inspector-diagnostic-reveal { color: var(--fgd-muted); }
|
|
124
|
+
.zenfg-inspector-diagnostic-section {
|
|
125
|
+
min-width: 0;
|
|
126
|
+
padding: 10px 0 0;
|
|
127
|
+
border-top: 1px solid var(--fgd-border-subtle);
|
|
128
|
+
overflow-wrap: anywhere;
|
|
129
|
+
}
|
|
130
|
+
.zenfg-inspector-diagnostic-section > summary {
|
|
131
|
+
padding: 3px 0;
|
|
132
|
+
font: 600 var(--fgd-font-size)/1.5 var(--fgd-font-ui);
|
|
133
|
+
cursor: pointer;
|
|
134
|
+
}
|
|
135
|
+
.zenfg-inspector-diagnostic-section > .zenfg-inspector-diagnostic-section { margin: var(--fgd-space-2) 0 0 var(--fgd-space-3); }
|
|
136
|
+
.zenfg-inspector-diagnostic-section .zenfg-inspector-diagnostic-list { overflow: visible; padding: var(--fgd-space-1) 0; }
|
|
137
|
+
.zenfg-inspector-diagnostic-section ul { padding-left: 20px; }
|
|
138
|
+
.zenfg-inspector-diagnostic-section > .zenfg-inspector-relation-button { margin: 5px 0; }
|
|
139
|
+
.zenfg-inspector-diagnostic-links .selected { background: var(--fgd-accent-soft); }
|
|
140
|
+
.zenfg-inspector-diagnostic-section summary:focus-visible,
|
|
141
|
+
.zenfg-inspector-view-toolbar button:focus-visible { outline: 2px solid var(--fgd-accent); outline-offset: 2px; }
|
|
142
|
+
@container zenfg-inspector-main (max-width: 640px) {
|
|
143
|
+
.zenfg-inspector-passes-view .zenfg-inspector-workbench-table,
|
|
144
|
+
.zenfg-inspector-resources-view .zenfg-inspector-workbench-table { min-width: 420px; }
|
|
145
|
+
.zenfg-inspector-passes-view [id$='pass-list-panel'] tr > :nth-child(3),
|
|
146
|
+
.zenfg-inspector-passes-view [id$='pass-list-panel'] tr > :nth-child(6),
|
|
147
|
+
.zenfg-inspector-passes-view [id$='group-list-panel'] tr > :nth-child(5),
|
|
148
|
+
.zenfg-inspector-passes-view [id$='group-list-panel'] tr > :nth-child(6),
|
|
149
|
+
.zenfg-inspector-resources-view tr > :nth-child(4),
|
|
150
|
+
.zenfg-inspector-resources-view tr > :nth-child(5) { display: none; }
|
|
151
|
+
.zenfg-inspector-passes-view .zenfg-inspector-workbench-table td:first-child,
|
|
152
|
+
.zenfg-inspector-resources-view .zenfg-inspector-workbench-table td:first-child { max-width: 190px; }
|
|
153
|
+
}
|
|
154
|
+
`;
|