Skip to content

Commit b0ea7ef

Browse files
authored
Merge pull request #10349 from The-OpenROAD-Project-staging/remove-button-update-static-GUI
web: Remove 'Update' button in static HTML GUI (#10220)
2 parents a9b82a2 + c742d54 commit b0ea7ef

8 files changed

Lines changed: 89 additions & 6 deletions

File tree

src/web/src/charts-widget.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// Canvas-based slack histogram widget.
55

66
import { getThemeColors } from './theme.js';
7+
import { isStaticMode } from './ui-utils.js';
78

89
// Layout margins (pixels)
910
export const kLeftMargin = 60;
@@ -155,6 +156,9 @@ export class ChartsWidget {
155156
this._updateBtn = document.createElement('button');
156157
this._updateBtn.className = 'timing-btn';
157158
this._updateBtn.textContent = 'Update';
159+
if (isStaticMode(this._app)) {
160+
this._updateBtn.style.display = 'none';
161+
}
158162

159163
this._statusLabel = document.createElement('span');
160164
this._statusLabel.className = 'timing-path-count';
@@ -224,6 +228,10 @@ export class ChartsWidget {
224228

225229
this._ctx = this._canvas.getContext('2d');
226230
this._bindEvents();
231+
232+
if (isStaticMode(this._app)) {
233+
setTimeout(() => this.update(), 0);
234+
}
227235
}
228236

229237
_bindEvents() {
@@ -365,7 +373,10 @@ export class ChartsWidget {
365373
ctx.font = '14px monospace';
366374
ctx.textAlign = 'center';
367375
ctx.textBaseline = 'middle';
368-
ctx.fillText('Click "Update" to load histogram', w / 2, h / 2);
376+
const msg = isStaticMode(this._app)
377+
? 'No histogram data available'
378+
: 'Click "Update" to load histogram';
379+
ctx.fillText(msg, w / 2, h / 2);
369380
return;
370381
}
371382

src/web/src/clock-tree-widget.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// Canvas-based clock tree viewer widget.
55

66
import { getThemeColors } from './theme.js';
7+
import { isStaticMode } from './ui-utils.js';
78

89
export const kNodeSpacing = 24; // pixels between adjacent leaf bins
910
export const kNodeSize = 10; // base node shape size in pixels
@@ -189,6 +190,9 @@ export class ClockTreeWidget {
189190
this._updateBtn = document.createElement('button');
190191
this._updateBtn.className = 'timing-btn';
191192
this._updateBtn.textContent = 'Update';
193+
if (isStaticMode(this._app)) {
194+
this._updateBtn.style.display = 'none';
195+
}
192196
this._fitBtn = document.createElement('button');
193197
this._fitBtn.className = 'timing-btn';
194198
this._fitBtn.textContent = 'Fit';
@@ -220,6 +224,10 @@ export class ClockTreeWidget {
220224

221225
this._ctx = this._canvas.getContext('2d');
222226
this._bindEvents();
227+
228+
if (isStaticMode(this._app)) {
229+
setTimeout(() => this.update(), 0);
230+
}
223231
}
224232

225233
_fit() {
@@ -393,8 +401,10 @@ export class ClockTreeWidget {
393401
ctx.fillStyle = tc.canvasText;
394402
ctx.font = '14px monospace';
395403
ctx.textAlign = 'center';
396-
ctx.fillText('Click "Update" to load clock tree data',
397-
w / 2, h / 2);
404+
const msg = isStaticMode(this._app)
405+
? 'No clock tree data available'
406+
: 'Click "Update" to load clock tree data';
407+
ctx.fillText(msg, w / 2, h / 2);
398408
return;
399409
}
400410

src/web/src/hierarchy-browser.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Hierarchy browser widget — module tree with coloring.
55

66
import { CheckboxTreeModel } from './checkbox-tree-model.js';
7-
import { makeResizableHeaders } from './ui-utils.js';
7+
import { isStaticMode, makeResizableHeaders } from './ui-utils.js';
88

99
const COLS = [
1010
'Instance', 'Module', 'Instances', 'Macros', 'Modules',
@@ -35,7 +35,7 @@ export class HierarchyBrowser {
3535
app.hierarchyBrowser = this;
3636

3737
// Auto-load in static mode (data is already cached).
38-
if (app.websocketManager && app.websocketManager.isStaticMode) {
38+
if (isStaticMode(app)) {
3939
this.update();
4040
}
4141
}
@@ -51,6 +51,9 @@ export class HierarchyBrowser {
5151
this._updateBtn = document.createElement('button');
5252
this._updateBtn.className = 'timing-btn';
5353
this._updateBtn.textContent = 'Update';
54+
if (isStaticMode(this._app)) {
55+
this._updateBtn.style.display = 'none';
56+
}
5457

5558
this._statusLabel = document.createElement('span');
5659
this._statusLabel.className = 'timing-path-count';
@@ -352,6 +355,20 @@ export class HierarchyBrowser {
352355

353356
tbody.appendChild(tr);
354357
}
358+
359+
if (this._rows.length === 0) {
360+
const tr = document.createElement('tr');
361+
const td = document.createElement('td');
362+
td.colSpan = COLS.length;
363+
td.style.textAlign = 'center';
364+
td.style.color = 'var(--fg-secondary)';
365+
td.textContent = isStaticMode(this._app) ?
366+
'No hierarchy data available' :
367+
'Click "Update" to load hierarchy';
368+
tr.appendChild(td);
369+
tbody.appendChild(tr);
370+
}
371+
355372
this._table.appendChild(tbody);
356373
makeResizableHeaders(this._table);
357374
}

src/web/src/main.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { ClockTreeWidget } from './clock-tree-widget.js';
1010
import { ChartsWidget } from './charts-widget.js';
1111
import { HierarchyBrowser } from './hierarchy-browser.js';
1212
import { createInspectorPanel } from './inspector.js';
13+
import { isStaticMode } from './ui-utils.js';
1314
import { populateDisplayControls } from './display-controls.js';
1415
import { createMenuBar } from './menu-bar.js';
1516
import { RulerManager } from './ruler.js';
@@ -571,6 +572,18 @@ function createTclConsole(container) {
571572
container.element.appendChild(el);
572573

573574
app.tclOutputEl = el.querySelector('.tcl-output');
575+
576+
if (isStaticMode(app)) {
577+
el.querySelector('.tcl-input-row').style.display = 'none';
578+
const notice = document.createElement('span');
579+
notice.className = 'tcl-static-notice';
580+
notice.setAttribute('role', 'status');
581+
notice.setAttribute('aria-live', 'polite');
582+
notice.textContent = 'Tcl console is not available in saved reports.';
583+
app.tclOutputEl.appendChild(notice);
584+
return;
585+
}
586+
574587
const input = el.querySelector('.tcl-input');
575588
const completer = new TclCompleter(input, app.websocketManager);
576589

src/web/src/style.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,10 @@ html, body {
749749
.tcl-error {
750750
color: var(--error-text);
751751
}
752+
.tcl-static-notice {
753+
color: var(--fg-muted);
754+
font-style: italic;
755+
}
752756
.tcl-input-row {
753757
display: flex;
754758
align-items: center;

src/web/src/timing-widget.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
// Timing report widget — path summary + detail tables.
55

6-
import { makeResizableHeaders } from './ui-utils.js';
6+
import { isStaticMode, makeResizableHeaders } from './ui-utils.js';
77

88
export class TimingWidget {
99
constructor(app, redrawAllLayers) {
@@ -31,6 +31,9 @@ export class TimingWidget {
3131
this._updateBtn = document.createElement('button');
3232
this._updateBtn.className = 'timing-btn';
3333
this._updateBtn.textContent = 'Update';
34+
if (isStaticMode(this._app)) {
35+
this._updateBtn.style.display = 'none';
36+
}
3437

3538
this._pathCountLabel = document.createElement('span');
3639
this._pathCountLabel.className = 'timing-path-count';
@@ -77,6 +80,10 @@ export class TimingWidget {
7780
this.element = el;
7881

7982
this._bindEvents();
83+
84+
if (isStaticMode(this._app)) {
85+
setTimeout(() => this.update(), 0);
86+
}
8087
}
8188

8289
_makeTab(label, active) {
@@ -270,6 +277,20 @@ export class TimingWidget {
270277
tr.addEventListener('click', () => this._selectPathRow(idx));
271278
tbody.appendChild(tr);
272279
});
280+
281+
if (paths.length === 0) {
282+
const tr = document.createElement('tr');
283+
const td = document.createElement('td');
284+
td.colSpan = TimingWidget.PATH_COLS.length;
285+
td.style.textAlign = 'center';
286+
td.style.color = 'var(--fg-secondary)';
287+
td.textContent = isStaticMode(this._app) ?
288+
'No timing data available' :
289+
'Click "Update" to load timing paths';
290+
tr.appendChild(td);
291+
tbody.appendChild(tr);
292+
}
293+
273294
this._pathTable.appendChild(tbody);
274295

275296
// Restore previous widths if available, otherwise compute fresh.

src/web/src/ui-utils.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33

44
// Shared UI utilities.
55

6+
// True when the app was bootstrapped from a saved/static report
7+
// (i.e. there is no live WebSocket backend).
8+
export function isStaticMode(app) {
9+
return !!app?.websocketManager?.isStaticMode;
10+
}
11+
612
// Make table column headers resizable by dragging.
713
export function makeResizableHeaders(table) {
814
// Reset to auto layout so browser computes natural column widths

src/web/src/web.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,7 @@ window.__STATIC_CACHE__ = {
12361236
</script>
12371237
<script type="module">
12381238
import { GoldenLayout, LayoutConfig } from 'https://esm.sh/golden-layout@2.6.0';
1239+
import * as THREE from 'https://esm.sh/three@0.160.0';
12391240
)" << kReportJS
12401241
<< R"(
12411242
</script>

0 commit comments

Comments
 (0)