Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore: Add a graph application marketplace to build user use cases #489

Merged
merged 3 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/graph-apps/.fatherrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default {
esm: { output: 'es' },
cjs: { output: 'lib' },
};
1 change: 1 addition & 0 deletions examples/graph-apps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Graph Apps
18 changes: 18 additions & 0 deletions examples/graph-apps/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Graph Apps</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="root" style="height: 100vh"></div>
<script type="module" src="./src/index.tsx"></script>
</body>
</html>
45 changes: 45 additions & 0 deletions examples/graph-apps/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "@graphscope/graph-apps",
"version": "0.1.1",
"description": "",
"main": "lib/index.js",
"module": "es/index.js",
"types": "lib/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/GraphScope/portal.git"
},
"files": [
"es",
"lib",
"dist"
],
"scripts": {
"start": "father dev",
"build": "father build",
"start:site": "vite dev",
"build:site": "vite build"
},
"dependencies": {
"@graphscope/studio-components": "workspace:*",
"@graphscope/studio-graph": "workspace:*",
"@graphscope/studio-importor": "workspace:*",
"@graphscope/studio-query": "workspace:*",
"d3-force": "latest",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-intl": "^6.6.8",
"react-router-dom": "^6.26.1",
"typewriter-effect": "^2.21.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.1",
"vite": "^5.0.12"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"author": "",
"license": "ISC"
}
9 changes: 9 additions & 0 deletions examples/graph-apps/src/fraud-detection/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as React from 'react';

interface IFraudDetectionProps {}

const FraudDetection: React.FunctionComponent<IFraudDetectionProps> = props => {
return <div>FraudDetection</div>;
};

export default FraudDetection;
9 changes: 9 additions & 0 deletions examples/graph-apps/src/graph-learning/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as React from 'react';

interface IGraphLearningProps {}

const GraphLearning: React.FunctionComponent<IGraphLearningProps> = props => {
return <div>Graph Learning case</div>;
};

export default GraphLearning;
154 changes: 154 additions & 0 deletions examples/graph-apps/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import ReactDOM from 'react-dom/client';
import React, { Suspense } from 'react';
import { BrowserRouter, Routes, Route, Outlet, Navigate, useNavigate } from 'react-router-dom';
import { Flex, Card, Typography, Divider, Tag } from 'antd';
import { ConfigProvider, Skeleton, Space, Button } from 'antd';
import { GithubOutlined, ReadOutlined } from '@ant-design/icons';
// import locales from '../locales';
// import { IntlProvider } from 'react-intl';
import PaperReading from './paper-reading';

interface IPagesProps {}

const APP_INFO = [
{
name: 'Graph Data Query Scenarios',
description:
'Using powerful query languages like Cypher and Gremlin, enabling you to extract meaningful insights from complex networks of interconnected data',
icon: 'https://www.connectedpapers.com/img/ScienceMapping.2218dc18.png',
category: 'Graph Database',
link: '/paper-reading',
dataset: 'https://github.com/csuvis/CyberAssetGraphData',
github: '',
},

{
name: 'Discover Network Vulnerability Risks',
description:
'Identify Network Vulnerability Risks by detecting weaknesses and exposures in network infrastructure, enabling proactive security measures to prevent potential threats and safeguard critical systems.',
icon: 'https://www.connectedpapers.com/img/ScienceMapping.2218dc18.png',
category: 'Cyber Security',
link: '/paper-reading',
dataset: 'https://github.com/csuvis/CyberAssetGraphData',
github: '',
},
{
name: 'Paper Discovery',
description:
'Discover the connections between papers by exploring how research builds upon existing knowledge, linking studies through shared references, methodologies, and findings to create a comprehensive view of academic contributions.',
icon: 'https://www.connectedpapers.com/img/ScienceMapping.2218dc18.png',
link: '/paper-reading',
category: 'Knowledge Graph',
dataset: 'https://github.com/csuvis/CyberAssetGraphData',
},
{
name: 'GitHub Collaboration Network',
description:
'Explore the GitHub Collaboration Network, where developers connect, share code, and collaborate on projects to drive innovation and solve complex problems together.',
icon: 'https://www.connectedpapers.com/img/ScienceMapping.2218dc18.png',
link: '/paper-reading',
category: 'Social Network',
dataset: 'https://github.com/csuvis/CyberAssetGraphData',
},
];
const Home = () => {
const navigate = useNavigate();
return (
<Flex justify="center" gap={24} style={{ padding: '80px' }} vertical align="center">
<Typography.Title level={1}>Discover More Graph Applications and Inspire Innovation</Typography.Title>
<Divider />
<Flex justify="center" gap={48} wrap>
{APP_INFO.map((item, index) => {
return (
<Card
hoverable
bordered={false}
key={item.link}
style={{ width: '400px' }}
styles={{
body: {
padding: '24px 24px 8px 24px',
},
}}
cover={
<img
alt="example"
src={item.icon}
onClick={() => {
navigate(item.link);
}}
/>
}
>
<Typography.Title style={{ margin: '0px' }} level={5}>
{item.name}
</Typography.Title>

<Typography.Paragraph ellipsis={{ rows: 3 }} type="secondary">
{item.description}
</Typography.Paragraph>
<Divider style={{ margin: '0px', marginBottom: '8px' }}></Divider>
<Flex align="center" justify="space-between">
<Tag color="geekblue">{item.category}</Tag>
<Space size={0}>
<Button type="text" icon={<GithubOutlined />} onClick={() => navigate(item.github || '')}></Button>
<Button type="text" icon={<ReadOutlined />} onClick={() => navigate(item.github || '')}></Button>
</Space>
</Flex>
</Card>
);
})}
</Flex>
</Flex>
);
};
const routes = [
{ path: '/', component: Home },
{ path: '/paper-reading', component: React.lazy(() => import('./paper-reading')) },
];

