Owows so many new files

This commit is contained in:
2026-09-09 22:20:29 +03:00
parent 3fcee5ea9a
commit 6441cc6709
21 changed files with 3249 additions and 58 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/target
/config.toml
/node_modules

1833
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -17,12 +17,14 @@ chrono = { version = "0.4.45", features = ["serde"] }
console_error_panic_hook = "0.1.7"
diesel = { version = "2.3.13", features = ["postgres", "uuid", "chrono", "r2d2"] }
diesel_migrations = "2.3.2"
leptos = "0.8.20"
leptos_axum = "0.8.10"
leptos = { version = "0.8.20", features = ["hydration"] }
leptos_axum = { version = "0.8.10", features = ["tracing", "wasm"]}
leptos_meta = "0.8.6"
leptos_router = { version = "0.8.15", features = ["tracing"] }
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
thiserror = "2.0.20"
tokio = { version = "1.53.1", features = ["full"] }
tokio = { version = "1.53.1", features = ["rt-multi-thread","macros"] }
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
uuid = { version = "1.26.0", features = ["v4", "serde"] }
@@ -31,4 +33,70 @@ clap = { version = "4.6.6", features = ["derive"] }
toml = "1.1.5"
camino = { version = "1.2.5", features = ["serde1"]}
humantime = "2.4.0"
humantime-serde = "1.1.1"
humantime-serde = "1.1.1"
any_spawner = { version = "0.3", features = ["tokio"] }
[profile.wasm-release]
inherits = "release"
opt-level = 'z'
lto = true
codegen-units = 1
panic = "abort"
[[workspace.metadata.leptos]]
name="erplt"
bin-package="erplt"
lib-package="erplt"
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
output-name = "erplt"
# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup.
site-root = "target/site"
# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
# Defaults to pkg
site-pkg-dir = "pkg"
# The tailwind input file.
#
# Optional, Activates the tailwind build
tailwind-input-file = "crates/erplt-api/style/tailwind.css"
# [Optional] Files in the asset-dir will be copied to the site-root directory
assets-dir = "public"
# The port to use for automatic reload monitoring
site-addr = "0.0.0.0:8080"
reload-port = 8081
# [Optional] Command to use when running end2end tests. It will run in the end2end dir.
# [Windows] for non-WSL use "npx.cmd playwright test"
# This binary name can be checked in Powershell with Get-Command npx
end2end-cmd = "npx playwright test"
end2end-dir = "end2end"
# The browserlist query used for optimizing the CSS.
browserquery = "defaults"
# Set by cargo-leptos watch when building with that tool. Controls whether autoreload JS will be included in the head
watch = false
# The environment Leptos will run in, usually either "DEV" or "PROD"
env = "DEV"
# The features to use when compiling the bin target
#
# Optional. Can be over-ridden with the command line parameter --bin-features
bin-features = ["ssr"]
# If the --no-default-features flag should be used when compiling the bin target
#
# Optional. Defaults to false.
bin-default-features = false
# The features to use when compiling the lib target
#
# Optional. Can be over-ridden with the command line parameter --lib-features
lib-features = ["hydrate"]
# If the --no-default-features flag should be used when compiling the lib target
#
# Optional. Defaults to false.
lib-default-features = false

View File

@@ -3,10 +3,40 @@ name = "erplt-api"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
hydrate=["leptos/hydrate"]
ssr=[
"dep:erplt-db",
"dep:erplt-config",
"dep:leptos_axum",
"dep:tokio",
"dep:anyhow",
"dep:any_spawner",
"dep:tracing",
"dep:axum",
]
[dependencies]
erplt-db.path="../erplt-db"
erplt-config.path = "../erplt-config"
anyhow.workspace = true
axum.workspace = true
tokio.workspace = true
tracing.workspace = true
leptos.workspace = true
leptos_meta.workspace = true
leptos_router.workspace = true
console_error_panic_hook.workspace = true
wasm-bindgen.workspace = true
axum = { workspace = true, optional = true }
erplt-db = { path = "../erplt-db", optional = true }
erplt-config = { path = "../erplt-config", optional = true }
leptos_axum = { workspace = true, optional = true }
tokio = { workspace = true, optional = true }
anyhow = { workspace = true, optional = true }
any_spawner = { workspace = true, optional = true }
tracing = { workspace = true, optional = true }
[package.metadata.cargo-all-features]
denylist = ["axum", "tokio", "tower", "tower-http", "leptos_axum"]
skip_feature_sets = [["ssr", "hydrate"], []]

