Browse Source

feat: 模型演化避免重叠

pull/62/head
cp3hnu 1 year ago
parent
commit
cf23d61a0d
9 changed files with 405 additions and 308 deletions
  1. +4
    -4
      react-ui/src/components/ParameterSelect/config.tsx
  2. +1
    -1
      react-ui/src/hooks/sessionStorage.ts
  3. +22
    -22
      react-ui/src/pages/Dataset/config.tsx
  4. +4
    -4
      react-ui/src/pages/Model/components/GraphLegand/index.tsx
  5. +18
    -263
      react-ui/src/pages/Model/components/ModelEvolution/index.tsx
  6. +344
    -0
      react-ui/src/pages/Model/components/ModelEvolution/utils.tsx
  7. +1
    -1
      react-ui/src/pages/Model/components/NodeTooltips/index.tsx
  8. +10
    -10
      react-ui/src/pages/Pipeline/components/ResourceSelectorModal/config.tsx
  9. +1
    -3
      react-ui/src/pages/Pipeline/editPipeline/index.jsx

+ 4
- 4
react-ui/src/components/ParameterSelect/config.tsx View File

@@ -17,10 +17,10 @@ const filterResourceStandard: SelectProps<string, ComputingResource>['filterOpti
const convertId = (item: any) => ({ ...item, id: String(item.id) });

export type SelectPropsConfig = {
getOptions: () => Promise<any>;
fieldNames?: SelectProps['fieldNames'];
optionFilterProp?: SelectProps['optionFilterProp'];
filterOption?: SelectProps['filterOption'];
getOptions: () => Promise<any>; // 获取下拉数据
fieldNames?: SelectProps['fieldNames']; // 下拉数据字段
optionFilterProp?: SelectProps['optionFilterProp']; // 过滤字段名
filterOption?: SelectProps['filterOption']; // 过滤函数
};

export const paramSelectConfig: Record<string, SelectPropsConfig> = {


+ 1
- 1
react-ui/src/hooks/sessionStorage.ts View File

@@ -1,7 +1,7 @@
import { getSessionStorageItem, removeSessionStorageItem } from '@/utils/sessionStorage';
import { useEffect, useState } from 'react';

// 获取缓存数据
// 读取缓存数据,组件卸载时清除缓存
export function useSessionStorage<T>(key: string, isObject: boolean, initialValue: T) {
const [storage, setStorage] = useState<T>(initialValue);



+ 22
- 22
react-ui/src/pages/Dataset/config.tsx View File

@@ -24,32 +24,32 @@ export enum ResourceType {
}

type ResourceTypeInfo = {
getList: (params: any) => Promise<any>;
getVersions: (params: any) => Promise<any>;
getFiles: (params: any) => Promise<any>;
deleteRecord: (params: any) => Promise<any>;
addVersion: (params: any) => Promise<any>;
deleteVersion: (params: any) => Promise<any>;
getInfo: (params: any) => Promise<any>;
name: string;
typeParamKey: string;
tagParamKey: string;
fileReqParamKey: 'models_id' | 'dataset_id';
tabItems: TabsProps['items'];
typeTitle: string;
tagTitle: string;
getList: (params: any) => Promise<any>; // 获取资源列表
getVersions: (params: any) => Promise<any>; // 获取版本列表
getFiles: (params: any) => Promise<any>; // 获取版本下的文件列表
deleteRecord: (params: any) => Promise<any>; // 删除
addVersion: (params: any) => Promise<any>; // 新增版本
deleteVersion: (params: any) => Promise<any>; // 删除版本
getInfo: (params: any) => Promise<any>; // 获取详情
name: string; // 名称
typeParamKey: string; // 类型参数名称,获取资源列表接口使用
tagParamKey: string; // 标签参数名称,获取资源列表接口使用
fileReqParamKey: 'models_id' | 'dataset_id'; // 文件请求参数名称,获取文件列表接口使用
tabItems: TabsProps['items']; // tab 列表
typeTitle: string; // 类型标题
tagTitle: string; // 标签标题
typeValue: number; // 从 getAssetIcon 接口获取特定值的数据为 type 分类 (category_id === typeValue)
tagValue: number; // 从 getAssetIcon 接口获取特定值的数据为 tag 分类(category_id === tagValue)
prefix: string; // 前缀
prefix: string; // 图片资源、详情 url 的前缀
deleteModalTitle: string; // 删除弹框的title
addBtnTitle: string; // 新增按钮的title
idParamKey: 'models_id' | 'dataset_id';
uploadAction: string;
uploadAccept?: string;
downloadAllAction: string;
downloadSingleAction: string;
infoTypePropertyName: string;
infoTagPropertyName: string;
idParamKey: 'models_id' | 'dataset_id'; // 新建版本、删除版本接口,版本 id 的参数名称
uploadAction: string; // 上传接口 url
uploadAccept?: string; // 上传文件类型
downloadAllAction: string; // 批量下载接口 url
downloadSingleAction: string; // 单个下载接口 url
infoTypePropertyName: string; // 详情数据中,类型属性名称
infoTagPropertyName: string; // 详情数据中,标签属性名称
};

export const resourceConfig: Record<ResourceType, ResourceTypeInfo> = {


+ 4
- 4
react-ui/src/pages/Model/components/GraphLegand/index.tsx View File

@@ -16,19 +16,19 @@ function GraphLegand({ style }: GraphLegandProps) {
const legends: GraphLegandData[] = [
{
name: '父模型',
color: '#76b1ff',
color: 'linear-gradient(305deg,#43c9b1 0%,#93dfd1 100%)',
radius: 2,
fill: true,
},
{
name: '当前模型',
color: '#1664ff',
color: 'linear-gradient(139.97deg,#72a1ff 0%,#1664ff 100%)',
radius: 2,
fill: true,
},
{
name: '衍生模型',
color: '#b7cfff',
color: 'linear-gradient(139.97deg,#72b4ff 0%,#169aff 100%)',
radius: 2,
fill: true,
},
@@ -42,7 +42,7 @@ function GraphLegand({ style }: GraphLegandProps) {
width: '16px',
height: '12px',
borderRadius: item.radius,
backgroundColor: item.color,
background: item.color,
}}
></div>
<div className={styles['graph-legend__item__name']}>{item.name}</div>


+ 18
- 263
react-ui/src/pages/Model/components/ModelEvolution/index.tsx View File

@@ -2,264 +2,16 @@ import { useEffectWhen } from '@/hooks';
import { ResourceVersionData } from '@/pages/Dataset/config';
import { getModelAtlasReq } from '@/services/dataset/index.js';
import themes from '@/styles/theme.less';
import { changePropertyName, fittingString } from '@/utils';
import { to } from '@/utils/promise';
import G6, {
EdgeConfig,
G6GraphEvent,
Graph,
GraphData,
LayoutConfig,
NodeConfig,
TreeGraphData,
Util,
} from '@antv/g6';
import G6, { G6GraphEvent, Graph, Item } from '@antv/g6';
// @ts-ignore
import Hierarchy from '@antv/hierarchy';
import { Flex, Select } from 'antd';
import { useEffect, useRef, useState } from 'react';
import GraphLegand from '../GraphLegand';
import NodeTooltips from '../NodeTooltips';
import styles from './index.less';

const nodeWidth = 98;
const nodeHeight = 58;
const vGap = 58;
const hGap = 58;

enum NodeType {
current = 'current',
parent = 'parent',
children = 'children',
project = 'project',
trainDataset = 'trainDataset',
testDataset = 'testDataset',
}

type TrainTask = {
ins_id: number;
name: string;
task_id: string;
};

interface TrainDataset extends NodeConfig {
dataset_id: number;
dataset_name: string;
dataset_version: string;
model_type: NodeType;
}

interface ProjectDependency extends NodeConfig {
url: string;
name: string;
branch: string;
model_type: NodeType;
}

type ModalDetail = {
name: string;
available_range: number;
file_name: string;
file_size: string;
description: string;
model_type_name: string;
model_tag_name: string;
create_time: string;
};

interface ModelDepsAPIData {
current_model_id: number;
version: string;
exp_ins_id: number;
model_type: NodeType;
current_model_name: string;
project_dependency: ProjectDependency;
test_dataset: TrainDataset[];
train_dataset: TrainDataset[];
train_task: TrainTask;
model_version_dependcy_vo: ModalDetail;
children_models: ModelDepsAPIData[];
parent_models: ModelDepsAPIData[];
}

export interface ModelDepsData extends Omit<ModelDepsAPIData, 'children_models'>, TreeGraphData {
children: ModelDepsData[];
}

// 规范化子数据
function normalizeChildren(data: ModelDepsData[]) {
if (Array.isArray(data)) {
data.forEach((item) => {
item.model_type = NodeType.children;
item.id = `$M_${item.current_model_id}_${item.version}`;
item.label = getLabel(item);
item.style = getStyle(NodeType.children);
normalizeChildren(item.children);
});
}
}

// 获取 label
function getLabel(node: { current_model_name: string; version: string }) {
return (
fittingString(`${node.current_model_name}`, 87, 8) +
'\n' +
fittingString(`${node.version}`, 87, 8)
);
}

// 获取 style
function getStyle(model_type: NodeType) {
let fill = '';
switch (model_type) {
case NodeType.current:
fill = '#1664ff';
break;
case NodeType.parent:
fill = '#76b1ff';
break;
case NodeType.children:
fill = '#b7cfff';
break;
case NodeType.project:
fill = '#FA8C16';
break;
case NodeType.trainDataset:
fill = '#ff0000';
break;
case NodeType.testDataset:
fill = '#ff00ff';
break;
default:
break;
}
return {
fill,
};
}

// 将后台返回的数据转换成树形数据
function normalizeTreeData(apiData: ModelDepsAPIData, currentNodeName: string): ModelDepsData {
// 将 children_models 转换成 children
let normalizedData = changePropertyName(apiData, {
children_models: 'children',
}) as ModelDepsData;

// 设置当前模型的数据
normalizedData.model_type = NodeType.current;
normalizedData.current_model_name = currentNodeName;
normalizedData.id = `$M_${normalizedData.current_model_id}_${normalizedData.version}`;
normalizedData.label = getLabel(normalizedData);
normalizedData.style = getStyle(NodeType.current);

normalizeChildren(normalizedData.children as ModelDepsData[]);

// 将 parent_models 转换成树形结构
let parent_models = normalizedData.parent_models || [];
while (parent_models.length > 0) {
const parent = parent_models[0];
normalizedData = {
...parent,
model_type: NodeType.parent,
id: `$M_${parent.current_model_id}_${parent.version}`,
label: getLabel(parent),
style: getStyle(NodeType.parent),
children: [
{
...normalizedData,
parent_models: [],
},
],
};
parent_models = normalizedData.parent_models || [];
}
return normalizedData;
}

// 将树形数据,使用 Hierarchy 进行布局,计算出坐标,然后转换成 G6 的数据
function getGraphData(data: ModelDepsData): GraphData {
const config = {
direction: 'LR',
getHeight: () => nodeHeight,
getWidth: () => nodeWidth,
getVGap: () => vGap / 2,
getHGap: () => hGap / 2,
};

// 树形布局计算出坐标
const treeLayoutData: LayoutConfig = Hierarchy['compactBox'](data, config);

const nodes: NodeConfig[] = [];
const edges: EdgeConfig[] = [];
Util.traverseTree(treeLayoutData, (node: NodeConfig, parent: NodeConfig) => {
const data = node.data as ModelDepsData;
nodes.push({
...data,
x: node.x,
y: node.y,
});
if (parent) {
edges.push({
source: parent.id,
target: node.id,
});
}

// 当前模型显示数据集和项目
if (data.model_type === NodeType.current) {
const { project_dependency, train_dataset, test_dataset } = data;
train_dataset.forEach((item) => {
item.id = `$DTrain_${item.dataset_id}`;
item.model_type = NodeType.trainDataset;
item.type = 'ellipse';
item.label = fittingString(`${item.dataset_name}`, 87, 8);
item.style = getStyle(NodeType.trainDataset);
});
test_dataset.forEach((item) => {
item.id = `$DTest_${item.dataset_id}`;
item.model_type = NodeType.testDataset;
item.type = 'ellipse';
item.label = fittingString(item.dataset_name, 87, 8);
item.style = getStyle(NodeType.testDataset);
});

const len = train_dataset.length + test_dataset.length;
[...train_dataset, ...test_dataset].forEach((item, index) => {
const half = len / 2 - 0.5;
item.x = node.x! - (half - index) * (nodeWidth + hGap);
item.y = node.y! - nodeHeight - vGap;
nodes.push(item);
edges.push({
source: node.id,
target: item.id,
sourceAnchor: 2,
targetAnchor: 3,
type: 'cubic-vertical',
});
});

if (project_dependency?.url) {
project_dependency.id = `$P_${project_dependency.url}`;
project_dependency.model_type = NodeType.project;
project_dependency.type = 'rect';
project_dependency.size = [nodeHeight, nodeHeight];
project_dependency.label = fittingString(project_dependency.name, 48, 8);
project_dependency.style = getStyle(NodeType.project);
project_dependency.x = node.x;
project_dependency.y = node.y! + nodeHeight + vGap;
nodes.push(project_dependency);
edges.push({
source: node.id,
target: project_dependency.id,
sourceAnchor: 3,
targetAnchor: 2,
type: 'cubic-vertical',
});
}
}
});
return { nodes, edges };
}
import type { ModelDepsData, ProjectDependency, TrainDataset } from './utils';
import { NodeType, getGraphData, nodeHeight, nodeWidth, normalizeTreeData } from './utils';

type modeModelEvolutionProps = {
resourceId: number;
@@ -361,14 +113,15 @@ function ModelEvolution({
default: [
'drag-canvas',
'zoom-canvas',
// {
// type: 'collapse-expand',
// onChange(item?: Item, collapsed?: boolean) {
// const data = item!.getModel();
// data.collapsed = collapsed;
// return true;
// },
// },
'drag-node',
{
type: 'collapse-expand',
onChange(item?: Item, collapsed?: boolean) {
const data = item!.getModel();
data.collapsed = collapsed;
return true;
},
},
],
},
});
@@ -392,16 +145,18 @@ function ModelEvolution({
return;
}
const point = graph.getCanvasByPoint(x!, y!);
const zoom = graph.getZoom();
// 更加缩放,调整 tooltip 位置
const offsetX = (nodeWidth * zoom) / 4;
const offsetY = (nodeHeight * zoom) / 4;

const canvasWidth = graphRef.current!.clientWidth;
if (point.x + 300 > canvasWidth) {
point.x = canvasWidth - 300;
}
const zoom = graph.getZoom();
// 更加缩放,调整 tooltip 位置
const offsetY = (nodeHeight * zoom) / 4;

setHoverNodeData(model);
setNodeToolTipX(point.x);
setNodeToolTipX(point.x + offsetX);
// 92: 版本选择器的高度,296: tooltip的高度
setNodeToolTipY(point.y + 92 - 296 - offsetY);
setShowNodeTooltip(true);


+ 344
- 0
react-ui/src/pages/Model/components/ModelEvolution/utils.tsx View File

@@ -0,0 +1,344 @@
import { changePropertyName, fittingString } from '@/utils';
import { EdgeConfig, GraphData, LayoutConfig, NodeConfig, TreeGraphData, Util } from '@antv/g6';
// @ts-ignore
import Hierarchy from '@antv/hierarchy';

export const nodeWidth = 110;
export const nodeHeight = 50;
export const vGap = nodeHeight + 20;
export const hGap = nodeHeight + 20;
export const ellipseWidth = nodeWidth;

// 数据集节点矩形数组
const datasetRects: Rect[] = [];

export enum NodeType {
current = 'current',
parent = 'parent',
children = 'children',
project = 'project',
trainDataset = 'trainDataset',
testDataset = 'testDataset',
}

export type Rect = {
x: number;
y: number;
width: number;
height: number;
};

export type TrainTask = {
ins_id: number;
name: string;
task_id: string;
};

export interface TrainDataset extends NodeConfig {
dataset_id: number;
dataset_name: string;
dataset_version: string;
model_type: NodeType;
}

export interface ProjectDependency extends NodeConfig {
url: string;
name: string;
branch: string;
model_type: NodeType;
}

export type ModalDetail = {
name: string;
available_range: number;
file_name: string;
file_size: string;
description: string;
model_type_name: string;
model_tag_name: string;
create_time: string;
};

export interface ModelDepsAPIData {
current_model_id: number;
version: string;
exp_ins_id: number;
model_type: NodeType;
current_model_name: string;
project_dependency: ProjectDependency;
test_dataset: TrainDataset[];
train_dataset: TrainDataset[];
train_task: TrainTask;
model_version_dependcy_vo: ModalDetail;
children_models: ModelDepsAPIData[];
parent_models: ModelDepsAPIData[];
}

export interface ModelDepsData extends Omit<ModelDepsAPIData, 'children_models'>, TreeGraphData {
children: ModelDepsData[];
}

// 规范化子数据
export function normalizeChildren(data: ModelDepsData[]) {
if (Array.isArray(data)) {
data.forEach((item) => {
item.model_type = NodeType.children;
item.id = `$M_${item.current_model_id}_${item.version}`;
item.label = getLabel(item);
item.style = getStyle(NodeType.children);
normalizeChildren(item.children);
});
}
}

// 获取 label
export function getLabel(node: { current_model_name: string; version: string }) {
return (
fittingString(`${node.current_model_name}`, nodeWidth - 12, 8) +
'\n' +
fittingString(`${node.version}`, nodeWidth - 12, 8)
);
}

// 获取 style
export function getStyle(model_type: NodeType) {
let fill = '';
switch (model_type) {
case NodeType.current:
fill = 'l(0) 0:#72a1ff 1:#1664ff';
break;
case NodeType.parent:
fill = 'l(0) 0:#93dfd1 1:#43c9b1';
break;
case NodeType.children:
fill = 'l(0) 0:#72b4ff 1:#169aff';
break;
case NodeType.project:
fill = 'l(0) 0:#b3a9ff 1:#8981ff';
break;
case NodeType.trainDataset:
fill = '#a5d878';
break;
case NodeType.testDataset:
fill = '#d8b578';
break;
default:
break;
}
return {
fill,
};
}

// 将后台返回的数据转换成树形数据
export function normalizeTreeData(
apiData: ModelDepsAPIData,
currentNodeName: string,
): ModelDepsData {
// 将 children_models 转换成 children
let normalizedData = changePropertyName(apiData, {
children_models: 'children',
}) as ModelDepsData;

// 设置当前模型的数据
normalizedData.model_type = NodeType.current;
normalizedData.current_model_name = currentNodeName;
normalizedData.id = `$M_${normalizedData.current_model_id}_${normalizedData.version}`;
normalizedData.label = getLabel({
current_model_name: currentNodeName,
version: normalizedData.version,
});
normalizedData.style = getStyle(NodeType.current);
// let first1 = { ...normalizedData.children[0] };
// let first2 = { ...normalizedData.children[0] };
// let first3 = { ...normalizedData.children[0] };
// first1.current_model_id = 202020;
// first2.current_model_id = 202021;
// first3.current_model_id = 202022;
// normalizedData.children.push(first1, first2, first3);

normalizeChildren(normalizedData.children as ModelDepsData[]);

// 将 parent_models 转换成树形结构
let parent_models = normalizedData.parent_models || [];
while (parent_models.length > 0) {
const parent = parent_models[0];
normalizedData = {
...parent,
model_type: NodeType.parent,
id: `$M_${parent.current_model_id}_${parent.version}`,
label: getLabel(parent),
style: getStyle(NodeType.parent),
children: [
{
...normalizedData,
parent_models: [],
},
],
};
parent_models = normalizedData.parent_models || [];
}
return normalizedData;
}

// 将树形数据,使用 Hierarchy 进行布局,计算出坐标,然后转换成 G6 的数据
export function getGraphData(data: ModelDepsData): GraphData {
const config = {
direction: 'LR',
getHeight: () => nodeHeight,
getWidth: () => nodeWidth,
getVGap: () => vGap / 2,
getHGap: () => hGap / 2,
};

// 树形布局计算出坐标
const treeLayoutData: LayoutConfig = Hierarchy['compactBox'](data, config);

const nodes: NodeConfig[] = [];
const edges: EdgeConfig[] = [];
Util.traverseTree(treeLayoutData, (node: NodeConfig, parent: NodeConfig) => {
const data = node.data as ModelDepsData;
console.log('data', data);

// 当前模型显示数据集和项目
if (data.model_type === NodeType.current) {
addDatasetDependency(data, node, nodes, edges);
addProjectDependency(data, node, nodes, edges);
} else if (data.model_type === NodeType.children) {
adjustChildrenPosition(node);
}
nodes.push({
...data,
x: node.x,
y: node.y,
});
if (parent) {
edges.push({
source: parent.id,
target: node.id,
});
}
});
return { nodes, edges };
}

// 将数据集转换成 G6 的数据
const addDatasetDependency = (
data: ModelDepsData,
currentNode: NodeConfig,
nodes: NodeConfig[],
edges: EdgeConfig[],
) => {
const { train_dataset, test_dataset } = data;
train_dataset.forEach((item) => {
item.id = `$DTrain_${item.dataset_id}`;
item.model_type = NodeType.trainDataset;
item.style = getStyle(NodeType.trainDataset);
});
test_dataset.forEach((item) => {
item.id = `$DTest_${item.dataset_id}`;
item.model_type = NodeType.testDataset;
item.style = getStyle(NodeType.testDataset);
});

datasetRects.length = 0;
const len = train_dataset.length + test_dataset.length;
[...train_dataset, ...test_dataset].forEach((item, index) => {
const node = { ...item };
node.type = 'ellipse';
node.size = [ellipseWidth, nodeHeight];
node.label =
fittingString(node.dataset_name, ellipseWidth - 12, 8) +
'\n' +
fittingString(node.dataset_version, ellipseWidth - 12, 8);

const half = len / 2 - 0.5;
node.x = currentNode.x! - (half - index) * (ellipseWidth + hGap);
node.y = currentNode.y! - nodeHeight - vGap;
nodes.push(node);
edges.push({
source: currentNode.id,
target: node.id,
sourceAnchor: 2,
targetAnchor: 3,
type: 'cubic-vertical',
});
datasetRects.push({
x: node.x - ellipseWidth / 2,
y: node.y - nodeHeight / 2,
width: ellipseWidth,
height: nodeHeight,
});
});
};

// 将模型依赖数据转换成 G6 的数据
const addProjectDependency = (
data: ModelDepsData,
currentNode: NodeConfig,
nodes: NodeConfig[],
edges: EdgeConfig[],
) => {
const { project_dependency } = data;
if (project_dependency?.url) {
const node = { ...project_dependency };
node.id = `$P_${node.url}`;
node.model_type = NodeType.project;
node.type = 'rect';
node.label = fittingString(node.name, nodeWidth - 12, 8);
node.style = getStyle(NodeType.project);
node.style.radius = nodeHeight / 2;
node.x = currentNode.x;
node.y = currentNode.y! + nodeHeight + vGap;

nodes.push(node);
edges.push({
source: currentNode.id,
target: node.id,
sourceAnchor: 3,
targetAnchor: 2,
type: 'cubic-vertical',
});
}
};

// 判断两个矩形是否相交
function isRectanglesIntersect(rect1: Rect, rect2: Rect) {
return !(
rect1.x + rect1.width < rect2.x ||
rect1.x > rect2.x + rect2.width ||
rect1.y + rect1.height < rect2.y ||
rect1.y > rect2.y + rect2.height
);
}

// 判断子节点是否与数据集节点重叠
function isChildrenIntersectDataset(rects: Rect[], childrenRect: Rect) {
for (const r of rects) {
if (isRectanglesIntersect(r, childrenRect)) {
return r;
}
}

return null;
}

// 计算子节点位置
function adjustChildrenPosition(node: NodeConfig) {
const nodeRect = {
x: node.x! - nodeWidth / 2,
y: node.y! - nodeHeight / 2,
width: nodeWidth,
height: nodeHeight,
};
const overlapRect = isChildrenIntersectDataset(datasetRects, nodeRect);
if (overlapRect) {
const offsetY = nodeRect.y - overlapRect.y;
const space = 10; //(vGap + Math.abs(offsetY) - nodeHeight) / 2;
if (offsetY >= 0) {
node.y = node.y! + (nodeHeight - offsetY + space);
} else {
node.y = node.y! - (nodeHeight - Math.abs(offsetY) + space);
}
}
}

+ 1
- 1
react-ui/src/pages/Model/components/NodeTooltips/index.tsx View File

@@ -1,5 +1,5 @@
import { formatDate } from '@/utils/date';
import { ModelDepsData } from '../ModelEvolution';
import { ModelDepsData } from '../ModelEvolution/utils';
import styles from './index.less';

type NodeTooltipsProps = {


+ 10
- 10
react-ui/src/pages/Pipeline/components/ResourceSelectorModal/config.tsx View File

@@ -27,16 +27,16 @@ export type MirrorVersion = {
};

export type SelectorTypeInfo = {
getList: (params: any) => Promise<any>;
getVersions: (params: any) => Promise<any>;
getFiles: (params: any) => Promise<any>;
handleVersionResponse: (res: any) => any[];
modalIcon: string;
buttonIcon: string;
name: string;
litReqParamKey: 'available_range' | 'image_type';
fileReqParamKey: 'models_id' | 'dataset_id';
tabItems: TabsProps['items'];
getList: (params: any) => Promise<any>; // 获取资源列表
getVersions: (params: any) => Promise<any>; // 获取资源版本列表
getFiles: (params: any) => Promise<any>; // 获取资源文件列表
handleVersionResponse: (res: any) => any[]; // 处理版本列表接口数据
modalIcon: string; // modal icon
buttonIcon: string; // button icon
name: string; // 名称
litReqParamKey: 'available_range' | 'image_type'; // 表示是公开还是私有的参数名称,获取资源列表接口使用
fileReqParamKey: 'models_id' | 'dataset_id'; // 文件请求参数名称,获取文件列表接口使用
tabItems: TabsProps['items']; // tab 列表
};

// 获取镜像文件列表,为了兼容数据集和模型


+ 1
- 3
react-ui/src/pages/Pipeline/editPipeline/index.jsx View File

@@ -35,13 +35,11 @@ const EditPipeline = () => {
}, []);

const onDragEnd = (val) => {
console.log(val);
const _x = val.x;
const _y = val.y;
const point = graph.getPointByClient(_x, _y);
let model = {};
// 元模型
model = {
const model = {
...val,
x: point.x,
y: point.y,


Loading…
Cancel
Save