forked from ddrilling/asb_cloud_front
innit
This commit is contained in:
parent
221faded03
commit
ef8bca20a4
23
.vscode/launch.json
vendored
Normal file
23
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch Edge",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "pwa-msedge",
|
||||||
|
"url": "http://localhost:3000",
|
||||||
|
"webRoot": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "pwa-chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Chrome against localhost",
|
||||||
|
"url": "http://localhost:3000",
|
||||||
|
"webRoot": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
17
craco.config.js
Normal file
17
craco.config.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const CracoLessPlugin = require('craco-less');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
plugin: CracoLessPlugin,
|
||||||
|
options: {
|
||||||
|
lessLoaderOptions: {
|
||||||
|
lessOptions: {
|
||||||
|
//modifyVars: { '@primary-color': '#E20000' },
|
||||||
|
javascriptEnabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
1177
package-lock.json
generated
1177
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@ -3,20 +3,29 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@craco/craco": "^6.1.1",
|
||||||
"@testing-library/jest-dom": "^5.11.10",
|
"@testing-library/jest-dom": "^5.11.10",
|
||||||
"@testing-library/react": "^11.2.6",
|
"@testing-library/react": "^11.2.6",
|
||||||
"@testing-library/user-event": "^12.8.3",
|
"@testing-library/user-event": "^12.8.3",
|
||||||
|
"antd": "^4.15.0",
|
||||||
|
"craco-less": "^1.17.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
|
"typescript": "^4.2.3",
|
||||||
"web-vitals": "^1.1.1"
|
"web-vitals": "^1.1.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "craco start",
|
||||||
"build": "react-scripts build",
|
"build": "craco build",
|
||||||
"test": "react-scripts test",
|
"test": "craco test",
|
||||||
|
"react_start": "react-scripts start",
|
||||||
|
"react_build": "react-scripts build",
|
||||||
|
"react_test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
|
"proxy": "http://localhost:5000",
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
"react-app",
|
"react-app",
|
||||||
@ -25,7 +34,7 @@
|
|||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
">0.2%",
|
">10%",
|
||||||
"not dead",
|
"not dead",
|
||||||
"not op_mini all"
|
"not op_mini all"
|
||||||
],
|
],
|
||||||
@ -34,5 +43,9 @@
|
|||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"openapi-typescript": "^3.2.0",
|
||||||
|
"openapi-typescript-codegen": "^0.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
src/App.css
38
src/App.css
@ -1,38 +0,0 @@
|
|||||||
.App {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-logo {
|
|
||||||
height: 40vmin;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
|
||||||
.App-logo {
|
|
||||||
animation: App-logo-spin infinite 20s linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-header {
|
|
||||||
background-color: #282c34;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: calc(10px + 2vmin);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.App-link {
|
|
||||||
color: #61dafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes App-logo-spin {
|
|
||||||
from {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
58
src/App.js
58
src/App.js
@ -1,25 +1,43 @@
|
|||||||
import logo from './logo.svg';
|
import './styles/App.less'
|
||||||
import './App.css';
|
import React /*, { useContext, createContext, useState }*/ from "react"
|
||||||
|
import {
|
||||||
|
BrowserRouter as Router,
|
||||||
|
Switch,
|
||||||
|
Route,
|
||||||
|
Redirect
|
||||||
|
} from "react-router-dom"
|
||||||
|
import Login from './pages/Login'
|
||||||
|
import Main from './pages/Main'
|
||||||
|
import {OpenAPI} from './services/api'
|
||||||
|
|
||||||
function App() {
|
OpenAPI.BASE = 'http://localhost:3000'
|
||||||
|
OpenAPI.TOKEN = localStorage['token']
|
||||||
|
|
||||||
|
function PrivateRoute({ children, ...rest }) {
|
||||||
|
let token = localStorage['token']
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<Route
|
||||||
<header className="App-header">
|
{...rest}
|
||||||
<img src={logo} className="App-logo" alt="logo" />
|
render={({ location }) =>
|
||||||
<p>
|
token
|
||||||
Edit <code>src/App.js</code> and save to reload.
|
? (children)
|
||||||
</p>
|
: (<Redirect to={{pathname: "/login",state: { from: location }}}/>)
|
||||||
<a
|
}
|
||||||
className="App-link"
|
/>
|
||||||
href="https://reactjs.org"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Learn React
|
|
||||||
</a>
|
|
||||||
</header>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<Router>
|
||||||
|
<Switch>
|
||||||
|
<Route path="/login">
|
||||||
|
<Login />
|
||||||
|
</Route>
|
||||||
|
<PrivateRoute path="/">
|
||||||
|
<Main />
|
||||||
|
</PrivateRoute>
|
||||||
|
</Switch>
|
||||||
|
</Router>
|
||||||
|
)
|
||||||
|
}
|
@ -1,8 +0,0 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
|
||||||
import App from './App';
|
|
||||||
|
|
||||||
test('renders learn react link', () => {
|
|
||||||
render(<App />);
|
|
||||||
const linkElement = screen.getByText(/learn react/i);
|
|
||||||
expect(linkElement).toBeInTheDocument();
|
|
||||||
});
|
|
4
src/components/Loader.jsx
Normal file
4
src/components/Loader.jsx
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/* original from https://loading.io/css/ */
|
||||||
|
export default function Loader(){
|
||||||
|
return(<div className="lds-ripple"><div></div><div></div></div>)
|
||||||
|
}
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
125
src/images/logoSmaill.svg
Normal file
125
src/images/logoSmaill.svg
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
id="svg736"
|
||||||
|
viewBox="0 0 8006.9226 3574.0189"
|
||||||
|
style="clip-rule:evenodd;fill-rule:evenodd;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
|
||||||
|
version="1.1"
|
||||||
|
height="38.606144mm"
|
||||||
|
width="86.490891mm"
|
||||||
|
xml:space="preserve"><metadata
|
||||||
|
id="metadata740"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs674"><style
|
||||||
|
id="style669"
|
||||||
|
type="text/css"><![CDATA[
|
||||||
|
.fil4 {fill:none}
|
||||||
|
.fil1 {fill:#2D2242}
|
||||||
|
.fil3 {fill:#9D9E9E}
|
||||||
|
.fil0 {fill:#E31E24}
|
||||||
|
.fil2 {fill:#FEFEFE}
|
||||||
|
.fil5 {fill:#2D2242;fill-rule:nonzero}
|
||||||
|
]]></style><clipPath
|
||||||
|
id="id0"><path
|
||||||
|
id="path671"
|
||||||
|
d="m 5189,716 c 587,0 1063,476 1063,1063 0,587 -476,1063 -1063,1063 -588,0 -1064,-476 -1064,-1063 0,-587 476,-1063 1064,-1063 z" /></clipPath></defs><g
|
||||||
|
transform="translate(-1018.0595)"
|
||||||
|
id="Слой_x0020_1"><metadata
|
||||||
|
id="CorelCorpID_0Corel-Layer" /><g
|
||||||
|
id="_661845560"><path
|
||||||
|
style="fill:#e31e24"
|
||||||
|
id="path677"
|
||||||
|
d="M 1756,3564 H 1018 L 3236,2 3848,3 4452,0 4400,184 C 4637,66 4905,0 5189,0 5751,0 6253,261 6579,669 l -233,810 C 6213,964 5745,584 5189,584 c -528,0 -975,341 -1134,815 l -30,108 c -20,87 -31,178 -31,272 0,660 535,1195 1195,1195 318,0 607,-125 821,-327 l -220,764 c -185,88 -388,147 -601,147 -636,0 -1194,-334 -1508,-836 l -239,842 h -702 l 187,-595 H 2146 Z M 3082,2443 3703,446 2463,2444 Z"
|
||||||
|
class="fil0" /><path
|
||||||
|
style="fill:#e31e24"
|
||||||
|
id="path679"
|
||||||
|
d="m 7725,3574 c -392,-2 -748,-14 -1152,-2 L 5869,3559 6882,2 l 1790,1 -136,559 -1176,9 -121,462 h 836 c 570,93 953,697 950,1254 -3,656 -585,1291 -1300,1287 z m -995,-606 c 333,0 665,0 998,2 381,2 691,-335 693,-686 1,-291 -206,-632 -510,-673 h -824 z"
|
||||||
|
class="fil0" /><polygon
|
||||||
|
style="fill:#2d2242"
|
||||||
|
id="polygon681"
|
||||||
|
points="5347,1437 5105,1437 5105,1315 5347,1315 "
|
||||||
|
class="fil1" /><polygon
|
||||||
|
style="fill:#2d2242"
|
||||||
|
id="polygon683"
|
||||||
|
points="5455,1555 4992,1555 4992,1469 5455,1469 "
|
||||||
|
class="fil1" /><polygon
|
||||||
|
style="fill:#2d2242"
|
||||||
|
id="polygon685"
|
||||||
|
points="5597,2523 4860,2523 5027,1587 5419,1587 "
|
||||||
|
class="fil1" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon687"
|
||||||
|
points="5166,1737 5061,1830 5089,1676 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon689"
|
||||||
|
points="5288,1737 5393,1830 5365,1676 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon691"
|
||||||
|
points="5224,1696 5285,1654 5172,1654 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon693"
|
||||||
|
points="5143,2007 5019,2062 5039,1952 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon695"
|
||||||
|
points="5310,2007 5435,2062 5415,1952 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon697"
|
||||||
|
points="5091,1894 5229,1962 5365,1894 5229,1783 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon699"
|
||||||
|
points="5052,2132 5232,2251 5412,2130 5229,2043 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon701"
|
||||||
|
points="5163,2297 4949,2445 4996,2184 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon703"
|
||||||
|
points="5292,2297 5505,2445 5458,2184 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#fefefe"
|
||||||
|
id="polygon705"
|
||||||
|
points="5226,2337 5497,2523 4958,2523 "
|
||||||
|
class="fil2" /><polygon
|
||||||
|
style="fill:#2d2242"
|
||||||
|
id="polygon707"
|
||||||
|
points="5246,2523 5200,2523 5200,1735 5246,1735 "
|
||||||
|
class="fil1" /><g
|
||||||
|
id="g709" /><g
|
||||||
|
id="g722"
|
||||||
|
clip-path="url(#id0)"><g
|
||||||
|
id="_661862656"><path
|
||||||
|
style="fill:#9d9e9e"
|
||||||
|
id="path711"
|
||||||
|
d="m 5136,177 c -688,66 -1152,378 -1415,911 l 1475,-196 783,591 z"
|
||||||
|
class="fil3" /><path
|
||||||
|
style="fill:#9d9e9e"
|
||||||
|
id="path713"
|
||||||
|
d="M 6684,1229 C 6401,599 5957,260 5367,182 l 659,1333 -308,931 z"
|
||||||
|
class="fil3" /><path
|
||||||
|
style="fill:#2d2242"
|
||||||
|
id="path715"
|
||||||
|
d="m 6189,3044 c 509,-466 692,-994 581,-1579 l -1059,1044 -981,-1 z"
|
||||||
|
class="fil1" /><path
|
||||||
|
style="fill:#2d2242"
|
||||||
|
id="path717"
|
||||||
|
d="m 4267,3105 c 598,345 1157,360 1681,78 L 4633,2488 4337,1552 Z"
|
||||||
|
class="fil1" /><path
|
||||||
|
style="fill:#2d2242"
|
||||||
|
id="path719"
|
||||||
|
d="m 3626,1346 c -142,676 17,1212 447,1622 l 253,-1466 798,-571 z"
|
||||||
|
class="fil1" /></g></g><path
|
||||||
|
style="fill:none"
|
||||||
|
id="path724"
|
||||||
|
d="m 5189,716 c 587,0 1063,476 1063,1063 0,587 -476,1063 -1063,1063 -588,0 -1064,-476 -1064,-1063 0,-587 476,-1063 1064,-1063 z"
|
||||||
|
class="fil4" /></g></g></svg>
|
After Width: | Height: | Size: 5.3 KiB |
BIN
src/images/logo_32.png
Normal file
BIN
src/images/logo_32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './index.css';
|
import './styles/index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from './reportWebVitals';
|
||||||
|
|
||||||
|
3
src/pages/Files.jsx
Normal file
3
src/pages/Files.jsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function Files(props){
|
||||||
|
return(<h2>Files</h2>)
|
||||||
|
}
|
71
src/pages/Login.jsx
Normal file
71
src/pages/Login.jsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { Card, Form, Input, Button, notification } from 'antd';
|
||||||
|
import { UserOutlined, LockOutlined } from '@ant-design/icons'
|
||||||
|
import logo from '../images/logo_32.png'
|
||||||
|
import Loader from '../components/Loader'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useHistory } from "react-router-dom";
|
||||||
|
import { AuthService, OpenAPI } from '../services/api/'
|
||||||
|
|
||||||
|
const { login } = AuthService
|
||||||
|
|
||||||
|
const openNotificationError = (message, title) => {
|
||||||
|
notification['error']({
|
||||||
|
message: title||'Ошибка',
|
||||||
|
description: message,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setUser = (user) =>{
|
||||||
|
OpenAPI.TOKEN = user.token
|
||||||
|
localStorage['token'] = user.token
|
||||||
|
localStorage['login'] = user.login
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Login() {
|
||||||
|
const [loader, setLoader] = useState(false);
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
const logoIcon = <img src={logo} alt="АСБ" className="logo"/>
|
||||||
|
|
||||||
|
let handleSubmit = async (formData) =>{
|
||||||
|
setLoader(true)
|
||||||
|
try{
|
||||||
|
let user = await login(formData)
|
||||||
|
setUser(user)
|
||||||
|
history.push('well')
|
||||||
|
}catch(e){
|
||||||
|
if(e.status === 400)
|
||||||
|
openNotificationError(e.message)
|
||||||
|
console.error(`Error ${e}`)
|
||||||
|
}
|
||||||
|
setLoader(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='login_page shadow'>
|
||||||
|
<Card title="Система мониторинга" className='shadow' bordered={true} style={{ width: 350 }} extra={logoIcon}>
|
||||||
|
<Form onFinish={handleSubmit}>
|
||||||
|
<Form.Item
|
||||||
|
name="login"
|
||||||
|
rules={[{ required: true, message: 'Пожалуйста введите имя!' }]}>
|
||||||
|
<Input placeholder="Пользователь" prefix={<UserOutlined />}/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="password"
|
||||||
|
rules={[{ required: true, message: 'Пожалуйста введите пароль!' }]}
|
||||||
|
>
|
||||||
|
<Input.Password placeholder='пароль' prefix={<LockOutlined />}/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="primary" htmlType="submit">
|
||||||
|
Вход
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
{loader && <Loader/>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
72
src/pages/Main.jsx
Normal file
72
src/pages/Main.jsx
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { Layout, Menu, Button, } from 'antd'
|
||||||
|
import { UserOutlined, MenuOutlined, FundViewOutlined, FolderOutlined } from '@ant-design/icons'
|
||||||
|
import logo from '../images/logo_32.png'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { Switch, Route, Redirect, Link} from "react-router-dom"
|
||||||
|
import Wells from './Wells'
|
||||||
|
import Files from './Files'
|
||||||
|
|
||||||
|
const { Header, Content, Sider } = Layout
|
||||||
|
|
||||||
|
export default function Main(){
|
||||||
|
const [sidebarVisible, setSidebarVisible] = useState(true)
|
||||||
|
const login = localStorage['login']
|
||||||
|
|
||||||
|
let handlerExit = ()=>{
|
||||||
|
localStorage.removeItem('login')
|
||||||
|
localStorage.removeItem('token')
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<Layout>
|
||||||
|
<Header className="header">
|
||||||
|
<Button icon={<MenuOutlined />} onClick={()=>setSidebarVisible(!sidebarVisible)}/>
|
||||||
|
<img src={logo} alt="АСБ" className="logo"/>
|
||||||
|
<h1 className="title">Мониторинг</h1>
|
||||||
|
<Link to="/login" onClick={handlerExit}>
|
||||||
|
<Button icon={<UserOutlined/>}>
|
||||||
|
({login}) Выход
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</Header>
|
||||||
|
<Layout>
|
||||||
|
{sidebarVisible &&
|
||||||
|
<Sider width={200} className="site-layout-background">
|
||||||
|
<Menu
|
||||||
|
mode="inline"
|
||||||
|
defaultSelectedKeys={['1']}
|
||||||
|
defaultOpenKeys={['sub1']}
|
||||||
|
style={{ height: '100%', borderRight: 0 }}
|
||||||
|
>
|
||||||
|
<Menu.Item key="1" icon= {<FundViewOutlined />}>
|
||||||
|
<Link to="/well">Мониторинг</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="2" icon= {<FolderOutlined />}>
|
||||||
|
<Link to="/file">файлы</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
</Sider>
|
||||||
|
}
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<Content className="site-layout-background sheet">
|
||||||
|
<Switch>
|
||||||
|
<Route path="/file">
|
||||||
|
<Files />
|
||||||
|
</Route>
|
||||||
|
<Route path="/well/:id">
|
||||||
|
<Wells/>
|
||||||
|
</Route>
|
||||||
|
<Route path="/well">
|
||||||
|
<Wells />
|
||||||
|
</Route>
|
||||||
|
<Route path="/">
|
||||||
|
<Redirect to={{pathname: "/well"}}/>
|
||||||
|
</Route>
|
||||||
|
</Switch>
|
||||||
|
</Content>
|
||||||
|
</Layout>
|
||||||
|
</Layout>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
3
src/pages/Well.jsx
Normal file
3
src/pages/Well.jsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function Well(props){
|
||||||
|
return(<div>Well id: {props.id}</div>)
|
||||||
|
}
|
60
src/pages/Wells.jsx
Normal file
60
src/pages/Wells.jsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { WellService, OpenAPI } from '../services/api'
|
||||||
|
import Loader from '../components/Loader'
|
||||||
|
import { Table } from 'antd';
|
||||||
|
import { useHistory } from 'react-router-dom'
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'Месторождение',
|
||||||
|
dataIndex: 'deposit',
|
||||||
|
key: 'deposit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Куст',
|
||||||
|
dataIndex: 'cluster',
|
||||||
|
key: 'cluster',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Скважина',
|
||||||
|
dataIndex: 'caption',
|
||||||
|
key: 'caption',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Данные',
|
||||||
|
dataIndex: 'lastData',
|
||||||
|
key: 'lastData',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Wells(props){
|
||||||
|
const [wells, setWells] = useState([])
|
||||||
|
const [loader, setLoader] = useState(false)
|
||||||
|
const history = useHistory()
|
||||||
|
|
||||||
|
let updateWellsList = async () => {
|
||||||
|
setLoader(true)
|
||||||
|
try{
|
||||||
|
setWells( await WellService.get())
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
console.error(`${e.message}`);
|
||||||
|
}
|
||||||
|
setLoader(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(()=>{updateWellsList()}, [])
|
||||||
|
|
||||||
|
return(<>
|
||||||
|
<h2>Wells</h2>
|
||||||
|
<Table
|
||||||
|
dataSource={wells}
|
||||||
|
columns={columns}
|
||||||
|
onRow={(record, rowIndex) => {
|
||||||
|
return {
|
||||||
|
onClick: event => {history.push(`wells/${record.id}`)},
|
||||||
|
};
|
||||||
|
}}/>
|
||||||
|
{loader&&<Loader/>}
|
||||||
|
</>)
|
||||||
|
}
|
1
src/react-app-env.d.ts
vendored
Normal file
1
src/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="react-scripts" />
|
1
src/services/AutoGenerateApi.md
Normal file
1
src/services/AutoGenerateApi.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
npx openapi -i http://localhost:5000/swagger/v1/swagger.json -o src/services/openapi
|
20
src/services/api/core/ApiError.ts
Normal file
20
src/services/api/core/ApiError.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
import type { ApiResult } from './ApiResult';
|
||||||
|
|
||||||
|
export class ApiError extends Error {
|
||||||
|
public readonly url: string;
|
||||||
|
public readonly status: number;
|
||||||
|
public readonly statusText: string;
|
||||||
|
public readonly body: any;
|
||||||
|
|
||||||
|
constructor(response: ApiResult, message: string) {
|
||||||
|
super(message);
|
||||||
|
|
||||||
|
this.url = response.url;
|
||||||
|
this.status = response.status;
|
||||||
|
this.statusText = response.statusText;
|
||||||
|
this.body = response.body;
|
||||||
|
}
|
||||||
|
}
|
14
src/services/api/core/ApiRequestOptions.ts
Normal file
14
src/services/api/core/ApiRequestOptions.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type ApiRequestOptions = {
|
||||||
|
readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH';
|
||||||
|
readonly path: string;
|
||||||
|
readonly cookies?: Record<string, any>;
|
||||||
|
readonly headers?: Record<string, any>;
|
||||||
|
readonly query?: Record<string, any>;
|
||||||
|
readonly formData?: Record<string, any>;
|
||||||
|
readonly body?: any;
|
||||||
|
readonly responseHeader?: string;
|
||||||
|
readonly errors?: Record<number, string>;
|
||||||
|
}
|
10
src/services/api/core/ApiResult.ts
Normal file
10
src/services/api/core/ApiResult.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type ApiResult = {
|
||||||
|
readonly url: string;
|
||||||
|
readonly ok: boolean;
|
||||||
|
readonly status: number;
|
||||||
|
readonly statusText: string;
|
||||||
|
readonly body: any;
|
||||||
|
}
|
27
src/services/api/core/OpenAPI.ts
Normal file
27
src/services/api/core/OpenAPI.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||||
|
|
||||||
|
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
|
||||||
|
type Headers = Record<string, string>;
|
||||||
|
|
||||||
|
type Config = {
|
||||||
|
BASE: string;
|
||||||
|
VERSION: string;
|
||||||
|
WITH_CREDENTIALS: boolean;
|
||||||
|
TOKEN?: string | Resolver<string>;
|
||||||
|
USERNAME?: string | Resolver<string>;
|
||||||
|
PASSWORD?: string | Resolver<string>;
|
||||||
|
HEADERS?: Headers | Resolver<Headers>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const OpenAPI: Config = {
|
||||||
|
BASE: '',
|
||||||
|
VERSION: '1',
|
||||||
|
WITH_CREDENTIALS: false,
|
||||||
|
TOKEN: undefined,
|
||||||
|
USERNAME: undefined,
|
||||||
|
PASSWORD: undefined,
|
||||||
|
HEADERS: undefined,
|
||||||
|
};
|
205
src/services/api/core/request.ts
Normal file
205
src/services/api/core/request.ts
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
import { ApiError } from './ApiError';
|
||||||
|
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||||
|
import type { ApiResult } from './ApiResult';
|
||||||
|
import { OpenAPI } from './OpenAPI';
|
||||||
|
|
||||||
|
function isDefined<T>(value: T | null | undefined): value is Exclude<T, null | undefined> {
|
||||||
|
return value !== undefined && value !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isString(value: any): value is string {
|
||||||
|
return typeof value === 'string';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isStringWithValue(value: any): value is string {
|
||||||
|
return isString(value) && value !== '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBlob(value: any): value is Blob {
|
||||||
|
return value instanceof Blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getQueryString(params: Record<string, any>): string {
|
||||||
|
const qs: string[] = [];
|
||||||
|
Object.keys(params).forEach(key => {
|
||||||
|
const value = params[key];
|
||||||
|
if (isDefined(value)) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.forEach(value => {
|
||||||
|
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (qs.length > 0) {
|
||||||
|
return `?${qs.join('&')}`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUrl(options: ApiRequestOptions): string {
|
||||||
|
const path = options.path.replace(/[:]/g, '_');
|
||||||
|
const url = `${OpenAPI.BASE}${path}`;
|
||||||
|
|
||||||
|
if (options.query) {
|
||||||
|
return `${url}${getQueryString(options.query)}`;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFormData(params: Record<string, any>): FormData {
|
||||||
|
const formData = new FormData();
|
||||||
|
Object.keys(params).forEach(key => {
|
||||||
|
const value = params[key];
|
||||||
|
if (isDefined(value)) {
|
||||||
|
formData.append(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
|
||||||
|
|
||||||
|
async function resolve<T>(options: ApiRequestOptions, resolver?: T | Resolver<T>): Promise<T | undefined> {
|
||||||
|
if (typeof resolver === 'function') {
|
||||||
|
return (resolver as Resolver<T>)(options);
|
||||||
|
}
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
|
||||||
|
const token = await resolve(options, OpenAPI.TOKEN);
|
||||||
|
const username = await resolve(options, OpenAPI.USERNAME);
|
||||||
|
const password = await resolve(options, OpenAPI.PASSWORD);
|
||||||
|
const defaultHeaders = await resolve(options, OpenAPI.HEADERS);
|
||||||
|
|
||||||
|
const headers = new Headers({
|
||||||
|
Accept: 'application/json',
|
||||||
|
...defaultHeaders,
|
||||||
|
...options.headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isStringWithValue(token)) {
|
||||||
|
headers.append('Authorization', `Bearer ${token}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStringWithValue(username) && isStringWithValue(password)) {
|
||||||
|
const credentials = btoa(`${username}:${password}`);
|
||||||
|
headers.append('Authorization', `Basic ${credentials}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.body) {
|
||||||
|
if (isBlob(options.body)) {
|
||||||
|
headers.append('Content-Type', options.body.type || 'application/octet-stream');
|
||||||
|
} else if (isString(options.body)) {
|
||||||
|
headers.append('Content-Type', 'text/plain');
|
||||||
|
} else {
|
||||||
|
headers.append('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRequestBody(options: ApiRequestOptions): BodyInit | undefined {
|
||||||
|
if (options.formData) {
|
||||||
|
return getFormData(options.formData);
|
||||||
|
}
|
||||||
|
if (options.body) {
|
||||||
|
if (isString(options.body) || isBlob(options.body)) {
|
||||||
|
return options.body;
|
||||||
|
} else {
|
||||||
|
return JSON.stringify(options.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendRequest(options: ApiRequestOptions, url: string): Promise<Response> {
|
||||||
|
const request: RequestInit = {
|
||||||
|
method: options.method,
|
||||||
|
headers: await getHeaders(options),
|
||||||
|
body: getRequestBody(options),
|
||||||
|
};
|
||||||
|
if (OpenAPI.WITH_CREDENTIALS) {
|
||||||
|
request.credentials = 'include';
|
||||||
|
}
|
||||||
|
return await fetch(url, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getResponseHeader(response: Response, responseHeader?: string): string | null {
|
||||||
|
if (responseHeader) {
|
||||||
|
const content = response.headers.get(responseHeader);
|
||||||
|
if (isString(content)) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getResponseBody(response: Response): Promise<any> {
|
||||||
|
try {
|
||||||
|
const contentType = response.headers.get('Content-Type');
|
||||||
|
if (contentType) {
|
||||||
|
const isJSON = contentType.toLowerCase().startsWith('application/json');
|
||||||
|
if (isJSON) {
|
||||||
|
return await response.json();
|
||||||
|
} else {
|
||||||
|
return await response.text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function catchErrors(options: ApiRequestOptions, result: ApiResult): void {
|
||||||
|
const errors: Record<number, string> = {
|
||||||
|
400: 'Bad Request',
|
||||||
|
401: 'Unauthorized',
|
||||||
|
403: 'Forbidden',
|
||||||
|
404: 'Not Found',
|
||||||
|
500: 'Internal Server Error',
|
||||||
|
502: 'Bad Gateway',
|
||||||
|
503: 'Service Unavailable',
|
||||||
|
...options.errors,
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = errors[result.status];
|
||||||
|
if (error) {
|
||||||
|
throw new ApiError(result, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.ok) {
|
||||||
|
throw new ApiError(result, 'Generic Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request using fetch client
|
||||||
|
* @param options The request options from the the service
|
||||||
|
* @returns ApiResult
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
export async function request(options: ApiRequestOptions): Promise<ApiResult> {
|
||||||
|
const url = getUrl(options);
|
||||||
|
const response = await sendRequest(options, url);
|
||||||
|
const responseBody = await getResponseBody(response);
|
||||||
|
const responseHeader = getResponseHeader(response, options.responseHeader);
|
||||||
|
|
||||||
|
const result: ApiResult = {
|
||||||
|
url,
|
||||||
|
ok: response.ok,
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
body: responseHeader || responseBody,
|
||||||
|
};
|
||||||
|
|
||||||
|
catchErrors(options, result);
|
||||||
|
return result;
|
||||||
|
}
|
12
src/services/api/index.ts
Normal file
12
src/services/api/index.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export { ApiError } from './core/ApiError';
|
||||||
|
export { OpenAPI } from './core/OpenAPI';
|
||||||
|
|
||||||
|
export type { AuthDto } from './models/AuthDto';
|
||||||
|
export type { UserTokenDto } from './models/UserTokenDto';
|
||||||
|
export type { WellDto } from './models/WellDto';
|
||||||
|
|
||||||
|
export { AuthService } from './services/AuthService';
|
||||||
|
export { WellService } from './services/WellService';
|
8
src/services/api/models/AuthDto.ts
Normal file
8
src/services/api/models/AuthDto.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
export type AuthDto = {
|
||||||
|
login?: string | null;
|
||||||
|
password?: string | null;
|
||||||
|
}
|
15
src/services/api/models/UserTokenDto.ts
Normal file
15
src/services/api/models/UserTokenDto.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
export type UserTokenDto = {
|
||||||
|
login?: string | null;
|
||||||
|
level?: number | null;
|
||||||
|
name?: string | null;
|
||||||
|
surname?: string | null;
|
||||||
|
patronymic?: string | null;
|
||||||
|
id?: number;
|
||||||
|
customerName?: string | null;
|
||||||
|
roleName?: string | null;
|
||||||
|
token?: string | null;
|
||||||
|
}
|
11
src/services/api/models/WellDto.ts
Normal file
11
src/services/api/models/WellDto.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
export type WellDto = {
|
||||||
|
id?: number;
|
||||||
|
caption?: string | null;
|
||||||
|
cluster?: string | null;
|
||||||
|
deposit?: string | null;
|
||||||
|
lastData?: any;
|
||||||
|
}
|
43
src/services/api/services/AuthService.ts
Normal file
43
src/services/api/services/AuthService.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
import type { AuthDto } from '../models/AuthDto';
|
||||||
|
import type { UserTokenDto } from '../models/UserTokenDto';
|
||||||
|
import { request as __request } from '../core/request';
|
||||||
|
|
||||||
|
export class AuthService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Аутентификация пользователя
|
||||||
|
* @param requestBody
|
||||||
|
* @returns UserTokenDto новый токен
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static async login(
|
||||||
|
requestBody?: AuthDto,
|
||||||
|
): Promise<UserTokenDto> {
|
||||||
|
const result = await __request({
|
||||||
|
method: 'POST',
|
||||||
|
path: `/auth/login`,
|
||||||
|
body: requestBody,
|
||||||
|
errors: {
|
||||||
|
400: `логин и пароль не подходят`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return result.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Продление срока действия токена
|
||||||
|
* @returns any Success
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static async refresh(): Promise<any> {
|
||||||
|
const result = await __request({
|
||||||
|
method: 'GET',
|
||||||
|
path: `/auth/refresh`,
|
||||||
|
});
|
||||||
|
return result.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
21
src/services/api/services/WellService.ts
Normal file
21
src/services/api/services/WellService.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
import type { WellDto } from '../models/WellDto';
|
||||||
|
import { request as __request } from '../core/request';
|
||||||
|
|
||||||
|
export class WellService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns WellDto Success
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static async get(): Promise<Array<WellDto>> {
|
||||||
|
const result = await __request({
|
||||||
|
method: 'GET',
|
||||||
|
path: `/api/Well`,
|
||||||
|
});
|
||||||
|
return result.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +0,0 @@
|
|||||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
|
||||||
// allows you to do things like:
|
|
||||||
// expect(element).toHaveTextContent(/react/i)
|
|
||||||
// learn more: https://github.com/testing-library/jest-dom
|
|
||||||
import '@testing-library/jest-dom';
|
|
76
src/styles/App.less
Normal file
76
src/styles/App.less
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
@import '~antd/dist/antd.less';
|
||||||
|
@import './loader.css';
|
||||||
|
// Переменные для темы тут:
|
||||||
|
// https://github.com/ant-design/ant-design/blob/master/components/style/themes/default.less
|
||||||
|
|
||||||
|
//@primary-color: rgba(124, 124, 124, 0.3);
|
||||||
|
@primary-color: rgb(195, 40,40);
|
||||||
|
//@primary-color:rgb(65, 63, 61);
|
||||||
|
//@layout-header-background: rgb(195, 40,40);
|
||||||
|
@layout-header-background: rgb(65, 63, 61);
|
||||||
|
|
||||||
|
#root, .app{min-height:100%;}
|
||||||
|
|
||||||
|
.login_page{
|
||||||
|
position: absolute;
|
||||||
|
height:100%;
|
||||||
|
width:100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shadow{
|
||||||
|
box-shadow: 1px 1px 4px #00000033;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header .logo {
|
||||||
|
background-color: rgb(230, 230, 230);
|
||||||
|
border-radius: 32px;
|
||||||
|
padding: 8px 24px;
|
||||||
|
margin: 8px 10px;
|
||||||
|
box-shadow: #fff 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header .title{
|
||||||
|
flex-grow: 1;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
justify-content: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header button{
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sheet{
|
||||||
|
padding: 24px;
|
||||||
|
margin: 8px;
|
||||||
|
min-height: 280;
|
||||||
|
}
|
||||||
|
|
||||||
|
#components-layout-demo-top-side-2 .logo {
|
||||||
|
float: left;
|
||||||
|
width: 120px;
|
||||||
|
height: 31px;
|
||||||
|
margin: 16px 24px 16px 0;
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-row-rtl #components-layout-demo-top-side-2 .logo {
|
||||||
|
float: right;
|
||||||
|
margin: 16px 0 16px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-layout-background {
|
||||||
|
background: #fff;
|
||||||
|
}
|
@ -7,7 +7,9 @@ body {
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
34
src/styles/loader.css
Normal file
34
src/styles/loader.css
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* original from https://loading.io/css/ */
|
||||||
|
|
||||||
|
.lds-ripple {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
.lds-ripple div {
|
||||||
|
position: absolute;
|
||||||
|
border: 4px solid rgb(226, 29, 29);
|
||||||
|
opacity: 1;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
||||||
|
}
|
||||||
|
.lds-ripple div:nth-child(2) {
|
||||||
|
animation-delay: -0.5s;
|
||||||
|
}
|
||||||
|
@keyframes lds-ripple {
|
||||||
|
0% {
|
||||||
|
top: 36px;
|
||||||
|
left: 36px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
26
tsconfig.json
Normal file
26
tsconfig.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user