diff --git a/app/components/ErrorBoundary/index.module.less b/app/components/ErrorBoundary/index.module.less index 413b6e58..f4c5cd95 100644 --- a/app/components/ErrorBoundary/index.module.less +++ b/app/components/ErrorBoundary/index.module.less @@ -1,9 +1,9 @@ .errPage { width: 100%; - height: 100%; + padding: 20px; + overflow: auto; display: flex; flex-direction: column; - justify-content: center; align-items: center; background-color: #fff; .errImg { diff --git a/app/components/ErrorBoundary/index.tsx b/app/components/ErrorBoundary/index.tsx index 21611e41..351d5096 100644 --- a/app/components/ErrorBoundary/index.tsx +++ b/app/components/ErrorBoundary/index.tsx @@ -17,9 +17,9 @@ class ErrorBoundary extends React.PureComponent { errInfo: null, }; } - componentDidCatch(_error, errorInfo) { + componentDidCatch(error) { this.setState({ - errInfo: errorInfo.componentStack, + errInfo: error?.stack?.toString(), }); } componentDidUpdate(prevProps: Readonly): void { diff --git a/app/config/locale/en-US.json b/app/config/locale/en-US.json index 1c0ef90a..a6173c85 100644 --- a/app/config/locale/en-US.json +++ b/app/config/locale/en-US.json @@ -56,7 +56,8 @@ "copySuccess": "Copied successfully", "sketch": "Schema drafting", "viewSchema": "View Schema", - "beta": "Beta" + "beta": "Beta", + "danglingEdge": "Dangling edge" }, "doc": { "welcome": "Welcome to", diff --git a/app/config/locale/zh-CN.json b/app/config/locale/zh-CN.json index e3d9ef97..f2fdf7d7 100644 --- a/app/config/locale/zh-CN.json +++ b/app/config/locale/zh-CN.json @@ -56,7 +56,8 @@ "copySuccess": "复制成功", "sketch": "Schema 草图", "viewSchema": "查看 Schema", - "beta": "Beta" + "beta": "Beta", + "danglingEdge": "悬挂边" }, "doc": { "welcome": "欢迎使用", diff --git a/app/pages/Schema/SchemaConfig/List/Edge/index.tsx b/app/pages/Schema/SchemaConfig/List/Edge/index.tsx index c7fcc115..87c6d667 100644 --- a/app/pages/Schema/SchemaConfig/List/Edge/index.tsx +++ b/app/pages/Schema/SchemaConfig/List/Edge/index.tsx @@ -96,7 +96,8 @@ const EdgeList = () => { { + onConfirm={(e) => { + e.stopPropagation(); handleDeleteEdge(edge.name); }} title={intl.get('common.ask')} diff --git a/app/pages/Schema/SchemaConfig/List/Index/index.tsx b/app/pages/Schema/SchemaConfig/List/Index/index.tsx index 3d9c314c..32d8d099 100644 --- a/app/pages/Schema/SchemaConfig/List/Index/index.tsx +++ b/app/pages/Schema/SchemaConfig/List/Index/index.tsx @@ -143,6 +143,7 @@ const IndexList = () => { { + e.stopPropagation(); handleDeleteIndex(e, indexType, index.name); }} title={intl.get('common.ask')} diff --git a/app/pages/Schema/SchemaConfig/List/SchemaVisualization/index.module.less b/app/pages/Schema/SchemaConfig/List/SchemaVisualization/index.module.less index 3b99304d..fecf3f06 100644 --- a/app/pages/Schema/SchemaConfig/List/SchemaVisualization/index.module.less +++ b/app/pages/Schema/SchemaConfig/List/SchemaVisualization/index.module.less @@ -19,6 +19,7 @@ white-space: nowrap; } .tip { + max-width: 600px; background: #DBEFFF; border-radius: 3px; padding: 13px; @@ -35,6 +36,9 @@ height: 700px; background-color: #fff; border: 1px solid #E0E0E0; + :global(.ve-link-points) { + display: none !important; + } } .visualizationTip { position: absolute; @@ -51,6 +55,10 @@ &:not(:last-child) { margin-bottom: 20px; } + & > span:nth-child(2) { + width: 55px; + font-size: 12px; + } } .circle { width: 30px; @@ -60,6 +68,13 @@ display: inline-block; border: 3px solid #626F81; } + .dashedCircle { + width: 28px; + height: 28px; + border-radius: 28px; + display: inline-block; + border: 3px dashed #626F81; + } .edge { display: inline-flex; align-items: center; @@ -70,6 +85,17 @@ height: 2px; background-color: #636F81; } + .danglingEdges { + display: inline-flex; + align-items: center; + } + .danglingLine { + display: inline-block; + width: 26px; + height: 2px; + background-color: #636F81; + margin-left: 2px; + } .arrow { width: 10px; height: 10px; diff --git a/app/pages/Schema/SchemaConfig/List/SchemaVisualization/index.tsx b/app/pages/Schema/SchemaConfig/List/SchemaVisualization/index.tsx index b4a9e0f3..676d3542 100644 --- a/app/pages/Schema/SchemaConfig/List/SchemaVisualization/index.tsx +++ b/app/pages/Schema/SchemaConfig/List/SchemaVisualization/index.tsx @@ -14,11 +14,24 @@ import ZoomBtns from '@app/pages/SketchModeling/ZoomBtns'; import { initTooltip } from '@app/pages/SketchModeling/Plugins/Tooltip'; import styles from './index.module.less'; +const NODE_CONFIG = { + width: NODE_RADIUS * 2, + height: NODE_RADIUS * 2, + type: ISchemaEnum.Tag, + hideActive: true, + x: Math.random() * 100, + y: Math.random() * 100, +}; +const DANLEING_NODE_CONFIG = { + strokeDasharray: '10 5', + strokeColor: 'rgba(60, 60, 60, 0.5)', + fill: 'transparent', +}; const SchemaVisualization = () => { const editorRef = useRef(); const { schema, sketchModel } = useStore(); const { initEditor } = sketchModel; - const { currentSpace, getSchemaSnapshot, tagList, getTagList, getEdgeList, getRandomEdgeData, getNodeTagMap, updateSchemaSnapshot } = schema; + const { currentSpace, getSchemaSnapshot, getTagList, getEdgeList, getRandomEdgeData, getNodeTagMap, updateSchemaSnapshot } = schema; const [updateTime, setUpdateTime] = useState(''); const [loading, setLoading] = useState(false); @@ -45,23 +58,19 @@ const SchemaVisualization = () => { return; } const { tags, vidMap } = await getNodeTagMap(vids); + const danglingEdges = []; const nodes = tags.map((tag, index) => { const color = COLOR_LIST[index % COLOR_LIST.length]; return { + ...NODE_CONFIG, name: tag, properties: schema.tagList.find(i => i.name === tag).fields.map(field => ({ name: field.Field, type: field.Type, })), uuid: uuidv4(), - width: NODE_RADIUS * 2, - height: NODE_RADIUS * 2, - type: ISchemaEnum.Tag, strokeColor: color.strokeColor, fill: color.fill, - hideActive: true, - x: Math.random() * 100, - y: Math.random() * 100, }; }); let lines = []; @@ -69,22 +78,94 @@ const SchemaVisualization = () => { const { src, dst, name, properties } = line; const srcTags = vidMap[src]; const dstTags = vidMap[dst]; - srcTags.forEach(srcTag => { - dstTags.forEach(dstTag => { - lines.push({ - from: srcTag, - to: dstTag, - name, - properties, + if(!srcTags || !dstTags) { + danglingEdges.push(line); + } else { + srcTags?.forEach(srcTag => { + dstTags?.forEach(dstTag => { + lines.push({ + from: srcTag, + to: dstTag, + name, + properties, + }); }); }); + } + }); + const result = danglingEdges.reduce((acc, cur) => { + // { + // e1: { + // noSrc: [edge2, edge3], + // noDst: [], + // noBoth: edge1 + // }, + // ..., + // flatten: [] + // } + const _acc = { ...acc }; + const { src, dst, name } = cur; + const uniqLines = _acc.flatten; + _acc[name] = _acc[name] || {}; + const lines = _acc[name]; + const srcTags = vidMap[src]; + const dstTags = vidMap[dst]; + if(!srcTags && !dstTags) { + if(!lines.noBoth) { + lines.noBoth = cur; + uniqLines.push({ ...cur, srcId: src, dstId: dst }); + } + } else if (!srcTags) { + dstTags.forEach(dstTag => { + const hasDst = lines.noSrc?.find(i => i.dst === dstTag); + const _line = { ...cur, dst: dstTag, srcId: src }; + if(!hasDst) { + uniqLines.push(_line); + } + lines.noSrc ? lines.noSrc.push(_line) : lines.noSrc = [_line]; + }); + } else if (!dstTags) { + srcTags.forEach(srcTag => { + const hasDst = lines.noDst?.find(i => i.src === srcTag); + const _line = { ...cur, src: srcTag, dstId: dst }; + if(!hasDst) { + uniqLines.push(_line); + } + lines.noDst ? lines.noDst.push(_line) : lines.noDst = [_line]; + }); + } + return _acc; + }, { flatten: [] }); + result.flatten.forEach(line => { + const { src, dst, srcId, dstId, name, properties } = line; + if(srcId && !nodes.find(i => i.vid === srcId)) { + nodes.push({ + ...NODE_CONFIG, + ...DANLEING_NODE_CONFIG, + vid: srcId, + uuid: uuidv4(), + }); + } + if(dstId && !nodes.find(i => i.vid === dstId)) { + nodes.push({ + ...NODE_CONFIG, + ...DANLEING_NODE_CONFIG, + vid: dstId, + uuid: uuidv4(), + }); + } + lines.push({ + from: src, + to: dst, + name, + properties, }); }); lines = uniqWith(lines, isEqual); const _lines = lines.map(line => { return { - from: nodes.find(node => node.name === line.from)?.uuid, - to: nodes.find(node => node.name === line.to)?.uuid, + from: nodes.find(node => node.name === line.from || node.vid === line.from)?.uuid, + to: nodes.find(node => node.name === line.to || node.vid === line.to)?.uuid, name: line.name, type: ISchemaEnum.Edge, fromPoint: 2, @@ -175,6 +256,13 @@ const SchemaVisualization = () => { {intl.get('common.edge')} +
+ + + + + {intl.get('common.danglingEdge')} +
diff --git a/app/pages/Schema/SchemaConfig/List/Tag/index.tsx b/app/pages/Schema/SchemaConfig/List/Tag/index.tsx index 1cb4ac54..7344166f 100644 --- a/app/pages/Schema/SchemaConfig/List/Tag/index.tsx +++ b/app/pages/Schema/SchemaConfig/List/Tag/index.tsx @@ -99,7 +99,8 @@ const TagList = () => { { + onConfirm={(e) => { + e.stopPropagation(); handleDeleteTag(tag.name); }} title={intl.get('common.ask')} diff --git a/app/pages/SketchModeling/SchemaConfig/index.module.less b/app/pages/SketchModeling/SchemaConfig/index.module.less index 7629db85..9673eacf 100644 --- a/app/pages/SketchModeling/SchemaConfig/index.module.less +++ b/app/pages/SketchModeling/SchemaConfig/index.module.less @@ -64,10 +64,12 @@ border-bottom: 1px solid @gray; } .propertiesForm :global(.ant-form-item) { - margin-bottom: 9px; + margin-bottom: 13px; } - .propertiesForm :global(.ant-form-item-with-help .ant-form-item-explain) { - white-space: nowrap; + .propertiesForm :global(.ant-row) { + &:has(:global(.ant-form-item-explain)) { + height: 60px; + } } .label { display: inline-block; @@ -111,6 +113,11 @@ position: absolute; right: 8px; top: 0; + :global(.ant-form-item-explain) { + white-space: nowrap; + position: relative; + left: -100px; + } } .removeBtn { display: flex; diff --git a/app/pages/SketchModeling/index.tsx b/app/pages/SketchModeling/index.tsx index 3691271e..2408541c 100644 --- a/app/pages/SketchModeling/index.tsx +++ b/app/pages/SketchModeling/index.tsx @@ -21,7 +21,7 @@ const SketchPage: React.FC = () => { useEffect(() => { trackPageView('/sketchModeling'); return () => { - currentSketch && sketchModel.destroy(); + sketchModel.currentSketch && sketchModel.destroy(); }; }, []); useEffect(() => { diff --git a/app/stores/schema.ts b/app/stores/schema.ts index c95000ab..8b915df9 100644 --- a/app/stores/schema.ts +++ b/app/stores/schema.ts @@ -694,7 +694,7 @@ export class SchemaStore { tables.forEach(item => { const { id, tags } = item; const _tags: string[] = safeParse(tags) || []; - vidMap[id] = _tags; + vidMap[id] = _tags.length > 0 ? _tags : undefined; _tags.forEach(i => tagSet.add(i)); }); return { vidMap, tags: [...tagSet] }; diff --git a/app/utils/constant.ts b/app/utils/constant.ts index 28780259..9ed9534f 100644 --- a/app/utils/constant.ts +++ b/app/utils/constant.ts @@ -106,7 +106,7 @@ export const ENUM_OF_COMPARE = { export const DATA_TYPE = [ { value: 'int', - label: 'int', + label: 'int64', }, { value: 'bool',