From 818a14b9ccab4654124f5671517a0ce4c14db725 Mon Sep 17 00:00:00 2001 From: Hoang Thuan Pham Date: Wed, 11 Oct 2023 16:53:51 -0400 Subject: [PATCH 1/3] Add prototype of React Component displaying configurations source types ADR-0011 introduces the API for managing global configurations. Thus, the Trace Extension needs an interface to expose this API to users. The purpose of this commit is to start creating this UI for the trace extension as a React Component. It provides a skeleton for the component so that it can be further extended in future commits: [1] Added TraceConfigurationManager to handle calls to the TSPClient that relates to trace configuration. [2] Introduce a prototype of the UI as the TraceConfigurationsDialogComponent. This is the main component of the UI that handles the display logic for other sub-components, such as [3]. [3] Added TraceConfigurationListComponent to list the available configuration source types and their instances from the server. To test, open a trace and hover the mouse over the toolbar of the Available Views widget. There should be an icon that appears. Click on the icon to open the trace configuration dialog. In this prototype, the dialog should only display the configuration source types. Signed-off-by: Hoang Thuan Pham --- packages/base/src/signals/signal-manager.ts | 7 +- .../components/abstract-dialog-component.tsx | 5 ++ .../trace-configuration-dialog-component.tsx | 67 ++++++++++++++++++ .../trace-configuration-list-component.tsx | 70 +++++++++++++++++++ .../trace-configuration-manager.ts | 22 ++++++ .../trace-explorer-views-widget.tsx | 24 ++++++- .../trace-viewer/trace-viewer-commands.ts | 5 ++ .../trace-viewer/trace-viewer-contribution.ts | 10 ++- .../trace-viewer-toolbar-commands.ts | 6 ++ .../trace-viewer-toolbar-contribution.tsx | 21 +++++- 10 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 packages/react-components/src/components/trace-configurations/trace-configuration-dialog-component.tsx create mode 100644 packages/react-components/src/components/trace-configurations/trace-configuration-list-component.tsx create mode 100644 packages/react-components/src/components/trace-configurations/trace-configuration-manager.ts diff --git a/packages/base/src/signals/signal-manager.ts b/packages/base/src/signals/signal-manager.ts index 2cd3da831..7b526379f 100644 --- a/packages/base/src/signals/signal-manager.ts +++ b/packages/base/src/signals/signal-manager.ts @@ -41,6 +41,7 @@ export declare interface SignalManager { fireSelectionRangeUpdated(payload: TimeRangeUpdatePayload): void; fireViewRangeUpdated(payload: TimeRangeUpdatePayload): void; fireRequestSelectionRangeChange(payload: TimeRangeUpdatePayload): void; + fireShowTraceConfigurations(): void; } export const Signals = { @@ -75,7 +76,8 @@ export const Signals = { VIEW_RANGE_UPDATED: 'view range updated', SELECTION_RANGE_UPDATED: 'selection range updated', REQUEST_SELECTION_RANGE_CHANGE: 'change selection range', - OUTPUT_DATA_CHANGED: 'output data changed' + OUTPUT_DATA_CHANGED: 'output data changed', + SHOW_TRACE_CONFIGURATIONS: 'open trace configurations' }; export class SignalManager extends EventEmitter implements SignalManager { @@ -174,6 +176,9 @@ export class SignalManager extends EventEmitter implements SignalManager { fireRequestSelectionRangeChange(payload: TimeRangeUpdatePayload): void { this.emit(Signals.REQUEST_SELECTION_RANGE_CHANGE, payload); } + fireShowTraceConfigurations(): void { + this.emit(Signals.SHOW_TRACE_CONFIGURATIONS); + } } let instance: SignalManager = new SignalManager(); diff --git a/packages/react-components/src/components/abstract-dialog-component.tsx b/packages/react-components/src/components/abstract-dialog-component.tsx index 4625d0eb4..66c9a1b1f 100644 --- a/packages/react-components/src/components/abstract-dialog-component.tsx +++ b/packages/react-components/src/components/abstract-dialog-component.tsx @@ -22,6 +22,7 @@ export abstract class AbstractDialogComponent

className="dialog" ariaHideApp={false} onRequestClose={this.props.onCloseDialog} + onAfterOpen={() => this.onAfterOpen()} shouldFocusAfterRender={false} >

protected abstract renderDialogBody(): React.ReactElement; protected abstract renderFooter(): React.ReactElement; + + protected onAfterOpen(): void { + return; + } } diff --git a/packages/react-components/src/components/trace-configurations/trace-configuration-dialog-component.tsx b/packages/react-components/src/components/trace-configurations/trace-configuration-dialog-component.tsx new file mode 100644 index 000000000..d324a8c0c --- /dev/null +++ b/packages/react-components/src/components/trace-configurations/trace-configuration-dialog-component.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; +import { ITspClient } from 'tsp-typescript-client'; +import { TraceConfigurationListComponent } from './trace-configuration-list-component'; +import { TraceConfigurationManager } from './trace-configuration-manager'; +import { AbstractDialogComponent, DialogComponentProps } from '../abstract-dialog-component'; + +export interface TraceConfigurationVisibility { + list: boolean; + add: boolean; +} + +export interface TraceConfigurationsDialogComponentProps extends DialogComponentProps { + tspClient: ITspClient; +} +export interface TraceConfigurationsDialogComponentState { + visibility: TraceConfigurationVisibility; + configurationSourceTypes: ConfigurationSourceType[]; +} + +export class TraceConfigurationsDialogComponent extends AbstractDialogComponent< + TraceConfigurationsDialogComponentProps, + TraceConfigurationsDialogComponentState +> { + protected renderDialogBody(): React.ReactElement { + return ( + + + + ); + } + protected renderFooter(): React.ReactElement { + return ; + } + private traceConfigurationManager: TraceConfigurationManager; + + constructor(props: TraceConfigurationsDialogComponentProps) { + super(props); + this.traceConfigurationManager = new TraceConfigurationManager(this.props.tspClient); + this.state = { + visibility: { + list: false, + add: false + }, + configurationSourceTypes: [] + }; + } + + protected onAfterOpen(): void { + this.traceConfigurationManager.getConfigurationSourceTypes().then(result => { + if (result !== undefined) { + this.setState({ + configurationSourceTypes: result + }); + } + }); + } + + private updateVisibility(visibility: TraceConfigurationVisibility): void { + this.setState({ + visibility: visibility + }); + } +} diff --git a/packages/react-components/src/components/trace-configurations/trace-configuration-list-component.tsx b/packages/react-components/src/components/trace-configurations/trace-configuration-list-component.tsx new file mode 100644 index 000000000..539a5310a --- /dev/null +++ b/packages/react-components/src/components/trace-configurations/trace-configuration-list-component.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; +import { AutoSizer, List, ListRowProps } from 'react-virtualized'; +import { TraceConfigurationManager } from './trace-configuration-manager'; + +export interface TraceConfigurationListComponentProps { + traceConfigurationManager: TraceConfigurationManager; + configurationSourceTypes: ConfigurationSourceType[]; +} + +export class TraceConfigurationListComponent extends React.Component { + private _forceUpdateKey = false; + private readonly TRACE_CONFIGURATIONS_ROW_HEIGHT = 20; + + constructor(props: TraceConfigurationListComponentProps) { + super(props); + } + + render(): React.ReactElement { + this._forceUpdateKey = !this._forceUpdateKey; + const key = Number(this._forceUpdateKey); + let outputsRowCount = 0; + const outputs = this.props.configurationSourceTypes; + if (outputs) { + outputsRowCount = outputs.length; + } + const totalHeight = 400; // TODO: Change this value once styling is applied + return ( +
+ List of configurations + + {({ width }) => ( + + )} + +
+ ); + } + + protected renderRowOutputs = (props: ListRowProps): React.ReactNode => this.doRenderRowOutputs(props); + + private doRenderRowOutputs(props: ListRowProps): React.ReactNode { + let outputName = ''; + let output: ConfigurationSourceType | undefined; + const configurationSourceTypes = this.props.configurationSourceTypes; + if ( + configurationSourceTypes && + configurationSourceTypes.length && + props.index < configurationSourceTypes.length + ) { + output = configurationSourceTypes[props.index]; + outputName = output.name; + } + + return ( +
+
+

{outputName}

+
+
+ ); + } +} diff --git a/packages/react-components/src/components/trace-configurations/trace-configuration-manager.ts b/packages/react-components/src/components/trace-configurations/trace-configuration-manager.ts new file mode 100644 index 000000000..a5e15d9c8 --- /dev/null +++ b/packages/react-components/src/components/trace-configurations/trace-configuration-manager.ts @@ -0,0 +1,22 @@ +import { ITspClient } from 'tsp-typescript-client'; +import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; + +export class TraceConfigurationManager { + private tspClient: ITspClient; + + constructor(tspClient: ITspClient) { + this.tspClient = tspClient; + } + + /** + * Get an array of OutputDescriptor for a given experiment + * @param experimentUUID experiment UUID + */ + async getConfigurationSourceTypes(): Promise { + const outputsResponse = await this.tspClient.fetchConfigurationSourceTypes(); + if (outputsResponse && outputsResponse.isOk()) { + return outputsResponse.getModel(); + } + return undefined; + } +} 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 b2eac9058..78f74f02b 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 @@ -6,6 +6,7 @@ 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 { TraceConfigurationsDialogComponent } from '../components/trace-configurations/trace-configuration-dialog-component'; export interface ReactAvailableViewsProps { id: string; @@ -16,6 +17,7 @@ export interface ReactAvailableViewsProps { export interface ReactAvailableViewsState { availableOutputDescriptors: OutputDescriptor[]; + showConfigurations: boolean; } export class ReactAvailableViewsWidget extends React.Component { @@ -24,6 +26,7 @@ export class ReactAvailableViewsWidget extends React.Component this.doHandleExperimentSelectedSignal(experiment); private _onExperimentClosed = (experiment: Experiment): void => this.doHandleExperimentClosedSignal(experiment); + private _onConfigurationOpened = (): void => this.showConfiguration(); constructor(props: ReactAvailableViewsProps) { super(props); @@ -33,17 +36,28 @@ export class ReactAvailableViewsWidget extends React.Component + this.closeConfiguration()} + isOpen={this.state.showConfigurations} + > { + this.setState({ showConfigurations: true }); + }; + + protected closeConfiguration(): void { + this.setState({ showConfigurations: false }); + } } diff --git a/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-commands.ts b/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-commands.ts index 058d7c7b8..d48ea50aa 100644 --- a/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-commands.ts +++ b/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-commands.ts @@ -30,6 +30,11 @@ export const OpenTraceWithRootPathCommand: Command = { label: 'Open Trace With Root Path' }; +export const OpenTraceConfigurations: Command = { + id: 'open-trace-configurations', + label: 'Open Trace Configurations' +}; + /** * A command to open a trace in the trace viewer. * diff --git a/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-contribution.ts b/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-contribution.ts index 96d4d420a..5d1d6f67e 100644 --- a/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-contribution.ts +++ b/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-contribution.ts @@ -17,7 +17,8 @@ import { TraceViewerCommand, KeyboardShortcutsCommand, OpenTraceWithRootPathCommand, - OpenTraceWithPathCommand + OpenTraceWithPathCommand, + OpenTraceConfigurations } from './trace-viewer-commands'; import { PortBusy, TraceServerConfigService } from '../../common/trace-server-config'; import { TracePreferences, TRACE_PATH, TRACE_ARGS } from '../trace-server-preference'; @@ -138,6 +139,10 @@ export class TraceViewerContribution } } + async openTraceConfigurations(): Promise { + signalManager().fireShowTraceConfigurations(); + } + async open(traceURI: URI, options?: TraceViewerWidgetOpenerOptions): Promise { let healthResponse; try { @@ -272,6 +277,9 @@ export class TraceViewerContribution await new ChartShortcutsDialog({ title: 'Trace Viewer Keyboard and Mouse Shortcuts' }).open(); } }); + registry.registerCommand(OpenTraceConfigurations, { + execute: () => this.openTraceConfigurations() + }); } canHandle(_uri: URI): number { diff --git a/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-toolbar-commands.ts b/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-toolbar-commands.ts index 5c182617b..71bf440fa 100644 --- a/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-toolbar-commands.ts +++ b/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-toolbar-commands.ts @@ -59,6 +59,12 @@ export namespace TraceViewerToolbarCommands { label: 'Show trace overview', iconClass: 'codicon codicon-graph-line' }; + + export const OPEN_TRACE_CONFIGURATIONS: Command = { + id: 'trace.viewer.openTraceConfigurations', + label: 'Open trace configurations', + iconClass: 'codicon codicon-server-process' + }; } export namespace TraceViewerToolbarMenus { diff --git a/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-toolbar-contribution.tsx b/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-toolbar-contribution.tsx index b0d313e70..3547e4e11 100644 --- a/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-toolbar-contribution.tsx +++ b/theia-extensions/viewer-prototype/src/browser/trace-viewer/trace-viewer-toolbar-contribution.tsx @@ -9,7 +9,8 @@ import { ChartShortcutsDialog } from '../trace-explorer/trace-explorer-sub-widge import { TspClientProvider } from '../tsp-client-provider-impl'; import { TraceViewerWidget } from './trace-viewer'; import { TraceViewerToolbarCommands, TraceViewerToolbarMenus } from './trace-viewer-toolbar-commands'; -import { OpenTraceCommand } from './trace-viewer-commands'; +import { OpenTraceCommand, OpenTraceConfigurations } from './trace-viewer-commands'; +import { TraceExplorerViewsWidget } from '../trace-explorer/trace-explorer-sub-widgets/theia-trace-explorer-views-widget'; @injectable() export class TraceViewerToolbarContribution implements TabBarToolbarContribution, CommandContribution { @@ -140,6 +141,18 @@ export class TraceViewerToolbarContribution implements TabBarToolbarContribution await new ChartShortcutsDialog({ title: 'Trace Viewer Keyboard and Mouse Shortcuts' }).open(); } }); + + registry.registerCommand(TraceViewerToolbarCommands.OPEN_TRACE_CONFIGURATIONS, { + isVisible: (w: Widget) => { + if (w instanceof TraceExplorerViewsWidget) { + return true; + } + return false; + }, + execute: async () => { + await registry.executeCommand(OpenTraceConfigurations.id); + } + }); } registerToolbarItems(registry: TabBarToolbarRegistry): void { @@ -348,5 +361,11 @@ export class TraceViewerToolbarContribution implements TabBarToolbarContribution tooltip: TraceViewerToolbarCommands.CHARTS_CHEATSHEET.label, priority: 10 }); + registry.registerItem({ + id: TraceViewerToolbarCommands.OPEN_TRACE_CONFIGURATIONS.id, + command: TraceViewerToolbarCommands.OPEN_TRACE_CONFIGURATIONS.id, + tooltip: TraceViewerToolbarCommands.OPEN_TRACE_CONFIGURATIONS.label, + priority: 11 + }); } } From bc0acd82bdc0af754428a6b43ffaae66a36815f5 Mon Sep 17 00:00:00 2001 From: Hoang Thuan Pham Date: Thu, 19 Oct 2023 14:51:31 -0400 Subject: [PATCH 2/3] Add trace cofiguration manager This commit adds the TraceConfigurationManager to handle calls to the trace server to manage configurations in the configuration UI. Signed-off-by: Hoang Thuan Pham --- .../base/src/trace-configuration-manager.ts | 50 +++++++++++++++++++ .../trace-configuration-manager.ts | 22 -------- 2 files changed, 50 insertions(+), 22 deletions(-) create mode 100644 packages/base/src/trace-configuration-manager.ts delete mode 100644 packages/react-components/src/components/trace-configurations/trace-configuration-manager.ts diff --git a/packages/base/src/trace-configuration-manager.ts b/packages/base/src/trace-configuration-manager.ts new file mode 100644 index 000000000..5192acec8 --- /dev/null +++ b/packages/base/src/trace-configuration-manager.ts @@ -0,0 +1,50 @@ +import { ITspClient } from 'tsp-typescript-client'; +import { Configuration } from 'tsp-typescript-client/lib/models/configuration'; +import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; +import { Query } from 'tsp-typescript-client/lib/models/query/query'; + +export class TraceConfigurationManager { + private tspClient: ITspClient; + + constructor(tspClient: ITspClient) { + this.tspClient = tspClient; + } + + /** + * Get an array of OutputDescriptor for a given experiment + * @param experimentUUID experiment UUID + */ + async getConfigurationSourceTypes(): Promise { + const outputsResponse = await this.tspClient.fetchConfigurationSourceTypes(); + if (outputsResponse && outputsResponse.isOk()) { + return outputsResponse.getModel(); + } + return undefined; + } + + async fetchConfigurations(typeId: string): Promise { + const outputsResponse = await this.tspClient.fetchConfigurations(typeId); + if (outputsResponse && outputsResponse.isOk()) { + return outputsResponse.getModel(); + } + return undefined; + } + + async createConfiguration(sourceTypeId: string, query: Query): Promise { + const outputsResponse = await this.tspClient.createConfiguration(sourceTypeId, query); + if (outputsResponse && outputsResponse.isOk()) { + return outputsResponse.getModel(); + } + + return undefined; + } + + async deleteConfiguration(sourceTypeId: string, configId: string): Promise { + const outputsResponse = await this.tspClient.deleteConfiguration(sourceTypeId, configId); + if (outputsResponse && outputsResponse.isOk()) { + return outputsResponse.getModel(); + } + + return undefined; + } +} diff --git a/packages/react-components/src/components/trace-configurations/trace-configuration-manager.ts b/packages/react-components/src/components/trace-configurations/trace-configuration-manager.ts deleted file mode 100644 index a5e15d9c8..000000000 --- a/packages/react-components/src/components/trace-configurations/trace-configuration-manager.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ITspClient } from 'tsp-typescript-client'; -import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; - -export class TraceConfigurationManager { - private tspClient: ITspClient; - - constructor(tspClient: ITspClient) { - this.tspClient = tspClient; - } - - /** - * Get an array of OutputDescriptor for a given experiment - * @param experimentUUID experiment UUID - */ - async getConfigurationSourceTypes(): Promise { - const outputsResponse = await this.tspClient.fetchConfigurationSourceTypes(); - if (outputsResponse && outputsResponse.isOk()) { - return outputsResponse.getModel(); - } - return undefined; - } -} From ba6e9ecc79319f1e36fb175ae2cf2b2a0c1cacf9 Mon Sep 17 00:00:00 2001 From: Hoang Thuan Pham Date: Thu, 19 Oct 2023 15:01:57 -0400 Subject: [PATCH 3/3] Add react components to add, update and delete configurations This commit add 2 new components to the configuration UI: A component used to add new configurations and another one to view the details of existing configurations. Existing components are also updated to integrate the new components. Signed-off-by: Hoang Thuan Pham --- .../trace-configuration-add-component.tsx | 106 ++++++++++++ .../trace-configuration-details-component.tsx | 50 ++++++ .../trace-configuration-dialog-component.tsx | 24 ++- .../trace-configuration-list-component.tsx | 154 ++++++++++++++---- 4 files changed, 299 insertions(+), 35 deletions(-) create mode 100644 packages/react-components/src/components/trace-configurations/trace-configuration-add-component.tsx create mode 100644 packages/react-components/src/components/trace-configurations/trace-configuration-details-component.tsx diff --git a/packages/react-components/src/components/trace-configurations/trace-configuration-add-component.tsx b/packages/react-components/src/components/trace-configurations/trace-configuration-add-component.tsx new file mode 100644 index 000000000..f4137fdb1 --- /dev/null +++ b/packages/react-components/src/components/trace-configurations/trace-configuration-add-component.tsx @@ -0,0 +1,106 @@ + +import React from 'react'; +import { TraceConfigurationManager } from 'traceviewer-base/lib/trace-configuration-manager'; +import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; +import { Query } from 'tsp-typescript-client/lib/models/query/query'; + +interface ConfigurationParameters { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any +} + +export interface TraceConfigurationsAddComponentProps { + configurationSourceTypes: ConfigurationSourceType[], + traceConfigurationManager: TraceConfigurationManager +} + +export interface TraceConfigurationsAddComponentState { + selectedConfigType: ConfigurationSourceType | undefined; +} + +export class TraceConfigurationsAddDialogComponent extends React.Component{ + private sourceTypeSelectRef: React.RefObject; + private readonly traceConfigParamPrefix = 'trace-configuration-param-'; + + constructor(props: TraceConfigurationsAddComponentProps) { + super(props); + this.sourceTypeSelectRef = React.createRef(); + this.state = { + selectedConfigType: undefined + }; + } + + render(): React.ReactElement { + return + + + { + this.state.selectedConfigType !== undefined && +
+ {this.renderParameters(this.state.selectedConfigType)} +
+ } +
+ +
+
; + } + + private renderParameters(configType: ConfigurationSourceType): React.ReactElement { + const parameters = configType.parameterDescriptors; + if (parameters) { + return +
Parameters
+ { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + parameters.map((param: any) => { + const paramHtmlId = this.traceConfigParamPrefix + param.keyName; + return (
+
+ + +
+
); + }) + } +
; + } + return ; + } + + private onChangeConfigurationSourceType(): void { + const selectedIndex = this.sourceTypeSelectRef.current?.selectedIndex; + if (selectedIndex !== undefined) { + const selectedConfigurationType = this.props.configurationSourceTypes[selectedIndex]; + this.setState({ + selectedConfigType: selectedConfigurationType + }); + } + } + + private async createConfiguration(): Promise { + const selectedIndex = this.sourceTypeSelectRef?.current?.selectedIndex; + if ((selectedIndex !== undefined) && (selectedIndex < this.props.configurationSourceTypes.length)) { + + const selectedSourceType = this.props.configurationSourceTypes[selectedIndex]; + const sourceTypeId = selectedSourceType.id; + const parameters: ConfigurationParameters = {}; + selectedSourceType.parameterDescriptors.forEach(param => { + const htmlId = this.traceConfigParamPrefix + param.keyName; + const inputElement = document.getElementById(htmlId); + if (inputElement instanceof HTMLInputElement) { + parameters[param.keyName] = inputElement.value; + } + }); + + await this.props.traceConfigurationManager.createConfiguration(sourceTypeId, new Query(parameters)); + } + } +} diff --git a/packages/react-components/src/components/trace-configurations/trace-configuration-details-component.tsx b/packages/react-components/src/components/trace-configurations/trace-configuration-details-component.tsx new file mode 100644 index 000000000..3efa482de --- /dev/null +++ b/packages/react-components/src/components/trace-configurations/trace-configuration-details-component.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { TraceConfigurationManager } from 'traceviewer-base/src/trace-configuration-manager'; +import { Configuration } from 'tsp-typescript-client/lib/models/configuration'; +import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; + +export interface TraceConfigurationsDetailsComponentProps { + configuration: Configuration, + configurationSourceType: ConfigurationSourceType, + traceConfigurationManager: TraceConfigurationManager +} + +export class TraceConfigurationsDetailsComponent extends React.Component< +TraceConfigurationsDetailsComponentProps +> { + constructor(props: TraceConfigurationsDetailsComponentProps) { + super(props); + } + + render(): React.ReactNode { + return +
Config Details
+
+ + {this.props.configuration.name} +
+
+ + {this.props.configuration.description} +
+
+ + {this.props.configurationSourceType.name} +
+
; + } + + renderParameters(): React.ReactNode { + return + { + this.props.configuration.parameters && + this.props.configuration.parameters.forEach((value: string, key: string) => { +
+ + {value} +
; + }) + } +
; + } +} diff --git a/packages/react-components/src/components/trace-configurations/trace-configuration-dialog-component.tsx b/packages/react-components/src/components/trace-configurations/trace-configuration-dialog-component.tsx index d324a8c0c..34c3249b0 100644 --- a/packages/react-components/src/components/trace-configurations/trace-configuration-dialog-component.tsx +++ b/packages/react-components/src/components/trace-configurations/trace-configuration-dialog-component.tsx @@ -1,9 +1,10 @@ import React from 'react'; -import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; -import { ITspClient } from 'tsp-typescript-client'; import { TraceConfigurationListComponent } from './trace-configuration-list-component'; -import { TraceConfigurationManager } from './trace-configuration-manager'; import { AbstractDialogComponent, DialogComponentProps } from '../abstract-dialog-component'; +import { TraceConfigurationsAddDialogComponent } from './trace-configuration-add-component'; +import { TraceConfigurationManager } from 'traceviewer-base/lib/trace-configuration-manager'; +import { ITspClient } from 'tsp-typescript-client/lib/protocol/tsp-client'; +import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; export interface TraceConfigurationVisibility { list: boolean; @@ -25,10 +26,19 @@ export class TraceConfigurationsDialogComponent extends AbstractDialogComponent< protected renderDialogBody(): React.ReactElement { return ( - +
+ +
+
+ +
); } diff --git a/packages/react-components/src/components/trace-configurations/trace-configuration-list-component.tsx b/packages/react-components/src/components/trace-configurations/trace-configuration-list-component.tsx index 539a5310a..8517aeeaf 100644 --- a/packages/react-components/src/components/trace-configurations/trace-configuration-list-component.tsx +++ b/packages/react-components/src/components/trace-configurations/trace-configuration-list-component.tsx @@ -1,46 +1,103 @@ import React from 'react'; -import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; import { AutoSizer, List, ListRowProps } from 'react-virtualized'; -import { TraceConfigurationManager } from './trace-configuration-manager'; +import { TraceConfigurationManager } from 'traceviewer-base/lib/trace-configuration-manager'; +import { Configuration } from 'tsp-typescript-client/lib/models/configuration'; +import { ConfigurationSourceType } from 'tsp-typescript-client/lib/models/configuration-source'; +import { TraceConfigurationsDetailsComponent } from './trace-configuration-details-component'; export interface TraceConfigurationListComponentProps { traceConfigurationManager: TraceConfigurationManager; configurationSourceTypes: ConfigurationSourceType[]; } -export class TraceConfigurationListComponent extends React.Component { +export interface TraceConfigurationListComponentState { + configurations: Configuration[], + selectedConfiguration: Configuration | undefined, + selectedConfigurationSourceType: ConfigurationSourceType | undefined +} + +export class TraceConfigurationListComponent extends React.Component { private _forceUpdateKey = false; private readonly TRACE_CONFIGURATIONS_ROW_HEIGHT = 20; + private sourceTypeSelectRef: React.RefObject; constructor(props: TraceConfigurationListComponentProps) { super(props); + + this.sourceTypeSelectRef = React.createRef(); + this.state = { + configurations: [], + selectedConfiguration: undefined, + selectedConfigurationSourceType: undefined + }; } render(): React.ReactElement { this._forceUpdateKey = !this._forceUpdateKey; const key = Number(this._forceUpdateKey); let outputsRowCount = 0; - const outputs = this.props.configurationSourceTypes; + const outputs = this.state.configurations; if (outputs) { outputsRowCount = outputs.length; } - const totalHeight = 400; // TODO: Change this value once styling is applied + const totalHeight = this.TRACE_CONFIGURATIONS_ROW_HEIGHT * outputsRowCount; return ( -
- List of configurations - - {({ width }) => ( - - )} - -
+ +
+ { + this.state.selectedConfiguration && this.state.selectedConfigurationSourceType && +
+ +
+ } +
+ + +
+ {/* + {({ width }) => ( + + )} + */} + +
List of configurations
+ { + this.state.configurations && +
+ + {({ width }) => ( + + )} + +
+ } +
+
); } @@ -48,23 +105,64 @@ export class TraceConfigurationListComponent extends React.Component -
+
this.onConfigurationSelected(output)}> +

{outputName}

+
); } + + private async fetchConfigurations() { + const selectedIndex = this.sourceTypeSelectRef.current?.selectedIndex; + if (selectedIndex !== undefined && selectedIndex < this.props.configurationSourceTypes.length) { + const selectedSourceType = this.props.configurationSourceTypes[selectedIndex]; + + const configurations = await this.props.traceConfigurationManager.fetchConfigurations(selectedSourceType.id); + if (configurations) { + this.setState({ + configurations: configurations, + selectedConfigurationSourceType: selectedSourceType + }); + } + } + } + + private async onChangeConfigurationSource(): Promise { + this.fetchConfigurations(); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private async onConfigurationSelected(selectedConfiguration: Configuration | undefined): Promise { + if (selectedConfiguration) { + this.setState({ + selectedConfiguration: selectedConfiguration + }); + } + } + + private async onConfigurationDeleted(event: React.MouseEvent, configuration: Configuration | undefined) { + event.stopPropagation(); + if (configuration !== undefined) { + const result = await this.props.traceConfigurationManager.deleteConfiguration(configuration.sourceTypeId, configuration.id); + if (result !== undefined) { + this.fetchConfigurations(); + } + } + } }