diff --git a/packages/react-components/src/components/utils/filter-tree/table-cell.tsx b/packages/react-components/src/components/utils/filter-tree/table-cell.tsx index 792e4cab..aec2df47 100644 --- a/packages/react-components/src/components/utils/filter-tree/table-cell.tsx +++ b/packages/react-components/src/components/utils/filter-tree/table-cell.tsx @@ -21,8 +21,15 @@ export class TableCell extends React.Component { content = node.labels[index]; } - const title = node.showTooltip ? node.labels[index] : undefined; + let title = undefined; + if (node.showTooltip) { + if (node.tooltips !== undefined) { + title = node.tooltips[index]; + } else { + title = node.labels[index]; + } + } return ( diff --git a/packages/react-components/src/components/utils/filter-tree/tree-node.tsx b/packages/react-components/src/components/utils/filter-tree/tree-node.tsx index 10e590a5..a041faae 100644 --- a/packages/react-components/src/components/utils/filter-tree/tree-node.tsx +++ b/packages/react-components/src/components/utils/filter-tree/tree-node.tsx @@ -2,6 +2,7 @@ export interface TreeNode { id: number; parentId: number; labels: string[]; + tooltips?: string[]; children: Array; isRoot: boolean; showTooltip?: boolean; diff --git a/packages/react-components/src/trace-explorer/trace-explorer-views-widget.tsx b/packages/react-components/src/trace-explorer/trace-explorer-views-widget.tsx index b2eac905..310afd96 100644 --- a/packages/react-components/src/trace-explorer/trace-explorer-views-widget.tsx +++ b/packages/react-components/src/trace-explorer/trace-explorer-views-widget.tsx @@ -5,7 +5,9 @@ import { OutputDescriptor } from 'tsp-typescript-client/lib/models/output-descri import { Experiment } from 'tsp-typescript-client/lib/models/experiment'; import { ITspClientProvider } from 'traceviewer-base/lib/tsp-client-provider'; import { ExperimentManager } from 'traceviewer-base/lib/experiment-manager'; -import { AvailableViewsComponent } from '../components/utils/available-views-component'; +import { FilterTree } from '../components/utils/filter-tree/tree'; +import { TreeNode } from '../components/utils/filter-tree/tree-node'; +import { getAllExpandedNodeIds } from '../components/utils/filter-tree/utils'; export interface ReactAvailableViewsProps { id: string; @@ -15,13 +17,18 @@ export interface ReactAvailableViewsProps { } export interface ReactAvailableViewsState { - availableOutputDescriptors: OutputDescriptor[]; + treeNodes: TreeNode[]; + collapsedNodes: number[]; + orderedNodes: number[]; + selectedOutput: number; } export class ReactAvailableViewsWidget extends React.Component { private _selectedExperiment: Experiment | undefined; private _experimentManager: ExperimentManager; + private _nodeIdToOutput: { [key: number]: OutputDescriptor } = {}; + private _onExperimentSelected = (experiment: Experiment): void => this.doHandleExperimentSelectedSignal(experiment); private _onExperimentClosed = (experiment: Experiment): void => this.doHandleExperimentClosedSignal(experiment); @@ -33,7 +40,10 @@ export class ReactAvailableViewsWidget extends React.Component - +
{this.renderOutputs()}
); } - protected handleOutputClicked = (outputDescriptor: OutputDescriptor): void => - this.doHandleOutputClicked(outputDescriptor); - protected handleContextMenuEvent = ( - e: React.MouseEvent, - output: OutputDescriptor | undefined - ): void => this.doHandleContextMenuEvent(e, output); + private renderOutputs() { + if (this.state.treeNodes) { + return ( +
+ { + this.handleOutputClicked(id); + }} + onContextMenu={this.handleContextMenuEvent} + headers={[{ title: 'Name', sortable: true, resizable: true }]} + /> +
+ ); + } + return <>; + } + protected handleOutputClicked = (id: number): void => this.doHandleOutputClicked(id); + protected handleContextMenuEvent = (e: React.MouseEvent, id: number | undefined): void => + this.doHandleContextMenuEvent(e, id); - private doHandleOutputClicked(selectedOutput: OutputDescriptor) { + private doHandleOutputClicked(id: number) { + const selectedOutput: OutputDescriptor = this._nodeIdToOutput[id]; + this.setState({ selectedOutput: id }); if (selectedOutput && this._selectedExperiment) { - signalManager().fireOutputAddedSignal( - new OutputAddedSignalPayload(selectedOutput, this._selectedExperiment) - ); + if (selectedOutput.type !== 'NONE') { + signalManager().fireOutputAddedSignal( + new OutputAddedSignalPayload(selectedOutput, this._selectedExperiment) + ); + } } } - protected doHandleContextMenuEvent( - event: React.MouseEvent, - output: OutputDescriptor | undefined - ): void { - if (this.props.contextMenuRenderer && output) { - this.props.contextMenuRenderer(event, output); + protected doHandleContextMenuEvent(event: React.MouseEvent, id: number | undefined): void { + if (id !== undefined) { + const output: OutputDescriptor = this._nodeIdToOutput[id]; + if (this.props.contextMenuRenderer && output) { + this.props.contextMenuRenderer(event, output); + } } event.preventDefault(); event.stopPropagation(); } protected doHandleExperimentSelectedSignal(experiment: Experiment | undefined): void { - if (this._selectedExperiment?.UUID !== experiment?.UUID || this.state.availableOutputDescriptors.length === 0) { + if (this._selectedExperiment?.UUID !== experiment?.UUID || this.state.treeNodes.length === 0) { this._selectedExperiment = experiment; - this.setState({ availableOutputDescriptors: [] }); + this._nodeIdToOutput = {}; + this.setState({ treeNodes: [] }); this.updateAvailableViews(); } } protected doHandleExperimentClosedSignal(experiment: Experiment | undefined): void { if (this._selectedExperiment?.UUID === experiment?.UUID) { - this.setState({ availableOutputDescriptors: [] }); + this._nodeIdToOutput = {}; + this.setState({ treeNodes: [] }); } } @@ -102,9 +135,24 @@ export class ReactAvailableViewsWidget extends React.Component { + const node: TreeNode = { + id: index, + parentId: -1, + labels: [output?.name], + tooltips: [output?.description], + children: [], + isRoot: true, + showTooltip: true + }; + entries.push(node); + this._nodeIdToOutput[index] = output; + }); + this.setState({ treeNodes: entries }); } else { - this.setState({ availableOutputDescriptors: [] }); + this._nodeIdToOutput = {}; + this.setState({ treeNodes: [] }); } } @@ -117,4 +165,22 @@ export class ReactAvailableViewsWidget extends React.Component expandId === id); + + if (exist !== undefined) { + newList = newList.filter(collapsed => id !== collapsed); + } else { + newList = newList.concat(id); + } + const orderedIds = getAllExpandedNodeIds(nodes, newList); + this.setState({ collapsedNodes: newList, orderedNodes: orderedIds }); + } + + private onOrderChange(ids: number[]): void { + this.setState({ orderedNodes: ids }); + } } diff --git a/packages/react-components/style/output-components-style.css b/packages/react-components/style/output-components-style.css index 7fc38bd5..6ff04dc9 100644 --- a/packages/react-components/style/output-components-style.css +++ b/packages/react-components/style/output-components-style.css @@ -258,6 +258,15 @@ canvas { font-weight: normal; } +.avail-views-table .table-tree td span { + text-wrap: pretty; + min-width: 100px; +} + +.avail-views-table .table-tree th { + font-weight: normal; +} + .table-tree tr.selected td { background-color: var(--trace-viewer-selection-background) !important; }