Skip to content

Commit

Permalink
Persist state of view after pin/unpin
Browse files Browse the repository at this point in the history
Keep track of tree selections of the pinned/unpinned chart so that users don't have to redo them

Fixes #762

Signed-off-by: hriday-panchasara <hriday.panchasara@ericsson.com>
  • Loading branch information
hriday-panchasara authored and bhufmann committed Jul 25, 2022
1 parent f772811 commit 773ab11
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 23 deletions.
16 changes: 10 additions & 6 deletions packages/base/src/signals/signal-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ export declare interface SignalManager {
fireTraceServerStartedSignal(): void;
fireUndoSignal(): void;
fireRedoSignal(): void;
firePinView(output: OutputDescriptor): void;
fireUnPinView(): void;
fireOpenOverviewOutputSignal(): void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
firePinView(output: OutputDescriptor, payload?: any): void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fireUnPinView(output: OutputDescriptor, payload?: any): void;
}

export const Signals = {
Expand Down Expand Up @@ -123,11 +125,13 @@ export class SignalManager extends EventEmitter implements SignalManager {
fireRedoSignal(): void {
this.emit(Signals.REDO);
}
firePinView(output: OutputDescriptor): void {
this.emit(Signals.PIN_VIEW, output);
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
firePinView(output: OutputDescriptor, payload?: any): void {
this.emit(Signals.PIN_VIEW, output, payload);
}
fireUnPinView(): void {
this.emit(Signals.UNPIN_VIEW);
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
fireUnPinView(output: OutputDescriptor, payload?: any): void {
this.emit(Signals.UNPIN_VIEW, output, payload);
}
fireOpenOverviewOutputSignal(): void {
this.emit(Signals.OPEN_OVERVIEW_OUTPUT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export interface AbstractOutputProps {
onTouchEnd?: VoidFunction;
setChartOffset?: (chartOffset: number) => void;
pinned?: boolean
// eslint-disable-next-line @typescript-eslint/no-explicit-any
persistChartState?: any;
}

export interface AbstractOutputState {
Expand Down Expand Up @@ -120,7 +122,7 @@ export abstract class AbstractOutputComponent<P extends AbstractOutputProps, S e

private closeComponent() {
if (this.props.pinned) {
signalManager().fireUnPinView();
signalManager().fireUnPinView(this.props.outputDescriptor);
}
this.props.onOutputRemove(this.props.outputDescriptor.id);
}
Expand Down Expand Up @@ -150,7 +152,7 @@ export abstract class AbstractOutputComponent<P extends AbstractOutputProps, S e

abstract resultsAreEmpty(): boolean;

private showOptions(): React.ReactNode {
protected showOptions(): React.ReactNode {
return <React.Fragment>
<ul>
{this.props.pinned === undefined && <li className='drop-down-list-item' onClick={() => this.pinView()}>Pin View</li>}
Expand All @@ -168,12 +170,18 @@ export abstract class AbstractOutputComponent<P extends AbstractOutputProps, S e
return;
}

protected pinView(): void {
signalManager().firePinView(this.props.outputDescriptor);
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
protected pinView(payload?: any): void {
signalManager().firePinView(this.props.outputDescriptor, payload);
}

protected unPinView(): void {
signalManager().fireUnPinView();
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
protected unPinView(payload?: any): void {
if (payload) {
signalManager().fireUnPinView(this.props.outputDescriptor, payload);
} else {
signalManager().fireUnPinView(this.props.outputDescriptor);
}
}

protected renderAnalysisFailed(): React.ReactFragment {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export class DataTreeOutputComponent extends AbstractOutputComponent<AbstractOut
collapsedNodes: [],
orderedNodes: [],
columns: [{title: 'Name', sortable: true}],
optionsDropdownOpen: false
optionsDropdownOpen: false,
additionalOptions: true
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { TspDataProvider } from './data-providers/tsp-data-provider';
import { ReactTimeGraphContainer } from './utils/timegraph-container-component';
import { OutputElementStyle } from 'tsp-typescript-client/lib/models/styles';
import { EntryTree } from './utils/filter-tree/entry-tree';
import { listToTree, getAllExpandedNodeIds, getIndexOfNode } from './utils/filter-tree/utils';
import { listToTree, getAllExpandedNodeIds, getIndexOfNode, validateNumArray } from './utils/filter-tree/utils';
import hash from 'traceviewer-base/lib/utils/value-hash';
import ColumnHeader from './utils/filter-tree/column-header';
import { TimeGraphAnnotationComponent } from 'timeline-chart/lib/components/time-graph-annotation';
Expand Down Expand Up @@ -77,9 +77,9 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
timegraphTree: [],
markerCategoryEntries: [],
markerLayerData: undefined,
collapsedNodes: [],
collapsedNodes: validateNumArray(this.props.persistChartState?.collapsedNodes) ? this.props.persistChartState.collapsedNodes as number[] : [],
columns: [],
collapsedMarkerNodes: [],
collapsedMarkerNodes: validateNumArray(this.props.persistChartState?.collapsedMarkerNodes) ? this.props.persistChartState.collapsedMarkerNodes as number[] : [],
optionsDropdownOpen: false,
dataRows: []
};
Expand Down Expand Up @@ -912,4 +912,23 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
this.chartLayer.selectAndReveal(rowIndex);
}

protected showOptions(): React.ReactNode {
return <React.Fragment>
<ul>
{this.props.pinned === undefined &&
<li className='drop-down-list-item'
onClick={() => this.pinView({ collapsedNodes: this.state.collapsedNodes,
collapsedMarkerNodes: this.state.collapsedMarkerNodes })}>
Pin View
</li>}
{this.props.pinned === true &&
<li className='drop-down-list-item'
onClick={() => this.unPinView({ collapsedNodes: this.state.collapsedNodes,
collapsedMarkerNodes: this.state.collapsedMarkerNodes })}>
Unpin View
</li>}
</ul>
{this.state.additionalOptions && this.showAdditionalOptions()}
</React.Fragment>;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ export class TraceContextComponent extends React.Component<TraceContextProps, Tr
private readonly SCROLLBAR_PADDING: number = 12;
private readonly DEFAULT_CHART_OFFSET = 200;
private readonly MIN_COMPONENT_HEIGHT: number = 2;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private chartPersistedState: { output: OutputDescriptor, payload?: any} | undefined = undefined;

private unitController: TimeGraphUnitController;
private historyHandler: UnitControllerHistoryHandler;
Expand All @@ -115,8 +117,10 @@ export class TraceContextComponent extends React.Component<TraceContextProps, Tr
private onBackgroundThemeChange = (theme: string): void => this.doHandleBackgroundThemeChange(theme);
private onUpdateZoom = (hasZoomedIn: boolean) => this.doHandleUpdateZoomSignal(hasZoomedIn);
private onResetZoom = () => this.doHandleResetZoomSignal();
private onPinView = (output: OutputDescriptor) => this.doHandlePinView(output);
private onUnPinView = () => this.doHandleUnPinView();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private onPinView = (output: OutputDescriptor, payload?: any) => this.doHandlePinView(output, payload);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private onUnPinView = (output: OutputDescriptor, payload?: any) => this.doHandleUnPinView(output, payload);

constructor(props: TraceContextProps) {
super(props);
Expand Down Expand Up @@ -546,7 +550,7 @@ export class TraceContextComponent extends React.Component<TraceContextProps, Tr
responseType = 'OVERVIEW';
}
else {
isPinned = this.state.pinnedView ? (this.state.pinnedView === output) : undefined;
isPinned = this.state.pinnedView ? (this.state.pinnedView.id === output.id) : undefined;
onOutputRemove = this.props.onOutputRemove;
responseType = output.type;
}
Expand Down Expand Up @@ -576,11 +580,19 @@ export class TraceContextComponent extends React.Component<TraceContextProps, Tr
case 'OVERVIEW':
return <TraceOverviewComponent key={this.OVERVIEW_OUTPUT_GRID_LAYOUT_ID} {...outputProps}></TraceOverviewComponent>;
case 'TIME_GRAPH':
if (this.chartPersistedState && this.chartPersistedState.output.id === output.id) {
outputProps.persistChartState = this.chartPersistedState.payload;
this.chartPersistedState = undefined;
}
return <TimegraphOutputComponent key={output.id} {...outputProps}
addWidgetResizeHandler={this.addWidgetResizeHandler} removeWidgetResizeHandler={this.removeWidgetResizeHandler}
className={this.state.pinnedView?.id === output.id ? 'pinned-view-shadow' : ''}
/>;
case 'TREE_TIME_XY':
if (this.chartPersistedState && this.chartPersistedState.output.id === output.id) {
outputProps.persistChartState = this.chartPersistedState.payload;
this.chartPersistedState = undefined;
}
return <XYOutputComponent key={output.id} {...outputProps} className={this.state.pinnedView?.id === output.id ? 'pinned-view-shadow' : ''}/>;
case 'TABLE':
return <TableOutputComponent key={output.id} {...outputProps} className={this.state.pinnedView?.id === output.id ? 'pinned-view-shadow' : ''}/>;
Expand Down Expand Up @@ -639,13 +651,17 @@ export class TraceContextComponent extends React.Component<TraceContextProps, Tr
this.historyHandler.addCurrentState();
};

private doHandleUnPinView() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private doHandleUnPinView(output: OutputDescriptor, payload?: any) {
this.chartPersistedState = { output: output, payload: payload };
this.setState({
pinnedView: undefined
});
}

private doHandlePinView(output: OutputDescriptor) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private doHandlePinView(output: OutputDescriptor, payload?: any) {
this.chartPersistedState = { output: output, payload: payload };
this.setState({
pinnedView: output
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,13 @@ export const getIndexOfNode = (id: number, nodes: TreeNode[], collapsedNodes: nu
const ids = getAllExpandedNodeIds(nodes, collapsedNodes);
return ids.findIndex(eId => eId === id);
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const validateNumArray = (arr: any | undefined): boolean => {
if (arr && Array.isArray(arr)) {
return (arr.length > 0 &&
arr.every( value => typeof value === 'number')
);
}
return false;
};
26 changes: 24 additions & 2 deletions packages/react-components/src/components/xy-output-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { BIMath } from 'timeline-chart/lib/bigint-utils';
import { scaleLinear } from 'd3-scale';
import { AbstractXYOutputComponent, AbstractXYOutputState, FLAG_PAN_LEFT, FLAG_PAN_RIGHT, FLAG_ZOOM_IN, FLAG_ZOOM_OUT, MouseButton } from './abstract-xy-output-component';
import { TimeRange } from 'traceviewer-base/src/utils/time-range';
import { validateNumArray } from './utils/filter-tree/utils';

export class XYOutputComponent extends AbstractXYOutputComponent<AbstractOutputProps, AbstractXYOutputState> {
private mousePanningStart = BigInt(0);
Expand All @@ -18,8 +19,8 @@ export class XYOutputComponent extends AbstractXYOutputComponent<AbstractOutputP
outputStatus: ResponseStatus.RUNNING,
selectedSeriesId: [],
xyTree: [],
checkedSeries: [],
collapsedNodes: [],
checkedSeries: validateNumArray(this.props.persistChartState?.checkedSeries) ? this.props.persistChartState.checkedSeries as number[] : [],
collapsedNodes: validateNumArray(this.props.persistChartState?.collapsedNodes) ? this.props.persistChartState.collapsedNodes as number[] : [],
orderedNodes: [],
xyData: {},
columns: [{title: 'Name', sortable: true}],
Expand Down Expand Up @@ -372,4 +373,25 @@ export class XYOutputComponent extends AbstractXYOutputComponent<AbstractOutputP
protected getZoomTime(): bigint {
return this.getTimeForX(this.positionXMove);
}

protected showOptions(): React.ReactNode {
return <React.Fragment>
<ul>
{this.props.pinned === undefined &&
<li className='drop-down-list-item'
onClick={() => this.pinView({ checkedSeries: this.state.checkedSeries,
collapsedNodes: this.state.collapsedNodes })}
>
Pin View
</li>}
{this.props.pinned === true &&
<li className='drop-down-list-item'
onClick={() => this.unPinView({ checkedSeries: this.state.checkedSeries,
collapsedNodes: this.state.collapsedNodes })}>
Unpin View
</li>}
</ul>
{this.state.additionalOptions && this.showAdditionalOptions()}
</React.Fragment>;
}
}

0 comments on commit 773ab11

Please sign in to comment.