未验证 提交 73c30cdb 编写于 作者: N Niandalu 提交者: GitHub

feat: update graph page locale file & some code polishment (#573)

* feat: update graph page locale file & some code polishment

* feat: update graph page locale file & some code polishment

* fix: eslint violations

* fix: dedup
上级 e903e752
......@@ -29,6 +29,8 @@ module.exports = {
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn'
'react-hooks/exhaustive-deps': 'warn',
'@typescript-eslint/no-explicit-any': 'error',
'no-console': 'warn'
}
};
import React, {FunctionComponent} from 'react';
import {useTranslation} from '~/utils/i18n';
import {NodeType, TypedNode} from '~/resource/graph';
import styled from 'styled-components';
import {WithStyled} from '~/utils/style';
const typeName: {[k in NodeType]: string} = {
[NodeType.Input]: 'input',
......@@ -12,6 +14,27 @@ export interface NodeInfoProps {
node?: TypedNode | {type: 'unknown'; guessType: NodeType; msg: string};
}
const DataList: FunctionComponent<{items: {key: string; value: string | string[]}[]} & WithStyled> = props => {
return (
<ul className={props.className}>
{props.items.map(({key, value}) => (
<li key={key}>
{key}: {value}
</li>
))}
</ul>
);
};
const PropertyList = styled(DataList)`
padding: 0;
list-style: none;
color: #666;
li + li {
margin-top: 1em;
}
`;
const NodeInfo: FunctionComponent<NodeInfoProps> = props => {
const {t} = useTranslation(['graphs']);
if (!props.node) {
......@@ -23,46 +46,28 @@ const NodeInfo: FunctionComponent<NodeInfoProps> = props => {
case NodeType.Input:
case NodeType.Output:
return (
<ul>
<li>
{t('node-type')}: {typeName[node.type]}
</li>
<li>
{t('node-name')}: {node.name}
</li>
<li>
{t('node-data-shape')}: {node.shape}
</li>
<li>
{t('node-data-type')}: {node.data_type}
</li>
</ul>
<PropertyList
items={[
{key: t('node-type'), value: typeName[node.type]},
{key: t('node-name'), value: node.name},
{key: t('node-data-shape'), value: node.shape},
{key: t('node-data-tyep'), value: node.data_type}
]}
/>
);
case NodeType.Op:
return (
<ul>
<li>
{t('node-type')}: {typeName[node.type]}
</li>
<li>
{t('input')}: {node.input}
</li>
<li>
{t('op-type')}: {node.opType}
</li>
<li>
{t('output')}: {node.output}
</li>
</ul>
<PropertyList
items={[
{key: t('node-type'), value: typeName[node.type]},
{key: t('input'), value: node.input},
{key: t('op-type'), value: node.opType},
{key: t('output'), value: node.output}
]}
/>
);
case 'unknown':
return (
<ul>
<li>
{t('node-type')}: {typeName[node.guessType]}
</li>
</ul>
);
return <PropertyList items={[{key: t('node-type'), value: typeName[node.guessType]}]} />;
default:
return <></>;
}
......
......@@ -41,6 +41,41 @@ const GraphSvg = styled('svg')`
.node {
cursor: pointer;
.label-container {
stroke-width: 3px;
stroke: #e6e6e6;
&.rect {
rx: 10;
ry: 10;
}
}
&.operator {
.label-container {
fill: #cdd9da;
}
}
&.output {
.label-container {
stroke-dasharray: 5, 5;
stroke: #e6e6e6;
fill: #cad2d0;
}
}
&.input {
.label-container {
fill: #d5d3d8;
}
}
&.active {
.label-container {
stroke: #25c9ff;
}
}
}
.edgePath path.path {
......@@ -55,9 +90,9 @@ const MAX_SCALE = 4;
const useDag = (graph?: Graph) => {
const [displaySwitch, setDisplaySwitch] = useState({
detail: true,
input: true,
output: true
detail: false,
input: false,
output: false
});
const facts = useMemo(() => collectDagFacts(graph), [graph]);
......@@ -134,17 +169,23 @@ const useDagreD3 = (graph: Graph | undefined) => {
.on('end', () => svg.classed('grabbing', false));
svg.call(zoom);
let prevDom: HTMLElement | undefined;
// install event listeners
svg.selectAll('g.node').on('click', v => {
const uid = v as string;
const {type} = g.node(uid);
const dagNode = dagInfo.findNode(type, uid);
if (!dagNode) {
const {type, elem: dom} = g.node(uid);
if (prevDom) {
prevDom.classList.remove('active');
}
dom.classList.add('active');
prevDom = dom;
const node = dagInfo.findNode(type, uid);
if (!node) {
setCurrentNode({type: 'unknown', guessType: type, msg: uid});
return;
}
setCurrentNode({...dagNode, type});
setCurrentNode({...node, type});
});
const fitScreen = () => {
......@@ -209,21 +250,21 @@ const Graphs: NextI18NextPage<GraphsProps> = () => {
<section>
<SubSection>
<Button icon="download" onClick={downloadImage}>
{t('common:download-image')}
{t('download-image')}
</Button>
<Button icon="revert" onClick={fitScreen}>
{t('common:restore-image')}
{t('restore-image')}
</Button>
</SubSection>
<SubSection>
<Field label={`${t('common:scale')}:`}>
<Field label={`${t('scale')}:`}>
<RangeSlider min={MIN_SCALE} max={MAX_SCALE} step={0.1} value={scale} onChange={setScale} />
</Field>
</SubSection>
<SubSection>
<Field label={`${t('common:node-info')}:`}></Field>
<Field label={`${t('node-info')}:`}></Field>
<NodeInfo node={currentNode}></NodeInfo>
</SubSection>
</section>
......
......@@ -10,10 +10,6 @@
"select": "Please Select",
"runs": "Runs",
"select-runs": "Select Runs",
"scale": "Scale",
"download-image": "Download Image",
"restore-image": "Restore Image",
"node-info": "Node Info",
"running": "Running",
"stopped": "Stopped",
"loading": "Loading"
......
{
"scale": "Scale",
"download-image": "Download Image",
"restore-image": "Restore Image",
"node-info": "Node Info",
"node-type": "Node Type",
"node-name": "Node Name",
"node-data-shape": "Shape",
......@@ -6,5 +10,5 @@
"output": "Output",
"op-type": "Operator Type",
"node-data-type": "Data Type",
"click-node": "Click a node to display"
"click-node": "Click a node to view its detail"
}
{}
{
"scale": "比例",
"download-image": "下载图片",
"restore-image": "还原图片",
"node-info": "节点信息",
"node-type": "节点类型",
"node-name": "节点名称",
"node-data-shape": "数据类型",
"input": "输入",
"output": "输出",
"op-type": "算子类型",
"node-data-type": "数据类型",
"click-node": "点击左侧节点,查看节点信息"
}
import {Graph, Node, NodeUID, InputNode, NodeType} from './types';
import {OpNodeStyle, OutputNodeStyle, InputNodeStyle} from './style';
interface DagNode {
key: string;
......@@ -7,7 +6,6 @@ interface DagNode {
label: string;
shape: string;
class: string;
style: string;
}
type DagEdge = [string, string];
......@@ -124,8 +122,7 @@ const expandRelations = (nodeMapping: NodeRelationMapping) => {
label: bridge,
shape: 'diamond',
class: 'output',
type: NodeType.Output,
style: OutputNodeStyle
type: NodeType.Output
});
detailLayer.edges.push([inputTo, bridge]);
......@@ -158,8 +155,7 @@ type: ${inputNode.data_type}
dims: ${inputNode.shape.join(' × ')}
`,
shape: 'rect',
class: 'input',
style: InputNodeStyle
class: 'input'
});
relations.output.forEach(o => edges.push([inputNodeUID, o]));
......@@ -180,8 +176,7 @@ const extractOutputLayer = (nodeRelationMapping: NodeRelationMapping) => {
type: NodeType.Output,
label: nodeUID,
shape: 'diamond',
class: 'output',
style: OutputNodeStyle
class: 'output'
});
for (const inputNode of relations.input) {
......@@ -208,8 +203,7 @@ export const collectDagFacts = (graph?: Graph) => {
type: NodeType.Op,
label: n.opType,
shape: 'rect',
class: 'operator',
style: OpNodeStyle
class: 'operator'
}));
const {briefLayer: bl, detailLayer: dl} = expandRelations(nodeRelationMapping);
......
export const OpNodeStyle = `
stroke-width: 3px;
opacity: 0.1;
rx: 10;
ry: 10;
stroke: #333;
stroke-color: #41b3a3;
fill: #008c99;
`;
export const OutputNodeStyle = `
opacity: 0.1;
stroke-width: 3px;
stroke-dasharray: 5, 5;
stroke: #333;
stroke-color: #41b3a3;
fill: #015249;
`;
export const InputNodeStyle = `
opacity: 0.1;
stroke-width: 3px;
stroke: #333;
stroke-color: #41b3a3;
fill: #6c648b;
`;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册