This commit is contained in:
Djkáťo 2024-06-03 00:03:30 +02:00
commit a6a32a896b
26 changed files with 7425 additions and 0 deletions

2
.env Normal file
View file

@ -0,0 +1,2 @@
DB_USER=saleor-marketplace
DB_PASSWORD="{%cA_#dr}{3'ZDGC,Jy<+S-_M+FE?]][Cu#N`D_V"

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules
target

12
.neoconf.json Normal file
View file

@ -0,0 +1,12 @@
{
"lspconfig": {
"rust_analyzer": {
"rust-analyzer.cargo.features": "all",
"rust-analyzer.rustfmt.overrideCommand": [
"leptosfmt",
"--stdin",
"--rustfmt"
]
}
}
}

5169
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

117
Cargo.toml Normal file
View file

@ -0,0 +1,117 @@
[package]
name = "saleor-marketplace"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
axum = { version = "0.7", optional = true }
console_error_panic_hook = "0.1"
leptos = { version = "0.6", features = ["nightly"] }
leptos_axum = { version = "0.6", optional = true }
leptos_meta = { version = "0.6", features = ["nightly"] }
leptos_router = { version = "0.6", features = ["nightly"] }
tokio = { version = "1", features = [
"macros",
"rt-multi-thread",
], optional = true }
tower = { version = "0.4", optional = true }
tower-http = { version = "0.5", features = ["fs"], optional = true }
wasm-bindgen = "=0.2.92"
thiserror = "1"
tracing = { version = "0.1", optional = true }
http = "1"
pulldown-cmark = "0.11.0"
surrealdb = { version = "<1.5.0", features = ["kv-rocksdb"], optional = true }
serde = { version = "1.0.202", features = ["derive"] }
semver = { version = "1.0.23", features = ["serde"] }
saleor-app-sdk = { version = "0.2.3", default-features = false }
chrono = { version = "0.4.38", features = ["serde"] }
[features]
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
ssr = [
"dep:axum",
"dep:surrealdb",
"dep:tokio",
"dep:tower",
"dep:tower-http",
"dep:leptos_axum",
"leptos/ssr",
"leptos_meta/ssr",
"leptos_router/ssr",
"dep:tracing",
]
# Defines a size-optimized profile for the WASM bundle in release mode
[profile.wasm-release]
inherits = "release"
opt-level = 'z'
lto = true
codegen-units = 1
panic = "abort"
[package.metadata.leptos]
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
output-name = "saleor-marketplace"
# 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"
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css
# style-file = "style/main.scss"
# Assets source dir. All files found here will be copied and synchronized to site-root.
tailwind-input-file = "style/base.css"
# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir.
#
# Optional. Env: LEPTOS_ASSETS_DIR.
assets-dir = "public"
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
site-addr = "127.0.0.1:3000"
# The port to use for automatic reload monitoring
reload-port = 3001
# [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"
# 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
# The profile to use for the lib target when compiling for release
#
# Optional. Defaults to "release".
lib-profile-release = "wasm-release"

24
LICENSE Normal file
View file

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>

90
README.md Normal file
View file

