Skip to content

Commit

Permalink
Merge pull request #475 from BQXBQX/main
Browse files Browse the repository at this point in the history
feat: draw-pattern section
  • Loading branch information
pomelo-nwu authored Oct 9, 2024
2 parents e8b1066 + cab66b9 commit e750ea6
Show file tree
Hide file tree
Showing 81 changed files with 4,133 additions and 434 deletions.
3 changes: 2 additions & 1 deletion packages/studio-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"react-resizable-panels": "^2.0.20",
"sql-ddl-to-json-schema": "latest",
"typewriter-effect": "^2.21.0",
"uuid": "latest"
"uuid": "latest",
"uuidv4": "latest"
},
"publishConfig": {
"access": "public",
Expand Down
121 changes: 80 additions & 41 deletions packages/studio-draw-pattern/README.md
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.
13 changes: 13 additions & 0 deletions packages/studio-draw-pattern/index.html
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>
32 changes: 23 additions & 9 deletions packages/studio-draw-pattern/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
"dev": "father dev",
"build": "father build",
"build:deps": "father prebundle",
"prepublishOnly": "father doctor && npm run build"
"prepublishOnly": "father doctor && npm run build",
"start:site": "vite dev",
"build:site": "vite build",
"test": "vitest",
"ci": "cd ../studio-components && npm run build && cd ../studio-draw-pattern && npm run build:site "
},
"keywords": [],
"authors": [],
Expand All @@ -23,16 +27,26 @@
},
"devDependencies": {
"@swc/core": "^1.7.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/lodash": "^4.14.202",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/uuid": "^9.0.8",
"@vitejs/plugin-react": "^4.3.1",
"father": "^4.4.5",
"typescript": "^5.5.4"
},
"peerDependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
"typescript": "^5.5.4",
"vite": "^5.4.3",
"vitest": "^2.0.5"
},
"dependencies": {
"valtio": "^1.13.2"
"@ant-design/icons": "^5.2.6",
"@graphscope/studio-components": "workspace:*",
"@graphscope/studio-graph-editor": "workspace:*",
"antd": "^5.17.0",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"rxjs": "^7.8.1",
"uuid": "^10.0.0",
"zustand": "^4.5.5"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions packages/studio-draw-pattern/src/App.tsx
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 packages/studio-draw-pattern/src/components/Canvas/PopoverContent.tsx
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;
Loading

0 comments on commit e750ea6

Please sign in to comment.