Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add export to png & fix bugs #153

Merged
merged 1 commit into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions app/config/locale/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"confirm": "Confirm",
"import": "Import",
"ask": "Are you sure to proceed?",
"output": "Export CSV File",
"openInExplore": "Open In Explorer",
"schema": "Schema",
"create": "Create",
Expand Down Expand Up @@ -77,14 +76,15 @@
"username": "Username",
"password": "Password",
"success": "succeed",
"clear": "Clear Connection",
"clear": "Log out",
"title": "Connect to Nebula Graph"
},
"formRules": {
"hostRequired": "Host Required",
"usernameRequired": "Username Required",
"passwordRequired": "Password Required",
"positiveIntegerRequired": "Please enter a non-negative integer",
"nameValidate": "The name must start with a letter, and it only supports English letters, numbers and underscores",
"nameRequired": "Please enter the name",
"numberRequired": "Please enter a positive integer",
"replicaLimit": "Replica factor must not exceed the number of your current online machines({number})",
Expand Down Expand Up @@ -130,7 +130,6 @@
"fileSize": "Size",
"fileTitle": "Select Files",
"bindDatasource": "Bind Datasource",
"confirm": "Confirm",
"endImport": "Stop Import",
"prop": "Prop",
"mapping": "CSV Index",
Expand All @@ -154,10 +153,15 @@
"addTag": "Add Tag",
"config": "Task Config",
"parseFailed": "File parsing failed",
"uploadTemplate": "Click or drag the yaml configuration file to this area to upload",
"uploadTemplateTip": "Please keep only the file name (retain the file extension) for all file paths in the template, such as logPath: config.csv",
"fileUploadRequired": "Make sure all csv data files are uploaded before uploading the configuration",
"reUpload": "Re-upload"
"uploadTemplate": "Drag & drop the YAML configuration file to this area",
"uploadBoxTip": "The YAML configuration file is used to describe information about the files to be imported, the Nebula Graph server, and more. ",
"fileUploadRequired": "1. Please make sure all CSV data files are uploaded before import the YAML file. If not, please go to ",
"fileUploadRequired2": " first.",
"exampleDownload": "2. An example for the configuration file: ",
"uploadTemplateTip": "3. 3. Configure the Yaml file: please keep only the file name (retain the file extension) for all file paths (path, failDataPath, logPath) in the template, e.g. logPath: config.csv",
"reUpload": "Re-upload",
"fileNotExist": "{name} file does not exist!",
"importYaml": "Import the YAML file"
},
"schema": {
"spaceList": "Graph Space List",
Expand Down Expand Up @@ -215,11 +219,13 @@
"deleteSpace": "Delete Graph Space",
"cloneSpace": "Clone Graph Space",
"length": "Length",
"selectVidTypeTip": "Please select the type"
"selectVidTypeTip": "Please select the type",
"csvDownload": "Export CSV File",
"pngDownload": "Export PNG File"
},
"menu": {
"use": "Use Manual",
"release": "New Version",
"release": "Release Note",
"forum": "Help Forum",
"nGql": "nGQL"
},
Expand Down
24 changes: 15 additions & 9 deletions app/config/locale/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"confirm": "确认",
"import": "导入",
"ask": "确定进行当前操作?",
"output":"导出CSV文件",
"openInExplore": "导入图探索",
"schema": "Schema",
"create": "创建",
Expand Down Expand Up @@ -77,14 +76,15 @@
"username": "用户名",
"password": "密码",
"success": "配置成功",
"clear": "清除连接",
"clear": "登出",
"title": "配置数据库"
},
"formRules": {
"hostRequired": "请填写数据库服务器的IP地址",
"usernameRequired": "请填写用户名",
"passwordRequired": "请填写密码",
"positiveIntegerRequired": "请输入一个非负整数",
"nameValidate": "命名必须以字母开头,且只支持输入英文字母、数字以及下划线_",
"nameRequired": "请输入名称",
"numberRequired": "请输入正整数",
"replicaLimit": "副本数量不得超过你当前 online 机器数量({number})",
Expand Down Expand Up @@ -130,7 +130,6 @@
"fileSize": "大小",
"fileTitle": "文件列表",
"bindDatasource": "绑定数据源",
"confirm": "确认",
"endImport": "终止导入",
"prop": "属性",
"mapping": "对应列标",
Expand All @@ -154,10 +153,15 @@
"addTag": "添加 Tag",
"config": "任务配置",
"parseFailed": "文件解析失败",
"uploadTemplate": "点击或拖动yaml配置文件到该区域上传",
"uploadTemplateTip": "模板中所有文件路径请仅保留文件名(保留文件扩展名),比如 logPath: config.csv",
"fileUploadRequired": "上传配置前请确保所有 csv 数据文件已上传",
"reUpload": "重新上传"
"uploadTemplate": "将 YAML 配置文件拖放到该区域",
"uploadBoxTip": "The YAML configuration file is used to describe information about the files to be imported, the Nebula Graph server, and more. ",
"fileUploadRequired": "1. 请确保在导入 YAML 文件之前上传所有 CSV 数据文件。 如果没有,请先前往",
"fileUploadRequired2": "数据文件",
"exampleDownload": "2. 配置文件示例:",
"uploadTemplateTip": "3.配置Yaml文件:模板中所有文件路径(path、failDataPath、logPath)请只保留文件名(保留文件扩展名),例如: 日志路径:config.csv",
"reUpload": "重新上传",
"fileNotExist": "文件 {name} 不存在",
"importYaml": "导入 YAML 文件"
},
"schema": {
"spaceList": "图空间列表",
Expand Down Expand Up @@ -215,11 +219,13 @@
"deleteSpace": "删除图空间",
"cloneSpace": "克隆图空间",
"length": "长度",
"selectVidTypeTip": "选择 Vid 类型"
"selectVidTypeTip": "选择 Vid 类型",
"csvDownload": "导出 CSV",
"pngDownload": " 导出 PNG"
},
"menu": {
"use": "使用手册",
"release": "新发布",
"release": "更新日志",
"forum": "求助论坛",
"nGql": "nGQL"
},
Expand Down
24 changes: 17 additions & 7 deletions app/config/rules.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { POSITIVE_INTEGER_REGEX } from '@app/utils/constant';
import { NAME_REGEX, POSITIVE_INTEGER_REGEX } from '@app/utils/constant';
import intl from 'react-intl-universal';