@ -0,0 +1,90 @@
<picture>
<source srcset="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_Solid_White.svg" media="(prefers-color-scheme: dark)">
<img src="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_RGB.svg" alt="Leptos Logo">
</picture>
# Leptos Axum Starter Template
This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool using [Axum](https://github.com/tokio-rs/axum).
## Creating your template repo
If you don't have `cargo-leptos` installed you can install it with
```bash
cargo install cargo-leptos
```
Then run
```bash
cargo leptos new --git leptos-rs/start-axum
```
to generate a new project template.
```bash
cd saleor-marketplace
```
to go to your newly created project.
Feel free to explore the project structure, but the best place to start with your application code is in `src/app.rs`.
Addtionally, Cargo.toml may need updating as new versions of the dependencies are released, especially if things are not working after a `cargo update`.
## Running your project
```bash
cargo leptos watch
```
## Installing Additional Tools
By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools.
1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly
2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly
3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future)
4. `npm install -g sass` - install `dart-sass` (should be optional in future
## Compiling for Release
```bash
cargo leptos build --release
```
Will generate your server binary in target/server/release and your site package in target/site
## Testing Your Project
```bash
cargo leptos end-to-end
```
```bash
cargo leptos end-to-end --release
```
Cargo-leptos uses Playwright as the end-to-end test tool.
Tests are located in end2end/tests directory.
## Executing a Server on a Remote Machine Without the Toolchain
After running a `cargo leptos build --release` the minimum files needed are:
1. The server binary located in `target/server/release`
2. The `site` directory and all files within located in `target/site`
Copy these files to your remote server. The directory structure should be:
```text
saleor-marketplace
site/
```
Set the following environment variables (updating for your project as needed):
```text
LEPTOS_OUTPUT_NAME="saleor-marketplace"
LEPTOS_SITE_ROOT="site"
LEPTOS_SITE_PKG_DIR="pkg"
LEPTOS_SITE_ADDR="127.0.0.1:3000"
LEPTOS_RELOAD_PORT="3001"
```
Finally, run the server binary.
## Licensing
This template itself is released under the Unlicense. You should replace the LICENSE for your own application with an appropriate license if you plan to release it publicly.

18
docker-compose.yml Normal file
View file

@ -0,0 +1,18 @@
services:
surrealdb:
env_file:
- .env
entrypoint:
- /surreal
- start
- --auth
- --user
- $DB_USER
- --pass
- $DB_PASSWORD
- file:/db/saleor-marketplace.db
image: surrealdb/surrealdb:latest
volumes:
- ./db:/db
ports:
- 8000:8000

74
end2end/package-lock.json generated Normal file
View file

@ -0,0 +1,74 @@
{
"name": "end2end",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "end2end",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.28.0"
}
},
"node_modules/@playwright/test": {
"version": "1.28.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz",
"integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==",
"dev": true,
"dependencies": {
"@types/node": "*",
"playwright-core": "1.28.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@types/node": {
"version": "18.11.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
"integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
"dev": true
},
"node_modules/playwright-core": {
"version": "1.28.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz",
"integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==",
"dev": true,
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=14"
}
}
},
"dependencies": {
"@playwright/test": {
"version": "1.28.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz",
"integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==",
"dev": true,
"requires": {
"@types/node": "*",
"playwright-core": "1.28.0"
}
},
"@types/node": {
"version": "18.11.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz",
"integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==",
"dev": true
},
"playwright-core": {
"version": "1.28.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz",
"integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==",
"dev": true
}
}
}

13
end2end/package.json Normal file
View file

@ -0,0 +1,13 @@
{
"name": "end2end",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.28.0"
}
}

View file

@ -0,0 +1,107 @@
import type { PlaywrightTestConfig } from "@playwright/test";
import { devices } from "@playwright/test";
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();
/**
* See https://playwright.dev/docs/test-configuration.
*/
const config: PlaywrightTestConfig = {
testDir: "./tests",
/* Maximum time one test can run for. */
timeout: 30 * 1000,
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
* For example in `await expect(locator).toHaveText();`
*/
timeout: 5000,
},
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
actionTimeout: 0,
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://localhost:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
},
},
{
name: "firefox",
use: {
...devices["Desktop Firefox"],
},
},
{
name: "webkit",
use: {
...devices["Desktop Safari"],
},
},
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: {
// ...devices['Pixel 5'],
// },
// },
// {
// name: 'Mobile Safari',
// use: {
// ...devices['iPhone 12'],
// },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: {
// channel: 'msedge',
// },
// },
// {
// name: 'Google Chrome',
// use: {
// channel: 'chrome',
// },
// },
],
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
// outputDir: 'test-results/',
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// port: 3000,
// },
};
export default config;

