diff --git a/app-v2/common.less b/app-v2/common.less index 02167d4d..db5582fe 100644 --- a/app-v2/common.less +++ b/app-v2/common.less @@ -1,10 +1,5 @@ -@grayDark: #36383D; -@dark: rgba(0,0,0,.9); -@disableGray: rgba(255, 255, 255, 0.3); -@promptGray: #8C8C8C; -@blue: #0091ff; -@errorRed: #E02020; -@disableBlue: #375d7a; +@gray: #D5DDEB; +@lightGray: #F8F8F8; @font-face { font-family: 'Roboto-Black'; diff --git a/app-v2/config/locale/en-US.json b/app-v2/config/locale/en-US.json index f4bba64f..9b094ee4 100644 --- a/app-v2/config/locale/en-US.json +++ b/app-v2/config/locale/en-US.json @@ -368,5 +368,21 @@ "mannualHref": "https://docs.nebula-graph.io/3.0.0/nebula-studio/about-studio/st-ug-what-is-graph-studio/", "versionLogHref": "https://docs.nebula-graph.io/3.0.0/nebula-studio/about-studio/st-ug-release-note/", "forumLink": "https://discuss.nebula-graph.io/" + }, + "_schema": { + "spaceList": "Graph Space List", + "createSpace": "Create Space", + "No": "No", + "spaceName": "Name", + "partitionNumber": "Partition Number", + "replicaFactor": "Replica Factor", + "charset": "Charset", + "collate": "Collate", + "vidType": "Vid Type", + "atomicEdge": "Atomic Edge", + "group": "Group", + "comment": "Comment", + "operations": "Operations", + "useSpaceErrTip": "Space not found. Trying to use a newly created graph space may fail because the creation is implemented asynchronously. To make sure the follow-up operations work as expected, Wait for two heartbeat cycles, i.e., 20 seconds." } } diff --git a/app-v2/config/locale/zh-CN.json b/app-v2/config/locale/zh-CN.json index d56bfb8f..2b6839a8 100644 --- a/app-v2/config/locale/zh-CN.json +++ b/app-v2/config/locale/zh-CN.json @@ -364,5 +364,21 @@ "mannualHref": "https://docs.nebula-graph.com.cn/3.0.0/nebula-studio/about-studio/st-ug-what-is-graph-studio/", "versionLogHref": "https://docs.nebula-graph.com.cn/3.0.0/nebula-studio/about-studio/st-ug-release-note/", "forumLink": "https://discuss.nebula-graph.com.cn/" + }, + "_schema": { + "spaceList": "图空间列表", + "createSpace": "创建图空间", + "No": "序号", + "spaceName": "名称", + "partitionNumber": "Partition Number", + "replicaFactor": "Replica Factor", + "charset": "Charset", + "collate": "Collate", + "vidType": "Vid Type", + "atomicEdge": "Atomic Edge", + "group": "Group", + "comment": "Comment", + "operations": "操作", + "useSpaceErrTip": "图空间未找到。立刻尝试使用刚创建的图空间可能会失败,因为创建是异步实现的。为确保数据同步,后续操作能顺利进行,请等待 2 个心跳周期(20 秒)。" } } \ No newline at end of file diff --git a/app-v2/index.html b/app-v2/index.html index ca279552..85abb767 100644 --- a/app-v2/index.html +++ b/app-v2/index.html @@ -73,7 +73,7 @@ - +
diff --git a/app-v2/pages/Import/FileUpload/index.less b/app-v2/pages/Import/FileUpload/index.less index 5a1262f6..349f41cb 100644 --- a/app-v2/pages/Import/FileUpload/index.less +++ b/app-v2/pages/Import/FileUpload/index.less @@ -1,3 +1,4 @@ +@import '~@appv2/common.less'; .nebula-file-upload { .upload-btn { margin: 15px 0; @@ -9,7 +10,7 @@ font-weight: bold; font-size: 18px; padding-bottom: 12px; - border-bottom: 1px solid #D5DDEB; + border-bottom: 1px solid @gray; margin-bottom: 20px; } } diff --git a/app-v2/pages/Import/TaskCreate/SchemaConfig/EdgeConfig/index.less b/app-v2/pages/Import/TaskCreate/SchemaConfig/EdgeConfig/index.less deleted file mode 100644 index ecf41382..00000000 --- a/app-v2/pages/Import/TaskCreate/SchemaConfig/EdgeConfig/index.less +++ /dev/null @@ -1,21 +0,0 @@ -.tag-config-container { - padding: 10px 15px; - margin-bottom: 15px; - background: #FFFFFF; - border: 1px solid #D5DDEB; - box-sizing: border-box; - border-radius: 3px; - .tag-select-row { - display: flex; - justify-content: space-between; - align-items: center; - .left { - display: flex; - align-items: center; - .tag-select { - min-width: 60px; - } - } - } - -} \ No newline at end of file diff --git a/app-v2/pages/Import/TaskCreate/SchemaConfig/EdgeConfig/index.tsx b/app-v2/pages/Import/TaskCreate/SchemaConfig/EdgeConfig/index.tsx index 46e5138e..ba3e734e 100644 --- a/app-v2/pages/Import/TaskCreate/SchemaConfig/EdgeConfig/index.tsx +++ b/app-v2/pages/Import/TaskCreate/SchemaConfig/EdgeConfig/index.tsx @@ -6,7 +6,6 @@ import { CloseOutlined } from '@ant-design/icons'; import { observer } from 'mobx-react-lite'; import { useStore } from '@appv2/stores'; import CSVPreviewLink from '@appv2/components/CSVPreviewLink'; -import './index.less'; const Option = Select.Option; interface IProps { @@ -66,7 +65,7 @@ const EdgeConfig = (configProps: IProps) => { ]; return ( -
+
Edge Type diff --git a/app-v2/pages/Import/TaskCreate/SchemaConfig/TagConfig/index.less b/app-v2/pages/Import/TaskCreate/SchemaConfig/TagConfig/index.less deleted file mode 100644 index ecf41382..00000000 --- a/app-v2/pages/Import/TaskCreate/SchemaConfig/TagConfig/index.less +++ /dev/null @@ -1,21 +0,0 @@ -.tag-config-container { - padding: 10px 15px; - margin-bottom: 15px; - background: #FFFFFF; - border: 1px solid #D5DDEB; - box-sizing: border-box; - border-radius: 3px; - .tag-select-row { - display: flex; - justify-content: space-between; - align-items: center; - .left { - display: flex; - align-items: center; - .tag-select { - min-width: 60px; - } - } - } - -} \ No newline at end of file diff --git a/app-v2/pages/Import/TaskCreate/SchemaConfig/TagConfig/index.tsx b/app-v2/pages/Import/TaskCreate/SchemaConfig/TagConfig/index.tsx index 4c1327f0..65651399 100644 --- a/app-v2/pages/Import/TaskCreate/SchemaConfig/TagConfig/index.tsx +++ b/app-v2/pages/Import/TaskCreate/SchemaConfig/TagConfig/index.tsx @@ -6,7 +6,6 @@ import { CloseOutlined } from '@ant-design/icons'; import { observer } from 'mobx-react-lite'; import { useStore } from '@appv2/stores'; import CSVPreviewLink from '@appv2/components/CSVPreviewLink'; -import './index.less'; const Option = Select.Option; interface IProps { @@ -67,7 +66,7 @@ const VerticesConfig = (props: IProps) => { updateTagPropMapping({ configIndex, tagIndex }); }; return ( -
+
Tag diff --git a/app-v2/pages/Import/TaskCreate/SchemaConfig/index.less b/app-v2/pages/Import/TaskCreate/SchemaConfig/index.less index e35695c1..29ff8b87 100644 --- a/app-v2/pages/Import/TaskCreate/SchemaConfig/index.less +++ b/app-v2/pages/Import/TaskCreate/SchemaConfig/index.less @@ -1,6 +1,7 @@ +@import '~@appv2/common.less'; .config-collapse { background: #F3F6F9; - border: 1px solid #D5DDEB; + border: 1px solid @gray; box-sizing: border-box; border-radius: 6px; margin-bottom: 20px; @@ -18,7 +19,7 @@ .id-row { padding: 10px 15px; background: #FFFFFF; - border: 1px solid #D5DDEB; + border: 1px solid @gray; box-sizing: border-box; border-radius: 3px; margin-bottom: 10px; @@ -27,6 +28,27 @@ text-align: center; } } + .config-container { + padding: 10px 15px; + margin-bottom: 15px; + background: #FFFFFF; + border: 1px solid @gray; + box-sizing: border-box; + border-radius: 3px; + .tag-select-row { + display: flex; + justify-content: space-between; + align-items: center; + .left { + display: flex; + align-items: center; + .tag-select { + min-width: 60px; + } + } + } + + } .btn-close { cursor: pointer; } diff --git a/app-v2/pages/Import/TaskCreate/index.less b/app-v2/pages/Import/TaskCreate/index.less index 51c20338..61fbd08c 100644 --- a/app-v2/pages/Import/TaskCreate/index.less +++ b/app-v2/pages/Import/TaskCreate/index.less @@ -1,8 +1,9 @@ +@import '~@appv2/common.less'; .nebula-import-create { .create-form { padding: 32px 35px 100px; .basic-config { - border-bottom: 1px solid #D5DDEB; + border-bottom: 1px solid @gray; } .container { background: #FFFFFF; diff --git a/app-v2/pages/Import/TaskList/index.less b/app-v2/pages/Import/TaskList/index.less index 3149f735..408f25d6 100644 --- a/app-v2/pages/Import/TaskList/index.less +++ b/app-v2/pages/Import/TaskList/index.less @@ -1,3 +1,4 @@ +@import '~@appv2/common.less'; .nebula-data-import { .task-btns { margin: 15px 0 20px; @@ -10,7 +11,7 @@ font-weight: bold; font-size: 18px; padding-bottom: 12px; - border-bottom: 1px solid #D5DDEB; + border-bottom: 1px solid @gray; margin-bottom: 20px; } } \ No newline at end of file diff --git a/app-v2/pages/Import/index.less b/app-v2/pages/Import/index.less index 6b93d3c3..6ad46023 100644 --- a/app-v2/pages/Import/index.less +++ b/app-v2/pages/Import/index.less @@ -1,10 +1,11 @@ +@import '~@appv2/common.less'; .nebua-import-page { padding: 25px 35px; .tab-header { display: flex; justify-content: center; padding-bottom: 16px; - border-bottom: 1px solid #D5DDEB; + border-bottom: 1px solid @gray; .import-tab { background: #E9EDEF; border-radius: 20px; diff --git a/app-v2/pages/MainPage/routes.tsx b/app-v2/pages/MainPage/routes.tsx index ac605da8..ad0d067f 100644 --- a/app-v2/pages/MainPage/routes.tsx +++ b/app-v2/pages/MainPage/routes.tsx @@ -1,10 +1,16 @@ import { lazy } from 'react'; +const Schema = lazy(() => import('@appv2/pages/Schema')); const Import = lazy(() => import('@appv2/pages/Import')); const TaskCreate = lazy(() => import('@appv2/pages/Import/TaskCreate')); export const RoutesList = [ + { + path: '/schema', + component: Schema, + exact: true, + }, { path: '/import/create', component: TaskCreate, diff --git a/app-v2/pages/Schema/index.less b/app-v2/pages/Schema/index.less new file mode 100644 index 00000000..173fa3ac --- /dev/null +++ b/app-v2/pages/Schema/index.less @@ -0,0 +1,39 @@ +@import '~@appv2/common.less'; +.schema-page { + padding: 25px 35px; + .schema-header { + font-family: Roboto; + font-weight: bold; + font-size: 18px; + padding-bottom: 12px; + border-bottom: 1px solid @gray; + } + .schema-container { + padding-top: 20px; + .btn-create { + margin-bottom: 12px; + } + .table-space-list { + .space-item { + margin-top: 15px; + box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1); + border-radius: 6px; + } + .ant-table { + background-color: transparent; + } + table { + border-collapse: separate; + border-spacing: 0 15px; + } + .ant-table-row { + box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1); + border-radius: 6px; + background-color: #FFFFFF; + } + .cell-btn { + padding-left: 0; + } + } + } +} \ No newline at end of file diff --git a/app-v2/pages/Schema/index.tsx b/app-v2/pages/Schema/index.tsx new file mode 100644 index 00000000..bd5b112c --- /dev/null +++ b/app-v2/pages/Schema/index.tsx @@ -0,0 +1,165 @@ +import { Button, Popconfirm, Table, message } from 'antd'; +import React, { useEffect, useState } from 'react'; +import intl from 'react-intl-universal'; +import Icon from '@appv2/components/Icon'; +import { trackPageView } from '@appv2/utils/stat'; +import { observer } from 'mobx-react-lite'; +import { useStore } from '@appv2/stores'; +import './index.less'; +import { Link, useHistory } from 'react-router-dom'; + + + + +const Schema = () => { + const { schema } = useStore(); + const [loading, setLoading] = useState(false); + const history = useHistory(); + const { currentSpace, switchSpace, getSpacesList, deleteSpace, spaceList } = schema; + useEffect(() => { + trackPageView('/schema'); + getSpaces(); + }, []); + + const handleDeleteSpace = async(name: string) => { + setLoading(true); + const res = await deleteSpace(name); + if (res.code === 0) { + message.success(intl.get('common.deleteSuccess')); + await getSpaces(); + if (currentSpace === name) { + schema.update({ + currentSpace: '' + }); + } + } + }; + + const handleSwitchSpace = async(space: string) => { + const err = await switchSpace(space); + if (!err) { + history.push(`/space/${space}/tag/list`); + } else if (err && err.toLowerCase().includes('spacenotfound')) { + message.warning(intl.get('_schema.useSpaceErrTip')); + } + }; + const getSpaces = async() => { + setLoading(true); + await getSpacesList(); + setLoading(false); + }; + const columns = [ + { + title: intl.get('_schema.No'), + dataIndex: 'serialNumber', + align: 'center' as const, + }, + { + title: intl.get('_schema.spaceName'), + dataIndex: 'Name', + render: value => ( + + ), + }, + { + title: intl.get('_schema.partitionNumber'), + dataIndex: 'Partition Number', + }, + { + title: intl.get('_schema.replicaFactor'), + dataIndex: 'Replica Factor', + }, + { + title: intl.get('_schema.charset'), + dataIndex: 'Charset', + }, + { + title: intl.get('_schema.collate'), + dataIndex: 'Collate', + }, + { + title: intl.get('_schema.vidType'), + dataIndex: 'Vid Type', + }, + { + title: intl.get('_schema.atomicEdge'), + dataIndex: 'Atomic Edge', + render: value => String(value), + }, + { + title: intl.get('_schema.group'), + dataIndex: 'Group', + }, + { + title: intl.get('_schema.comment'), + dataIndex: 'Comment', + }, + { + title: intl.get('_schema.operations'), + dataIndex: 'operation', + render: (_1, space) => { + if (space.ID) { + return ( +
+
+ + handleDeleteSpace(space.Name)} + title={intl.get('common.ask')} + okText={intl.get('common.ok')} + cancelText={intl.get('common.cancel')} + > + + +
+
+ ); + } + }, + }, + ]; + return
+
+ {intl.get('_schema.spaceList')} +
+
+ + + + ; +}; + +export default observer(Schema); diff --git a/app-v2/stores/schema.ts b/app-v2/stores/schema.ts index 8d11e47c..0b972930 100644 --- a/app-v2/stores/schema.ts +++ b/app-v2/stores/schema.ts @@ -51,7 +51,7 @@ export class SchemaStore { } switchSpace = async(space: string) => { - const { code } = (await service.execNGQL({ + const { code, message } = (await service.execNGQL({ // HACK: Processing keyword gql: 'use' + '`' + space + '`;', })) as any; @@ -63,6 +63,8 @@ export class SchemaStore { spaceVidType: data?.tables?.[0]?.['Vid Type'] || 'FIXED_STRING(8)', }); sessionStorage.setItem('currentSpace', space); + } else { + return message; } }; @@ -93,7 +95,7 @@ export class SchemaStore { return { code, data }; } - asyncGetSpacesList = async(_payload) => { + getSpacesList = async() => { const res = await this.getSpaces(); if (res.data) { const spaces: ISpace[] = []; @@ -115,6 +117,21 @@ export class SchemaStore { } } + deleteSpace = async(space: string) => { + const { code, data } = (await service.execNGQL( + { + gql: `DROP SPACE ${handleKeyword(space)}`, + }, + { + trackEventConfig: { + category: 'schema', + action: 'delete_space', + }, + }, + )) as any; + return { code, data }; + } + // edges getEdges = async() => { const { code, data } = (await service.execNGQL({ diff --git a/config/webpack.base.ts b/config/webpack.base.ts index b489e9ea..940ab3ee 100644 --- a/config/webpack.base.ts +++ b/config/webpack.base.ts @@ -40,8 +40,11 @@ const commonConfig: Configuration = { lessOptions: { javascriptEnabled: true, modifyVars: { - 'menu-dark-bg': '#2F3A4A', 'primary-color': '#2F80ED', + 'menu-dark-bg': '#2F3A4A', + 'table-header-bg': '#E9EDEF', + 'table-header-color': '#465B7A', + 'table-header-cell-split-color': '#E9EDEF' } } }, diff --git a/package-lock.json b/package-lock.json index 998c587c..0cf7c376 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "nebula-graph-studio", - "version": "3.2.0", + "version": "3.2.1", "lockfileVersion": 1, "requires": true, "dependencies": {