Skip to content

Commit

Permalink
feat(gi-sdk): slot-driven component tree rendering and global state m…
Browse files Browse the repository at this point in the history
…anagement enhancements (#542)

* feat: slot-driven component tree rendering

* feat: support global state management

* feat: graph store

* feat: dataset store

* fix: fix cr issue that nested useCallback and useState for widget rendering
  • Loading branch information
yvonneyx authored Jul 26, 2024
1 parent e927ccb commit c17d91c
Show file tree
Hide file tree
Showing 81 changed files with 5,635 additions and 444 deletions.
19 changes: 15 additions & 4 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
plugins: [
require.resolve('prettier-plugin-organize-imports'),
require.resolve('prettier-plugin-packagejson'),
],
printWidth: 120,
arrowParens: 'avoid',
proseWrap: 'never',
singleQuote: true,
trailingComma: 'all',
overrides: [
{
files: '*.md',
options: {
proseWrap: 'preserve',
},
},
],
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@
"eslint-plugin-jsdoc": "^48.2.7",
"husky": "^9.0.11",
"prettier": "^3.3.0",
"prettier-plugin-organize-imports": "^4.0.0",
"prettier-plugin-packagejson": "^2.5.1",
"typescript": "^5.3.3",
"vite": "^5.0.12"
},
"license": "MIT",

"commitlint": {
"extends": [
"@commitlint/config-conventional"
Expand Down
2 changes: 1 addition & 1 deletion packages/gi-sdk/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ dist
es
lib
node_modules
tests
tests
20 changes: 20 additions & 0 deletions packages/gi-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<h1 align="center">GISDK</h1>

<div align="center">

SDK for Graph Insight App.

## 🔨 快速使用

```jsx | pure
import React from 'react';
import { GISDK } from '@antv/gi-sdk';
import { myAssetPackage } from './assets';
import { config } from './config';

export default () => {
const assets = [myAssetPackage];

return <GISDK className="my-graph-application" style={{ height: '80vh' }} config={config} assets={assets}></GISDK>;
};
```
32 changes: 32 additions & 0 deletions packages/gi-sdk/docs/assets/CustomCanvasComponent/Component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { CanvasEvent, NodeEvent } from '@antv/g6';
import type { ImplementWidgetProps } from '@antv/gi-sdk';
import { useGlobalModel, useGraph } from '@antv/gi-sdk';
import React, { useEffect } from 'react';

export const CustomCanvasComponent: React.FC<ImplementWidgetProps> = () => {
const [, setGlobalModel] = useGlobalModel();
const [graph] = useGraph();

useEffect(() => {
if (!graph || graph.destroyed) return;

const clickNode = (e) => {
const nodeId = e.target.id;
setGlobalModel({ currentNode: graph?.getNodeData(nodeId), panel: true });
};

const clickCanvas = () => {
setGlobalModel({ currentNode: null, panel: false });
};

graph.on(NodeEvent.CLICK, clickNode);
graph.on(CanvasEvent.CLICK, clickCanvas);

return () => {
graph.off(NodeEvent.CLICK, clickNode);
graph.off(CanvasEvent.CLICK, clickCanvas);
};
}, [graph]);

return null;
};
12 changes: 12 additions & 0 deletions packages/gi-sdk/docs/assets/CustomCanvasComponent/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { ImplementWidget, ImplementWidgetProps } from '@antv/gi-sdk';
import { CustomCanvasComponent as CustomCanvasComponent2 } from './Component';

export const CustomCanvasComponent: ImplementWidget<ImplementWidgetProps> = {
version: 'v0.1',
metadata: {
name: 'CustomCanvasComponent',
displayName: '自定义图表组件',
description: '这是一个自定义图表组件',
},
component: CustomCanvasComponent2,
};
24 changes: 24 additions & 0 deletions packages/gi-sdk/docs/assets/CustomPanel/Component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ImplementWidgetProps, useGlobalModel } from '@antv/gi-sdk';
import React from 'react';
import { fontStyle } from '../../constant';

export interface CustomPanelProps extends ImplementWidgetProps {
count: number;
}

export const CustomPanel: React.FC<CustomPanelProps> = (props) => {
const { count } = props;
const [{ currentNode }] = useGlobalModel();

const isSiderOpen = true;

return (
<div>
<p style={fontStyle}>{count}...</p>
<p>Sider {isSiderOpen ? <b style={fontStyle}>opened</b> : <b style={fontStyle}>closed</b>}</p>
<p>
current node: <b style={fontStyle}>{currentNode?.id}</b>
</p>
</div>
);
};
16 changes: 16 additions & 0 deletions packages/gi-sdk/docs/assets/CustomPanel/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ImplementWidget } from '@antv/gi-sdk';
import type { CustomPanelProps } from './Component';
import { CustomPanel as CustomPanelComponent } from './Component';