View file

@ -0,0 +1,9 @@
import { test, expect } from "@playwright/test";
test("homepage has title and heading text", async ({ page }) => {
await page.goto("http://localhost:3000/");
await expect(page).toHaveTitle("Welcome to Leptos");
await expect(page.locator("h1")).toHaveText("Welcome to Leptos!");
});

1379
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

5
package.json Normal file
View file

@ -0,0 +1,5 @@
{
"devDependencies": {
"tailwindcss": "^3.4.3"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

2
rust-toolchain.toml Normal file
View file

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

56
src/app.rs Normal file
View file

@ -0,0 +1,56 @@
use crate::error_template::{AppError, ErrorTemplate};
use crate::server::types::SaleorApp;
use leptos::*;
use leptos_meta::*;
use leptos_router::*;
#[component]
pub fn App() -> impl IntoView {
// Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context();
view! {
<Stylesheet id="leptos" href="/pkg/saleor-marketplace.css"/>
// sets the document title
<Title text="Welcome to Leptos"/>
// content for this welcome page
<Router fallback=|| {
let mut outside_errors = Errors::default();
outside_errors.insert_with_default_key(AppError::NotFound);
view! { <ErrorTemplate outside_errors/> }.into_view()
}>
<main>
<Routes>
<Route path="" view=HomePage/>
</Routes>
</main>
</Router>
}
}
#[server]
pub async fn get_all_apps() -> Result<Vec<SaleorApp>, ServerFnError>{
let conn = crate::server::db::connect()?;
let res = conn.query("SELECT * FROM saleor_app WHERE saleor_app.name ='Sitemap generator' ");
dbg!(&res);
_ = res.await;
Err(ServerFnError::new("rip"))
}
/// Renders the home page of your application.
#[component]
fn HomePage() -> impl IntoView {
let apps = create_resource(|| (), |_| async move {get_all_apps().await});
view! {
<h1>"Welcome to Leptos!"</h1>
{move || match apps.get() {
Some(_d) => view! { <p>"loaded smt"</p> }.into_view(),
None => view! { <p>"loading..."</p> }.into_view(),
}}
<div></div>
}
}

72
src/error_template.rs Normal file
View file

@ -0,0 +1,72 @@
use http::status::StatusCode;
use leptos::*;
use thiserror::Error;
#[derive(Clone, Debug, Error)]
pub enum AppError {
#[error("Not Found")]
NotFound,
}
impl AppError {
pub fn status_code(&self) -> StatusCode {
match self {
AppError::NotFound => StatusCode::NOT_FOUND,
}
}
}
// A basic function to display errors served by the error boundaries.
// Feel free to do more complicated things here than just displaying the error.
#[component]
pub fn ErrorTemplate(
#[prop(optional)] outside_errors: Option<Errors>,
#[prop(optional)] errors: Option<RwSignal<Errors>>,
) -> impl IntoView {
let errors = match outside_errors {
Some(e) => create_rw_signal(e),
None => match errors {
Some(e) => e,
None => panic!("No Errors found and we expected errors!"),
},
};
// Get Errors from Signal
let errors = errors.get_untracked();
// Downcast lets us take a type that implements `std::error::Error`
let errors: Vec<AppError> = errors
.into_iter()
.filter_map(|(_k, v)| v.downcast_ref::<AppError>().cloned())
.collect();
println!("Errors: {errors:#?}");
// Only the response code for the first error is actually sent from the server
// this may be customized by the specific application
#[cfg(feature = "ssr")]
{
use leptos_axum::ResponseOptions;
let response = use_context::<ResponseOptions>();
if let Some(response) = response {
response.set_status(errors[0].status_code());
}
}
view! {
<h1>{if errors.len() > 1 {"Errors"} else {"Error"}}</h1>
<For
// a function that returns the items we're iterating over; a signal is fine
each= move || {errors.clone().into_iter().enumerate()}
// a unique key for each item as a reference
key=|(index, _error)| *index
// renders each item to a view
children=move |error| {
let error_string = error.1.to_string();
let error_code= error.1.status_code();
view! {
<h2>{error_code.to_string()}</h2>
<p>"Error: " {error_string}</p>
}
}
/>
}
}

60
src/fileserv.rs Normal file
View file

@ -0,0 +1,60 @@
use crate::app::App;
use axum::response::Response as AxumResponse;
use axum::{
body::Body,
extract::State,
http::{Request, Response, StatusCode},
response::IntoResponse,
};
use leptos::*;
use tower::ServiceExt;
use tower_http::services::ServeDir;
pub async fn file_and_error_handler(
State(options): State<LeptosOptions>,
req: Request<Body>,
) -> AxumResponse {
let root = options.site_root.clone();
let (parts, body) = req.into_parts();
let mut static_parts = parts.clone();
static_parts.headers.clear();
if let Some(encodings) = parts.headers.get("accept-encoding") {
static_parts
.headers
.insert("accept-encoding", encodings.clone());
}
let res = get_static_file(Request::from_parts(static_parts, Body::empty()), &root)
.await
.unwrap();
if res.status() == StatusCode::OK {
res.into_response()
} else {
let handler = leptos_axum::render_app_to_stream(options.to_owned(), App);
handler(Request::from_parts(parts, body))
.await
.into_response()
}
}
async fn get_static_file(
request: Request<Body>,
root: &str,
) -> Result<Response<Body>, (StatusCode, String)> {
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root)
.precompressed_gzip()
.precompressed_br()
.oneshot(request)
.await
{
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Error serving files: {err}"),
)),
}
}

