Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernize method binding patterns in OpenTracesWidget #1174

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"react-contexify": "^5.0.0",
"react-grid-layout": "1.2.0",
"react-modal": "^3.8.1",
"react-tooltip": "4.2.14",
"react-virtualized": "^9.21.0",
"timeline-chart": "^0.4.1",
"traceviewer-base": "0.6.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ exports[`<TableOutputComponent /> Renders AG-Grid table with provided props & st
<div>
<div
class="output-container undefined"
data-for="tooltip-component"
data-tip=""
id="00"
style="width: 0px; height: 0px;"
tabindex="-1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ describe('<TableOutputComponent />', () => {

test('Renders AG-Grid table with provided props & state', async () => {
const tableOutputComponentProps: AbstractOutputProps = {
tooltipComponent: null,
style: {
width: 0,
height: 0,
Expand Down Expand Up @@ -61,7 +60,6 @@ describe('<TableOutputComponent />', () => {
onOutputRemove: () => 0,
unitController: new TimeGraphUnitController(BigInt(0), { start: BigInt(0), end: BigInt(0) }),
backgroundTheme: 'light',
tooltipXYComponent: null,
outputWidth: 0
};

Expand Down Expand Up @@ -95,7 +93,6 @@ describe('<TableOutputComponent />', () => {
// Renders with provided props
expect(table.state.tableColumns).toEqual(tableOutputComponentState);
expect(table.props.backgroundTheme).toEqual('light');
expect(table.props.tooltipComponent).toEqual(null);
expect(table.props.style).toEqual({
width: 0,
height: 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,90 +1,36 @@
import { render, fireEvent, act } from '@testing-library/react';
import * as React from 'react';
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
import { TooltipComponent } from '../tooltip-component';

const model = {
id: '123',
range: { start: 1, end: 10 },
label: 'model'
};
const tooltip = new TooltipComponent(10);
tooltip.setState = jest.fn();

describe('Tooltip component', () => {
let axisComponent: any;
const ref = (el: TooltipComponent | undefined | null): void => {
axisComponent = el;
};

describe('TooltipComponent', () => {
beforeEach(() => {
axisComponent = null;
document.body.innerHTML = '';
});

afterEach(() => {
cleanup();
jest.clearAllMocks();
it('renders content', async () => {
render(<TooltipComponent visible={true} content="Test Content" />);
const tooltip = document.querySelector('.trace-compass-tooltip') as HTMLElement;
expect(tooltip.textContent).toBe('Test Content');
expect(tooltip.style.opacity).toBe('1');
});

/*
* Skip due to issues with TooltipComponent:
*
* react-tooltip v4.2.14 works in the application but causes an exception
* in tests (https://github.com/ReactTooltip/react-tooltip/issues/681),
* which is fixed in v4.2.17. However, version v4.2.17 breaks the tooltip
* when running in the application.
*/
it.skip('renders itself', () => {
render(<TooltipComponent />);
expect(axisComponent).toBeTruthy();
expect(axisComponent instanceof TooltipComponent).toBe(true);
});

// Skip due to issues with TooltipComponent (see above for details)
it.skip('resets timer on mouse enter', () => {
tooltip.state = {
element: model,
func: undefined,
content: 'Test'
};
render(<TooltipComponent />);
const component = screen.getByRole('tooltip-component-role');
fireEvent.mouseEnter(component);
fireEvent.mouseLeave(component);

expect(tooltip.setState).toBeCalledWith({ content: undefined });
});

it('displays a tooltip for a time graph state component', () => {
tooltip.state = {
element: undefined,
func: undefined,
content: undefined
};
tooltip.setElement(model);

expect(tooltip.setState).toBeCalledWith({ element: model, func: undefined });
});
it('de-renders when visibility changes', async () => {
const { rerender } = render(<TooltipComponent visible={true} content="Test" />);
const tooltip = document.querySelector('.trace-compass-tooltip') as HTMLElement;

it('hides tooltip if mouse is not hovering over element', async () => {
tooltip.state = {
element: model,
func: undefined,
content: 'Test'
};
tooltip.setElement(undefined);
await new Promise(r => setTimeout(r, 500));
expect(tooltip.style.opacity).toBe('1');

expect(tooltip.setState).toBeCalledWith({ content: undefined });
rerender(<TooltipComponent visible={false} content="Test" />);
await new Promise(resolve => setTimeout(resolve, 1001));
expect(tooltip.style.opacity).toBe('0');
});

it('hide tooltip because there is no content', () => {
tooltip.state = {
element: model,
func: undefined,
content: undefined
};
tooltip.setElement(undefined);
it('stays rendered when mouse moves on top of it', async () => {
render(<TooltipComponent visible={true} content="Test" />);
const tooltip = document.querySelector('.trace-compass-tooltip') as HTMLElement;

expect(tooltip.setState).toBeCalledWith({ content: undefined });
fireEvent.mouseEnter(tooltip);
await new Promise(resolve => setTimeout(resolve, 500));
expect(tooltip.style.opacity).toBe('1');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@ import { TimeRange } from 'traceviewer-base/lib/utils/time-range';
import { OutputComponentStyle } from './utils/output-component-style';
import { OutputStyleModel } from 'tsp-typescript-client/lib/models/styles';
import { TooltipComponent } from './tooltip-component';
import { TooltipXYComponent } from './tooltip-xy-component';
import { ResponseStatus } from 'tsp-typescript-client/lib/models/response/responses';
import { signalManager } from 'traceviewer-base/lib/signals/signal-manager';
import { DropDownComponent, DropDownSubSection, OptionState } from './drop-down-component';

export interface AbstractOutputProps {
tspClient: ITspClient;
tooltipComponent: TooltipComponent | null;
tooltipXYComponent: TooltipXYComponent | null;
traceId: string;
traceName?: string;
range: TimeRange;
Expand Down Expand Up @@ -51,6 +48,8 @@ export interface AbstractOutputState {
outputStatus: string;
styleModel?: OutputStyleModel;
dropDownOpen?: boolean;
tooltipContent?: React.ReactNode;
tooltipVisible?: boolean;
}

export abstract class AbstractOutputComponent<
Expand Down Expand Up @@ -99,8 +98,7 @@ export abstract class AbstractOutputComponent<
onMouseDown={this.props.onMouseDown}
onTouchStart={this.props.onTouchStart}
onTouchEnd={this.props.onTouchEnd}
data-tip=""
data-for="tooltip-component"
onMouseLeave={() => this.closeTooltip()}
>
<div
id={this.getOutputComponentDomId() + 'handle'}
Expand All @@ -117,6 +115,7 @@ export abstract class AbstractOutputComponent<
{this.renderMainOutputContainer()}
</div>
{this.props.children}
<TooltipComponent content={this.state.tooltipContent} visible={this.state.tooltipVisible} />
</div>
);
}
Expand Down Expand Up @@ -314,4 +313,12 @@ export abstract class AbstractOutputComponent<
protected getTitleBarTooltip(): string {
return this.props.outputDescriptor.name;
}

protected setTooltipContent(content: React.ReactNode): void {
this.setState({ tooltipContent: content, tooltipVisible: true });
}

protected closeTooltip(): void {
this.setState({ tooltipVisible: false });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,25 @@ export type AbstractXYOutputState = AbstractTreeOutputState & {
cursor?: string;
};

interface Point {
label: any;
color: any;
background: any;
value: string;
}

interface TooltipData {
title?: string;
dataPoints?: Point[];
top?: number;
bottom?: number;
right?: number;
left?: number;
opacity?: number;
transition?: string;
zeros: number;
}

class xyPair {
x: number;
y: number;
Expand Down Expand Up @@ -664,7 +683,7 @@ export abstract class AbstractXYOutputComponent<
: this.chartRef.current.chartInstance.height;
const arraySize = this.state.xyData.labels.length;
const index = Math.max(Math.round((xPos / chartWidth) * (arraySize - 1)), 0);
const points: any = [];
const points: Point[] = [];
let zeros = 0;

this.state.xyData.datasets.forEach((d: any) => {
Expand Down Expand Up @@ -717,7 +736,7 @@ export abstract class AbstractXYOutputComponent<
// If there are more than 10 lines in the chart, summarise the ones that are equal to 0.
if (!invalidPoint) {
if (this.state.xyData.datasets.length <= 10 || rounded > 0) {
const point: any = {
const point = {
label: d.label,
color: d.borderColor,
background: d.backgroundColor,
Expand Down Expand Up @@ -751,7 +770,7 @@ export abstract class AbstractXYOutputComponent<
rightPos = xLocation;
}

const tooltipData = {
const tooltipData: TooltipData = {
title: timeLabel,
dataPoints: points,
top: topPos,
Expand All @@ -763,15 +782,41 @@ export abstract class AbstractXYOutputComponent<
};

if (points.length > 0) {
this.props.tooltipXYComponent?.setElement(tooltipData);
this.setTooltipContent(this.generateXYComponentTooltip(tooltipData));
} else {
this.hideTooltip();
this.closeTooltip();
}
}

protected hideTooltip(): void {
this.props.tooltipXYComponent?.setElement({
opacity: 0
});
}
private generateXYComponentTooltip = (tooltipData: TooltipData) => (
<>
<p style={{ margin: '0 0 5px 0' }}>{tooltipData?.title}</p>
<ul style={{ padding: '0' }}>
{tooltipData.dataPoints?.map(
(point: { color: string; background: string; label: string; value: string }, i: number) => (
<li key={i} style={{ listStyle: 'none', display: 'flex', marginBottom: 5 }}>
<div
style={{
height: '10px',
width: '10px',
margin: 'auto 0',
border: 'solid thin',
borderColor: point.color,
backgroundColor: point.background
}}
></div>
<span style={{ marginLeft: '5px' }}>
{point.label} {point.value}
</span>
</li>
)
)}
</ul>
{tooltipData.zeros > 0 && (
<p style={{ marginBottom: 0 }}>
{tooltipData.zeros} other{tooltipData.zeros > 1 ? 's' : ''}: 0
</p>
)}
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,17 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
this.onElementSelected(this.selectedElement);
});
this.chartLayer.registerMouseInteractions({
mouseover: el => {
this.props.tooltipComponent?.setElement(el, () => this.fetchTooltip(el));
mouseover: async el => {
const tooltipObject = await this.fetchTooltip(el);
if (!tooltipObject) {
this.closeTooltip();
} else {
const tooltipContent = this.generateTooltipTable(tooltipObject);
this.setTooltipContent(tooltipContent);
}
},
mouseout: () => {
this.props.tooltipComponent?.setElement(undefined);
this.closeTooltip();
},
click: (el, ev, clickCount) => {
if (clickCount === 2) {
Expand Down Expand Up @@ -816,6 +822,19 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
return fullTooltip;
}

private generateTooltipTable(tooltip: { [key: string]: string }) {
return (
<table>
{Object.keys(tooltip).map(key => (
<tr key={key}>
<td style={{ textAlign: 'left' }}> {key} </td>
<td style={{ textAlign: 'left' }}> {tooltip[key]} </td>
</tr>
))}
</table>
);
}

private renderTimeGraphContent() {
return (
<div id="main-timegraph-content" ref={this.horizontalContainer} style={{ height: this.props.style.height }}>
Expand Down
Loading
Loading