export const CustomPanel: ImplementWidget<CustomPanelProps> = {
version: 'v0.1',
metadata: {
name: 'CustomPanel',
displayName: '自定义面板',
description: '这是一个自定义面板',
},
component: CustomPanelComponent,
defaultProperties: {
count: 200,
},
};
41 changes: 41 additions & 0 deletions packages/gi-sdk/docs/assets/CustomSiderbar/Component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { ImplementWidgetProps } from '@antv/gi-sdk';
import { useGlobalModel, useGraphOptions, useWidgetProps } from '@antv/gi-sdk';
import { Button } from 'antd';
import React from 'react';
import { fontStyle } from '../../constant';

export const CustomSidebar: React.FC<ImplementWidgetProps> = (props) => {
const { slotElements } = props;
const [{ panel }, setGlobalModel] = useGlobalModel();
const [, updatePanelProperties] = useWidgetProps('custom-panel');
const [, updateOptions] = useGraphOptions();

const openPanel = () => {
setGlobalModel({ panel: true });
};

return (
<div>
<p>Sider</p>
<p>
Panel <b style={fontStyle}>{panel ? 'opened' : 'closed'}</b>
</p>
<Button onClick={openPanel}>Open Panel</Button>
<Button
onClick={() => {
updatePanelProperties({ count: Math.floor(Math.random() * 1000) });
}}
>
Change panel Count
</Button>
<b style={fontStyle}>{slotElements.default}</b>
<Button
onClick={() => {
updateOptions((options) => ({ ...options, layout: { type: 'dagre' } }));
}}
>
Change Layout
</Button>
</div>
);
};
12 changes: 12 additions & 0 deletions packages/gi-sdk/docs/assets/CustomSiderbar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { ImplementWidget, ImplementWidgetProps } from '@antv/gi-sdk';
import { CustomSidebar as CustomSidebarComponent } from './Component';

export const CustomSidebar: ImplementWidget<ImplementWidgetProps> = {
version: 'v0.1',
metadata: {
name: 'CustomSidebar',
displayName: '自定义右侧栏',
description: '这是一个自定义右侧栏',
},
component: CustomSidebarComponent,
};
Empty file.
27 changes: 27 additions & 0 deletions packages/gi-sdk/docs/assets/MyAppLayout/Component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { GraphContainer, type ImplementWidgetProps } from '@antv/gi-sdk';
import React from 'react';
import { PREFIX } from '../../constant';
import { Header, Panel, Sider } from './components';

type Slot = 'header' | 'sider' | 'panel' | 'canvas';

export interface MyAppLayoutProps extends ImplementWidgetProps<Slot> {
showHeader: boolean;
}

