-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #475 from BQXBQX/main
feat: draw-pattern section
- Loading branch information
Showing
81 changed files
with
4,133 additions
and
434 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,90 @@ | ||
# 📊 @graphscope/studio-draw-pattern | ||
# 📊 `@graphscope/studio-draw-pattern` | ||
|
||
[![NPM version](https://img.shields.io/npm/v/studio-draw-pattern.svg?style=flat)](https://npmjs.com/package/studio-draw-pattern) | ||
[![NPM downloads](http://img.shields.io/npm/dm/studio-draw-pattern.svg?style=flat)](https://npmjs.com/package/studio-draw-pattern) | ||
This section covers the `DrawPattern` component of the `GraphScope Portal`. | ||
|
||
## 🛠 工具开发 | ||
## Data Structure | ||
|
||
```bash | ||
$ git clone https://github.com/BQXBQX/studio-draw-pattern.git | ||
$ pnpm install | ||
``` | ||
The following diagram illustrates the data structure design: | ||
|
||
![data structure](./public/structure.png) | ||
|
||
### Key Points: | ||
|
||
- **Properties**: In both nodes and edges, the properties store the property ID values. | ||
- **isErgodic**: This flag is used to determine whether a node has been traversed during generation. | ||
|
||
## Component | ||
|
||
### Overview | ||
|
||
```bash | ||
$ npm run dev | ||
$ npm run build | ||
The `DrawPattern` component is designed to handle graph schema previews and provide an interactive interface for users to define graph patterns using `MATCH`, `WHERE`, and `description` values. It allows custom handling of changes through a callback function and renders a user interface split into two sections: a quick start guide and a canvas for graph visualization. | ||
|
||
### Props | ||
|
||
#### `previewGraph?: GraphProps` | ||
|
||
- **Type**: `GraphProps` (an object containing nodes and edges) | ||
- **Description**: This optional prop allows you to pass in a preview graph, which consists of schema nodes and edges to visualize on the canvas. | ||
|
||
**GraphProps Interface**: | ||
|
||
```ts | ||
export interface GraphProps { | ||
nodes: ISchemaNode[]; | ||
edges: ISchemaEdge[]; | ||
} | ||
``` | ||
|
||
## 🦴 项目架构 | ||
|
||
主要开发集中在 src 文件夹内 | ||
|
||
```bash | ||
. | ||
├── README.md | ||
├── package.json | ||
├── pnpm-lock.yaml | ||
├── src | ||
│ ├── components # 相关组件,计划封装为<DrawPattern />组件 | ||
│ ├── hooks # 相关的React Hook, 计划最后封装两个Hook, useGenerate&useDeconstruct, | ||
│ ├── index.ts # 项目入口 | ||
│ ├── stores # 项目的状态管理,使用valtio进行封装 | ||
│ ├── types # 项目的所有类型 | ||
│ │ ├── edge.d.ts | ||
│ │ ├── node.d.ts | ||
│ │ ├── property.d.ts | ||
│ │ └── variable.d.ts | ||
│ └── utils # 相关工具函数 | ||
└── tsconfig.json | ||
- `nodes`: An array of graph nodes (`ISchemaNode`). | ||
- `edges`: An array of graph edges (`ISchemaEdge`). | ||
|
||
### `onClick?: (value: DrawPatternValue) => void` | ||
|
||
- **Type**: `(value: DrawPatternValue) => void` | ||
- **Description**: An optional callback function that will be triggered when a user action occurs, providing the `MATCH`, `WHERE`, and `description` values. | ||
|
||
**DrawPatternValue Interface**: | ||
|
||
```ts | ||
export interface DrawPatternValue { | ||
MATCHs: string; | ||
WHEREs: string; | ||
description: string; | ||
} | ||
``` | ||
|
||
## 🛠 API | ||
- `MATCHs`: String representation of the graph pattern’s `MATCH` statement. | ||
- `WHEREs`: String representation of the `WHERE` conditions. | ||
- `description`: A string describing the pattern. | ||
|
||
### Usage Example | ||
|
||
Here’s how you can use the `DrawPattern` component within a React application: | ||
|
||
```tsx | ||
import React from 'react'; | ||
import { DrawPattern, DrawPatternValue, GraphProps } from './DrawPattern'; | ||
|
||
const App: React.FC = () => { | ||
const graphData: GraphProps = { | ||
nodes: [ | ||
{ id: 'node1', label: 'Node 1' }, | ||
{ id: 'node2', label: 'Node 2' }, | ||
], | ||
edges: [{ source: 'node1', target: 'node2', label: 'Edge 1' }], | ||
}; | ||
|
||
const handlePatternClick = (value: DrawPatternValue) => { | ||
console.log('Pattern clicked:', value); | ||
}; | ||
|
||
return <DrawPattern previewGraph={graphData} onClick={handlePatternClick} />; | ||
}; | ||
|
||
export default App; | ||
``` | ||
|
||
## 🌞 TODO | ||
### Explanation | ||
|
||
- [ ] Cypher 语句适配 | ||
- [ ] Cypher Node 正则匹配 | ||
- [ ] Cypher Edge 正则匹配 | ||
- [ ] Cypher MATCH 语句正则匹配 | ||
- [ ] Cypher Node 字符串拼接 | ||
- [ ] Cypher Edge 字符串拼接 | ||
- [ ] Cypher MATCH 字符串拼接 | ||
1. **Graph Data**: You pass graph data (`nodes` and `edges`) to the `previewGraph` prop, allowing the component to visualize the graph schema. | ||
2. **Callback**: The `onClick` prop is used to handle changes in graph pattern selection, such as when the user defines a `MATCH` or `WHERE` condition. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Vite + React + TS</title> | ||
</head> | ||
<body style="margin: unset"> | ||
<div id="root"></div> | ||
<script type="module" src="/src/main.tsx"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { DrawPattern } from '.'; | ||
import { defaultEdges, defaultNodes } from './data'; | ||
|
||
|
||
function App() { | ||
return ( | ||
<div style={{ height: '100vh' }}> | ||
<DrawPattern | ||
previewGraph={{ | ||
// @ts-ignore | ||
nodes: defaultNodes, | ||
edges: defaultEdges, | ||
}} | ||
/> | ||
</div> | ||
); | ||
} | ||
|
||
export default App; |
120 changes: 120 additions & 0 deletions
120
packages/studio-draw-pattern/src/components/Canvas/PopoverContent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import { Form, Input, Button, Row, Col, Table, Select } from 'antd'; | ||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons'; | ||
import { Property } from '../../types/property'; | ||
import { usePropertiesStore } from '../../stores/usePropertiesStore'; | ||
|
||
interface PopoverContentProps { | ||
currentId?: string; | ||
onChange?: (value: { currentId: string; properties: Property[] }) => void; | ||
} | ||
|
||
const PopoverContent: React.FC<PopoverContentProps> = ({ currentId, onChange }) => { | ||
const properties = usePropertiesStore(state => state.properties); | ||
const [items, setItems] = useState<Property[]>(properties.find(item => item.belongId === currentId)?.data ?? []); | ||
|
||
useEffect(() => { | ||
console.log('id change', currentId); | ||
}, [currentId]); | ||
|
||
useEffect(() => { | ||
onChange && onChange({ currentId: currentId ?? '', properties: items }); | ||
}, [items, currentId]); | ||
|
||
const addItem = () => { | ||
setItems([...items, { id: Date.now().toString(), name: '', compare: '', value: '' }]); | ||
}; | ||
|
||
const removeItem = (id: string) => { | ||
const newItems = items.filter(item => item.id !== id); | ||
setItems(newItems); | ||
}; | ||
|
||
const handleChange = (id: string, key: keyof Property, value: string) => { | ||
const newItems = items.map(item => (item.id === id ? { ...item, [key]: value } : item)); | ||
setItems(newItems); | ||
}; | ||
|
||
const columns = [ | ||
{ | ||
title: 'Name', | ||
dataIndex: 'name', | ||
render: (_: any, record: Property) => ( | ||
<Input | ||
placeholder="Name" | ||
value={record.name} | ||
onChange={e => handleChange(record.id, 'name', e.target.value)} | ||
style={{ width: '100%' }} | ||
/> | ||
), | ||
width: '35%', | ||
}, | ||
{ | ||
title: 'Compare', | ||
dataIndex: 'compare', | ||
render: (_: any, record: Property) => ( | ||
<Select | ||
defaultValue={record.compare} | ||
onChange={value => handleChange(record.id, 'compare', value)} | ||
style={{ width: '100%' }} | ||
options={[ | ||
{ value: '>', label: '>' }, | ||
{ value: '=', label: '=' }, | ||
{ value: '<', label: '<' }, | ||
{ value: '>=', label: '>=' }, | ||
{ value: '<=', label: '<=' }, | ||
]} | ||
className="nospan nodrag" | ||
// @ts-ignore | ||
getPopupContainer={() => document.getElementById(currentId!)} | ||
/> | ||
), | ||
width: '20%', | ||
}, | ||
{ | ||
title: 'Value', | ||
dataIndex: 'value', | ||
render: (_: any, record: Property) => ( | ||
<Input | ||
placeholder="Value" | ||
value={record.value} | ||
onChange={e => handleChange(record.id, 'value', e.target.value)} | ||
style={{ width: '100%' }} | ||
/> | ||
), | ||
width: '35%', | ||
}, | ||
{ | ||
title: 'Actions', | ||
dataIndex: 'actions', | ||
render: (_: any, record: Property) => ( | ||
<Button type="text" icon={<DeleteOutlined />} onClick={() => removeItem(record.id)} /> | ||
), | ||
width: '10%', | ||
}, | ||
]; | ||
|
||
return ( | ||
<Form layout="vertical"> | ||
<Row justify="space-between" align="middle" style={{ marginBottom: 16 }}> | ||
<Col> | ||
<h3>Properties</h3> | ||
</Col> | ||
<Col> | ||
<Button type="primary" icon={<PlusOutlined />} onClick={addItem}> | ||
Add | ||
</Button> | ||
</Col> | ||
</Row> | ||
<Table | ||
columns={columns} | ||
dataSource={items} | ||
pagination={false} | ||
rowKey="id" // 使用唯一的 id 作为 rowKey | ||
bordered | ||
/> | ||
</Form> | ||
); | ||
}; | ||
|
||
export default PopoverContent; |
Oops, something went wrong.