View File

@@ -1,5 +1,21 @@
mod routes;
#[cfg(feature="ssr")]
mod state;
#[cfg(feature="ssr")]
mod server;
#[cfg(feature="ssr")]
pub use server::start;
pub use server::start;
#[cfg(feature="ssr")]
use leptos::config::LeptosOptions;
#[cfg(feature="ssr")]
type Router = axum::Router<LeptosOptions>;
#[cfg(feature = "hydrate")]
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
use routes::pages::App;
console_error_panic_hook::set_once();
leptos::mount::hydrate_body(App);
}

View File

@@ -0,0 +1,8 @@
mod v1;
pub fn router() -> crate::Router {
crate::Router::new()
.merge(v1::router())
.nest("/v1", v1::router())
}

View File

@@ -0,0 +1,9 @@
use axum::routing::get;
mod health;
pub fn router() -> crate::Router {
crate::Router::new()
.route("/health", get(health::get))
}

View File

@@ -1,8 +1,10 @@
use axum::{routing::get, Router};
pub mod pages;
mod health;
#[cfg(feature="ssr")]
mod api;
pub fn router() -> Router {
Router::new()
.route("/health", get(health::get))
#[cfg(feature="ssr")]
pub fn router() -> crate::Router {
crate::Router::new()
.nest("/api", api::router())
}

View File

@@ -0,0 +1,11 @@
use leptos::prelude::*;
#[component]
pub fn HomePage() -> impl IntoView {
view! {
<main>
<h1>"ERPLT"</h1>
<p>"Welcome to ERPLT."</p>
</main>
}
}

View File

@@ -0,0 +1,32 @@
use leptos::prelude::*;
#[component]
pub fn Layout(children: Children) -> impl IntoView {
view! {
<div class="flex min-h-screen">
<aside class="w-64 border-r p-4">
<h1 class="mb-6 text-xl font-bold">
"ERPLT"
</h1>
<nav class="space-y-2">
<a href="/">"Dashboard"</a>
<a href="/sales">"Sales"</a>
<a href="/purchases">"Purchases"</a>
<a href="/inventory">"Inventory"</a>
<a href="/accounting">"Accounting"</a>
</nav>
</aside>
<div class="flex flex-1 flex-col">
<header class="border-b p-4">
"ERPLT"
</header>
<main class="flex-1 p-6">
{children()}
</main>
</div>
</div>
}
}

View File

@@ -0,0 +1,50 @@
use leptos::prelude::*;
use leptos_meta::*;
use leptos_router::{
SsrMode, StaticSegment, components::{FlatRoutes, Route, Router},
};
mod home;
mod layout;
#[cfg(feature="ssr")]
pub fn shell(options: LeptosOptions) -> impl IntoView {
view! {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<AutoReload options=options.clone() />
<HydrationScripts options/>
<link rel="stylesheet" id="leptos" href="/pkg/erplt.css"/>
<link rel="shortcut icon" type="image/ico" href="/favicon.ico"/>
<MetaTags/>
</head>
<body>
<App/>
</body>
</html>
}
}
#[component]
pub fn App() -> impl IntoView {
provide_meta_context();
view! {
<Router>
<FlatRoutes fallback=|| "Page not found.">
<Route
path=StaticSegment("")
view=|| view! {
<layout::Layout>
<home::HomePage/>
</layout::Layout>
}
ssr=SsrMode::Async
/>
</FlatRoutes>
</Router>
}
}

View File

@@ -1,20 +1,41 @@
use std::{net::{Ipv4Addr, SocketAddr, SocketAddrV4}, str::FromStr};
use anyhow::Context;
use axum::http::StatusCode;
use leptos::prelude::*;
use leptos_axum::{LeptosRoutes, generate_route_list};
use erplt_db::DbPool;
#[axum::debug_handler]
async fn fallback() -> (StatusCode, &'static str) {
(StatusCode::NOT_FOUND, "Not Found")
}
use crate::routes;
pub async fn start(db: DbPool) -> anyhow::Result<()> {
let config = erplt_config::get();
// Need this because tokio has threading panics otherwise
any_spawner::Executor::init_tokio().unwrap();
let leptos_options = LeptosOptions::builder()
.output_name("erplt")
.site_root("target/site")
.site_pkg_dir("pkg")
.reload_external_port(Some((config.web.port+1) as u32))
.site_addr(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_str(&config.web.host)?, config.web.port)))
.build();
let routes = generate_route_list(routes::pages::App);
let app = axum::Router::new()
.merge(crate::routes::router())
.fallback(fallback);
//.merge(crate::routes::router())
.merge(routes::router())
.leptos_routes(&leptos_options, routes, {
let leptos_options = leptos_options.clone();
move || routes::pages::shell(leptos_options.clone())
})
.fallback(leptos_axum::file_and_error_handler(routes::pages::shell))
.with_state(leptos_options)
.with_state(db);
@@ -25,7 +46,7 @@ pub async fn start(db: DbPool) -> anyhow::Result<()> {
tracing::info!("Web server listening on http://{}", listener.local_addr()?);
axum::serve(listener, app)
axum::serve(listener, app.into_make_service())
.await
.context("Web server stopped unexpectedly")?;

View File

@@ -0,0 +1 @@
@import "tailwindcss";

View File

@@ -2,7 +2,6 @@ use std::time::Duration;
use anyhow::Context;
use camino::Utf8PathBuf;
use serde::de;
pub mod cli;

View File

@@ -1,6 +1,7 @@
use anyhow::Context;
use diesel::r2d2::ConnectionManager;
#[allow(dead_code)]
pub type DbBackend = diesel::pg::Pg;
pub type DbConnection = diesel::PgConnection;
pub type DbPool = diesel::r2d2::Pool<
@@ -25,6 +26,8 @@ pub fn connect(url: &str) -> anyhow::Result<DbPool> {
pool.get()
.context("Failed to connect to PostgreSQL")?;
tracing::info!("Connected to database");
// crate::migrations::run_migrations(&pool)?;
Ok(pool)
}

View File

@@ -1,19 +1,41 @@
[package]
name = "erplt"
version = "0.1.0"
edition = "2024"
[package]
name = "erplt"
version = "0.1.0"
edition = "2024"
[dependencies]
erplt-db.path="../erplt-db"
erplt-api.path="../erplt-api"
erplt-config.path="../erplt-config"
camino.workspace = true
clap.workspace = true
serde.workspace = true
toml.workspace = true
anyhow.workspace = true
tracing-subscriber.workspace = true
tracing.workspace = true
humantime.workspace = true
humantime-serde.workspace = true
tokio.workspace = true
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["ssr", "erplt-api/ssr"]
hydrate=["erplt-api/hydrate"]
ssr=[
"erplt-api/ssr",
"dep:erplt-db",
"dep:erplt-config",
"dep:camino",
"dep:clap",
"dep:serde",
"dep:toml",
"dep:anyhow",
"dep:tracing",
"dep:tracing-subscriber",
"dep:humantime",
"dep:humantime-serde",
"dep:tokio",
]
[dependencies]
erplt-api.path="../erplt-api"
erplt-db = { path="../erplt-db", optional = true }
erplt-config = { path="../erplt-config", optional = true }
camino = { workspace = true, optional = true }
clap = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
toml = { workspace = true, optional = true }
anyhow = { workspace = true, optional = true }
tracing-subscriber = { workspace = true, optional = true }
tracing = { workspace = true, optional = true }
humantime = { workspace = true, optional = true }
humantime-serde = { workspace = true, optional = true }
tokio = { workspace = true, optional = true }

2
crates/erplt/src/lib.rs Normal file
View File

@@ -0,0 +1,2 @@
#[cfg(feature = "hydrate")]
pub use erplt_api::hydrate;

1103
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

6
package.json Normal file
View File

@@ -0,0 +1,6 @@
{
"dependencies": {
"@tailwindcss/cli": "^4.3.3",
"tailwindcss": "^4.3.3"
}
}

2
scripts/cloc.sh Normal file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/bash
cloc . --fullpath --not-match-d="\.hemttout|\.hemtt/presets|target|node_modules" --not-match-f="package-lock.json"