|
| 1 | +import * as React from 'react'; |
| 2 | +import { Trace } from 'tsp-typescript-client'; |
| 3 | +import { signalManager, Signals } from '@trace-viewer/base/lib/signals/signal-manager'; |
| 4 | + |
| 5 | +interface MenuItemProps { |
| 6 | + index: number; |
| 7 | + experimentName: string; |
| 8 | + experimentUUID: string; |
| 9 | + traces: Trace[]; |
| 10 | + onTabNameChange: (tabEditingOpen: string, index: number) => void; |
| 11 | + menuItemTraceContainerClassName: string; |
| 12 | + handleClickEvent: (event: React.MouseEvent<HTMLDivElement>, experimentName: string) => void; |
| 13 | + handleContextMenuEvent: (event: React.MouseEvent<HTMLDivElement>, experimentUUID: string) => void; |
| 14 | +} |
| 15 | +interface MenuItemState { |
| 16 | + editingTab: boolean; |
| 17 | + oldexpirementName: string; |
| 18 | + expirementNameState: string; |
| 19 | +} |
| 20 | + |
| 21 | +export class MenuItemTrace extends React.Component<MenuItemProps, MenuItemState> { |
| 22 | + |
| 23 | + private wrapper: React.RefObject<HTMLDivElement>; |
| 24 | + |
| 25 | + constructor(menuItemProps: MenuItemProps) { |
| 26 | + super(menuItemProps); |
| 27 | + this.state = { |
| 28 | + oldexpirementName: this.props.experimentName, |
| 29 | + expirementNameState: this.props.experimentName, |
| 30 | + editingTab: false |
| 31 | + }; |
| 32 | + this.wrapper = React.createRef(); |
| 33 | + } |
| 34 | + |
| 35 | + componentDidMount(): void { |
| 36 | + document.addEventListener('click', this.handleClickOutside); |
| 37 | + } |
| 38 | + |
| 39 | + componentWillUnmount(): void { |
| 40 | + document.removeEventListener('click', this.handleClickOutside); |
| 41 | + } |
| 42 | + |
| 43 | + submitNewTab(): void { |
| 44 | + if (this.state.expirementNameState.length > 0) { |
| 45 | + this.setState({ |
| 46 | + editingTab: false, |
| 47 | + oldexpirementName: this.state.expirementNameState |
| 48 | + }); |
| 49 | + this.props.onTabNameChange(this.state.expirementNameState, this.props.index); |
| 50 | + } else { |
| 51 | + this.setState({ |
| 52 | + editingTab: false, |
| 53 | + expirementNameState: this.state.oldexpirementName |
| 54 | + }); |
| 55 | + signalManager().fireTabChangedSignal(this.state.oldexpirementName, this.props.experimentUUID); |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + handleClickOutside = (event: Event): void => { |
| 60 | + const node = this.wrapper.current; |
| 61 | + if ((!node || !node.contains(event.target as Node)) && this.state.editingTab === true) { |
| 62 | + this.submitNewTab(); |
| 63 | + } |
| 64 | + }; |
| 65 | + |
| 66 | + protected handleEnterPress(event: React.KeyboardEvent<HTMLInputElement>): void{ |
| 67 | + if (event.key === 'Enter' && this.state.editingTab === true){ |
| 68 | + this.submitNewTab(); |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + protected changeText(event: React.ChangeEvent<HTMLInputElement>): void{ |
| 73 | + const newName = event.target.value.toString(); |
| 74 | + this.setState({ |
| 75 | + expirementNameState : newName |
| 76 | + }); |
| 77 | + signalManager().fireTabChangedSignal(newName, this.props.experimentUUID); |
| 78 | + } |
| 79 | + protected inputTab(): React.ReactNode { |
| 80 | + return <input name="tab-name" className="theia-input" |
| 81 | + defaultValue = {this.state.expirementNameState} |
| 82 | + onChange = {e => (this.changeText(e))} |
| 83 | + onClick = {e => e.stopPropagation()} |
| 84 | + onKeyPress = {e => (this.handleEnterPress(e))} |
| 85 | + maxLength = {50} |
| 86 | + />; |
| 87 | + } |
| 88 | + protected renderEditTraceName(event: React.MouseEvent<HTMLDivElement>): void { |
| 89 | + this.setState(() => ({ |
| 90 | + editingTab: true |
| 91 | + })); |
| 92 | + event.stopPropagation(); |
| 93 | + } |
| 94 | + protected renderTracesForExperiment = (): React.ReactNode => this.doRenderTracesForExperiment(); |
| 95 | + protected doRenderTracesForExperiment(): React.ReactNode { |
| 96 | + const tracePaths = this.props.traces; |
| 97 | + return ( |
| 98 | + <div className='trace-element-path-container'> |
| 99 | + {tracePaths.map(trace => ( |
| 100 | + <div className='trace-element-path child-element' id={trace.UUID} key={trace.UUID}> |
| 101 | + {` > ${trace.name}`} |
| 102 | + </div> |
| 103 | + ))} |
| 104 | + </div> |
| 105 | + ); |
| 106 | + } |
| 107 | + protected subscribeToExplorerEvents(): void { |
| 108 | + signalManager().on(Signals.OUTPUT_ADDED, this.changeText); |
| 109 | + } |
| 110 | + |
| 111 | + render(): JSX.Element { |
| 112 | + return ( |
| 113 | + <div className={this.props.menuItemTraceContainerClassName} |
| 114 | + id={`${this.props.menuItemTraceContainerClassName}-${this.props.index}`} |
| 115 | + onClick={event => { this.props.handleClickEvent(event, this.props.experimentUUID); }} |
| 116 | + onContextMenu={event => { this.props.handleContextMenuEvent(event, this.props.experimentUUID); }} |
| 117 | + data-id={`${this.props.index}`} |
| 118 | + ref={this.wrapper}> |
| 119 | + <div className='trace-element-container'> |
| 120 | + <div className='trace-element-info' > |
| 121 | + <h4 className='trace-element-name'> |
| 122 | + {this.state.editingTab ? this.inputTab() : this.state.expirementNameState} |
| 123 | + <div className='edit-trace-name' onClick={e => {this.renderEditTraceName(e);}}> |
| 124 | + <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" x="0px" y="0px" |
| 125 | + width="16px" height="16px" viewBox="0 0 512 512" enableBackground="new 0 0 512 512" xmlSpace="preserve"> |
| 126 | + <g> |
| 127 | + <path fill="#020202" d="M422.953,176.019c0.549-0.48,1.09-0.975,1.612-1.498l21.772-21.772c12.883-12.883,12.883-33.771,0-46.654 |
| 128 | + l-40.434-40.434c-12.883-12.883-33.771-12.883-46.653,0l-21.772,21.772c-0.523,0.523-1.018,1.064-1.498,1.613L422.953,176.019z"/> |
| 129 | + <polygon fill="#020202" points="114.317,397.684 157.317,440.684 106.658,448.342 56,456 63.658,405.341 71.316,354.683 "/> |
| 130 | + <polygon fill="#020202" points="349.143,125.535 118.982,355.694 106.541,343.253 336.701,113.094 324.26,100.653 81.659,343.253 |
| 131 | + 168.747,430.341 411.348,187.74 "/> |
| 132 | + </g> |
| 133 | + </svg> |
| 134 | + </div> |
| 135 | + </h4> |
| 136 | + { this.renderTracesForExperiment() } |
| 137 | + </div> |
| 138 | + {/* <div className='trace-element-options'> |
| 139 | + <button className='share-context-button' onClick={this.handleShareButtonClick.bind(this, props.index)}> |
| 140 | + <FontAwesomeIcon icon={faShareSquare} /> |
| 141 | + </button> |
| 142 | + </div> */} |
| 143 | + </div> |
| 144 | + </div> |
| 145 | + ); |
| 146 | + } |
| 147 | +} |
0 commit comments