Skip to content

Commit

Permalink
frontend rework (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
archeoss committed Dec 2, 2023
1 parent fee8e01 commit d8bddc1
Show file tree
Hide file tree
Showing 18 changed files with 1,049 additions and 848 deletions.
15 changes: 6 additions & 9 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(clippy::multiple_crate_versions)]

use bob_management::main::prelude::*;
use cli::Config;

const FRONTEND_FOLDER: &str = "frontend";

Expand All @@ -16,17 +17,12 @@ async fn main() -> Result<(), AppError> {
init_tracer(&logger.log_file, logger.trace_level);
tracing::info!("Logger: {logger:?}");

let cors: CorsLayer = config.get_cors_configuration();
tracing::info!("CORS: {cors:?}");

let addr = config.address;
tracing::info!("Listening on {addr}");

let app = router(cors);
let app = router(&config);
#[cfg(all(feature = "swagger", debug_assertions))]
let app = app
.merge(bob_management::openapi_doc())
.layer(Extension(RequestTimeout::from(config.request_timeout)));
let app = app.merge(bob_management::openapi_doc());

axum::Server::bind(&addr)
.serve(app.into_make_service())
Expand All @@ -43,7 +39,7 @@ fn init_tracer(_log_file: &Option<PathBuf>, trace_level: Level) {
}

#[allow(clippy::unwrap_used, clippy::expect_used)]
fn router(cors: CorsLayer) -> Router {
fn router(config: &Config) -> Router {
let session_store = MemoryStore::default();
let session_service = ServiceBuilder::new()
.layer(HandleErrorLayer::new(|_: BoxError| async {
Expand All @@ -70,7 +66,8 @@ fn router(cors: CorsLayer) -> Router {
ApiV1::to_path(),
api_router_v1(auth_state.clone())
.expect("couldn't get API routes")
.layer(ServiceBuilder::new().layer(cors)),
.layer(ServiceBuilder::new().layer(config.get_cors_configuration()))
.layer(Extension(RequestTimeout::from(config.request_timeout))),
)
.layer(session_service)
.with_state(auth_state)
Expand Down
1 change: 1 addition & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
address: 0.0.0.0:9000
request-timeout: 1s
logger:
trace-level: INFO
129 changes: 107 additions & 22 deletions frontend/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
parserOptions: {
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
sourceType: 'module', // Allows for the use of imports
extraFileExtensions: ['.astro'],
ecmaFeatures: {
jsx: true, // Allows for the parsing of JSX
},
Expand All @@ -16,34 +17,118 @@ module.exports = {
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended', // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
'plugin:astro/recommended', //
'plugin:import/recommended',
'plugin:prettier/recommended',
'plugin:astro/recommended',
],
plugins: ['react-refresh'],
ignorePatterns: ['dist', '.eslintrc.cjs'],
rules: {
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
// overrides: [
// {
// // Define the configuration for `.astro` file.
// files: ['*.astro'],
// // Allows Astro components to be parsed.
// parser: 'astro-eslint-parser',
// // Parse the script in `.astro` as TypeScript by adding the following configuration.
// // It's the setting you need when using TypeScript.
// parserOptions: {
// parser: '@typescript-eslint/parser',
// extraFileExtensions: ['.astro'],
// },
// rules: {
// // override/add rules settings here, such as:
// // "astro/no-set-html-directive": "error"
// },
// },
// // ...
// ],
overrides: [
// Configuration for mjs,cjs files
{
files: ['*.mjs', '*.cjs'],
extends: ['plugin:prettier/recommended'],
rules: {
'import/no-extraneous-dependencies': 'off', // mjs is only used by Astro for configuration, false positive
'import/no-unresolved': 'off', // Also false positive with mjs file
},
},
// Configuration for TypeScript files
{
parser: '@typescript-eslint/parser',
files: ['*.ts', '*.tsx'],

plugins: ['@typescript-eslint', 'react', 'unused-imports', 'tailwindcss', 'simple-import-sort'],
extends: ['plugin:tailwindcss/recommended', 'airbnb-typescript/base', 'plugin:prettier/recommended'],
parserOptions: {
project: './tsconfig.json',
},
rules: {
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
'': 'never',
},
], // Avoid missing file extension errors when using '@/' alias
'react/destructuring-assignment': 'off', // Vscode doesn't support automatically destructuring, it's a pain to add a new variable
'react/require-default-props': 'off', // Allow non-defined react props as undefined
'react/jsx-props-no-spreading': 'off', // _app.tsx uses spread operator and also, react-hook-form
'@typescript-eslint/comma-dangle': 'off', // Avoid conflict rule between Eslint and Prettier
'@typescript-eslint/consistent-type-imports': 'error', // Ensure `import type` is used when it's necessary
'import/prefer-default-export': 'off', // Named export is easier to refactor automatically
'tailwindcss/classnames-order': [
'warn',
{
officialSorting: true,
},
], // Follow the same ordering as the official plugin `prettier-plugin-tailwindcss`
'simple-import-sort/imports': 'error', // Import configuration for `eslint-plugin-simple-import-sort`
'simple-import-sort/exports': 'error', // Export configuration for `eslint-plugin-simple-import-sort`
'@typescript-eslint/no-unused-vars': 'off',
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
},
// Configuration for Astro
{
files: ['*.astro'],
plugins: ['@typescript-eslint', 'react', 'unused-imports', 'tailwindcss', 'simple-import-sort'],
extends: ['plugin:tailwindcss/recommended', 'airbnb-typescript/base', 'plugin:prettier/recommended'],
parser: 'astro-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
},
rules: {
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
'': 'never',
},
], // Avoid missing file extension errors in .astro files
'import/no-unresolved': [
'error',
{
ignore: ['@/*'],
},
], // Disable no-unresolved rule for .astro files
'react/jsx-filename-extension': [1, { extensions: ['.astro'] }], // Accept jsx in astro files
'react/destructuring-assignment': 'off', // Vscode doesn't support automatically destructuring, it's a pain to add a new variable
'react/require-default-props': 'off', // Allow non-defined react props as undefined
'react/jsx-props-no-spreading': 'off', // _app.tsx uses spread operator and also, react-hook-form
'@typescript-eslint/comma-dangle': 'off', // Avoid conflict rule between Eslint and Prettier
'@typescript-eslint/consistent-type-imports': 'error', // Ensure `import type` is used when it's necessary
'import/prefer-default-export': 'off', // Named export is easier to refactor automatically
'tailwindcss/classnames-order': [
'warn',
{
officialSorting: true,
},
], // Follow the same ordering as the official plugin `prettier-plugin-tailwindcss`
'simple-import-sort/imports': 'error', // Import configuration for `eslint-plugin-simple-import-sort`
'simple-import-sort/exports': 'error', // Export configuration for `eslint-plugin-simple-import-sort`
'@typescript-eslint/no-unused-vars': 'off',
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
globals: {
Astro: 'readonly',
},
},
],
};
24 changes: 18 additions & 6 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "bob-management-frontend",
"type": "module",
"version": "0.0.1",
"license": "MIT",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
Expand All @@ -17,33 +18,44 @@
"@astrojs/ts-plugin": "^1.2.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.0",
"@mui/material": "^5.14.0",
"@mui/icons-material": "^5.14.19",
"@mui/material": "^5.14.19",
"@mui/styled-engine-sc": "^6.0.0-alpha.7",
"@mui/system": "^5.14.19",
"@mui/x-data-grid": "^6.16.2",
"@playwright/test": "^1.40.0",
"@types/material-ui": "^0.21.12",
"@types/mui-image": "^1.0.2",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"astro": "^3.0.2",
"mui-image": "^1.0.7",
"prop-types": "^15.8.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"styled-components": "^6.1.1",
"tailwindcss": "^3.0.24",
"typescript": "^5.2.2",
"vite": "^4.4.9"
},
"devDependencies": {
"@playwright/test": "^1.40.0",
"@types/node": "^20.10.2",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"eslint": "^8.51.0",
"eslint": "^8.55.0",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-astro": "^0.29.1",
"eslint-plugin-astro": "^0.30.0",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"prettier": "^3.0.2"
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-tailwindcss": "^3.13.0",
"eslint-plugin-unused-imports": "^3.0.0",
"prettier": "^3.0.2",
"prettier-plugin-astro": "^0.12.2"
}
}
9 changes: 5 additions & 4 deletions frontend/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ export default defineConfig({
use: { ...devices['Desktop Firefox'] },
},

{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
/* Mac'oids must suffer */
// {
// name: 'webkit',
// use: { ...devices['Desktop Safari'] },
// },

/* Test against mobile viewports. */
// {
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/components/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
type Valuable<T> = { [K in keyof T as T[K] extends null | undefined ? never : K]: T[K] };

export function removeEmpty<
// eslint-disable-next-line @typescript-eslint/ban-types
T extends {},
V = Valuable<T>,
>(obj: T): V {
return Object.fromEntries(
Object.entries(obj).filter(
([, v]) => !((typeof v === 'string' && !v.length) || v === null || typeof v === 'undefined'),
),
) as V;
}
53 changes: 13 additions & 40 deletions frontend/src/components/login/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Alert, Box, Button, Snackbar, Grid, TextField } from '@mui/material';
import React, { useState, type FormEvent } from 'react';
import { removeEmpty } from '@components/common.ts';
import { Alert, Box, Button, Grid, Snackbar, TextField } from '@mui/material';
import React, { type FormEvent, useState } from 'react';

import BobLogo from '../../../public/logo.svg';
import style from './login.module.css';

Expand All @@ -20,20 +22,6 @@ const LoginPage = ({ redirectTo }: { redirectTo: string }) => {
);
}

// FIXME
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function removeEmpty(obj: any) {
for (const key of Object.keys(obj)) {
if (obj[key] === '') {
delete obj[key];
} else if (typeof obj[key] === 'object') {
obj[key] = removeEmpty(obj[key]);
if (Object.keys(obj[key]).length === 0) delete obj[key];
}
}
return Array.isArray(obj) ? obj.filter((val) => val) : obj;
}

const snackbarStyle = {
top: '20%',
left: '50%',
Expand All @@ -42,19 +30,7 @@ const LoginPage = ({ redirectTo }: { redirectTo: string }) => {

async function handleSubmit(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
// const formData = new FormData(e.target as HTMLFormElement);
console.log(
address,
port,
removeEmpty({
hostname: address + ':' + port,
credentials: {
login: username,
password: password,
},
}),
);
const response = await fetch('/api/login', {
const response = await fetch('/api/v1/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8',
Expand All @@ -69,17 +45,13 @@ const LoginPage = ({ redirectTo }: { redirectTo: string }) => {
}),
),
});
await response
.json()
.then((res) => {
console.log(res);
setRedirect(true);
})
.catch((err) => {
setSnackbarMessage('Wrong data');
setOpenSnackbar(true);
console.log(err.message);
});
if (response.ok) {
setRedirect(true);
} else {
setSnackbarMessage('Wrong data');
setOpenSnackbar(true);
console.log(response.json());
}
}

return (
Expand Down Expand Up @@ -163,3 +135,4 @@ const LoginPage = ({ redirectTo }: { redirectTo: string }) => {
};

export default LoginPage;

Check failure on line 138 in frontend/src/components/login/Login.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Delete `⏎`

Check failure on line 138 in frontend/src/components/login/Login.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Delete `⏎`
Loading

0 comments on commit d8bddc1

Please sign in to comment.