const GraphApps: React.FunctionComponent<IPagesProps> = props => {
// const locale = 'en-US';
// const messages = locales[locale];
const routeComponents = routes.map(({ path, component: Component }, index) => {
return (
<Route
key={index}
path={path}
element={
<Suspense fallback={<></>}>
{/** @ts-ignore */}
<Component />
</Suspense>
}
/>
);
});

return (
<ConfigProvider
// direction="rtl"
theme={{
components: {
Menu: {
itemSelectedBg: '#ececec',
itemSelectedColor: '#191919',
collapsedWidth: 50,
collapsedIconSize: 14,
},
},
}}
>
{/* <IntlProvider messages={messages} locale={locale}> */}
<BrowserRouter>
<Routes>{routeComponents}</Routes>
</BrowserRouter>
{/* </IntlProvider> */}
</ConfigProvider>
);
};

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(<GraphApps />);

export { PaperReading, GraphApps };
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import * as React from 'react';
import { useContext } from '@graphscope/studio-graph';
import { Typography, Flex } from 'antd';
import useHover from './useHover';
interface IPaperListProps {}

const Item = props => {
const { title, authors, published } = props;
const date = new Date(published);
const [isHovered, hoverRef] = useHover();
console.log('isHovered', isHovered);
const style = {
background: isHovered ? '#f0f0f0' : 'transparent',
cursor: 'pointer',
};

return (
<Flex
justify="space-between"
vertical
gap={8}
style={{ borderBottom: '1px solid #ccc', padding: '8px', ...style }}
//@ts-ignore
ref={hoverRef}
>
<Typography.Text>{title}</Typography.Text>
<Flex justify="space-between" align="center" flex={1}>
<Typography.Paragraph ellipsis={{ rows: 4 }} style={{ maxWidth: '260px' }} type="secondary">
{authors}
</Typography.Paragraph>
<Typography.Text type="secondary">{date.toLocaleDateString()}</Typography.Text>
</Flex>
</Flex>
);
};
const PaperList: React.FunctionComponent<IPaperListProps> = props => {
const { store } = useContext();
const { data } = store;
const { nodes = [] } = data;

return (
<Flex justify="space-between" vertical style={{ height: '100%', overflowY: 'scroll' }}>
{nodes.map(item => {
const { properties } = item;

return <Item {...properties} />;
})}
</Flex>
);
};

export default PaperList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useState, useCallback, useRef, useEffect } from 'react';

/**
* useHover hook
* @returns {Array} [isHovered, hoverRef]
*/
function useHover() {
const [isHovered, setIsHovered] = useState(false);
const ref = useRef<HTMLDivElement>(null);

const handleMouseEnter = useCallback(() => setIsHovered(true), []);
const handleMouseLeave = useCallback(() => setIsHovered(false), []);

// Add event listeners when the component mounts and clean them up on unmount
useEffect(() => {
const node = ref.current;
if (node) {
node.addEventListener('mouseenter', handleMouseEnter);
node.addEventListener('mouseleave', handleMouseLeave);

return () => {
node.removeEventListener('mouseenter', handleMouseEnter);
node.removeEventListener('mouseleave', handleMouseLeave);
};
}
}, [handleMouseEnter, handleMouseLeave]);

return [isHovered, ref];
}

export default useHover;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as React from 'react';
import { Input } from 'antd';
import { SearchOutlined } from '@ant-design/icons';
interface ISearchbarProps {}

const Searchbar: React.FunctionComponent<ISearchbarProps> = props => {
return (
<div style={{ display: 'flex', flex: 1, width: '100%' }}>
<Input
variant="borderless"
placeholder="Search for a paper..."
style={{ width: '100%' }}
suffix={
<SearchOutlined
style={
{
// color: 'rgba(0,0,0,.45)'
}
}
/>
}
/>
</div>
);
};

export default Searchbar;
5 changes: 5 additions & 0 deletions examples/graph-apps/src/paper-reading/components/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Searchbar from './Searchbar';
import PaperList from './PaperList';
import FetchGraph from './FetchGraph';

export { Searchbar, PaperList, FetchGraph };
Loading