diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/.babelrc b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/.babelrc
new file mode 100644
index 0000000000000000000000000000000000000000..18151f1f8f709838202b6231652ea8cec184527e
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/.babelrc
@@ -0,0 +1,3 @@
+{
+ "presets": ["@babel/preset-env", "@babel/preset-react"]
+}
\ No newline at end of file
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/.prettierrc b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/.prettierrc
new file mode 100644
index 0000000000000000000000000000000000000000..e3d2acb00457084b2f6cccafb8c95740e0344485
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/.prettierrc
@@ -0,0 +1,13 @@
+{
+ "parser": "typescript",
+ "semi": true,
+ "singleQuote": true,
+ "jsxSingleQuote": false,
+ "bracketSpacing": true,
+ "tabWidth": 2,
+ "useTabs": false,
+ "trailingComma": "all",
+ "proseWrap": "always",
+ "endOfLine": "lf",
+ "printWidth": 120
+}
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/package.json b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..bcd95816016e78f3a02187ee0d3e69e6cabf3ee3
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "fe",
+ "version": "1.0.0",
+ "main": "webpack.config.js",
+ "scripts": {
+ "dev": "webpack serve --config webpack.dev.js",
+ "buildWin": "cross-env NODE_ENV=production webpack && copy dist\\index.html ..\\server\\static\\",
+ "prettier": "prettier --config ./.prettierrc --write ./src/**/*.ts"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "description": "",
+ "devDependencies": {
+ "@babel/core": "^7.27.3",
+ "@babel/preset-env": "^7.27.2",
+ "@babel/preset-react": "^7.27.1",
+ "babel-loader": "^10.0.0",
+ "clean-webpack-plugin": "^4.0.0",
+ "cross-env": "^7.0.3",
+ "css-loader": "^7.1.2",
+ "file-loader": "^6.2.0",
+ "html-loader": "^5.1.0",
+ "html-webpack-plugin": "^5.6.3",
+ "inline-chunk-html-plugin": "^1.1.1",
+ "less": "^4.3.0",
+ "less-loader": "^12.3.0",
+ "mini-css-extract-plugin": "^2.9.2",
+ "prettier": "^3.5.3",
+ "style-loader": "^4.0.0",
+ "ts-loader": "^9.5.2",
+ "typescript": "^5.8.3",
+ "webpack": "^5.96.1",
+ "webpack-cli": "^5.1.4",
+ "webpack-dev-server": "4.15.1"
+ },
+ "dependencies": {
+ "ahooks": "^3.8.5",
+ "antd": "^5.25.3",
+ "axios": "^1.9.0",
+ "echarts": "^5.6.0",
+ "echarts-for-react": "^3.0.2",
+ "lodash": "^4.17.21",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "use-sync-external-store": "^1.5.0",
+ "zustand": "^5.0.5"
+ }
+}
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/public/index.html b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/public/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..a0c678cdf146296b73a19afc2e04fe1aaab32448
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/public/index.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Graph
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/index.less b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/index.less
new file mode 100644
index 0000000000000000000000000000000000000000..2d10e24d0616249373f6e376747bd4e245448d82
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/index.less
@@ -0,0 +1,34 @@
+/* -------------------------------------------------------------------------
+ Copyright (c) 2025, Huawei Technologies.
+ All rights reserved.
+
+ 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.
+--------------------------------------------------------------------------------------------*/
+
+.warpper {
+ background-color: #eeeeee;
+ height: 100%;
+}
+
+.controller {
+ padding: 16px 12px;
+ background-color: white;
+}
+
+.title {
+ font-size: 16px;
+ font-weight: 500;
+ text-align: center;
+ padding-block: 6px;
+ background-color: #f1f1f1;
+}
\ No newline at end of file
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/index.tsx b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/index.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..ee2a7a787517fdcb504a1ea8162299b6b9363ca4
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/index.tsx
@@ -0,0 +1,216 @@
+/* -------------------------------------------------------------------------
+ Copyright (c) 2025, Huawei Technologies.
+ All rights reserved.
+
+ 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 React, { useEffect, useState, memo } from 'react';
+import { shallow, useShallow } from 'zustand/shallow';
+import { message } from 'antd';
+import { isEmpty } from 'lodash';
+import './index.less';
+import { useGlobalStore } from '../store';
+import { DIMENSIONS_OPTIONS, HEATMAP_TYPE } from '../common/constant';
+import SelectWithLabel from '../common/SelectWithLabel';
+import useController from './useController';
+import type { SelectOptionType } from '../common/type';
+import type { ControllerProps, ValuesResponseType, ValuesRequestParamsType } from './type';
+
+const Controller: React.FC = (props: ControllerProps) => {
+ const { metrics } = props;
+ const useControllerInstance = useController();
+ const { metric, stat, dimension, dimensionValue, heatMapType, setContextState } = useGlobalStore(
+ useShallow((state) => ({
+ metric: state.metric,
+ stat: state.stat,
+ dimension: state.dimension,
+ dimensionValue: state.dimensionValue,
+ heatMapType: state.heatMapType,
+ setContextState: state.setContextState,
+ })),
+ shallow,
+ );
+ const [metricsMapStats, setMetricsMapStats] = useState>>({});
+ const [metricsNameList, setMetricsNameList] = useState([]);
+ const [statNameList, setStatNameList] = useState([]);
+ const [dimensionValueList, setDimensionValueList] = useState();
+
+ useEffect(() => {
+ if (metrics) {
+ const metricsMapStats: Record> = {};
+ const metricsNameList: Array = [];
+ metrics.forEach(({ name, stats }) => {
+ metricsMapStats[name] = stats.map((stat) => {
+ return {
+ label: stat,
+ value: stat,
+ };
+ });
+ metricsNameList.push({ label: name, value: name });
+ });
+
+ const selecrMetric = metricsNameList?.[0]?.value;
+ const statNameList: Array = metricsMapStats[selecrMetric];
+ const selectedStat = statNameList?.[0]?.value;
+ setMetricsMapStats(metricsMapStats);
+ // 初始化指标
+ setMetricsNameList(metricsNameList);
+ // 初始化统计量
+ setStatNameList(statNameList);
+ setContextState({ metric: selecrMetric, stat: selectedStat });
+ // 初始化维度,默认选中step维度
+ const params: ValuesRequestParamsType = {
+ metric: selecrMetric,
+ stat: selectedStat,
+ dimension: DIMENSIONS_OPTIONS[0].value,
+ value: 0,
+ };
+ updateDimensionValueList(params);
+ }
+ }, [metrics]);
+
+ useEffect(() => {
+ if (!metric || !stat || !dimension || !dimensionValue) {
+ return;
+ }
+ const params = {
+ metric,
+ stat,
+ dimension,
+ value: dimensionValue,
+ };
+ const loadGraphData = async (params) => {
+ setContextState({ loadingHeatMap: true });
+ const result = await useControllerInstance.loadGraphData(params);
+ setContextState({ loadingHeatMap: false });
+ if (result.error) {
+ message.error(result?.error);
+ return;
+ }
+ setContextState({
+ heatMaphData: result?.data,
+ trendData: { dimensions: [], values: [] },
+ dimX: ' ',
+ dimY: ' ',
+ });
+ };
+ loadGraphData(params);
+ }, [metric, stat, dimension, dimensionValue]);
+
+ const updateDimensionValueList = async (params: ValuesRequestParamsType) => {
+ const result: ValuesResponseType = await useControllerInstance.loadDimensionValueList(params);
+ if (result.error) {
+ message.error(result.error);
+ return;
+ }
+ if (!isEmpty(result)) {
+ const dimensionValueList = Object.entries(result?.data || {}).map(([key, value]) => {
+ return {
+ value: key,
+ label: value,
+ };
+ });
+ setContextState({
+ dimension: params.dimension,
+ dimensionValue: dimensionValueList?.[0]?.value,
+ });
+ setDimensionValueList(dimensionValueList);
+ }
+ };
+
+ // 指标选择
+ const onSelectMetricChange = (value: string) => {
+ const statNameList = metricsMapStats[value];
+ const selectedStat = statNameList?.[0]?.value;
+ setContextState({ metric: value, stat: selectedStat });
+ setStatNameList(statNameList);
+ };
+
+ // 统计量选择
+ const onSelectStatChange = (value: string) => {
+ setContextState({ stat: value });
+ };
+
+ // 维度选择
+ const onSelectDimensionChange = (value: string) => {
+ const params: ValuesRequestParamsType = {
+ metric,
+ stat,
+ dimension: value,
+ value: 0,
+ } as ValuesRequestParamsType;
+ updateDimensionValueList(params);
+ };
+ // 维度值选择
+ const onSelectDimensionValueChange = (value: string) => {
+ setContextState({ dimensionValue: value });
+ };
+
+ return (
+
+
设置
+
+
+
+
+
+
+ setContextState({
+ heatMapType: value,
+ })
+ }
+ options={HEATMAP_TYPE}
+ />
+
+
+ );
+};
+
+export default memo(Controller);
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/type/index.d.ts b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/type/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4d396a0bd142596cd4930555b633d07e234387ad
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/type/index.d.ts
@@ -0,0 +1,39 @@
+/* -------------------------------------------------------------------------
+ Copyright (c) 2025, Huawei Technologies.
+ All rights reserved.
+
+ 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.
+--------------------------------------------------------------------------------------------*/
+
+export interface ControllerProps {
+ metrics: Array;
+}
+
+export interface ValuesResponseType {
+ data?: {
+ [string]: string;
+ };
+ error?: string;
+}
+
+export interface HeatmapDataResponseType {
+ data?: Array;
+ error?: string;
+}
+
+export interface ValuesRequestParamsType {
+ metric: string;
+ stat: string;
+ dimension: string;
+ value: number;
+}
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/useController.ts b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/useController.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c2ff9d1f32ae41f327ad27ebd7ffac45e1475475
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/controller/useController.ts
@@ -0,0 +1,59 @@
+/* -------------------------------------------------------------------------
+ Copyright (c) 2025, Huawei Technologies.
+ All rights reserved.
+
+ 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 request from '../utils/request';
+import { ValuesResponseType, ValuesRequestParamsType, HeatmapDataResponseType } from './type';
+
+const useController = () => {
+ const loadGraphData = async (params: ValuesRequestParamsType) => {
+ try {
+ const result = await request({
+ url: 'heatmap_data',
+ method: 'GET',
+ params,
+ }) as unknown as HeatmapDataResponseType;
+ return result;
+ } catch (error) {
+ return {
+ error: '网络异常:获取维度值列表失败',
+ };
+ }
+ };
+ const loadDimensionValueList = async (params: ValuesRequestParamsType) => {
+ if (!params.dimension || !params.metric || !params.stat) {
+ return {};
+ }
+ try {
+ const result: ValuesResponseType = (await request({
+ url: 'values',
+ method: 'GET',
+ params,
+ })) as unknown as ValuesResponseType;
+ return result;
+ } catch (error) {
+ return {
+ error: '网络异常:获取维度值列表失败',
+ };
+ }
+ };
+ return {
+ loadGraphData,
+ loadDimensionValueList,
+ };
+};
+
+export default useController;
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/index.tsx b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/index.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..e7b152719b9137b34bfda8670660716bb256e9e5
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/index.tsx
@@ -0,0 +1,26 @@
+/* -------------------------------------------------------------------------
+ Copyright (c) 2025, Huawei Technologies.
+ All rights reserved.
+
+ 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 React from 'react';
+import ReactDOM from 'react-dom/client';
+import MonVis from './main';
+
+const rootElement = document.getElementById('root');
+if (rootElement) {
+ const root = ReactDOM.createRoot(rootElement);
+ root.render();
+}
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/store/index.ts b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/store/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..79b5345c0732045975a3ccdbedf1cdd57bdfc364
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/store/index.ts
@@ -0,0 +1,39 @@
+/* -------------------------------------------------------------------------
+ Copyright (c) 2025, Huawei Technologies.
+ All rights reserved.
+
+ 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 { createWithEqualityFn } from 'zustand/traditional';
+import { CONTINUOUS } from '../common/constant';
+import type { ContextStateType } from '../common/type';
+
+// 使用createWithEqualityFn而不是create
+export const useGlobalStore = createWithEqualityFn(
+ (set) => ({
+ heatMaphData: [],
+ trendData: { dimensions: [], values: [] },
+ metric: '',
+ stat: '',
+ dimension: '',
+ dimensionValue: '',
+ heatMapType: CONTINUOUS,
+ dimX: '',
+ dimY: '',
+ loadingHeatMap: false,
+ loadingLineChart: false,
+ setContextState: (newState) => set((state) => ({ ...state, ...newState })),
+ }),
+ Object.is, // 指定默认的相等性函数,可以是浅层比较
+);
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/utils/index.ts b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/utils/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d899bc2456624d58fc7f3e24364e2831f2c41ff1
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/utils/index.ts
@@ -0,0 +1,27 @@
+/* -------------------------------------------------------------------------
+ Copyright (c) 2025, Huawei Technologies.
+ All rights reserved.
+
+ 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.
+--------------------------------------------------------------------------------------------*/
+export const formatSegmentLabel = (min, max) => {
+ const format = (value) => {
+ if (value === Infinity) return '∞';
+ if (value === -Infinity) return '-∞';
+ return value.toExponential(2);
+ };
+
+ if (min === -Infinity) return `< ${format(max)}`;
+ if (max === Infinity) return `> ${format(min)}`;
+ return `${format(min)} ~ ${format(max)}`;
+};
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/utils/request.ts b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/utils/request.ts
new file mode 100644
index 0000000000000000000000000000000000000000..84c23efb6d96aa88883dec5570062d93ccdfd3a3
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/src/utils/request.ts
@@ -0,0 +1,91 @@
+/* Copyright (c) 2025, Huawei Technologies.
+ * All rights reserved.
+ *
+ * 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 axios, { AxiosResponse, AxiosError } from 'axios';
+interface RequestOptions {
+ url: string; // 请求地址
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; // 请求方法,默认为 GET
+ data?: any; // 请求体数据(适用于 POST、PUT)
+ params?: any; // URL 参数(适用于 GET)
+ headers?: Record; // 自定义请求头
+ timeout?: number; // 超时时间(毫秒),默认 10 秒
+}
+interface ApiResponse {
+ success: boolean; // 是否成功
+ data?: T; // 响应数据
+ error?: string; // 错误信息
+}
+export default async function request(options: RequestOptions): Promise> {
+ const { url, method = 'GET', data = null, params = null, headers = {}, timeout = 60000 * 3 } = options;
+
+ try {
+ const controller = new AbortController();
+ const signal = controller.signal;
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
+ const response: AxiosResponse = await axios({
+ url,
+ method,
+ data,
+ params,
+ headers: {
+ 'Content-Type': 'application/json', // 默认 Content-Type
+ ...headers, // 自定义请求头覆盖默认值
+ },
+ maxBodyLength: Infinity, // 允许发送大文件
+ signal, // 绑定信号以支持超时
+ });
+
+ clearTimeout(timeoutId);
+ if (response.status >= 200 && response.status < 300) {
+ return response.data as ApiResponse;
+ } else {
+ return {
+ success: false,
+ error: `HTTP Error: ${response.status} - ${response.statusText}`,
+ };
+ }
+ } catch (error) {
+ if (axios.isAxiosError(error)) {
+ const axiosError = error as AxiosError;
+ if (axiosError.code === 'ECONNABORTED') {
+ return {
+ success: false,
+ error: '请求超时,请稍后重试。',
+ };
+ } else if (axiosError.response) {
+ const { status, statusText } = axiosError.response;
+ return {
+ success: false,
+ error: `HTTP Error: ${status} - ${statusText}`,
+ };
+ } else if (axiosError.request) {
+ return {
+ success: false,
+ error: '网络错误,未收到服务器响应。',
+ };
+ } else {
+ return {
+ success: false,
+ error: axiosError.message || '未知错误',
+ };
+ }
+ } else {
+ return {
+ success: false,
+ error: (error as Error).message || '未知错误',
+ };
+ }
+ }
+}
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/tsconfig.json b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..15fb526ae25d57334e4719f957c99682989b3240
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/tsconfig.json
@@ -0,0 +1,40 @@
+/* -------------------------------------------------------------------------
+ Copyright (c) 2025, Huawei Technologies.
+ All rights reserved.
+
+ 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.
+--------------------------------------------------------------------------------------------*/
+{
+ "compilerOptions": {
+ "jsx": "react",
+ "downlevelIteration": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "importHelpers": true,
+ "inlineSourceMap": true,
+ "lib": [
+ "dom",
+ "ES2022",
+ "dom.iterable"
+ ],
+ "moduleResolution": "node",
+ "module": "ES2022",
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitReturns": true,
+ "noImplicitOverride": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noImplicitAny": false,
+ "target": "es2018"
+ }
+}
\ No newline at end of file
diff --git a/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/webpack.config.js b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/webpack.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..e52a714e3b4c1c07ba668d738f2dbea423d9025c
--- /dev/null
+++ b/plugins/tensorboard-plugins/tb_graph_ascend/monvis_plugin/fe/webpack.config.js
@@ -0,0 +1,81 @@
+/* -------------------------------------------------------------------------
+ Copyright (c) 2025, Huawei Technologies.
+ All rights reserved.
+
+ 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.
+--------------------------------------------------------------------------------------------*/
+
+const path = require('path');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const { CleanWebpackPlugin } = require('clean-webpack-plugin');
+const InlineChunkHtmlPlugin = require('inline-chunk-html-plugin');
+
+module.exports = {
+ entry: {
+ app: './src/index.tsx',
+ },
+ output: {
+ filename: 'index.js',
+ path: path.resolve(__dirname, 'dist'),
+ },
+ module: {
+ rules: [
+ {
+ test: /\.(html)$/,
+ use: {
+ loader: 'html-loader',
+ },
+ },
+ {
+ test: /\.tsx?$/,
+ use: {
+ loader: 'ts-loader',
+ options: {
+ transpileOnly: true,
+ },
+ },
+ exclude: /node_modules/,
+ },
+ {
+ test: /\.css$/i,
+ use: ['style-loader', 'css-loader'],
+ },
+ {
+ test: /\.less$/i,
+ use: [
+ 'style-loader', // 将 JS 字符串生成为