diff --git a/app/index.tsx b/app/index.tsx
index 02cf0d5e..18927d0f 100644
--- a/app/index.tsx
+++ b/app/index.tsx
@@ -1,14 +1,23 @@
-import { message } from 'antd';
-import React from 'react';
+import { hot } from 'react-hot-loader/root';
+import { Spin } from 'antd';
+import React, { Suspense, lazy, useState } from 'react';
import ReactDom from 'react-dom';
-import { Provider } from 'react-redux';
-import { BrowserRouter as Router } from 'react-router-dom';
-import Cookie from 'js-cookie';
+import { Route, BrowserRouter as Router, Switch, useHistory } from 'react-router-dom';
+import { observer } from 'mobx-react-lite';
+import rootStore, { StoreProvider } from './stores';
+import dayjs from 'dayjs';
import intl from 'react-intl-universal';
-import { INTL_LOCALES } from '#app/config/constants';
+import duration from 'dayjs/plugin/duration';
+import AuthorizedRoute from './AuthorizedRoute';
+import Cookie from 'js-cookie';
+import { INTL_LOCALES } from '@app/config/constants';
+import { LanguageContext } from '@app/context';
+const Login = lazy(() => import('@app/pages/Login'));
+const MainPage = lazy(() => import('@app/pages/MainPage'));
-import App from './App';
-import { store } from './store';
+import './common.less';
+import './app.less';
+dayjs.extend(duration);
const defaultLanguage = Cookie.get('lang') || document.documentElement.getAttribute('lang');
intl.init({
@@ -16,14 +25,52 @@ intl.init({
locales: INTL_LOCALES,
});
-message.config({
- maxCount: 1,
+
+const PageRoot = observer(() => {
+ const [currentLocale, setCurrentLocale] = useState(
+ defaultLanguage || 'EN-US',
+ );
+
+ const toggleLanguage = (locale: string) => {
+ Cookie.set('lang', locale);
+ setCurrentLocale(locale);
+ intl
+ .init({
+ currentLocale: locale,
+ locales: INTL_LOCALES,
+ });
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
});
-ReactDom.render(
-
-
-
-
- ,
- document.getElementById('app'),
-);
+
+const App = () => {
+ const history = useHistory();
+ rootStore.global.history = history;
+
+ return (
+
+ }>
+
+
+
+
+ );
+};
+
+const HotPageRoot = hot(PageRoot);
+
+ReactDom.render(
, document.getElementById('app'));
diff --git a/app-v2/interfaces/import.ts b/app/interfaces/import.ts
similarity index 100%
rename from app-v2/interfaces/import.ts
rename to app/interfaces/import.ts
diff --git a/app-v2/interfaces/schema.ts b/app/interfaces/schema.ts
similarity index 100%
rename from app-v2/interfaces/schema.ts
rename to app/interfaces/schema.ts
diff --git a/app/modules/ConfigServer/index.less b/app/modules/ConfigServer/index.less
deleted file mode 100644
index ad78d6d9..00000000
--- a/app/modules/ConfigServer/index.less
+++ /dev/null
@@ -1,19 +0,0 @@
-.config-server {
- position: relative;
- background: #fff;
- height: 100%;
-
- .nebula-authorization {
- width: 100%;
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
-
- > h3 {
- padding-top: 12px;
- text-align: center;
- font-size: 24px;
- }
- }
-}
diff --git a/app/modules/ConfigServer/index.tsx b/app/modules/ConfigServer/index.tsx
deleted file mode 100644
index b19cc55f..00000000
--- a/app/modules/ConfigServer/index.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import React from 'react';
-import intl from 'react-intl-universal';
-import { connect } from 'react-redux';
-import { RouteComponentProps } from 'react-router-dom';
-
-import ConfigServerForm from '#app/components/ConfigServerForm';
-import { IDispatch } from '#app/store';
-import { trackPageView } from '#app/utils/stat';
-
-import './index.less';
-
-const mapDispatch = (dispatch: IDispatch) => ({
- asyncConfigServer: dispatch.nebula.asyncConfigServer,
-});
-
-const mapState = () => ({});
-
-interface IProps
- extends ReturnType
,
- ReturnType,
- RouteComponentProps {}
-
-class ConfigServer extends React.Component {
- componentDidMount() {
- trackPageView('/connect-server');
- }
-
- handleConfigServer = async(values: any) => {
- const ok = await this.props.asyncConfigServer(values);
- if (ok) {
- this.props.history.replace('/');
- }
- };
- render() {
- return (
-
-
-
{intl.get('configServer.title')}
-
-
-
- );
- }
-}
-
-export default connect(mapState, mapDispatch)(ConfigServer);
diff --git a/app/modules/Console/SpaceSearchInput.tsx b/app/modules/Console/SpaceSearchInput.tsx
deleted file mode 100644
index 20f6a68e..00000000
--- a/app/modules/Console/SpaceSearchInput.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { Select } from 'antd';
-import React from 'react';
-import { connect } from 'react-redux';
-
-import { IDispatch, IRootState } from '#app/store';
-
-const { Option } = Select;
-
-const mapState = (state: IRootState) => ({
- spaces: state.nebula.spaces,
- loading: state.loading.effects.nebula.asyncGetSpaces,
-});
-
-const mapDispatch = (dispatch: IDispatch) => ({
- asyncGetSpaces: dispatch.nebula.asyncGetSpaces,
-});
-
-interface IProps
- extends ReturnType,
- ReturnType {
- onSpaceChange: (value: string) => void;
- value: string;
-}
-
-class SpaceSearchInput extends React.Component {
- componentDidMount() {
- this.getSpaces();
- }
- getSpaces = () => {
- this.props.asyncGetSpaces();
- };
-
- render() {
- const { value, onSpaceChange, loading } = this.props;
- return (
-
- );
- }
-}
-
-export default connect(mapState, mapDispatch)(SpaceSearchInput);
diff --git a/app/modules/Console/index.less b/app/modules/Console/index.less
deleted file mode 100644
index 4dee001a..00000000
--- a/app/modules/Console/index.less
+++ /dev/null
@@ -1,153 +0,0 @@
-.nebula-console {
- display: flex;
- flex-direction: column;
- height: 100%;
-
- .ngql-content {
- position: relative;
- display: flex;
- background: #f7f7f7;
- padding: 0 8px 16px 8px;
- font-size: 16px;
-
- > .mirror-wrap {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
-
- .mirror-content {
- width: 100%;
- display: flex;
- align-items: center;
-
- .btn-drawer {
- cursor: pointer;
- }
-
- > .CodeMirror {
- min-height: 240px;
- width: 100%;
- }
- }
-
-
- .mirror-nav {
- display: flex;
- align-items: center;
- text-align: left;
- background: #f7f7f7;
- padding: 16px 0 16px 30px;
- width: 100%;
-
- .space-search-input {
- width: 350px;
- margin: 0 8px;
- }
-
- svg {
- color: #999;
- }
- }
-
- > .expand {
- height: 21px;
- display: flex;
- justify-content: center;
- align-items: center;
- background: #f9f9f9;
- cursor: pointer;
-
- &:hover {
- background: #f7f7f7;
- }
-
- > .anticon {
- font-size: 20px;
- }
- }
- }
-
- .operation {
- display: flex;
- justify-content: flex-end;
- flex: 1;
-
- .anticon-play-circle,
- .anticon-history,
- .anticon-loading,
- .anticon-delete {
- display: flex;
- width: 64px;
- justify-content: center;
- align-items: center;
- font-size: 32px;
- cursor: pointer;
- }
- }
- }
-
- .result-wrap {
- flex: 1;
- display: flex;
- flex-direction: column;
- margin: 15px 0;
- }
-}
-
-.historyList {
- height: 80%;
- overflow: hidden;
- position: relative;
-
- .ant-modal-content {
- position: relative;
- height: 100%;
- }
-
- .ant-modal-body {
- max-height: 100%;
- overflow: auto;
- padding-top: 55px;
- }
-
- .ant-modal-header {
- position: absolute;
- top: 0;
- z-index: 9;
- width: 100%;
-
- button {
- float: right;
- margin-right: 20px;
- margin-top: -2px;
- color: rgba(0, 0, 0, 0.45);
- }
- }
-
- .ant-modal-close {
- top: 10px;
- right: 5px;
- }
-
- .history-title {
- display: inline-block;
- margin-top: 2px;
- }
-}
-
-.param-box {
- padding: 10px;
- background-color: white;
- height: 100%;
- margin-left: 5px;
- max-width: 320px;
- overflow: auto;
- max-height: 240px;
-
- p {
- font-size: 12px;
- word-break: break-all;
- margin-bottom: 8px;
- }
-}
diff --git a/app/modules/Console/index.tsx b/app/modules/Console/index.tsx
deleted file mode 100644
index 73e2a174..00000000
--- a/app/modules/Console/index.tsx
+++ /dev/null
@@ -1,294 +0,0 @@
-import { Button, List, Modal, Tooltip, message } from 'antd';
-import React from 'react';
-import intl from 'react-intl-universal';
-import { connect } from 'react-redux';
-import { RouteComponentProps } from 'react-router-dom';
-
-import { DeleteOutlined, FileSearchOutlined, HistoryOutlined, LoadingOutlined, PlayCircleOutlined, QuestionCircleOutlined } from '@ant-design/icons';
-import SpaceSearchInput from './SpaceSearchInput';
-import { CodeMirror, OutputBox } from '#app/components';
-import { maxLineNum } from '#app/config/nebulaQL';
-import { IDispatch, IRootState } from '#app/store';
-import { trackPageView } from '#app/utils/stat';
-
-import './index.less';
-
-interface IState {
- isUpDown: boolean;
- history: boolean;
- visible: boolean;
-}
-
-const mapState = (state: IRootState) => ({
- result: state._console.result,
- currentGQL: state._console.currentGQL,
- paramsMap: state._console.paramsMap,
- currentSpace: state.nebula.currentSpace,
- runGQLLoading: state.loading.effects._console.asyncRunGQL,
-});
-
-const mapDispatch = (dispatch: IDispatch) => ({
- asyncRunGQL: dispatch._console.asyncRunGQL,
- asyncGetParams: dispatch._console.asyncGetParams,
- updateCurrentGQL: gql =>
- dispatch._console.update({
- currentGQL: gql,
- }),
- asyncSwitchSpace: async space => {
- await dispatch.nebula.asyncSwitchSpace(space);
- await dispatch.explore.clear();
- },
-});
-
-interface IProps
- extends ReturnType,
- ReturnType,
- RouteComponentProps {}
-
-// split from semicolon out of quotation marks
-const SEMICOLON_REG = /((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/;
-class Console extends React.Component {
- codemirror;
- editor;
-
- constructor(props: IProps) {
- super(props);
-
- this.state = {
- isUpDown: true,
- history: false,
- visible: false,
- };
- }
-
- componentDidMount() {
- trackPageView('/console');
- this.props.asyncGetParams();
- }
-
- getLocalStorage = () => {
- const value: string | null = localStorage.getItem('history');
- if (value && value !== 'undefined' && value !== 'null') {
- return JSON.parse(value).slice(-15);
- }
- return [];
- };
-
- handleSaveQuery = (query: string) => {
- if (query !== '') {
- const history = this.getLocalStorage();
- history.push(query);
- localStorage.setItem('history', JSON.stringify(history));
- }
- };
-
- checkSwitchSpaceGql = (query: string) => {
- const queryList = query.split(SEMICOLON_REG).filter(Boolean);
- const reg = /^USE `?[0-9a-zA-Z_]+`?(?=[\s*;?]?)/gim;
- if (queryList.some(sentence => sentence.trim().match(reg))) {
- return intl.get('common.disablesUseToSwitchSpace');
- }
- };
- handleRun = async() => {
- const query = this.editor.getValue();
- if (!query) {
- message.error(intl.get('common.sorryNGQLCannotBeEmpty'));
- return;
- }
- const errInfo = this.checkSwitchSpaceGql(query);
- if (errInfo) {
- return message.error(errInfo);
- }
-
- this.editor.execCommand('goDocEnd');
- this.handleSaveQuery(query);
- await this.props.asyncRunGQL(query);
- this.setState({
- isUpDown: true,
- });
- };
-
- handleHistoryItem = (value: string) => {
- this.props.updateCurrentGQL(value);
- this.setState({
- history: false,
- });
- };
-
- handleEmptyNgqlHistory = () => {
- localStorage.setItem('history', 'null');
- this.setState({
- history: false,
- });
- };
-
- handleEmptyNgql = () => {
- this.props.updateCurrentGQL('');
- this.forceUpdate();
- };
-
- getInstance = instance => {
- if (instance) {
- this.codemirror = instance.codemirror;
- this.editor = instance.editor;
- }
- };
-
- handleUpDown = () => {
- this.setState({
- isUpDown: !this.state.isUpDown,
- });
- };
-
- handleLineCount = () => {
- let line;
- if (this.editor.lineCount() > maxLineNum) {
- line = maxLineNum;
- } else if (this.editor.lineCount() < 5) {
- line = 5;
- } else {
- line = this.editor.lineCount();
- }
- this.editor.setSize(undefined, line * 24 + 10 + 'px');
- };
-
- historyListShow = (str: string) => {
- if (str.length < 300) {
- return str;
- }
- return str.substring(0, 300) + '...';
- };
-
- toggleDrawer = () => {
- const { visible } = this.state;
- this.setState({
- visible: !visible,
- });
- };
-
- render() {
- const { isUpDown, history } = this.state;
- const {
- currentSpace,
- currentGQL,
- result,
- runGQLLoading,
- paramsMap,
- } = this.props;
- return (
-
-
-
-
- {intl.get('common.currentSpace')}:
-
-
-
-
-
-
-
-
-
- {
- this.setState({ history: true });
- }}
- />
-
-
- {!!runGQLLoading ? (
-
- ) : (
- this.handleRun()}
- />
- )}
-
-
-
-
-
-
-
- {this.state.visible && (
-
- {Object.entries(paramsMap).map(([k, v]) => (
-
{`${k} => ${JSON.stringify(v)}`}
- ))}
-
- )}
-
this.props.updateCurrentGQL(value)}
- onChangeLine={this.handleLineCount}
- ref={this.getInstance}
- height={isUpDown ? '240px' : 24 * maxLineNum + 'px'}
- onShiftEnter={this.handleRun}
- options={{
- keyMap: 'sublime',
- fullScreen: true,
- mode: 'nebula',
- }}
- />
-
-
-
-
- this.handleHistoryItem(e)}
- />
-
-
-
- {intl.get('common.NGQLHistoryList')}
-
-
-
- }
- visible={history}
- className="historyList"
- footer={null}
- onCancel={() => {
- this.setState({ history: false });
- }}
- >
- {
- (
- this.handleHistoryItem(item)}
- >
- {this.historyListShow(item)}
-
- )}
- />
- }
-
-
- );
- }
-}
-
-export default connect(mapState, mapDispatch)(Console);
diff --git a/app/modules/Explore/Control/AlgorithmQuery/index.less b/app/modules/Explore/Control/AlgorithmQuery/index.less
deleted file mode 100644
index ecca24a6..00000000
--- a/app/modules/Explore/Control/AlgorithmQuery/index.less
+++ /dev/null
@@ -1,16 +0,0 @@
-.algorithm-query {
- text-align: center;
-
- .algorithm-form {
- .select-algorithm .icon-instruction {
- position: absolute;
- right: -25px;
- top: 50%;
- transform: translateY(-50%);
- }
- }
-
- button {
- margin-top: 20px;
- }
-}
diff --git a/app/modules/Explore/Control/AlgorithmQuery/index.tsx b/app/modules/Explore/Control/AlgorithmQuery/index.tsx
deleted file mode 100644
index 7dc03fbb..00000000
--- a/app/modules/Explore/Control/AlgorithmQuery/index.tsx
+++ /dev/null
@@ -1,205 +0,0 @@
-import { Button, Divider, Form, Input, Select } from 'antd';
-import _ from 'lodash';
-import React from 'react';
-import intl from 'react-intl-universal';
-import { connect } from 'react-redux';
-
-import { FormInstance } from 'antd/es/form';
-import { Instruction } from '#app/components';
-import GQLCodeMirror from '#app/components/GQLCodeMirror';
-import { GRAPH_ALOGORITHM } from '#app/config/explore';
-import { IDispatch, IRootState } from '#app/store';
-import { getPathGQL } from '#app/utils/gql';
-
-import './index.less';
-
-const Option = Select.Option;
-
-const mapState = (state: IRootState) => ({
- edgeTypes: state.nebula.edgeTypes,
- spaceVidType: state.nebula.spaceVidType,
- loading: state.loading.effects.explore.asyncGetPathResult,
-});
-
-const mapDispatch = (dispatch: IDispatch) => ({
- asyncGetEdges: dispatch.nebula.asyncGetEdges,
- asyncGetPathResult: dispatch.explore.asyncGetPathResult,
-});
-
-interface IProps
- extends ReturnType