Skip to content

Commit

Permalink
Add Layouts for FrontEnd (#8)
Browse files Browse the repository at this point in the history
Signed-off-by: Breezewish <[email protected]>
  • Loading branch information
breezewish authored Jan 9, 2020
1 parent cf6df9c commit eb0a97a
Show file tree
Hide file tree
Showing 20 changed files with 1,294 additions and 1,125 deletions.
1 change: 1 addition & 0 deletions ui/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/utils/dashboard_client
2 changes: 1 addition & 1 deletion ui/.github_release_version
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# This file contains a version number which will be used to release assets to
# GitHub. To trigger a new asset release, simply increase this version number.
20200108_2
20200109_1
21 changes: 19 additions & 2 deletions ui/config-overrides.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
const { override, fixBabelImports, addLessLoader, addWebpackPlugin } = require('customize-cra');
const path = require('path');
const { override, fixBabelImports, addLessLoader, addWebpackResolve, addWebpackPlugin } = require('customize-cra');
const AntdDayjsWebpackPlugin = require('antd-dayjs-webpack-plugin');

const enableEslintIgnore = () => config => {
const eslintRule = config.module.rules.filter(
r => r.use && r.use.some(u => u.options && u.options.useEslintrc !== void 0)
)[0];
eslintRule.use[0].options.ignore = true;
return config;
}

module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
Expand All @@ -9,7 +18,15 @@ module.exports = override(
}),
addLessLoader({
javascriptEnabled: true,
modifyVars: { '@primary-color': '#3351ff' },
modifyVars: {
'@primary-color': '#3351ff',
'@body-background': '#f0f2f5',
},
localIdentName: '[local]--[hash:base64:5]',
}),
addWebpackPlugin(new AntdDayjsWebpackPlugin()),
addWebpackResolve({
alias: { '@': path.resolve(__dirname, 'src') },
}),
enableEslintIgnore(),
);
27 changes: 14 additions & 13 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,14 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@pingcap-incubator/pd-client-js": "^0.1.5",
"antd": "^3.26.5",
"antd-dayjs-webpack-plugin": "^0.0.7",
"axios": "^0.19.0",
"babel-plugin-import": "^1.13.0",
"customize-cra": "^0.9.1",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"react": "^16.12.0",
"react-app-rewired": "^2.1.5",
"react-dom": "^16.12.0",
"react-scripts": "3.3.0",
"typescript": "^3.7.4",
"@pingcap-incubator/pd-client-js": "^0.1.5"
"react-router-dom": "^5.1.2",
"single-spa": "^4.4.2",
"single-spa-react": "^2.11.0"
},
"scripts": {
"start": "react-app-rewired start",
Expand All @@ -44,6 +36,15 @@
]
},
"devDependencies": {
"@openapitools/openapi-generator-cli": "^1.0.8-4.2.2"
"@openapitools/openapi-generator-cli": "^1.0.8-4.2.2",
"@types/react-router-dom": "^5.1.3",
"antd-dayjs-webpack-plugin": "^0.0.8",
"babel-plugin-import": "^1.13.0",
"customize-cra": "^0.9.1",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"react-app-rewired": "^2.1.5",
"react-scripts": "3.1.x",
"typescript": "^3.7.4"
}
}
18 changes: 3 additions & 15 deletions ui/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,13 @@
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="TiDB Dashboard"
/>
<meta name="description" content="TiDB Dashboard"/>
<style>body{margin:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Fira Sans','Droid Sans','Helvetica Neue',sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background:#f0f2f5}#dashboard_page_spinner{font-size:10px;text-indent:-9999em;width:8em;height:8em;position:fixed;margin-left:-4em;margin-top:-4em;left:50%;top:50%;border-radius:50%;background:#a1d8f8;background:-moz-linear-gradient(left,#a1d8f8 10%,rgba(161,216,248,0) 42%);background:-webkit-linear-gradient(left,#a1d8f8 10%,rgba(161,216,248,0) 42%);background:-o-linear-gradient(left,#a1d8f8 10%,rgba(161,216,248,0) 42%);background:-ms-linear-gradient(left,#a1d8f8 10%,rgba(161,216,248,0) 42%);background:linear-gradient(to right,#a1d8f8 10%,rgba(161,216,248,0) 42%);-webkit-animation:load3 1.4s infinite linear;animation:load3 1.4s infinite linear;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}#dashboard_page_spinner:before{width:50%;height:50%;background:#a1d8f8;border-radius:100% 0 0 0;position:absolute;top:0;left:0;content:''}#dashboard_page_spinner:after{background:#f0f2f5;width:75%;height:75%;border-radius:50%;content:'';margin:auto;position:absolute;top:0;left:0;bottom:0;right:0}@-webkit-keyframes load3{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load3{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}</style>
<title>TiDB Dashboard</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="dashboard_page_spinner"></div>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
Empty file removed ui/src/App.css
Empty file.
12 changes: 8 additions & 4 deletions ui/src/App.js → ui/src/apps/demo/RootComponent.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import React from 'react';
import { Button } from 'antd';
import './App.css';
import { Link } from 'react-router-dom';
import { HashRouter as Router } from 'react-router-dom';

import client from './utils/client';
import client from '@/utils/client';

const App = () => (
<div className="App">
<Router>
<Button type="primary" onClick={handleClick}>Button</Button>
</div>
<Link to="/home">
<Button type="primary">Go To Home</Button>
</Link>
</Router>
);

async function handleClick() {
Expand Down
25 changes: 25 additions & 0 deletions ui/src/apps/demo/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import ReactDOM from 'react-dom';
import singleSpaReact from 'single-spa-react';
import RootComponent from './RootComponent.js';

const reactLifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent: RootComponent,
domElementGetter,
});