export const hostRulesFn = () => [
Expand All @@ -22,12 +22,22 @@ export const passwordRulesFn = () => [
},
];

export const nameRulesFn = () => [
{
required: true,
message: intl.get('formRules.nameRequired'),
},
];
export const nameRulesFn = () => {
const version = sessionStorage.getItem('nebulaVersion');
const nameRequired = [
{
required: true,
message: intl.get('formRules.nameRequired'),
},
];
const nameValidate = [
{
pattern: NAME_REGEX,
message: intl.get('formRules.nameValidate'),
},
];
return version?.startsWith('v2') ? [...nameRequired, ...nameValidate] : nameRequired;
};

export const numberRulesFn = () => [
{
Expand Down
4 changes: 2 additions & 2 deletions app/pages/Console/ExportModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const ExportModal = (props: IProps) => {
</Radio.Button>
</Radio.Group>
</Form.Item>
<Form.Item noStyle={true} dependencies={['type']}>
<Form.Item noStyle dependencies={['type']}>
{({ getFieldValue }) => {
const type = getFieldValue('type');
return type === 'vertex' ? <>
Expand Down Expand Up @@ -133,7 +133,7 @@ const ExportModal = (props: IProps) => {
</>;
}}
</Form.Item>
<Form.Item noStyle={true}>
<Form.Item noStyle>
<Button
htmlType="submit"
type="primary"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import '~@app/common.less';

.display-panel {
.output-display-panel {
position: absolute;
top: 0;
right: 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const DisplayPanel = (props: IProps) => {
const [visible, setVisible] = useState(false);
const { data, spaceVidType } = props;
return (
<div className="display-panel">
<div className="output-display-panel">
<div className="btn-toggle-panel" onClick={() => setVisible(!visible)}>
<Icon type="icon-studio-btn-back" />
</div>
Expand Down
5 changes: 4 additions & 1 deletion app/pages/Console/OutputBox/ForceGraph/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, { useEffect, useRef, useState } from 'react';
import { parseSubGraph } from '@app/utils/parseData';
import { v4 as uuidv4 } from 'uuid';
import { useStore } from '@app/stores';
import { GraphStore } from '@app/stores/graph';
import { initTooltip } from './Tootip';
import DisplayPanel from './DisplayPanel';
import OperationPanel from './OperationPanel';
Expand All @@ -14,12 +15,13 @@ import './index.less';
interface IProps {
data: any;
spaceVidType: string;
onGraphInit: (graph: GraphStore) => void;
}
const ForceGraphBox = (props: IProps) => {
const [uuid ] = useState(uuidv4());
const { graphInstances: { graphs, initGraph, clearGraph } } = useStore();
const grapfDomRef = useRef<any>();
const { data, spaceVidType } = props;
const { data, spaceVidType, onGraphInit } = props;
const [loading, setLoading] = useState(false);
const init = async () => {
const { vertexes, edges } = parseSubGraph(data, spaceVidType);
Expand All @@ -29,6 +31,7 @@ const ForceGraphBox = (props: IProps) => {
id: uuid,
data: { vertexes, edges }
});
onGraphInit(graphs[uuid]);
initTooltip({ container: grapfDomRef.current, id: uuid });
initBrushSelect({ container: grapfDomRef.current, id: uuid });
setLoading(false);
Expand Down
23 changes: 23 additions & 0 deletions app/pages/Console/OutputBox/index.less
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import '~@app/common.less';
.output-box {
overflow: hidden;
max-height: 850px;
background: #fff;
position: relative;
display: flex;
Expand Down Expand Up @@ -49,6 +50,9 @@
span.btn-yellow svg{
fill: #F2C94C;
}
.btn-export {
cursor: pointer;
}
}
}

Expand Down Expand Up @@ -126,3 +130,22 @@
letter-spacing: 1.48px;
}
}

.export-popover {
.ant-popover-inner-content {
padding: 0;
border-radius: 3px;
}
.download-item {
padding: 10px 20px;
display: flex;
align-items: center;
justify-content: center;
color: black;
font-weight: 400;
font-size: 12px;
&[disabled] {
color: rgba(0, 0, 0, 0.25);
}
}
}
55 changes: 46 additions & 9 deletions app/pages/Console/OutputBox/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Table, Tabs, Tooltip } from 'antd';
import { Button, Table, Tabs, Tooltip, Popover } from 'antd';
import { BigNumber } from 'bignumber.js';
import React, { useCallback, useEffect, useState } from 'react';
import intl from 'react-intl-universal';
Expand All @@ -9,6 +9,7 @@ import { v4 as uuidv4 } from 'uuid';
import Icon from '@app/components/Icon';
import { parseSubGraph } from '@app/utils/parseData';
import classNames from 'classnames';
import { GraphStore } from '@app/stores/graph';
import Graphviz from './Graphviz';
import ForceGraph from './ForceGraph';

Expand Down Expand Up @@ -38,6 +39,8 @@ const OutputBox = (props: IProps) => {
const [dataSource, setDataSource] = useState<any>([]);
const [isFavorited, setIsFavorited] = useState(false);
const [showGraph, setShowGraph] = useState(false);
const [graph, setGraph] = useState<GraphStore | null>(null);
const [tab, setTab] = useState('');
const initData = () => {
let _columns = [] as any;
let _dataSource = [] as any;
Expand Down Expand Up @@ -110,6 +113,7 @@ const OutputBox = (props: IProps) => {
}, []);

const handleTabChange = useCallback(key => {
setTab(key);
trackEvent('console', `change_tab_${key}`);
}, []);

Expand Down Expand Up @@ -145,7 +149,7 @@ const OutputBox = (props: IProps) => {
});
};

const downloadData = () => {
const downloadCsv = () => {
if (!data) {
return ;
}
Expand Down Expand Up @@ -178,6 +182,31 @@ const OutputBox = (props: IProps) => {
link.click();
};

const downloadPng = () => {
if(graph) {
let canvas = graph.twoGraph.canvas;
const shadowCanvas = document.createElement('canvas');
shadowCanvas.width = canvas.width;
shadowCanvas.height = canvas.height;
const ctx = shadowCanvas.getContext('2d');
ctx.fillStyle = '#F3F6F9';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(canvas, 0, 0);
canvas = shadowCanvas;
setTimeout(() => {
canvas.toBlob(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = canvas.toDataURL('image/png');
a.download = 'Image.png';
a.click();
window.URL.revokeObjectURL(url);
});
}, 0);
}
trackEvent('console', 'export_graph_png');
};

const handleExplore = () => {
if (
data.tables.filter(
Expand Down Expand Up @@ -220,12 +249,20 @@ const OutputBox = (props: IProps) => {
onClick={removeFavorite}
/>
</Tooltip>}
<Tooltip title={intl.get('common.output')} placement="top">
<Icon
type="icon-studio-btn-output"
onClick={downloadData}
/>
</Tooltip>
<Popover
overlayClassName="export-popover"
placement="bottom"
content={<>
<Button type="link" className="download-item" onClick={downloadCsv}>
{intl.get('schema.csvDownload')}
</Button>
<Button disabled={!graph || tab !== 'graph'} type="link" className="download-item" onClick={downloadPng}>
{intl.get('schema.pngDownload')}
</Button>
</>}
>
<Icon className="btn-export" type="icon-studio-btn-output" />
</Popover>
{visible ? <Icon
type="icon-studio-btn-up"
onClick={() => setVisible(false)}
Expand Down Expand Up @@ -293,7 +330,7 @@ const OutputBox = (props: IProps) => {
}
key="graph"
>
<ForceGraph data={dataSource} spaceVidType={spaceVidType} />
<ForceGraph data={dataSource} spaceVidType={spaceVidType} onGraphInit={setGraph} />
</Tabs.TabPane>
)}
{code !== 0 && (
Expand Down
1 change: 1 addition & 0 deletions app/pages/Console/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
border: 1px solid @gray;
border-top: none;
cursor: pointer;
opacity: 0.7;
svg {
fill: @darkBlue;
}
Expand Down
Loading