diff --git a/examples/graphy/src/app.tsx b/examples/graphy/src/app.tsx index ff2937f3a..b5d77ec31 100644 --- a/examples/graphy/src/app.tsx +++ b/examples/graphy/src/app.tsx @@ -1,6 +1,46 @@ -import React from 'react'; import ReactDOM from 'react-dom/client'; -import App from './pages'; + +import React, { Suspense, useEffect } from 'react'; +import { Routes, HashRouter, Route } from 'react-router-dom'; + +import { ConfigProvider } from 'antd'; + +import { IntlProvider } from 'react-intl'; +import { ROUTES, locales } from './index'; +import { Layout } from '@graphscope/studio-components'; +import { SIDE_MENU } from './pages/const'; + +interface IPagesProps {} + +const App: React.FunctionComponent = props => { + const locale = 'en-US'; + const messages = locales[locale]; + + return ( + + + + + }> + {ROUTES} + + + + + + ); +}; const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); root.render(); diff --git a/examples/graphy/src/index.tsx b/examples/graphy/src/index.tsx index 19eb27c10..4357a3730 100644 --- a/examples/graphy/src/index.tsx +++ b/examples/graphy/src/index.tsx @@ -1,2 +1,5 @@ import GraphyApp from './pages'; +export { default as locales } from './locales'; +export { default as ROUTES } from './pages'; +export { SIDE_MENU } from './pages/const'; export default GraphyApp; diff --git a/examples/graphy/src/locales/en-US.ts b/examples/graphy/src/locales/en-US.ts index f97c8ebe6..afffc5d55 100644 --- a/examples/graphy/src/locales/en-US.ts +++ b/examples/graphy/src/locales/en-US.ts @@ -3,4 +3,5 @@ export default { Dataset: 'Dataset', Explore: 'Explore', Apps: 'Apps', + Graphy: 'Graphy', }; diff --git a/examples/graphy/src/locales/zh-CN.ts b/examples/graphy/src/locales/zh-CN.ts index a280355cf..57dc4bafb 100644 --- a/examples/graphy/src/locales/zh-CN.ts +++ b/examples/graphy/src/locales/zh-CN.ts @@ -3,4 +3,5 @@ export default { Dataset: '数据集', Explore: '图查询', Apps: '应用商城', + Graphy: 'Graphy', }; diff --git a/examples/graphy/src/pages/const.tsx b/examples/graphy/src/pages/const.tsx index ccfb47439..220c442ee 100644 --- a/examples/graphy/src/pages/const.tsx +++ b/examples/graphy/src/pages/const.tsx @@ -1,19 +1,14 @@ import React, { useState } from 'react'; import { FormattedMessage } from 'react-intl'; -import { SettingFilled, DatabaseOutlined, DeploymentUnitOutlined, AppstoreOutlined } from '@ant-design/icons'; +import { SettingFilled, FilePdfOutlined, DeploymentUnitOutlined, AppstoreOutlined } from '@ant-design/icons'; import { MenuProps } from 'antd'; export const SIDE_MENU: MenuProps['items'] = [ { - label: , + label: , key: '/dataset', - icon: , - }, - { - label: , - key: '/explore', - icon: , + icon: , }, ]; diff --git a/examples/graphy/src/pages/dataset/service.ts b/examples/graphy/src/pages/dataset/service.ts index 6b393d53a..f9b606707 100644 --- a/examples/graphy/src/pages/dataset/service.ts +++ b/examples/graphy/src/pages/dataset/service.ts @@ -1,9 +1,9 @@ -const baseURL = 'http://localhost:9999/api'; import { Utils } from '@graphscope/studio-components'; import { KuzuDriver } from '../../kuzu-driver'; import JSZip from 'jszip'; -const url = new URL(baseURL); -// url.search = new URLSearchParams(params).toString(); + +const baseURL = Utils.storage.get('graphy_endpoint') || 'http://localhost:9999/api'; + export const queryDataset = async () => { return fetch(baseURL + '/dataset', { method: 'GET', diff --git a/examples/graphy/src/pages/index.tsx b/examples/graphy/src/pages/index.tsx index 52c933f76..f9afe6896 100644 --- a/examples/graphy/src/pages/index.tsx +++ b/examples/graphy/src/pages/index.tsx @@ -1,11 +1,5 @@ -import React, { Suspense, useEffect } from 'react'; -import { BrowserRouter, Routes, Route, Navigate, Outlet, HashRouter } from 'react-router-dom'; -import { Layout } from '@graphscope/studio-components'; -import { SIDE_MENU } from './const'; -import { ConfigProvider } from 'antd'; -import locales from '../locales'; -import { IntlProvider } from 'react-intl'; -import PaperReading from '../pages/explore/paper-reading'; +import React, { Suspense } from 'react'; +import { Route, Navigate } from 'react-router-dom'; /** 注册 服务 */ import { registerServices } from '../pages/explore/paper-reading/components/registerServices'; @@ -56,69 +50,24 @@ const routes = [ path: '/dataset/cluster', component: React.lazy(() => import('./dataset/cluster')), }, - { path: '/explore', component: React.lazy(() => import('./explore')) }, ]; -const Apps = () => { - const [isReady, setIsReady] = React.useState(false); - useEffect(() => { - reload().then(res => { - setIsReady(true); - }); - }, []); +const ROUTES = routes.map(({ path, redirect, component: Component }, index) => { + if (redirect) { + return } />; + } return ( - <> - - {isReady && } - + }> + {/** @ts-ignore */} + + + } + /> ); -}; -const Pages: React.FunctionComponent = props => { - const locale = 'en-US'; - const messages = locales[locale]; - const routeComponents = routes.map(({ path, redirect, component: Component }, index) => { - if (redirect) { - return } />; - } - return ( - }> - {/** @ts-ignore */} - - - } - /> - ); - }); +}); - return ( - - - - - }> - {routeComponents} - - } /> - - - - - ); -}; - -export default Pages; +export default ROUTES; diff --git a/packages/studio-components/src/Illustration/DesignSchema.tsx b/packages/studio-components/src/Illustration/DesignSchema.tsx new file mode 100644 index 000000000..5cba3557e --- /dev/null +++ b/packages/studio-components/src/Illustration/DesignSchema.tsx @@ -0,0 +1,139 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const DesignSchema: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default DesignSchema; diff --git a/packages/studio-components/src/Illustration/Experiment.tsx b/packages/studio-components/src/Illustration/Experiment.tsx new file mode 100644 index 000000000..32c327e1e --- /dev/null +++ b/packages/studio-components/src/Illustration/Experiment.tsx @@ -0,0 +1,192 @@ +import * as React from 'react'; +import { theme } from 'antd'; +export interface IJobProps { + style?: React.CSSProperties; +} + +const Experiment: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Experiment; diff --git a/packages/studio-components/src/Illustration/Explore.tsx b/packages/studio-components/src/Illustration/Explore.tsx new file mode 100644 index 000000000..057d01598 --- /dev/null +++ b/packages/studio-components/src/Illustration/Explore.tsx @@ -0,0 +1,160 @@ +import * as React from 'react'; +import { theme } from 'antd'; +export interface IJobProps { + style?: React.CSSProperties; +} + +const Explore: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Explore; diff --git a/packages/studio-components/src/Illustration/Extension.tsx b/packages/studio-components/src/Illustration/Extension.tsx new file mode 100644 index 000000000..4394a16d2 --- /dev/null +++ b/packages/studio-components/src/Illustration/Extension.tsx @@ -0,0 +1,161 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const Extension: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Extension; diff --git a/packages/studio-components/src/Illustration/FunArrow.tsx b/packages/studio-components/src/Illustration/FunArrow.tsx new file mode 100644 index 000000000..cc700b277 --- /dev/null +++ b/packages/studio-components/src/Illustration/FunArrow.tsx @@ -0,0 +1,34 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const FunArrow: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + ); +}; + +export default FunArrow; diff --git a/packages/studio-components/src/Illustration/Job.tsx b/packages/studio-components/src/Illustration/Job.tsx new file mode 100644 index 000000000..a3bd2b601 --- /dev/null +++ b/packages/studio-components/src/Illustration/Job.tsx @@ -0,0 +1,201 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const Job: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Job; diff --git a/packages/studio-components/src/Illustration/Loading.tsx b/packages/studio-components/src/Illustration/Loading.tsx new file mode 100644 index 000000000..908701e4e --- /dev/null +++ b/packages/studio-components/src/Illustration/Loading.tsx @@ -0,0 +1,94 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const Loading: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Loading; diff --git a/packages/studio-components/src/Illustration/Next.tsx b/packages/studio-components/src/Illustration/Next.tsx new file mode 100644 index 000000000..0b55d5547 --- /dev/null +++ b/packages/studio-components/src/Illustration/Next.tsx @@ -0,0 +1,206 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const Next: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Next; diff --git a/packages/studio-components/src/Illustration/NotFound.tsx b/packages/studio-components/src/Illustration/NotFound.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/packages/studio-components/src/Illustration/Process.tsx b/packages/studio-components/src/Illustration/Process.tsx new file mode 100644 index 000000000..959a7cd2f --- /dev/null +++ b/packages/studio-components/src/Illustration/Process.tsx @@ -0,0 +1,247 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const Process: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Process; diff --git a/packages/studio-components/src/Illustration/Programming.tsx b/packages/studio-components/src/Illustration/Programming.tsx new file mode 100644 index 000000000..205551354 --- /dev/null +++ b/packages/studio-components/src/Illustration/Programming.tsx @@ -0,0 +1,508 @@ +import * as React from 'react'; +import { theme } from 'antd'; +export interface IJobProps { + style?: React.CSSProperties; +} + +const Explore: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Explore; diff --git a/packages/studio-components/src/Illustration/Settings.tsx b/packages/studio-components/src/Illustration/Settings.tsx new file mode 100644 index 000000000..faaa693db --- /dev/null +++ b/packages/studio-components/src/Illustration/Settings.tsx @@ -0,0 +1,214 @@ +import * as React from 'react'; +import { theme } from 'antd'; +export interface IJobProps { + style?: React.CSSProperties; +} + +const Settings: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Settings; diff --git a/packages/studio-components/src/Illustration/Success.tsx b/packages/studio-components/src/Illustration/Success.tsx new file mode 100644 index 000000000..49b06de2c --- /dev/null +++ b/packages/studio-components/src/Illustration/Success.tsx @@ -0,0 +1,120 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const Success: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Success; diff --git a/packages/studio-components/src/Illustration/Upload.tsx b/packages/studio-components/src/Illustration/Upload.tsx new file mode 100644 index 000000000..3e00dffb6 --- /dev/null +++ b/packages/studio-components/src/Illustration/Upload.tsx @@ -0,0 +1,260 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const Upload: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Upload; diff --git a/packages/studio-components/src/Illustration/Welcome.tsx b/packages/studio-components/src/Illustration/Welcome.tsx new file mode 100644 index 000000000..2a6c7f83b --- /dev/null +++ b/packages/studio-components/src/Illustration/Welcome.tsx @@ -0,0 +1,297 @@ +import * as React from 'react'; +import { theme } from 'antd'; + +export interface IJobProps { + style?: React.CSSProperties; +} + +const Welcome: React.FunctionComponent = props => { + const { style = {} } = props; + const { width = '200px', height = '200px' } = style; + const { token } = theme.useToken(); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default Welcome; diff --git a/packages/studio-components/src/Illustration/index.md b/packages/studio-components/src/Illustration/index.md new file mode 100644 index 000000000..00086c532 --- /dev/null +++ b/packages/studio-components/src/Illustration/index.md @@ -0,0 +1,29 @@ +--- +tag: New +--- + +# Illustration + +- open source : https://undraw.co/illustrations + +```jsx +import React, { useState } from 'react'; +import { Space, Flex, Typography } from 'antd'; +import { Illustration } from '@graphscope/studio-components'; + +export default () => { + return ( + + {Object.keys(Illustration).map(key => { + const Item = Illustration[key]; + return ( + + + {key} + + ); + })} + + ); +}; +``` diff --git a/packages/studio-components/src/Illustration/index.tsx b/packages/studio-components/src/Illustration/index.tsx new file mode 100644 index 000000000..e0aea3271 --- /dev/null +++ b/packages/studio-components/src/Illustration/index.tsx @@ -0,0 +1,28 @@ +import Job from './Job'; +import Explore from './Explore'; +import DesignSchema from './DesignSchema'; +import Process from './Process'; +import Success from './Success'; +import Next from './Next'; +import Loading from './Loading'; +import Upload from './Upload'; +import FunArrow from './FunArrow'; +import Welcome from './Welcome'; +import Programming from './Programming'; +import Experiment from './Experiment'; +import Settings from './Settings'; +export default { + Job, + Explore, + DesignSchema, + Process, + Success, + Next, + Loading, + Upload, + FunArrow, + Welcome, + Programming, + Experiment, + Settings, +}; diff --git a/packages/studio-components/src/index.tsx b/packages/studio-components/src/index.tsx index c68df556c..22b0aac7e 100644 --- a/packages/studio-components/src/index.tsx +++ b/packages/studio-components/src/index.tsx @@ -1,3 +1,5 @@ +import Illustration from './Illustration'; + export { default as EditableText } from './EditableText'; export { default as EmptyCanvas } from './EmptyCanvas'; export { default as SegmentedTabs } from './SegmentedTabs'; @@ -35,3 +37,4 @@ export type { Property } from './PropertiesList/typing'; export type { ParsedFile } from './Utils/parseCSV'; export { useDynamicStyle } from './hooks/useDynamicStyle'; +export { default as Illustration } from './Illustration'; diff --git a/packages/studio-website/package.json b/packages/studio-website/package.json index 5eab956dc..01c3b437b 100644 --- a/packages/studio-website/package.json +++ b/packages/studio-website/package.json @@ -34,6 +34,7 @@ "@graphscope/studio-query": "workspace:*", "@graphscope/studio-server": "workspace:*", "@graphscope/use-zustand": "workspace:*", + "@graphscope/graphy-website": "workspace:*", "@uiw/react-codemirror": "^4.21.21", "antd": "^5.17.0", "js-yaml": "^4.1.0", diff --git a/packages/studio-website/src/app.tsx b/packages/studio-website/src/app.tsx index aa04921fa..003b174fa 100644 --- a/packages/studio-website/src/app.tsx +++ b/packages/studio-website/src/app.tsx @@ -1,6 +1,22 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import Pages from './pages'; +import { installSlot, unInstallSlot } from './slots'; +import { SIDE_MENU } from './layouts/const'; +import { ROUTES } from './pages'; +import { Utils } from '@graphscope/studio-components'; +import { ROUTES as GRAPHY_ROUTES, SIDE_MENU as GRAPHY_SIDE_MENU } from '@graphscope/graphy-website'; + +if (Utils.storage.get('PORTAL_PLUGIN_GRAPHY')) { + installSlot('SIDE_MEU', 'graphy', GRAPHY_SIDE_MENU); + installSlot('ROUTES', 'graphy', GRAPHY_ROUTES); +} else { + unInstallSlot('SIDE_MEU', 'graphy'); + unInstallSlot('ROUTES', 'graphy'); +} + +installSlot('SIDE_MEU', 'studio', SIDE_MENU); +installSlot('ROUTES', 'studio', ROUTES); const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); root.render(); diff --git a/packages/studio-website/src/components/feature-case/index.tsx b/packages/studio-website/src/components/feature-case/index.tsx new file mode 100644 index 000000000..3539cbbff --- /dev/null +++ b/packages/studio-website/src/components/feature-case/index.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; +import { getSupportFeature, type SupportFeature } from '../../layouts/services'; +interface IGrootCaseProps { + children: React.ReactNode; + match: SupportFeature; +} + +const FeatureCase: React.FunctionComponent = props => { + const { children, match } = props; + const feature = getSupportFeature(); + const support = feature[match]; + return ( +
+ {children} +
+ ); +}; + +export default FeatureCase; diff --git a/packages/studio-website/src/components/setting-parcel/index.tsx b/packages/studio-website/src/components/setting-parcel/index.tsx index 8cc99d6af..fd3e010da 100644 --- a/packages/studio-website/src/components/setting-parcel/index.tsx +++ b/packages/studio-website/src/components/setting-parcel/index.tsx @@ -14,21 +14,17 @@ type ISettingParcelProps = { const SettingParcel: React.FunctionComponent = props => { const { title, text, style = { margin: '0px 24px 0px 0px' }, leftModule, rightModule, children } = props; return ( - - - - - <FormattedMessage id={title} /> - - - - - - - {leftModule && {leftModule}} - {rightModule && {rightModule}} - {children && {children}} - + + + <FormattedMessage id={title} /> + + + + + {leftModule && leftModule} + {rightModule && rightModule} + {children && children} + ); }; diff --git a/packages/studio-website/src/global.d.ts b/packages/studio-website/src/global.d.ts index 79c51b089..0a8d8fcf3 100644 --- a/packages/studio-website/src/global.d.ts +++ b/packages/studio-website/src/global.d.ts @@ -1,3 +1,4 @@ interface Window { GS_ENGINE_TYPE: 'groot' | 'interactive' | 'gart'; + COORDINATOR_URL: string; } diff --git a/packages/studio-website/src/layouts/index.tsx b/packages/studio-website/src/layouts/index.tsx index 474fed4c2..a321979be 100644 --- a/packages/studio-website/src/layouts/index.tsx +++ b/packages/studio-website/src/layouts/index.tsx @@ -6,7 +6,7 @@ import { DeploymentApiFactory } from '@graphscope/studio-server'; import { SIDE_MENU, SETTING_MENU } from './const'; import { notification } from 'antd'; import { listGraphs } from '../pages/instance/lists/service'; -import { SLOTS } from '../slots'; +import { SLOTS, getSlots } from '../slots'; export default function StudioLayout() { const { store, updateStore } = useContext(); @@ -16,7 +16,7 @@ export default function StudioLayout() { engineType: 'interactive', }); const depolymentInfo = async () => { - return await DeploymentApiFactory(undefined, location.origin) + return await DeploymentApiFactory(undefined, window.COORDINATOR_URL) .getDeploymentInfo() .then(res => { const { data } = res; @@ -78,6 +78,7 @@ export default function StudioLayout() { }; useEffect(() => { (async () => { + setCoordinator(); const engineType = (await depolymentInfo()) as 'interactive' | 'groot'; setState(preState => { return { @@ -108,7 +109,9 @@ export default function StudioLayout() { }, []); const { isReady } = state; - const _SIDE = [...(SIDE_MENU || []), ...(SLOTS.SIDE_MEU || [])]; + + const _SIDE = getSlots('SIDE_MEU'); + const { layoutBackground } = useCustomToken(); if (isReady) { return ( @@ -125,3 +128,13 @@ export default function StudioLayout() { return ; } + +function setCoordinator() { + const coordinatorURL = Utils.getSearchParams('coordinator'); + if (coordinatorURL) { + Utils.storage.set('coordinator', coordinatorURL); + } + const coordinator = Utils.storage.get('coordinator') || location.origin; + window.COORDINATOR_URL = coordinator; + return coordinator; +} diff --git a/packages/studio-website/src/layouts/services.tsx b/packages/studio-website/src/layouts/services.tsx index 35dbbaa64..cefeb7177 100644 --- a/packages/studio-website/src/layouts/services.tsx +++ b/packages/studio-website/src/layouts/services.tsx @@ -8,8 +8,53 @@ import { import { notification } from '../pages/utils'; +export type SupportFeature = + /** 是否支持多图 */ + | 'MULTIPLE_GRAPHS' + /** 是否支持批量创建图模型 */ + | 'BATCH_CREATE_SCHEMA' + /** schema是否支持更新修改 */ + | 'SCHEMA_UPDATE' + /** 是否支持CSV导图 */ + | 'LOAD_CSV_DATA' + /** 是否支持查询多版本 */ + | 'QUERY_MULTIPLE_VERSIONS'; + +type Features = { + [K in SupportFeature]: boolean; +}; + +export const getSupportFeature = (): Features => { + if (window.GS_ENGINE_TYPE === 'groot') { + return { + BATCH_CREATE_SCHEMA: false, + LOAD_CSV_DATA: false, + MULTIPLE_GRAPHS: false, + QUERY_MULTIPLE_VERSIONS: false, + SCHEMA_UPDATE: true, + }; + } + if (window.GS_ENGINE_TYPE === 'gart') { + return { + BATCH_CREATE_SCHEMA: true, + LOAD_CSV_DATA: false, + MULTIPLE_GRAPHS: false, + QUERY_MULTIPLE_VERSIONS: true, + SCHEMA_UPDATE: false, + }; + } + //interactive + return { + BATCH_CREATE_SCHEMA: true, + LOAD_CSV_DATA: true, + MULTIPLE_GRAPHS: true, + QUERY_MULTIPLE_VERSIONS: false, + SCHEMA_UPDATE: false, + }; +}; + export const listGraphs = async () => { - const status = await ServiceApiFactory(undefined, location.origin) + const status = await ServiceApiFactory(undefined, window.COORDINATOR_URL) .listServiceStatus() .then(res => { if (res.status === 200) { @@ -23,7 +68,7 @@ export const listGraphs = async () => { let graphs; - graphs = await GraphApiFactory(undefined, location.origin) + graphs = await GraphApiFactory(undefined, window.COORDINATOR_URL) .listGraphs() .then(res => { if (res.status === 200) { diff --git a/packages/studio-website/src/locales/en-US.ts b/packages/studio-website/src/locales/en-US.ts index 40336cea7..cf7a17f46 100644 --- a/packages/studio-website/src/locales/en-US.ts +++ b/packages/studio-website/src/locales/en-US.ts @@ -265,4 +265,6 @@ export default { 'No graph available': 'No graph available', 'Create instance': 'Create instance', Explore: 'Explore', + Settings: 'Settings', + 'System Setting': 'System Setting', }; diff --git a/packages/studio-website/src/locales/zh-CN.ts b/packages/studio-website/src/locales/zh-CN.ts index 40c66a2ea..784cecd5c 100644 --- a/packages/studio-website/src/locales/zh-CN.ts +++ b/packages/studio-website/src/locales/zh-CN.ts @@ -260,4 +260,6 @@ export default { 'No graph available': '无可用图实例', 'Create instance': '创建图实例', Explore: '图探索', + Settings: '设置', + 'System Setting': '系统设置', }; diff --git a/packages/studio-website/src/pages/extension/service.tsx b/packages/studio-website/src/pages/extension/service.tsx index 12fb5325c..943b90aba 100644 --- a/packages/studio-website/src/pages/extension/service.tsx +++ b/packages/studio-website/src/pages/extension/service.tsx @@ -3,7 +3,7 @@ import type { CreateStoredProcRequest, UpdateStoredProcRequest } from '@graphsco import { notification } from '../../pages/utils'; /** 获取插件列表 */ export const listProcedures = async () => { - const message = await GraphApiFactory(undefined, location.origin) + const message = await GraphApiFactory(undefined, window.COORDINATOR_URL) .listGraphs() .then(res => { if (res.status === 200) { @@ -19,7 +19,7 @@ export const listProcedures = async () => { }; /** 创建插件 */ export const createProcedure = async (graphId: string, procedure: CreateStoredProcRequest) => { - return await StoredProcedureApiFactory(undefined, location.origin) + return await StoredProcedureApiFactory(undefined, window.COORDINATOR_URL) .createStoredProcedure(graphId, procedure) .then(res => { if (res.status === 200) { @@ -33,7 +33,7 @@ export const createProcedure = async (graphId: string, procedure: CreateStoredPr }; /** 删除插件 */ export const deleteProcedure = async (graphId: string, procedureName: string) => { - return await StoredProcedureApiFactory(undefined, location.origin) + return await StoredProcedureApiFactory(undefined, window.COORDINATOR_URL) .deleteStoredProcedureById(graphId, procedureName) .then(res => { if (res.status === 200) { @@ -47,7 +47,7 @@ export const deleteProcedure = async (graphId: string, procedureName: string) => }; /** 修改插件 */ export const updateProcedure = async (graphId: string, procedureId: string, procedure: UpdateStoredProcRequest) => { - return await StoredProcedureApiFactory(undefined, location.origin) + return await StoredProcedureApiFactory(undefined, window.COORDINATOR_URL) .updateStoredProcedureById(graphId, procedureId, procedure) .then(res => { if (res.status === 200) { @@ -61,7 +61,7 @@ export const updateProcedure = async (graphId: string, procedureId: string, proc }; /** 获取某条插件数据 */ export const getProcedure = async (graphId: string, procedureId: string) => { - return await StoredProcedureApiFactory(undefined, location.origin) + return await StoredProcedureApiFactory(undefined, window.COORDINATOR_URL) .getStoredProcedureById(graphId, procedureId) .then(res => { if (res.status === 200) { @@ -75,7 +75,7 @@ export const getProcedure = async (graphId: string, procedureId: string) => { }; /** 获取 Binding graph 列表 */ export const listGraphs = async () => { - const deployments = await GraphApiFactory(undefined, location.origin) + const deployments = await GraphApiFactory(undefined, window.COORDINATOR_URL) .listGraphs() .then(res => { if (res.status === 200) { diff --git a/packages/studio-website/src/pages/importing/services.tsx b/packages/studio-website/src/pages/importing/services.tsx index d962f6265..489e7ec1d 100644 --- a/packages/studio-website/src/pages/importing/services.tsx +++ b/packages/studio-website/src/pages/importing/services.tsx @@ -7,7 +7,7 @@ import type { FieldType } from './start-load'; /** upload file */ export const uploadFile = async (file: File) => { - return UtilsApiFactory(undefined, location.origin) + return UtilsApiFactory(undefined, window.COORDINATOR_URL) .uploadFile(file) .then(res => { if (res.status === 200) { @@ -22,7 +22,7 @@ export const uploadFile = async (file: File) => { export const bindDatasourceInBatch = async (graph_id: string, options: any): Promise => { const schema = transformImportOptionsToSchemaMapping(options); - return await DataSourceApiFactory(undefined, location.origin).bindDatasourceInBatch(graph_id, schema); + return await DataSourceApiFactory(undefined, window.COORDINATOR_URL).bindDatasourceInBatch(graph_id, schema); }; /** 数据绑定 dataMap(nodes/edges集合)*/ export const submitDataloadingJob = async (graph_id: string, graphSchema: any, loadConfig: FieldType): Promise => { @@ -53,7 +53,7 @@ export const submitDataloadingJob = async (graph_id: string, graphSchema: any, l : { quoting: loadConfig.quoting, }; - return JobApiFactory(undefined, location.origin).submitDataloadingJob(graph_id, { + return JobApiFactory(undefined, window.COORDINATOR_URL).submitDataloadingJob(graph_id, { ...schema, loading_config: { import_option: loadConfig.import_option, @@ -74,7 +74,7 @@ export const submitDataloadingJob = async (graph_id: string, graphSchema: any, l export const getSchema = async (graph_id: string) => { let schema; if (window.GS_ENGINE_TYPE === 'interactive' || window.GS_ENGINE_TYPE === 'gart') { - schema = await GraphApiFactory(undefined, location.origin) + schema = await GraphApiFactory(undefined, window.COORDINATOR_URL) .getGraphById(graph_id) .then(res => { if (res.status === 200) { @@ -87,7 +87,7 @@ export const getSchema = async (graph_id: string) => { }); } if (window.GS_ENGINE_TYPE === 'groot') { - schema = await GraphApiFactory(undefined, location.origin) + schema = await GraphApiFactory(undefined, window.COORDINATOR_URL) .getSchemaById(graph_id) .then(res => { if (res.status === 200) { @@ -104,7 +104,7 @@ export const getSchema = async (graph_id: string) => { /** getDatasourceById 获取数据源信息 */ export const getDatasourceById = async (graph_id: string) => { - const schemaMapping = await DataSourceApiFactory(undefined, location.origin) + const schemaMapping = await DataSourceApiFactory(undefined, window.COORDINATOR_URL) .getDatasourceById(graph_id!) .then(res => res.data) .catch(error => { diff --git a/packages/studio-website/src/pages/index.tsx b/packages/studio-website/src/pages/index.tsx index 0bfef6289..6aab22268 100644 --- a/packages/studio-website/src/pages/index.tsx +++ b/packages/studio-website/src/pages/index.tsx @@ -4,6 +4,7 @@ import { StudioProvier, GlobalSpin } from '@graphscope/studio-components'; import Layout from '../layouts'; import StoreProvider from '@graphscope/use-zustand'; import { initialStore } from '../layouts/useContext'; +import { getSlots } from '../slots'; import locales from '../locales'; interface IPagesProps { @@ -27,26 +28,28 @@ const routes = [ { path: '/extension/:name', component: React.lazy(() => import('./extension/create-plugins')) }, ]; +export const ROUTES = routes.map(({ path, redirect, component: Component }, index) => { + if (redirect) { + return } />; + } + return ( + }> + {/** @ts-ignore */} + + + } + /> + ); +}); + const Pages: React.FunctionComponent = props => { const { children } = props; - - const routeComponents = routes.map(({ path, redirect, component: Component }, index) => { - if (redirect) { - return } />; - } - return ( - }> - {/** @ts-ignore */} - - - } - /> - ); - }); + const routes = getSlots('ROUTES'); + console.log('routes', routes); return ( @@ -54,7 +57,7 @@ const Pages: React.FunctionComponent = props => { }> - {routeComponents} + {routes} {children} diff --git a/packages/studio-website/src/pages/instance/index.tsx b/packages/studio-website/src/pages/instance/index.tsx index ffdc22e8f..7f9a1eb6a 100644 --- a/packages/studio-website/src/pages/instance/index.tsx +++ b/packages/studio-website/src/pages/instance/index.tsx @@ -5,6 +5,7 @@ import Section from '../../components/section'; import { PlusOutlined } from '@ant-design/icons'; import { FormattedMessage } from 'react-intl'; import CreateInstance from './create'; +import FeatureCase from '../../components/feature-case'; const Instance: React.FunctionComponent = () => { return (
{ style={{ padding: '0px 20px' }} > - + + +
diff --git a/packages/studio-website/src/pages/instance/lists/service.tsx b/packages/studio-website/src/pages/instance/lists/service.tsx index 96a22a4b9..d3dcd626d 100644 --- a/packages/studio-website/src/pages/instance/lists/service.tsx +++ b/packages/studio-website/src/pages/instance/lists/service.tsx @@ -3,7 +3,7 @@ import type { DataloadingJobConfig } from '@graphscope/studio-server'; import { notification } from '../../../pages/utils'; export const listGraphs = async () => { - const _status = await ServiceApiFactory(undefined, location.origin) + const _status = await ServiceApiFactory(undefined, window.COORDINATOR_URL) .listServiceStatus() .then(res => { if (res.status === 200) { @@ -18,7 +18,7 @@ export const listGraphs = async () => { // const { GS_ENGINE_TYPE } = window; let graphs; // if (GS_ENGINE_TYPE === 'interactive') { - graphs = await GraphApiFactory(undefined, location.origin) + graphs = await GraphApiFactory(undefined, window.COORDINATOR_URL) .listGraphs() .then(res => { if (res.status === 200) { @@ -31,7 +31,7 @@ export const listGraphs = async () => { // } // if (GS_ENGINE_TYPE === 'groot') { - // graphs = await LegacyApiFactory(undefined, location.origin) + // graphs = await LegacyApiFactory(undefined,window.COORDINATOR_URL) // .listGrootGraph() // .then(res => { // if (res.status === 200) { @@ -77,7 +77,7 @@ export const listGraphs = async () => { }; export const deleteGraph = async (graph_id: string) => { - return await GraphApiFactory(undefined, location.origin) + return await GraphApiFactory(undefined, window.COORDINATOR_URL) .deleteGraphById(graph_id) .then(res => { if (res.status === 200) { @@ -94,7 +94,7 @@ export const deleteGraph = async (graph_id: string) => { }; export const startService = async (graph_id: string) => { - return await ServiceApiFactory(undefined, location.origin) + return await ServiceApiFactory(undefined, window.COORDINATOR_URL) .startService({ graph_id, }) @@ -112,7 +112,7 @@ export const startService = async (graph_id: string) => { }); }; export const stopService = async (graph_id: string) => { - return await ServiceApiFactory(undefined, location.origin) + return await ServiceApiFactory(undefined, window.COORDINATOR_URL) .stopService({ graph_id, }) @@ -131,7 +131,7 @@ export const stopService = async (graph_id: string) => { }; /** 获取是否已经导入 */ export const getDataloadingConfig = async (graph_id: string, dataloadingJobConfig: DataloadingJobConfig) => { - return await JobApiFactory(undefined, location.origin) + return await JobApiFactory(undefined, window.COORDINATOR_URL) .getDataloadingJobConfig(graph_id!, dataloadingJobConfig) .then(res => { if (res.status === 200) { diff --git a/packages/studio-website/src/pages/job/service.tsx b/packages/studio-website/src/pages/job/service.tsx index d5ddd74ef..2f48d1fdf 100644 --- a/packages/studio-website/src/pages/job/service.tsx +++ b/packages/studio-website/src/pages/job/service.tsx @@ -14,7 +14,7 @@ export type IJobType = { }; }; export const listJobs = async () => { - const message = await JobApiFactory(undefined, location.origin) + const message = await JobApiFactory(undefined, window.COORDINATOR_URL) .listJobs() .then(res => { if (res.status === 200) { @@ -26,7 +26,7 @@ export const listJobs = async () => { notification('error', error); return []; }); - const graphs = await GraphApiFactory(undefined, location.origin) + const graphs = await GraphApiFactory(undefined, window.COORDINATOR_URL) .listGraphs() .then(res => { if (res.status === 200) { @@ -60,7 +60,7 @@ export const listJobs = async () => { return info; }; export const deleteJobById = async (jobId: string) => { - return await JobApiFactory(undefined, location.origin) + return await JobApiFactory(undefined, window.COORDINATOR_URL) .deleteJobById(jobId) .then(res => { if (res.status === 200) { @@ -73,7 +73,7 @@ export const deleteJobById = async (jobId: string) => { }); }; export const getJobById = async (jobId: string) => { - return await JobApiFactory(undefined, location.origin) + return await JobApiFactory(undefined, window.COORDINATOR_URL) .getJobById(jobId) .then(res => { if (res.status === 200) { diff --git a/packages/studio-website/src/pages/modeling/services.tsx b/packages/studio-website/src/pages/modeling/services.tsx index 3e228c372..adae72237 100644 --- a/packages/studio-website/src/pages/modeling/services.tsx +++ b/packages/studio-website/src/pages/modeling/services.tsx @@ -17,12 +17,12 @@ export const createGraph = async (params: { graphName: string; nodes: any[]; edg description: '', schema: schemaJSON, }; - graphs = await GraphApiFactory(undefined, location.origin).createGraph(data); + graphs = await GraphApiFactory(undefined, window.COORDINATOR_URL).createGraph(data); } /** groot 创建 */ if (GS_ENGINE_TYPE === 'groot' && graph_id) { // const schemagrootJSON = transOptionsToGrootSchema(cloneDeep({ nodes: nodes, edges: edges })); - graphs = await GraphApiFactory(undefined, location.origin) + graphs = await GraphApiFactory(undefined, window.COORDINATOR_URL) .importSchemaById(graph_id, schemaJSON) .then(res => { if (res.status === 200) { @@ -39,7 +39,7 @@ export const createGraph = async (params: { graphName: string; nodes: any[]; edg }; /** upload file */ export const uploadFile = async (file: File) => { - return UtilsApiFactory(undefined, location.origin) + return UtilsApiFactory(undefined, window.COORDINATOR_URL) .uploadFile(file) .then(res => { if (res.status === 200) { @@ -54,7 +54,7 @@ export const uploadFile = async (file: File) => { export const getSchema = async (graph_id: string) => { let schema; if (window.GS_ENGINE_TYPE === 'interactive' || window.GS_ENGINE_TYPE === 'gart') { - schema = await GraphApiFactory(undefined, location.origin) + schema = await GraphApiFactory(undefined, window.COORDINATOR_URL) .getGraphById(graph_id) .then(res => { if (res.status === 200) { @@ -68,7 +68,7 @@ export const getSchema = async (graph_id: string) => { }); } if (window.GS_ENGINE_TYPE === 'groot') { - schema = await GraphApiFactory(undefined, location.origin) + schema = await GraphApiFactory(undefined, window.COORDINATOR_URL) .getSchemaById(graph_id) .then(res => { if (res.status === 200) { @@ -101,7 +101,7 @@ export const deleteVertexTypeOrEdgeType = async ( const graph_id = getSearchParams('graph_id') || ''; if (type === 'nodes') { try { - const res = await GraphApiFactory(undefined, location.origin).deleteVertexTypeByName(graph_id, label); + const res = await GraphApiFactory(undefined, window.COORDINATOR_URL).deleteVertexTypeByName(graph_id, label); response = true; notification('success', res.data); } catch (error) { @@ -110,7 +110,7 @@ export const deleteVertexTypeOrEdgeType = async ( } if (type === 'edges' && sourceVertexType && destinationVertexType) { try { - const res = await GraphApiFactory(undefined, location.origin).deleteEdgeTypeByName( + const res = await GraphApiFactory(undefined, window.COORDINATOR_URL).deleteEdgeTypeByName( graph_id, label, sourceVertexType, @@ -139,7 +139,7 @@ export const createVertexTypeOrEdgeType = async ( //@ts-ignore const { vertex_types } = transOptionsToSchema({ nodes: [params], edges: [] }); try { - const res = await GraphApiFactory(undefined, location.origin).createVertexType(graph_id, vertex_types[0]); + const res = await GraphApiFactory(undefined, window.COORDINATOR_URL).createVertexType(graph_id, vertex_types[0]); notification('success', res.data); response = true; } catch (error) { @@ -151,7 +151,7 @@ export const createVertexTypeOrEdgeType = async ( const { edge_types } = transOptionsToSchema({ nodes: nodes, edges: [params] }); console.log('edge_types', edge_types, params); try { - const res = await GraphApiFactory(undefined, location.origin).createEdgeType(graph_id, edge_types[0]); + const res = await GraphApiFactory(undefined, window.COORDINATOR_URL).createEdgeType(graph_id, edge_types[0]); notification('success', res.data); response = true; } catch (error) { diff --git a/packages/studio-website/src/pages/query/services.tsx b/packages/studio-website/src/pages/query/services.tsx index ec50ec334..14622d953 100644 --- a/packages/studio-website/src/pages/query/services.tsx +++ b/packages/studio-website/src/pages/query/services.tsx @@ -41,7 +41,7 @@ export const queryEndpoint = async (): Promise<{ }; export const queryInfo = async (id: string) => { - const result = await ServiceApiFactory(undefined, location.origin) + const result = await ServiceApiFactory(undefined, window.COORDINATOR_URL) .getServiceStatusById(id) .then(res => handleResponse(res)) .catch(error => handleError(error)); @@ -49,7 +49,7 @@ export const queryInfo = async (id: string) => { return result; }; export const queryGraphSchema = async (graph_id: string): Promise => { - const schema = await GraphApiFactory(undefined, location.origin) + const schema = await GraphApiFactory(undefined, window.COORDINATOR_URL) .getSchemaById(graph_id) .then(res => handleResponse(res)) .catch(error => handleError(error)); @@ -86,7 +86,7 @@ export const queryStatements: IStudioQueryProps['queryStatements'] = async type if (!graph_id) { return []; } - return await StoredProcedureApiFactory(undefined, location.origin) + return await StoredProcedureApiFactory(undefined, window.COORDINATOR_URL) .listStoredProcedures(graph_id) .then(res => { if (res.status === 200) { diff --git a/packages/studio-website/src/pages/setting/coordinator.tsx b/packages/studio-website/src/pages/setting/coordinator.tsx new file mode 100644 index 000000000..5c3cdee08 --- /dev/null +++ b/packages/studio-website/src/pages/setting/coordinator.tsx @@ -0,0 +1,33 @@ +import React, { useRef } from 'react'; +import { Button, Input, theme, InputRef, Space, Flex } from 'antd'; +import { Utils } from '@graphscope/studio-components'; +import SettingParcel from '../../components/setting-parcel'; +import { SaveOutlined } from '@ant-design/icons'; +const { useToken } = theme; +const Coordinator: React.FunctionComponent = () => { + const inputRef = useRef(null); + const handleSave = () => { + if (inputRef) { + Utils.storage.set('coordinator', inputRef.current?.input?.value || location.origin); + window.location.reload(); + } + }; + const defaultValue = Utils.storage.get('coordinator') || location.origin; + return ( + + + + + } + /> + ); +}; + +export default Coordinator; diff --git a/packages/studio-website/src/pages/setting/index.tsx b/packages/studio-website/src/pages/setting/index.tsx index 3dd41153e..7f168c5fb 100644 --- a/packages/studio-website/src/pages/setting/index.tsx +++ b/packages/studio-website/src/pages/setting/index.tsx @@ -1,36 +1,79 @@ import * as React from 'react'; -import { Divider, Card } from 'antd'; +import { Divider, Card, Row, Col, Typography, Flex } from 'antd'; import Section from '../../components/section'; import InteractTheme from './interact-theme'; import PrimaryColor from './primary-color'; import RoundedCorner from './rounded-corner'; import International from './International'; -import NavStyle from './nav-style'; + import QuerySetting from './query-setting'; import { FormattedMessage } from 'react-intl'; +import Coordinator from './coordinator'; +import GraphyPlugin from './plugins/graphy'; + const Setting: React.FunctionComponent = () => { return (
, + title: , }, ]} desc="Change how Untitled UI looks and feels in your browser" > - - - - - - - - - - - - - + + + + + + + } + > + + + + + + + + + } + > + + + + + + + + + + } + > + + + + + + + + + + } + > + + + + +
); }; diff --git a/packages/studio-website/src/pages/setting/nav-style.tsx b/packages/studio-website/src/pages/setting/nav-style.tsx deleted file mode 100644 index 5ff05f1a6..000000000 --- a/packages/studio-website/src/pages/setting/nav-style.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { Segmented } from 'antd'; -import { useContext } from '../../layouts/useContext'; -import localStorage from '../../components/utils/localStorage'; -import SettingParcel from '../../components/setting-parcel'; -import { FormattedMessage } from 'react-intl'; - -interface ILocaleSwitchProps {} -interface INavStyleOption { - label: React.ReactNode; - value: string; -} -const NavStyle: React.FunctionComponent = () => { - const { store, updateStore } = useContext(); - const { navStyle } = store; - const { setItem, getItem } = localStorage; - const onChange = (value: string) => { - setItem('navStyle', value); - const navStyle = getItem('navStyle'); - updateStore(draft => { - draft.navStyle = navStyle; - }); - }; - - const options: INavStyleOption[] = [ - { - label: , - value: 'inline', - }, - { - label: , - value: 'menu', - }, - ]; - return ( - - - - ); -}; - -export default NavStyle; diff --git a/packages/studio-website/src/pages/setting/plugins/graphy.tsx b/packages/studio-website/src/pages/setting/plugins/graphy.tsx new file mode 100644 index 000000000..8ebaddf1a --- /dev/null +++ b/packages/studio-website/src/pages/setting/plugins/graphy.tsx @@ -0,0 +1,66 @@ +import * as React from 'react'; +import { Typography, Tooltip, Switch, Input, Flex, Space, Card } from 'antd'; +import { QuestionCircleOutlined } from '@ant-design/icons'; +import { Utils, Illustration } from '@graphscope/studio-components'; +import { ROUTES, SIDE_MENU } from '@graphscope/graphy-website'; +import { installSlot, unInstallSlot } from '../../../slots'; +import { useContext } from '../../../layouts/useContext'; + +interface IGraphyPluginProps {} + +const GraphyPlugin: React.FunctionComponent = props => { + const defaultChecked = Utils.storage.get('PORTAL_PLUGIN_GRAPHY'); + const defaultEndpoint = Utils.storage.get('graphy_endpoint') || 'http://127.0.0.1:9999'; + const onChange = (checked: boolean) => { + Utils.storage.set('PORTAL_PLUGIN_GRAPHY', checked); + if (checked) { + installSlot('SIDE_MEU', 'graphy', SIDE_MENU); + installSlot('ROUTES', 'graphy', ROUTES); + } else { + unInstallSlot('SIDE_MEU', 'graphy'); + unInstallSlot('ROUTES', 'graphy'); + } + window.location.reload(); + }; + const handleChangeUrl = () => { + Utils.storage.get('graphy_endpoint'); + }; + + return ( + + {/* */} + + + + Graphy'ourData + + + + + + + An intuitive tool that transforms unstructured data into graph dataset. + + + Enable: + + + + Endpoint: + + + + + + ); +}; + +export default GraphyPlugin; diff --git a/packages/studio-website/src/pages/setting/rounded-corner.tsx b/packages/studio-website/src/pages/setting/rounded-corner.tsx index b5dee02a2..ba972d7f6 100644 --- a/packages/studio-website/src/pages/setting/rounded-corner.tsx +++ b/packages/studio-website/src/pages/setting/rounded-corner.tsx @@ -18,12 +18,13 @@ const RoundedCorner: React.FunctionComponent = () => { style={{ margin: '0px' }} title="Rounded corners" text="Corner radians" - leftModule={} - rightModule={ - } /> diff --git a/packages/studio-website/src/slots/index.tsx b/packages/studio-website/src/slots/index.tsx index 8e76d541d..403bc775c 100644 --- a/packages/studio-website/src/slots/index.tsx +++ b/packages/studio-website/src/slots/index.tsx @@ -1,19 +1,53 @@ import React from 'react'; import type { MenuProps } from 'antd'; - +// import { SIDE_MENU } from '../layouts/const'; +// import { ROUTES } from '../pages/index'; export const SLOTS: { /** 侧边栏 */ - SIDE_MEU: MenuProps['items']; - /** 查询模块的头部 */ - QUERY_HEADER: string; - /** 导入模块的配置 */ - IMPORT_CONFIG: React.ReactNode; + SIDE_MEU: { [id: string]: MenuProps['items'] }; + /** 路由 */ + ROUTES: { + [id: string]: any[]; + }; } = { - SIDE_MEU: [], - QUERY_HEADER: '', - IMPORT_CONFIG: <>, + SIDE_MEU: { + studio: [], + }, + ROUTES: { + studio: [], + }, +}; + +export type SlotType = 'SIDE_MEU' | 'ROUTES'; +export const installSlot = (slotType: SlotType, appId: string, slot: any) => { + SLOTS[slotType] = { + ...SLOTS[slotType], + [appId]: slot, + }; + console.log('SLOTS', SLOTS); +}; +export const unInstallSlot = (slotType: SlotType, appId: string) => { + delete SLOTS[slotType][appId]; +}; + +export const getSlots = (slotType: SlotType) => { + const slots = SLOTS[slotType]; + //@ts-ignore + return Object.keys(slots).reduce((acc, appId) => { + //@ts-ignore + return [...acc, ...slots[appId]]; + }, []); +}; +export const registerSideMenuSlot = (appId: string, slot: MenuProps['items']) => { + SLOTS['SIDE_MEU'] = { + ...SLOTS['SIDE_MEU'], + [appId]: slot, + }; }; -export const registerSideMenuSlot = (slot: MenuProps['items']) => { - SLOTS['SIDE_MEU'] = slot; +export const registerRoutesSlot = (appId: string, slot: any) => { + SLOTS['ROUTES'] = { + ...SLOTS['ROUTES'], + [appId]: slot, + }; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3439da50..37174ead9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -693,6 +693,9 @@ importers: '@fortawesome/react-fontawesome': specifier: latest version: 0.2.2(@fortawesome/fontawesome-svg-core@6.7.1)(react@18.2.0) + '@graphscope/graphy-website': + specifier: workspace:* + version: link:../../examples/graphy '@graphscope/studio-components': specifier: workspace:* version: link:../studio-components