diff --git a/README.md b/README.md index 868e20b0..3c6ae419 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,24 @@ TuGraph DB BROWSER 是 TuGraph 图数据库的可视化工具。可以完成图 yarn run bootstrap ``` -2. 项目编译 +2. 启动客户端 -```bash -yarn run build +```js +cd client +yarn start // 切记,一定要 yarn start,npm run start 会存在若干问题! ``` -1. 启动项目 +2. 启动服务端 ```bash -yarn run start +cd server +npm run dec ``` 浏览器访问 http://localhost:8888 + + +发布时打压缩包 +``` +tar -czvf tugraph-db-browser.tgz ./ +``` diff --git a/client/packages/app/client/.umirc.ts b/client/packages/app/client/.umirc.ts index 70c669bc..a100fd83 100644 --- a/client/packages/app/client/.umirc.ts +++ b/client/packages/app/client/.umirc.ts @@ -8,6 +8,9 @@ const umiConfig = getUmiConfig(); process.env.MFSU_AD = 'none'; +const ANTD_VERSION = '4.23.5'; +const GI_SDK_APP_VERSION = '1.2.0'; + export default defineConfig({ hash: true, define: { @@ -31,10 +34,7 @@ export default defineConfig({ react: 'React', 'react-dom': 'ReactDOM', antd: 'antd', - '@antv/g2plot': 'G2Plot', 'antd/es/*': 'antd', - '@ant-design/charts': 'charts', - '@ant-design/icons': 'icons', moment: 'moment', }, headScripts: [ @@ -47,22 +47,13 @@ export default defineConfig({ // 'https://gw.alipayobjects.com/os/lib/lodash/4.17.21/lodash.min.js', 'https://gw.alipayobjects.com/os/lib/moment/2.29.1/moment.js', - 'https://gw.alipayobjects.com/os/lib/antd/4.20.6/dist/antd.min.js', - 'https://gw.alipayobjects.com/os/lib/ant-design/charts/1.2.13/dist/charts.min.js', - 'https://gw.alipayobjects.com/os/lib/ant-design/icons/4.6.4/dist/index.umd.min.js', - // - 'https://gw.alipayobjects.com/os/lib/antv/g6/4.8.14/dist/g6.min.js', - 'https://gw.alipayobjects.com/os/lib/antv/graphin/2.7.16/dist/graphin.min.js', - 'https://gw.alipayobjects.com/os/lib/antv/g2plot/2.4.16/dist/g2plot.min.js', - 'https://gw.alipayobjects.com/os/lib/antv/gi-sdk/2.3.5/dist/index.min.js', + `https://gw.alipayobjects.com/os/lib/antd/${ANTD_VERSION}/dist/antd.min.js`, + + `https://gw.alipayobjects.com/os/lib/antv/gi-sdk-app/${GI_SDK_APP_VERSION}/dist/index.min.js`, ], styles: [ - // "https://gw.alipayobjects.com/os/lib/antd/4.18.3/dist/antd.min.css", - // "https://gw.alipayobjects.com/os/lib/alipay/theme-tools/0.3.0/dist/GraphInsight/light.css", - 'https://gw.alipayobjects.com/os/lib/antd/4.23.5/dist/antd.css', - 'https://gw.alipayobjects.com/os/lib/antv/graphin/2.7.16/dist/index.css', - 'https://gw.alipayobjects.com/os/lib/antv/gi-sdk/2.3.5/dist/index.css', - 'https://gw.alipayobjects.com/os/lib/antv/gi-theme-antd/0.1.0/dist/light.css', + `https://gw.alipayobjects.com/os/lib/antd/${ANTD_VERSION}/dist/antd.css`, + `https://gw.alipayobjects.com/os/lib/antv/gi-sdk-app/${GI_SDK_APP_VERSION}/dist/index.css`, ], theme: { 'primary-color': '#1650ff', diff --git a/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/domain-core/graph-query/components/path-query/index.module.less b/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/domain-core/graph-query/components/path-query/index.module.less index af7d0a40..cfc1d687 100644 --- a/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/domain-core/graph-query/components/path-query/index.module.less +++ b/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/domain-core/graph-query/components/path-query/index.module.less @@ -90,7 +90,7 @@ } .anticon-caret-right { color: #c6c6c8 !important; - transform: scale(1.5, 0.9); + // transform: scale(1.5, 0.9); margin-left: -3px; } } diff --git a/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/domain-core/project/project-list/components/project-card/index.tsx b/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/domain-core/project/project-list/components/project-card/index.tsx index 88ef60e2..0989c61a 100644 --- a/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/domain-core/project/project-list/components/project-card/index.tsx +++ b/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/domain-core/project/project-list/components/project-card/index.tsx @@ -117,7 +117,11 @@ const ProjectCard = ({ true, `${redirectPath?.[1]?.path}?graphName=${graphName}` ), - getActions('图分析', false, ''), + getActions( + '图分析', + true, + `${redirectPath?.[2]?.path}?graphName=${graphName}` + ), ]} bordered={false} hoverable diff --git a/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/global.less b/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/global.less index 4ff2a775..ea66af9e 100644 --- a/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/global.less +++ b/client/packages/app/client/src/components/@@plugins/src/components/studio/tugraph/global.less @@ -8,9 +8,9 @@ .ant-btn { border-radius: 6px; } -.ant-select-selector { - border-radius: 6px !important; -} +// .ant-select-selector { +// border-radius: 6px !important; +// } .ant-input { border-radius: 6px; } @@ -24,3 +24,64 @@ .ant-input-password { border-radius: 6px; } + +.LanguageQueryPanel { + height: calc(100vh - 145px) !important; + .buttonContainer { + bottom: 0px !important; + } +} + +.navbar-setting { + .ant-btn.ant-btn-text { + padding: 0; + margin-left: 4px; + } +} + +.gi-rich-container .gi-rich-container-toolbar { + border-bottom: none !important; + .toolbar-item { + .anticon { + svg { + font-size: 16px; + } + } + } +} + +.gi-rich-container-side > div:first-child { + box-shadow: 0px 0px 2px #ddd; + max-width: 720px; +} + +.gi-rich-container-side { + .ant-segmented { + background: #eaeff9; + padding: 4px; + width: 100% + } + .ant-segmented:not(.ant-segmented-disabled):hover, + .ant-segmented:not(.ant-segmented-disabled):focus { + background: #eaeff9; + } +} + +.style-setting-container { + height: calc(100vh - 110px) !important; + .style-setting-element-container .nodeConfigurationContainer, .style-setting-element-container .edgeConfigurationContainer { + height: calc(100vh - 210px) !important; + .ant-slider-mark-text { + font-size: 12px; + color: #6A6B71; + } + } +} + +.attribute-filter-container .attribute-filter-container-form { + height: calc(100vh - 195px) !important; +} + +.statictics-filter-container .statictics-filter-container-form { + height: calc(100vh - 195px) !important; +} \ No newline at end of file diff --git a/client/packages/app/client/src/plugins/graph-analysis.ts b/client/packages/app/client/src/plugins/graph-analysis.ts new file mode 100644 index 00000000..b913f73d --- /dev/null +++ b/client/packages/app/client/src/plugins/graph-analysis.ts @@ -0,0 +1 @@ +export { default } from '@tugraph/plugin-graph-analysis/client'; \ No newline at end of file diff --git a/client/packages/plugins/graph-analysis/README.md b/client/packages/plugins/graph-analysis/README.md new file mode 100644 index 00000000..01d5cc11 --- /dev/null +++ b/client/packages/plugins/graph-analysis/README.md @@ -0,0 +1,24 @@ +# Plugin Template + +## Register + +```ts +yarn pm add {{plugin-name}} +``` + +## Activate + +```bash +yarn pm enable {{plugin-name}} +``` + +## Launch the app + +```bash +# for development +yarn dev + +# for production +yarn build +yarn start +``` diff --git a/client/packages/plugins/graph-analysis/client.d.ts b/client/packages/plugins/graph-analysis/client.d.ts new file mode 100755 index 00000000..765db922 --- /dev/null +++ b/client/packages/plugins/graph-analysis/client.d.ts @@ -0,0 +1,4 @@ +// @ts-nocheck +export * from './lib/client'; +export { default } from './lib/client'; + diff --git a/client/packages/plugins/graph-analysis/client.js b/client/packages/plugins/graph-analysis/client.js new file mode 100755 index 00000000..edff0442 --- /dev/null +++ b/client/packages/plugins/graph-analysis/client.js @@ -0,0 +1,30 @@ +"use strict"; + +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } + +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } + +var _index = _interopRequireWildcard(require("./src/client")); + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var _exportNames = {}; +Object.defineProperty(exports, "default", { + enumerable: true, + get: function get() { + return _index.default; + } +}); + +Object.keys(_index).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; + if (key in exports && exports[key] === _index[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function get() { + return _index[key]; + } + }); +}); diff --git a/client/packages/plugins/graph-analysis/package.json b/client/packages/plugins/graph-analysis/package.json new file mode 100644 index 00000000..ac6f3eee --- /dev/null +++ b/client/packages/plugins/graph-analysis/package.json @@ -0,0 +1,16 @@ +{ + "name": "@tugraph/plugin-graph-analysis", + "version": "0.0.1", + "main": "lib/server/index.js", + "devDependencies": { + "@tugraph/openpiece-client": "^0.0.17", + "@tugraph/openpiece-server": "^0.0.10" + }, + "peerDependencies": { + "@tugraph/openpiece-client": "*", + "@tugraph/openpiece-server": "*" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/client/packages/plugins/graph-analysis/server.d.ts b/client/packages/plugins/graph-analysis/server.d.ts new file mode 100755 index 00000000..e70edb92 --- /dev/null +++ b/client/packages/plugins/graph-analysis/server.d.ts @@ -0,0 +1,4 @@ +// @ts-nocheck +export * from './lib/server'; +export { default } from './lib/server'; + diff --git a/client/packages/plugins/graph-analysis/server.js b/client/packages/plugins/graph-analysis/server.js new file mode 100755 index 00000000..33926d1d --- /dev/null +++ b/client/packages/plugins/graph-analysis/server.js @@ -0,0 +1,30 @@ +"use strict"; + +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } + +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } + +var _index = _interopRequireWildcard(require("./src/server")); + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var _exportNames = {}; +Object.defineProperty(exports, "default", { + enumerable: true, + get: function get() { + return _index.default; + } +}); + +Object.keys(_index).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; + if (key in exports && exports[key] === _index[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function get() { + return _index[key]; + } + }); +}); diff --git a/client/packages/plugins/graph-analysis/src/client/GI_EXPORT_FILES.ts b/client/packages/plugins/graph-analysis/src/client/GI_EXPORT_FILES.ts new file mode 100644 index 00000000..4d50d9f7 --- /dev/null +++ b/client/packages/plugins/graph-analysis/src/client/GI_EXPORT_FILES.ts @@ -0,0 +1,1245 @@ +export default { + "workbook": { + "id": "d72a7985-292f-4dc5-a9c9-c38f3e3639e5", + "name": "admin", + "activeAssetsKeys": { + "elements": [ + "SimpleNode", + "SimpleEdge" + ], + "components": [ + "ActivateRelations", + "AdvanceNeighborsQuery", + "CanvasSetting", + "ClearCanvas", + "ConfigQuery", + "ContextMenu", + "GraphDemo", + "Initializer", + "JSONMode", + "LanguageQuery", + "LassoSelect", + "LayoutSwitchTool", + "Loading", + "PinNodeWithMenu", + "Placeholder", + "PointEdgeView", + "PropertiesPanel", + "PropertyGraphInitializer", + "RichContainer", + "SimpleQuery", + "ToggleClusterWithMenu", + "TuGraphAttributesFilter", + "TuGraphBack", + "TuGraphStatisticsFilter", + "TuGraphStyleSetting", + "ZoomStatus" + ], + "layouts": [ + "Force2", + "Concentric", + "Dagre", + "FundForce" + ] + }, + "projectConfig": { + "nodes": [ + { + "id": "SimpleNode", + "props": { + "size": 26, + "color": "#ddd", + "label": [] + }, + "name": "官方节点", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "edges": [ + { + "id": "SimpleEdge", + "props": { + "size": 1, + "color": "#ddd", + "label": [] + }, + "name": "官方边", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "components": [ + { + "id": "ActivateRelations", + "type": "AUTO", + "name": "元素高亮", + "props": { + "enableNodeHover": true, + "enableEdgeHover": true, + "enable": true, + "trigger": "click", + "upstreamDegree": 1, + "downstreamDegree": 1, + "multiSelectEnabled": false, + "modifierKey": "alt" + } + }, + { + "id": "AdvanceNeighborsQuery", + "type": "GIAC_MENU", + "name": "高级邻居查询", + "props": { + "serviceId": "TuGraph-DB/neighborsQueryService", + "languageServiceId": "TuGraph-DB/languageQueryService" + } + }, + { + "id": "CanvasSetting", + "type": "AUTO", + "name": "画布设置", + "props": { + "styleCanvas": { + "backgroundColor": "#fff", + "backgroundImage": "" + }, + "dragCanvas": { + "disabled": false, + "direction": "both", + "enableOptimize": true + }, + "zoomCanvas": { + "disabled": false, + "enableOptimize": true + }, + "clearStatus": true, + "doubleClick": true + } + }, + { + "id": "ClearCanvas", + "type": "GIAC", + "name": "清空画布", + "props": { + "GI_CONTAINER_INDEX": 2, + "GIAC": { + "visible": false, + "disabled": false, + "isShowTitle": false, + "title": "清空画布", + "isShowIcon": true, + "icon": "icon-tugraph-clear", + "iconFontSize": "18px", + "buttonType": "text", + "isShowTooltip": true, + "tooltip": "清空画布", + "tooltipColor": "rgba(0,0,0,1)", + "tooltipPlacement": "top", + "hasDivider": false, + "height": "46px", + "isVertical": true + } + } + }, + { + "id": "ConfigQuery", + "type": "GIAC_CONTENT", + "name": "配置查询", + "props": { + "languageServiceId": "TuGraph-DB/languageQueryService", + "schemaServiceId": "TuGraph-DB/graphSchemaService", + "GI_CONTAINER_INDEX": 2, + "GIAC_CONTENT": { + "visible": false, + "disabled": false, + "isShowTitle": true, + "title": "未命名组件", + "isShowIcon": true, + "icon": "icon-star", + "isShowTooltip": true, + "tooltip": "", + "tooltipColor": "#3056e3", + "tooltipPlacement": "right", + "hasDivider": false, + "height": "60px", + "isVertical": true, + "containerType": "div", + "containerAnimate": false, + "containerDraggable": false, + "dragHandle": "header", + "containerPlacement": "RT", + "offset": [ + 0, + 0 + ], + "containerWidth": "350px", + "containerHeight": "calc(100% - 100px)", + "contaienrMask": false + } + } + }, + { + "id": "ContextMenu", + "type": "GICC_MENU", + "name": "右键菜单", + "props": { + "GI_CONTAINER": [ + "AdvanceNeighborsQuery", + "ToggleClusterWithMenu", + "PinNodeWithMenu" + ], + "nodeMenuComponents": [ + "NeighborsQuery", + "ToggleClusterWithMenu", + "PinNodeWithMenu" + ] + } + }, + { + "id": "GraphDemo", + "type": "GIAC", + "name": "Graph Demo 示例", + "props": { + "GI_CONTAINER_INDEX": 2, + "GIAC": { + "visible": false, + "disabled": false, + "isShowTitle": false, + "title": "Demo 示例", + "isShowIcon": true, + "icon": "icon-xiaodengpao", + "iconFontSize": "25px", + "buttonType": "text", + "isShowTooltip": true, + "tooltip": "", + "tooltipColor": "rgba(0,0,0,1)", + "tooltipPlacement": "top", + "hasDivider": false, + "height": "46px", + "isVertical": true + } + } + }, + { + "id": "Initializer", + "type": "INITIALIZER", + "name": "初始化器", + "props": { + "serviceId": "TuGraph-DB/GI_SERVICE_INTIAL_GRAPH", + "schemaServiceId": "TuGraph-DB/GI_SERVICE_SCHEMA", + "GI_INITIALIZER": true, + "aggregate": false, + "transByFieldMapping": false + } + }, + { + "id": "JSONMode", + "type": "GIAC_CONTENT", + "name": "代码模式", + "props": { + "theme": "rjv-default", + "GI_CONTAINER_INDEX": 2, + "GIAC_CONTENT": { + "visible": false, + "disabled": false, + "isShowTitle": true, + "title": "代码模式", + "isShowIcon": true, + "icon": "icon-tugraph-code-view", + "isShowTooltip": true, + "tooltip": "将数据以代码形式展示", + "tooltipColor": "#3056e3", + "tooltipPlacement": "right", + "hasDivider": false, + "height": "60px", + "isVertical": true, + "containerType": "div", + "containerAnimate": false, + "containerDraggable": false, + "dragHandle": "header", + "containerPlacement": "RT", + "offset": [ + 0, + 0 + ], + "containerWidth": "400px", + "containerHeight": "calc(100% - 100px)", + "contaienrMask": false + } + } + }, + { + "id": "LanguageQuery", + "type": "GIAC_CONTENT", + "name": "语句查询", + "props": { + "languageServiceId": "TuGraph-DB/languageQueryService", + "GI_CONTAINER_INDEX": 2, + "GIAC_CONTENT": { + "visible": false, + "disabled": false, + "isShowTitle": true, + "title": "未命名组件", + "isShowIcon": true, + "icon": "icon-star", + "isShowTooltip": true, + "tooltip": "", + "tooltipColor": "#3056e3", + "tooltipPlacement": "right", + "hasDivider": false, + "height": "60px", + "isVertical": true, + "containerType": "div", + "containerAnimate": false, + "containerDraggable": false, + "dragHandle": "header", + "containerPlacement": "RT", + "offset": [ + 0, + 0 + ], + "containerWidth": "350px", + "containerHeight": "calc(100% - 100px)", + "contaienrMask": false + } + } + }, + { + "id": "LassoSelect", + "type": "GIAC", + "name": "自由圈选", + "props": { + "GI_CONTAINER_INDEX": 2, + "GIAC": { + "visible": false, + "disabled": false, + "isShowTitle": false, + "title": "自由圈选", + "isShowIcon": true, + "icon": "icon-tugraph-lasso", + "isShowTooltip": true, + "tooltip": "套索", + "tooltipColor": "rgba(0,0,0,1)", + "tooltipPlacement": "top", + "hasDivider": false, + "height": "46px", + "isVertical": true, + "iconFontSize": "18px", + "buttonType": "text" + } + } + }, + { + "id": "LayoutSwitchTool", + "type": "GIAC", + "name": "高级布局切换", + "props": { + "GI_CONTAINER_INDEX": 2, + "GIAC": { + "visible": false, + "disabled": false, + "isShowTitle": false, + "title": "布局", + "isShowIcon": true, + "icon": "icon-tugraph-layout", + "iconFontSize": "18px", + "buttonType": "text", + "isShowTooltip": true, + "tooltip": "", + "tooltipColor": "rgba(0,0,0,1)", + "tooltipPlacement": "top", + "hasDivider": false, + "height": "46px", + "isVertical": true + } + } + }, + { + "id": "Loading", + "type": "AUTO", + "name": "加载动画", + "props": {} + }, + { + "id": "PinNodeWithMenu", + "type": "GIAC_MENU", + "name": "固定节点(MENU)", + "props": {} + }, + { + "id": "Placeholder", + "type": "AUTO", + "name": "画布占位符", + "props": { + "img": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*1BGfQ78mW4kAAAAAAAAAAAAADmJ7AQ/original", + "text": "画布为空时,请先试试查询-语句查询/配置查询", + "width": 340, + "textColor": "#999", + "spacing": 8 + } + }, + { + "id": "PointEdgeView", + "type": "AUTO", + "name": "TuGraph 图例", + "props": {} + }, + { + "id": "PropertiesPanel", + "type": "AUTO", + "name": "属性面板", + "props": { + "serviceId": "GI/PropertiesPanel", + "title": "属性面板", + "placement": "RT", + "width": "356px", + "height": "calc(100% - 0px)", + "offset": [ + 10, + 10 + ], + "animate": false, + "enableInfoDetect": true, + "defaultiStatistic": false + } + }, + { + "id": "PropertyGraphInitializer", + "type": "AUTO", + "name": "属性图计算", + "props": {} + }, + { + "id": "RichContainer", + "type": "GICC_LAYOUT", + "name": "中台布局", + "props": { + "containers": [ + { + "id": "navbar-left", + "name": "导航左区", + "required": true, + "GI_CONTAINER": [] + }, + { + "id": "navbar-right", + "name": "导航右区", + "required": true, + "GI_CONTAINER": [] + }, + { + "id": "view-mode", + "name": "模式展示", + "required": true, + "GI_CONTAINER": [], + "icon": "icon-deploymentunit1" + }, + { + "id": "data-query", + "name": "数据查询", + "required": true, + "GI_CONTAINER": [], + "icon": "icon-query" + }, + { + "id": "data-filter", + "name": "数据筛选", + "required": true, + "GI_CONTAINER": [], + "icon": "icon-filter" + }, + { + "id": "styling-setting", + "name": "布局样式", + "required": true, + "GI_CONTAINER": [] + }, + { + "id": "canvas-operator", + "name": "画布操作", + "required": true, + "GI_CONTAINER": [] + } + ], + "isSheet": false + } + }, + { + "id": "SimpleQuery", + "type": "AUTO", + "name": "简单查询", + "props": {} + }, + { + "id": "ToggleClusterWithMenu", + "type": "GIAC_MENU", + "name": "展开/收起", + "props": { + "isReLayout": false, + "degree": 1 + } + }, + { + "id": "TuGraphAttributesFilter", + "type": "GIAC_CONTENT", + "name": "属性筛选", + "props": { + "schemaServiceId": "TuGraph-DB/graphSchemaService", + "GI_CONTAINER_INDEX": 2, + "GIAC_CONTENT": { + "visible": false, + "disabled": false, + "isShowTitle": true, + "title": "未命名组件", + "isShowIcon": true, + "icon": "icon-star", + "isShowTooltip": true, + "tooltip": "", + "tooltipColor": "#3056e3", + "tooltipPlacement": "right", + "hasDivider": false, + "height": "60px", + "isVertical": true, + "containerType": "div", + "containerAnimate": false, + "containerDraggable": false, + "dragHandle": "header", + "containerPlacement": "RT", + "offset": [ + 0, + 0 + ], + "containerWidth": "350px", + "containerHeight": "calc(100% - 100px)", + "contaienrMask": false + } + } + }, + { + "id": "TuGraphBack", + "type": "GIAC", + "name": "返回按钮", + "props": {} + }, + { + "id": "TuGraphStatisticsFilter", + "type": "GIAC_CONTENT", + "name": "统计筛选", + "props": { + "schemaServiceId": "TuGraph-DB/graphSchemaService", + "GI_CONTAINER_INDEX": 2, + "GIAC_CONTENT": { + "visible": false, + "disabled": false, + "isShowTitle": true, + "title": "未命名组件", + "isShowIcon": true, + "icon": "icon-star", + "isShowTooltip": true, + "tooltip": "", + "tooltipColor": "#3056e3", + "tooltipPlacement": "right", + "hasDivider": false, + "height": "60px", + "isVertical": true, + "containerType": "div", + "containerAnimate": false, + "containerDraggable": false, + "dragHandle": "header", + "containerPlacement": "RT", + "offset": [ + 0, + 0 + ], + "containerWidth": "350px", + "containerHeight": "calc(100% - 100px)", + "contaienrMask": false + } + } + }, + { + "id": "TuGraphStyleSetting", + "type": "GIAC_CONTENT", + "name": "样式设置", + "props": { + "localServiceId": "TuGraph-DB/saveElementStyleToLocalService", + "schemaServiceId": "TuGraph-DB/graphSchemaService", + "GI_CONTAINER_INDEX": -8, + "GIAC_CONTENT": { + "visible": false, + "disabled": false, + "isShowTitle": true, + "title": "外观", + "isShowIcon": true, + "icon": "icon-tugraph-styling", + "isShowTooltip": true, + "tooltipColor": "rgba(0,0,0,1)", + "tooltipPlacement": "right", + "hasDivider": false, + "height": "60px", + "isVertical": true, + "containerType": "div", + "containerAnimate": false, + "containerDraggable": false, + "dragHandle": "header", + "containerPlacement": "RT", + "offset": [ + 0, + 0 + ], + "containerWidth": "350px", + "containerHeight": "calc(100% - 100px)", + "contaienrMask": false, + "tooltip": "根据点上的属性值可指定颜色、大小、形状" + } + } + }, + { + "id": "ZoomStatus", + "type": "AUTO", + "name": "缩放状态", + "props": { + "minZoom": 0.6, + "statusName": "minZoom" + } + } + ], + "layout": { + "id": "Force2", + "props": { + "type": "force2", + "animate": true, + "preset": { + "type": "concentric", + "width": 800, + "height": 800, + "minNodeSpacing": 10, + "nodeSize": 10 + }, + "clusterNodeStrength": 35, + "minMovement": 2, + "damping": 0.8, + "maxSpeed": 1000, + "distanceThresholdMode": "max", + "edgeStrength": 200, + "nodeStrength": 1000, + "defSpringLenCfg": { + "minLimitDegree": 5, + "maxLimitLength": 500, + "defaultSpring": 100 + }, + "centripetalOptions": { + "leaf": 2, + "single": 2, + "others": 1 + }, + "advanceWeight": false, + "edgeWeightFieldScale": 1, + "nodeWeightFromType": "node", + "nodeWeightFieldScale": 1, + "directed": false, + "directedFromType": "node", + "directedIsLog": true, + "directedMultiple": "0.1" + } + }, + "pageLayout": { + "id": "RichContainer", + "name": "中台布局", + "type": "GICC_LAYOUT", + "props": { + "containers": [ + { + "id": "navbar-left", + "name": "导航左区", + "required": true, + "GI_CONTAINER": [ + { + "value": "TuGraphBack", + "label": "返回按钮" + } + ], + "display": true + }, + { + "id": "navbar-right", + "name": "导航右区", + "required": true, + "GI_CONTAINER": [ + "GraphDemo" + ], + "display": true + }, + { + "id": "view-mode", + "name": "模式展示", + "required": true, + "GI_CONTAINER": [ + { + "value": "JSONMode", + "label": "代码模式" + } + ], + "icon": "icon-tugraph-graph-view", + "display": true + }, + { + "id": "data-query", + "name": "数据查询", + "required": true, + "GI_CONTAINER": [ + { + "value": "LanguageQuery", + "label": "语句查询" + }, + { + "value": "ConfigQuery", + "label": "配置查询" + } + ], + "icon": "icon-tugraph-query", + "display": true + }, + { + "id": "data-filter", + "name": "数据筛选", + "required": true, + "GI_CONTAINER": [ + { + "value": "TuGraphAttributesFilter", + "label": "属性筛选" + }, + { + "value": "TuGraphStatisticsFilter", + "label": "统计筛选" + } + ], + "icon": "icon-tugraph-filter", + "display": true + }, + { + "id": "styling-setting", + "name": "布局样式", + "required": true, + "GI_CONTAINER": [ + { + "value": "TuGraphStyleSetting", + "label": "业务样式设置" + }, + { + "value": "LayoutSwitchTool", + "label": "高级布局切换" + } + ], + "display": true + }, + { + "id": "canvas-operator", + "name": "画布操作", + "required": true, + "GI_CONTAINER": [ + { + "value": "LassoSelect", + "label": "自由圈选" + }, + { + "value": "ClearCanvas", + "label": "清空画布" + } + ], + "display": true + }, + { + "id": "GI_FreeContainer", + "name": "自运行组件", + "required": true, + "info": { + "id": "GI_FreeContainer", + "name": "自运行组件", + "icon": "icon-layout", + "type": "GICC" + }, + "meta": { + "GI_CONTAINER": { + "x-component-props": { + "mode": "multiple" + } + }, + "id": "GI_FreeContainer", + "name": "自运行组件", + "required": true + }, + "props": { + "id": "GI_FreeContainer", + "GI_CONTAINER": [ + { + "value": "CanvasSetting", + "label": "画布设置" + }, + { + "value": "Initializer", + "label": "初始化器" + }, + { + "value": "ActivateRelations", + "label": "元素高亮" + }, + { + "value": "Copyright", + "label": "版权" + }, + { + "value": "Loading", + "label": "加载动画" + }, + { + "value": "NodeLegend", + "label": "节点图例" + }, + { + "value": "Placeholder", + "label": "画布占位符" + }, + { + "value": "PropertiesPanel", + "label": "属性面板" + }, + { + "value": "PropertyGraphInitializer", + "label": "属性图计算" + } + ] + }, + "candidateAssets": [ + { + "label": "元素高亮", + "value": "ActivateRelations" + }, + { + "label": "画布设置", + "value": "CanvasSetting" + }, + { + "label": "版权", + "value": "Copyright" + }, + { + "label": "加载动画", + "value": "Loading" + }, + { + "label": "小地图", + "value": "MiniMap" + }, + { + "label": "节点图例", + "value": "NodeLegend" + }, + { + "label": "画布占位符", + "value": "Placeholder" + }, + { + "label": "属性面板", + "value": "PropertiesPanel" + }, + { + "label": "节点提示框", + "value": "Tooltip" + }, + { + "label": "初始化器", + "value": "Initializer" + }, + { + "label": "属性图计算", + "value": "PropertyGraphInitializer" + }, + { + "label": "水印", + "value": "Watermark" + }, + { + "label": "缩放状态", + "value": "ZoomStatus" + }, + { + "label": "分析历史沉淀", + "value": "AnalysisHistory" + }, + { + "label": "AI 助理", + "value": "Assistant" + }, + { + "label": "计数器", + "value": "Counter" + }, + { + "label": "简单查询", + "value": "SimpleQuery" + }, + { + "label": "demo案例", + "value": "Demo" + } + ], + "GI_CONTAINER": [ + "CanvasSetting", + "Initializer", + "ActivateRelations", + "Loading", + "Placeholder", + "PointEdgeView", + "PropertiesPanel", + "PropertyGraphInitializer", + "SimpleQuery", + "ZoomStatus" + ], + "display": true + } + ] + } + } + }, + "themes": [ + { + "canvasConfig": { + "styleCanvas": { + "backgroundColor": "#fff", + "backgroundImage": "https://gw.alipayobjects.com/mdn/rms_0d75e8/afts/img/A*k9t4QamMuQ4AAAAAAAAAAAAAARQnAQ", + "background": "#fff" + }, + "dragCanvas": { + "disabled": false, + "direction": "both", + "enableOptimize": true + }, + "zoomCanvas": { + "disabled": false, + "enableOptimize": true + }, + "clearStatus": true, + "doubleClick": true + }, + "nodesConfig": [ + { + "id": "SimpleNode", + "props": { + "size": 26, + "color": "#ddd", + "label": [], + "advanced": { + "label": { + "fill": "#000" + } + } + }, + "name": "官方节点", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "edgesConfig": [ + { + "id": "SimpleEdge", + "props": { + "size": 1, + "color": "#ddd", + "label": [] + }, + "name": "官方边", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "name": "清新蓝", + "id": "light", + "primaryColor": "rgb(48, 86, 227)" + }, + { + "canvasConfig": { + "styleCanvas": { + "backgroundColor": "#fff", + "backgroundImage": "https://gw.alipayobjects.com/mdn/rms_0d75e8/afts/img/A*k9t4QamMuQ4AAAAAAAAAAAAAARQnAQ", + "background": "#fff" + }, + "dragCanvas": { + "disabled": false, + "direction": "both", + "enableOptimize": true + }, + "zoomCanvas": { + "disabled": false, + "enableOptimize": true + }, + "clearStatus": true, + "doubleClick": true + }, + "nodesConfig": [ + { + "id": "SimpleNode", + "props": { + "size": 26, + "color": "#ddd", + "label": [], + "advanced": { + "label": { + "fill": "#000" + } + } + }, + "name": "官方节点", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "edgesConfig": [ + { + "id": "SimpleEdge", + "props": { + "size": 1, + "color": "#ddd", + "label": [] + }, + "name": "官方边", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "name": "暖阳橙", + "id": "ali", + "primaryColor": "rgb(255, 106, 0)" + }, + { + "canvasConfig": { + "styleCanvas": { + "backgroundColor": "#1f1f1f", + "backgroundImage": "https://gw.alipayobjects.com/mdn/rms_0d75e8/afts/img/A*k9t4QamMuQ4AAAAAAAAAAAAAARQnAQ", + "background": "#1f1f1f" + }, + "dragCanvas": { + "disabled": false, + "direction": "both", + "enableOptimize": true + }, + "zoomCanvas": { + "disabled": false, + "enableOptimize": true + }, + "clearStatus": true, + "doubleClick": true + }, + "nodesConfig": [ + { + "id": "SimpleNode", + "props": { + "size": 26, + "color": "#ddd", + "label": [], + "advanced": { + "label": { + "fill": "#fff" + } + } + }, + "name": "官方节点", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "edgesConfig": [ + { + "id": "SimpleEdge", + "props": { + "size": 1, + "color": "#ddd", + "label": [] + }, + "name": "官方边", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "name": "暗夜黑", + "id": "dark", + "primaryColor": "rgb(31, 31, 31)" + }, + { + "canvasConfig": { + "styleCanvas": { + "backgroundColor": "#fff", + "backgroundImage": "https://gw.alipayobjects.com/mdn/rms_0d75e8/afts/img/A*k9t4QamMuQ4AAAAAAAAAAAAAARQnAQ", + "background": "#fff" + }, + "dragCanvas": { + "disabled": false, + "direction": "both", + "enableOptimize": true + }, + "zoomCanvas": { + "disabled": false, + "enableOptimize": true + }, + "clearStatus": true, + "doubleClick": true + }, + "nodesConfig": [ + { + "id": "SimpleNode", + "props": { + "size": 26, + "color": "#ddd", + "label": [], + "advanced": { + "label": { + "fill": "#000" + } + } + }, + "name": "官方节点", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "edgesConfig": [ + { + "id": "SimpleEdge", + "props": { + "size": 1, + "color": "#ddd", + "label": [] + }, + "name": "官方边", + "order": -1, + "expressions": [], + "logic": true, + "groupName": "默认样式" + } + ], + "name": "芒种绿", + "id": "green", + "primaryColor": "rgb(39,118,88)" + } + ], + "theme": "light" + }, + "dataset": { + "id": "ds_504f732b-891d-4ff6-b807-430d9cc69cb8", + "engineContext": { + "engineId": "TuGraph-DB", + "schemaData": { + "nodes": [], + "edges": [] + }, + "name": "TuGraph 服务", + "HTTP_SERVER_URL": `http://${window.location.hostname}:7001` + }, + "engineId": "TuGraph-DB", + "name": "TuGraph 服务", + "schemaData": { + "nodes": [], + "edges": [] + }, + "data": { + "transData": { + "nodes": [], + "edges": [] + } + } + }, + "deps": { + "React": { + "url": "https://gw.alipayobjects.com/os/lib/react-dom/17.0.2/umd/react-dom.production.min.js", + "name": "react-dom", + "version": "17.0.2", + "global": "React" + }, + "ReactDOM": { + "url": "https://gw.alipayobjects.com/os/lib/react-dom/17.0.2/umd/react-dom.production.min.js", + "name": "react-dom", + "version": "17.0.2", + "global": "ReactDOM" + }, + "_": { + "name": "lodash", + "version": "4.17.21", + "global": "_", + "url": "https://gw.alipayobjects.com/os/lib/lodash/4.17.21/lodash.min.js" + }, + "antd": { + "url": "https://gw.alipayobjects.com/os/lib/antd/4.24.8/dist/antd.min.js", + "name": "antd", + "version": "4.24.8", + "global": "antd" + }, + "G6": { + "url": "https://gw.alipayobjects.com/os/lib/antv/g6/4.8.14/dist/g6.min.js", + "name": "@antv/g6", + "version": "4.8.14", + "global": "G6" + }, + "Graphin": { + "url": "https://gw.alipayobjects.com/os/lib/antv/graphin/2.7.25/dist/graphin.min.js", + "name": "@antv/graphin", + "version": "2.7.25", + "global": "Graphin" + }, + "GISDK": { + "name": "@antv/gi-sdk", + "version": "2.4.10", + "url": "https://gw.alipayobjects.com/os/lib/antv/gi-sdk/2.4.10/dist/index.min.js", + "global": "GISDK" + }, + "G2Plot": { + "url": "https://gw.alipayobjects.com/os/lib/antv/g2plot/2.4.16/dist/g2plot.min.js", + "name": "@antv/g2plot", + "version": "2.4.16", + "global": "G2Plot" + }, + "@antv/gi-theme-antd": { + "name": "@antv/gi-theme-antd", + "version": "0.6.5", + "url": "https://gw.alipayobjects.com/os/lib/antv/gi-theme-antd/0.6.5/dist/index.min.js", + "global": "GI_THEME_ANTD" + } + }, + "GI_ASSETS_PACKAGES": { + "GI_ASSETS_BASIC": { + "name": "@antv/gi-assets-basic", + "version": "2.4.14", + "url": "https://gw.alipayobjects.com/os/lib/antv/gi-assets-basic/2.4.14/dist/index.min.js", + "global": "GI_ASSETS_BASIC" + }, + "GI_ASSETS_ADVANCE": { + "name": "@antv/gi-assets-advance", + "version": "2.5.12", + "url": "https://gw.alipayobjects.com/os/lib/antv/gi-assets-advance/2.5.12/dist/index.min.js", + "global": "GI_ASSETS_ADVANCE" + }, + "GI_ASSETS_TUGRAPH_DB": { + "name": "@tugraph/gi-assets-tugraph-db", + "version": "0.6.12", + "global": "GI_ASSETS_TUGRAPH_DB", + "url": "https://gw.alipayobjects.com/os/lib/tugraph/gi-assets-tugraph-db/0.6.12/dist/index.min.js" + } + } +} \ No newline at end of file diff --git a/client/packages/plugins/graph-analysis/src/client/PluginDesigner.tsx b/client/packages/plugins/graph-analysis/src/client/PluginDesigner.tsx new file mode 100644 index 00000000..8e6616e1 --- /dev/null +++ b/client/packages/plugins/graph-analysis/src/client/PluginDesigner.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { useFieldSchema } from '@formily/react'; +import { + GeneralSchemaDesigner, + SchemaSettings, + useCollection, + useDesignable, +} from '@tugraph/openpiece-client'; +import { map, get } from 'lodash'; + +export const PluginDesigner = () => { + const { name, title } = useCollection(); + const fieldSchema = useFieldSchema(); + + const openpieceRouteList = localStorage.getItem('OPENPIECE_ROUTE_LIST'); + const routeOptions = openpieceRouteList ? JSON.parse(openpieceRouteList) : []; + + const { dn } = useDesignable(); + + return ( + + + { + const componentSchema = fieldSchema?.properties?.row1; + const redirectPath = map(routeValue, (item) => { + return { + path: `/admin/${item?.value}`, + pathName: item.label, + }; + }); + if (componentSchema) { + componentSchema['x-component-props'] = + componentSchema['x-component-props'] || {}; + componentSchema['x-component-props']['redirectPath'] = redirectPath; + componentSchema['x-component-props']['routeValue'] = routeValue; + dn.emit('patch', { + schema: { + 'x-uid': componentSchema['x-uid'], + 'x-component-props': componentSchema['x-component-props'], + }, + }); + dn.refresh(); + } + }} + /> + + ); +}; diff --git a/client/packages/plugins/graph-analysis/src/client/index.tsx b/client/packages/plugins/graph-analysis/src/client/index.tsx new file mode 100644 index 00000000..e0cc2a26 --- /dev/null +++ b/client/packages/plugins/graph-analysis/src/client/index.tsx @@ -0,0 +1,95 @@ +import { TableOutlined } from '@ant-design/icons'; +import { + SchemaComponentOptions, + SchemaInitializer, + SchemaInitializerContext, +} from '@tugraph/openpiece-client'; +import React, { useContext } from 'react'; +// @ts-ignore +import TuGraphGraphAppConfig from './GI_EXPORT_FILES.ts'; +import { PluginDesigner } from './PluginDesigner'; +//@ts-ignore +const { default: GI_SDK_APP } = window.GI_SDK_APP; + +const GraphAnalysis = () => { + const id = 'credit.json'; + // const url = `https://unpkg.alipay.com/@alipay/gi-assets-vip@latest/app/${id}`; // 内网 VIP 方案 + const service = async () => { + // const config = await fetch(url).then(res => res.json()); + const config = TuGraphGraphAppConfig; + return { + data: config, + success: true, + }; + }; + return ( +
+ +
+ ); +}; + +export const PluginBlockInitializer = props => { + const { insert } = props; + + const schema = { + type: 'void', + 'x-component': 'CardItem', + 'x-designer': 'PluginDesigner', + properties: { + row1: { + type: 'void', + 'x-component': 'GraphAnalysis', + 'x-async': false, + 'x-index': 1, + 'x-component-props': {}, + }, + }, + }; + + return ( + } + onClick={() => { + insert(schema); + }} + title="GraphAnalysis" + /> + ); +}; + +export default React.memo(props => { + const items = useContext(SchemaInitializerContext) as any; + const children = items?.BlockInitializers?.items?.[1]?.children ?? []; + + const hasCustomBlock = children?.find(d => d.key === ' GraphAnalysis'); + + if (!hasCustomBlock) { + children.push({ + key: ' GraphAnalysis', + type: 'item', + title: ' GraphAnalysis', + component: PluginBlockInitializer, + }); + } + return ( + + + {props.children} + + + ); +}); diff --git a/client/packages/plugins/graph-analysis/src/index.ts b/client/packages/plugins/graph-analysis/src/index.ts new file mode 100644 index 00000000..7ddad581 --- /dev/null +++ b/client/packages/plugins/graph-analysis/src/index.ts @@ -0,0 +1 @@ +export { default } from './server'; diff --git a/client/packages/plugins/graph-analysis/src/server/actions/.gitkeep b/client/packages/plugins/graph-analysis/src/server/actions/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/client/packages/plugins/graph-analysis/src/server/collections/.gitkeep b/client/packages/plugins/graph-analysis/src/server/collections/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/client/packages/plugins/graph-analysis/src/server/index.ts b/client/packages/plugins/graph-analysis/src/server/index.ts new file mode 100644 index 00000000..a56a2e38 --- /dev/null +++ b/client/packages/plugins/graph-analysis/src/server/index.ts @@ -0,0 +1,33 @@ +import { InstallOptions, Plugin } from '@tugraph/openpiece-server'; + +export class HelloPlugin extends Plugin { + + beforeLoad() { + // TODO + } + + async load() { + // TODO + // Visit: http://localhost:13000/api/testHello:getInfo + this.app.resource({ + name: 'testHello', + actions: { + async getInfo(ctx, next) { + ctx.body = `Hello hello!`; + next(); + }, + }, + }); + this.app.acl.allow('testHello', 'getInfo'); + } + + async disable() { + // this.app.resourcer.removeResource('testHello'); + } + + async install(options: InstallOptions) { + // TODO + } +} + +export default HelloPlugin; diff --git a/client/packages/plugins/graph-analysis/src/server/models/.gitkeep b/client/packages/plugins/graph-analysis/src/server/models/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/client/packages/plugins/graph-analysis/src/server/repositories/.gitkeep b/client/packages/plugins/graph-analysis/src/server/repositories/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/client/storage/db/openpiece.sqlite b/client/storage/db/openpiece.sqlite index 8c179c9a..ff4b3db5 100644 Binary files a/client/storage/db/openpiece.sqlite and b/client/storage/db/openpiece.sqlite differ diff --git a/server/app/controller/tugraph/query.ts b/server/app/controller/tugraph/query.ts index fb9208a0..318d01c9 100644 --- a/server/app/controller/tugraph/query.ts +++ b/server/app/controller/tugraph/query.ts @@ -33,6 +33,13 @@ class TuGraphQueryController extends Controller { const result = await ctx.service.tugraph.query.queryNeighbors(params); responseData(ctx, result); } + + async queryByConfig() { + const { ctx } = this; + const params = ctx.request.body; + const result = await ctx.service.tugraph.query.queryByConfig(params); + responseData(ctx, result); + } } export default TuGraphQueryController; diff --git a/server/app/router.ts b/server/app/router.ts index d7446a4e..18daed6d 100644 --- a/server/app/router.ts +++ b/server/app/router.ts @@ -102,6 +102,8 @@ export default (app: Application) => { ); router.post('/api/query/path', controller.tugraph.query.queryByPath); router.post('/api/query/node', controller.tugraph.query.queryByNode); + router.post('/api/query/config', controller.tugraph.query.queryByConfig); + router.post('/api/query/neighbors', controller.tugraph.query.queryNeighbors) // 数据相关 router.post('/api/data/node', controller.tugraph.data.createNode); diff --git a/server/app/service/tugraph/interface.ts b/server/app/service/tugraph/interface.ts index 391b6464..e9e2ad27 100644 --- a/server/app/service/tugraph/interface.ts +++ b/server/app/service/tugraph/interface.ts @@ -184,6 +184,7 @@ export interface INeighborsParams { ids: string[]; sep: number; graphName: string; + limit?: number; } export interface ISubGraphConfig { @@ -259,3 +260,10 @@ export interface ICypherResponse { result: any[]; size: number; } + +export interface IConfigQueryParams { + graphName: string; + nodeType: string; + conditions: Condition[]; + limit: number; +} diff --git a/server/app/service/tugraph/query.ts b/server/app/service/tugraph/query.ts index 8888c726..4fea05a7 100644 --- a/server/app/service/tugraph/query.ts +++ b/server/app/service/tugraph/query.ts @@ -8,6 +8,7 @@ */ import { Service } from 'egg'; import { + IConfigQueryParams, ILanguageQueryParams, INeighborsParams, INodeQueryParams, @@ -17,6 +18,7 @@ import { import { QueryResultFormatter } from '../../util'; import { formatVertexResponse, + generateCypherByConfig, generateCypherByNode, generateCypherByPath, } from '../../utils/query'; @@ -134,24 +136,45 @@ class TuGraphQueryService extends Service { * @param params */ async queryNeighbors(params: INeighborsParams) { - const { ids, graphName, sep = 1 } = params; - let cypher = `match(n)-[*..${sep}]-(m) WHERE id(n)=${ids[0]} RETURN n, m LIMIT 100`; + const { ids, graphName, sep = 1, limit = 200 } = params; + let cypher = `match p=(n)-[*..${sep}]-(m) WHERE id(n)=${ids[0]} RETURN p LIMIT ${limit}`; if (ids.length > 1) { // 查询两度关系,需要先查询节点,再查询子图 - cypher = `match(n)-[*..${sep}]-(m) WHERE id(n) in [${ids}] RETURN n, m LIMIT 200`; + cypher = `match p=(n)-[*..${sep}]-(m) WHERE id(n) in [${ids}] RETURN p LIMIT ${limit}`; } const responseData = - await this.service.openpiece.query.querySubGraphByCypher( + await this.ctx.service.tugraph.subgraph.querySubGraphByCypher( + graphName, cypher, - graphName ); - return { - data: responseData, - code: 200, - success: true, - }; + return responseData; + } + + /** + * 根据配置查询数据 + * @param params IConfigQueryParams + * @returns + */ + async queryByConfig(params: IConfigQueryParams) { + const { graphName } = params; + const script = generateCypherByConfig(params); + const result = await this.ctx.curl(`${EngineServerURL}/cypher`, { + headers: { + 'content-type': 'application/json', + Authorization: this.ctx.request.header.authorization, + }, + method: 'POST', + data: { + graph: graphName, + script, + }, + timeout: [30000, 50000], + dataType: 'json', + }); + + return QueryResultFormatter(result, script); } } export default TuGraphQueryService; diff --git a/server/app/service/tugraph/schema.ts b/server/app/service/tugraph/schema.ts index e18beeb8..b59b8b2f 100644 --- a/server/app/service/tugraph/schema.ts +++ b/server/app/service/tugraph/schema.ts @@ -319,7 +319,7 @@ class TuGraphSchemaService extends Service { const currentEdgeSchema = await this.querySchemaByLabel( graphName, 'edge', - d.edgeLabels + d.label ); return currentEdgeSchema; }); @@ -371,8 +371,8 @@ class TuGraphSchemaService extends Service { */ async querySchema(graphName: string) { const vertexSchema = await this.queryVertexSchema(graphName); - const edgeSchema = await this.queryEdgeSchema(graphName); + return { code: 200, success: true, diff --git a/server/app/service/tugraph/subgraph.ts b/server/app/service/tugraph/subgraph.ts index be4f2270..580b337b 100644 --- a/server/app/service/tugraph/subgraph.ts +++ b/server/app/service/tugraph/subgraph.ts @@ -9,7 +9,7 @@ */ import { Service } from 'egg'; -import { responseFormatter } from '../../util'; +import { QueryResultFormatter, responseFormatter } from '../../util'; import { EngineServerURL } from './constant'; import { ISubGraphConfig, ISubGraphTemplateParams } from './interface'; @@ -277,28 +277,8 @@ class TuGraphSubGraphService extends Service { timeout: [30000, 50000], dataType: 'json', }); - - if (result.data.errorCode != 200) { - return result.data; - } - - // TODO: 这个逻辑需要等 TuGraph 重构完再调整 - // const nodeIds = [...new Set([...getNodeIdsByEids(result).nodeIds, ...getNodeIds(result)])]; - const nodeIds = []; - // 拿到节点 ID 后,查询子图 - - if (nodeIds.length === 0) { - return { - nodes: [], - edges: [], - }; - } - - const subGraphResult = await this.querySubGraphByNodeIds( - graphName, - nodeIds - ); - return subGraphResult; + + return QueryResultFormatter(result as any, cypher) } /** diff --git a/server/app/util.ts b/server/app/util.ts index e2f209a4..f8461453 100644 --- a/server/app/util.ts +++ b/server/app/util.ts @@ -167,7 +167,10 @@ export const QueryResultFormatter = ( originalData: resultData, formatData: isEmpty(edges) && isEmpty(nodes) - ? null + ? { + nodes: [], + edges: [] + } : { edges, nodes, diff --git a/server/app/utils/query.ts b/server/app/utils/query.ts index 16cc05ff..c93a1d29 100644 --- a/server/app/utils/query.ts +++ b/server/app/utils/query.ts @@ -10,6 +10,7 @@ import { ISubGraphParams, IVertexResponse, IEdgeResponse, + IConfigQueryParams, } from '../service/tugraph/interface'; import { find, has, map, isEmpty } from 'lodash'; @@ -330,3 +331,20 @@ export const generateCypherByNode = (params: INodeQueryParams) => { ' AND ' )} RETURN ${nodesIndex.join(',')} LIMIT ${limit}`; }; + +/** + * 根据配置转换查询的 Cypher 语句 + * @param params IConfigQueryParams + * @return + */ +export const generateCypherByConfig = (params: IConfigQueryParams) => { + const { nodeType, conditions, limit } = params; + if (isEmpty(conditions)) { + return `MATCH (n: ${nodeType}) RETURN n LIMIT ${limit}`; + } + const conditionScripts = conditionToCypher(conditions); + + return `MATCH (n: ${nodeType}) WHERE ${conditionScripts.join( + ' AND ' + )} RETURN n LIMIT ${limit}`; +}; \ No newline at end of file diff --git a/server/package.json b/server/package.json index 117b1e3c..049f052b 100644 --- a/server/package.json +++ b/server/package.json @@ -56,5 +56,6 @@ "coverage" ], "files.insertFinalNewline": true, - "files.trimFinalNewlines": true -} + "files.trimFinalNewlines": true, + "repository": "https://github.com/TuGraph-family/tugraph-db-browser.git" +} \ No newline at end of file