export const MyAppLayout: React.FC<MyAppLayoutProps> = (props) => {
const { slotElements, showHeader } = props;

return (
<div className={`${PREFIX}-container`}>
{showHeader && <Header>{slotElements.header}</Header>}
<div className={`${PREFIX}-content`}>
<Sider>{slotElements.sider}</Sider>
<div className={`${PREFIX}-graph-container`}>
<GraphContainer>{slotElements.canvas}</GraphContainer>
</div>
<Panel>{slotElements.panel}</Panel>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import '../../global.less';
@import '../../../../global.less';

.@{prefix}-header {
height: var(--header-height);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { PropsWithChildren } from 'react';
import { PREFIX } from '../../constants';
import { PREFIX } from '../../../../constant';
import './index.less';

export const Header: React.FC<PropsWithChildren> = props => {
export const Header: React.FC<PropsWithChildren> = (props) => {
const { children } = props;

return <div className={`${PREFIX}-header`}>{children}</div>;
Expand Down
3 changes: 3 additions & 0 deletions packages/gi-sdk/docs/assets/MyAppLayout/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { Header } from './header';
export { Panel } from './panel';
export { Sider } from './sider';
21 changes: 21 additions & 0 deletions packages/gi-sdk/docs/assets/MyAppLayout/components/panel/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useGlobalModel } from '@antv/gi-sdk';
import { Drawer } from 'antd';
import React, { PropsWithChildren } from 'react';
import { PREFIX } from '../../../../constant';

export const Panel: React.FC<PropsWithChildren> = (props) => {
const { children } = props;
const [{ panel }, updateGlobalModel] = useGlobalModel();

const onClose = () => {
updateGlobalModel({ panel: false });
};

return (
<div className={`${PREFIX}-panel`}>
<Drawer placement="right" onClose={onClose} open={panel} getContainer={false}>
{children}
</Drawer>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import '../../global.less';
@import '../../../../global.less';

.@{prefix}-sider {
display: flex;
Expand All @@ -11,7 +11,7 @@
height: 100%;
border-right: 1px solid var(--border-color);
}

.@{prefix}-sider-icon {
position: absolute;
width: 24px;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import React, { PropsWithChildren } from 'react';
import { DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons';
import { useGlobalModel } from '@antv/gi-sdk';
import React, { PropsWithChildren } from 'react';
import { CSSTransition } from 'react-transition-group';
import { PREFIX } from '../../constants';
import { useGlobalModel } from '../../context';
import { PREFIX } from '../../../../constant';
import './index.less';

export const Sider: React.FC<PropsWithChildren> = props => {
export const Sider: React.FC<PropsWithChildren> = (props) => {
const { children } = props;
const [globalModel, updateGlobalModel] = useGlobalModel();
const isSiderOpen = Boolean(globalModel.sider);
const [{ sider }, updateGlobalModel] = useGlobalModel();

return (
<React.Fragment>
Expand All @@ -17,13 +16,13 @@ export const Sider: React.FC<PropsWithChildren> = props => {
<div
className={`${PREFIX}-sider-icon`}
onClick={() => {
updateGlobalModel({ sider: !globalModel.sider });
updateGlobalModel({ sider: !sider });
}}
>
{isSiderOpen ? <DoubleLeftOutlined /> : <DoubleRightOutlined />}
{sider ? <DoubleLeftOutlined /> : <DoubleRightOutlined />}
</div>
</div>
<CSSTransition in={isSiderOpen} classNames="fade" timeout={400}>
<CSSTransition in={sider} classNames="fade" timeout={400}>
<div className={`${PREFIX}-sider-content`}>{children}</div>
</CSSTransition>
</div>
Expand Down
16 changes: 16 additions & 0 deletions packages/gi-sdk/docs/assets/MyAppLayout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ImplementWidget } from '@antv/gi-sdk';
import type { MyAppLayoutProps } from './Component';
import { MyAppLayout as MyAppLayoutComponent } from './Component';

export const MyAppLayout: ImplementWidget<MyAppLayoutProps> = {
version: 'v0.1',
metadata: {
name: 'MyAppLayout',
displayName: '我的布局组件',
description: '这是一个布局组件',
},
component: MyAppLayoutComponent,
defaultProperties: {
showHeader: true,
},
};
43 changes: 43 additions & 0 deletions packages/gi-sdk/docs/assets/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { ImplementWidgetProps } from '@antv/gi-sdk';
import { AssetPackage, ImplementWidget } from '@antv/gi-sdk';
import React from 'react';
import { CustomCanvasComponent } from './CustomCanvasComponent';
import { CustomPanel } from './CustomPanel';
import { CustomSidebar } from './CustomSiderbar';
import { MyAppLayout } from './MyAppLayout';

export const CustomHeader: ImplementWidget<ImplementWidgetProps> = {
version: 'v0.1',
metadata: {
name: 'CustomHeader',
displayName: '自定义头部',
description: '这是一个自定义头部',
},
component: () => {
return <h1 style={{ height: 48, lineHeight: '48px', textAlign: 'center' }}>GI-SDK</h1>;
},
};

export const StatisticCard: ImplementWidget = {
version: 'v0.1',
metadata: {
name: 'StatisticCard',
displayName: '统计卡片',
description: '用于展示统计数据的卡片',
},
component: () => {
return <div>StatisticCard</div>;
},
};

export const myAssetPackage: AssetPackage = {
version: 'v0.1',
widgets: [
MyAppLayout,
CustomCanvasComponent,
CustomHeader,
CustomPanel,
CustomSidebar,
StatisticCard,
] as ImplementWidget<ImplementWidgetProps>[],
};
Loading

0 comments on commit c17d91c

Please sign in to comment.