diff --git a/ide/src/trace/component/SpFlags.ts b/ide/src/trace/component/SpFlags.ts index 3a2920f3f9dd869d15d13e9e9c7825665a9f9cad..431e913c8678d80c0d37ef18c3e3df77bd074c06 100644 --- a/ide/src/trace/component/SpFlags.ts +++ b/ide/src/trace/component/SpFlags.ts @@ -244,6 +244,11 @@ export class FlagsConfig { switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], describeContent: 'Lost Frame and HitchTime templates', }, + { + title: 'UserPluginsRow', + switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], + describeContent: 'User Upload Plugin To Draw', + } ]; static getAllFlagConfig(): Array { diff --git a/ide/src/trace/component/SpSystemTrace.event.ts b/ide/src/trace/component/SpSystemTrace.event.ts index c83aaa0839ba79ca1b54811f8ccb8907264e28be..ef1744b77bf143a61dbedac1c6fe02fdd76782ad 100644 --- a/ide/src/trace/component/SpSystemTrace.event.ts +++ b/ide/src/trace/component/SpSystemTrace.event.ts @@ -358,7 +358,7 @@ function allStructOnClick(clickRowType: string, sp: SpSystemTrace, row?: TraceRo .then(() => FrameAnimationStructOnClick(clickRowType, sp, scrollToFuncHandlerFunc(sp), row!)) .then(() => FrameDynamicStructOnClick(clickRowType, sp, row)) .then(() => FrameSpacingStructOnClick(clickRowType, sp, row!)) - .then(() => sampleStructOnClick(clickRowType, sp)) + .then(() => sampleStructOnClick(clickRowType, sp, row)) .then(() => PerfToolsStructOnClick(clickRowType, sp)) .then(() => { diff --git a/ide/src/trace/component/chart/SpChartManager.ts b/ide/src/trace/component/chart/SpChartManager.ts index 924b0a5628dd31189d899df59f5bdb79103bd268..62c1bc613b612ef838615cf6142c829d2e14da2a 100644 --- a/ide/src/trace/component/chart/SpChartManager.ts +++ b/ide/src/trace/component/chart/SpChartManager.ts @@ -55,6 +55,7 @@ import { queryMemoryConfig } from '../../database/sql/Memory.sql'; import { SpLtpoChart } from './SpLTPO'; import { SpBpftraceChart } from './SpBpftraceChart'; import { sliceSender } from '../../database/data-trafic/SliceSender'; +import { SpUserFileChart } from './SpUserPluginChart' export class SpChartManager { static APP_STARTUP_PID_ARR: Array = []; @@ -84,6 +85,7 @@ export class SpChartManager { private spBpftraceChart: SpBpftraceChart; private tranceRange = { startTs: 0, endTs: 0 }; private spPerfOutputDataChart: SpPerfOutputDataChart; + private spUserFileChart: SpUserFileChart; constructor(trace: SpSystemTrace) { this.trace = trace; @@ -110,6 +112,7 @@ export class SpChartManager { this.spSegmentationChart = new SpSegmentationChart(trace); this.spBpftraceChart = new SpBpftraceChart(trace); this.spPerfOutputDataChart = new SpPerfOutputDataChart(trace); + this.spUserFileChart = new SpUserFileChart(trace) } async initPreprocessData(progress: Function): Promise { progress('load data dict', 50); @@ -144,6 +147,9 @@ export class SpChartManager { if (FlagsConfig.getFlagsConfigEnableStatus('Bpftrace')) { await this.spBpftraceChart.init(null); } + if (FlagsConfig.getFlagsConfigEnableStatus('UserPluginsRow')){ + await this.spUserFileChart.init(null) + } if (FlagsConfig.getFlagsConfigEnableStatus('SchedulingAnalysis')) { await this.cpu.initCpuIdle0Data(progress); await this.cpu.initSchedulingPTData(progress); diff --git a/ide/src/trace/component/chart/SpUserPluginChart.ts b/ide/src/trace/component/chart/SpUserPluginChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2116110aab74b68128772176f194ac935f21bf7 --- /dev/null +++ b/ide/src/trace/component/chart/SpUserPluginChart.ts @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { SpSystemTrace } from '../SpSystemTrace'; +import { TraceRow } from '../trace/base/TraceRow'; +import { renders } from '../../database/ui-worker/ProcedureWorker'; +import { SampleStruct, SampleRender } from '../../database/ui-worker/ProcedureWorkerBpftrace'; +import { queryStartTime } from '../../database/sql/SqlLite.sql'; +import { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil'; + +export class SpUserFileChart { + private trace: SpSystemTrace; + private currentFile: undefined; + static userPluginData: []; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init(file: File | null) { + if (!file) { + let startTime = await queryStartTime(); + //@ts-ignore + let folder = await this.initSample(startTime[0].start_ts, file); + this.trace.rowsEL?.appendChild(folder); + } else { + let folder = await this.initSample(-1, file); + this.trace.rowsEL?.appendChild(folder); + } + } + + async initSample(start_ts: number, file: unknown): Promise> { + let traceRow = TraceRow.skeleton(); + traceRow.rowId = 'userPlugin'; + traceRow.index = 0; + traceRow.rowType = TraceRow.ROW_TYPE_SAMPLE; + traceRow.rowParentId = ''; + traceRow.folder = false; + traceRow.style.height = '40px'; + traceRow.name = 'UserPluginRow'; + traceRow.selectChangeHandler = this.trace.selectChangeHandler; + traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + traceRow.findHoverStruct = () => { + SampleStruct.hoverSampleStruct = traceRow.getHoverStruct(); + }; + //添加上传按钮 + traceRow.addRowSampleUpload(); + this.addTraceRowEventListener(traceRow, start_ts); + //单独上传 + if (file) { + this.getJsonData(file).then((res: unknown) => { + //@ts-ignore + const propertyData = res.data; + //@ts-ignore + const treeNodes = res.relation.children || [res.relation.RS.children[0]]; + SpUserFileChart.userPluginData = treeNodes.data[0] || []; + const uniqueProperty = this.removeDuplicates(propertyData); + const flattenTreeArray = this.getFlattenTreeData(treeNodes); + //@ts-ignore + const height = (Math.max(...flattenTreeArray.map((obj: unknown) => obj.depth)) + 1) * 20; + const sampleProperty = this.setRelationDataProperty(flattenTreeArray, uniqueProperty); + //@ts-ignore + const startTS = flattenTreeArray[0].property[0].begin; + traceRow.supplier = () => + new Promise((resolve): void => { + //@ts-ignore + resolve(sampleProperty) + }) + traceRow.onThreadHandler = (useCache) => { + let context: CanvasRenderingContext2D; + if (traceRow.currentContext) { + context = traceRow.currentContext; + } else { + context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + } + traceRow.canvasSave(context); + (renders.sample as SampleRender).renderMainThread( + { + context: context, + useCache: useCache, + type: 'bpftrace', + start_ts: startTS, + uniqueProperty: uniqueProperty, + //@ts-ignore + flattenTreeArray: flattenTreeArray + }, + traceRow + ); + traceRow.canvasRestore(context) + }; + traceRow.style.height = `${height}px`; + }) + } + return traceRow; + } + + /** + * 监听文件上传事件 + * @param row + * @param start_ts + */ + + //@ts-ignore + addTraceRowEventListener(row: TraceRow, start_ts: number) { + row.uploadEl?.addEventListener('sample-file-change', (e: unknown) => { + this.getJsonData(e).then((res: unknown) => { + this.resetChartData(row); + if (!res) { + row.supplier = () => + new Promise((resolve): void => { + resolve([]) + }) + this.trace.traceSheetEL?.setMode('hidden'); + row.style.height = '40px'; + row.name = 'UserPluginRow' + } else { + //@ts-ignore + const propertyData = res.data; + //@ts-ignore + SpUserFileChart.userPluginData = res.data[0]; + //@ts-ignore + const treeNodes = res.relation.children || [res.relation.RS.children[0]]; + const uniqueProperty = this.removeDuplicates(propertyData); + const flattenTreeArray = this.getFlattenTreeData(treeNodes); + //@ts-ignore + const height = (Math.max(...flattenTreeArray.map((obj: unknown) => obj.depth)) + 1) * 20; + const sampleProperty = this.setRelationDataProperty(flattenTreeArray, uniqueProperty); + //@ts-ignore + const startTS = start_ts > 0 ? start_ts : flattenTreeArray[0].property[0].begin; + row.supplier = () => + new Promise((resolve): void => { + resolve(sampleProperty) + }) + row.onThreadHandler = (useCache) => { + let context: CanvasRenderingContext2D; + if (row.currentContext) { + context = row.currentContext; + } else { + context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + } + row.canvasSave(context); + (renders.sample as SampleRender).renderMainThread( + { + context: context, + useCache: useCache, + type: 'bpftrace', + start_ts: startTS, + uniqueProperty: uniqueProperty, + //@ts-ignore + flattenTreeArray: flattenTreeArray + }, + row + ); + row.canvasRestore(context) + }; + //@ts-ignore + row.name = `${res.relation.detail}(${res.relation.function_name})`; + row.style.height = `${height}px`; + } + this.trace.refreshCanvas(false) + }) + }) + } + + /** + * 清空缓存 + * @param row + */ + //@ts-ignore + resetChartData(row: TraceRow) { + row.dataList = []; + row.dataList2 = []; + row.dataListCache = []; + row.isComplete = false; + } + + /** + * 获取上传的文件内容 转为json格式 + * @param file + * @returns + */ + getJsonData(file: unknown): Promise { + return new Promise((resolve, reject) => { + let reader = new FileReader(); + //@ts-ignore + reader.readAsText(file.detail || file); + reader.onloadend = (e: unknown) => { + //@ts-ignore + const fileContent = e.target?.result; + if (fileContent === this.currentFile) { + this.currentFile = undefined; + resolve(false) + } else { + this.currentFile = fileContent; + } + try { + resolve(JSON.parse(fileContent)); + document.dispatchEvent( + new CustomEvent('file-correct') + ) + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'bpftrace', + action: 'bpftrace', + }); + } catch (error) { + document.dispatchEvent( + new CustomEvent('file-error') + ) + } + } + }) + } + + /** + * 树结构扁平化 + * @param treeData + * @param depth + * @param parentName + * @returns + */ + getFlattenTreeData(treeData: Array, depth: number = 0, parentName: string = ''): Array { + let result: Array = []; + treeData.forEach(node => { + //@ts-ignore + const name: string = node['function_name']; + const newNode: unknown = {}; + if (name && name.indexOf('unknown') > -1) { + //@ts-ignore + newNode['children'] = this.getUnknownAllChildrenNames(node); + } + //@ts-ignore + newNode['detail'] = node['detail']; + //@ts-ignore + newNode['depth'] = depth; + //@ts-ignore + newNode['name'] = name; + //@ts-ignore + newNode['parentName'] = parentName; + //@ts-ignore + newNode['property'] = []; + //@ts-ignore + result.push(newNode); + //@ts-ignore + if (node.children) { + //@ts-ignore + result = result.concat(this.getFlattenTreeData(node.children, depth + 1, node['function_name'])) + } + }) + return result + } + + /** + * 查找重复项 + * @param propertyData + * @returns + */ + removeDuplicates(propertyData: Array): Array { + const result: Array = []; + propertyData.forEach(propertyGroup => { + const groups: Array = []; + //@ts-ignore + propertyGroup.forEach((property: unknown) => { + //@ts-ignore + const duplicateObj = groups.find(group => group['func_name'] === property['func_name']); + if (duplicateObj) { + //@ts-ignore + duplicateObj['begin'] = Math.min(duplicateObj['begin'], property['begin']); + //@ts-ignore + duplicateObj['end'] = Math.max(duplicateObj['end'], property['end']); + } else { + groups.push(property) + } + }) + result.push(groups); + }) + return result + } + + /** + * 关系树赋值 + * @param relationData + * @param propertyData + */ + setRelationDataProperty(relationData: Array, propertyData: Array): Array { + const sampleProperty = relationData; + //数组每一项进行比对 + propertyData.forEach(propertyGroup => { + //@ts-ignore + propertyGroup.forEach((property: unknown) => { + //@ts-ignore + const relation = sampleProperty.find(relation => relation['name'] === property['func_name']); + //property属性存储每帧数据 + //@ts-ignore + relation?.property.push({ + //@ts-ignore + name: property['func_name'], + //@ts-ignore + detail: relation['detail'], + //@ts-ignore + end: property['end'], + //@ts-ignore + begin: property['begin'], + //@ts-ignore + depth: relation['depth'], + //@ts-ignore + instructions: property['instructions'], + //@ts-ignore + cycles: property['cycles'] + }) + }) + }) + + //获取所有名字为unknown的数据 + //@ts-ignore + const unknownRelation = sampleProperty.filter(relation => relation['name'].indexOf('unknown') > -1); + //二维数组 用于存放unknown下所有子节点的数据 + let twoDimensionalArray: Array = []; + let result: Array = []; + unknownRelation.forEach(unknownItem => { + result = []; + twoDimensionalArray = []; + //@ts-ignore + const children = unknownItem['children']; + //先获取到unknwon节点下每个子节点的property + Object.keys(children).forEach(key => { + //@ts-ignore + unknownItem.children[key] = (sampleProperty.find(relation => relation['name'] === key)).property; + }) + //将每个子节点的property加到二维数组中 + Object.values(children).forEach((value: unknown) => { + //@ts-ignore + if (value.length > 0) { + twoDimensionalArray.push(value) + } + }) + if (twoDimensionalArray.length > 0) { + //取每列的最大值和最小值 + //@ts-ignore + for (let i = 0; i < twoDimensionalArray[0].length; i++) { + const data = { + //@ts-ignore + name: unknownItem['name'], + //@ts-ignore + detail: unknownItem['detail'], + //@ts-ignore + begin: (twoDimensionalArray[0][i]).begin, + end: 0, + //@ts-ignore + depth: unknownItem['depth'] + } + for (let j = 0; j < twoDimensionalArray.length; j++) { + //@ts-ignore + data['end'] = Math.max((twoDimensionalArray[j][i])['end'], data['end']); + //@ts-ignore + data['begin'] = Math.min((twoDimensionalArray[j][i])['begin'], data['begin']); + } + result.push(data); + } + //@ts-ignore + unknownItem.property = result; + } + }) + return sampleProperty; + } + + /** + * 获取unknown节点下所有孩子节点的名称 + * @param node + * @param names + */ + getUnknownAllChildrenNames(node: unknown, names: unknown = {}): object { + //@ts-ignore + if (node['children']) { + //@ts-ignore + node['children'].forEach((child: unknown) => { + //@ts-ignore + if (child['function_name'].indexOf('unknown') < 0) { + //@ts-ignore + names[child['function_name']] = [] + } else { + this.getUnknownAllChildrenNames(child, names) + } + }) + } + //@ts-ignore + return names + } +} diff --git a/ide/src/trace/component/trace/base/TraceSheet.ts b/ide/src/trace/component/trace/base/TraceSheet.ts index 741bebdc24ea955092eef47fde78388081ae70e1..27459b0424f3574fb0864b3b87dece70116fd527 100644 --- a/ide/src/trace/component/trace/base/TraceSheet.ts +++ b/ide/src/trace/component/trace/base/TraceSheet.ts @@ -84,6 +84,7 @@ import { LitPopover } from '../../../../base-ui/popover/LitPopoverV'; import { LitTree, TreeItemData } from '../../../../base-ui/tree/LitTree'; import { SampleStruct } from '../../../database/ui-worker/ProcedureWorkerBpftrace'; import { TabPaneSampleInstruction } from '../sheet/bpftrace/TabPaneSampleInstruction'; +import { TabPaneUserPlugin } from '../sheet/userPlugin/TabPaneUserPlugin'; import { TabPaneFreqStatesDataCut } from '../sheet/states/TabPaneFreqStatesDataCut'; import { TabPaneDataCut } from '../sheet/TabPaneDataCut'; import { SpSystemTrace } from '../../SpSystemTrace'; @@ -340,19 +341,17 @@ export class TraceSheet extends BaseElement { this.initNavElements(tabsPackUp!, borderTop, initialHeight); this.exportBt = this.shadowRoot?.querySelector('#export-btn'); tabsOpenUp!.onclick = (): void => { - this.tabs!.style.height = `${ - window.innerHeight - this.search!.offsetHeight - this.timerShaft!.offsetHeight - borderTop - }px`; + this.tabs!.style.height = `${window.innerHeight - this.search!.offsetHeight - this.timerShaft!.offsetHeight - borderTop + }px`; let litTabpane: NodeListOf | undefined | null = this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); litTabpane!.forEach((node: HTMLDivElement): void => { - node!.style.height = `${ - window.innerHeight - + node!.style.height = `${window.innerHeight - this.search!.offsetHeight - this.timerShaft!.offsetHeight - this.navRoot!.offsetHeight - borderTop - }px`; + }px`; initialHeight.node = node!.style.height; }); initialHeight.tabs = this.tabs!.style.height; @@ -449,7 +448,7 @@ export class TraceSheet extends BaseElement { // 只要没有移动到边界区域都会进入该条件 that.navRoot!.offsetHeight <= newHeight && that.search!.offsetHeight + that.timerShaft!.offsetHeight + borderTop + that.spacer!.offsetHeight <= - window.innerHeight - newHeight + window.innerHeight - newHeight ) { that.tabs!.style.height = `${newHeight}px`; litTabpane!.style.height = `${newHeight - that.navRoot!.offsetHeight}px`; @@ -464,21 +463,19 @@ export class TraceSheet extends BaseElement { window.innerHeight - newHeight ) { // 该条件在面板高度置顶时触发 - that.tabs!.style.height = `${ - window.innerHeight - + that.tabs!.style.height = `${window.innerHeight - that.search!.offsetHeight - that.timerShaft!.offsetHeight - borderTop - that.spacer!.offsetHeight - }px`; - litTabpane!.style.height = `${ - window.innerHeight - + }px`; + litTabpane!.style.height = `${window.innerHeight - that.search!.offsetHeight - that.timerShaft!.offsetHeight - that.navRoot!.offsetHeight - borderTop - that.spacer!.offsetHeight - }px`; + }px`; tabsPackUp!.name = 'down'; } that.tabPaneHeight = litTabpane!.style.height; @@ -864,6 +861,11 @@ export class TraceSheet extends BaseElement { ]; }; + + displayUserPlugin = (selectData: any): void => { + this.displayTab("tab-pane-userplugin").data = selectData; + }; + displaySystemStatesData = (): void => { let dataCutPane = this.shadowRoot?.querySelector('tabpane-datacut'); if (dataCutPane) { diff --git a/ide/src/trace/component/trace/base/TraceSheetConfig.ts b/ide/src/trace/component/trace/base/TraceSheetConfig.ts index a0a5f6baef4429bc80ec94ed636eed99fc1fa24a..d2048e5beb5a427bf4fd78b2068cc2e12c721229 100644 --- a/ide/src/trace/component/trace/base/TraceSheetConfig.ts +++ b/ide/src/trace/component/trace/base/TraceSheetConfig.ts @@ -128,6 +128,7 @@ import { TabPaneSampleInstructionDistributions } from '../sheet/bpftrace/TabPane import { TabPaneSampleInstructionTotalTime } from '../sheet/bpftrace/TabPaneSampleInstructionSelectionTotalTime'; import { TabPaneSampleInstructionSelection } from '../sheet/bpftrace/TabPaneSampleInstructionSelection'; import { TabPaneDataCut } from '../sheet/TabPaneDataCut'; +import { TabPaneUserPlugin } from '../sheet/userPlugin/TabPaneUserPlugin'; export let tabConfig: unknown = { 'current-selection': { @@ -688,4 +689,8 @@ export let tabConfig: unknown = { title: 'Data Flow', type: TabPaneSampleInstruction, }, + 'tab-pane-userplugin': { + title: 'User Plugin', + type: TabPaneUserPlugin, + }, }; diff --git a/ide/src/trace/component/trace/sheet/userPlugin/TabPaneUserPlugin.ts b/ide/src/trace/component/trace/sheet/userPlugin/TabPaneUserPlugin.ts new file mode 100644 index 0000000000000000000000000000000000000000..63c638763388e669ae5554b26bdc16704252f7d6 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/userPlugin/TabPaneUserPlugin.ts @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BaseElement, element } from '../../../../../base-ui/BaseElement'; +import { LitTable } from '../../../../../base-ui/table/lit-table'; + +@element('tab-pane-userplugin') +export class TabPaneUserPlugin extends BaseElement { + static isStateTabHover: boolean = false; + private currentSelectionTbl: LitTable | null | undefined; + + // tab页入口函数 + set data(selectionData: any) { + let list = new Array(); + for (let key in selectionData) { + list.push({ + name: key, + value: selectionData[key] + }) + } + this.currentSelectionTbl!.dataSource = list; + } + + initElements(): void { + this.currentSelectionTbl = this.shadowRoot?.querySelector('#selectionTbl'); + } + // 页面结构 + + initHtml(): string { + return ` + +
+
+
+

Data Flow

+
+
+
+ + + + + + + + +
+
` + } +} \ No newline at end of file diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerBpftrace.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerBpftrace.ts index 3b41582957a146a114c9d646396a242268386d31..f606476449a1ccf37399df607ca65e67bed69520 100644 --- a/ide/src/trace/database/ui-worker/ProcedureWorkerBpftrace.ts +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerBpftrace.ts @@ -25,6 +25,7 @@ import { } from './ProcedureWorkerCommon'; import { TraceRow } from '../../component/trace/base/TraceRow'; import { SpSystemTrace } from '../../component/SpSystemTrace'; +import { SpUserFileChart } from '../../component/chart/SpUserPluginChart'; const SAMPLE_STRUCT_HEIGHT = 20; const Y_PADDING = 2; @@ -132,12 +133,24 @@ function setSampleFilter( } } -export function sampleStructOnClick(clickRowType: string, sp: SpSystemTrace): Promise { +// @ts-ignore +export function sampleStructOnClick(clickRowType: string, sp: SpSystemTrace, row: TraceRow | undefined) { return new Promise((resolve, reject) => { - if (clickRowType === TraceRow.ROW_TYPE_SAMPLE && SampleStruct.hoverSampleStruct) { - SampleStruct.selectSampleStruct = SampleStruct.hoverSampleStruct; - sp.traceSheetEL?.displaySampleData(SampleStruct.selectSampleStruct, SampleStruct.reqProperty); - sp.timerShaftEL?.modifyFlagList(undefined); + SampleStruct.selectSampleStruct = SampleStruct.hoverSampleStruct; + if (clickRowType === TraceRow.ROW_TYPE_SAMPLE && SampleStruct.hoverSampleStruct && SampleStruct.selectSampleStruct !== undefined) { + if (row?.rowId === 'userPlugin') { + SpUserFileChart.userPluginData!.map((v: unknown) => { + //@ts-ignore + if (v.func_name === SampleStruct.selectSampleStruct!.name && + //@ts-ignore + v.begin === SampleStruct.selectSampleStruct?.begin) { + sp.traceSheetEL?.displayUserPlugin(v) + } + }) + } else { + sp.traceSheetEL?.displaySampleData(SampleStruct.selectSampleStruct, SampleStruct.reqProperty); + sp.timerShaftEL?.modifyFlagList(undefined); + } reject(new Error()); } else { resolve(null);