Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Frontend of the mugen dms #26

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
9c26211
init frontend with trunk and leptos
koopa1338 Oct 28, 2023
82ca6f1
add serve release task
koopa1338 Oct 28, 2023
3f62818
formatting with leptosfmt and rustfmt
koopa1338 Oct 28, 2023
aef737c
add format task to `Makefile.toml`
koopa1338 Oct 28, 2023
2ef5583
sidebar components
koopa1338 Oct 31, 2023
59a3bd0
remove dropdown menu because auf transition impl issues
koopa1338 Oct 31, 2023
2afa5f8
workaround for dropdowns
koopa1338 Nov 1, 2023
f55b787
bad styles and sidebar
koopa1338 Nov 1, 2023
ab136aa
better styles
koopa1338 Nov 1, 2023
70caa6b
refactor: module structure and fetch api function
koopa1338 Nov 1, 2023
c7ccce9
add routes for collections
koopa1338 Nov 1, 2023
0ad00b0
add logo and allow assets folder in gitignore
koopa1338 Nov 2, 2023
2be41f9
update look and feel
koopa1338 Nov 2, 2023
727464b
refactor api call to be more generic
koopa1338 Nov 2, 2023
c42737a
fmt
koopa1338 Nov 2, 2023
75239e1
remove unused import `Deserialize`
koopa1338 Nov 3, 2023
913c19f
add comment to trait bounds
koopa1338 Nov 3, 2023
8890fe9
toggle signal as trait
koopa1338 Nov 3, 2023
1241804
removed typescript binding generation because of faulty macro
koopa1338 Nov 3, 2023
1698c9e
error handling and rendering document table
koopa1338 Nov 5, 2023
341a652
about page and tailwind class fix
koopa1338 Nov 5, 2023
e122c7a
fix documents table field for filetype
koopa1338 Nov 5, 2023
8dffe46
fixup! error handling and rendering document table
koopa1338 Nov 6, 2023
4e4f04e
add trait for formatting datetimes for rendering in frontend
koopa1338 Nov 6, 2023
abf206b
fmt
koopa1338 Nov 6, 2023
9df6ece
update makefile.toml
koopa1338 Nov 6, 2023
4f42107
add upload component with drag and drop
koopa1338 Nov 6, 2023
a3ad49e
use qualified function call to prevent std library issues in the future
koopa1338 Nov 6, 2023
e4ed3a8
refactored upload component
koopa1338 Nov 7, 2023
cca68d9
simplified css classes, we only have a darkmode for now.
koopa1338 Nov 7, 2023
87fa6a9
add pagination support for querying documents
koopa1338 Nov 9, 2023
690bd28
wip: infinite scroll for document table
koopa1338 Nov 9, 2023
bff2a7e
use yarn instead of npm
koopa1338 Nov 9, 2023
2850fee
add tailwind-scrollbar plugin
koopa1338 Nov 9, 2023
0fdc097
infinite scroll for document list
koopa1338 Nov 9, 2023
0be1eaa
fmt
koopa1338 Nov 9, 2023
621fcb2
add fixme for non reactive context in infinite scoll
koopa1338 Nov 10, 2023
d71c8c0
clippy pedantic lints
koopa1338 Nov 10, 2023
c578fdb
wip infinite scroll
koopa1338 Nov 13, 2023
eab12ba
failsafe infinte scroll for documents table
koopa1338 Nov 15, 2023
2914a92
fixup! simplified css classes, we only have a darkmode for now.
koopa1338 Nov 15, 2023
508e132
add lib for charts and diagrams for dashboard
koopa1338 Nov 15, 2023
4bf0f5b
refactore modules, grid and add wip chart component
koopa1338 Nov 17, 2023
f4c7721
make upload component callback async to use file apis
koopa1338 Nov 18, 2023
15ab35b
fix clippy lint for return values
koopa1338 Nov 19, 2023
e1eaf04
fix upload component design
koopa1338 Nov 19, 2023
4bfca7e
fmt
koopa1338 Nov 19, 2023
2816830
add filetype validation to drop handler
koopa1338 Nov 19, 2023
6b88577
fix css conflict
koopa1338 Nov 19, 2023
98386d1
generic signal toggle trait
koopa1338 Nov 30, 2023
8c89a4f
removed charming charts
koopa1338 Jan 27, 2024
094436a
update deps
koopa1338 Jan 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
[workspace]
resolver = "2"
members = [
"backend",
"common",
]
members = ["backend", "common", "frontend"]

[workspace.package]
authors = ["koopa1338 <[email protected]>"]
Expand Down
21 changes: 18 additions & 3 deletions backend/src/handler/docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use crate::error::ApiResult as Result;

use common::models::document::Doc;

use super::QueryPagination;