14
src/lib.rs Normal file
View file

@ -0,0 +1,14 @@
pub mod app;
pub mod error_template;
#[cfg(feature = "ssr")]
pub mod fileserv;
pub mod server;
#[cfg(feature = "hydrate")]
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
use crate::app::*;
console_error_panic_hook::set_once();
leptos::mount_to_body(App);
}

40
src/main.rs Normal file
View file

@ -0,0 +1,40 @@
pub mod server;
#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() {
use axum::Router;
use leptos::*;
use leptos_axum::{generate_route_list, LeptosRoutes};
use saleor_marketplace::app::*;
use saleor_marketplace::fileserv::file_and_error_handler;
// Setting get_configuration(None) means we'll be using cargo-leptos's env values
// For deployment these variables are:
// <https://github.com/leptos-rs/start-axum#executing-a-server-on-a-remote-machine-without-the-toolchain>
// Alternately a file can be specified such as Some("Cargo.toml")
// The file would need to be included with the executable when moved to deployment
let conf = get_configuration(None).await.unwrap();
let leptos_options = conf.leptos_options;
let addr = leptos_options.site_addr;
let routes = generate_route_list(App);
// build our application with a route
let app = Router::new()
.leptos_routes(&leptos_options, routes, App)
.fallback(file_and_error_handler)
.with_state(leptos_options);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
logging::log!("listening on http://{}", &addr);
axum::serve(listener, app.into_make_service())
.await
.unwrap();
}
#[cfg(not(feature = "ssr"))]
pub fn main() {
// no client-side main function
// unless we want this to work with e.g., Trunk for a purely client-side app
// see lib.rs for hydration function instead
}

87
src/server/db.rs Normal file
View file

