init a react-app
Signed-off-by: Augustin Husson <augustin.husson@amadeus.com>
This commit is contained in:
parent
eea788a968
commit
c86c6131ae
|
@ -0,0 +1,83 @@
|
|||
module.exports = {
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
'plugin:jsx-a11y/recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
|
||||
plugins: ['import'],
|
||||
|
||||
env: {
|
||||
commonjs: true,
|
||||
es6: true,
|
||||
jest: true,
|
||||
node: true,
|
||||
browser: true,
|
||||
},
|
||||
|
||||
parser: '@typescript-eslint/parser',
|
||||
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
'prettier/prettier': 'error',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/array-type': [
|
||||
'warn',
|
||||
{
|
||||
default: 'array-simple',
|
||||
},
|
||||
],
|
||||
'import/order': 'warn',
|
||||
// you must disable the base rule as it can report incorrect errors
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': ['error'],
|
||||
|
||||
'react/prop-types': 'off',
|
||||
'react-hooks/exhaustive-deps': 'warn',
|
||||
// Not necessary in React 17
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: [
|
||||
{
|
||||
/**
|
||||
* This library is gigantic and named imports end up slowing down builds/blowing out bundle sizes,
|
||||
* so this prevents that style of import.
|
||||
*/
|
||||
group: ['mdi-material-ui', '!mdi-material-ui/'],
|
||||
message: `
|
||||
Please use the default import from the icon file directly rather than using a named import.
|
||||
|
||||
Good:
|
||||
import IconName from 'mdi-material-ui/IconName';
|
||||
|
||||
Bad:
|
||||
import { IconName } from 'mdi-material-ui';
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
ignorePatterns: ['**/dist'],
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
node_modules/
|
|
@ -0,0 +1,2 @@
|
|||
# Build output
|
||||
dist/
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5"
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "@prometheus-io/alertmanager",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "rimraf dist/",
|
||||
"start": "webpack serve --config webpack.dev.ts",
|
||||
"build": "webpack --config webpack.prod.ts",
|
||||
"lint": "eslint src --ext .ts,.tsx",
|
||||
"lint:fix": "eslint --fix src --ext .ts,.tsx"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.9.3",
|
||||
"@emotion/styled": "^11.9.3",
|
||||
"@mui/material": "^5.10.14",
|
||||
"mdi-material-ui": "^7.4.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-router-dom": "^6.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.7",
|
||||
"@typescript-eslint/parser": "^5.30.7",
|
||||
"css-loader": "^6.7.1",
|
||||
"dotenv-defaults": "^5.0.2",
|
||||
"esbuild-loader": "^2.20.0",
|
||||
"eslint": "^8.20.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.6.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-webpack-plugin": "^3.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.3.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-loader": "^9.3.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.7.4",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-bundle-analyzer": "^4.7.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.11.1",
|
||||
"webpack-merge": "^5.8.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { Box } from '@mui/material';
|
||||
import Navbar from './components/navbar';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
minHeight: '100vh',
|
||||
}}
|
||||
>
|
||||
<Navbar />
|
||||
<Box
|
||||
sx={{
|
||||
paddingBottom: (theme) => theme.spacing(1),
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
|
@ -0,0 +1,30 @@
|
|||
import { AppBar, Box, Button, Toolbar, Typography } from '@mui/material';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
|
||||
export default function Navbar(): JSX.Element {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<AppBar position='relative'>
|
||||
<Toolbar>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'row' }} flexGrow={1}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
navigate('/');
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant='h1'
|
||||
sx={(theme) => ({
|
||||
marginRight: '1rem',
|
||||
color: theme.palette.common.white,
|
||||
})}
|
||||
>
|
||||
AlertManager
|
||||
</Typography>
|
||||
</Button>
|
||||
</Box>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<meta name="theme-color" content="#000000"/>
|
||||
<meta name="description" content="AlertManager"/>
|
||||
<title>Perses</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,20 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
function renderApp(container: Element| null) {
|
||||
if (container === null) {
|
||||
return;
|
||||
}
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<BrowserRouter>
|
||||
<App/>
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
renderApp(document.getElementById('root'));
|
|
@ -0,0 +1,31 @@
|
|||
// Base config for all typescript packages
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2018",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"module": "esnext",
|
||||
"jsx": "react-jsx",
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"pretty": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src"],
|
||||
// For builds that use ts-node to compile the configs (e.g. webpack, jest)
|
||||
"ts-node": {
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2023 The Perses Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import path from 'path';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import { Configuration } from 'webpack';
|
||||
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
||||
import ESLintWebpackPlugin from 'eslint-webpack-plugin';
|
||||
|
||||
export const commonConfig: Configuration = {
|
||||
entry: path.resolve(__dirname, './src/index.tsx'),
|
||||
output: {
|
||||
path: path.resolve(__dirname, './dist'),
|
||||
publicPath: '/',
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js', 'jsx', '.json'],
|
||||
},
|
||||
plugins: [
|
||||
// Generates HTML index page with bundle injected
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.resolve(__dirname, './src/index.html'),
|
||||
templateParameters: {},
|
||||
}),
|
||||
// Does TS type-checking in a separate process
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
typescript: {
|
||||
configFile: path.resolve(__dirname, './tsconfig.json'),
|
||||
},
|
||||
}),
|
||||
new ESLintWebpackPlugin({
|
||||
threads: true,
|
||||
files: '../*/src/**/*.{ts,tsx,js,jsx}',
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
// Type-checking happens in separate plugin process
|
||||
transpileOnly: true,
|
||||
projectReferences: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|woff|woff2)$/,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|gif)$/,
|
||||
type: 'asset',
|
||||
},
|
||||
// SVG as React components
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
{
|
||||
loader: '@svgr/webpack',
|
||||
options: {
|
||||
// Generated React components will support a 'title' prop to render
|
||||
// a <title> inside the <svg>
|
||||
titleProp: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2023 The Perses Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import fs from 'fs';
|
||||
import { Configuration } from 'webpack';
|
||||
import { Configuration as DevServerConfig, ServerConfiguration } from 'webpack-dev-server';
|
||||
import { merge } from 'webpack-merge';
|
||||
import { commonConfig } from './webpack.common';
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
require('dotenv-defaults').config();
|
||||
|
||||
declare module 'webpack' {
|
||||
interface Configuration {
|
||||
devServer?: DevServerConfig | undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Get dev server HTTP options (note: HTTP2 is not currently supported by webpack since we're on Node 16)
|
||||
function getServerConfig(): ServerConfiguration | undefined {
|
||||
// Just use regular HTTP by default
|
||||
if (process.env.HTTPS !== 'true') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Support the same HTTPS options as Creact React App if HTTPS is set
|
||||
if (process.env.SSL_KEY_FILE === undefined || process.env.SSL_CRT_FILE === undefined) {
|
||||
// Use the default self-signed cert
|
||||
return { type: 'https' };
|
||||
}
|
||||
|
||||
// Use a custom cert
|
||||
return {
|
||||
type: 'https',
|
||||
options: {
|
||||
key: fs.readFileSync(process.env.SSL_KEY_FILE),
|
||||
cert: fs.readFileSync(process.env.SSL_CRT_FILE),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Webpack configuration in dev
|
||||
const devConfig: Configuration = {
|
||||
mode: 'development',
|
||||
devtool: 'cheap-module-source-map',
|
||||
|
||||
output: {
|
||||
pathinfo: true,
|
||||
},
|
||||
|
||||
watchOptions: {
|
||||
aggregateTimeout: 300,
|
||||
},
|
||||
|
||||
devServer: {
|
||||
port: parseInt(process.env.PORT ?? '3000'),
|
||||
open: true,
|
||||
server: getServerConfig(),
|
||||
historyApiFallback: true,
|
||||
allowedHosts: 'all',
|
||||
proxy: {
|
||||
'/api': 'http://localhost:8080',
|
||||
},
|
||||
},
|
||||
cache: true,
|
||||
};
|
||||
|
||||
const merged = merge(commonConfig, devConfig);
|
||||
export default merged;
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2023 The Perses Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Configuration } from 'webpack';
|
||||
import { merge } from 'webpack-merge';
|
||||
import { ESBuildMinifyPlugin } from 'esbuild-loader';
|
||||
import { commonConfig } from './webpack.common';
|
||||
|
||||
const prodConfig: Configuration = {
|
||||
mode: 'production',
|
||||
bail: true,
|
||||
devtool: 'source-map',
|
||||
optimization: {
|
||||
// TODO: Could this also be replaced with swc minifier?
|
||||
minimizer: [new ESBuildMinifyPlugin({ target: 'es2018' })],
|
||||
},
|
||||
};
|
||||
|
||||
const merged = merge(commonConfig, prodConfig);
|
||||
export default merged;
|
Loading…
Reference in New Issue