Skip to content

Commit

Permalink
Add Login Page
Browse files Browse the repository at this point in the history
  • Loading branch information
archeoss committed Feb 2, 2024
1 parent 35d21ae commit 80fc86d
Show file tree
Hide file tree
Showing 36 changed files with 2,232 additions and 1,042 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Bob Management GUI changelog
- CI/CD configuration (#11)
- Logger Initialization (#14)
- Login Page, backend (#16)
- Login Page, frontend (#17)
3 changes: 3 additions & 0 deletions backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ utoipa-swagger-ui = { version = "4.0", features = ["axum"], optional = true }
utoipa-redoc = { version = "1.0", features = ["axum"], optional = true }
utoipa-rapidoc = { version = "1.0", features = ["axum"], optional = true }

## Transpiling
tsync = "2.0"

## CLI
cli = { path = "../cli" }

Expand Down
18 changes: 8 additions & 10 deletions backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
)]

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

const FRONTEND_FOLDER: &str = "frontend";

Expand All @@ -19,17 +20,12 @@ async fn main() -> Result<(), AppError> {
let _guard = logger.init_logger().unwrap();
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 @@ -41,7 +37,7 @@ async fn main() -> Result<(), AppError> {
}

#[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(|err: BoxError| async move {
Expand All @@ -50,7 +46,8 @@ fn router(cors: CorsLayer) -> Router {
}))
.layer(
SessionManagerLayer::new(session_store)
.with_expiry(tower_sessions::Expiry::OnSessionEnd),
.with_expiry(tower_sessions::Expiry::OnSessionEnd)
.with_http_only(false),
);

let user_store: InMemorySessionStore<Uuid, BobUser> = InMemorySessionStore::default();
Expand All @@ -69,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 backend/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ pub mod prelude {
pub use crate::prelude::*;
pub use hyper::Uri;
pub use std::{net::SocketAddr, time::Duration};
pub use tsync::tsync;
}
4 changes: 3 additions & 1 deletion backend/src/models/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl TryFrom<Hostname> for SocketAddr {
type Error = std::net::AddrParseError;

fn try_from(value: Hostname) -> Result<Self, Self::Error> {
value.to_string().parse()
value.0.to_string().parse()
}
}

Expand All @@ -71,6 +71,7 @@ impl ToString for Hostname {
)]
#[cfg_attr(all(feature = "swagger", debug_assertions),
schema(example = json!({"hostname": "0.0.0.0:7000", "credentials": {"login": "archeoss", "password": "12345"}})))]
#[tsync]
pub struct BobConnectionData {
/// Address to connect to
pub hostname: Hostname,
Expand All @@ -84,6 +85,7 @@ pub struct BobConnectionData {
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
#[cfg_attr(all(feature = "swagger", debug_assertions), derive(ToSchema))]
#[cfg_attr(all(feature = "swagger", debug_assertions), schema(example = json!({"login": "archeoss", "password": "12345"})))]
#[tsync]
pub struct Credentials {
/// Login used during auth
pub login: String,
Expand Down
1 change: 1 addition & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
address: 0.0.0.0:9000
request-timeout: 1s
logger:
trace-level: INFO
file:
Expand Down
111 changes: 108 additions & 3 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,14 +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:import/recommended',
'plugin:prettier/recommended',
'plugin:astro/recommended',
],
plugins: ['react-refresh'],
ignorePatterns: ['dist', '.eslintrc.cjs'],
ignorePatterns: ['dist', '.eslintrc.cjs', 'rust.d.ts'],
rules: {
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
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',
},
},
],
};
2 changes: 1 addition & 1 deletion frontend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ repository.workspace = true

[lib]
name = "frontend"
path = "frontend.rs"
path = "bindings.rs"
crate-type = ["lib"]

[build-dependencies]
Expand Down
15 changes: 12 additions & 3 deletions frontend/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';

import tailwind from '@astrojs/tailwind';
// import node from '@astrojs/node';

// https://astro.build/config
export default defineConfig({
integrations: [react(), tailwind()],
outDir: './frontend',
// output: 'server',
integrations: [
react({
experimentalReactChildren: true,
}),
tailwind(),
],
// adapter: node({
// mode: 'standalone',
// }),
outDir: './frontend',
});
6 changes: 6 additions & 0 deletions frontend/bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Some structs that must be redefined for transpiling without changing actual types on backend

use tsync::tsync;

#[tsync]
pub type Hostname = String;
9 changes: 9 additions & 0 deletions frontend/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,11 @@ pub fn build_types() {
let mut inputs = vec![PathBuf::from(env!("CARGO_MANIFEST_DIR"))];
let mut output = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
inputs[0].pop();
inputs.push(inputs[0].clone());

inputs[0].push("backend");
inputs[1].push("frontend");
inputs[1].push("frontend.rs");
output.push("src/types/rust.d.ts");

tsync::generate_typescript_defs(inputs, output, false);
Expand All @@ -70,6 +73,10 @@ pub fn build_frontend() {
// #[cfg(not(debug_assertions))]
shell("yarn");

let mut project_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
project_dir.push(FRONTEND_DIR);
std::fs::remove_dir_all(project_dir);

// Only build frontend when building a release
// #[cfg(not(debug_assertions))]
shell("yarn build");
Expand All @@ -82,6 +89,8 @@ pub fn move_frontend() {
target.pop();
target.push(FRONTEND_DIR);

// Note: sometimes, build can fail if the previous build is still present
// What a lovely language....
let mut project_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
project_dir.push(FRONTEND_DIR);

Expand Down
2 changes: 1 addition & 1 deletion frontend/e2e/example.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { test, expect } from '@playwright/test';
import { expect, test } from '@playwright/test';

test('has title', async ({ page }) => {
await page.goto('https://playwright.dev/');
Expand Down
1 change: 0 additions & 1 deletion frontend/frontend.rs

This file was deleted.

Loading

0 comments on commit 80fc86d

Please sign in to comment.