@ -0,0 +1,87 @@
use std::path::PathBuf;
use saleor_app_sdk::manifest::AppManifest;
use serde::Deserialize;
use surrealdb::engine::local::Db;
use surrealdb::engine::local::RocksDb;
use surrealdb::sql::Thing;
use surrealdb::Surreal;
use super::types::SaleorApp;
#[derive(Debug, Deserialize)]
struct Record {
#[allow(dead_code)]
id: Thing,
}
#[tokio::main]
pub async fn connect() -> surrealdb::Result<Surreal<Db>> {
// Create database connection
let db = Surreal::new::<RocksDb>("/db").await?;
// Select a specific namespace / database
db.use_ns("marketplace").use_db("apps").await?;
let demo_data: Vec<Record> = db.create("saleor_app").content(SaleorApp{
name: "Sitemap generator".to_owned(),
logo: PathBuf::new(),
images: vec![PathBuf::new()],
authors: vec![],
versions: vec![semver::Version::parse( "2.1.1").unwrap()],
description: "Sitemap stuff".to_owned(),
is_verified: true,
last_updated: chrono::Local::now().into(),
built_for_url: None,
supported_apls: vec![],
supported_deployments: vec![],
minimal_docker_compose: "".to_owned(),
manifest: AppManifest{
name: "Sitemap generator".to_owned(),
id: "hihihaha".to_owned(),
about: None,
brand: None,
author: None,
version: "2.1.1".to_owned(),
app_url: "localhost:3000".to_owned(),
token_target_url: "localhost:3000".to_owned(),
..Default::default()
}
}).await?;
dbg!(demo_data);
// // Create a new person with a random id
// let created: Vec<Record> = db
// .create("person")
// .content(Person {
// title: "Founder & CEO",
// name: Name {
// first: "Tobie",
// last: "Morgan Hitchcock",
// },
// marketing: true,
// })
// .await?;
// dbg!(created);
//
// // Update a person record with a specific id
// let updated: Option<Record> = db
// .update(("person", "jaime"))
// .merge(Responsibility { marketing: true })
// .await?;
// dbg!(updated);
//
// // Select all people records
// let people: Vec<Record> = db.select("person").await?;
// dbg!(people);
//
// // Perform a custom advanced query
// let groups = db
// .query("SELECT marketing, count() FROM type::table($table) GROUP BY marketing")
// .bind(("table", "person"))
// .await?;
// dbg!(groups);
//
Ok(db)
}

4
src/server/mod.rs Normal file
View file

@ -0,0 +1,4 @@
#[cfg(feature = "ssr")]
pub mod db;
pub mod types;

56
src/server/types.rs Normal file
View file

@ -0,0 +1,56 @@
use std::path::PathBuf;
use chrono::FixedOffset;
use saleor_app_sdk::manifest::AppManifest;
use semver::Version;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SaleorApp {
pub name: String,
pub authors: Vec<AppAuthor>,
pub description: String,
pub versions: Vec<Version>,
/**
All files will target ./public/app_data/<app-id>/
*/
pub logo: PathBuf,
pub images: Vec<PathBuf>,
pub manifest: AppManifest,
/**
This will be a tag, which shows if I verified this app. Adding apps will be allowed publicly and anonymously.
This will show a disclaimer about quality and security.
*/
pub is_verified: bool,
pub supported_deployments: Vec<DeploymentType>,
/**
Service description will be read from this via openGraph.
*/
pub built_for_url: Option<String>,
/**
Will be either a .yml file or a static url to one. Not sure how to store this yet.
*/
pub minimal_docker_compose: String,
pub supported_apls: Vec<CustomAplType>,
pub last_updated: chrono::DateTime<FixedOffset>,
}
#[derive(Debug, Serialize, PartialEq, Deserialize, Clone)]
pub enum DeploymentType {
Docker,
Podman,
Linux,
Windows,
MacOS,
WASM,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AppAuthor {
name: String,
links: Vec<String>,
apps: Vec<SaleorApp>,
}
#[derive(Debug, Serialize, PartialEq, Deserialize, Clone)]
pub struct CustomAplType(String);

5
style/base.css Normal file
View file

@ -0,0 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital@0;1&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;

8
tailwind.config.js Normal file
View file

@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: {
files: ["*.html", "./src/**/*.rs"],
},
theme: {},
plugins: [],
}