/// Returns a router for the document resource.
pub fn router() -> Router<AppState> {
Router::new().nest(
Expand Down Expand Up @@ -43,12 +45,25 @@ pub struct QueryCategory {
pub async fn doc_list(
State(ref conn): State<DatabaseConnection>,
Query(category): Query<QueryCategory>,
Query(QueryPagination { page, page_size }): Query<QueryPagination>,
) -> Result<impl IntoResponse> {
let docs = if let Some(category_id) = category.category_id {
services::docs::get_docs_by_category(category_id, conn).await
let docs = if let Some(page) = page {
let page_size = page_size.unwrap_or(50);
if let Some(category_id) = category.category_id {
services::docs::get_docs_by_category_paginated(category_id, page, page_size, conn).await
} else {
services::docs::get_docs_paginated(page, page_size, conn).await
}

} else {
services::docs::get_docs(conn).await
if let Some(category_id) = category.category_id {
services::docs::get_docs_by_category(category_id, conn).await
} else {
services::docs::get_docs(conn).await
}

};

match docs {
Ok(documents) => {
debug!("Retrieved {} documents", documents.len());
Expand Down
8 changes: 8 additions & 0 deletions backend/src/handler/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
use serde::Deserialize;

pub mod categories;
pub mod docs;

#[derive(Debug, Deserialize)]
pub struct QueryPagination {
page: Option<u64>,
page_size: Option<u64>,
}
36 changes: 36 additions & 0 deletions backend/src/services/docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ pub async fn get_docs(conn: &DatabaseConnection) -> Result<Vec<Doc>, DbErr> {
Doc::get_entities(conn).await
}

#[instrument(skip(conn))]
pub async fn get_docs_paginated(
page: u64,
page_size: u64,
conn: &DatabaseConnection,
) -> Result<Vec<Doc>, DbErr> {
tracing::debug!("Requested documents paginated with page: {page} and page_size: {page_size}.");
let docs = DocumentEntity::find().paginate(conn, page_size);
let max_page = docs.num_pages().await?;
if page > max_page {
return Ok(Vec::new());
}

Ok(docs.fetch_page(page).await?.into_iter().collect::<Vec<_>>())
}

/// Returns a [Doc] entity with the specified ID from the database.
///
/// ## Arguments
Expand Down Expand Up @@ -176,3 +192,23 @@ pub async fn get_docs_by_category(id: i32, conn: &DatabaseConnection) -> Result<
.into_iter()
.collect::<Vec<_>>())
}

#[instrument(skip(conn))]
pub async fn get_docs_by_category_paginated(
id: i32,
page: u64,
page_size: u64,
conn: &DatabaseConnection,
) -> Result<Vec<Doc>, DbErr> {
tracing::debug!("Fetch Documents with linked Category id {id} and paginated with page: {page} and page_size: {page_size}.");

let docs = DocumentEntity::find()
.filter(document::Column::CategoryId.eq(id))
.paginate(conn, page_size);
let max_page = docs.num_pages().await?;
if page > max_page {
return Ok(Vec::new());
}

Ok(docs.fetch_page(page).await?.into_iter().collect::<Vec<_>>())
}
6 changes: 3 additions & 3 deletions common/src/models/category.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use serde::{Deserialize, Serialize};
use ts_rs::TS;
// use ts_rs::TS;

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TS)]
#[ts(export)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize/* , TS */)]
// #[ts(export)]
pub struct Category {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<i32>,
Expand Down
6 changes: 3 additions & 3 deletions common/src/models/document.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use ts_rs::TS;
// use ts_rs::TS;

use crate::DateTimeWithTimeZone;

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, TS)]
#[ts(export)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize/* , TS */)]
// #[ts(export)]
pub struct Doc {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<i64>,
Expand Down
18 changes: 18 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Cargo
# will have compiled files and executables
/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# Support playwright testing
node_modules/
test-results/
end2end/playwright-report/
playwright/.cache/
pnpm-lock.yaml
!assets/
29 changes: 29 additions & 0 deletions frontend/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "mugen-frontend"
version = "0.1.0"
edition = "2021"

[dependencies]
console_error_panic_hook = { version = "0.1" }
console_log = { version = "1" }
gloo-net = { version = "0.5", features = ["http"] }
gloo-utils = "0.2"
gloo-file = { version = "0.3", features = ["futures"] }
leptos = { version = "0.6", features = ["csr", "nightly"] }
leptos_meta = { version = "0.6", features = ["csr", "nightly"] }
leptos_router = { version = "0.6", features = ["csr", "nightly"] }
log = "0.4"
serde = { version = "1", features = ["derive"] }
thiserror = "1"
wasm-bindgen = { version = "0.2" }
wasm-bindgen-futures = "0.4"
web-sys = { version = "0.3", features = [
"AbortController",
"AbortSignal",
"File",
"FileList",
"DataTransfer",
] }

common = { path = "../common" }
leptos-use = "0.9"
23 changes: 23 additions & 0 deletions frontend/Makefile.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[env]
CLIENT_PROCESS_NAME = "trunk"
RUSTFLAGS = "--cfg=web_sys_unstable_apis"

[tasks.build]
command = "trunk"
args = ["build"]

[tasks.fmt]
command = "leptosfmt"
args = ["."]

[tasks.pkg]
command = "trunk"
args = ["build", "--release"]

[tasks.serve]
command = "trunk"
args = ["serve", "${@}"]

[tasks.serve-release]
command = "trunk"
args = ["serve", "${@}", "--release"]
9 changes: 9 additions & 0 deletions frontend/Trunk.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[build]
target = "index.html"
dist = "dist"

[serve]
# The address to serve on.
address = "127.0.0.1"
# The port to serve on.
port = 3030
Binary file added frontend/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en" class="h-full scrollbar-thumb-amber-600 scrollbar-track-gray-950">

<head>
<meta charset="utf-8" />
<link data-trunk rel="rust" data-wasm-opt="z" />
<!--<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico" /> -->
<link data-trunk rel="copy-dir" href="assets"/>
<link data-trunk rel="tailwind-css" href="tailwind.css"/>

<title>Mugen DMS</title>
</head>

<body class="bg-gray-950 antialiased !p-0"></body>

</html>
6 changes: 6 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"devDependencies": {
"tailwind-scrollbar": "^3.0.5",
"tailwindcss": "^3.3.5"
}
}
2 changes: 2 additions & 0 deletions frontend/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"
71 changes: 71 additions & 0 deletions frontend/src/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use gloo_net::http::{Method, RequestBuilder};
use gloo_utils::errors::JsError;
use leptos::Serializable;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use web_sys::AbortController;

pub async fn api_call<T, P>(
path: &str,
method: Method,
payload: Option<P>,
query_params: Option<Vec<(&str, &str)>>,
) -> Result<T, FetchError>
where
T: Serializable, // this means both serializable and deserializable
P: Serialize,
{
let abort_controller = web_sys::AbortController::new().ok();
let abort_signal = abort_controller.as_ref().map(AbortController::signal);

// abort in-flight requests if, e.g., we've navigated away from this page
leptos::on_cleanup(move || {
if let Some(abort_controller) = abort_controller {
abort_controller.abort();
}
});

let mut builder = RequestBuilder::new(&format!("http://localhost:4000/{path}"))
.method(method)
.abort_signal(abort_signal.as_ref());
if let Some(params) = query_params {
builder = builder.query(params);
}

let req = if let Some(payload) = payload {
builder
.json(&payload)
.map_err(|e| FetchError::PayloadError(e.to_string()))?
} else {
builder
.build()
.map_err(|e| FetchError::ClientError(e.to_string()))?
};

let json = req
.send()
.await
.map_err(|e| {
let error_message = match e {
gloo_net::Error::JsError(JsError { message, .. }) => message,
gloo_net::Error::SerdeError(e) => e.to_string(),
gloo_net::Error::GlooError(msg) => msg,
};
FetchError::GenericError(error_message)
})?
.text()
.await
.map_err(|e| FetchError::GenericError(e.to_string()))?;

T::de(&json).map_err(|e| FetchError::GenericError(e.to_string()))
}

#[derive(Error, Clone, Debug, Deserialize, Serialize)]
pub enum FetchError {
#[error("Generic Error: {0}")]
GenericError(String),
#[error("Error initializing request client: {0}")]
ClientError(String),
#[error("Error setting payload: {0}")]
PayloadError(String),
}
30 changes: 30 additions & 0 deletions frontend/src/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use leptos::*;
use leptos_meta::*;
use leptos_router::*;

use crate::components::sidebar::Sidebar;
use crate::routes::{about::About, dashboard::Dashboard, document::Documents};

#[component]
pub fn App() -> impl IntoView {
provide_meta_context();

view! {
<Router>
<Sidebar/>
<main class="bg-gray-950 p-3 sm:ml-60 h-screen">
<Routes>
<Route path="/" view=Dashboard/>
<Route path="/documents" view=Documents/>
<Route path="/documents/:id" view=Dashboard/>
<Route path="/categories/:id" view=Dashboard/>
<Route path="/categories" view=Dashboard/>
<Route path="/collections/:id" view=Dashboard/>
<Route path="/collections" view=Dashboard/>
<Route path="/settings" view=Dashboard/>
<Route path="/about" view=About/>
</Routes>
</main>
</Router>
}
}
8 changes: 8 additions & 0 deletions frontend/src/components/grid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use leptos::*;

#[component]
pub fn Grid(#[prop(optional)] classes: Option<&'static str>, children: Children) -> impl IntoView {
let classes = classes.unwrap_or("grid-cols-1");

view! { <div class=format!("grid gap-4 {classes}")>{children()}</div> }
}
3 changes: 3 additions & 0 deletions frontend/src/components/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod grid;
pub mod sidebar;
pub mod upload;
Loading