Skip to content

Commit ea1110a

Browse files
authored
Merge pull request #667 from GraphScope/add-table-view
feat: Add TableView & Add LayoutSetting
2 parents aa76664 + 063f018 commit ea1110a

File tree

24 files changed

+670
-104
lines changed

24 files changed

+670
-104
lines changed

.dumirc.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { defineConfig } from 'dumi';
22
import { join } from 'path';
33
import { defineThemeConfig } from 'dumi-theme-antd/dist/defineThemeConfig';
4+
import { Divider } from 'antd';
45

56
const isProduction = process.env.NODE_ENV === 'production';
67
const basePath = isProduction ? '/portal/' : '/';
78

89
const themeConfig = defineThemeConfig({
9-
name: 'GraphScope',
10+
name: '| Portal',
1011
title: 'GraphScope Portal',
11-
logo: 'https://img.alicdn.com/imgextra/i4/O1CN01uhy1Yu1lO7HkUaW3K_!!6000000004808-2-tps-256-257.png',
12+
logo: 'https://img.alicdn.com/imgextra/i4/O1CN012GxzhO1h3j6rsmvuQ_!!6000000004222-2-tps-1890-453.png',
1213
lastUpdated: true,
1314
nav: {
1415
'zh-CN': [

examples/graphy/src/pages/dataset/cluster/graph.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,7 @@ const ClusterGraph: React.FunctionComponent<QueryGraphProps> = props => {
9494
<GraphProvider id="cluster-graph">
9595
<Section
9696
splitBorder
97-
rightSide={
98-
<PropertiesPanel>
99-
<SegmentedTabs items={items} block />
100-
</PropertiesPanel>
101-
}
97+
rightSide={<SegmentedTabs items={items} block />}
10298
autoResize={false}
10399
rightSideStyle={{
104100
width: '350px',
@@ -112,6 +108,7 @@ const ClusterGraph: React.FunctionComponent<QueryGraphProps> = props => {
112108
<ClearStatus />
113109

114110
<BasicInteraction />
111+
<PropertiesPanel />
115112
<Loading />
116113
<Toolbar style={{ position: 'absolute', top: '20px', right: '20px', left: 'unset' }}>
117114
<ToogleButton />

packages/studio-explore/src/app.tsx

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
LayoutSwitch,
2929
ZoomStatus,
3030
registerIcons,
31+
LayoutSetting,
3132
} from '@graphscope/studio-graph';
3233

3334
import { ToogleLeftButton, ToogleRightButton } from './components/ToggleButton';
@@ -51,9 +52,13 @@ import {
5152
GroupOutlined,
5253
CodeOutlined,
5354
CodeTwoTone,
55+
TabletOutlined,
56+
BranchesOutlined,
57+
CopyrightOutlined,
5458
} from '@ant-design/icons';
5559
import { Divider, Flex, theme, Segmented, Tabs, Typography } from 'antd';
5660
import { getDefaultServices } from './services';
61+
import TableView from './components/TableView';
5762

5863
interface ExploreProps {
5964
id?: string;
@@ -117,7 +122,7 @@ const Explore: React.FunctionComponent<ExploreProps> = props => {
117122
<FetchGraph />
118123
<Placeholder />
119124
<Loading />
120-
<PropertiesPanel />
125+
<PropertiesPanel style={{ right: '12px' }} />
121126
<FloatTabs
122127
searchbar={<Searchbar />}
123128
direction="vertical"
@@ -128,23 +133,36 @@ const Explore: React.FunctionComponent<ExploreProps> = props => {
128133
children: <Statistics />,
129134
key: 'Statistics',
130135
},
136+
{
137+
label: <Typography.Title level={3}>Table View</Typography.Title>,
138+
icon: <TableOutlined />,
139+
children: <TableView />,
140+
key: 'TableView',
141+
},
131142
{
132143
label: <Typography.Title level={3}>Cluster Analysis</Typography.Title>,
133-
icon: <GroupOutlined />,
144+
icon: <CopyrightOutlined />,
134145
children: <ClusterAnalysis />,
135146
key: 'ClusterAnalysis',
136147
},
148+
149+
{
150+
label: <Typography.Title level={3}>Cypher Query</Typography.Title>,
151+
icon: <CodeOutlined />,
152+
children: <CypherQuery />,
153+
key: 'CypherQuery',
154+
},
137155
{
138156
label: <Typography.Title level={3}>Style Setting</Typography.Title>,
139157
icon: <BgColorsOutlined />,
140158
children: <StyleSetting />,
141159
key: 'StyleSetting',
142160
},
143161
{
144-
label: <Typography.Title level={3}>Cypher Query</Typography.Title>,
145-
icon: <CodeOutlined />,
146-
children: <CypherQuery />,
147-
key: 'CypherQuery',
162+
label: <Typography.Title level={3}>Layout Setting</Typography.Title>,
163+
icon: <BranchesOutlined />,
164+
children: <LayoutSetting />,
165+
key: 'LayoutSetting',
148166
},
149167
]}
150168
tools={
@@ -155,10 +173,8 @@ const Explore: React.FunctionComponent<ExploreProps> = props => {
155173
<ZoomFit />
156174
<Brush />
157175
<FixedMode />
158-
<Divider style={{ margin: '0px' }} />
159-
<CurvatureLinks />
160-
<DagreMode />
161-
<LayoutSwitch />
176+
{/* <Divider style={{ margin: '0px' }} />
177+
<CurvatureLinks /> */}
162178
<Divider style={{ margin: '0px' }} />
163179
<SwitchEngine />
164180
<RunCluster />

packages/studio-explore/src/components/CypherQuery/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ const CypherQuery: React.FunctionComponent<IStatementQueryProps> = props => {
2222
return (
2323
<Flex vertical gap={12}>
2424
<Typography.Text italic>You can write Cypher queries here to retrieve data.</Typography.Text>
25-
<Input.TextArea rows={10} ref={inputRef} defaultValue={`Match (n) return n limit 100`}></Input.TextArea>
25+
<Input.TextArea
26+
rows={10}
27+
ref={inputRef}
28+
defaultValue={`Match (a)-[r]-(b) return a,r,b limit 100`}
29+
></Input.TextArea>
2630
<Space>
2731
<Button icon={<PlayCircleOutlined />} block onClick={handleQuery}>
2832
Query

packages/studio-explore/src/components/FloatTabs/index.tsx

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import * as React from 'react';
22
import { Button, Flex, Divider, theme, Typography } from 'antd';
33
import { Icons } from '@graphscope/studio-components';
4-
import { CaretLeftOutlined, CaretDownOutlined } from '@ant-design/icons';
4+
import { CaretLeftOutlined, CaretDownOutlined, ColumnWidthOutlined, PauseOutlined } from '@ant-design/icons';
55
import { Toolbar } from '@graphscope/studio-components';
6+
import useResizeWidth from './useResizeWidth';
67
interface IFloatTabsProps {
78
direction?: 'vertical' | 'horizontal';
89
posotion?: 'left' | 'right' | 'top' | 'bottom';
@@ -48,7 +49,7 @@ const getRootStyle = (
4849
...directionStyle,
4950
top: '0px',
5051
right: '0px',
51-
width: '400px',
52+
width: 300 + 100,
5253
};
5354
}
5455
// if (position === 'right') {
@@ -67,6 +68,8 @@ const FloatTabs: React.FunctionComponent<IFloatTabsProps> = props => {
6768
activeKey: items[0].key,
6869
});
6970
const { visible } = state;
71+
const { width: panelWidth, handleMouseDown: handleResizeStart } = useResizeWidth(300);
72+
7073
const handleToggle = () => {
7174
setState(preState => {
7275
return {
@@ -88,15 +91,17 @@ const FloatTabs: React.FunctionComponent<IFloatTabsProps> = props => {
8891
const panelStyle: React.CSSProperties =
8992
direction === 'vertical'
9093
? {
91-
width: visible ? '300px' : '0px',
94+
width: visible ? (panelWidth as number) : '0px',
9295
overflowY: 'scroll',
9396
// transition: 'all 0.3s ease-in-out',
9497
background: token.colorBgContainer,
9598
boxShadow: token.boxShadow,
9699
padding: visible ? 12 : 0,
97100
borderRadius: token.borderRadius,
101+
position: 'relative',
98102
}
99103
: {
104+
position: 'relative',
100105
maxHeight: visible ? (posotion === 'bottom' ? '300px' : 'unset') : 0,
101106
// height: visible ? '300px' : '0px',
102107
overflowY: 'scroll',
@@ -112,15 +117,16 @@ const FloatTabs: React.FunctionComponent<IFloatTabsProps> = props => {
112117
? {
113118
position: 'absolute',
114119
top: '12px',
115-
left: visible ? '400px' : '66px',
120+
left: visible ? panelWidth + 100 : '66px',
116121
width: 500,
117122
}
118123
: {
119124
position: 'absolute',
120125
top: '12px',
121-
right: visible ? '400px' : '66px',
126+
right: visible ? panelWidth + 100 : '66px',
122127
width: 500,
123128
};
129+
124130
return (
125131
<Flex
126132
style={{
@@ -194,6 +200,17 @@ const FloatTabs: React.FunctionComponent<IFloatTabsProps> = props => {
194200
</Flex>
195201

196202
<Flex vertical style={panelStyle}>
203+
<div
204+
onMouseDown={handleResizeStart}
205+
style={{
206+
position: 'absolute',
207+
right: '0px',
208+
top: '0px',
209+
bottom: '0px',
210+
width: '12px',
211+
cursor: 'ew-resize',
212+
}}
213+
></div>
197214
{items.map(item => {
198215
const { key, children, label } = item;
199216
const isActive = key === state.activeKey;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { useState, useEffect, useRef } from 'react';
2+
3+
function useResizeWidth(initialWidth = 200) {
4+
const [width, setWidth] = useState(initialWidth);
5+
const isResizingRef = useRef(false);
6+
const startXRef = useRef(0);
7+
const startWidthRef = useRef(initialWidth);
8+
9+
// Throttling function to limit the frequency of state updates
10+
const throttle = (fn, delay) => {
11+
let lastCall = 0;
12+
return (...args) => {
13+
const now = new Date().getTime();
14+
if (now - lastCall < delay) {
15+
return;
16+
}
17+
lastCall = now;
18+
fn(...args);
19+
};
20+
};
21+
22+
const handleMouseDown = event => {
23+
isResizingRef.current = true;
24+
startXRef.current = event.clientX;
25+
startWidthRef.current = width;
26+
};
27+
28+
const handleMouseMove = throttle(event => {
29+
if (!isResizingRef.current) return;
30+
31+
const dx = event.clientX - startXRef.current;
32+
const newWidth = Math.max(100, startWidthRef.current + dx); // Minimum width of 100px
33+
34+
if (newWidth !== width) {
35+
setWidth(newWidth);
36+
}
37+
}, 16); // Approximately 60 FPS
38+
39+
const handleMouseUp = () => {
40+
isResizingRef.current = false;
41+
};
42+
43+
useEffect(() => {
44+
window.addEventListener('mousemove', handleMouseMove);
45+
window.addEventListener('mouseup', handleMouseUp);
46+
47+
return () => {
48+
window.removeEventListener('mousemove', handleMouseMove);
49+
window.removeEventListener('mouseup', handleMouseUp);
50+
};
51+
}, [handleMouseMove, handleMouseUp]);
52+
53+
return { width, handleMouseDown };
54+
}
55+
56+
export default useResizeWidth;

packages/studio-explore/src/components/Next/Neighbors/TableView.tsx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import React, { useEffect, useState } from 'react';
2-
import { Flex, theme, Table, Typography, Button, Space } from 'antd';
2+
import { Flex, theme, Table, Typography, Button, Space, Tooltip } from 'antd';
33

44
import { getTable } from './getTableData';
55

66
import type { TableColumnsType, TableProps } from 'antd';
77
import { NodeData } from '@graphscope/studio-graph';
88
import { PlayCircleOutlined } from '@ant-design/icons';
9-
import { FullScreen } from '@graphscope/studio-components';
9+
import { FullScreen, Utils } from '@graphscope/studio-components';
10+
import AdjustColumns, { getTableColumns } from '../../TableView/AdjustColumns';
1011

1112
export interface IPropertiesPanelProps {
1213
items: NodeData[];
@@ -22,6 +23,23 @@ const TableView: React.FunctionComponent<IPropertiesPanelProps> = props => {
2223
const defaultSelectedRowKeys = dataSource.map(item => item.key);
2324
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>(defaultSelectedRowKeys);
2425
// const containerRef = React.useRef<HTMLDivElement>(null);
26+
27+
/** filter cloumns */
28+
const [state, setState] = useState({
29+
columnIds: (Utils.storage.get('explore_table_view_column_ids') as string[]) || columns.map(item => item.key),
30+
});
31+
const { columnIds } = state;
32+
const tableColumns = getTableColumns(columnIds);
33+
const handleChangeColumns = value => {
34+
setState(preState => {
35+
return {
36+
...preState,
37+
columnIds: value,
38+
};
39+
});
40+
};
41+
/** filter cloumns end */
42+
2543
useEffect(() => {
2644
const { dataSource } = getTable([...items]);
2745
const defaultSelectedRowKeys = dataSource.map(item => item.key);
@@ -57,7 +75,10 @@ const TableView: React.FunctionComponent<IPropertiesPanelProps> = props => {
5775
Total {counts} data items, {selectedRowKeys.length} selected.
5876
</Typography.Text>
5977
<Space>
60-
<Button icon={<PlayCircleOutlined />} type="text" onClick={handleClick}></Button>
78+
<Tooltip title="Appand selected items to the graph">
79+
<Button icon={<PlayCircleOutlined />} type="text" onClick={handleClick}></Button>
80+
</Tooltip>
81+
<AdjustColumns onChange={handleChangeColumns} />
6182
<FullScreen containerRef={containerRef} />
6283
</Space>
6384
</Flex>
@@ -70,7 +91,7 @@ const TableView: React.FunctionComponent<IPropertiesPanelProps> = props => {
7091
}}
7192
// pagination={false}
7293
dataSource={dataSource}
73-
columns={columns}
94+
columns={tableColumns}
7495
bordered
7596
scroll={{ x: 'max-content' }}
7697
/>

packages/studio-explore/src/components/Searchbar/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ const Searchbar: React.FunctionComponent<ISearchbarProps> = props => {
174174
});
175175
const data = await getService<IQuerySearch>('querySearch')({
176176
config: breadcrumb,
177-
value: '',
177+
value: state.words,
178178
});
179179

180180
updateStore(draft => {

0 commit comments

Comments
 (0)