mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-28 10:11:56 -05:00
Compare commits
107 Commits
gbj-patch-
...
wb-0.2.92
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
204c8eb360 | ||
|
|
2b4f5e0f58 | ||
|
|
943a992570 | ||
|
|
372a241d78 | ||
|
|
c06f6bede2 | ||
|
|
3e93a686f4 | ||
|
|
34cdff4cb3 | ||
|
|
530087d77d | ||
|
|
4bb43f6207 | ||
|
|
9e2fb62857 | ||
|
|
1da2fff706 | ||
|
|
9fd2987447 | ||
|
|
7996f835d0 | ||
|
|
d72b12524e | ||
|
|
8e79c5be5c | ||
|
|
de25658c36 | ||
|
|
e2e35a9659 | ||
|
|
bf1ba589c5 | ||
|
|
f70ebc1289 | ||
|
|
3cab09e015 | ||
|
|
b431315f7c | ||
|
|
5b40881e77 | ||
|
|
59d3cce3be | ||
|
|
6a83161368 | ||
|
|
4b00c16cb9 | ||
|
|
6d6019b956 | ||
|
|
3540291065 | ||
|
|
4809cf473e | ||
|
|
aa977001c1 | ||
|
|
c16189f095 | ||
|
|
d0a013c248 | ||
|
|
531ea74e33 | ||
|
|
545e87e540 | ||
|
|
2ca30a0b2d | ||
|
|
753bf1ed54 | ||
|
|
37c6387fea | ||
|
|
0a73487152 | ||
|
|
747aba0d7f | ||
|
|
04cf47d5da | ||
|
|
47abe00993 | ||
|
|
aa3700ffb9 | ||
|
|
0770b87cb7 | ||
|
|
330ebdb018 | ||
|
|
c3179d88cf | ||
|
|
ffcf3c2952 | ||
|
|
001ca5148e | ||
|
|
1e000afa78 | ||
|
|
0f7b8841b2 | ||
|
|
7dc0441f6c | ||
|
|
0a321a1bd7 | ||
|
|
88742952f0 | ||
|
|
8a4b972e0b | ||
|
|
95bd9cc544 | ||
|
|
23bc892a24 | ||
|
|
830fba794e | ||
|
|
98633c8700 | ||
|
|
b0f5c39711 | ||
|
|
b54aa7f3f5 | ||
|
|
e33ee7ec99 | ||
|
|
cd70b2f52b | ||
|
|
c75842ed0c | ||
|
|
4ad228bf47 | ||
|
|
bbe7115360 | ||
|
|
0658a550b0 | ||
|
|
4222c832b1 | ||
|
|
dfddbd6bf9 | ||
|
|
8a77691cb5 | ||
|
|
1dbe8b2d4b | ||
|
|
fe64f0d332 | ||
|
|
c00207aa46 | ||
|
|
65b7603192 | ||
|
|
d4bdc36062 | ||
|
|
1b55227d10 | ||
|
|
a903e19eb2 | ||
|
|
38bf73947f | ||
|
|
e4b89ba243 | ||
|
|
701e3077fb | ||
|
|
aec4d680aa | ||
|
|
06721c5fcd | ||
|
|
1ddb39e9bd | ||
|
|
15d4ca0638 | ||
|
|
85c3755f6d | ||
|
|
66ea072bc0 | ||
|
|
b0b3c21285 | ||
|
|
56088a9ead | ||
|
|
69d25d9c63 | ||
|
|
5029b8f315 | ||
|
|
0cba7bc22b | ||
|
|
fb97c50886 | ||
|
|
f1bc734dcf | ||
|
|
f71b4aae69 | ||
|
|
a834c03974 | ||
|
|
595013579c | ||
|
|
8b1bd1ae9e | ||
|
|
6ef1531059 | ||
|
|
9f1406250e | ||
|
|
1f6a892291 | ||
|
|
0ff1e279a2 | ||
|
|
c6096cc2a0 | ||
|
|
8a2ae7fc7c | ||
|
|
9de34b74cf | ||
|
|
1b5961edaa | ||
|
|
26d1aee9ad | ||
|
|
2bf09384df | ||
|
|
ac12e1a411 | ||
|
|
b367b68a43 | ||
|
|
1f9dad421f |
2
.github/workflows/ci-changed-examples.yml
vendored
2
.github/workflows/ci-changed-examples.yml
vendored
@@ -29,4 +29,4 @@ jobs:
|
||||
with:
|
||||
directory: ${{ matrix.directory }}
|
||||
cargo_make_task: "ci"
|
||||
toolchain: nightly
|
||||
toolchain: nightly-2024-01-29
|
||||
|
||||
2
.github/workflows/ci-examples.yml
vendored
2
.github/workflows/ci-examples.yml
vendored
@@ -24,4 +24,4 @@ jobs:
|
||||
with:
|
||||
directory: ${{ matrix.directory }}
|
||||
cargo_make_task: "ci"
|
||||
toolchain: nightly
|
||||
toolchain: nightly-2024-01-29
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -40,4 +40,4 @@ jobs:
|
||||
with:
|
||||
directory: ${{ matrix.directory }}
|
||||
cargo_make_task: "ci"
|
||||
toolchain: nightly
|
||||
toolchain: nightly-2024-01-29
|
||||
|
||||
@@ -31,10 +31,9 @@ jobs:
|
||||
dir_names: true
|
||||
dir_names_max_depth: "2"
|
||||
files: |
|
||||
examples
|
||||
!examples/cargo-make
|
||||
!examples/gtk
|
||||
!examples/hackernews_js_fetch
|
||||
examples/**
|
||||
!examples/cargo-make/**
|
||||
!examples/gtk/**
|
||||
!examples/Makefile.toml
|
||||
!examples/*.md
|
||||
json: true
|
||||
|
||||
4
.github/workflows/get-example-changed.yml
vendored
4
.github/workflows/get-example-changed.yml
vendored
@@ -25,8 +25,8 @@ jobs:
|
||||
with:
|
||||
files: |
|
||||
examples/**
|
||||
!examples/cargo-make
|
||||
!examples/gtk
|
||||
!examples/cargo-make/**
|
||||
!examples/gtk/**
|
||||
!examples/Makefile.toml
|
||||
!examples/*.md
|
||||
|
||||
|
||||
9
.github/workflows/run-cargo-make-task.yml
vendored
9
.github/workflows/run-cargo-make-task.yml
vendored
@@ -55,9 +55,9 @@ jobs:
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: pnpm/action-setup@v3
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
@@ -107,6 +107,11 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Install Deno
|
||||
uses: denoland/setup-deno@v1
|
||||
with:
|
||||
deno-version: v1.x
|
||||
|
||||
# Run Cargo Make Task
|
||||
- name: ${{ inputs.cargo_make_task }}
|
||||
run: |
|
||||
|
||||
27
Cargo.toml
27
Cargo.toml
@@ -25,22 +25,23 @@ members = [
|
||||
exclude = ["benchmarks", "examples"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.6.0-rc1"
|
||||
version = "0.6.9"
|
||||
rust-version = "1.75"
|
||||
|
||||
[workspace.dependencies]
|
||||
leptos = { path = "./leptos", version = "0.6.0-rc1" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.6.0-rc1" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.6.0-rc1" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.6.0-rc1" }
|
||||
leptos_reactive = { path = "./leptos_reactive", version = "0.6.0-rc1" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.6.0-rc1" }
|
||||
server_fn = { path = "./server_fn", version = "0.6.0-rc1" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.6.0-rc1" }
|
||||
leptos = { path = "./leptos", version = "0.6.9" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.6.9" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.6.9" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.6.9" }
|
||||
leptos_reactive = { path = "./leptos_reactive", version = "0.6.9" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.6.9" }
|
||||
server_fn = { path = "./server_fn", version = "0.6.9" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.6.9" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.6" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.6.0-rc1" }
|
||||
leptos_router = { path = "./router", version = "0.6.0-rc1" }
|
||||
leptos_meta = { path = "./meta", version = "0.6.0-rc1" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.6.0-rc1" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.6.9" }
|
||||
leptos_router = { path = "./router", version = "0.6.9" }
|
||||
leptos_meta = { path = "./meta", version = "0.6.9" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.6.9" }
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
||||
@@ -150,7 +150,7 @@ There are several people in the community using Leptos right now for internal ap
|
||||
|
||||
### Can I use this for native GUI?
|
||||
|
||||
Sure! Obviously the `view` macro is for generating DOM nodes but you can use the reactive system to drive native any GUI toolkit that uses the same kind of object-oriented, event-callback-based framework as the DOM pretty easily. The principles are the same:
|
||||
Sure! Obviously the `view` macro is for generating DOM nodes but you can use the reactive system to drive any native GUI toolkit that uses the same kind of object-oriented, event-callback-based framework as the DOM pretty easily. The principles are the same:
|
||||
|
||||
- Use signals, derived signals, and memos to create your reactive system
|
||||
- Create GUI widgets
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "benchmarks"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
l0410 = { package = "leptos", version = "0.4.10", features = [
|
||||
|
||||
@@ -3,5 +3,5 @@ alias = "check-all"
|
||||
|
||||
[tasks.check-all]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "check-all-features"]
|
||||
args = ["+nightly-2024-01-29", "check-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
@@ -3,5 +3,5 @@ alias = "test-all"
|
||||
|
||||
[tasks.test-all]
|
||||
command = "cargo"
|
||||
args = ["+nightly", "test-all-features"]
|
||||
args = ["+nightly-2024-01-29", "test-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
@@ -51,103 +51,5 @@ echo "CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = $examples"
|
||||
|
||||
[tasks.test-report]
|
||||
workspace = false
|
||||
description = "report web testing technology used by examples - OPTION: [all]"
|
||||
script = '''
|
||||
set -emu
|
||||
|
||||
BOLD="\e[1m"
|
||||
GREEN="\e[0;32m"
|
||||
ITALIC="\e[3m"
|
||||
YELLOW="\e[0;33m"
|
||||
RESET="\e[0m"
|
||||
|
||||
echo
|
||||
echo "${YELLOW}Web Test Technology${RESET}"
|
||||
echo
|
||||
|
||||
makefile_paths=$(find . -name Makefile.toml -not -path '*/target/*' -not -path '*/node_modules/*' |
|
||||
sed 's%./%%' |
|
||||
sed 's%/Makefile.toml%%' |
|
||||
grep -v Makefile.toml |
|
||||
sort -u)
|
||||
|
||||
start_path=$(pwd)
|
||||
|
||||
for path in $makefile_paths; do
|
||||
cd $path
|
||||
|
||||
crate_symbols=
|
||||
|
||||
pw_count=$(find . -name playwright.config.ts | wc -l)
|
||||
|
||||
while read -r line; do
|
||||
case $line in
|
||||
*"cucumber"*)
|
||||
crate_symbols=$crate_symbols"C"
|
||||
;;
|
||||
*"fantoccini"*)
|
||||
crate_symbols=$crate_symbols"D"
|
||||
;;
|
||||
esac
|
||||
done <"./Cargo.toml"
|
||||
|
||||
while read -r line; do
|
||||
case $line in
|
||||
*"cargo-make/wasm-test.toml"*)
|
||||
crate_symbols=$crate_symbols"W"
|
||||
;;
|
||||
*"cargo-make/playwright-test.toml"*)
|
||||
crate_symbols=$crate_symbols"P"
|
||||
crate_symbols=$crate_symbols"N"
|
||||
;;
|
||||
*"cargo-make/playwright-trunk-test.toml"*)
|
||||
crate_symbols=$crate_symbols"P"
|
||||
crate_symbols=$crate_symbols"T"
|
||||
;;
|
||||
*"cargo-make/trunk_server.toml"*)
|
||||
crate_symbols=$crate_symbols"T"
|
||||
;;
|
||||
*"cargo-make/cargo-leptos-webdriver-test.toml"*)
|
||||
crate_symbols=$crate_symbols"L"
|
||||
;;
|
||||
*"cargo-make/cargo-leptos-test.toml"*)
|
||||
crate_symbols=$crate_symbols"L"
|
||||
if [ $pw_count -gt 0 ]; then
|
||||
crate_symbols=$crate_symbols"P"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done <"./Makefile.toml"
|
||||
|
||||
# Sort list of tools
|
||||
sorted_crate_symbols=$(echo ${crate_symbols} | grep -o . | sort | tr -d "\n")
|
||||
|
||||
formatted_crate_symbols=" ➤ ${BOLD}${YELLOW}${sorted_crate_symbols}${RESET}"
|
||||
crate_line=$path
|
||||
if [ ! -z ${1+x} ]; then
|
||||
# Show all examples
|
||||
if [ ! -z $crate_symbols ]; then
|
||||
crate_line=$crate_line$formatted_crate_symbols
|
||||
fi
|
||||
echo $crate_line
|
||||
elif [ ! -z $crate_symbols ]; then
|
||||
# Filter out examples that do not run tests in `ci`
|
||||
crate_line=$crate_line$formatted_crate_symbols
|
||||
echo $crate_line
|
||||
fi
|
||||
|
||||
cd ${start_path}
|
||||
done
|
||||
|
||||
c="${BOLD}${YELLOW}C${RESET} = Cucumber"
|
||||
d="${BOLD}${YELLOW}D${RESET} = WebDriver"
|
||||
l="${BOLD}${YELLOW}L${RESET} = Cargo Leptos"
|
||||
n="${BOLD}${YELLOW}N${RESET} = Node"
|
||||
p="${BOLD}${YELLOW}P${RESET} = Playwright"
|
||||
t="${BOLD}${YELLOW}T${RESET} = Trunk"
|
||||
w="${BOLD}${YELLOW}W${RESET} = WASM"
|
||||
|
||||
echo
|
||||
echo "${ITALIC}Keys:${RESET} $c, $d, $l, $n, $p, $t, $w"
|
||||
echo
|
||||
'''
|
||||
description = "show the cargo-make configuration for web examples [web|all|help]"
|
||||
script = { file = "./cargo-make/scripts/web-report.sh" }
|
||||
|
||||
@@ -16,7 +16,7 @@ You can also run any of the examples using [`cargo-make`](https://github.com/sag
|
||||
|
||||
Follow these steps to get any example up and running.
|
||||
|
||||
1. `cd` to the example root directory
|
||||
1. `cd` to the example you want to run
|
||||
2. Run `cargo make ci` to setup and test the example
|
||||
3. Run `cargo make start` to run the example
|
||||
4. Open the client URL in the console output (<http://127.0.0.1:8080> or <http://127.0.0.1:3000> by default)
|
||||
|
||||
@@ -16,7 +16,7 @@ leptos = { path = "../../leptos" }
|
||||
leptos_meta = { path = "../../meta" }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -15,13 +15,13 @@ clear = true
|
||||
dependencies = ["check-debug", "check-release"]
|
||||
|
||||
[tasks.check-debug]
|
||||
toolchain = "nightly"
|
||||
toolchain = "nightly-2024-01-29"
|
||||
command = "cargo"
|
||||
args = ["check-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
[tasks.check-release]
|
||||
toolchain = "nightly"
|
||||
toolchain = "nightly-2024-01-29"
|
||||
command = "cargo"
|
||||
args = ["check-all-features", "--release"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
@@ -3,32 +3,36 @@
|
||||
[tasks.stop-client]
|
||||
condition = { env_set = ["CLIENT_PROCESS_NAME"] }
|
||||
script = '''
|
||||
if [ ! -z $(pidof ${CLIENT_PROCESS_NAME}) ]; then
|
||||
if pidof -q ${CLIENT_PROCESS_NAME}; then
|
||||
echo " Stopping ${CLIENT_PROCESS_NAME}"
|
||||
pkill -ef ${CLIENT_PROCESS_NAME}
|
||||
else
|
||||
echo " ${CLIENT_PROCESS_NAME} is already stopped"
|
||||
fi
|
||||
'''
|
||||
|
||||
[tasks.client-status]
|
||||
condition = { env_set = ["CLIENT_PROCESS_NAME"] }
|
||||
script = '''
|
||||
if [ -z $(pidof ${CLIENT_PROCESS_NAME}) ]; then
|
||||
echo " ${CLIENT_PROCESS_NAME} is not running"
|
||||
else
|
||||
if pidof -q ${CLIENT_PROCESS_NAME}; then
|
||||
echo " ${CLIENT_PROCESS_NAME} is up"
|
||||
else
|
||||
echo " ${CLIENT_PROCESS_NAME} is not running"
|
||||
fi
|
||||
'''
|
||||
|
||||
[tasks.maybe-start-client]
|
||||
condition = { env_set = ["CLIENT_PROCESS_NAME"] }
|
||||
script = '''
|
||||
if [ -z $(pidof ${CLIENT_PROCESS_NAME}) ]; then
|
||||
if pidof -q ${CLIENT_PROCESS_NAME}; then
|
||||
echo " ${CLIENT_PROCESS_NAME} is already started"
|
||||
else
|
||||
echo " Starting ${CLIENT_PROCESS_NAME}"
|
||||
if [ -z ${SPAWN_CLIENT_PROCESS} ];then
|
||||
if [ -n "${SPAWN_CLIENT_PROCESS}" ];then
|
||||
echo "Spawning process..."
|
||||
cargo make start-client ${@} &
|
||||
else
|
||||
cargo make start-client ${@}
|
||||
fi
|
||||
else
|
||||
echo " ${CLIENT_PROCESS_NAME} is already started"
|
||||
fi
|
||||
'''
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[tasks.build]
|
||||
toolchain = "nightly"
|
||||
toolchain = "nightly-2024-01-29"
|
||||
command = "cargo"
|
||||
args = ["build-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
[tasks.check]
|
||||
toolchain = "nightly"
|
||||
toolchain = "nightly-2024-01-29"
|
||||
command = "cargo"
|
||||
args = ["check-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
24
examples/cargo-make/deno-build.toml
Normal file
24
examples/cargo-make/deno-build.toml
Normal file
@@ -0,0 +1,24 @@
|
||||
[tasks.build]
|
||||
clear = true
|
||||
command = "deno"
|
||||
args = ["task", "build"]
|
||||
|
||||
[tasks.start-client]
|
||||
command = "deno"
|
||||
args = ["task", "start"]
|
||||
|
||||
[tasks.check]
|
||||
clear = true
|
||||
dependencies = ["check-debug", "check-release"]
|
||||
|
||||
[tasks.check-debug]
|
||||
toolchain = "nightly-2024-01-29"
|
||||
command = "cargo"
|
||||
args = ["check-all-features"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
[tasks.check-release]
|
||||
toolchain = "nightly-2024-01-29"
|
||||
command = "cargo"
|
||||
args = ["check-all-features", "--release"]
|
||||
install_crate = "cargo-all-features"
|
||||
@@ -1,5 +1,5 @@
|
||||
[tasks.pre-clippy]
|
||||
env = { CARGO_MAKE_CLIPPY_ARGS = "--all-targets --all-features -- -D warnings" }
|
||||
env = { CARGO_MAKE_CLIPPY_ARGS = "--no-deps --all-targets --all-features -- -D warnings" }
|
||||
|
||||
[tasks.check-style]
|
||||
dependencies = ["check-format-flow", "clippy-flow"]
|
||||
|
||||
@@ -6,9 +6,17 @@ extend = [
|
||||
[tasks.integration-test]
|
||||
description = "Run integration test with automated start and stop of processes"
|
||||
env = { SPAWN_CLIENT_PROCESS = "1" }
|
||||
dependencies = ["start", "wait-one", "test-playwright", "stop"]
|
||||
run_task = { name = ["start", "wait-test-stop"], parallel = true }
|
||||
|
||||
[tasks.wait-one]
|
||||
[tasks.wait-test-stop]
|
||||
private = true
|
||||
dependencies = ["wait-server", "test-playwright", "stop"]
|
||||
|
||||
[tasks.wait-server]
|
||||
script = '''
|
||||
sleep 1
|
||||
for run in {1..12}; do
|
||||
echo "Waiting to ensure server is started..."
|
||||
sleep 10
|
||||
done
|
||||
echo "Times up, running tests"
|
||||
'''
|
||||
|
||||
176
examples/cargo-make/scripts/web-report.sh
Executable file
176
examples/cargo-make/scripts/web-report.sh
Executable file
@@ -0,0 +1,176 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -emu
|
||||
|
||||
BOLD="\e[1m"
|
||||
ITALIC="\e[3m"
|
||||
YELLOW="\e[1;33m"
|
||||
BLUE="\e[1;36m"
|
||||
RESET="\e[0m"
|
||||
|
||||
function web { #task: only include examples with web cargo-make configuration
|
||||
print_header
|
||||
print_crate_tags "$@"
|
||||
print_footer
|
||||
}
|
||||
|
||||
function all { #task: includes all examples
|
||||
print_header
|
||||
print_crate_tags "all"
|
||||
print_footer
|
||||
}
|
||||
|
||||
function print_header {
|
||||
echo -e "${YELLOW}Cargo Make Web Report${RESET}"
|
||||
echo
|
||||
echo -e "${ITALIC}Show how crates are configured to run and test web examples with cargo-make${RESET}"
|
||||
echo
|
||||
}
|
||||
|
||||
function print_crate_tags {
|
||||
local makefile_paths
|
||||
makefile_paths=$(find_makefile_lines)
|
||||
|
||||
local start_path
|
||||
start_path=$(pwd)
|
||||
|
||||
for path in $makefile_paths; do
|
||||
cd "$path"
|
||||
|
||||
local crate_tags=
|
||||
|
||||
# Add cargo tags
|
||||
while read -r line; do
|
||||
case $line in
|
||||
*"cucumber"*)
|
||||
crate_tags=$crate_tags"C"
|
||||
;;
|
||||
*"fantoccini"*)
|
||||
crate_tags=$crate_tags"F"
|
||||
;;
|
||||
*"package.metadata.leptos"*)
|
||||
crate_tags=$crate_tags"M"
|
||||
;;
|
||||
esac
|
||||
done <"./Cargo.toml"
|
||||
|
||||
#Add makefile tags
|
||||
|
||||
local pw_count
|
||||
pw_count=$(find . -name playwright.config.ts | wc -l)
|
||||
|
||||
while read -r line; do
|
||||
case $line in
|
||||
*"cargo-make/wasm-test.toml"*)
|
||||
crate_tags=$crate_tags"W"
|
||||
;;
|
||||
*"cargo-make/playwright-test.toml"*)
|
||||
crate_tags=$crate_tags"P"
|
||||
crate_tags=$crate_tags"N"
|
||||
;;
|
||||
*"cargo-make/playwright-trunk-test.toml"*)
|
||||
crate_tags=$crate_tags"P"
|
||||
crate_tags=$crate_tags"T"
|
||||
;;
|
||||
*"cargo-make/trunk_server.toml"*)
|
||||
crate_tags=$crate_tags"T"
|
||||
;;
|
||||
*"cargo-make/cargo-leptos-webdriver-test.toml"*)
|
||||
crate_tags=$crate_tags"L"
|
||||
;;
|
||||
*"cargo-make/cargo-leptos-test.toml"*)
|
||||
crate_tags=$crate_tags"L"
|
||||
if [ "$pw_count" -gt 0 ]; then
|
||||
crate_tags=$crate_tags"P"
|
||||
fi
|
||||
;;
|
||||
*"cargo-make/cargo-leptos.toml"*)
|
||||
crate_tags=$crate_tags"L"
|
||||
;;
|
||||
*"cargo-make/deno-build.toml"*)
|
||||
crate_tags=$crate_tags"D"
|
||||
;;
|
||||
esac
|
||||
done <"./Makefile.toml"
|
||||
|
||||
# Sort tags
|
||||
local keys
|
||||
keys=$(echo "$crate_tags" | grep -o . | sort | tr -d "\n")
|
||||
|
||||
# Find leptos projects that are not configured to build with cargo-leptos
|
||||
keys=${keys//"LM"/"L"}
|
||||
|
||||
# Find leptos projects that are not configured to build with deno
|
||||
keys=${keys//"DM"/"D"}
|
||||
|
||||
# Maybe print line
|
||||
local crate_line=$path
|
||||
|
||||
if [ -n "$crate_tags" ]; then
|
||||
local color=$YELLOW
|
||||
case $keys in
|
||||
*"M"*)
|
||||
color=$BLUE
|
||||
;;
|
||||
esac
|
||||
|
||||
crate_line="$crate_line ➤ ${color}$keys${RESET}"
|
||||
echo -e "$crate_line"
|
||||
elif [ "$#" -gt 0 ]; then
|
||||
crate_line="${BOLD}$crate_line${RESET}"
|
||||
echo -e "$crate_line"
|
||||
fi
|
||||
|
||||
cd "$start_path"
|
||||
done
|
||||
}
|
||||
|
||||
function find_makefile_lines {
|
||||
find . -name Makefile.toml -not -path '*/target/*' -not -path '*/node_modules/*' |
|
||||
sed 's%./%%' |
|
||||
sed 's%/Makefile.toml%%' |
|
||||
grep -v Makefile.toml |
|
||||
sort -u
|
||||
}
|
||||
|
||||
function print_footer {
|
||||
c="${BOLD}${YELLOW}C${RESET} = Cucumber Test Runner"
|
||||
d="${BOLD}${YELLOW}D${RESET} = Deno"
|
||||
f="${BOLD}${YELLOW}F${RESET} = Fantoccini WebDriver"
|
||||
l="${BOLD}${YELLOW}L${RESET} = Cargo Leptos"
|
||||
m="${BOLD}${BLUE}M${RESET} = Cargo Leptos Metadata Only (${ITALIC}ci is not configured to build with cargo-leptos or deno${RESET})"
|
||||
n="${BOLD}${YELLOW}N${RESET} = Node"
|
||||
p="${BOLD}${YELLOW}P${RESET} = Playwright Test"
|
||||
t="${BOLD}${YELLOW}T${RESET} = Trunk"
|
||||
w="${BOLD}${YELLOW}W${RESET} = WASM Test"
|
||||
|
||||
echo
|
||||
echo -e "${ITALIC}Report Keys:${RESET}\n $c\n $d\n $f\n $l\n $m\n $n\n $p\n $t\n $w"
|
||||
echo
|
||||
}
|
||||
|
||||
###################
|
||||
# HELP
|
||||
###################
|
||||
|
||||
function list_help_for {
|
||||
local task=$1
|
||||
grep -E "^function.+ #$task" "$0" |
|
||||
sed 's/function/ /' |
|
||||
sed -e "s| { #$task: |~|g" |
|
||||
column -s"~" -t |
|
||||
sort
|
||||
}
|
||||
|
||||
function help { #help: show task descriptions
|
||||
echo -e "${BOLD}Usage:${RESET} ./$(basename "$0") <task> [options]"
|
||||
echo
|
||||
echo "Show the cargo-make configuration for web examples"
|
||||
echo
|
||||
echo -e "${BOLD}Tasks:${RESET}"
|
||||
list_help_for task
|
||||
echo
|
||||
}
|
||||
|
||||
TIMEFORMAT="./web-report.sh completed in %3lR"
|
||||
time "${@:-all}" # Show the report by default
|
||||
@@ -3,18 +3,21 @@
|
||||
[tasks.stop-server]
|
||||
condition = { env_set = ["SERVER_PROCESS_NAME"] }
|
||||
script = '''
|
||||
if [ ! -z $(pidof ${SERVER_PROCESS_NAME}) ]; then
|
||||
if pidof -q ${SERVER_PROCESS_NAME}; then
|
||||
echo " Stopping ${SERVER_PROCESS_NAME}"
|
||||
pkill -ef ${SERVER_PROCESS_NAME}
|
||||
else
|
||||
echo " ${SERVER_PROCESS_NAME} is already stopped"
|
||||
fi
|
||||
'''
|
||||
|
||||
[tasks.server-status]
|
||||
condition = { env_set = ["SERVER_PROCESS_NAME"] }
|
||||
script = '''
|
||||
if [ -z $(pidof ${SERVER_PROCESS_NAME}) ]; then
|
||||
echo " ${SERVER_PROCESS_NAME} is not running"
|
||||
else
|
||||
if pidof -q ${SERVER_PROCESS_NAME}; then
|
||||
echo " ${SERVER_PROCESS_NAME} is up"
|
||||
else
|
||||
echo " ${SERVER_PROCESS_NAME} is not running"
|
||||
fi
|
||||
'''
|
||||
|
||||
@@ -24,11 +27,11 @@ script = '''
|
||||
YELLOW="\e[0;33m"
|
||||
RESET="\e[0m"
|
||||
|
||||
if [ -z $(pidof ${SERVER_PROCESS_NAME}) ]; then
|
||||
if pidof -q ${SERVER_PROCESS_NAME}; then
|
||||
echo " ${SERVER_PROCESS_NAME} is already started"
|
||||
else
|
||||
echo " Starting ${SERVER_PROCESS_NAME}"
|
||||
echo " ${YELLOW}>> Run cargo make stop to end process${RESET}"
|
||||
cargo make start-server ${@} &
|
||||
else
|
||||
echo " ${SERVER_PROCESS_NAME} is already started"
|
||||
fi
|
||||
'''
|
||||
|
||||
@@ -6,25 +6,33 @@ script = '''
|
||||
RESET="\e[0m"
|
||||
|
||||
if command -v chromedriver; then
|
||||
if [ -z $(pidof chromedriver) ]; then
|
||||
if pidof -q chromedriver; then
|
||||
echo " chromedriver is already started"
|
||||
else
|
||||
echo "Starting chomedriver"
|
||||
chromedriver --port=4444 &
|
||||
fi
|
||||
else
|
||||
echo "${RED}${BOLD}ERROR${RESET} - chromedriver is required by this task"
|
||||
echo "${RED}${BOLD}ERROR${RESET} - chromedriver not found"
|
||||
exit 1
|
||||
fi
|
||||
'''
|
||||
|
||||
[tasks.stop-webdriver]
|
||||
script = '''
|
||||
pkill -f "chromedriver"
|
||||
if pidof -q chromedriver; then
|
||||
echo " Stopping chromedriver"
|
||||
pkill -ef "chromedriver"
|
||||
else
|
||||
echo " chromedriver is already stopped"
|
||||
fi
|
||||
'''
|
||||
|
||||
[tasks.webdriver-status]
|
||||
script = '''
|
||||
if [ -z $(pidof chromedriver) ]; then
|
||||
echo chromedriver is not running
|
||||
else
|
||||
if pidof -q chromedriver; then
|
||||
echo chromedriver is up
|
||||
else
|
||||
echo chromedriver is not running
|
||||
fi
|
||||
'''
|
||||
|
||||
@@ -14,6 +14,6 @@ log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
web-sys = "0.3"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -25,7 +25,7 @@ leptos_router = { path = "../../router" }
|
||||
log = "0.4"
|
||||
once_cell = "1.18"
|
||||
gloo-net = { git = "https://github.com/rustwasm/gloo" }
|
||||
wasm-bindgen = "0.2.87"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
simple_logger = "4.3"
|
||||
tracing = { version = "0.1", optional = true }
|
||||
@@ -69,7 +69,7 @@ reload-port = 3001
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -132,15 +132,6 @@ pub fn Counter() -> impl IntoView {
|
||||
|_| get_server_count(),
|
||||
);
|
||||
|
||||
let value =
|
||||
move || counter.get().map(|count| count.unwrap_or(0)).unwrap_or(0);
|
||||
let error_msg = move || {
|
||||
counter.get().and_then(|res| match res {
|
||||
Ok(_) => None,
|
||||
Err(e) => Some(e),
|
||||
})
|
||||
};
|
||||
|
||||
view! {
|
||||
<div>
|
||||
<h2>"Simple Counter"</h2>
|
||||
@@ -150,15 +141,24 @@ pub fn Counter() -> impl IntoView {
|
||||
<div>
|
||||
<button on:click=move |_| clear.dispatch(())>"Clear"</button>
|
||||
<button on:click=move |_| dec.dispatch(())>"-1"</button>
|
||||
<span>"Value: " {value} "!"</span>
|
||||
<span>
|
||||
"Value: "
|
||||
<Suspense>
|
||||
{move || counter.and_then(|count| *count)} "!"
|
||||
</Suspense>
|
||||
</span>
|
||||
<button on:click=move |_| inc.dispatch(())>"+1"</button>
|
||||
</div>
|
||||
{move || {
|
||||
error_msg()
|
||||
.map(|msg| {
|
||||
view! { <p>"Error: " {msg.to_string()}</p> }
|
||||
})
|
||||
}}
|
||||
<Suspense>
|
||||
{move || {
|
||||
counter.get().and_then(|res| match res {
|
||||
Ok(_) => None,
|
||||
Err(e) => Some(e),
|
||||
}).map(|msg| {
|
||||
view! { <p>"Error: " {msg.to_string()}</p> }
|
||||
})
|
||||
}}
|
||||
</Suspense>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,7 @@ pub fn FormCounter() -> impl IntoView {
|
||||
<input type="hidden" name="msg" value="form value down"/>
|
||||
<input type="submit" value="-1"/>
|
||||
</ActionForm>
|
||||
<span>"Value: " {move || value().to_string()} "!"</span>
|
||||
<span>"Value: " <Suspense>{move || value().to_string()} "!"</Suspense></span>
|
||||
<ActionForm action=adjust>
|
||||
<input type="hidden" name="delta" value="1"/>
|
||||
<input type="hidden" name="msg" value="form value up"/>
|
||||
|
||||
@@ -15,6 +15,6 @@ log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
web-sys = "0.3"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "counter_without_macros"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.75"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
||||
@@ -4,12 +4,12 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
log = "0.4"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
web-sys = "0.3"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "counters_stable"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.75"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr"] }
|
||||
@@ -11,7 +12,7 @@ console_log = "1"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen = "0.2.87"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
wasm-bindgen-test = "0.3.37"
|
||||
pretty_assertions = "1.4.0"
|
||||
|
||||
|
||||
@@ -12,6 +12,6 @@ web-sys = { version = "0.3", features = ["Clipboard", "Navigator"] }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
web-sys = "0.3"
|
||||
gloo-timers = { version = "0.3", features = ["futures"] }
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use leptos::{ev::click, html::AnyElement, *};
|
||||
|
||||
// no extra parameter
|
||||
pub fn highlight(el: HtmlElement<AnyElement>) {
|
||||
let mut highlighted = false;
|
||||
|
||||
@@ -14,6 +15,7 @@ pub fn highlight(el: HtmlElement<AnyElement>) {
|
||||
});
|
||||
}
|
||||
|
||||
// one extra parameter
|
||||
pub fn copy_to_clipboard(el: HtmlElement<AnyElement>, content: &str) {
|
||||
let content = content.to_string();
|
||||
|
||||
@@ -31,6 +33,35 @@ pub fn copy_to_clipboard(el: HtmlElement<AnyElement>, content: &str) {
|
||||
});
|
||||
}
|
||||
|
||||
// custom parameter
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Amount(usize);
|
||||
|
||||
impl From<usize> for Amount {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
// a 'default' value if no value is passed in
|
||||
impl From<()> for Amount {
|
||||
fn from(_: ()) -> Self {
|
||||
Self(1)
|
||||
}
|
||||
}
|
||||
|
||||
// .into() will automatically be called on the parameter
|
||||
pub fn add_dot(el: HtmlElement<AnyElement>, amount: Amount) {
|
||||
_ = el.clone().on(click, move |_| {
|
||||
el.set_inner_text(&format!(
|
||||
"{}{}",
|
||||
el.inner_text(),
|
||||
".".repeat(amount.0)
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn SomeComponent() -> impl IntoView {
|
||||
view! {
|
||||
@@ -46,6 +77,11 @@ pub fn App() -> impl IntoView {
|
||||
|
||||
view! {
|
||||
<a href="#" use:copy_to_clipboard=data>"Copy \"" {data} "\" to clipboard"</a>
|
||||
// automatically applies the directive to every root element in `SomeComponent`
|
||||
<SomeComponent use:highlight />
|
||||
// no value will default to `().into()`
|
||||
<button use:add_dot>"Add a dot"</button>
|
||||
// `5.into()` automatically called
|
||||
<button use:add_dot=5>"Add 5 dots"</button>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ See the [Examples README](../README.md) for setup and run instructions.
|
||||
|
||||
## Testing
|
||||
|
||||
This project is configured to run start and stop of processes for integration tests wihtout the use of Cargo Leptos or Node.
|
||||
This project is configured to run start and stop of processes for integration tests without the use of Cargo Leptos or Node.
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -22,7 +22,7 @@ tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||
tokio = { version = "1", features = ["full"], optional = true }
|
||||
http = { version = "1.0" }
|
||||
thiserror = "1.0"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
@@ -61,7 +61,7 @@ reload-port = 3001
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
[env]
|
||||
VERIFY_GTK = false
|
||||
|
||||
[tasks.verify-flow]
|
||||
condition = { env_set = ["VERIFY_GTK"] }
|
||||
|
||||
[tasks.verify]
|
||||
condition = { env_set = ["VERIFY_GTK"] }
|
||||
@@ -25,7 +25,7 @@ gloo-net = { version = "0.2", features = ["http"] }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
tracing = "0.1"
|
||||
# openssl = { version = "0.10", features = ["v110"] }
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
|
||||
|
||||
[features]
|
||||
@@ -70,7 +70,7 @@ reload-port = 3001
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -62,16 +62,18 @@ pub fn Stories() -> impl IntoView {
|
||||
}}
|
||||
</span>
|
||||
<span>"page " {page}</span>
|
||||
<span class="page-link"
|
||||
class:disabled=hide_more_link
|
||||
aria-hidden=hide_more_link
|
||||
>
|
||||
<a href=move || format!("/{}?page={}", story_type(), page() + 1)
|
||||
aria-label="Next Page"
|
||||
<Suspense>
|
||||
<span class="page-link"
|
||||
class:disabled=hide_more_link
|
||||
aria-hidden=hide_more_link
|
||||
>
|
||||
"more >"
|
||||
</a>
|
||||
</span>
|
||||
<a href=move || format!("/{}?page={}", story_type(), page() + 1)
|
||||
aria-label="Next Page"
|
||||
>
|
||||
"more >"
|
||||
</a>
|
||||
</span>
|
||||
</Suspense>
|
||||
</div>
|
||||
<main class="news-list">
|
||||
<div>
|
||||
|
||||
@@ -29,7 +29,7 @@ tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||
tokio = { version = "1", features = ["full"], optional = true }
|
||||
http = { version = "1.0", optional = true }
|
||||
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
|
||||
[features]
|
||||
default = ["csr"]
|
||||
@@ -71,7 +71,7 @@ reload-port = 3001
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -37,7 +37,7 @@ tower-http = { version = "0.5", features = [
|
||||
tokio = { version = "1", features = ["full"], optional = true }
|
||||
http = { version = "1.0", optional = true }
|
||||
web-sys = { version = "0.3", features = ["AbortController", "AbortSignal"] }
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
[features]
|
||||
@@ -81,7 +81,7 @@ reload-port = 3001
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
extend = [{ path = "../cargo-make/main.toml" }]
|
||||
extend = [
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/cargo-leptos.toml" },
|
||||
]
|
||||
|
||||
[env]
|
||||
|
||||
CLIENT_PROCESS_NAME = "hackernews_islands"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -33,7 +33,7 @@ web-sys = { version = "0.3", features = [
|
||||
"Request",
|
||||
"Response",
|
||||
] }
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
wasm-bindgen-futures = { version = "0.4.37", features = [
|
||||
"futures-core-03-stream",
|
||||
], optional = true }
|
||||
@@ -78,7 +78,7 @@ reload-port = 3001
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
extend = [{ path = "../cargo-make/main.toml" }]
|
||||
extend = [
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/deno-build.toml" },
|
||||
]
|
||||
|
||||
[env]
|
||||
|
||||
CLIENT_PROCESS_NAME = "deno"
|
||||
|
||||
@@ -8,7 +8,11 @@ codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly", "template_macro"] }
|
||||
leptos = { path = "../../leptos", features = [
|
||||
"csr",
|
||||
"nightly",
|
||||
"template_macro",
|
||||
] }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
# used in rand, but we need to enable js feature
|
||||
@@ -17,6 +21,6 @@ rand = { version = "0.8.5", features = ["small_rng"] }
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
web-sys = "0.3"
|
||||
|
||||
@@ -5,13 +5,13 @@ extend = [
|
||||
]
|
||||
|
||||
[tasks.build]
|
||||
toolchain = "nightly"
|
||||
toolchain = "nightly-2024-01-29"
|
||||
command = "cargo"
|
||||
args = ["build-all-features", "--target", "wasm32-unknown-unknown"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
[tasks.check]
|
||||
toolchain = "nightly"
|
||||
toolchain = "nightly-2024-01-29"
|
||||
command = "cargo"
|
||||
args = ["check-all-features", "--target", "wasm32-unknown-unknown"]
|
||||
install_crate = "cargo-all-features"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -11,6 +11,6 @@ console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
web-sys = "0.3"
|
||||
gloo-timers = { version = "0.3", features = ["futures"] }
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -15,22 +15,33 @@ leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_meta = { path = "../../meta", features = ["nightly"] }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
server_fn = { path = "../../server_fn", features = ["serde-lite", "rkyv", "multipart" ]}
|
||||
server_fn = { path = "../../server_fn", features = [
|
||||
"serde-lite",
|
||||
"rkyv",
|
||||
"multipart",
|
||||
] }
|
||||
log = "0.4"
|
||||
simple_logger = "4.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
axum = { version = "0.7", optional = true }
|
||||
tower = { version = "0.4", optional = true }
|
||||
tower-http = { version = "0.5", features = ["fs", "tracing", "trace"], optional = true }
|
||||
tower-http = { version = "0.5", features = [
|
||||
"fs",
|
||||
"tracing",
|
||||
"trace",
|
||||
], optional = true }
|
||||
tokio = { version = "1", features = ["full"], optional = true }
|
||||
thiserror = "1.0"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
serde_toml = "0.0.1"
|
||||
toml = "0.8.8"
|
||||
web-sys = { version = "0.3.67", features = ["FileList", "File"] }
|
||||
strum = { version = "0.25.0", features = ["strum_macros", "derive"] }
|
||||
notify = { version = "6.1.1", optional = true }
|
||||
pin-project-lite = "0.2.13"
|
||||
dashmap = { version = "5.5.3", optional = true }
|
||||
once_cell = { version = "1.19.0", optional = true }
|
||||
async-broadcast = { version = "0.6.0", optional = true }
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
@@ -43,7 +54,10 @@ ssr = [
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
"dep:leptos_axum",
|
||||
"dep:notify"
|
||||
"dep:notify",
|
||||
"dep:dashmap",
|
||||
"dep:once_cell",
|
||||
"dep:async-broadcast",
|
||||
]
|
||||
|
||||
[package.metadata.cargo-all-features]
|
||||
@@ -71,7 +85,7 @@ end2end-cmd = "cargo make test-ui"
|
||||
end2end-dir = "e2e"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -5,13 +5,15 @@ use leptos_meta::{provide_meta_context, Link, Meta, Stylesheet};
|
||||
use leptos_router::{ActionForm, Route, Router, Routes};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use server_fn::{
|
||||
client::{browser::BrowserClient, Client},
|
||||
codec::{
|
||||
Encoding, FromReq, FromRes, GetUrl, IntoReq, IntoRes, MultipartData,
|
||||
MultipartFormData, Rkyv, SerdeLite, StreamingText, TextStream,
|
||||
},
|
||||
request::{ClientReq, Req},
|
||||
response::{ClientRes, Res},
|
||||
request::{browser::BrowserRequest, ClientReq, Req},
|
||||
response::{browser::BrowserResponse, ClientRes, Res},
|
||||
};
|
||||
use std::future::Future;
|
||||
#[cfg(feature = "ssr")]
|
||||
use std::sync::{
|
||||
atomic::{AtomicU8, Ordering},
|
||||
@@ -55,8 +57,10 @@ pub fn HomePage() -> impl IntoView {
|
||||
<ServerFnArgumentExample/>
|
||||
<RkyvExample/>
|
||||
<FileUpload/>
|
||||
<FileUploadWithProgress/>
|
||||
<FileWatcher/>
|
||||
<CustomEncoding/>
|
||||
<CustomClientExample/>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +320,7 @@ pub fn RkyvExample() -> impl IntoView {
|
||||
set_input(value);
|
||||
}
|
||||
>
|
||||
Click to see length
|
||||
Click to capitalize
|
||||
</button>
|
||||
<p>{input}</p>
|
||||
<Transition>
|
||||
@@ -331,8 +335,8 @@ pub fn FileUpload() -> impl IntoView {
|
||||
///
|
||||
/// On the server, this uses the `multer` crate, which provides a streaming API.
|
||||
#[server(
|
||||
input = MultipartFormData,
|
||||
)]
|
||||
input = MultipartFormData,
|
||||
)]
|
||||
pub async fn file_length(
|
||||
data: MultipartData,
|
||||
) -> Result<usize, ServerFnError> {
|
||||
@@ -390,6 +394,168 @@ pub fn FileUpload() -> impl IntoView {
|
||||
}
|
||||
}
|
||||
|
||||
/// This component uses server functions to upload a file, while streaming updates on the upload
|
||||
/// progress.
|
||||
#[component]
|
||||
pub fn FileUploadWithProgress() -> impl IntoView {
|
||||
/// In theory, you could create a single server function which
|
||||
/// 1) received multipart form data
|
||||
/// 2) returned a stream that contained updates on the progress
|
||||
///
|
||||
/// In reality, browsers do not actually support duplexing requests in this way. In other
|
||||
/// words, every existing browser actually requires that the request stream be complete before
|
||||
/// it begins processing the response stream.
|
||||
///
|
||||
/// Instead, we can create two separate server functions:
|
||||
/// 1) one that receives multipart form data and begins processing the upload
|
||||
/// 2) a second that returns a stream of updates on the progress
|
||||
///
|
||||
/// This requires us to store some global state of all the uploads. In a real app, you probably
|
||||
/// shouldn't do exactly what I'm doing here in the demo. For example, this map just
|
||||
/// distinguishes between files by filename, not by user.
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
mod progress {
|
||||
use async_broadcast::{broadcast, Receiver, Sender};
|
||||
use dashmap::DashMap;
|
||||
use futures::Stream;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
struct File {
|
||||
total: usize,
|
||||
tx: Sender<usize>,
|
||||
rx: Receiver<usize>,
|
||||
}
|
||||
|
||||
static FILES: Lazy<DashMap<String, File>> = Lazy::new(DashMap::new);
|
||||
|
||||
pub async fn add_chunk(filename: &str, len: usize) {
|
||||
println!("[{filename}]\tadding {len}");
|
||||
let mut entry =
|
||||
FILES.entry(filename.to_string()).or_insert_with(|| {
|
||||
println!("[{filename}]\tinserting channel");
|
||||
let (tx, rx) = broadcast(128);
|
||||
File { total: 0, tx, rx }
|
||||
});
|
||||
entry.total += len;
|
||||
let new_total = entry.total;
|
||||
|
||||
// we're about to do an async broadcast, so we don't want to hold a lock across it
|
||||
let tx = entry.tx.clone();
|
||||
drop(entry);
|
||||
|
||||
// now we send the message and don't have to worry about it
|
||||
tx.broadcast(new_total)
|
||||
.await
|
||||
.expect("couldn't send a message over channel");
|
||||
}
|
||||
|
||||
pub fn for_file(filename: &str) -> impl Stream<Item = usize> {
|
||||
let entry =
|
||||
FILES.entry(filename.to_string()).or_insert_with(|| {
|
||||
println!("[{filename}]\tinserting channel");
|
||||
let (tx, rx) = broadcast(128);
|
||||
File { total: 0, tx, rx }
|
||||
});
|
||||
entry.rx.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[server(
|
||||
input = MultipartFormData,
|
||||
)]
|
||||
pub async fn upload_file(data: MultipartData) -> Result<(), ServerFnError> {
|
||||
let mut data = data.into_inner().unwrap();
|
||||
|
||||
while let Ok(Some(mut field)) = data.next_field().await {
|
||||
let name =
|
||||
field.file_name().expect("no filename on field").to_string();
|
||||
while let Ok(Some(chunk)) = field.chunk().await {
|
||||
let len = chunk.len();
|
||||
println!("[{name}]\t{len}");
|
||||
progress::add_chunk(&name, len).await;
|
||||
// in a real server function, you'd do something like saving the file here
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[server(output = StreamingText)]
|
||||
pub async fn file_progress(
|
||||
filename: String,
|
||||
) -> Result<TextStream, ServerFnError> {
|
||||
println!("getting progress on {filename}");
|
||||
// get the stream of current length for the file
|
||||
let progress = progress::for_file(&filename);
|
||||
// separate each number with a newline
|
||||
// the HTTP response might pack multiple lines of this into a single chunk
|
||||
// we need some way of dividing them up
|
||||
let progress = progress.map(|bytes| Ok(format!("{bytes}\n")));
|
||||
Ok(TextStream::new(progress))
|
||||
}
|
||||
|
||||
let (filename, set_filename) = create_signal(None);
|
||||
let (max, set_max) = create_signal(None);
|
||||
let (current, set_current) = create_signal(None);
|
||||
let on_submit = move |ev: SubmitEvent| {
|
||||
ev.prevent_default();
|
||||
let target = ev.target().unwrap().unchecked_into::<HtmlFormElement>();
|
||||
let form_data = FormData::new_with_form(&target).unwrap();
|
||||
let file = form_data
|
||||
.get("file_to_upload")
|
||||
.unchecked_into::<web_sys::File>();
|
||||
let filename = file.name();
|
||||
let size = file.size() as usize;
|
||||
set_filename(Some(filename.clone()));
|
||||
set_max(Some(size));
|
||||
set_current(None::<usize>);
|
||||
|
||||
spawn_local(async move {
|
||||
let mut progress = file_progress(filename)
|
||||
.await
|
||||
.expect("couldn't initialize stream")
|
||||
.into_inner();
|
||||
while let Some(Ok(len)) = progress.next().await {
|
||||
// the TextStream from the server function will be a series of `usize` values
|
||||
// however, the response itself may pack those chunks into a smaller number of
|
||||
// chunks, each with more text in it
|
||||
// so we've padded them with newspace, and will split them out here
|
||||
// each value is the latest total, so we'll just take the last one
|
||||
let len = len
|
||||
.split('\n')
|
||||
.filter(|n| !n.is_empty())
|
||||
.last()
|
||||
.expect(
|
||||
"expected at least one non-empty value from \
|
||||
newline-delimited rows",
|
||||
)
|
||||
.parse::<usize>()
|
||||
.expect("invalid length");
|
||||
set_current(Some(len));
|
||||
}
|
||||
});
|
||||
spawn_local(async move {
|
||||
upload_file(form_data.into())
|
||||
.await
|
||||
.expect("couldn't upload file");
|
||||
});
|
||||
};
|
||||
|
||||
view! {
|
||||
<h3>File Upload with Progress</h3>
|
||||
<p>A file upload with progress can be handled with two separate server functions.</p>
|
||||
<aside>See the doc comment on the component for an explanation.</aside>
|
||||
<form on:submit=on_submit>
|
||||
<input type="file" name="file_to_upload"/>
|
||||
<input type="submit"/>
|
||||
</form>
|
||||
{move || filename().map(|filename| view! { <p>Uploading {filename}</p> })}
|
||||
{move || max().map(|max| view! {
|
||||
<progress max=max value=move || current().unwrap_or_default()/>
|
||||
})}
|
||||
}
|
||||
}
|
||||
#[component]
|
||||
pub fn FileWatcher() -> impl IntoView {
|
||||
#[server(input = GetUrl, output = StreamingText)]
|
||||
@@ -632,3 +798,55 @@ pub fn CustomEncoding() -> impl IntoView {
|
||||
<p>{result}</p>
|
||||
}
|
||||
}
|
||||
|
||||
/// Middleware lets you modify the request/response on the server.
|
||||
///
|
||||
/// On the client, you might also want to modify the request. For example, you may need to add a
|
||||
/// custom header for authentication on every request. You can do this by creating a "custom
|
||||
/// client."
|
||||
#[component]
|
||||
pub fn CustomClientExample() -> impl IntoView {
|
||||
// Define a type for our client.
|
||||
pub struct CustomClient;
|
||||
|
||||
// Implement the `Client` trait for it.
|
||||
impl<CustErr> Client<CustErr> for CustomClient {
|
||||
// BrowserRequest and BrowserResponse are the defaults used by other server functions.
|
||||
// They are wrappers for the underlying Web Fetch API types.
|
||||
type Request = BrowserRequest;
|
||||
type Response = BrowserResponse;
|
||||
|
||||
// Our custom `send()` implementation does all the work.
|
||||
fn send(
|
||||
req: Self::Request,
|
||||
) -> impl Future<Output = Result<Self::Response, ServerFnError<CustErr>>>
|
||||
+ Send {
|
||||
// BrowserRequest derefs to the underlying Request type from gloo-net,
|
||||
// so we can get access to the headers here
|
||||
let headers = req.headers();
|
||||
// modify the headers by appending one
|
||||
headers.append("X-Custom-Header", "foobar");
|
||||
// delegate back out to BrowserClient to send the modified request
|
||||
BrowserClient::send(req)
|
||||
}
|
||||
}
|
||||
|
||||
// Specify our custom client with `client = `
|
||||
#[server(client = CustomClient)]
|
||||
pub async fn fn_with_custom_client() -> Result<(), ServerFnError> {
|
||||
use http::header::HeaderMap;
|
||||
use leptos_axum::extract;
|
||||
|
||||
let headers: HeaderMap = extract().await?;
|
||||
let custom_header = headers.get("X-Custom-Header");
|
||||
println!("X-Custom-Header = {custom_header:?}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
view! {
|
||||
<h3>Custom clients</h3>
|
||||
<p>You can define a custom server function client to do something like adding a header to every request.</p>
|
||||
<p>Check the network request in your browser devtools to see how this client adds a custom header.</p>
|
||||
<button on:click=|_| spawn_local(async { fn_with_custom_client().await.unwrap() })>Click me</button>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
log = "0.4"
|
||||
simple_logger = "4.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
axum = { version = "0.7", optional = true, features=["macros"] }
|
||||
axum = { version = "0.7", optional = true, features = ["macros"] }
|
||||
tower = { version = "0.4", optional = true }
|
||||
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||
tokio = { version = "1", features = ["full"], optional = true }
|
||||
@@ -29,11 +29,11 @@ sqlx = { version = "0.7.2", features = [
|
||||
"sqlite",
|
||||
], optional = true }
|
||||
thiserror = "1.0"
|
||||
wasm-bindgen = "0.2"
|
||||
axum_session_auth = { version = "0.10", features = [
|
||||
wasm-bindgen = "=0.2.92"
|
||||
axum_session_auth = { version = "0.12.1", features = [
|
||||
"sqlite-rustls",
|
||||
], optional = true }
|
||||
axum_session = { version = "0.10", features = [
|
||||
axum_session = { version = "0.12.4", features = [
|
||||
"sqlite-rustls",
|
||||
], optional = true }
|
||||
bcrypt = { version = "0.15", optional = true }
|
||||
@@ -83,7 +83,7 @@ reload-port = 3001
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -51,7 +51,7 @@ pub mod ssr {
|
||||
.await
|
||||
.ok()?;
|
||||
|
||||
//lets just get all the tokens the user can use, we will only use the full permissions if modifing them.
|
||||
//lets just get all the tokens the user can use, we will only use the full permissions if modifying them.
|
||||
let sql_user_perms = sqlx::query_as::<_, SqlPermissionTokens>(
|
||||
"SELECT token FROM user_permissions WHERE user_id = ?;",
|
||||
)
|
||||
@@ -75,7 +75,7 @@ pub mod ssr {
|
||||
.await
|
||||
.ok()?;
|
||||
|
||||
//lets just get all the tokens the user can use, we will only use the full permissions if modifing them.
|
||||
//lets just get all the tokens the user can use, we will only use the full permissions if modifying them.
|
||||
let sql_user_perms = sqlx::query_as::<_, SqlPermissionTokens>(
|
||||
"SELECT token FROM user_permissions WHERE user_id = ?;",
|
||||
)
|
||||
|
||||
@@ -70,7 +70,7 @@ async fn main() {
|
||||
SessionConfig::default().with_table_name("axum_sessions");
|
||||
let auth_config = AuthConfig::<i64>::default();
|
||||
let session_store = SessionStore::<SessionSqlitePool>::new(
|
||||
Some(pool.clone().into()),
|
||||
Some(SessionSqlitePool::from(pool.clone())),
|
||||
session_config,
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use leptos::*;
|
||||
|
||||
// Slots are created in simillar manner to components, except that they use the #[slot] macro.
|
||||
// Slots are created in similar manner to components, except that they use the #[slot] macro.
|
||||
#[slot]
|
||||
struct Then {
|
||||
children: ChildrenFn,
|
||||
|
||||
@@ -31,7 +31,7 @@ sqlx = { version = "0.7", features = [
|
||||
"sqlite",
|
||||
], optional = true }
|
||||
thiserror = "1.0.38"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
axum_session_auth = { version = "0.12", features = [
|
||||
"sqlite-rustls",
|
||||
], optional = true }
|
||||
@@ -86,7 +86,7 @@ reload-port = 3001
|
||||
end2end-cmd = "npx playwright test"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -47,7 +47,7 @@ pub mod ssr_imports {
|
||||
.await
|
||||
.ok()?;
|
||||
|
||||
//lets just get all the tokens the user can use, we will only use the full permissions if modifing them.
|
||||
//lets just get all the tokens the user can use, we will only use the full permissions if modifying them.
|
||||
let sql_user_perms = sqlx::query_as::<_, SqlPermissionTokens>(
|
||||
"SELECT token FROM user_permissions WHERE user_id = ?;",
|
||||
)
|
||||
@@ -71,7 +71,7 @@ pub mod ssr_imports {
|
||||
.await
|
||||
.ok()?;
|
||||
|
||||
//lets just get all the tokens the user can use, we will only use the full permissions if modifing them.
|
||||
//lets just get all the tokens the user can use, we will only use the full permissions if modifying them.
|
||||
let sql_user_perms = sqlx::query_as::<_, SqlPermissionTokens>(
|
||||
"SELECT token FROM user_permissions WHERE user_id = ?;",
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ log = "0.4"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
thiserror = "1"
|
||||
tokio = { version = "1", features = ["time"] }
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -9,12 +9,13 @@ use thiserror::Error;
|
||||
pub fn App() -> impl IntoView {
|
||||
// Provides context that manages stylesheets, titles, meta tags, etc.
|
||||
provide_meta_context();
|
||||
let fallback = || view! { "Page not found." }.into_view();
|
||||
|
||||
view! {
|
||||
<Stylesheet id="leptos" href="/pkg/ssr_modes.css"/>
|
||||
<Title text="Welcome to Leptos"/>
|
||||
|
||||
<Router>
|
||||
<Router fallback>
|
||||
<main>
|
||||
<Routes>
|
||||
// We’ll load the home page with out-of-order streaming and <Suspense/>
|
||||
|
||||
@@ -20,8 +20,12 @@ thiserror = "1"
|
||||
axum = { version = "0.7", optional = true }
|
||||
tower = { version = "0.4", optional = true }
|
||||
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "macros", "time"], optional = true }
|
||||
wasm-bindgen = "0.2"
|
||||
tokio = { version = "1", features = [
|
||||
"rt-multi-thread",
|
||||
"macros",
|
||||
"time",
|
||||
], optional = true }
|
||||
wasm-bindgen = "=0.2.92"
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -9,12 +9,13 @@ use thiserror::Error;
|
||||
pub fn App() -> impl IntoView {
|
||||
// Provides context that manages stylesheets, titles, meta tags, etc.
|
||||
provide_meta_context();
|
||||
let fallback = || view! { "Page not found." }.into_view();
|
||||
|
||||
view! {
|
||||
<Stylesheet id="leptos" href="/pkg/ssr_modes.css"/>
|
||||
<Title text="Welcome to Leptos"/>
|
||||
|
||||
<Router>
|
||||
<Router fallback>
|
||||
<main>
|
||||
<Routes>
|
||||
// We’ll load the home page with out-of-order streaming and <Suspense/>
|
||||
|
||||
@@ -16,7 +16,7 @@ leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
log = "0.4"
|
||||
simple_logger = "4"
|
||||
wasm-bindgen = "0.2.87"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
serde = "1.0.159"
|
||||
tokio = { version = "1.29", features = ["time", "rt"], optional = true }
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["nightly"] }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
@@ -17,12 +16,12 @@ leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
gloo-net = { version = "0.2", features = ["http"] }
|
||||
log = "0.4"
|
||||
|
||||
# dependecies for client (enable when csr or hydrate set)
|
||||
wasm-bindgen = { version = "0.2", optional = true }
|
||||
# dependencies for client (enable when csr or hydrate set)
|
||||
wasm-bindgen = { version = "=0.2.92", optional = true }
|
||||
console_log = { version = "1", optional = true }
|
||||
console_error_panic_hook = { version = "0.1", optional = true }
|
||||
|
||||
# dependecies for server (enable when ssr set)
|
||||
# dependencies for server (enable when ssr set)
|
||||
actix-files = { version = "0.6", optional = true }
|
||||
actix-web = { version = "4", features = ["macros"], optional = true }
|
||||
futures = { version = "0.3", optional = true }
|
||||
@@ -97,7 +96,7 @@ 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 tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -16,10 +16,13 @@ leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_router = { path = "../../router", features = ["nightly"] }
|
||||
log = "0.4.17"
|
||||
simple_logger = "4"
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "macros"], optional = true }
|
||||
tokio = { version = "1", features = [
|
||||
"rt-multi-thread",
|
||||
"macros",
|
||||
], optional = true }
|
||||
tower = { version = "0.4", optional = true }
|
||||
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
thiserror = "1.0"
|
||||
tracing = { version = "0.1", optional = true }
|
||||
http = "1.0"
|
||||
@@ -44,7 +47,7 @@ skip_feature_sets = [["ssr", "hydrate"]]
|
||||
|
||||
[package.metadata.leptos]
|
||||
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
|
||||
output-name = "tailwind_axum"
|
||||
output-name = "leptos_tailwind"
|
||||
# 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Leptos with Axum + TailwindCSS Tempate
|
||||
# Leptos with Axum + TailwindCSS Template
|
||||
|
||||
This is a template demonstrating how to integrate [TailwindCSS](https://tailwindcss.com/) with the [Leptos](https://github.com/leptos-rs/leptos) web framework, Axum server, and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool.
|
||||
|
||||
|
||||
18
examples/tailwind_axum/package-lock.json
generated
18
examples/tailwind_axum/package-lock.json
generated
@@ -9,7 +9,6 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"preline": "^1.8.0",
|
||||
"tailwindcss": "^3.3.2"
|
||||
}
|
||||
},
|
||||
@@ -104,15 +103,6 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/any-promise": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||
@@ -699,14 +689,6 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||
},
|
||||
"node_modules/preline": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/preline/-/preline-1.8.0.tgz",
|
||||
"integrity": "sha512-guttn86Fc/+AbvN9oKcr2z3zU7DL3Q5dl7nhcR4nTi5F02LXQc7WIYwgIXMR97kymCs52feiju6glXO3dUIpvA==",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.2"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -7,8 +7,7 @@ pub fn App() -> impl IntoView {
|
||||
provide_meta_context();
|
||||
|
||||
view! {
|
||||
|
||||
<Stylesheet id="leptos" href="/pkg/tailwind_axum.css"/>
|
||||
<Stylesheet id="leptos" href="/pkg/leptos_tailwind.css"/>
|
||||
<Link rel="shortcut icon" type_="image/ico" href="/favicon.ico"/>
|
||||
<Router>
|
||||
<Routes>
|
||||
|
||||
@@ -10,9 +10,7 @@ leptos_router = { path = "../../router", features = ["csr", "nightly"] }
|
||||
log = "0.4"
|
||||
gloo-net = { version = "0.2", features = ["http"] }
|
||||
|
||||
|
||||
# dependecies for client (enable when csr or hydrate set)
|
||||
wasm-bindgen = { version = "0.2" }
|
||||
console_log = { version = "1"}
|
||||
console_error_panic_hook = { version = "0.1"}
|
||||
|
||||
# dependencies for client (enable when csr or hydrate set)
|
||||
wasm-bindgen = { version = "=0.2.92" }
|
||||
console_log = { version = "1" }
|
||||
console_error_panic_hook = { version = "0.1" }
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -8,7 +8,7 @@ pub fn App() -> impl IntoView {
|
||||
|
||||
view! {
|
||||
|
||||
<Stylesheet id="leptos" href="/pkg/tailwind.css"/>
|
||||
<Stylesheet id="leptos" href="/style/output.css"/>
|
||||
<Link rel="shortcut icon" type_="image/ico" href="/favicon.ico"/>
|
||||
<Router>
|
||||
<Routes>
|
||||
|
||||
@@ -12,13 +12,11 @@ leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3"
|
||||
features = [
|
||||
"Window",
|
||||
]
|
||||
features = ["Window"]
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -26,7 +26,7 @@ sqlx = { version = "0.6.2", features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
], optional = true }
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
tokio = { version = "1", features = ["rt", "time"], optional = true }
|
||||
|
||||
[features]
|
||||
@@ -67,7 +67,7 @@ end2end-cmd = "cargo make test-ui"
|
||||
end2end-dir = "e2e"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -28,7 +28,7 @@ sqlx = { version = "0.7", features = [
|
||||
"sqlite",
|
||||
], optional = true }
|
||||
thiserror = "1.0"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
|
||||
[features]
|
||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
||||
@@ -69,7 +69,7 @@ end2end-cmd = "cargo make test-ui"
|
||||
end2end-dir = "e2e"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -28,7 +28,7 @@ sqlx = { version = "0.7", features = [
|
||||
"sqlite",
|
||||
], optional = true }
|
||||
thiserror = "1.0"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen = "=0.2.92"
|
||||
|
||||
[features]
|
||||
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
|
||||
@@ -70,7 +70,7 @@ end2end-cmd = "cargo make test-ui"
|
||||
end2end-dir = "e2e"
|
||||
# The browserlist query used for optimizing the CSS.
|
||||
browserquery = "defaults"
|
||||
# Set by cargo-leptos watch when building with tha tool. Controls whether autoreload JS will be included in the head
|
||||
# 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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
||||
channel = "nightly-2024-01-29"
|
||||
|
||||
@@ -7,9 +7,8 @@ pub struct Todos(pub Vec<Todo>);
|
||||
|
||||
const STORAGE_KEY: &str = "todos-leptos";
|
||||
|
||||
// Basic operations to manipulate the todo list: nothing really interesting here
|
||||
impl Todos {
|
||||
pub fn new() -> Self {
|
||||
impl Default for Todos {
|
||||
fn default() -> Self {
|
||||
let starting_todos =
|
||||
window()
|
||||
.local_storage()
|
||||
@@ -23,7 +22,10 @@ impl Todos {
|
||||
.unwrap_or_default();
|
||||
Self(starting_todos)
|
||||
}
|
||||
}
|
||||
|
||||
// Basic operations to manipulate the todo list: nothing really interesting here
|
||||
impl Todos {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
@@ -86,12 +88,6 @@ impl Todos {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Todos {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||
pub struct Todo {
|
||||
pub id: Uuid,
|
||||
@@ -136,7 +132,7 @@ const ENTER_KEY: u32 = 13;
|
||||
#[component]
|
||||
pub fn TodoMVC() -> impl IntoView {
|
||||
// The `todos` are a signal, since we need to reactively update the list
|
||||
let (todos, set_todos) = create_signal(Todos::new());
|
||||
let (todos, set_todos) = create_signal(Todos::default());
|
||||
|
||||
// We provide a context that each <Todo/> component can use to update the list
|
||||
// Here, I'm just passing the `WriteSignal`; a <Todo/> doesn't need to read the whole list
|
||||
|
||||
@@ -6,6 +6,7 @@ authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
description = "Actix integrations for the Leptos web framework."
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
actix-http = "3"
|
||||
|
||||
@@ -150,14 +150,6 @@ pub fn redirect(path: &str) {
|
||||
to redirect()."
|
||||
);
|
||||
}
|
||||
if let Some(response_options) = use_context::<ResponseOptions>() {
|
||||
response_options.set_status(StatusCode::FOUND);
|
||||
response_options.insert_header(
|
||||
header::LOCATION,
|
||||
header::HeaderValue::from_str(path)
|
||||
.expect("Failed to create HeaderValue"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// An Actix [struct@Route](actix_web::Route) that listens for a `POST` request with
|
||||
@@ -211,7 +203,7 @@ pub fn handle_server_fns() -> Route {
|
||||
/// context, allowing you to pass in info about the route or user from Actix, or other info.
|
||||
///
|
||||
/// **NOTE**: If your server functions expect a context, make sure to provide it both in
|
||||
/// [`handle_server_fns_with_context`] **and** in [`leptos_routes_with_context`] (or whatever
|
||||
/// [`handle_server_fns_with_context`] **and** in [`LeptosRoutes::leptos_routes_with_context`] (or whatever
|
||||
/// rendering method you are using). During SSR, server functions are called by the rendering
|
||||
/// method, while subsequent calls from the client are handled by the server function handler.
|
||||
/// The same context needs to be provided to both handlers.
|
||||
@@ -1223,13 +1215,18 @@ where
|
||||
let mode = listing.mode();
|
||||
|
||||
for method in listing.methods() {
|
||||
let additional_context = additional_context.clone();
|
||||
let additional_context_and_method = move || {
|
||||
provide_context(method);
|
||||
additional_context();
|
||||
};
|
||||
router = if let Some(static_mode) = listing.static_mode() {
|
||||
router.route(
|
||||
path,
|
||||
static_route(
|
||||
options.clone(),
|
||||
app_fn.clone(),
|
||||
additional_context.clone(),
|
||||
additional_context_and_method.clone(),
|
||||
method,
|
||||
static_mode,
|
||||
),
|
||||
@@ -1241,7 +1238,7 @@ where
|
||||
SsrMode::OutOfOrder => {
|
||||
render_app_to_stream_with_context(
|
||||
options.clone(),
|
||||
additional_context.clone(),
|
||||
additional_context_and_method.clone(),
|
||||
app_fn.clone(),
|
||||
method,
|
||||
)
|
||||
@@ -1249,7 +1246,7 @@ where
|
||||
SsrMode::PartiallyBlocked => {
|
||||
render_app_to_stream_with_context_and_replace_blocks(
|
||||
options.clone(),
|
||||
additional_context.clone(),
|
||||
additional_context_and_method.clone(),
|
||||
app_fn.clone(),
|
||||
method,
|
||||
true,
|
||||
@@ -1258,14 +1255,14 @@ where
|
||||
SsrMode::InOrder => {
|
||||
render_app_to_stream_in_order_with_context(
|
||||
options.clone(),
|
||||
additional_context.clone(),
|
||||
additional_context_and_method.clone(),
|
||||
app_fn.clone(),
|
||||
method,
|
||||
)
|
||||
}
|
||||
SsrMode::Async => render_app_async_with_context(
|
||||
options.clone(),
|
||||
additional_context.clone(),
|
||||
additional_context_and_method.clone(),
|
||||
app_fn.clone(),
|
||||
method,
|
||||
),
|
||||
@@ -1369,7 +1366,7 @@ impl LeptosRoutes for &mut ServiceConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper to make it easier to use Axum extractors in server functions.
|
||||
/// A helper to make it easier to use Actix extractors in server functions.
|
||||
///
|
||||
/// It is generic over some type `T` that implements [`FromRequest`] and can
|
||||
/// therefore be used in an extractor. The compiler can often infer this type.
|
||||
@@ -1390,15 +1387,13 @@ impl LeptosRoutes for &mut ServiceConfig {
|
||||
/// Ok(data)
|
||||
/// }
|
||||
/// ```
|
||||
pub async fn extract<T, CustErr>() -> Result<T, ServerFnError<CustErr>>
|
||||
pub async fn extract<T>() -> Result<T, ServerFnError>
|
||||
where
|
||||
T: actix_web::FromRequest,
|
||||
<T as FromRequest>::Error: Display,
|
||||
{
|
||||
let req = use_context::<HttpRequest>().ok_or_else(|| {
|
||||
ServerFnError::ServerError(
|
||||
"HttpRequest should have been provided via context".to_string(),
|
||||
)
|
||||
ServerFnError::new("HttpRequest should have been provided via context")
|
||||
})?;
|
||||
|
||||
T::extract(&req)
|
||||
|
||||
148
integrations/actix/tests/extract_routes.rs
Normal file
148
integrations/actix/tests/extract_routes.rs
Normal file
@@ -0,0 +1,148 @@
|
||||
use leptos::*;
|
||||
use leptos_actix::generate_route_list;
|
||||
use leptos_router::{Route, Router, Routes, TrailingSlash};
|
||||
|
||||
#[component]
|
||||
fn DefaultApp() -> impl IntoView {
|
||||
let view = || view! { "" };
|
||||
view! {
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/foo" view/>
|
||||
<Route path="/bar/" view/>
|
||||
<Route path="/baz/:id" view/>
|
||||
<Route path="/baz/:name/" view/>
|
||||
<Route path="/baz/*any" view/>
|
||||
</Routes>
|
||||
</Router>
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_app() {
|
||||
let routes = generate_route_list(DefaultApp);
|
||||
|
||||
// We still have access to the original (albeit normalized) Leptos paths:
|
||||
assert_same(
|
||||
&routes,
|
||||
|r| r.leptos_path(),
|
||||
&["/bar", "/baz/*any", "/baz/:id", "/baz/:name", "/foo"],
|
||||
);
|
||||
|
||||
// ... But leptos-actix has also reformatted "paths" to work for Actix.
|
||||
assert_same(
|
||||
&routes,
|
||||
|r| r.path(),
|
||||
&["/bar", "/baz/{id}", "/baz/{name}", "/baz/{tail:.*}", "/foo"],
|
||||
);
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn ExactApp() -> impl IntoView {
|
||||
let view = || view! { "" };
|
||||
let trailing_slash = TrailingSlash::Exact;
|
||||
view! {
|
||||
<Router trailing_slash>
|
||||
<Routes>
|
||||
<Route path="/foo" view/>
|
||||
<Route path="/bar/" view/>
|
||||
<Route path="/baz/:id" view/>
|
||||
<Route path="/baz/:name/" view/>
|
||||
<Route path="/baz/*any" view/>
|
||||
</Routes>
|
||||
</Router>
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exact_app() {
|
||||
let routes = generate_route_list(ExactApp);
|
||||
|
||||
// In Exact mode, the Leptos paths no longer have their trailing slashes stripped:
|
||||
assert_same(
|
||||
&routes,
|
||||
|r| r.leptos_path(),
|
||||
&["/bar/", "/baz/*any", "/baz/:id", "/baz/:name/", "/foo"],
|
||||
);
|
||||
|
||||
// Actix paths also have trailing slashes as a result:
|
||||
assert_same(
|
||||
&routes,
|
||||
|r| r.path(),
|
||||
&[
|
||||
"/bar/",
|
||||
"/baz/{id}",
|
||||
"/baz/{name}/",
|
||||
"/baz/{tail:.*}",
|
||||
"/foo",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn RedirectApp() -> impl IntoView {
|
||||
let view = || view! { "" };
|
||||
let trailing_slash = TrailingSlash::Redirect;
|
||||
view! {
|
||||
<Router trailing_slash>
|
||||
<Routes>
|
||||
<Route path="/foo" view/>
|
||||
<Route path="/bar/" view/>
|
||||
<Route path="/baz/:id" view/>
|
||||
<Route path="/baz/:name/" view/>
|
||||
<Route path="/baz/*any" view/>
|
||||
</Routes>
|
||||
</Router>
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_redirect_app() {
|
||||
let routes = generate_route_list(RedirectApp);
|
||||
|
||||
assert_same(
|
||||
&routes,
|
||||
|r| r.leptos_path(),
|
||||
&[
|
||||
"/bar",
|
||||
"/bar/",
|
||||
"/baz/*any",
|
||||
"/baz/:id",
|
||||
"/baz/:id/",
|
||||
"/baz/:name",
|
||||
"/baz/:name/",
|
||||
"/foo",
|
||||
"/foo/",
|
||||
],
|
||||
);
|
||||
|
||||
// ... But leptos-actix has also reformatted "paths" to work for Actix.
|
||||
assert_same(
|
||||
&routes,
|
||||
|r| r.path(),
|
||||
&[
|
||||
"/bar",
|
||||
"/bar/",
|
||||
"/baz/{id}",
|
||||
"/baz/{id}/",
|
||||
"/baz/{name}",
|
||||
"/baz/{name}/",
|
||||
"/baz/{tail:.*}",
|
||||
"/foo",
|
||||
"/foo/",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
fn assert_same<'t, T, F, U>(
|
||||
input: &'t Vec<T>,
|
||||
mapper: F,
|
||||
expected_sorted_values: &[U],
|
||||
) where
|
||||
F: Fn(&'t T) -> U + 't,
|
||||
U: Ord + std::fmt::Debug,
|
||||
{
|
||||
let mut values: Vec<U> = input.iter().map(mapper).collect();
|
||||
values.sort();
|
||||
assert_eq!(values, expected_sorted_values);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user