Skip to content

Commit

Permalink
Disable delete buttons during engine activity (#31)
Browse files Browse the repository at this point in the history
While the engine has operations pending in the database, disable the
track deletion buttons to avoid trying to query deleted tables.

Signed-off-by: Christian W. Damus <[email protected]>
  • Loading branch information
cdamus authored Sep 13, 2023
1 parent 9f0755f commit 615a0b3
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 25 deletions.
10 changes: 9 additions & 1 deletion ui/src/assets/common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,10 @@ $bottom-tab-padding: 10px;
width: 22px;
font-size: 18px;
opacity: 0;

&.disabled {
filter: saturate(0) opacity(35%);
}
}

.track-button.show {
Expand All @@ -447,7 +451,7 @@ $bottom-tab-padding: 10px;
align-items: center;
justify-content: center;

&:hover {
&:hover:not(.disabled) {
background-color: #ebeef9;
}
}
Expand Down Expand Up @@ -683,6 +687,10 @@ button.query-ctrl {
width: 22px;
font-size: 18px;
opacity: 0;

&.disabled {
filter: saturate(0) opacity(35%);
}
}
}
&:hover .track-button.action {
Expand Down
10 changes: 10 additions & 0 deletions ui/src/common/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,16 @@ export abstract class Engine {
getProxy(tag: string): EngineProxy {
return new EngineProxy(this, tag);
}

// Query whether the engine has any data/query results pending.
get hasDataPending(): boolean {
return this.pendingParses.length > 0 ||
this.pendingEOFs.length > 0 ||
this.pendingResetTraceProcessors.length > 0 ||
this.pendingQueries.length > 0 ||
this.pendingRestoreTables.length > 0 ||
this.pendingComputeMetrics.length > 0;
}
}

// Lightweight wrapper over Engine exposing only `query` method and annotating
Expand Down
40 changes: 26 additions & 14 deletions ui/src/frontend/track_group_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,23 +203,35 @@ export class TrackGroupPanel extends Panel<Attrs> {

getTrackGroupActionButtons(): m.Vnode<any>[] {
const result: m.Vnode<any>[] = [];
result.push(m('i.material-icons.track-button.action',
{
onclick: (e: MouseEvent) => {
globals.dispatchMultiple([
...this.trackGroupState.tracks.map((trackId) => Actions.removeTrack({trackId})),
Actions.removeTrackGroup({
id: this.trackGroupState.id,
summaryTrackId: this.trackGroupState.tracks[0],
}),
]);
e.stopPropagation();
},
},
'delete'));
const action = (e: MouseEvent) => {
globals.dispatchMultiple([
...this.trackGroupState.tracks.map(
(trackId) => Actions.removeTrack({trackId})),
Actions.removeTrackGroup({
id: this.trackGroupState.id,
summaryTrackId: this.trackGroupState.tracks[0],
}),
]);
e.stopPropagation();
};
const disabled = !this.canDeleteTrackGroup(this.trackGroupState);
result.push(m('i.material-icons.track-button.action',
{
class: disabled ? 'disabled' : '',
onclick: disabled ? null : action,
},
'delete'));
return result;
}

// We cannot delete a track group while its tracks are loading,
// otherwise we'll try to read data from tables that have been dropped.
// We assume a track group may be loading if its engine is busy.
protected canDeleteTrackGroup(trackGroupState: TrackGroupState): boolean {
const engine = globals.engines.get(trackGroupState.engineId);
return !engine || !engine.hasDataPending;
}

highlightIfTrackSelected(ctx: CanvasRenderingContext2D, size: PanelSize) {
const {visibleTimeScale} = globals.frontendLocalState;
const selection = globals.state.currentSelection;
Expand Down
31 changes: 21 additions & 10 deletions ui/src/frontend/track_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,25 @@ class TrackShell implements m.ClassComponent<TrackShellAttrs> {

getTrackShellButtons(attrs: TrackShellAttrs): m.Vnode<TrackButtonAttrs>[] {
const result = [...attrs.track.getTrackShellButtons()];
result.push(m(TrackButton, {
action: () => globals.dispatch(Actions.removeTrack({trackId: attrs.trackState.id})),
i: 'delete',
tooltip: 'Remove track',
showButton: false, // Only show on roll-over
fullHeight: true,
}));
result.push(m(TrackButton, {
action: () => globals.dispatch(
Actions.removeTrack({trackId: attrs.trackState.id})),
i: 'delete',
tooltip: 'Remove track',
showButton: false, // Only show on roll-over
fullHeight: true,
disabled: !this.canDeleteTrack(attrs.trackState),
}));
return result;
}

// We cannot delete a track while it is loading, otherwise
// we'll try to read data from tables that have been dropped.
// We assume it may be loading if its engine is busy.
protected canDeleteTrack(trackState: TrackState): boolean {
const engine = globals.engines.get(trackState.engineId);
return !engine || !engine.hasDataPending;
}
}

export interface TrackContentAttrs { track: Track; }
Expand Down Expand Up @@ -301,6 +311,7 @@ export interface TrackButtonAttrs {
showButton: boolean;
fullHeight?: boolean;
filledIcon?: boolean;
disabled?: boolean;
}
export class TrackButton implements m.ClassComponent<TrackButtonAttrs> {
view({attrs}: m.CVnode<TrackButtonAttrs>) {
Expand All @@ -311,9 +322,9 @@ export class TrackButton implements m.ClassComponent<TrackButtonAttrs> {
(attrs.showButton ? 'show' : ''),
(attrs.fullHeight ? 'full-height' : ''),
(attrs.filledIcon ? 'material-icons-filled' : 'material-icons'),
].filter(Boolean)
.join(' '),
onclick: attrs.action,
(attrs.disabled) ? 'disabled' : '',
].filter(Boolean).join(' '),
onclick: attrs.disabled ? null : attrs.action,
title: attrs.tooltip,
},
attrs.i);
Expand Down

0 comments on commit 615a0b3

Please sign in to comment.