export const bootstrap = [
reactLifecycles.bootstrap,
];
export const mount = [
reactLifecycles.mount,
];
export const unmount = [
reactLifecycles.unmount,
];

function domElementGetter() {
return document.getElementById('__spa_content__');
}
7 changes: 7 additions & 0 deletions ui/src/apps/demo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
id: 'demo',
loader: () => import('./app.js'),
routerPrefix: '/demo',
icon: 'pie-chart',
menuTitle: 'Demo 2', // TODO: I18N
}
49 changes: 49 additions & 0 deletions ui/src/apps/home/RootComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { Menu } from 'antd';
import { HashRouter as Router, Switch, Route, Link } from 'react-router-dom';

const App = () => (
<Router>
<p>Hello World</p>
<p>Sample child navigation</p>
<Menu mode="horizontal">
<Menu.Item>
<Link to="/home/">Home</Link>
</Menu.Item>
<Menu.Item>
<Link to="/home/about">Home/About</Link>
</Menu.Item>
<Menu.Item>
<Link to="/home/users">Home/Users</Link>
</Menu.Item>
<Menu.Item>
<Link to="/demo">Demo</Link>
</Menu.Item>
</Menu>
<Switch>
<Route path="/home/about">
<About />
</Route>
<Route path="/home/users">
<Users />
</Route>
<Route path="/demo">
<Home />
</Route>
</Switch>
</Router>
);

function Home() {
return <h2>Home</h2>;
}

function About() {
return <h2>About</h2>;
}

function Users() {
return <h2>Users</h2>;
}

export default App;
25 changes: 25 additions & 0 deletions ui/src/apps/home/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import ReactDOM from 'react-dom';
import singleSpaReact from 'single-spa-react';
import RootComponent from './RootComponent.js';

const reactLifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent: RootComponent,
domElementGetter,
});

export const bootstrap = [
reactLifecycles.bootstrap,
];
export const mount = [
reactLifecycles.mount,
];
export const unmount = [
reactLifecycles.unmount,
];

function domElementGetter() {
return document.getElementById('__spa_content__');
}
7 changes: 7 additions & 0 deletions ui/src/apps/home/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
id: 'home',
loader: () => import('./app.js'),
routerPrefix: '/home',
icon: 'desktop',
menuTitle: 'Demo 1', // TODO: I18N
}
13 changes: 0 additions & 13 deletions ui/src/index.css
Original file line number Diff line number Diff line change
@@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
99 changes: 96 additions & 3 deletions ui/src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,99 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Menu, Icon } from 'antd';
import { Link } from 'react-router-dom';

import * as singleSpa from 'single-spa';
import * as LayoutSPA from '@/layout';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
import AppHome from '@/apps/home';
import AppDemo from '@/apps/demo';

// TODO: This part might be better in TS.
class AppRegistry {
constructor() {
this.defaultRouter = '';
this.apps = {};
}

/**
* Register a TiDB Dashboard application.
*
* This function is a light encapsulation over single-spa's registerApplication
* which provides some extra registry capabilities.
*
* @param {{
* id: string,
* loader: Function,
* routerPrefix: string,
* indexRoute: string,
* isDefaultRouter: boolean,
* icon: string,
* menuTitle: string,
* }} app
*/
register(app) {
singleSpa.registerApplication(app.id, app.loader, (location) => {
return location.hash.indexOf('#' + app.routerPrefix) === 0;
});
if (!app.indexRoute) {
app.indexRoute = app.routerPrefix;
}
if (!this.defaultRouter || app.isDefaultRouter) {
this.defaultRouter = app.indexRoute;
}
this.apps[app.id] = app;
return this;
}

/**
* Get the default router for initial routing.
*/
getDefaultRouter() {
return this.defaultRouter || '/';
}

/**
* Get the registry of the current active app.
*/
getActiveApp() {
const mountedApps = singleSpa.getMountedApps();
for (let i = 0; i < mountedApps.length; i++) {
const app = mountedApps[i];
if (this.apps[app] !== undefined) {
return this.apps[app];
}
}
}

/**
* Render an Antd menu item according to the app id.
*
* @param {string} appId
*/
renderAppMenuItem(appId) {
const app = this.apps[appId];
if (!app) {
return null;
}
return (
<Menu.Item key={appId}>
<Link to={app.indexRoute}>
{ app.icon ? <Icon type={app.icon} /> : null }
<span>{app.menuTitle}</span>
</Link>
</Menu.Item>
);
}
}

const registry = new AppRegistry();

singleSpa.registerApplication('layout', LayoutSPA, () => true, { registry });
registry
.register(AppHome)
.register(AppDemo)
;
singleSpa.start();

document.getElementById('dashboard_page_spinner').remove();
Loading

0 comments on commit eb0a97a

Please sign in to comment.