diff --git a/engine/Cargo.lock b/engine/Cargo.lock index c5ef6d9..de8bfc2 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -2625,6 +2625,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3632,6 +3643,7 @@ dependencies = [ "scraper", "serde", "serde_json", + "serde_repr", "serde_with", "sha2", "sqlx", diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 341c8b7..a061c49 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -31,6 +31,7 @@ reqwest = "0.12.5" scraper = "0.21.0" serde = "1.0.204" serde_json = { version = "1.0", features = ["raw_value"] } +serde_repr = "0.1.19" serde_with = { version = "3.9.0", features = ["json", "chrono"] } sha2 = "0.10.8" sqlx = { version = "0.7.4", features = [ diff --git a/engine/migrations/0001_init.up.sql b/engine/migrations/0001_init.up.sql index 3ac22ff..312f935 100644 --- a/engine/migrations/0001_init.up.sql +++ b/engine/migrations/0001_init.up.sql @@ -13,6 +13,9 @@ CREATE TABLE users ( -- Insert a system user INSERT INTO users (user_id, oauth_sub, oauth_data, nickname) VALUES (1, '$$SYSTEM$$', '{}', 'System'); +-- Set the sequence for user_id to start at 2 +SELECT setval(pg_get_serial_sequence('users', 'user_id'), 2, false); + -- Create Sessions table CREATE TABLE sessions ( session_id TEXT PRIMARY KEY, -- Unique session identifier diff --git a/engine/rustfmt.toml b/engine/rustfmt.toml index 4b79dc5..22e5809 100644 --- a/engine/rustfmt.toml +++ b/engine/rustfmt.toml @@ -1,2 +1,5 @@ reorder_imports = true -# group_imports = "StdExternalCrate" +group_imports = "StdExternalCrate" +blank_lines_upper_bound = 2 +edition = "2021" +error_on_unformatted = true diff --git a/engine/src/auth/middleware.rs b/engine/src/auth/middleware.rs index 28ac75e..593838d 100644 --- a/engine/src/auth/middleware.rs +++ b/engine/src/auth/middleware.rs @@ -3,9 +3,8 @@ use std::sync::Arc; use poem::{web::Data, Error, FromRequest, Request, RequestBody, Result}; use reqwest::StatusCode; -use crate::{models::sessions::Session, state::AppState}; - use super::hash::hash_session; +use crate::{models::sessions::Session, state::AppState}; pub struct ActiveUser { pub session: Session, diff --git a/engine/src/models/field/definition.rs b/engine/src/models/field/definition.rs index 1ecf9e2..ba0d300 100644 --- a/engine/src/models/field/definition.rs +++ b/engine/src/models/field/definition.rs @@ -1,16 +1,18 @@ -use crate::database::Database; -use crate::models::field::kind::FieldKind; +use chrono::{DateTime, Utc}; use poem_openapi::Object; use serde::{Deserialize, Serialize}; use sqlx::{query_as, FromRow}; +use crate::database::Database; +use crate::models::field::kind::FieldKind; + #[derive(FromRow, Object, Debug, Clone, Serialize, Deserialize)] pub struct FieldDefinition { pub definition_id: String, pub kind: FieldKind, pub name: String, - pub created_at: Option>, - pub updated_at: Option>, + pub created_at: Option>, + pub updated_at: Option>, } impl FieldDefinition { diff --git a/engine/src/models/item/field.rs b/engine/src/models/item/field.rs index a06f760..646fef9 100644 --- a/engine/src/models/item/field.rs +++ b/engine/src/models/item/field.rs @@ -1,7 +1,8 @@ -use crate::database::Database; use serde::{Deserialize, Serialize}; use sqlx::query_as; +use crate::database::Database; + #[derive(sqlx::FromRow, poem_openapi::Object, Debug, Clone, Serialize, Deserialize)] pub struct ItemField { pub item_id: String, diff --git a/engine/src/models/item/media.rs b/engine/src/models/item/media.rs index 4fdba2f..af48e44 100644 --- a/engine/src/models/item/media.rs +++ b/engine/src/models/item/media.rs @@ -1,7 +1,8 @@ -use crate::database::Database; use serde::{Deserialize, Serialize}; use sqlx::query_as; +use crate::database::Database; + #[derive(sqlx::FromRow, poem_openapi::Object, Debug, Clone, Serialize, Deserialize)] pub struct ItemMedia { pub item_id: String, diff --git a/engine/src/models/media.rs b/engine/src/models/media.rs index 4e7fba6..979a7f8 100644 --- a/engine/src/models/media.rs +++ b/engine/src/models/media.rs @@ -1,9 +1,10 @@ -use crate::database::Database; use chrono::{DateTime, Utc}; use poem_openapi::Object; use serde::{Deserialize, Serialize}; use sqlx::{query_as, FromRow}; +use crate::database::Database; + #[derive(FromRow, Object, Debug, Clone, Serialize, Deserialize)] pub struct Media { pub media_id: i32, diff --git a/engine/src/models/products.rs b/engine/src/models/products.rs index 115d9db..53be71c 100644 --- a/engine/src/models/products.rs +++ b/engine/src/models/products.rs @@ -1,9 +1,10 @@ -use crate::database::Database; use chrono::{DateTime, Utc}; use poem_openapi::Object; use serde::{Deserialize, Serialize}; use sqlx::{query_as, FromRow}; +use crate::database::Database; + #[derive(FromRow, Object, Debug, Clone, Serialize, Deserialize)] pub struct Product { pub product_id: i32, diff --git a/engine/src/models/tags.rs b/engine/src/models/tags.rs index 8f59e5c..5fbbc20 100644 --- a/engine/src/models/tags.rs +++ b/engine/src/models/tags.rs @@ -1,9 +1,10 @@ -use crate::database::Database; use chrono::{DateTime, Utc}; use poem_openapi::Object; use serde::{Deserialize, Serialize}; use sqlx::{query_as, FromRow}; +use crate::database::Database; + #[derive(FromRow, Object, Debug, Clone, Serialize, Deserialize)] pub struct Tag { pub tag_id: i32, diff --git a/engine/src/models/user/userentry.rs b/engine/src/models/user/userentry.rs index 312ca0a..c3ddad2 100644 --- a/engine/src/models/user/userentry.rs +++ b/engine/src/models/user/userentry.rs @@ -1,9 +1,10 @@ -use crate::database::Database; use chrono::{DateTime, Utc}; use openid::Userinfo; use serde::{Deserialize, Serialize}; use sqlx::{query, query_as, types::Json, FromRow}; +use crate::database::Database; + /// A user object that is stored in the database #[derive(FromRow, Debug, Clone, Serialize, Deserialize)] pub struct UserEntry { @@ -44,8 +45,7 @@ impl UserEntry { ) -> Result, sqlx::Error> { query_as!( UserEntry, - r#"SELECT user_id, oauth_sub, oauth_data::text::json as "oauth_data!: Json", - nickname, created_at, updated_at FROM users WHERE oauth_sub = $1"#, + "SELECT user_id, oauth_sub, oauth_data::text::json as \"oauth_data!: Json\", nickname, created_at, updated_at FROM users WHERE oauth_sub = $1", oauth_sub ) .fetch_optional(&database.pool) @@ -58,8 +58,7 @@ impl UserEntry { ) -> Result, sqlx::Error> { query_as!( UserEntry, - r#"SELECT user_id, oauth_sub, oauth_data::text::json as "oauth_data!: Json", - nickname, created_at, updated_at FROM users WHERE user_id = $1"#, + "SELECT user_id, oauth_sub, oauth_data::text::json as \"oauth_data!: Json\", nickname, created_at, updated_at FROM users WHERE user_id = $1", user_id ) .fetch_optional(&database.pool) diff --git a/engine/src/routes/error.rs b/engine/src/routes/error.rs deleted file mode 100644 index 08a4c65..0000000 --- a/engine/src/routes/error.rs +++ /dev/null @@ -1,24 +0,0 @@ -use poem::{error::ResponseError, IntoResponse, Response}; -use poem_openapi::Enum; -use reqwest::StatusCode; - -#[derive(Debug, Clone, Enum, thiserror::Error)] -pub enum HttpError { - #[error("Not found")] - NotFound, -} - -impl ResponseError for HttpError { - fn status(&self) -> StatusCode { - match self { - HttpError::NotFound => StatusCode::NOT_FOUND, - } - } - - fn as_response(&self) -> Response - where - Self: std::error::Error + Send + Sync + 'static, - { - self.status().into_response() - } -} diff --git a/engine/src/routes/mod.rs b/engine/src/routes/mod.rs index 3dfa84b..09b7c10 100644 --- a/engine/src/routes/mod.rs +++ b/engine/src/routes/mod.rs @@ -13,7 +13,6 @@ use users::ApiUserById; use crate::state::AppState; -pub mod error; pub mod instance; pub mod items; pub mod me; diff --git a/engine/src/routes/oauth/callback.rs b/engine/src/routes/oauth/callback.rs index 8ba09fa..98a74b9 100644 --- a/engine/src/routes/oauth/callback.rs +++ b/engine/src/routes/oauth/callback.rs @@ -4,9 +4,10 @@ use openid::Token; use poem::{ handler, http::HeaderMap, - web::{Data, Query, RealIp, Redirect}, - IntoResponse, + web::{Data, Query, RealIp, Redirect, WithHeader}, + IntoResponse, Result, }; +use reqwest::StatusCode; use serde::Deserialize; use url::Url; use uuid::Uuid; @@ -33,8 +34,12 @@ pub async fn callback( state: Data<&Arc>, ip: RealIp, headers: &HeaderMap, -) -> impl IntoResponse { - let mut token = state.openid.request_token(&query.code).await.unwrap(); +) -> Result> { + let mut token = state.openid.request_token(&query.code).await.map_err(|_| { + poem::Error::from_response( + Redirect::temporary(state.openid.redirect_url()).into_response(), + ) + })?; let mut token = Token::from(token); @@ -45,8 +50,6 @@ pub async fn callback( let oauth_userinfo = state.openid.request_userinfo(&token).await.unwrap(); - format!("Hello {:?}", oauth_userinfo); - // Now we must verify the user information, decide wether they deserve access, and if so return a token. let user = UserEntry::upsert(&oauth_userinfo, None, &state.database) .await @@ -77,6 +80,6 @@ pub async fn callback( redirect_url.set_query(Some(&format!("token={}", token))); - Redirect::temporary(redirect_url) - .with_header("Set-Cookie", format!("property.v3x.token={}", token)) + Ok(Redirect::temporary(redirect_url) + .with_header("Set-Cookie", format!("property.v3x.token={}", token))) } diff --git a/engine/src/routes/root.rs b/engine/src/routes/root.rs index c9346e4..52e4b2c 100644 --- a/engine/src/routes/root.rs +++ b/engine/src/routes/root.rs @@ -1,22 +1,17 @@ use std::sync::Arc; -use poem::{ - web::{Data, Path}, - Result, -}; +use poem::{web::{Data, Path}, Result}; use poem_openapi::{ param::Query, payload::{Json, PlainText}, OpenApi, }; +use reqwest::StatusCode; use crate::{ - models::{item::Item, media::Media, products::Product}, - state::AppState, + models::{item::Item, media::Media, products::Product}, state::AppState }; -use super::error::HttpError; - pub struct RootApi; #[OpenApi] @@ -79,7 +74,7 @@ impl RootApi { match item { Some(item) => Ok(Json(item)), - None => Err(HttpError::NotFound.into()), + None => Err(StatusCode::NOT_FOUND.into()), } } } diff --git a/engine/src/routes/sessions/delete.rs b/engine/src/routes/sessions/delete.rs index 384724a..6c267df 100644 --- a/engine/src/routes/sessions/delete.rs +++ b/engine/src/routes/sessions/delete.rs @@ -1,11 +1,13 @@ -use crate::{auth::middleware::AuthToken, models::sessions::Session, state::AppState}; +use std::sync::Arc; + use poem::{ handler, web::{Data, Json}, Error, IntoResponse, }; use reqwest::StatusCode; -use std::sync::Arc; + +use crate::{auth::middleware::AuthToken, models::sessions::Session, state::AppState}; #[handler] pub async fn delete_sessions(state: Data<&Arc>, token: AuthToken) -> impl IntoResponse { diff --git a/engine/src/state.rs b/engine/src/state.rs index 25726d8..7ddcb8a 100644 --- a/engine/src/state.rs +++ b/engine/src/state.rs @@ -1,9 +1,10 @@ use std::env; -use crate::{auth::oauth::OpenIDClient, database::Database}; use openid::DiscoveredClient; use reqwest::Url; +use crate::{auth::oauth::OpenIDClient, database::Database}; + pub struct AppState { pub database: Database, // #[cfg(feature = "oauth")] diff --git a/web/src/api/core.ts b/web/src/api/core.ts index fc412d7..ed4c5ba 100644 --- a/web/src/api/core.ts +++ b/web/src/api/core.ts @@ -1,4 +1,4 @@ -import { QueryObserverOptions, QueryOptions, useMutation, useQuery } from '@tanstack/react-query'; +import { DefinedUseQueryResult, QueryObserverOptions, QueryOptions, useMutation, useQuery, UseQueryResult } from '@tanstack/react-query'; import { useAuth } from './auth'; @@ -17,13 +17,13 @@ export function useHttp( key: string, options?: HttpOptions, queryOptions?: Partial -) { +): DefinedUseQueryResult { const { token, clearAuthToken } = useAuth(); const { auth = 'ignore', skipIfUnauthed = false } = options || {}; return useQuery({ queryKey: [key], - enabled: true, + enabled: auth !== 'required' || !!token, queryFn: async () => { const headers = new Headers(); diff --git a/web/src/api/instance_settings.ts b/web/src/api/instance_settings.ts index dd25e01..f148d44 100644 --- a/web/src/api/instance_settings.ts +++ b/web/src/api/instance_settings.ts @@ -23,10 +23,7 @@ export const getInstanceSettings = () => { }; export const useInstanceSettings = () => { - return useQuery({ - queryKey: ['instance_settings'], - queryFn: getInstanceSettings, - }); + return useQuery(getInstanceSettings()); }; export const formatIdCasing = ( diff --git a/web/src/components/Navbar.tsx b/web/src/components/Navbar.tsx index 840037d..fc80ece 100644 --- a/web/src/components/Navbar.tsx +++ b/web/src/components/Navbar.tsx @@ -2,6 +2,7 @@ /* eslint-disable no-undef */ import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import { Link } from '@tanstack/react-router'; +import { FileRoutesByPath } from '@tanstack/react-router'; import { useAuth } from '../api/auth'; import { useApiMe } from '../api/me'; @@ -21,19 +22,26 @@ export const Navbar = () => { return (
-
+ v3x.property -
+
- {[ - ['/', 'Home'], - ['/create', 'Create'], - ['/sessions', 'Sessions'], - ].map(([path, name]) => ( + {( + [ + ['/search', 'Search'], + ['/items', 'Items'], + ['/products', 'Products'], + ['/logs', 'Logs'], + ['/create', 'Create'], + ] as [keyof FileRoutesByPath, string][] + ).map(([path, name]) => ( {name} @@ -65,8 +73,13 @@ export const Navbar = () => { className="DropdownMenuContent" sideOffset={5} > - - Settings + + + Settings + void; errorMessage?: string; + width?: 'full' | 'fit'; }; export const BaseInput = ({ @@ -26,20 +27,32 @@ export const BaseInput = ({ value, onChange, errorMessage, + width = 'fit', }: BaseInputProperties) => { return ( <> - - {label} - -
-
+ {label && ( + + {label} + + )} +
+
onChange?.(event.target.value)} value={value} /> diff --git a/web/src/components/search/SearchInput.tsx b/web/src/components/search/SearchInput.tsx new file mode 100644 index 0000000..050c98d --- /dev/null +++ b/web/src/components/search/SearchInput.tsx @@ -0,0 +1,12 @@ +import { BaseInput } from '../input/BaseInput'; + +export const SearchInput = () => { + return ( +
+
+ + +
+
+ ); +}; diff --git a/web/src/index.css b/web/src/index.css index eb35d38..c82123b 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -7,6 +7,18 @@ @apply disabled:bg-neutral-100 disabled:text-neutral-400 disabled:border-neutral-200 disabled:hover:bg-neutral-100 disabled:cursor-not-allowed; } +.card { + @apply border border-solid border-neutral-200 rounded-md; + /* @apply w-full gap-4 border border-t-4 shadow-sm rounded-md pt-4; */ +} +.card:not(.no-padding) { + @apply p-4; +} + +.input { + @apply border rounded-md focus:outline focus:outline-2 outline-offset-2 outline-blue-500 px-2 py-1; +} + .h1 { @apply text-2xl font-semibold; } diff --git a/web/src/layouts/SimpleCenterPage.tsx b/web/src/layouts/SimpleCenterPage.tsx new file mode 100644 index 0000000..e4ca4a7 --- /dev/null +++ b/web/src/layouts/SimpleCenterPage.tsx @@ -0,0 +1,28 @@ +import clsx from 'clsx'; +import { FC, PropsWithChildren } from 'react'; + +export type SCPageProperties = PropsWithChildren<{ + title: string; + width?: 'xl' | '2xl' | '3xl' | '4xl'; +}>; + +export const SCPage: FC = ({ + children, + title, + width = '4xl', +}) => { + return ( +
+

{title}

+ {children} +
+ ); +}; diff --git a/web/src/routeTree.gen.ts b/web/src/routeTree.gen.ts index ccc5f9d..4e4525c 100644 --- a/web/src/routeTree.gen.ts +++ b/web/src/routeTree.gen.ts @@ -23,6 +23,11 @@ import { Route as ItemItemIdEditImport } from './routes/item/$itemId/edit' const CreateLazyImport = createFileRoute('/create')() const AboutLazyImport = createFileRoute('/about')() const IndexLazyImport = createFileRoute('/')() +const SettingsIndexLazyImport = createFileRoute('/settings/')() +const SearchIndexLazyImport = createFileRoute('/search/')() +const ProductsIndexLazyImport = createFileRoute('/products/')() +const LogsIndexLazyImport = createFileRoute('/logs/')() +const ItemsIndexLazyImport = createFileRoute('/items/')() // Create/Update Routes @@ -51,6 +56,35 @@ const IndexLazyRoute = IndexLazyImport.update({ getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route)) +const SettingsIndexLazyRoute = SettingsIndexLazyImport.update({ + path: '/settings/', + getParentRoute: () => rootRoute, +} as any).lazy(() => + import('./routes/settings/index.lazy').then((d) => d.Route), +) + +const SearchIndexLazyRoute = SearchIndexLazyImport.update({ + path: '/search/', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/search/index.lazy').then((d) => d.Route)) + +const ProductsIndexLazyRoute = ProductsIndexLazyImport.update({ + path: '/products/', + getParentRoute: () => rootRoute, +} as any).lazy(() => + import('./routes/products/index.lazy').then((d) => d.Route), +) + +const LogsIndexLazyRoute = LogsIndexLazyImport.update({ + path: '/logs/', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/logs/index.lazy').then((d) => d.Route)) + +const ItemsIndexLazyRoute = ItemsIndexLazyImport.update({ + path: '/items/', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/items/index.lazy').then((d) => d.Route)) + const ItemItemIdIndexRoute = ItemItemIdIndexImport.update({ path: '/item/$itemId/', getParentRoute: () => rootRoute, @@ -100,6 +134,41 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof CreateLazyImport parentRoute: typeof rootRoute } + '/items/': { + id: '/items/' + path: '/items' + fullPath: '/items' + preLoaderRoute: typeof ItemsIndexLazyImport + parentRoute: typeof rootRoute + } + '/logs/': { + id: '/logs/' + path: '/logs' + fullPath: '/logs' + preLoaderRoute: typeof LogsIndexLazyImport + parentRoute: typeof rootRoute + } + '/products/': { + id: '/products/' + path: '/products' + fullPath: '/products' + preLoaderRoute: typeof ProductsIndexLazyImport + parentRoute: typeof rootRoute + } + '/search/': { + id: '/search/' + path: '/search' + fullPath: '/search' + preLoaderRoute: typeof SearchIndexLazyImport + parentRoute: typeof rootRoute + } + '/settings/': { + id: '/settings/' + path: '/settings' + fullPath: '/settings' + preLoaderRoute: typeof SettingsIndexLazyImport + parentRoute: typeof rootRoute + } '/item/$itemId/edit': { id: '/item/$itemId/edit' path: '/item/$itemId/edit' @@ -125,6 +194,11 @@ export const routeTree = rootRoute.addChildren({ SessionsRoute, AboutLazyRoute, CreateLazyRoute, + ItemsIndexLazyRoute, + LogsIndexLazyRoute, + ProductsIndexLazyRoute, + SearchIndexLazyRoute, + SettingsIndexLazyRoute, ItemItemIdEditRoute, ItemItemIdIndexRoute, }) @@ -142,6 +216,11 @@ export const routeTree = rootRoute.addChildren({ "/sessions", "/about", "/create", + "/items/", + "/logs/", + "/products/", + "/search/", + "/settings/", "/item/$itemId/edit", "/item/$itemId/" ] @@ -161,6 +240,21 @@ export const routeTree = rootRoute.addChildren({ "/create": { "filePath": "create.lazy.tsx" }, + "/items/": { + "filePath": "items/index.lazy.tsx" + }, + "/logs/": { + "filePath": "logs/index.lazy.tsx" + }, + "/products/": { + "filePath": "products/index.lazy.tsx" + }, + "/search/": { + "filePath": "search/index.lazy.tsx" + }, + "/settings/": { + "filePath": "settings/index.lazy.tsx" + }, "/item/$itemId/edit": { "filePath": "item/$itemId/edit.tsx" }, diff --git a/web/src/routes/create.lazy.tsx b/web/src/routes/create.lazy.tsx index a80545f..425bca8 100644 --- a/web/src/routes/create.lazy.tsx +++ b/web/src/routes/create.lazy.tsx @@ -6,19 +6,20 @@ import { isValidId } from '../api/generate_id'; import { formatId, useInstanceSettings } from '../api/instance_settings'; import { useApiCreateItem } from '../api/item'; import { NewItemIdInput } from '../components/input/NewItemIdInput'; +import { SCPage } from '../layouts/SimpleCenterPage'; const component = () => { const { data: instanceSettings } = useInstanceSettings(); const navigate = useNavigate(); const [item_id, setItemId] = useState(''); const { mutate: createItem } = useApiCreateItem(); + const isDisabled = !isValidId(item_id); const formattedItemId = formatId(item_id, instanceSettings); return ( -
-

Create new Item

-
+ +
{
-
+ ); }; diff --git a/web/src/routes/index.lazy.tsx b/web/src/routes/index.lazy.tsx index a98ff47..7a6d2e5 100644 --- a/web/src/routes/index.lazy.tsx +++ b/web/src/routes/index.lazy.tsx @@ -2,23 +2,27 @@ import { createLazyFileRoute } from '@tanstack/react-router'; import { ItemPreview } from '../components/item/ItemPreview'; import { UserProfile } from '../components/UserProfile'; +import { SCPage } from '../layouts/SimpleCenterPage'; const component = () => { return ( -
-

Welcome Home!

-
- {/* */} + +
+
+ {/* */} +
-
- - - +
+
+ + + +
+
+ +
-
- -
-
+
); }; diff --git a/web/src/routes/item/$itemId/edit.tsx b/web/src/routes/item/$itemId/edit.tsx index 01c2c05..a26b2c1 100644 --- a/web/src/routes/item/$itemId/edit.tsx +++ b/web/src/routes/item/$itemId/edit.tsx @@ -1,5 +1,15 @@ -import { createFileRoute } from '@tanstack/react-router'; +import { createFileRoute, useParams } from '@tanstack/react-router'; + +import { SCPage } from '../../../layouts/SimpleCenterPage'; export const Route = createFileRoute('/item/$itemId/edit')({ - component: () =>
Hello /item/$itemId/edit!
, + component: () => { + const { itemId } = useParams({ from: '/item/$itemId/edit' }); + + return ( + + Hello /item/$itemId/edit! + + ); + }, }); diff --git a/web/src/routes/item/$itemId/index.tsx b/web/src/routes/item/$itemId/index.tsx index a689933..78078c0 100644 --- a/web/src/routes/item/$itemId/index.tsx +++ b/web/src/routes/item/$itemId/index.tsx @@ -10,6 +10,7 @@ import { useApiItemById } from '../../../api/item'; import { ItemPreview } from '../../../components/item/ItemPreview'; import { MediaGallery } from '../../../components/media/MediaGallery'; import { UnauthorizedResourceModal } from '../../../components/Unauthorized'; +import { SCPage } from '../../../layouts/SimpleCenterPage'; import { queryClient } from '../../../util/query'; export const Route = createFileRoute('/item/$itemId/')({ @@ -36,8 +37,7 @@ export const Route = createFileRoute('/item/$itemId/')({ } return ( -
-

Item {itemId}

+
-
+
); }, }); diff --git a/web/src/routes/items/index.lazy.tsx b/web/src/routes/items/index.lazy.tsx new file mode 100644 index 0000000..e2f9ec7 --- /dev/null +++ b/web/src/routes/items/index.lazy.tsx @@ -0,0 +1,13 @@ +import { createLazyFileRoute } from '@tanstack/react-router'; + +import { SCPage } from '../../layouts/SimpleCenterPage'; + +export const Route = createLazyFileRoute('/items/')({ + component: () => ( + +
+

All Items go here

+
+
+ ), +}); diff --git a/web/src/routes/logs/index.lazy.tsx b/web/src/routes/logs/index.lazy.tsx new file mode 100644 index 0000000..0532181 --- /dev/null +++ b/web/src/routes/logs/index.lazy.tsx @@ -0,0 +1,16 @@ +import { createLazyFileRoute } from '@tanstack/react-router'; + +import { SCPage } from '../../layouts/SimpleCenterPage'; + +export const Route = createLazyFileRoute('/logs/')({ + component: () => ( + +
+

Recent logs

+
+
+

Search for logs

+
+
+ ), +}); diff --git a/web/src/routes/products/index.lazy.tsx b/web/src/routes/products/index.lazy.tsx new file mode 100644 index 0000000..177e774 --- /dev/null +++ b/web/src/routes/products/index.lazy.tsx @@ -0,0 +1,13 @@ +import { createLazyFileRoute } from '@tanstack/react-router'; + +import { SCPage } from '../../layouts/SimpleCenterPage'; + +export const Route = createLazyFileRoute('/products/')({ + component: () => ( + +
+

All Products go here

+
+
+ ), +}); diff --git a/web/src/routes/search/index.lazy.tsx b/web/src/routes/search/index.lazy.tsx new file mode 100644 index 0000000..399a2f3 --- /dev/null +++ b/web/src/routes/search/index.lazy.tsx @@ -0,0 +1,15 @@ +import { createLazyFileRoute } from '@tanstack/react-router'; + +import { SearchInput } from '../../components/search/SearchInput'; +import { SCPage } from '../../layouts/SimpleCenterPage'; + +export const Route = createLazyFileRoute('/search/')({ + component: () => ( + +
+ +
+
Results...
+
+ ), +}); diff --git a/web/src/routes/sessions.tsx b/web/src/routes/sessions.tsx index 33fcf12..fbbedd5 100644 --- a/web/src/routes/sessions.tsx +++ b/web/src/routes/sessions.tsx @@ -3,12 +3,13 @@ import { FC } from 'react'; import { useAuth } from '../api/auth'; import { ActiveSessionsTable } from '../components/ActiveSessionsTable'; +import { SCPage } from '../layouts/SimpleCenterPage'; const component: FC = () => { return ( -
+ -
+ ); }; diff --git a/web/src/routes/settings/index.lazy.tsx b/web/src/routes/settings/index.lazy.tsx new file mode 100644 index 0000000..cdb71e8 --- /dev/null +++ b/web/src/routes/settings/index.lazy.tsx @@ -0,0 +1,7 @@ +import { createLazyFileRoute } from '@tanstack/react-router'; + +import { SCPage } from '../../layouts/SimpleCenterPage'; + +export const Route = createLazyFileRoute('/settings/')({ + component: () => Hello /settings!, +});