From c2a2721ec6c853901a5cd98dcc8a6f4a900d78cd Mon Sep 17 00:00:00 2001
From: Matthieu Bessat
Date: Mon, 22 Jul 2024 12:07:02 +0200
Subject: [PATCH] feat: add block layout for home page with CSS
---
Cargo.lock | 421 ++---------
Cargo.toml | 3 +-
assets/styles/app.css | 0
assets/styles/simple.css | 712 ++++++++++++++++++
src/controllers.rs | 27 +-
src/main.rs | 12 +
src/templates/layouts/base.html | 15 +
src/templates/{ => pages}/home.html | 3 +
src/templates/{ => pages}/list_task_runs.html | 0
src/templates/{ => pages}/list_tasks.html | 0
src/templates/{ => pages}/run_task.html | 0
.../{ => pages}/task_run_details.html | 0
tmp/dbs/current.db | Bin 0 -> 12288 bytes
13 files changed, 842 insertions(+), 351 deletions(-)
create mode 100644 assets/styles/app.css
create mode 100644 assets/styles/simple.css
create mode 100644 src/templates/layouts/base.html
rename src/templates/{ => pages}/home.html (84%)
rename src/templates/{ => pages}/list_task_runs.html (100%)
rename src/templates/{ => pages}/list_tasks.html (100%)
rename src/templates/{ => pages}/run_task.html (100%)
rename src/templates/{ => pages}/task_run_details.html (100%)
create mode 100644 tmp/dbs/current.db
diff --git a/Cargo.lock b/Cargo.lock
index f3394d9..88a3171 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -146,18 +146,19 @@ version = "0.1.0"
dependencies = [
"anyhow",
"axum",
+ "axum-template",
"chrono",
"clap",
"env_logger",
"fully_pub",
"log",
- "minijinja",
+ "minijinja 1.0.20",
"serde",
"serde_json",
"serde_yaml",
"sqlx",
- "tera",
"tokio",
+ "tower-http",
"uuid",
]
@@ -216,6 +217,18 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "axum-template"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7013f6403ac283c62d843b344d27742a3ffb48f57a2263522b7c978cec40cc1"
+dependencies = [
+ "axum",
+ "minijinja 2.0.3",
+ "serde",
+ "thiserror",
+]
+
[[package]]
name = "backtrace"
version = "0.3.71"
@@ -267,16 +280,6 @@ dependencies = [
"generic-array",
]
-[[package]]
-name = "bstr"
-version = "1.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
-dependencies = [
- "memchr",
- "serde",
-]
-
[[package]]
name = "bumpalo"
version = "3.15.4"
@@ -322,28 +325,6 @@ dependencies = [
"windows-targets 0.52.4",
]
-[[package]]
-name = "chrono-tz"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e"
-dependencies = [
- "chrono",
- "chrono-tz-build",
- "phf",
-]
-
-[[package]]
-name = "chrono-tz-build"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f"
-dependencies = [
- "parse-zoneinfo",
- "phf",
- "phf_codegen",
-]
-
[[package]]
name = "clap"
version = "4.5.4"
@@ -413,25 +394,6 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
-[[package]]
-name = "crossbeam-deque"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
-dependencies = [
- "crossbeam-epoch",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
-dependencies = [
- "crossbeam-utils",
-]
-
[[package]]
name = "crossbeam-queue"
version = "0.3.11"
@@ -468,12 +430,6 @@ dependencies = [
"zeroize",
]
-[[package]]
-name = "deunicode"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94"
-
[[package]]
name = "digest"
version = "0.10.7"
@@ -704,30 +660,6 @@ version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
-[[package]]
-name = "globset"
-version = "0.4.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
-dependencies = [
- "aho-corasick",
- "bstr",
- "log",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "globwalk"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
-dependencies = [
- "bitflags 1.3.2",
- "ignore",
- "walkdir",
-]
-
[[package]]
name = "hashbrown"
version = "0.14.3"
@@ -829,6 +761,12 @@ dependencies = [
"pin-project-lite",
]
+[[package]]
+name = "http-range-header"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a"
+
[[package]]
name = "httparse"
version = "1.8.0"
@@ -841,15 +779,6 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
-[[package]]
-name = "humansize"
-version = "2.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
-dependencies = [
- "libm",
-]
-
[[package]]
name = "humantime"
version = "2.1.0"
@@ -924,22 +853,6 @@ dependencies = [
"unicode-normalization",
]
-[[package]]
-name = "ignore"
-version = "0.4.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
-dependencies = [
- "crossbeam-deque",
- "globset",
- "log",
- "memchr",
- "regex-automata",
- "same-file",
- "walkdir",
- "winapi-util",
-]
-
[[package]]
name = "indexmap"
version = "2.2.6"
@@ -1056,6 +969,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+[[package]]
+name = "mime_guess"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
[[package]]
name = "minijinja"
version = "1.0.20"
@@ -1065,6 +988,15 @@ dependencies = [
"serde",
]
+[[package]]
+name = "minijinja"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "933ee10775d58fca8238a84fe165dfe4bde8b07d7574f24d76ffea91170f3ac6"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -1196,15 +1128,6 @@ dependencies = [
"windows-targets 0.48.5",
]
-[[package]]
-name = "parse-zoneinfo"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41"
-dependencies = [
- "regex",
-]
-
[[package]]
name = "paste"
version = "1.0.14"
@@ -1226,89 +1149,6 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
-[[package]]
-name = "pest"
-version = "2.7.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95"
-dependencies = [
- "memchr",
- "thiserror",
- "ucd-trie",
-]
-
-[[package]]
-name = "pest_derive"
-version = "2.7.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c"
-dependencies = [
- "pest",
- "pest_generator",
-]
-
-[[package]]
-name = "pest_generator"
-version = "2.7.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd"
-dependencies = [
- "pest",
- "pest_meta",
- "proc-macro2",
- "quote",
- "syn 2.0.58",
-]
-
-[[package]]
-name = "pest_meta"
-version = "2.7.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca"
-dependencies = [
- "once_cell",
- "pest",
- "sha2",
-]
-
-[[package]]
-name = "phf"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
-dependencies = [
- "phf_shared",
-]
-
-[[package]]
-name = "phf_codegen"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
-dependencies = [
- "phf_generator",
- "phf_shared",
-]
-
-[[package]]
-name = "phf_generator"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
-dependencies = [
- "phf_shared",
- "rand",
-]
-
-[[package]]
-name = "phf_shared"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
-dependencies = [
- "siphasher",
-]
-
[[package]]
name = "pin-project"
version = "1.1.5"
@@ -1511,15 +1351,6 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
-[[package]]
-name = "same-file"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
-dependencies = [
- "winapi-util",
-]
-
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -1633,12 +1464,6 @@ dependencies = [
"rand_core",
]
-[[package]]
-name = "siphasher"
-version = "0.3.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
-
[[package]]
name = "slab"
version = "0.4.9"
@@ -1648,16 +1473,6 @@ dependencies = [
"autocfg",
]
-[[package]]
-name = "slug"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bd94acec9c8da640005f8e135a39fc0372e74535e6b368b7a04b875f784c8c4"
-dependencies = [
- "deunicode",
- "wasm-bindgen",
-]
-
[[package]]
name = "smallvec"
version = "1.13.2"
@@ -1977,28 +1792,6 @@ dependencies = [
"windows-sys 0.52.0",
]
-[[package]]
-name = "tera"
-version = "1.19.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "970dff17c11e884a4a09bc76e3a17ef71e01bb13447a11e85226e254fe6d10b8"
-dependencies = [
- "chrono",
- "chrono-tz",
- "globwalk",
- "humansize",
- "lazy_static",
- "percent-encoding",
- "pest",
- "pest_derive",
- "rand",
- "regex",
- "serde",
- "serde_json",
- "slug",
- "unic-segment",
-]
-
[[package]]
name = "thiserror"
version = "1.0.58"
@@ -2075,6 +1868,19 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "tokio-util"
+version = "0.7.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
[[package]]
name = "tower"
version = "0.4.13"
@@ -2091,6 +1897,31 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "tower-http"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
+dependencies = [
+ "bitflags 2.5.0",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "http-range-header",
+ "httpdate",
+ "mime",
+ "mime_guess",
+ "percent-encoding",
+ "pin-project-lite",
+ "tokio",
+ "tokio-util",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
[[package]]
name = "tower-layer"
version = "0.3.2"
@@ -2142,59 +1973,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
-name = "ucd-trie"
-version = "0.1.6"
+name = "unicase"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
-
-[[package]]
-name = "unic-char-property"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
+checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
dependencies = [
- "unic-char-range",
-]
-
-[[package]]
-name = "unic-char-range"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
-
-[[package]]
-name = "unic-common"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
-
-[[package]]
-name = "unic-segment"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23"
-dependencies = [
- "unic-ucd-segment",
-]
-
-[[package]]
-name = "unic-ucd-segment"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700"
-dependencies = [
- "unic-char-property",
- "unic-char-range",
- "unic-ucd-version",
-]
-
-[[package]]
-name = "unic-ucd-version"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
-dependencies = [
- "unic-common",
+ "version_check",
]
[[package]]
@@ -2281,16 +2065,6 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-[[package]]
-name = "walkdir"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
-dependencies = [
- "same-file",
- "winapi-util",
-]
-
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@@ -2367,37 +2141,6 @@ dependencies = [
"wasite",
]
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-util"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
[[package]]
name = "windows-core"
version = "0.52.0"
diff --git a/Cargo.toml b/Cargo.toml
index 21096a9..5f43a6e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,7 +11,6 @@ chrono = { version = "0.4.26", features = ["serde"] }
sqlx = { version = "0.7.4", features = ["sqlite", "runtime-tokio", "chrono"] }
anyhow = "1.0.75"
clap = "4.5.4"
-tera = "1.19.1"
tokio = { version = "1.37.0", features = ["full"] }
axum = { version = "0.7.5", features = ["json"] }
minijinja = { version = "1.0.20", features = ["builtins"] }
@@ -19,4 +18,6 @@ uuid = { version = "1.8.0", features = ["serde", "v4"] }
fully_pub = "0.1.4"
log = "0.4.22"
env_logger = "0.11.3"
+tower-http = { version = "0.5.2", features = ["fs"] }
+axum-template = { version = "2.3.0", features = ["minijinja"] }
diff --git a/assets/styles/app.css b/assets/styles/app.css
new file mode 100644
index 0000000..e69de29
diff --git a/assets/styles/simple.css b/assets/styles/simple.css
new file mode 100644
index 0000000..6addf12
--- /dev/null
+++ b/assets/styles/simple.css
@@ -0,0 +1,712 @@
+/* Global variables. */
+:root,
+::backdrop {
+ /* Set sans-serif & mono fonts */
+ --sans-font: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir,
+ "Nimbus Sans L", Roboto, "Noto Sans", "Segoe UI", Arial, Helvetica,
+ "Helvetica Neue", sans-serif;
+ --mono-font: Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
+ --standard-border-radius: 5px;
+
+ /* Default (light) theme */
+ --bg: #fff;
+ --accent-bg: #f5f7ff;
+ --text: #212121;
+ --text-light: #585858;
+ --border: #898EA4;
+ --accent: #0d47a1;
+ --accent-hover: #1266e2;
+ --accent-text: var(--bg);
+ --code: #d81b60;
+ --preformatted: #444;
+ --marked: #ffdd33;
+ --disabled: #efefef;
+}
+
+/* Dark theme */
+@media (prefers-color-scheme: dark) {
+ :root,
+ ::backdrop {
+ color-scheme: dark;
+ --bg: #212121;
+ --accent-bg: #2b2b2b;
+ --text: #dcdcdc;
+ --text-light: #ababab;
+ --accent: #ffb300;
+ --accent-hover: #ffe099;
+ --accent-text: var(--bg);
+ --code: #f06292;
+ --preformatted: #ccc;
+ --disabled: #111;
+ }
+ /* Add a bit of transparency so light media isn't so glaring in dark mode */
+ img,
+ video {
+ opacity: 0.8;
+ }
+}
+
+/* Reset box-sizing */
+*, *::before, *::after {
+ box-sizing: border-box;
+}
+
+/* Reset default appearance */
+textarea,
+select,
+input,
+progress {
+ appearance: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+}
+
+html {
+ /* Set the font globally */
+ font-family: var(--sans-font);
+ scroll-behavior: smooth;
+}
+
+/* Make the body a nice central block */
+body {
+ color: var(--text);
+ background-color: var(--bg);
+ font-size: 1.15rem;
+ line-height: 1.5;
+ display: grid;
+ grid-template-columns: 1fr min(45rem, 90%) 1fr;
+ margin: 0;
+}
+body > * {
+ grid-column: 2;
+}
+
+/* Make the header bg full width, but the content inline with body */
+body > header {
+ background-color: var(--accent-bg);
+ border-bottom: 1px solid var(--border);
+ text-align: center;
+ padding: 0 0.5rem 2rem 0.5rem;
+ grid-column: 1 / -1;
+}
+
+body > header > *:only-child {
+ margin-block-start: 2rem;
+}
+
+body > header h1 {
+ max-width: 1200px;
+ margin: 1rem auto;
+}
+
+body > header p {
+ max-width: 40rem;
+ margin: 1rem auto;
+}
+
+/* Add a little padding to ensure spacing is correct between content and header > nav */
+main {
+ padding-top: 1.5rem;
+}
+
+body > footer {
+ margin-top: 4rem;
+ padding: 2rem 1rem 1.5rem 1rem;
+ color: var(--text-light);
+ font-size: 0.9rem;
+ text-align: center;
+ border-top: 1px solid var(--border);
+}
+
+/* Format headers */
+h1 {
+ font-size: 3rem;
+}
+
+h2 {
+ font-size: 2.6rem;
+ margin-top: 3rem;
+}
+
+h3 {
+ font-size: 2rem;
+ margin-top: 3rem;
+}
+
+h4 {
+ font-size: 1.44rem;
+}
+
+h5 {
+ font-size: 1.15rem;
+}
+
+h6 {
+ font-size: 0.96rem;
+}
+
+p {
+ margin: 1.5rem 0;
+}
+
+/* Prevent long strings from overflowing container */
+p, h1, h2, h3, h4, h5, h6 {
+ overflow-wrap: break-word;
+}
+
+/* Fix line height when title wraps */
+h1,
+h2,
+h3 {
+ line-height: 1.1;
+}
+
+/* Reduce header size on mobile */
+@media only screen and (max-width: 720px) {
+ h1 {
+ font-size: 2.5rem;
+ }
+
+ h2 {
+ font-size: 2.1rem;
+ }
+
+ h3 {
+ font-size: 1.75rem;
+ }
+
+ h4 {
+ font-size: 1.25rem;
+ }
+}
+
+/* Format links & buttons */
+a,
+a:visited {
+ color: var(--accent);
+}
+
+a:hover {
+ text-decoration: none;
+}
+
+button,
+.button,
+a.button, /* extra specificity to override a */
+input[type="submit"],
+input[type="reset"],
+input[type="button"],
+label[type="button"] {
+ border: 1px solid var(--accent);
+ background-color: var(--accent);
+ color: var(--accent-text);
+ padding: 0.5rem 0.9rem;
+ text-decoration: none;
+ line-height: normal;
+}
+
+.button[aria-disabled="true"],
+input:disabled,
+textarea:disabled,
+select:disabled,
+button[disabled] {
+ cursor: not-allowed;
+ background-color: var(--disabled);
+ border-color: var(--disabled);
+ color: var(--text-light);
+}
+
+input[type="range"] {
+ padding: 0;
+}
+
+/* Set the cursor to '?' on an abbreviation and style the abbreviation to show that there is more information underneath */
+abbr[title] {
+ cursor: help;
+ text-decoration-line: underline;
+ text-decoration-style: dotted;
+}
+
+button:enabled:hover,
+.button:not([aria-disabled="true"]):hover,
+input[type="submit"]:enabled:hover,
+input[type="reset"]:enabled:hover,
+input[type="button"]:enabled:hover,
+label[type="button"]:hover {
+ background-color: var(--accent-hover);
+ border-color: var(--accent-hover);
+ cursor: pointer;
+}
+
+.button:focus-visible,
+button:focus-visible:where(:enabled),
+input:enabled:focus-visible:where(
+ [type="submit"],
+ [type="reset"],
+ [type="button"]
+) {
+ outline: 2px solid var(--accent);
+ outline-offset: 1px;
+}
+
+/* Format navigation */
+header > nav {
+ font-size: 1rem;
+ line-height: 2;
+ padding: 1rem 0 0 0;
+}
+
+/* Use flexbox to allow items to wrap, as needed */
+header > nav ul,
+header > nav ol {
+ align-content: space-around;
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ justify-content: center;
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+
+/* List items are inline elements, make them behave more like blocks */
+header > nav ul li,
+header > nav ol li {
+ display: inline-block;
+}
+
+header > nav a,
+header > nav a:visited {
+ margin: 0 0.5rem 1rem 0.5rem;
+ border: 1px solid var(--border);
+ border-radius: var(--standard-border-radius);
+ color: var(--text);
+ display: inline-block;
+ padding: 0.1rem 1rem;
+ text-decoration: none;
+}
+
+header > nav a:hover,
+header > nav a.current,
+header > nav a[aria-current="page"] {
+ border-color: var(--accent);
+ color: var(--accent);
+ cursor: pointer;
+}
+
+/* Reduce nav side on mobile */
+@media only screen and (max-width: 720px) {
+ header > nav a {
+ border: none;
+ padding: 0;
+ text-decoration: underline;
+ line-height: 1;
+ }
+}
+
+/* Consolidate box styling */
+aside, details, pre, progress {
+ background-color: var(--accent-bg);
+ border: 1px solid var(--border);
+ border-radius: var(--standard-border-radius);
+ margin-bottom: 1rem;
+}
+
+aside {
+ font-size: 1rem;
+ width: 30%;
+ padding: 0 15px;
+ margin-inline-start: 15px;
+ float: right;
+}
+*[dir="rtl"] aside {
+ float: left;
+}
+
+/* Make aside full-width on mobile */
+@media only screen and (max-width: 720px) {
+ aside {
+ width: 100%;
+ float: none;
+ margin-inline-start: 0;
+ }
+}
+
+article, fieldset, dialog {
+ border: 1px solid var(--border);
+ padding: 1rem;
+ border-radius: var(--standard-border-radius);
+ margin-bottom: 1rem;
+}
+
+article h2:first-child,
+section h2:first-child,
+article h3:first-child,
+section h3:first-child {
+ margin-top: 1rem;
+}
+
+section {
+ border-top: 1px solid var(--border);
+ border-bottom: 1px solid var(--border);
+ padding: 2rem 1rem;
+ margin: 3rem 0;
+}
+
+/* Don't double separators when chaining sections */
+section + section,
+section:first-child {
+ border-top: 0;
+ padding-top: 0;
+}
+
+section + section {
+ margin-top: 0;
+}
+
+section:last-child {
+ border-bottom: 0;
+ padding-bottom: 0;
+}
+
+details {
+ padding: 0.7rem 1rem;
+}
+
+summary {
+ cursor: pointer;
+ font-weight: bold;
+ padding: 0.7rem 1rem;
+ margin: -0.7rem -1rem;
+ word-break: break-all;
+}
+
+details[open] > summary + * {
+ margin-top: 0;
+}
+
+details[open] > summary {
+ margin-bottom: 0.5rem;
+}
+
+details[open] > :last-child {
+ margin-bottom: 0;
+}
+
+/* Format tables */
+table {
+ border-collapse: collapse;
+ margin: 1.5rem 0;
+}
+
+figure > table {
+ width: max-content;
+ margin: 0;
+}
+
+td,
+th {
+ border: 1px solid var(--border);
+ text-align: start;
+ padding: 0.5rem;
+}
+
+th {
+ background-color: var(--accent-bg);
+ font-weight: bold;
+}
+
+tr:nth-child(even) {
+ /* Set every other cell slightly darker. Improves readability. */
+ background-color: var(--accent-bg);
+}
+
+table caption {
+ font-weight: bold;
+ margin-bottom: 0.5rem;
+}
+
+/* Format forms */
+textarea,
+select,
+input,
+button,
+.button {
+ font-size: inherit;
+ font-family: inherit;
+ padding: 0.5rem;
+ margin-bottom: 0.5rem;
+ border-radius: var(--standard-border-radius);
+ box-shadow: none;
+ max-width: 100%;
+ display: inline-block;
+}
+textarea,
+select,
+input {
+ color: var(--text);
+ background-color: var(--bg);
+ border: 1px solid var(--border);
+}
+label {
+ display: block;
+}
+textarea:not([cols]) {
+ width: 100%;
+}
+
+/* Add arrow to drop-down */
+select:not([multiple]) {
+ background-image: linear-gradient(45deg, transparent 49%, var(--text) 51%),
+ linear-gradient(135deg, var(--text) 51%, transparent 49%);
+ background-position: calc(100% - 15px), calc(100% - 10px);
+ background-size: 5px 5px, 5px 5px;
+ background-repeat: no-repeat;
+ padding-inline-end: 25px;
+}
+*[dir="rtl"] select:not([multiple]) {
+ background-position: 10px, 15px;
+}
+
+/* checkbox and radio button style */
+input[type="checkbox"],
+input[type="radio"] {
+ vertical-align: middle;
+ position: relative;
+ width: min-content;
+}
+
+input[type="checkbox"] + label,
+input[type="radio"] + label {
+ display: inline-block;
+}
+
+input[type="radio"] {
+ border-radius: 100%;
+}
+
+input[type="checkbox"]:checked,
+input[type="radio"]:checked {
+ background-color: var(--accent);
+}
+
+input[type="checkbox"]:checked::after {
+ /* Creates a rectangle with colored right and bottom borders which is rotated to look like a check mark */
+ content: " ";
+ width: 0.18em;
+ height: 0.32em;
+ border-radius: 0;
+ position: absolute;
+ top: 0.05em;
+ left: 0.17em;
+ background-color: transparent;
+ border-right: solid var(--bg) 0.08em;
+ border-bottom: solid var(--bg) 0.08em;
+ font-size: 1.8em;
+ transform: rotate(45deg);
+}
+input[type="radio"]:checked::after {
+ /* creates a colored circle for the checked radio button */
+ content: " ";
+ width: 0.25em;
+ height: 0.25em;
+ border-radius: 100%;
+ position: absolute;
+ top: 0.125em;
+ background-color: var(--bg);
+ left: 0.125em;
+ font-size: 32px;
+}
+
+/* Makes input fields wider on smaller screens */
+@media only screen and (max-width: 720px) {
+ textarea,
+ select,
+ input {
+ width: 100%;
+ }
+}
+
+/* Set a height for color input */
+input[type="color"] {
+ height: 2.5rem;
+ padding: 0.2rem;
+}
+
+/* do not show border around file selector button */
+input[type="file"] {
+ border: 0;
+}
+
+/* Misc body elements */
+hr {
+ border: none;
+ height: 1px;
+ background: var(--border);
+ margin: 1rem auto;
+}
+
+mark {
+ padding: 2px 5px;
+ border-radius: var(--standard-border-radius);
+ background-color: var(--marked);
+ color: black;
+}
+
+mark a {
+ color: #0d47a1;
+}
+
+img,
+video {
+ max-width: 100%;
+ height: auto;
+ border-radius: var(--standard-border-radius);
+}
+
+figure {
+ margin: 0;
+ display: block;
+ overflow-x: auto;
+}
+
+figure > img,
+figure > picture > img {
+ display: block;
+ margin-inline: auto;
+}
+
+figcaption {
+ text-align: center;
+ font-size: 0.9rem;
+ color: var(--text-light);
+ margin-block: 1rem;
+}
+
+blockquote {
+ margin-inline-start: 2rem;
+ margin-inline-end: 0;
+ margin-block: 2rem;
+ padding: 0.4rem 0.8rem;
+ border-inline-start: 0.35rem solid var(--accent);
+ color: var(--text-light);
+ font-style: italic;
+}
+
+cite {
+ font-size: 0.9rem;
+ color: var(--text-light);
+ font-style: normal;
+}
+
+dt {
+ color: var(--text-light);
+}
+
+/* Use mono font for code elements */
+code,
+pre,
+pre span,
+kbd,
+samp {
+ font-family: var(--mono-font);
+ color: var(--code);
+}
+
+kbd {
+ color: var(--preformatted);
+ border: 1px solid var(--preformatted);
+ border-bottom: 3px solid var(--preformatted);
+ border-radius: var(--standard-border-radius);
+ padding: 0.1rem 0.4rem;
+}
+
+pre {
+ padding: 1rem 1.4rem;
+ max-width: 100%;
+ overflow: auto;
+ color: var(--preformatted);
+}
+
+/* Fix embedded code within pre */
+pre code {
+ color: var(--preformatted);
+ background: none;
+ margin: 0;
+ padding: 0;
+}
+
+/* Progress bars */
+/* Declarations are repeated because you */
+/* cannot combine vendor-specific selectors */
+progress {
+ width: 100%;
+}
+
+progress:indeterminate {
+ background-color: var(--accent-bg);
+}
+
+progress::-webkit-progress-bar {
+ border-radius: var(--standard-border-radius);
+ background-color: var(--accent-bg);
+}
+
+progress::-webkit-progress-value {
+ border-radius: var(--standard-border-radius);
+ background-color: var(--accent);
+}
+
+progress::-moz-progress-bar {
+ border-radius: var(--standard-border-radius);
+ background-color: var(--accent);
+ transition-property: width;
+ transition-duration: 0.3s;
+}
+
+progress:indeterminate::-moz-progress-bar {
+ background-color: var(--accent-bg);
+}
+
+dialog {
+ max-width: 40rem;
+ margin: auto;
+}
+
+dialog::backdrop {
+ background-color: var(--bg);
+ opacity: 0.8;
+}
+
+@media only screen and (max-width: 720px) {
+ dialog {
+ max-width: 100%;
+ margin: auto 1em;
+ }
+}
+
+/* Superscript & Subscript */
+/* Prevent scripts from affecting line-height. */
+sup, sub {
+ vertical-align: baseline;
+ position: relative;
+}
+
+sup {
+ top: -0.4em;
+}
+
+sub {
+ top: 0.3em;
+}
+
+/* Classes for notices */
+.notice {
+ background: var(--accent-bg);
+ border: 2px solid var(--border);
+ border-radius: var(--standard-border-radius);
+ padding: 1.5rem;
+ margin: 2rem 0;
+}
+
diff --git a/src/controllers.rs b/src/controllers.rs
index 97e0d83..317dcfa 100644
--- a/src/controllers.rs
+++ b/src/controllers.rs
@@ -2,23 +2,28 @@ use crate::models::{Task, TaskRun, TaskRunSummary};
use axum::extract::{Path as ExtractPath, State};
use axum::http::StatusCode;
use axum::Json;
-use axum::response::Html;
-use minijinja::render;
+use axum::response::{Html, IntoResponse, Response};
+use axum_template::RenderHtml;
+use minijinja::{context, render};
use uuid::Uuid;
use crate::models::ExecutorOrder;
-use crate::AppState;
+use crate::{AppState};
-pub async fn home() -> Html {
- Html(render!(
- include_str!("./templates/home.html"),
- ))
+pub async fn home(
+ State(app_state): State
+) -> impl IntoResponse {
+ Html(
+ app_state.template_engine.get_template("pages/home.html").unwrap()
+ .render(context!())
+ .unwrap()
+ )
}
pub async fn list_tasks(State(app_state): State) -> Html {
let tasks: Vec = app_state.config.tasks;
Html(render!(
- include_str!("./templates/list_tasks.html"),
+ include_str!("./templates/pages/list_tasks.html"),
tasks => tasks
))
}
@@ -49,7 +54,7 @@ pub async fn trigger_task(
(
StatusCode::OK,
Html(render!(
- include_str!("./templates/run_task.html"),
+ include_str!("./templates/pages/run_task.html"),
tasks => tasks
)),
)
@@ -80,7 +85,7 @@ pub async fn list_task_runs(
}
};
Html(render!(
- include_str!("./templates/list_task_runs.html"),
+ include_str!("./templates/pages/list_task_runs.html"),
task => task,
runs => runs,
))
@@ -102,7 +107,7 @@ pub async fn get_task_run(
};
Html(render!(
- include_str!("./templates/task_run_details.html"),
+ include_str!("./templates/pages/task_run_details.html"),
run => run_details
))
}
diff --git a/src/main.rs b/src/main.rs
index 18b0fc1..839ce30 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,12 +2,15 @@ mod controllers;
mod models;
mod executor;
+use axum_template::engine::Engine;
use log::info;
use anyhow::{anyhow, Context, Result};
use axum::routing::get;
use axum::Router;
+use minijinja::Environment;
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
use sqlx::{ConnectOptions, Pool, Sqlite};
+use tower_http::services::ServeDir;
use std::fs;
use std::str::FromStr;
use std::sync::Arc;
@@ -20,6 +23,7 @@ pub struct AppState {
config: Config,
db: Pool,
executor_tx: Arc>,
+ template_engine: Environment<'static>
}
fn get_config() -> Result {
@@ -42,10 +46,17 @@ async fn main() -> Result<()> {
let (tx, rx) = mpsc::channel::(32);
let config: Config = get_config().expect("Cannot get config");
+ let mut jinja = Environment::new();
+ jinja
+ .add_template("layouts/base.html", include_str!("./templates/layouts/base.html"))
+ .unwrap();
+ jinja.add_template("pages/home.html", include_str!("./templates/pages/home.html")).unwrap();
+
let state = AppState {
config,
db: pool,
executor_tx: Arc::new(tx),
+ template_engine: jinja
};
// start executor daemon
@@ -65,6 +76,7 @@ async fn main() -> Result<()> {
get(controllers::get_task_run),
)
.route("/webhooks/:token", get(controllers::handle_webhook))
+ .nest_service("/assets", ServeDir::new("./assets"))
.with_state(state);
let listen_addr = "0.0.0.0:8085";
diff --git a/src/templates/layouts/base.html b/src/templates/layouts/base.html
new file mode 100644
index 0000000..d11c24d
--- /dev/null
+++ b/src/templates/layouts/base.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+ Autotasker
+
+
+
+
+
+ {% block body %}{% endblock %}
+
+
+
diff --git a/src/templates/home.html b/src/templates/pages/home.html
similarity index 84%
rename from src/templates/home.html
rename to src/templates/pages/home.html
index 918e026..bb3294d 100644
--- a/src/templates/home.html
+++ b/src/templates/pages/home.html
@@ -1,3 +1,5 @@
+{% extends "layouts/base.html" %}
+{% block body %}
Hello welcome on autotasker
You main want to start in here.
@@ -10,3 +12,4 @@ Autotasker is free software under self-hosted forge repository.
+{% endblock %}
diff --git a/src/templates/list_task_runs.html b/src/templates/pages/list_task_runs.html
similarity index 100%
rename from src/templates/list_task_runs.html
rename to src/templates/pages/list_task_runs.html
diff --git a/src/templates/list_tasks.html b/src/templates/pages/list_tasks.html
similarity index 100%
rename from src/templates/list_tasks.html
rename to src/templates/pages/list_tasks.html
diff --git a/src/templates/run_task.html b/src/templates/pages/run_task.html
similarity index 100%
rename from src/templates/run_task.html
rename to src/templates/pages/run_task.html
diff --git a/src/templates/task_run_details.html b/src/templates/pages/task_run_details.html
similarity index 100%
rename from src/templates/task_run_details.html
rename to src/templates/pages/task_run_details.html
diff --git a/tmp/dbs/current.db b/tmp/dbs/current.db
new file mode 100644
index 0000000000000000000000000000000000000000..0b13db965680d0217570ff80274ecc435c2afb5a
GIT binary patch
literal 12288
zcmeI#!A`<37zgkUj2aRmH;**&03^hO_yQu-NF1m*6Fn`1RhW)Vw=Np59(*$2fk*LZ
z+l{f1aPesVP3XGz>%R6^F1@`mJ;CW?7%dz@Pe_dz205ja5K_*5@}Y}*-^tqQVHDci
znq_kQ@lrkbA*Je)RF?r(uI1`@>
zCw{i0B#84ysW)a_i&3k4W-^+0(`JRr;<>6`7mM9n^m;rPcE=C&l0CF_l%7=x)ls7>
zi;nJ0GYydmMG|j(sCU77m(6TwFrv-I3lCf`m^IoBxyT@GJvyGxUD*{U(g%-6&bxP}Mb}f)B}LwB#v^+Xx?E+|OG@*J;*id|aDv3~WrjCCnTO%C$~B#HH}UzF
zWUCoE7k~GJJPBqmn3}
zSDagEbxOO3tZoobM!d(bzP!=fP9j46Zs%ufck-sX%kQgyR#jCsRiQut0uX=z1Rwwb
u2tWV=5P$##An;!WDr#f6|NqzH#l9c_0SG_<0uX=z1Rwwb2tWV=THqIhlcf*<
literal 0
HcmV?d00001