This is an automated email from the ASF dual-hosted git repository.
piotr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git
The following commit(s) were added to refs/heads/master by this push:
new effbab6f6 feat(bench): add embeddable chart endpoints with PNG
rendering (#2833)
effbab6f6 is described below
commit effbab6f6a01386b65c115d9aa0d877c28b5dd83
Author: Hubert Gruszecki <[email protected]>
AuthorDate: Sun Mar 1 21:02:50 2026 +0100
feat(bench): add embeddable chart endpoints with PNG rendering (#2833)
The dashboard lacked a way to share benchmark charts externally
(e.g. in GitHub issues, docs, or third-party pages).
Add /embed/{uuid} for client-side rendering (self-contained HTML
page with ECharts) and /embed/{uuid}/chart.png for server-side
PNG rendering (charming SSR with deno_core/V8). A dedicated
render thread pins V8 to a single OS thread, with disk caching
so only the first request per variant incurs render cost. The
frontend gets an embed modal (iframe/image tabs, markdown/HTML
snippets, copy/download) wired to a topbar button.
---
.asf.yaml | 2 +-
.github/actions/rust/pre-merge/action.yml | 8 +-
.github/workflows/_build_rust_artifacts.yml | 11 +-
Cargo.lock | 1262 +++++++++++++++++++-
DEPENDENCIES.md | 123 +-
core/bench/dashboard/README.md | 4 +-
core/bench/dashboard/frontend/Cargo.toml | 2 +-
core/bench/dashboard/frontend/assets/style.css | 139 +++
.../frontend/src/components/embed_modal.rs | 205 ++++
.../frontend/src/components/layout/topbar.rs | 41 +
.../bench/dashboard/frontend/src/components/mod.rs | 2 +-
core/bench/dashboard/frontend/src/state/ui.rs | 7 +
core/bench/dashboard/server/Cargo.toml | 3 +-
core/bench/dashboard/server/src/cache/loader.rs | 1 +
core/bench/dashboard/server/src/cache/storage.rs | 4 +
core/bench/dashboard/server/src/cache/watcher.rs | 7 +
core/bench/dashboard/server/src/error.rs | 6 +
core/bench/dashboard/server/src/handlers.rs | 450 +++++++
core/bench/dashboard/server/src/main.rs | 8 +
core/bench/dashboard/server/src/render.rs | 93 ++
core/bench/report/src/plotting/chart.rs | 1 +
21 files changed, 2350 insertions(+), 29 deletions(-)
diff --git a/.asf.yaml b/.asf.yaml
index d9ca3e856..491791f5b 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -46,7 +46,7 @@ github:
io_uring_tpc:
required_pull_request_reviews:
dismiss_stale_reviews: true
- required_approving_review_count: 1
+ required_approving_review_count: 1
required_conversation_resolution: true
custom_subjects:
new_discussion: "{title}"
diff --git a/.github/actions/rust/pre-merge/action.yml
b/.github/actions/rust/pre-merge/action.yml
index eb852c6d6..453b28efd 100644
--- a/.github/actions/rust/pre-merge/action.yml
+++ b/.github/actions/rust/pre-merge/action.yml
@@ -173,7 +173,13 @@ runs:
- name: Build aarch64-musl
if: inputs.task == 'build-aarch64-musl'
- run: cargo build --locked --target aarch64-unknown-linux-musl
+ # Exclude dashboard crates: charming's "ssr" feature pulls deno_core ->
v8,
+ # which has no prebuilt binary for aarch64-unknown-linux-musl.
+ # TODO: support when upstream rusty_v8 publishes aarch64-musl binaries.
+ run: >-
+ cargo build --locked --workspace --target aarch64-unknown-linux-musl
+ --exclude iggy-bench-dashboard-server
+ --exclude bench-dashboard-frontend
shell: bash
env:
# Disable GCC outline atomics to avoid undefined __aarch64_ldadd4_sync
diff --git a/.github/workflows/_build_rust_artifacts.yml
b/.github/workflows/_build_rust_artifacts.yml
index ff4258883..3c2be13a3 100644
--- a/.github/workflows/_build_rust_artifacts.yml
+++ b/.github/workflows/_build_rust_artifacts.yml
@@ -144,7 +144,16 @@ jobs:
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=musl-gcc
fi
- cargo build --locked --release --target ${{ matrix.target }}
"${bin_flags[@]}"
+ # iggy-bench-dashboard-server enables charming's "ssr" feature
(deno_core -> v8).
+ # v8 has no prebuilt binary for aarch64-unknown-linux-musl, so
exclude dashboard
+ # crates to prevent cargo feature unification from pulling V8 into
unrelated binaries.
+ # TODO: build V8 from source (V8_FROM_SOURCE=1, ~30min + clang) or
wait for upstream support.
+ exclude_flags=()
+ if [[ "${{ matrix.target }}" == "aarch64-unknown-linux-musl" ]]; then
+ exclude_flags+=(--workspace --exclude iggy-bench-dashboard-server
--exclude bench-dashboard-frontend)
+ fi
+
+ cargo build --locked --release --target ${{ matrix.target }}
"${bin_flags[@]}" "${exclude_flags[@]}"
- name: Package binaries
id: pkg
diff --git a/Cargo.lock b/Cargo.lock
index 7ce811cec..e020afd0f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -299,6 +299,24 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "aligned"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
+dependencies = [
+ "as-slice",
+]
+
+[[package]]
+name = "aligned-vec"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
+dependencies = [
+ "equator",
+]
+
[[package]]
name = "alloc-no-stdlib"
version = "2.0.4"
@@ -410,6 +428,12 @@ dependencies = [
"zstd",
]
+[[package]]
+name = "arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
+
[[package]]
name = "arc-swap"
version = "1.8.1"
@@ -419,6 +443,17 @@ dependencies = [
"rustversion",
]
+[[package]]
+name = "arg_enum_proc_macro"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.115",
+]
+
[[package]]
name = "argon2"
version = "0.5.3"
@@ -621,6 +656,15 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0f477b951e452a0b6b4a10b53ccd569042d1d01729b519e02074a9c0958a063"
+[[package]]
+name = "as-slice"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
+dependencies = [
+ "stable_deref_trait",
+]
+
[[package]]
name = "asn1-rs"
version = "0.7.1"
@@ -891,6 +935,49 @@ dependencies = [
"cc",
]
+[[package]]
+name = "av-scenechange"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394"
+dependencies = [
+ "aligned",
+ "anyhow",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "log",
+ "num-rational",
+ "num-traits",
+ "pastey 0.1.1",
+ "rayon",
+ "thiserror 2.0.18",
+ "v_frame",
+ "y4m",
+]
+
+[[package]]
+name = "av1-grain"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
+dependencies = [
+ "anyhow",
+ "arrayvec",
+ "log",
+ "nom 8.0.0",
+ "num-rational",
+ "v_frame",
+]
+
+[[package]]
+name = "avif-serialize"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d"
+dependencies = [
+ "arrayvec",
+]
+
[[package]]
name = "aws-lc-rs"
version = "1.15.4"
@@ -999,6 +1086,12 @@ dependencies = [
"tower-service",
]
+[[package]]
+name = "az"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7"
+
[[package]]
name = "backon"
version = "1.6.0"
@@ -1028,6 +1121,16 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+[[package]]
+name = "base64-simd"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195"
+dependencies = [
+ "outref",
+ "vsimd",
+]
+
[[package]]
name = "base64ct"
version = "1.8.3"
@@ -1052,7 +1155,7 @@ checksum =
"3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
[[package]]
name = "bench-dashboard-frontend"
-version = "0.5.1-edge.1"
+version = "0.5.2-edge.1"
dependencies = [
"bench-dashboard-shared",
"bench-report",
@@ -1140,6 +1243,26 @@ dependencies = [
"serde",
]
+[[package]]
+name = "bindgen"
+version = "0.71.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
+dependencies = [
+ "bitflags 2.10.0",
+ "cexpr",
+ "clang-sys",
+ "itertools 0.13.0",
+ "log",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn 2.0.115",
+]
+
[[package]]
name = "bit-set"
version = "0.8.0"
@@ -1155,6 +1278,12 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+[[package]]
+name = "bit_field"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
+
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -1170,6 +1299,15 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "bitstream-io"
+version = "4.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757"
+dependencies = [
+ "core2",
+]
+
[[package]]
name = "bitvec"
version = "1.0.1"
@@ -1380,6 +1518,12 @@ dependencies = [
"serde",
]
+[[package]]
+name = "built"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64"
+
[[package]]
name = "bumpalo"
version = "3.19.1"
@@ -1438,6 +1582,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+[[package]]
+name = "byteorder-lite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
+
[[package]]
name = "bytes"
version = "1.11.1"
@@ -1471,6 +1621,26 @@ dependencies = [
"serde_core",
]
+[[package]]
+name = "capacity_builder"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f2d24a6dcf0cd402a21b65d35340f3a49ff3475dc5fdac91d22d2733e6641c6"
+dependencies = [
+ "capacity_builder_macros",
+ "itoa",
+]
+
+[[package]]
+name = "capacity_builder_macros"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b4a6cae9efc04cc6cbb8faf338d2c497c165c83e74509cf4dbedea948bbf6e5"
+dependencies = [
+ "quote",
+ "syn 2.0.115",
+]
+
[[package]]
name = "cargo-platform"
version = "0.3.2"
@@ -1513,6 +1683,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom 7.1.3",
+]
+
[[package]]
name = "cfg-if"
version = "1.0.4"
@@ -1543,11 +1722,15 @@ source =
"registry+https://github.com/rust-lang/crates.io-index"
checksum = "df19cf7d4540f4db08203dce5171421fdfc5e83ea3f14d7b5329f0dbff3bf3c2"
dependencies = [
"charming_macros",
+ "deno_core",
"handlebars",
+ "image",
"js-sys",
+ "resvg",
"serde",
"serde-wasm-bindgen",
"serde_json",
+ "serde_v8",
"serde_with",
"wasm-bindgen",
"web-sys",
@@ -1588,6 +1771,17 @@ dependencies = [
"inout",
]
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
[[package]]
name = "clap"
version = "4.5.58"
@@ -1663,6 +1857,12 @@ dependencies = [
"thiserror 2.0.18",
]
+[[package]]
+name = "color_quant"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+
[[package]]
name = "colorchoice"
version = "1.0.4"
@@ -2044,6 +2244,12 @@ dependencies = [
"unicode-segmentation",
]
+[[package]]
+name = "cooked-waker"
+version = "5.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f"
+
[[package]]
name = "cookie"
version = "0.16.2"
@@ -2071,6 +2277,15 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+[[package]]
+name = "core2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "core_affinity"
version = "0.8.3"
@@ -2082,6 +2297,15 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "core_maths"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30"
+dependencies = [
+ "libm",
+]
+
[[package]]
name = "cpufeatures"
version = "0.2.17"
@@ -2205,7 +2429,7 @@ dependencies = [
"crossterm_winapi",
"document-features",
"parking_lot",
- "rustix",
+ "rustix 1.1.3",
"winapi",
]
@@ -2551,6 +2775,12 @@ version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
+[[package]]
+name = "data-url"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376"
+
[[package]]
name = "dbus"
version = "0.9.10"
@@ -2573,6 +2803,126 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "debugid"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
+dependencies = [
+ "serde",
+ "uuid",
+]
+
+[[package]]
+name = "deno_core"
+version = "0.351.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4301eb6d378f3ae81fbac4cde14c3f467379efd7d46043268d76905effe3611d"
+dependencies = [
+ "anyhow",
+ "az",
+ "bincode",
+ "bit-set",
+ "bit-vec",
+ "bytes",
+ "capacity_builder",
+ "cooked-waker",
+ "deno_core_icudata",
+ "deno_error",
+ "deno_ops",
+ "deno_path_util",
+ "deno_unsync",
+ "futures",
+ "indexmap 2.13.0",
+ "libc",
+ "parking_lot",
+ "percent-encoding",
+ "pin-project",
+ "serde",
+ "serde_json",
+ "serde_v8",
+ "smallvec",
+ "sourcemap",
+ "static_assertions",
+ "thiserror 2.0.18",
+ "tokio",
+ "url",
+ "v8",
+ "wasm_dep_analyzer",
+]
+
+[[package]]
+name = "deno_core_icudata"
+version = "0.74.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695"
+
+[[package]]
+name = "deno_error"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "612ec3fc481fea759141b0c57810889b0a4fb6fee8f10748677bfe492fd30486"
+dependencies = [
+ "deno_error_macro",
+ "libc",
+ "serde",
+ "serde_json",
+ "tokio",
+ "url",
+]
+
+[[package]]
+name = "deno_error_macro"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8380a4224d5d2c3f84da4d764c4326cac62e9a1e3d4960442d29136fc07be863"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.115",
+]
+
+[[package]]
+name = "deno_ops"
+version = "0.227.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bab1eaf578a8cc0ae6fb933e91dc3388b41df22e5974d5891c17ba66b3a0bbb"
+dependencies = [
+ "indexmap 2.13.0",
+ "proc-macro-rules",
+ "proc-macro2",
+ "quote",
+ "stringcase",
+ "strum",
+ "strum_macros",
+ "syn 2.0.115",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "deno_path_util"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "516f813389095889776b81cc9108ff6f336fd9409b4b12fc0138aea23d2708e1"
+dependencies = [
+ "deno_error",
+ "percent-encoding",
+ "sys_traits",
+ "thiserror 2.0.18",
+ "url",
+]
+
+[[package]]
+name = "deno_unsync"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6742a724e8becb372a74c650a1aefb8924a5b8107f7d75b3848763ea24b27a87"
+dependencies = [
+ "futures-util",
+ "parking_lot",
+ "tokio",
+]
+
[[package]]
name = "der"
version = "0.7.10"
@@ -3000,6 +3350,26 @@ dependencies = [
"syn 2.0.115",
]
+[[package]]
+name = "equator"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
+dependencies = [
+ "equator-macro",
+]
+
+[[package]]
+name = "equator-macro"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.115",
+]
+
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -3067,6 +3437,15 @@ dependencies = [
"windows-sys 0.61.2",
]
+[[package]]
+name = "euclid"
+version = "0.22.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df61bf483e837f88d5c2291dcf55c67be7e676b3a51acc48db3a7b163b91ed63"
+dependencies = [
+ "num-traits",
+]
+
[[package]]
name = "event-listener"
version = "5.4.1"
@@ -3098,6 +3477,21 @@ dependencies = [
"once_cell",
]
+[[package]]
+name = "exr"
+version = "1.74.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
+dependencies = [
+ "bit_field",
+ "half",
+ "lebe",
+ "miniz_oxide",
+ "rayon-core",
+ "smallvec",
+ "zune-inflate",
+]
+
[[package]]
name = "ext-trait"
version = "1.0.1"
@@ -3148,6 +3542,35 @@ dependencies = [
"getrandom 0.2.17",
]
+[[package]]
+name = "fax"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab"
+dependencies = [
+ "fax_derive",
+]
+
+[[package]]
+name = "fax_derive"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.115",
+]
+
+[[package]]
+name = "fdeflate"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
+dependencies = [
+ "simd-adler32",
+]
+
[[package]]
name = "ferroid"
version = "0.8.9"
@@ -3242,6 +3665,12 @@ dependencies = [
"zlib-rs",
]
+[[package]]
+name = "float-cmp"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
+
[[package]]
name = "float-cmp"
version = "0.10.0"
@@ -3287,10 +3716,33 @@ source =
"registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
-name = "foldhash"
-version = "0.2.0"
+name = "foldhash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+
+[[package]]
+name = "fontconfig-parser"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
+dependencies = [
+ "roxmltree",
+]
+
+[[package]]
+name = "fontdb"
+version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905"
+dependencies = [
+ "fontconfig-parser",
+ "log",
+ "memmap2",
+ "slotmap",
+ "tinyvec",
+ "ttf-parser",
+]
[[package]]
name = "foreign-types"
@@ -3357,6 +3809,16 @@ dependencies = [
"libc",
]
+[[package]]
+name = "fslock"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
[[package]]
name = "funty"
version = "2.0.0"
@@ -3589,6 +4051,26 @@ dependencies = [
"typed-builder 0.23.2",
]
+[[package]]
+name = "gif"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
+dependencies = [
+ "color_quant",
+ "weezl",
+]
+
+[[package]]
+name = "gif"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f954a9e9159ec994f73a30a12b96a702dde78f5547bcb561174597924f7d4162"
+dependencies = [
+ "color_quant",
+ "weezl",
+]
+
[[package]]
name = "git2"
version = "0.20.4"
@@ -3602,6 +4084,12 @@ dependencies = [
"url",
]
+[[package]]
+name = "glob"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+
[[package]]
name = "globset"
version = "0.4.18"
@@ -3844,6 +4332,15 @@ dependencies = [
"subtle",
]
+[[package]]
+name = "gzip-header"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95cc527b92e6029a62960ad99aa8a6660faa4555fe5f731aab13aa6a921795a2"
+dependencies = [
+ "crc32fast",
+]
+
[[package]]
name = "h2"
version = "0.3.27"
@@ -4491,6 +4988,12 @@ dependencies = [
"icu_properties",
]
+[[package]]
+name = "if_chain"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb"
+
[[package]]
name = "iggy"
version = "0.9.0"
@@ -4553,13 +5056,14 @@ dependencies = [
[[package]]
name = "iggy-bench-dashboard-server"
-version = "0.6.1-edge.1"
+version = "0.6.2-edge.1"
dependencies = [
"actix-cors",
"actix-files",
"actix-web",
"bench-dashboard-shared",
"bench-report",
+ "charming",
"chrono",
"clap",
"dashmap",
@@ -4955,6 +5459,52 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "image"
+version = "0.25.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a"
+dependencies = [
+ "bytemuck",
+ "byteorder-lite",
+ "color_quant",
+ "exr",
+ "gif 0.14.0",
+ "image-webp",
+ "moxcms",
+ "num-traits",
+ "png 0.18.0",
+ "qoi",
+ "ravif",
+ "rayon",
+ "rgb",
+ "tiff",
+ "zune-core 0.5.1",
+ "zune-jpeg 0.5.12",
+]
+
+[[package]]
+name = "image-webp"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
+dependencies = [
+ "byteorder-lite",
+ "quick-error",
+]
+
+[[package]]
+name = "imagesize"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"
+
+[[package]]
+name = "imgref"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8"
+
[[package]]
name = "impl-more"
version = "0.1.9"
@@ -5103,6 +5653,17 @@ dependencies = [
"zip",
]
+[[package]]
+name = "interpolate_name"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.115",
+]
+
[[package]]
name = "inventory"
version = "0.3.21"
@@ -5131,7 +5692,7 @@ checksum =
"1838759bb8c2f24cf05a35429d83145c4aa6af43f8ad38477295e12a7320a80e"
dependencies = [
"bytes",
"io-uring",
- "rustix",
+ "rustix 1.1.3",
]
[[package]]
@@ -5341,6 +5902,17 @@ dependencies = [
"libc",
]
+[[package]]
+name = "kurbo"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62"
+dependencies = [
+ "arrayvec",
+ "euclid",
+ "smallvec",
+]
+
[[package]]
name = "language-tags"
version = "0.3.2"
@@ -5362,6 +5934,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
+[[package]]
+name = "lebe"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
+
[[package]]
name = "left-right"
version = "0.11.7"
@@ -5477,6 +6055,16 @@ dependencies = [
"pkg-config",
]
+[[package]]
+name = "libfuzzer-sys"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
+dependencies = [
+ "arbitrary",
+ "cc",
+]
+
[[package]]
name = "libgit2-sys"
version = "0.18.3+1.9.2"
@@ -5489,6 +6077,16 @@ dependencies = [
"pkg-config",
]
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link 0.2.1",
+]
+
[[package]]
name = "liblzma"
version = "0.4.5"
@@ -5564,6 +6162,12 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
@@ -5661,6 +6265,15 @@ dependencies = [
"tracing-subscriber",
]
+[[package]]
+name = "loop9"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
+dependencies = [
+ "imgref",
+]
+
[[package]]
name = "lru-slab"
version = "0.1.2"
@@ -5707,6 +6320,16 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
+[[package]]
+name = "maybe-rayon"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
+dependencies = [
+ "cfg-if",
+ "rayon",
+]
+
[[package]]
name = "md-5"
version = "0.10.6"
@@ -5723,6 +6346,15 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+[[package]]
+name = "memmap2"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "message_bus"
version = "0.1.0"
@@ -5869,6 +6501,16 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "moxcms"
+version = "0.7.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
+dependencies = [
+ "num-traits",
+ "pxfm",
+]
+
[[package]]
name = "murmur3"
version = "0.5.2"
@@ -5881,6 +6523,12 @@ version = "6.6.666"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf5a574dadd7941adeaa71823ecba5e28331b8313fb2e1c6a5c7e5981ea53ad6"
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+
[[package]]
name = "nix"
version = "0.31.1"
@@ -5935,6 +6583,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30a9e0365849b8ce3d067218268d6c523c1c14f539f7e9157d635d8adfb308fa"
+[[package]]
+name = "noop_proc_macro"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
+
[[package]]
name = "normalize-line-endings"
version = "0.3.0"
@@ -6029,6 +6683,7 @@ checksum =
"a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
+ "rand 0.8.5",
"serde",
]
@@ -6063,6 +6718,17 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.115",
+]
+
[[package]]
name = "num-integer"
version = "0.1.46"
@@ -6463,6 +7129,12 @@ dependencies = [
"windows-sys 0.61.2",
]
+[[package]]
+name = "outref"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
+
[[package]]
name = "p256"
version = "0.13.2"
@@ -6627,6 +7299,12 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+[[package]]
+name = "pastey"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
+
[[package]]
name = "pastey"
version = "0.2.1"
@@ -6751,6 +7429,12 @@ dependencies = [
"sha2",
]
+[[package]]
+name = "pico-args"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
+
[[package]]
name = "pin-project"
version = "1.1.10"
@@ -6821,6 +7505,32 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+[[package]]
+name = "png"
+version = "0.17.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
+dependencies = [
+ "bitflags 1.3.2",
+ "crc32fast",
+ "fdeflate",
+ "flate2",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "png"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
+dependencies = [
+ "bitflags 2.10.0",
+ "crc32fast",
+ "fdeflate",
+ "flate2",
+ "miniz_oxide",
+]
+
[[package]]
name = "polling"
version = "3.11.0"
@@ -6831,7 +7541,7 @@ dependencies = [
"concurrent-queue",
"hermit-abi",
"pin-project-lite",
- "rustix",
+ "rustix 1.1.3",
"windows-sys 0.61.2",
]
@@ -6913,7 +7623,7 @@ checksum =
"ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe"
dependencies = [
"anstyle",
"difflib",
- "float-cmp",
+ "float-cmp 0.10.0",
"normalize-line-endings",
"predicates-core",
"regex",
@@ -6997,6 +7707,29 @@ dependencies = [
"version_check",
]
+[[package]]
+name = "proc-macro-rules"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f"
+dependencies = [
+ "proc-macro-rules-macros",
+ "proc-macro2",
+ "syn 2.0.115",
+]
+
+[[package]]
+name = "proc-macro-rules-macros"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "207fffb0fe655d1d47f6af98cc2793405e85929bdbc420d685554ff07be27ac7"
+dependencies = [
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.115",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.106"
@@ -7019,6 +7752,25 @@ dependencies = [
"yansi",
]
+[[package]]
+name = "profiling"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
+dependencies = [
+ "profiling-procmacros",
+]
+
+[[package]]
+name = "profiling-procmacros"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
+dependencies = [
+ "quote",
+ "syn 2.0.115",
+]
+
[[package]]
name = "prometheus-client"
version = "0.24.0"
@@ -7133,6 +7885,24 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "pxfm"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "qoi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
+dependencies = [
+ "bytemuck",
+]
+
[[package]]
name = "quad-rand"
version = "0.2.3"
@@ -7154,6 +7924,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "quick-error"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
+
[[package]]
name = "quick-xml"
version = "0.37.5"
@@ -7329,12 +8105,62 @@ source =
"registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
[[package]]
-name = "rand_xoshiro"
-version = "0.8.0"
+name = "rand_xoshiro"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f0b2cc7bfeef8f0320ca45f88b00157a03c67137022d59393614352d6bf4312"
+dependencies = [
+ "rand_core 0.10.0",
+]
+
+[[package]]
+name = "rav1e"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b"
+dependencies = [
+ "aligned-vec",
+ "arbitrary",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "av-scenechange",
+ "av1-grain",
+ "bitstream-io",
+ "built",
+ "cfg-if",
+ "interpolate_name",
+ "itertools 0.14.0",
+ "libc",
+ "libfuzzer-sys",
+ "log",
+ "maybe-rayon",
+ "new_debug_unreachable",
+ "noop_proc_macro",
+ "num-derive",
+ "num-traits",
+ "paste",
+ "profiling",
+ "rand 0.9.2",
+ "rand_chacha 0.9.0",
+ "simd_helpers",
+ "thiserror 2.0.18",
+ "v_frame",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "ravif"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f0b2cc7bfeef8f0320ca45f88b00157a03c67137022d59393614352d6bf4312"
+checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285"
dependencies = [
- "rand_core 0.10.0",
+ "avif-serialize",
+ "imgref",
+ "loop9",
+ "quick-error",
+ "rav1e",
+ "rayon",
+ "rgb",
]
[[package]]
@@ -7596,6 +8422,23 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "resvg"
+version = "0.45.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43"
+dependencies = [
+ "gif 0.13.3",
+ "image-webp",
+ "log",
+ "pico-args",
+ "rgb",
+ "svgtypes",
+ "tiny-skia",
+ "usvg",
+ "zune-jpeg 0.4.21",
+]
+
[[package]]
name = "retry-policies"
version = "0.5.1"
@@ -7615,6 +8458,15 @@ dependencies = [
"subtle",
]
+[[package]]
+name = "rgb"
+version = "0.8.52"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce"
+dependencies = [
+ "bytemuck",
+]
+
[[package]]
name = "ring"
version = "0.17.14"
@@ -7679,7 +8531,7 @@ dependencies = [
"http 1.4.0",
"http-body",
"http-body-util",
- "pastey",
+ "pastey 0.2.1",
"pin-project-lite",
"rand 0.9.2",
"reqwest",
@@ -7754,6 +8606,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746"
+[[package]]
+name = "roxmltree"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
+
[[package]]
name = "rsa"
version = "0.9.10"
@@ -7858,6 +8716,19 @@ dependencies = [
"nom 7.1.3",
]
+[[package]]
+name = "rustix"
+version = "0.38.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
+dependencies = [
+ "bitflags 2.10.0",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.15",
+ "windows-sys 0.52.0",
+]
+
[[package]]
name = "rustix"
version = "1.1.3"
@@ -7867,7 +8738,7 @@ dependencies = [
"bitflags 2.10.0",
"errno",
"libc",
- "linux-raw-sys",
+ "linux-raw-sys 0.11.0",
"windows-sys 0.61.2",
]
@@ -7963,6 +8834,24 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+[[package]]
+name = "rustybuzz"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702"
+dependencies = [
+ "bitflags 2.10.0",
+ "bytemuck",
+ "core_maths",
+ "log",
+ "smallvec",
+ "ttf-parser",
+ "unicode-bidi-mirroring",
+ "unicode-ccc",
+ "unicode-properties",
+ "unicode-script",
+]
+
[[package]]
name = "ryu"
version = "1.0.23"
@@ -8218,6 +9107,7 @@ version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
+ "indexmap 2.13.0",
"itoa",
"memchr",
"serde",
@@ -8277,6 +9167,20 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_v8"
+version = "0.260.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4f284b4d521591b17ddee01aff830dd005a04476f7862aca9298c038d00fb7e"
+dependencies = [
+ "deno_error",
+ "num-bigint",
+ "serde",
+ "smallvec",
+ "thiserror 2.0.18",
+ "v8",
+]
+
[[package]]
name = "serde_with"
version = "3.16.1"
@@ -8519,6 +9423,15 @@ dependencies = [
"value-trait",
]
+[[package]]
+name = "simd_helpers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
+dependencies = [
+ "quote",
+]
+
[[package]]
name = "simdutf8"
version = "0.1.5"
@@ -8537,6 +9450,15 @@ dependencies = [
"time",
]
+[[package]]
+name = "simplecss"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c"
+dependencies = [
+ "log",
+]
+
[[package]]
name = "simulator"
version = "0.1.0"
@@ -8569,6 +9491,15 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+[[package]]
+name = "slotmap"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
+dependencies = [
+ "version_check",
+]
+
[[package]]
name = "smallvec"
version = "1.15.1"
@@ -8642,6 +9573,24 @@ dependencies = [
"windows-sys 0.60.2",
]
+[[package]]
+name = "sourcemap"
+version = "9.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "314d62a489431668f719ada776ca1d49b924db951b7450f8974c9ae51ab05ad7"
+dependencies = [
+ "base64-simd",
+ "bitvec",
+ "data-encoding",
+ "debugid",
+ "if_chain",
+ "rustc-hash",
+ "serde",
+ "serde_json",
+ "unicode-id-start",
+ "url",
+]
+
[[package]]
name = "spin"
version = "0.9.8"
@@ -8901,6 +9850,27 @@ dependencies = [
"toml 0.8.23",
]
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strict-num"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
+dependencies = [
+ "float-cmp 0.9.0",
+]
+
+[[package]]
+name = "stringcase"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72abeda133c49d7bddece6c154728f83eec8172380c80ab7096da9487e20d27c"
+
[[package]]
name = "stringprep"
version = "0.1.5"
@@ -8968,6 +9938,16 @@ version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+[[package]]
+name = "svgtypes"
+version = "0.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc"
+dependencies = [
+ "kurbo",
+ "siphasher",
+]
+
[[package]]
name = "syn"
version = "1.0.109"
@@ -9052,6 +10032,26 @@ dependencies = [
"syn 2.0.115",
]
+[[package]]
+name = "sys_traits"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5410f31d223892c1ce7a098da845c99d023b4c7f18632bc8f09e60dfae3cbb75"
+dependencies = [
+ "sys_traits_macros",
+]
+
+[[package]]
+name = "sys_traits_macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "181f22127402abcf8ee5c83ccd5b408933fec36a6095cf82cda545634692657e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.115",
+]
+
[[package]]
name = "sysinfo"
version = "0.37.2"
@@ -9112,7 +10112,7 @@ dependencies = [
"fastrand",
"getrandom 0.4.1",
"once_cell",
- "rustix",
+ "rustix 1.1.3",
"windows-sys 0.61.2",
]
@@ -9122,7 +10122,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0"
dependencies = [
- "rustix",
+ "rustix 1.1.3",
"windows-sys 0.60.2",
]
@@ -9281,6 +10281,20 @@ dependencies = [
"ordered-float 2.10.1",
]
+[[package]]
+name = "tiff"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f"
+dependencies = [
+ "fax",
+ "flate2",
+ "half",
+ "quick-error",
+ "weezl",
+ "zune-jpeg 0.4.21",
+]
+
[[package]]
name = "time"
version = "0.3.47"
@@ -9323,6 +10337,32 @@ dependencies = [
"crunchy",
]
+[[package]]
+name = "tiny-skia"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "bytemuck",
+ "cfg-if",
+ "log",
+ "png 0.17.16",
+ "tiny-skia-path",
+]
+
+[[package]]
+name = "tiny-skia-path"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "strict-num",
+]
+
[[package]]
name = "tinystr"
version = "0.8.2"
@@ -9771,6 +10811,15 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+[[package]]
+name = "ttf-parser"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
+dependencies = [
+ "core_maths",
+]
+
[[package]]
name = "tungstenite"
version = "0.28.0"
@@ -9888,6 +10937,24 @@ version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
+[[package]]
+name = "unicode-bidi-mirroring"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe"
+
+[[package]]
+name = "unicode-ccc"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e"
+
+[[package]]
+name = "unicode-id-start"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81b79ad29b5e19de4260020f8919b443b2ef0277d242ce532ec7b7a2cc8b6007"
+
[[package]]
name = "unicode-ident"
version = "1.0.23"
@@ -9915,12 +10982,24 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
+[[package]]
+name = "unicode-script"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee"
+
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+[[package]]
+name = "unicode-vo"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
+
[[package]]
name = "unicode-width"
version = "0.1.14"
@@ -10009,6 +11088,33 @@ version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
+[[package]]
+name = "usvg"
+version = "0.45.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef"
+dependencies = [
+ "base64 0.22.1",
+ "data-url",
+ "flate2",
+ "fontdb",
+ "imagesize",
+ "kurbo",
+ "log",
+ "pico-args",
+ "roxmltree",
+ "rustybuzz",
+ "simplecss",
+ "siphasher",
+ "strict-num",
+ "svgtypes",
+ "tiny-skia-path",
+ "unicode-bidi",
+ "unicode-script",
+ "unicode-vo",
+ "xmlwriter",
+]
+
[[package]]
name = "utf-8"
version = "0.7.6"
@@ -10047,6 +11153,33 @@ dependencies = [
"zerocopy",
]
+[[package]]
+name = "v8"
+version = "137.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33995a1fee055ff743281cde33a41f0d618ee0bdbe8bdf6859e11864499c2595"
+dependencies = [
+ "bindgen",
+ "bitflags 2.10.0",
+ "fslock",
+ "gzip-header",
+ "home",
+ "miniz_oxide",
+ "paste",
+ "which",
+]
+
+[[package]]
+name = "v_frame"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2"
+dependencies = [
+ "aligned-vec",
+ "num-traits",
+ "wasm-bindgen",
+]
+
[[package]]
name = "v_htmlescape"
version = "0.15.8"
@@ -10065,7 +11198,7 @@ version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e80f0c733af0720a501b3905d22e2f97662d8eacfe082a75ed7ffb5ab08cb59"
dependencies = [
- "float-cmp",
+ "float-cmp 0.10.0",
"halfbrown",
"itoa",
"ryu",
@@ -10132,6 +11265,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+[[package]]
+name = "vsimd"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
+
[[package]]
name = "wait-timeout"
version = "0.2.1"
@@ -10284,6 +11423,16 @@ dependencies = [
"web-sys",
]
+[[package]]
+name = "wasm_dep_analyzer"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51cf5f08b357e64cd7642ab4bbeb11aecab9e15520692129624fb9908b8df2c"
+dependencies = [
+ "deno_error",
+ "thiserror 2.0.18",
+]
+
[[package]]
name = "wasmparser"
version = "0.244.0"
@@ -10358,6 +11507,24 @@ dependencies = [
"rustls-pki-types",
]
+[[package]]
+name = "weezl"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
+
+[[package]]
+name = "which"
+version = "6.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
+dependencies = [
+ "either",
+ "home",
+ "rustix 0.38.44",
+ "winsafe",
+]
+
[[package]]
name = "whoami"
version = "1.6.1"
@@ -10919,6 +12086,12 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "winsafe"
+version = "0.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
+
[[package]]
name = "wit-bindgen"
version = "0.51.0"
@@ -11047,9 +12220,21 @@ source =
"registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
dependencies = [
"libc",
- "rustix",
+ "rustix 1.1.3",
]
+[[package]]
+name = "xmlwriter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
+
+[[package]]
+name = "y4m"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
+
[[package]]
name = "yansi"
version = "1.0.1"
@@ -11317,3 +12502,42 @@ dependencies = [
"cc",
"pkg-config",
]
+
+[[package]]
+name = "zune-core"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
+
+[[package]]
+name = "zune-core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"
+
+[[package]]
+name = "zune-inflate"
+version = "0.2.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "zune-jpeg"
+version = "0.4.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713"
+dependencies = [
+ "zune-core 0.4.12",
+]
+
+[[package]]
+name = "zune-jpeg"
+version = "0.5.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "410e9ecef634c709e3831c2cfdb8d9c32164fae1c67496d5b68fff728eec37fe"
+dependencies = [
+ "zune-core 0.5.1",
+]
diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md
index 537fcd7b3..acb2ba8c5 100644
--- a/DEPENDENCIES.md
+++ b/DEPENDENCIES.md
@@ -19,6 +19,8 @@ aes-gcm: 0.10.3, "Apache-2.0 OR MIT",
ahash: 0.7.8, "Apache-2.0 OR MIT",
ahash: 0.8.12, "Apache-2.0 OR MIT",
aho-corasick: 1.1.4, "MIT OR Unlicense",
+aligned: 0.4.3, "Apache-2.0 OR MIT",
+aligned-vec: 0.6.4, "MIT",
alloc-no-stdlib: 2.0.4, "BSD-3-Clause",
alloc-stdlib: 0.2.2, "BSD-3-Clause",
allocator-api2: 0.2.21, "Apache-2.0 OR MIT",
@@ -30,7 +32,9 @@ anstyle-query: 1.1.5, "Apache-2.0 OR MIT",
anstyle-wincon: 3.0.11, "Apache-2.0 OR MIT",
anyhow: 1.0.101, "Apache-2.0 OR MIT",
apache-avro: 0.21.0, "Apache-2.0",
+arbitrary: 1.4.2, "Apache-2.0 OR MIT",
arc-swap: 1.8.1, "Apache-2.0 OR MIT",
+arg_enum_proc_macro: 0.3.4, "MIT",
argon2: 0.5.3, "Apache-2.0 OR MIT",
array-init: 2.1.0, "Apache-2.0 OR MIT",
arrayref: 0.3.9, "BSD-2-Clause",
@@ -47,6 +51,7 @@ arrow-schema: 57.3.0, "Apache-2.0",
arrow-select: 57.3.0, "Apache-2.0",
arrow-string: 57.3.0, "Apache-2.0",
as-any: 0.3.2, "Apache-2.0 OR MIT",
+as-slice: 0.2.1, "Apache-2.0 OR MIT",
asn1-rs: 0.7.1, "Apache-2.0 OR MIT",
asn1-rs-derive: 0.6.0, "Apache-2.0 OR MIT",
asn1-rs-impl: 0.2.0, "Apache-2.0 OR MIT",
@@ -71,30 +76,38 @@ atomic-polyfill: 1.0.3, "Apache-2.0 OR MIT",
atomic-waker: 1.1.2, "Apache-2.0 OR MIT",
autocfg: 1.5.0, "Apache-2.0 OR MIT",
autotools: 0.2.7, "MIT",
+av-scenechange: 0.14.1, "MIT",
+av1-grain: 0.2.5, "BSD-2-Clause",
+avif-serialize: 0.8.8, "BSD-3-Clause",
aws-lc-rs: 1.15.4, "(Apache-2.0 OR ISC) AND ISC",
aws-lc-sys: 0.37.1, "(Apache-2.0 OR ISC) AND ISC AND OpenSSL",
axum: 0.8.8, "MIT",
axum-core: 0.5.6, "MIT",
axum-macros: 0.5.0, "MIT",
axum-server: 0.8.0, "MIT",
+az: 1.3.0, "Apache-2.0 OR MIT",
backon: 1.6.0, "Apache-2.0",
base16ct: 0.2.0, "Apache-2.0 OR MIT",
base64: 0.21.7, "Apache-2.0 OR MIT",
base64: 0.22.1, "Apache-2.0 OR MIT",
+base64-simd: 0.8.0, "MIT",
base64ct: 1.8.3, "Apache-2.0 OR MIT",
bdd: 0.0.1, "Apache-2.0",
beef: 0.5.2, "Apache-2.0 OR MIT",
-bench-dashboard-frontend: 0.5.1-edge.1, "Apache-2.0",
+bench-dashboard-frontend: 0.5.2-edge.1, "Apache-2.0",
bench-dashboard-shared: 0.1.0, "Apache-2.0",
bench-report: 0.2.3-edge.1, "Apache-2.0",
bench-runner: 0.1.0, "Apache-2.0",
bigdecimal: 0.4.10, "Apache-2.0 OR MIT",
bimap: 0.6.3, "Apache-2.0 OR MIT",
bincode: 1.3.3, "MIT",
+bindgen: 0.71.1, "BSD-3-Clause",
bit-set: 0.8.0, "Apache-2.0 OR MIT",
bit-vec: 0.8.0, "Apache-2.0 OR MIT",
+bit_field: 0.10.3, "Apache-2.0 OR MIT",
bitflags: 1.3.2, "Apache-2.0 OR MIT",
bitflags: 2.10.0, "Apache-2.0 OR MIT",
+bitstream-io: 4.9.0, "Apache-2.0 OR MIT",
bitvec: 1.0.1, "MIT",
blake2: 0.10.6, "Apache-2.0 OR MIT",
blake3: 1.8.3, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR CC0-1.0",
@@ -110,6 +123,7 @@ borsh-derive: 1.6.0, "Apache-2.0",
brotli: 8.0.2, "BSD-3-Clause AND MIT",
brotli-decompressor: 5.0.0, "BSD-3-Clause OR MIT",
bstr: 1.12.1, "Apache-2.0 OR MIT",
+built: 0.8.0, "MIT",
bumpalo: 3.19.1, "Apache-2.0 OR MIT",
byte-unit: 5.2.0, "MIT",
bytecheck: 0.6.12, "MIT",
@@ -117,14 +131,18 @@ bytecheck_derive: 0.6.12, "MIT",
bytecount: 0.6.9, "Apache-2.0 OR MIT",
bytemuck: 1.25.0, "Apache-2.0 OR MIT OR Zlib",
byteorder: 1.5.0, "MIT OR Unlicense",
+byteorder-lite: 0.1.0, "MIT OR Unlicense",
bytes: 1.11.1, "MIT",
bytestring: 1.5.0, "Apache-2.0 OR MIT",
bzip2: 0.6.1, "Apache-2.0 OR MIT",
camino: 1.2.2, "Apache-2.0 OR MIT",
+capacity_builder: 0.5.0, "MIT",
+capacity_builder_macros: 0.3.0, "MIT",
cargo-platform: 0.3.2, "Apache-2.0 OR MIT",
cargo_metadata: 0.23.1, "MIT",
cc: 1.2.55, "Apache-2.0 OR MIT",
cesu8: 1.1.0, "Apache-2.0 OR MIT",
+cexpr: 0.6.0, "Apache-2.0 OR MIT",
cfg-if: 1.0.4, "Apache-2.0 OR MIT",
cfg_aliases: 0.2.1, "MIT",
chacha20: 0.10.0, "Apache-2.0 OR MIT",
@@ -132,6 +150,7 @@ charming: 0.6.0, "Apache-2.0 OR MIT",
charming_macros: 0.1.0, "Apache-2.0 OR MIT",
chrono: 0.4.43, "Apache-2.0 OR MIT",
cipher: 0.4.4, "Apache-2.0 OR MIT",
+clang-sys: 1.8.1, "Apache-2.0",
clap: 4.5.58, "Apache-2.0 OR MIT",
clap_builder: 4.5.58, "Apache-2.0 OR MIT",
clap_complete: 4.5.66, "Apache-2.0 OR MIT",
@@ -140,6 +159,7 @@ clap_lex: 1.0.0, "Apache-2.0 OR MIT",
clock: 0.1.0, "N/A",
cmake: 0.1.57, "Apache-2.0 OR MIT",
cobs: 0.3.0, "Apache-2.0 OR MIT",
+color_quant: 1.1.0, "MIT",
colorchoice: 1.0.4, "Apache-2.0 OR MIT",
colored: 3.1.1, "MPL-2.0",
combine: 4.6.7, "MIT",
@@ -170,10 +190,13 @@ const-random-macro: 0.1.16, "Apache-2.0 OR MIT",
constant_time_eq: 0.4.2, "Apache-2.0 OR CC0-1.0 OR MIT-0",
convert_case: 0.6.0, "MIT",
convert_case: 0.10.0, "MIT",
+cooked-waker: 5.0.0, "MPL-2.0",
cookie: 0.16.2, "Apache-2.0 OR MIT",
core-foundation: 0.10.1, "Apache-2.0 OR MIT",
core-foundation-sys: 0.8.7, "Apache-2.0 OR MIT",
+core2: 0.4.0, "Apache-2.0 OR MIT",
core_affinity: 0.8.3, "Apache-2.0 OR MIT",
+core_maths: 0.1.1, "MIT",
cpufeatures: 0.2.17, "Apache-2.0 OR MIT",
cpufeatures: 0.3.0, "Apache-2.0 OR MIT",
crc: 3.4.0, "Apache-2.0 OR MIT",
@@ -215,8 +238,17 @@ darling_macro: 0.21.3, "MIT",
darling_macro: 0.23.0, "MIT",
dashmap: 6.1.0, "MIT",
data-encoding: 2.10.0, "MIT",
+data-url: 0.3.2, "Apache-2.0 OR MIT",
dbus: 0.9.10, "Apache-2.0 OR MIT",
dbus-secret-service: 4.1.0, "Apache-2.0 OR MIT",
+debugid: 0.8.0, "Apache-2.0",
+deno_core: 0.351.0, "MIT",
+deno_core_icudata: 0.74.0, "MIT",
+deno_error: 0.6.1, "MIT",
+deno_error_macro: 0.6.1, "MIT",
+deno_ops: 0.227.0, "MIT",
+deno_path_util: 0.4.0, "MIT",
+deno_unsync: 0.4.4, "MIT",
der: 0.7.10, "Apache-2.0 OR MIT",
der-parser: 10.0.0, "Apache-2.0 OR MIT",
deranged: 0.5.6, "Apache-2.0 OR MIT",
@@ -259,6 +291,8 @@ encoding_rs: 0.8.35, "(Apache-2.0 OR MIT) AND BSD-3-Clause",
enum_dispatch: 0.3.13, "Apache-2.0 OR MIT",
enumset: 1.1.10, "Apache-2.0 OR MIT",
enumset_derive: 0.14.0, "Apache-2.0 OR MIT",
+equator: 0.4.2, "MIT",
+equator-macro: 0.4.2, "MIT",
equivalent: 1.0.2, "Apache-2.0 OR MIT",
err_trail: 0.11.0, "Apache-2.0",
errno: 0.3.14, "Apache-2.0 OR MIT",
@@ -266,14 +300,19 @@ error_set: 0.9.1, "Apache-2.0",
error_set_impl: 0.9.1, "Apache-2.0",
etcetera: 0.8.0, "Apache-2.0 OR MIT",
etcetera: 0.11.0, "Apache-2.0 OR MIT",
+euclid: 0.22.13, "Apache-2.0 OR MIT",
event-listener: 5.4.1, "Apache-2.0 OR MIT",
event-listener-strategy: 0.5.4, "Apache-2.0 OR MIT",
expect-test: 1.5.1, "Apache-2.0 OR MIT",
+exr: 1.74.0, "BSD-3-Clause",
ext-trait: 1.0.1, "Apache-2.0 OR MIT OR Zlib",
ext-trait-proc_macros: 1.0.1, "Apache-2.0 OR MIT OR Zlib",
extension-traits: 1.0.1, "Apache-2.0 OR MIT OR Zlib",
fastbloom: 0.14.1, "Apache-2.0 OR MIT",
fastrand: 2.3.0, "Apache-2.0 OR MIT",
+fax: 0.2.6, "MIT",
+fax_derive: 0.2.0, "MIT",
+fdeflate: 0.3.7, "Apache-2.0 OR MIT",
ferroid: 0.8.9, "Apache-2.0 OR MIT",
ff: 0.13.1, "Apache-2.0 OR MIT",
fiat-crypto: 0.2.9, "Apache-2.0 OR BSD-1-Clause OR MIT",
@@ -284,12 +323,15 @@ filetime: 0.2.27, "Apache-2.0 OR MIT",
find-msvc-tools: 0.1.9, "Apache-2.0 OR MIT",
flatbuffers: 25.12.19, "Apache-2.0",
flate2: 1.1.9, "Apache-2.0 OR MIT",
+float-cmp: 0.9.0, "MIT",
float-cmp: 0.10.0, "MIT",
flume: 0.11.1, "Apache-2.0 OR MIT",
flume: 0.12.0, "Apache-2.0 OR MIT",
fnv: 1.0.7, "Apache-2.0 OR MIT",
foldhash: 0.1.5, "Zlib",
foldhash: 0.2.0, "Zlib",
+fontconfig-parser: 0.5.8, "MIT",
+fontdb: 0.23.0, "MIT",
foreign-types: 0.3.2, "Apache-2.0 OR MIT",
foreign-types-shared: 0.1.1, "Apache-2.0 OR MIT",
form_urlencoded: 1.2.2, "Apache-2.0 OR MIT",
@@ -298,6 +340,7 @@ fs-err: 3.3.0, "Apache-2.0 OR MIT",
fs2: 0.4.3, "Apache-2.0 OR MIT",
fs_extra: 1.3.0, "MIT",
fsevent-sys: 4.1.0, "MIT",
+fslock: 0.2.1, "MIT",
funty: 2.0.0, "MIT",
futures: 0.3.31, "Apache-2.0 OR MIT",
futures-channel: 0.3.31, "Apache-2.0 OR MIT",
@@ -319,7 +362,10 @@ getrandom: 0.3.4, "Apache-2.0 OR MIT",
getrandom: 0.4.1, "Apache-2.0 OR MIT",
ghash: 0.5.1, "Apache-2.0 OR MIT",
gherkin: 0.15.0, "Apache-2.0 OR MIT",
+gif: 0.13.3, "Apache-2.0 OR MIT",
+gif: 0.14.0, "Apache-2.0 OR MIT",
git2: 0.20.4, "Apache-2.0 OR MIT",
+glob: 0.3.3, "Apache-2.0 OR MIT",
globset: 0.4.18, "MIT OR Unlicense",
globwalk: 0.9.1, "MIT",
gloo: 0.11.0, "Apache-2.0 OR MIT",
@@ -337,6 +383,7 @@ gloo-worker: 0.5.0, "Apache-2.0 OR MIT",
gloo-worker-macros: 0.1.0, "Apache-2.0 OR MIT",
governor: 0.10.4, "MIT",
group: 0.13.0, "Apache-2.0 OR MIT",
+gzip-header: 1.0.0, "Apache-2.0 OR MIT",
h2: 0.3.27, "MIT",
h2: 0.4.13, "MIT",
half: 2.7.1, "Apache-2.0 OR MIT",
@@ -390,9 +437,10 @@ id-arena: 2.3.0, "Apache-2.0 OR MIT",
ident_case: 1.0.1, "Apache-2.0 OR MIT",
idna: 1.1.0, "Apache-2.0 OR MIT",
idna_adapter: 1.2.1, "Apache-2.0 OR MIT",
+if_chain: 1.0.3, "Apache-2.0 OR MIT",
iggy: 0.9.0, "Apache-2.0",
iggy-bench: 0.4.0, "Apache-2.0",
-iggy-bench-dashboard-server: 0.6.1-edge.1, "Apache-2.0",
+iggy-bench-dashboard-server: 0.6.2-edge.1, "Apache-2.0",
iggy-cli: 0.11.0, "Apache-2.0",
iggy-connectors: 0.3.0, "Apache-2.0",
iggy-mcp: 0.3.0, "Apache-2.0",
@@ -409,6 +457,10 @@ iggy_connector_sdk: 0.2.0, "Apache-2.0",
iggy_connector_stdout_sink: 0.3.0, "Apache-2.0",
iggy_examples: 0.0.6, "Apache-2.0",
ignore: 0.4.25, "MIT OR Unlicense",
+image: 0.25.9, "Apache-2.0 OR MIT",
+image-webp: 0.2.4, "Apache-2.0 OR MIT",
+imagesize: 0.13.0, "MIT",
+imgref: 1.12.0, "Apache-2.0 OR CC0-1.0",
impl-more: 0.1.9, "Apache-2.0 OR MIT",
implicit-clone: 0.6.0, "Apache-2.0 OR MIT",
implicit-clone-derive: 0.1.2, "Apache-2.0 OR MIT",
@@ -421,6 +473,7 @@ inotify-sys: 0.1.5, "ISC",
inout: 0.1.4, "Apache-2.0 OR MIT",
integer-encoding: 3.0.4, "MIT",
integration: 0.0.1, "Apache-2.0",
+interpolate_name: 0.2.4, "MIT",
inventory: 0.3.21, "Apache-2.0 OR MIT",
io-uring: 0.7.11, "Apache-2.0 OR MIT",
io_uring_buf_ring: 0.2.3, "MIT",
@@ -445,9 +498,11 @@ keccak: 0.1.6, "Apache-2.0 OR MIT",
keyring: 3.6.3, "Apache-2.0 OR MIT",
kqueue: 1.1.1, "MIT",
kqueue-sys: 1.0.4, "MIT",
+kurbo: 0.11.3, "Apache-2.0 OR MIT",
language-tags: 0.3.2, "Apache-2.0 OR MIT",
lazy_static: 1.5.0, "Apache-2.0 OR MIT",
leb128fmt: 0.1.0, "Apache-2.0 OR MIT",
+lebe: 0.5.3, "BSD-3-Clause",
left-right: 0.11.7, "Apache-2.0 OR MIT",
lending-iterator: 0.1.7, "Apache-2.0 OR MIT OR Zlib",
lending-iterator-proc_macros: 0.1.7, "Apache-2.0 OR MIT OR Zlib",
@@ -460,7 +515,9 @@ lexical-write-integer: 1.0.6, "Apache-2.0 OR MIT",
libbz2-rs-sys: 0.2.2, "bzip2-1.0.6",
libc: 0.2.180, "Apache-2.0 OR MIT",
libdbus-sys: 0.2.7, "Apache-2.0 OR MIT",
+libfuzzer-sys: 0.4.12, "(Apache-2.0 OR MIT) AND NCSA",
libgit2-sys: 0.18.3+1.9.2, "Apache-2.0 OR MIT",
+libloading: 0.8.9, "ISC",
liblzma: 0.4.5, "Apache-2.0 OR MIT",
liblzma-sys: 0.4.5, "Apache-2.0 OR MIT",
libm: 0.2.16, "MIT",
@@ -469,6 +526,7 @@ libredox: 0.1.12, "MIT",
libsqlite3-sys: 0.30.1, "MIT",
libz-sys: 1.1.23, "Apache-2.0 OR MIT",
linked-hash-map: 0.5.6, "Apache-2.0 OR MIT",
+linux-raw-sys: 0.4.15, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT",
linux-raw-sys: 0.11.0, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT",
litemap: 0.8.1, "Unicode-3.0",
litrs: 1.0.0, "Apache-2.0 OR MIT",
@@ -480,14 +538,17 @@ logos: 0.15.1, "Apache-2.0 OR MIT",
logos-codegen: 0.15.1, "Apache-2.0 OR MIT",
logos-derive: 0.15.1, "Apache-2.0 OR MIT",
loom: 0.7.2, "MIT",
+loop9: 0.1.5, "MIT",
lru-slab: 0.1.2, "Apache-2.0 OR MIT OR Zlib",
lz4_flex: 0.12.0, "MIT",
macro_rules_attribute: 0.1.3, "MIT",
macro_rules_attribute-proc_macro: 0.1.3, "MIT",
matchers: 0.2.0, "MIT",
matchit: 0.8.4, "BSD-3-Clause AND MIT",
+maybe-rayon: 0.1.1, "MIT",
md-5: 0.10.6, "Apache-2.0 OR MIT",
memchr: 2.8.0, "MIT OR Unlicense",
+memmap2: 0.9.10, "Apache-2.0 OR MIT",
message_bus: 0.1.0, "Apache-2.0",
metadata: 0.1.0, "Apache-2.0",
miette: 7.6.0, "Apache-2.0",
@@ -501,14 +562,17 @@ mio: 1.1.1, "MIT",
mockall: 0.14.0, "Apache-2.0 OR MIT",
mockall_derive: 0.14.0, "Apache-2.0 OR MIT",
moka: 0.12.13, "(Apache-2.0 OR MIT) AND Apache-2.0",
+moxcms: 0.7.11, "Apache-2.0 OR BSD-3-Clause",
murmur3: 0.5.2, "Apache-2.0 OR MIT",
never-say-never: 6.6.666, "Apache-2.0 OR MIT OR Zlib",
+new_debug_unreachable: 1.0.6, "MIT",
nix: 0.31.1, "MIT",
nom: 7.1.3, "MIT",
nom: 8.0.0, "MIT",
nom_locate: 5.0.0, "MIT",
nonzero_ext: 0.3.0, "Apache-2.0",
nonzero_lit: 0.1.2, "Apache-2.0 OR CC0-1.0 OR MIT",
+noop_proc_macro: 0.3.0, "MIT",
normalize-line-endings: 0.3.0, "Apache-2.0",
notify: 8.2.0, "CC0-1.0",
notify-types: 2.1.0, "Apache-2.0 OR MIT",
@@ -521,6 +585,7 @@ num-bigint: 0.4.6, "Apache-2.0 OR MIT",
num-bigint-dig: 0.8.6, "Apache-2.0 OR MIT",
num-complex: 0.4.6, "Apache-2.0 OR MIT",
num-conv: 0.2.0, "Apache-2.0 OR MIT",
+num-derive: 0.4.2, "Apache-2.0 OR MIT",
num-integer: 0.1.46, "Apache-2.0 OR MIT",
num-iter: 0.1.45, "Apache-2.0 OR MIT",
num-modular: 0.6.1, "Apache-2.0",
@@ -556,6 +621,7 @@ ordered-float: 2.10.1, "MIT",
ordered-float: 4.6.0, "MIT",
ordered-multimap: 0.7.3, "MIT",
os_pipe: 1.2.3, "MIT",
+outref: 0.5.2, "MIT",
p256: 0.13.2, "Apache-2.0 OR MIT",
p384: 0.13.1, "Apache-2.0 OR MIT",
papaya: 0.2.3, "MIT",
@@ -569,6 +635,7 @@ partitions: 0.1.0, "Apache-2.0",
passterm: 2.0.1, "BSD-3-Clause",
password-hash: 0.5.0, "Apache-2.0 OR MIT",
paste: 1.0.15, "Apache-2.0 OR MIT",
+pastey: 0.1.1, "Apache-2.0 OR MIT",
pastey: 0.2.1, "Apache-2.0 OR MIT",
pear: 0.2.9, "Apache-2.0 OR MIT",
pear_codegen: 0.2.9, "Apache-2.0 OR MIT",
@@ -582,6 +649,7 @@ pest: 2.8.6, "Apache-2.0 OR MIT",
pest_derive: 2.8.6, "Apache-2.0 OR MIT",
pest_generator: 2.8.6, "Apache-2.0 OR MIT",
pest_meta: 2.8.6, "Apache-2.0 OR MIT",
+pico-args: 0.5.0, "MIT",
pin-project: 1.1.10, "Apache-2.0 OR MIT",
pin-project-internal: 1.1.10, "Apache-2.0 OR MIT",
pin-project-lite: 0.2.16, "Apache-2.0 OR MIT",
@@ -590,6 +658,8 @@ pinned: 0.1.0, "Apache-2.0 OR MIT",
pkcs1: 0.7.5, "Apache-2.0 OR MIT",
pkcs8: 0.10.2, "Apache-2.0 OR MIT",
pkg-config: 0.3.32, "Apache-2.0 OR MIT",
+png: 0.17.16, "Apache-2.0 OR MIT",
+png: 0.18.0, "Apache-2.0 OR MIT",
polling: 3.11.0, "Apache-2.0 OR MIT",
polonius-the-crab: 0.2.1, "Apache-2.0 OR MIT OR Zlib",
polyval: 0.6.2, "Apache-2.0 OR MIT",
@@ -608,8 +678,12 @@ proc-macro-crate: 1.3.1, "Apache-2.0 OR MIT",
proc-macro-crate: 3.4.0, "Apache-2.0 OR MIT",
proc-macro-error: 1.0.4, "Apache-2.0 OR MIT",
proc-macro-error-attr: 1.0.4, "Apache-2.0 OR MIT",
+proc-macro-rules: 0.4.0, "Apache-2.0 OR MIT",
+proc-macro-rules-macros: 0.4.0, "Apache-2.0 OR MIT",
proc-macro2: 1.0.106, "Apache-2.0 OR MIT",
proc-macro2-diagnostics: 0.10.1, "Apache-2.0 OR MIT",
+profiling: 1.0.17, "Apache-2.0 OR MIT",
+profiling-procmacros: 1.0.17, "Apache-2.0 OR MIT",
prometheus-client: 0.24.0, "Apache-2.0 OR MIT",
prometheus-client-derive-encode: 0.5.0, "Apache-2.0 OR MIT",
prost: 0.14.3, "Apache-2.0",
@@ -620,8 +694,11 @@ protox: 0.9.1, "Apache-2.0 OR MIT",
protox-parse: 0.9.0, "Apache-2.0 OR MIT",
ptr_meta: 0.1.4, "MIT",
ptr_meta_derive: 0.1.4, "MIT",
+pxfm: 0.1.27, "Apache-2.0 OR BSD-3-Clause",
+qoi: 0.4.1, "Apache-2.0 OR MIT",
quad-rand: 0.2.3, "MIT",
quanta: 0.12.6, "MIT",
+quick-error: 2.0.1, "Apache-2.0 OR MIT",
quick-xml: 0.37.5, "MIT",
quick-xml: 0.38.4, "MIT",
quinn: 0.11.9, "Apache-2.0 OR MIT",
@@ -639,6 +716,8 @@ rand_core: 0.6.4, "Apache-2.0 OR MIT",
rand_core: 0.9.5, "Apache-2.0 OR MIT",
rand_core: 0.10.0, "Apache-2.0 OR MIT",
rand_xoshiro: 0.8.0, "Apache-2.0 OR MIT",
+rav1e: 0.8.1, "BSD-2-Clause",
+ravif: 0.12.0, "BSD-3-Clause",
raw-cpuid: 11.6.0, "MIT",
rayon: 1.11.0, "Apache-2.0 OR MIT",
rayon-core: 1.13.0, "Apache-2.0 OR MIT",
@@ -658,8 +737,10 @@ reqwest: 0.12.28, "Apache-2.0 OR MIT",
reqwest-middleware: 0.4.2, "Apache-2.0 OR MIT",
reqwest-retry: 0.8.0, "Apache-2.0 OR MIT",
reqwest-tracing: 0.5.8, "Apache-2.0 OR MIT",
+resvg: 0.45.1, "Apache-2.0 OR MIT",
retry-policies: 0.5.1, "Apache-2.0 OR MIT",
rfc6979: 0.4.0, "Apache-2.0 OR MIT",
+rgb: 0.8.52, "MIT",
ring: 0.17.14, "Apache-2.0 AND ISC",
ringbuffer: 0.16.0, "MIT",
rkyv: 0.7.46, "MIT",
@@ -671,6 +752,7 @@ rmp-serde: 1.3.1, "MIT",
roaring: 0.11.3, "Apache-2.0 OR MIT",
rolling-file: 0.2.0, "Apache-2.0 OR MIT",
route-recognizer: 0.3.1, "MIT",
+roxmltree: 0.20.0, "Apache-2.0 OR MIT",
rsa: 0.9.10, "Apache-2.0 OR MIT",
rust-embed: 8.11.0, "MIT",
rust-embed-impl: 8.11.0, "MIT",
@@ -680,6 +762,7 @@ rust_decimal: 1.40.0, "MIT",
rustc-hash: 2.1.1, "Apache-2.0 OR MIT",
rustc_version: 0.4.1, "Apache-2.0 OR MIT",
rusticata-macros: 4.1.0, "Apache-2.0 OR MIT",
+rustix: 0.38.44, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT",
rustix: 1.1.3, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT",
rustls: 0.23.36, "Apache-2.0 OR ISC OR MIT",
rustls-native-certs: 0.8.3, "Apache-2.0 OR ISC OR MIT",
@@ -689,6 +772,7 @@ rustls-platform-verifier: 0.6.2, "Apache-2.0 OR MIT",
rustls-platform-verifier-android: 0.1.1, "Apache-2.0 OR MIT",
rustls-webpki: 0.103.9, "ISC",
rustversion: 1.0.22, "Apache-2.0 OR MIT",
+rustybuzz: 0.20.1, "MIT",
ryu: 1.0.23, "Apache-2.0 OR BSL-1.0",
same-file: 1.0.6, "MIT OR Unlicense",
scc: 2.4.0, "Apache-2.0",
@@ -721,6 +805,7 @@ serde_repr: 0.1.20, "Apache-2.0 OR MIT",
serde_spanned: 0.6.9, "Apache-2.0 OR MIT",
serde_spanned: 1.0.4, "Apache-2.0 OR MIT",
serde_urlencoded: 0.7.1, "Apache-2.0 OR MIT",
+serde_v8: 0.260.0, "MIT",
serde_with: 3.16.1, "Apache-2.0 OR MIT",
serde_with_macros: 3.16.1, "Apache-2.0 OR MIT",
serde_yaml_ng: 0.10.0, "MIT",
@@ -737,11 +822,14 @@ signal-hook-registry: 1.4.8, "Apache-2.0 OR MIT",
signature: 2.2.0, "Apache-2.0 OR MIT",
simd-adler32: 0.3.8, "MIT",
simd-json: 0.17.0, "Apache-2.0 OR MIT",
+simd_helpers: 0.1.0, "MIT",
simdutf8: 0.1.5, "Apache-2.0 OR MIT",
simple_asn1: 0.6.3, "ISC",
+simplecss: 0.2.2, "Apache-2.0 OR MIT",
simulator: 0.1.0, "N/A",
siphasher: 1.0.2, "Apache-2.0 OR MIT",
slab: 0.4.12, "MIT",
+slotmap: 1.0.7, "Zlib",
smallvec: 1.15.1, "Apache-2.0 OR MIT",
smart-default: 0.7.1, "MIT",
smawk: 0.3.2, "MIT",
@@ -750,6 +838,7 @@ snafu-derive: 0.8.9, "Apache-2.0 OR MIT",
snap: 1.1.1, "BSD-3-Clause",
socket2: 0.5.10, "Apache-2.0 OR MIT",
socket2: 0.6.2, "Apache-2.0 OR MIT",
+sourcemap: 9.3.2, "BSD-3-Clause",
spin: 0.9.8, "MIT",
spinning_top: 0.3.0, "Apache-2.0 OR MIT",
spki: 0.7.3, "Apache-2.0 OR MIT",
@@ -763,6 +852,9 @@ sqlx-sqlite: 0.8.6, "Apache-2.0 OR MIT",
sse-stream: 0.2.1, "Apache-2.0 OR MIT",
stable_deref_trait: 1.2.1, "Apache-2.0 OR MIT",
static-toml: 1.3.0, "MIT",
+static_assertions: 1.1.0, "Apache-2.0 OR MIT",
+strict-num: 0.1.1, "MIT",
+stringcase: 0.4.0, "MIT",
stringprep: 0.1.5, "Apache-2.0 OR MIT",
strsim: 0.11.1, "MIT",
structmeta: 0.3.0, "Apache-2.0 OR MIT",
@@ -770,6 +862,7 @@ structmeta-derive: 0.3.0, "Apache-2.0 OR MIT",
strum: 0.27.2, "MIT",
strum_macros: 0.27.2, "MIT",
subtle: 2.6.1, "BSD-3-Clause",
+svgtypes: 0.15.3, "Apache-2.0 OR MIT",
syn: 1.0.109, "Apache-2.0 OR MIT",
syn: 2.0.115, "Apache-2.0 OR MIT",
sync_wrapper: 1.0.2, "Apache-2.0",
@@ -778,6 +871,8 @@ synstructure: 0.13.2, "MIT",
synthez: 0.4.0, "BlueOak-1.0.0",
synthez-codegen: 0.4.0, "BlueOak-1.0.0",
synthez-core: 0.4.0, "BlueOak-1.0.0",
+sys_traits: 0.1.24, "MIT",
+sys_traits_macros: 0.1.0, "MIT",
sysinfo: 0.37.2, "MIT",
sysinfo: 0.38.1, "MIT",
tagptr: 0.2.0, "Apache-2.0 OR MIT",
@@ -799,10 +894,13 @@ thiserror-impl: 1.0.69, "Apache-2.0 OR MIT",
thiserror-impl: 2.0.18, "Apache-2.0 OR MIT",
thread_local: 1.1.9, "Apache-2.0 OR MIT",
thrift: 0.17.0, "Apache-2.0",
+tiff: 0.10.3, "MIT",
time: 0.3.47, "Apache-2.0 OR MIT",
time-core: 0.1.8, "Apache-2.0 OR MIT",
time-macros: 0.2.27, "Apache-2.0 OR MIT",
tiny-keccak: 2.0.2, "CC0-1.0",
+tiny-skia: 0.11.4, "BSD-3-Clause",
+tiny-skia-path: 0.11.4, "BSD-3-Clause",
tinystr: 0.8.2, "Unicode-3.0",
tinyvec: 1.10.0, "Apache-2.0 OR MIT OR Zlib",
tinyvec_macros: 0.1.1, "Apache-2.0 OR MIT OR Zlib",
@@ -840,6 +938,7 @@ tracing-opentelemetry: 0.32.1, "MIT",
tracing-subscriber: 0.3.22, "MIT",
trait-variant: 0.1.2, "Apache-2.0 OR MIT",
try-lock: 0.2.5, "MIT",
+ttf-parser: 0.25.1, "Apache-2.0 OR MIT",
tungstenite: 0.28.0, "Apache-2.0 OR MIT",
twox-hash: 2.1.2, "MIT",
typed-builder: 0.20.1, "Apache-2.0 OR MIT",
@@ -853,11 +952,16 @@ ulid: 1.2.1, "MIT",
uncased: 0.9.10, "Apache-2.0 OR MIT",
unicase: 2.9.0, "Apache-2.0 OR MIT",
unicode-bidi: 0.3.18, "Apache-2.0 OR MIT",
+unicode-bidi-mirroring: 0.4.0, "Apache-2.0 OR MIT",
+unicode-ccc: 0.4.0, "Apache-2.0 OR MIT",
+unicode-id-start: 1.4.0, "(Apache-2.0 OR MIT) AND Unicode-3.0",
unicode-ident: 1.0.23, "(Apache-2.0 OR MIT) AND Unicode-3.0",
unicode-linebreak: 0.1.5, "Apache-2.0",
unicode-normalization: 0.1.25, "Apache-2.0 OR MIT",
unicode-properties: 0.1.4, "Apache-2.0 OR MIT",
+unicode-script: 0.5.8, "Apache-2.0 OR MIT",
unicode-segmentation: 1.12.0, "Apache-2.0 OR MIT",
+unicode-vo: 0.1.0, "Apache-2.0 OR MIT",
unicode-width: 0.1.14, "Apache-2.0 OR MIT",
unicode-width: 0.2.2, "Apache-2.0 OR MIT",
unicode-xid: 0.2.6, "Apache-2.0 OR MIT",
@@ -868,11 +972,14 @@ ureq: 3.2.0, "Apache-2.0 OR MIT",
ureq-proto: 0.5.3, "Apache-2.0 OR MIT",
url: 2.5.8, "Apache-2.0 OR MIT",
urlencoding: 2.1.3, "MIT",
+usvg: 0.45.1, "Apache-2.0 OR MIT",
utf-8: 0.7.6, "Apache-2.0 OR MIT",
utf8-width: 0.1.8, "MIT",
utf8_iter: 1.0.4, "Apache-2.0 OR MIT",
utf8parse: 0.2.2, "Apache-2.0 OR MIT",
uuid: 1.20.0, "Apache-2.0 OR MIT",
+v8: 137.3.0, "MIT",
+v_frame: 0.3.9, "BSD-2-Clause",
v_htmlescape: 0.15.8, "Apache-2.0 OR MIT",
valuable: 0.1.1, "MIT",
value-trait: 0.12.1, "Apache-2.0 OR MIT",
@@ -882,6 +989,7 @@ vergen-git2: 9.1.0, "Apache-2.0 OR MIT",
vergen-lib: 9.1.0, "Apache-2.0 OR MIT",
version_check: 0.9.5, "Apache-2.0 OR MIT",
void: 1.0.2, "MIT",
+vsimd: 0.8.0, "MIT",
wait-timeout: 0.2.1, "Apache-2.0 OR MIT",
walkdir: 2.5.0, "MIT OR Unlicense",
want: 0.3.1, "MIT",
@@ -897,6 +1005,7 @@ wasm-bindgen-shared: 0.2.108, "Apache-2.0 OR MIT",
wasm-encoder: 0.244.0, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT",
wasm-metadata: 0.244.0, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT",
wasm-streams: 0.4.2, "Apache-2.0 OR MIT",
+wasm_dep_analyzer: 0.3.0, "MIT",
wasmparser: 0.244.0, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT",
wasmtimer: 0.4.3, "MIT",
web-sys: 0.3.85, "Apache-2.0 OR MIT",
@@ -904,6 +1013,8 @@ web-time: 1.1.0, "Apache-2.0 OR MIT",
webpki-root-certs: 1.0.6, "CDLA-Permissive-2.0",
webpki-roots: 0.26.11, "CDLA-Permissive-2.0",
webpki-roots: 1.0.6, "CDLA-Permissive-2.0",
+weezl: 0.1.12, "Apache-2.0 OR MIT",
+which: 6.0.3, "MIT",
whoami: 1.6.1, "Apache-2.0 OR BSL-1.0 OR MIT",
widestring: 1.2.1, "Apache-2.0 OR MIT",
winapi: 0.3.9, "Apache-2.0 OR MIT",
@@ -972,6 +1083,7 @@ windows_x86_64_msvc: 0.52.6, "Apache-2.0 OR MIT",
windows_x86_64_msvc: 0.53.1, "Apache-2.0 OR MIT",
winnow: 0.5.40, "MIT",
winnow: 0.7.14, "MIT",
+winsafe: 0.0.19, "MIT",
wit-bindgen: 0.51.0, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT",
wit-bindgen-core: 0.51.0, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR
MIT",
wit-bindgen-rust: 0.51.0, "Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR
MIT",
@@ -982,6 +1094,8 @@ writeable: 0.6.2, "Unicode-3.0",
wyz: 0.5.1, "MIT",
x509-parser: 0.18.1, "Apache-2.0 OR MIT",
xattr: 1.6.1, "Apache-2.0 OR MIT",
+xmlwriter: 0.1.0, "MIT",
+y4m: 0.8.0, "MIT",
yansi: 1.0.1, "Apache-2.0 OR MIT",
yasna: 0.5.2, "Apache-2.0 OR MIT",
yew: 0.22.0, "Apache-2.0 OR MIT",
@@ -1006,3 +1120,8 @@ zopfli: 0.8.3, "Apache-2.0",
zstd: 0.13.3, "MIT",
zstd-safe: 7.2.4, "Apache-2.0 OR MIT",
zstd-sys: 2.0.16+zstd.1.5.7, "Apache-2.0 OR MIT",
+zune-core: 0.4.12, "Apache-2.0 OR MIT OR Zlib",
+zune-core: 0.5.1, "Apache-2.0 OR MIT OR Zlib",
+zune-inflate: 0.2.54, "Apache-2.0 OR MIT OR Zlib",
+zune-jpeg: 0.4.21, "Apache-2.0 OR MIT OR Zlib",
+zune-jpeg: 0.5.12, "Apache-2.0 OR MIT OR Zlib",
diff --git a/core/bench/dashboard/README.md b/core/bench/dashboard/README.md
index 4c810fdce..90ac5e8f3 100644
--- a/core/bench/dashboard/README.md
+++ b/core/bench/dashboard/README.md
@@ -169,10 +169,10 @@ All endpoints return JSON responses (except artifacts
which returns a ZIP file)
### Development Mode
-Run the development script to start both the frontend and backend servers:
+Run the development script from root of `apache/iggy` repository to start both
the frontend and backend servers:
```bash
-./scripts/run_dev.sh
+./scripts/dashboard/run_dev.sh
```
This will start:
diff --git a/core/bench/dashboard/frontend/Cargo.toml
b/core/bench/dashboard/frontend/Cargo.toml
index 7e02e1e71..0cdbb2f10 100644
--- a/core/bench/dashboard/frontend/Cargo.toml
+++ b/core/bench/dashboard/frontend/Cargo.toml
@@ -18,7 +18,7 @@
[package]
name = "bench-dashboard-frontend"
license = "Apache-2.0"
-version = "0.5.1-edge.1"
+version = "0.5.2-edge.1"
edition = "2024"
[package.metadata.cargo-machete]
diff --git a/core/bench/dashboard/frontend/assets/style.css
b/core/bench/dashboard/frontend/assets/style.css
index 327765fca..8a82cce6c 100644
--- a/core/bench/dashboard/frontend/assets/style.css
+++ b/core/bench/dashboard/frontend/assets/style.css
@@ -1737,3 +1737,142 @@ body.dark
.benchmark-list-item-metric.message-throughput {
display: inline-block;
margin-right: var(--spacing-md);
}
+
+/* Embed Modal */
+
+.embed-modal {
+ position: absolute;
+ left: 0;
+ top: calc(100% + var(--spacing-md));
+ transform: none;
+ background: var(--color-background);
+ border: 1px solid var(--color-border);
+ border-radius: var(--border-radius);
+ padding: var(--spacing-md);
+ min-width: 420px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+ z-index: 1000;
+}
+
+.embed-modal:before {
+ content: '';
+ position: absolute;
+ left: var(--spacing-md);
+ top: -8px;
+ width: 16px;
+ height: 16px;
+ background: var(--color-background);
+ border: 1px solid var(--color-border);
+ border-right: none;
+ border-bottom: none;
+ transform: rotate(45deg);
+ z-index: -1;
+}
+
+.embed-modal:after {
+ content: '';
+ position: absolute;
+ left: var(--spacing-md);
+ top: -7px;
+ width: 16px;
+ height: 16px;
+ background: var(--color-background);
+ transform: rotate(45deg);
+}
+
+.dark .embed-modal {
+ background: var(--color-dark-tooltip-background);
+ border-color: var(--color-dark-border);
+ color: var(--color-dark-text);
+}
+
+.dark .embed-modal:before {
+ background: var(--color-dark-tooltip-background);
+ border-color: var(--color-dark-border);
+}
+
+.dark .embed-modal:after {
+ background: var(--color-dark-tooltip-background);
+}
+
+.embed-snippet {
+ word-break: break-all;
+}
+
+.embed-tabs {
+ display: flex;
+ gap: var(--spacing-xs);
+ margin-bottom: var(--spacing-sm);
+}
+
+.embed-tab {
+ padding: var(--spacing-xs) var(--spacing-sm);
+ background: none;
+ border: 1px solid var(--color-border);
+ border-radius: var(--border-radius);
+ cursor: pointer;
+ font-size: var(--font-size-xs);
+ color: var(--color-text);
+ transition: all var(--transition-speed);
+}
+
+.embed-tab:hover {
+ background: var(--color-hover);
+}
+
+.embed-tab.active {
+ background: var(--color-active);
+ border-color: var(--color-text-secondary);
+}
+
+.dark .embed-tab {
+ color: var(--color-dark-text);
+ border-color: var(--color-dark-border);
+}
+
+.dark .embed-tab:hover {
+ background: var(--color-dark-hover);
+}
+
+.dark .embed-tab.active {
+ background: var(--color-dark-hover);
+ border-color: var(--color-dark-accent);
+ color: var(--color-dark-accent);
+}
+
+.embed-download-row {
+ margin-top: var(--spacing-sm);
+}
+
+.embed-download-button {
+ width: 100%;
+}
+
+.embed-theme-hint {
+ font-size: 11px;
+ color: #888;
+ margin-top: 4px;
+ font-family: monospace;
+}
+
+.embed-format-toggle {
+ display: flex;
+ gap: 4px;
+ margin-bottom: 6px;
+}
+
+.embed-format-btn {
+ padding: 2px 8px;
+ font-size: 11px;
+ border: 1px solid #555;
+ border-radius: 3px;
+ background: transparent;
+ color: #aaa;
+ cursor: pointer;
+}
+
+.embed-format-btn.active {
+ background: #444;
+ color: #fff;
+ border-color: #777;
+}
diff --git a/core/bench/dashboard/frontend/src/components/embed_modal.rs
b/core/bench/dashboard/frontend/src/components/embed_modal.rs
new file mode 100644
index 000000000..9609eaec2
--- /dev/null
+++ b/core/bench/dashboard/frontend/src/components/embed_modal.rs
@@ -0,0 +1,205 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::components::selectors::measurement_type_selector::MeasurementType;
+use crate::config::get_api_base_url;
+use gloo::timers::callback::Timeout;
+use web_sys::window;
+use yew::prelude::*;
+
+#[derive(Clone, PartialEq)]
+enum EmbedTab {
+ Iframe,
+ Image,
+}
+
+#[derive(Clone, PartialEq)]
+enum ImageFormat {
+ Markdown,
+ Html,
+}
+
+#[derive(Properties, PartialEq)]
+pub struct EmbedModalProps {
+ pub uuid: String,
+ pub measurement_type: MeasurementType,
+ pub is_dark: bool,
+}
+
+#[function_component(EmbedModal)]
+pub fn embed_modal(props: &EmbedModalProps) -> Html {
+ let active_tab = use_state(|| EmbedTab::Iframe);
+ let image_format = use_state(|| ImageFormat::Markdown);
+ let notification_visible = use_state(|| false);
+
+ let chart_type = match &props.measurement_type {
+ MeasurementType::Latency => "latency",
+ MeasurementType::Throughput => "throughput",
+ MeasurementType::Distribution => "distribution",
+ };
+
+ let theme = if props.is_dark { "dark" } else { "light" };
+ let base_url = get_api_base_url();
+ let embed_url = format!(
+ "{base_url}/embed/{uuid}?type={chart_type}&theme={theme}",
+ uuid = props.uuid,
+ );
+ let benchmark_url = format!("{base_url}/benchmarks/{uuid}", uuid =
props.uuid);
+ let png_url = format!(
+
"{base_url}/embed/{uuid}/chart.png?type={chart_type}&theme={theme}&width=1600&height=1200&legend=true",
+ uuid = props.uuid,
+ );
+
+ let iframe_snippet =
+ format!(r#"<iframe src="{embed_url}" width="800" height="600"
frameborder="0"></iframe>"#);
+
+ let markdown_snippet = format!("[]({benchmark_url})");
+ let html_image_snippet = format!(
+ r#"<a href="{benchmark_url}"><img src="{png_url}" alt="Iggy Benchmark"
width="800"></a>"#
+ );
+
+ let snippet = match *active_tab {
+ EmbedTab::Iframe => iframe_snippet.clone(),
+ EmbedTab::Image => match *image_format {
+ ImageFormat::Markdown => markdown_snippet.clone(),
+ ImageFormat::Html => html_image_snippet.clone(),
+ },
+ };
+
+ let on_copy = {
+ let snippet = snippet.clone();
+ let notification_visible = notification_visible.clone();
+ Callback::from(move |_| {
+ if let Some(window) = window() {
+ let clipboard = window.navigator().clipboard();
+ let _ = clipboard.write_text(&snippet);
+ notification_visible.set(true);
+
+ let notification_visible = notification_visible.clone();
+ let timeout = Timeout::new(1_000, move || {
+ notification_visible.set(false);
+ });
+ timeout.forget();
+ }
+ })
+ };
+
+ let on_download = {
+ let png_url = png_url.clone();
+ Callback::from(move |_| {
+ if let Some(window) = window() {
+ let _ = window.open_with_url_and_target(&png_url, "_blank");
+ }
+ })
+ };
+
+ let on_iframe_tab = {
+ let active_tab = active_tab.clone();
+ Callback::from(move |_| active_tab.set(EmbedTab::Iframe))
+ };
+
+ let on_image_tab = {
+ let active_tab = active_tab.clone();
+ Callback::from(move |_| active_tab.set(EmbedTab::Image))
+ };
+
+ let on_markdown_format = {
+ let image_format = image_format.clone();
+ Callback::from(move |_| image_format.set(ImageFormat::Markdown))
+ };
+
+ let on_html_format = {
+ let image_format = image_format.clone();
+ Callback::from(move |_| image_format.set(ImageFormat::Html))
+ };
+
+ html! {
+ <div class="embed-modal">
+ <div class="tooltip-section">
+ <h4>{"Embed Chart"}</h4>
+ <div class="embed-tabs">
+ <button
+ class={classes!("embed-tab", (*active_tab ==
EmbedTab::Iframe).then_some("active"))}
+ onclick={on_iframe_tab}
+ >
+ {"Iframe"}
+ </button>
+ <button
+ class={classes!("embed-tab", (*active_tab ==
EmbedTab::Image).then_some("active"))}
+ onclick={on_image_tab}
+ >
+ {"Image"}
+ </button>
+ </div>
+ {
+ if *active_tab == EmbedTab::Image {
+ html! {
+ <div class="embed-format-toggle">
+ <button
+ class={classes!("embed-format-btn",
(*image_format == ImageFormat::Markdown).then_some("active"))}
+ onclick={on_markdown_format}
+ >
+ {"Markdown"}
+ </button>
+ <button
+ class={classes!("embed-format-btn",
(*image_format == ImageFormat::Html).then_some("active"))}
+ onclick={on_html_format}
+ >
+ {"HTML"}
+ </button>
+ </div>
+ }
+ } else {
+ html! {}
+ }
+ }
+ <div class="tooltip-content">
+ <p class="command-row">
+ <span class="command-text
embed-snippet">{&snippet}</span>
+ <span class="copy-button-container">
+ <button onclick={on_copy}
class="copy-button">{"Copy"}</button>
+ <span class={classes!(
+ "copy-notification",
+ (*notification_visible).then_some("visible")
+ )}>
+ {"Copied!"}
+ </span>
+ </span>
+ </p>
+ {
+ if *active_tab == EmbedTab::Image {
+ html! {
+ <>
+ <p class="embed-download-row">
+ <button onclick={on_download}
class="copy-button embed-download-button">
+ {"Download PNG"}
+ </button>
+ </p>
+ <p class="embed-theme-hint">
+ {"Themes: dark, light, dark_nobg,
light_nobg"}
+ </p>
+ </>
+ }
+ } else {
+ html! {}
+ }
+ }
+ </div>
+ </div>
+ </div>
+ }
+}
diff --git a/core/bench/dashboard/frontend/src/components/layout/topbar.rs
b/core/bench/dashboard/frontend/src/components/layout/topbar.rs
index c6ec04efa..49368d24f 100644
--- a/core/bench/dashboard/frontend/src/components/layout/topbar.rs
+++ b/core/bench/dashboard/frontend/src/components/layout/topbar.rs
@@ -16,6 +16,7 @@
// under the License.
use crate::api;
+use crate::components::embed_modal::EmbedModal;
use crate::components::selectors::measurement_type_selector::MeasurementType;
use crate::components::theme::theme_toggle::ThemeToggle;
use crate::components::tooltips::benchmark_info_toggle::BenchmarkInfoToggle;
@@ -89,6 +90,13 @@ pub fn topbar(props: &TopBarProps) -> Html {
})
};
+ let on_embed_toggle = {
+ let ui_state = ui_state.clone();
+ Callback::from(move |_| {
+ ui_state.dispatch(UiAction::ToggleEmbedModal);
+ })
+ };
+
html! {
<div class="top-buttons">
<div class="controls">
@@ -112,6 +120,39 @@ pub fn topbar(props: &TopBarProps) -> Html {
<line x1="12" y1="15" x2="12" y2="3"/>
</svg>
</button>
+ <div class="info-container">
+ <button
+ class={classes!(
+ "icon-button",
+
ui_state.is_embed_modal_visible.then_some("active")
+ )}
+ onclick={on_embed_toggle.clone()}
+ title="Embed Chart"
+
disabled={benchmark_ctx.state.selected_benchmark.is_none()}
+ >
+ <svg
xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round">
+ <polyline points="16 18 22 12 16
6"/>
+ <polyline points="8 6 2 12 8 18"/>
+ </svg>
+ </button>
+ {
+ if ui_state.is_embed_modal_visible {
+ if let Some(benchmark) =
&benchmark_ctx.state.selected_benchmark {
+ html! {
+ <EmbedModal
+
uuid={benchmark.uuid.to_string()}
+
measurement_type={selected_measurement.clone()}
+ is_dark={props.is_dark}
+ />
+ }
+ } else {
+ html! {}
+ }
+ } else {
+ html! {}
+ }
+ }
+ </div>
<div class="info-container">
<ServerStatsToggle
is_visible={is_server_stats_tooltip_visible}
diff --git a/core/bench/dashboard/frontend/src/components/mod.rs
b/core/bench/dashboard/frontend/src/components/mod.rs
index d923c72b0..0781daaf9 100644
--- a/core/bench/dashboard/frontend/src/components/mod.rs
+++ b/core/bench/dashboard/frontend/src/components/mod.rs
@@ -17,7 +17,7 @@
pub mod app_content;
pub mod chart;
-// pub mod common; // Removed unused module
+pub mod embed_modal;
pub mod footer;
pub mod layout;
pub mod selectors;
diff --git a/core/bench/dashboard/frontend/src/state/ui.rs
b/core/bench/dashboard/frontend/src/state/ui.rs
index 0a7b691dc..57c0146d1 100644
--- a/core/bench/dashboard/frontend/src/state/ui.rs
+++ b/core/bench/dashboard/frontend/src/state/ui.rs
@@ -33,6 +33,7 @@ pub struct UiState {
pub selected_measurement: MeasurementType,
pub is_benchmark_tooltip_visible: bool,
pub is_server_stats_tooltip_visible: bool,
+ pub is_embed_modal_visible: bool,
}
impl Default for UiState {
@@ -42,6 +43,7 @@ impl Default for UiState {
selected_measurement: MeasurementType::Latency,
is_benchmark_tooltip_visible: false,
is_server_stats_tooltip_visible: false,
+ is_embed_modal_visible: false,
}
}
}
@@ -50,6 +52,7 @@ pub enum UiAction {
SetMeasurementType(MeasurementType),
ToggleBenchmarkTooltip,
ToggleServerStatsTooltip,
+ ToggleEmbedModal,
SetViewMode(ViewMode),
}
@@ -70,6 +73,10 @@ impl Reducible for UiState {
is_server_stats_tooltip_visible:
!self.is_server_stats_tooltip_visible,
..(*self).clone()
},
+ UiAction::ToggleEmbedModal => UiState {
+ is_embed_modal_visible: !self.is_embed_modal_visible,
+ ..(*self).clone()
+ },
UiAction::SetViewMode(vm) => UiState {
view_mode: vm,
..(*self).clone()
diff --git a/core/bench/dashboard/server/Cargo.toml
b/core/bench/dashboard/server/Cargo.toml
index 4ec3e5a24..f29ad2194 100644
--- a/core/bench/dashboard/server/Cargo.toml
+++ b/core/bench/dashboard/server/Cargo.toml
@@ -18,7 +18,7 @@
[package]
name = "iggy-bench-dashboard-server"
license = "Apache-2.0"
-version = "0.6.1-edge.1"
+version = "0.6.2-edge.1"
edition = "2024"
[dependencies]
@@ -27,6 +27,7 @@ actix-files = { workspace = true }
actix-web = { workspace = true }
bench-dashboard-shared = { workspace = true }
bench-report = { workspace = true }
+charming = { workspace = true, features = ["ssr", "ssr-raster"] }
chrono = { workspace = true, features = ["serde"] }
clap = { workspace = true }
dashmap = { workspace = true }
diff --git a/core/bench/dashboard/server/src/cache/loader.rs
b/core/bench/dashboard/server/src/cache/loader.rs
index 5dbff1170..e13217f4e 100644
--- a/core/bench/dashboard/server/src/cache/loader.rs
+++ b/core/bench/dashboard/server/src/cache/loader.rs
@@ -35,6 +35,7 @@ impl BenchmarkCache {
.map_err(IggyBenchDashboardServerError::Io)?
.filter_map(|r: std::result::Result<std::fs::DirEntry,
std::io::Error>| r.ok())
.filter(|entry| entry.file_type().map(|t|
t.is_dir()).unwrap_or(false))
+ .filter(|entry| entry.file_name() != "embed_cache")
.collect();
let mut total_removed_size = 0;
diff --git a/core/bench/dashboard/server/src/cache/storage.rs
b/core/bench/dashboard/server/src/cache/storage.rs
index 6c1186707..4328fe8e2 100644
--- a/core/bench/dashboard/server/src/cache/storage.rs
+++ b/core/bench/dashboard/server/src/cache/storage.rs
@@ -51,6 +51,10 @@ impl BenchmarkCache {
.map(|entry| entry.value().0.clone())
}
+ pub fn results_dir(&self) -> &std::path::Path {
+ &self.results_dir
+ }
+
pub(crate) fn clear(&self) {
self.benchmarks.clear();
self.hardware_to_gitref.clear();
diff --git a/core/bench/dashboard/server/src/cache/watcher.rs
b/core/bench/dashboard/server/src/cache/watcher.rs
index c5e6e622c..b3c98bcdd 100644
--- a/core/bench/dashboard/server/src/cache/watcher.rs
+++ b/core/bench/dashboard/server/src/cache/watcher.rs
@@ -43,6 +43,13 @@ impl CacheWatcher {
event.kind,
EventKind::Create(_) | EventKind::Modify(_) |
EventKind::Remove(_)
) {
+ let in_embed_cache = event
+ .paths
+ .iter()
+ .all(|p| p.components().any(|c| c.as_os_str() ==
"embed_cache"));
+ if in_embed_cache {
+ return;
+ }
let cache = Arc::clone(&cache_clone);
runtime_handle.spawn(async move {
cache.schedule_reload().await;
diff --git a/core/bench/dashboard/server/src/error.rs
b/core/bench/dashboard/server/src/error.rs
index 9af924a5f..1a9c4d92b 100644
--- a/core/bench/dashboard/server/src/error.rs
+++ b/core/bench/dashboard/server/src/error.rs
@@ -31,6 +31,8 @@ pub enum IggyBenchDashboardServerError {
InvalidJson(String),
#[error("Invalid UUID format: {0}")]
InvalidUuid(String),
+ #[error("Bad request: {0}")]
+ BadRequest(String),
#[error("Internal error: {0}")]
InternalError(String),
}
@@ -41,6 +43,10 @@ impl ResponseError for IggyBenchDashboardServerError {
IggyBenchDashboardServerError::NotFound(msg) => {
HttpResponse::NotFound().json(json!({ "error": msg }))
}
+ IggyBenchDashboardServerError::InvalidUuid(msg)
+ | IggyBenchDashboardServerError::BadRequest(msg) => {
+ HttpResponse::BadRequest().json(json!({ "error": msg }))
+ }
_ => HttpResponse::InternalServerError().json(json!({ "error":
self.to_string() })),
}
}
diff --git a/core/bench/dashboard/server/src/handlers.rs
b/core/bench/dashboard/server/src/handlers.rs
index 44c6bca45..d2f5f7b7a 100644
--- a/core/bench/dashboard/server/src/handlers.rs
+++ b/core/bench/dashboard/server/src/handlers.rs
@@ -15,8 +15,11 @@
// specific language governing permissions and limitations
// under the License.
+use crate::render::PngRenderPool;
use crate::{cache::BenchmarkCache, error::IggyBenchDashboardServerError};
use actix_web::{HttpRequest, HttpResponse, get, web};
+use serde::Deserialize;
+use std::path::PathBuf;
use std::sync::Arc;
use tracing::{info, warn};
use uuid::Uuid;
@@ -27,6 +30,7 @@ type Result<T> = std::result::Result<T,
IggyBenchDashboardServerError>;
pub struct AppState {
pub cache: Arc<BenchmarkCache>,
+ pub render_pool: Arc<PngRenderPool>,
}
#[get("/health")]
@@ -363,6 +367,452 @@ pub async fn get_recent_benchmarks(
Ok(HttpResponse::Ok().json(benchmarks))
}
+fn default_chart_type() -> String {
+ "latency".to_string()
+}
+
+fn default_theme() -> String {
+ "dark".to_string()
+}
+
+const DEFAULT_PNG_WIDTH: u32 = 1600;
+const DEFAULT_PNG_HEIGHT: u32 = 1200;
+
+fn default_png_width() -> u32 {
+ DEFAULT_PNG_WIDTH
+}
+
+fn default_png_height() -> u32 {
+ DEFAULT_PNG_HEIGHT
+}
+
+fn default_legend() -> bool {
+ true
+}
+
+#[derive(Deserialize)]
+pub struct EmbedQuery {
+ #[serde(rename = "type", default = "default_chart_type")]
+ pub chart_type: String,
+ #[serde(default = "default_theme")]
+ pub theme: String,
+ pub action: Option<String>,
+}
+
+#[derive(Deserialize)]
+pub struct PngQuery {
+ #[serde(rename = "type", default = "default_chart_type")]
+ pub chart_type: String,
+ #[serde(default = "default_theme")]
+ pub theme: String,
+ #[serde(default = "default_png_width")]
+ pub width: u32,
+ #[serde(default = "default_png_height")]
+ pub height: u32,
+ #[serde(default = "default_legend")]
+ pub legend: bool,
+}
+
+fn png_cache_path(cache_dir: &std::path::Path, uuid: &Uuid, query: &PngQuery)
-> PathBuf {
+ let legend_suffix = if query.legend { "" } else { "_nolegend" };
+ let filename = format!(
+ "{uuid}_{chart_type}_{w}x{h}_{theme}{legend_suffix}.png",
+ uuid = uuid,
+ chart_type = query.chart_type,
+ w = query.width,
+ h = query.height,
+ theme = query.theme,
+ );
+ cache_dir.join(filename)
+}
+
+#[get("/embed/{uuid}/chart.png")]
+pub async fn embed_chart_png(
+ data: web::Data<AppState>,
+ uuid_str: web::Path<String>,
+ query: web::Query<PngQuery>,
+ req: HttpRequest,
+) -> Result<HttpResponse> {
+ let client_addr = get_client_addr(&req);
+ info!(
+ "{}: Embed PNG request for '{}' (type={}, theme={}, {}x{})",
+ client_addr, uuid_str, query.chart_type, query.theme, query.width,
query.height
+ );
+
+ let uuid = Uuid::parse_str(&uuid_str).map_err(|_| {
+ IggyBenchDashboardServerError::InvalidUuid(format!("Invalid UUID
format: '{uuid_str}'"))
+ })?;
+
+ let chart_type = &query.chart_type;
+ if chart_type != "latency" && chart_type != "throughput" && chart_type !=
"distribution" {
+ return Err(IggyBenchDashboardServerError::BadRequest(format!(
+ "Invalid chart type: '{chart_type}'. Must be 'latency',
'throughput', or 'distribution'"
+ )));
+ }
+
+ let cache_dir = data.cache.results_dir().join("embed_cache");
+ let cached_path = png_cache_path(&cache_dir, &uuid, &query);
+
+ if cached_path.exists() {
+ info!("{}: Serving cached PNG for '{}'", client_addr, uuid_str);
+ let bytes = std::fs::read(&cached_path).map_err(|e| {
+ IggyBenchDashboardServerError::InternalError(format!("Failed to
read cached PNG: {e}"))
+ })?;
+ return Ok(HttpResponse::Ok().content_type("image/png").body(bytes));
+ }
+
+ let json_path = data.cache.get_benchmark_json_path(&uuid).ok_or_else(|| {
+ IggyBenchDashboardServerError::NotFound(format!("Benchmark
'{uuid_str}' not found"))
+ })?;
+
+ let json_content = std::fs::read_to_string(&json_path).map_err(|e| {
+ IggyBenchDashboardServerError::InternalError(format!(
+ "Failed to read report file '{}': {}",
+ json_path.display(),
+ e
+ ))
+ })?;
+
+ let report: bench_report::report::BenchmarkReport =
serde_json::from_str(&json_content)
+ .map_err(|e| {
+ IggyBenchDashboardServerError::InternalError(format!(
+ "Failed to deserialize report: {e}"
+ ))
+ })?;
+
+ let theme = &query.theme;
+ let is_dark = theme == "dark" || theme == "dark_nobg";
+ let transparent = theme == "dark_nobg" || theme == "light_nobg";
+
+ if !matches!(
+ theme.as_str(),
+ "dark" | "light" | "dark_nobg" | "light_nobg"
+ ) {
+ return Err(IggyBenchDashboardServerError::BadRequest(format!(
+ "Invalid theme: '{theme}'. Must be 'dark', 'light', 'dark_nobg',
or 'light_nobg'"
+ )));
+ }
+
+ let hardware_line = format!(
+ "{} @ {} (server {})",
+ report
+ .hardware
+ .identifier
+ .as_deref()
+ .unwrap_or("identifier"),
+ report.hardware.cpu_name,
+ report.params.gitref.as_deref().unwrap_or("version")
+ );
+
+ let chart = if chart_type == "latency" {
+ bench_report::create_latency_chart(&report, is_dark, false)
+ } else if chart_type == "throughput" {
+ bench_report::create_throughput_chart(&report, is_dark, false)
+ } else {
+ bench_report::create_latency_distribution_chart(&report, is_dark,
false)
+ };
+
+ // Strip interactive-only components and adapt layout for static PNG
+ let mut chart_value = serde_json::to_value(&chart).map_err(|e| {
+ IggyBenchDashboardServerError::InternalError(format!(
+ "Failed to serialize chart for PNG: {e}"
+ ))
+ })?;
+ if let Some(obj) = chart_value.as_object_mut() {
+ obj.remove("dataZoom");
+ obj.insert("toolbox".to_string(), serde_json::json!({ "show": false
}));
+ let series_count = obj
+ .get("series")
+ .and_then(|s| s.as_array())
+ .map(|s| s.len())
+ .unwrap_or(0);
+ if transparent {
+ obj.insert(
+ "backgroundColor".to_string(),
+ serde_json::json!("transparent"),
+ );
+ } else if !is_dark {
+ obj.insert("backgroundColor".to_string(),
serde_json::json!("#ffffff"));
+ }
+ // Scale text relative to image dimensions (baseline: 1200x800)
+ let scale = (query.width as f64 / 1200.0).min(query.height as f64 /
800.0);
+ if let Some(t) = obj
+ .get_mut("title")
+ .and_then(|t| t.as_array_mut())
+ .and_then(|titles| titles.first_mut())
+ .and_then(|t| t.as_object_mut())
+ {
+ // Prepend hardware identifier to existing subtext
+ if let Some(existing) = t.get("subtext").and_then(|s| s.as_str()) {
+ t.insert(
+ "subtext".to_string(),
+ serde_json::json!(format!("{hardware_line}\n{existing}")),
+ );
+ }
+ t.insert(
+ "subtextStyle".to_string(),
+ serde_json::json!({
+ "fontSize": (10.0 * scale).round() as u32,
+ "lineHeight": (14.0 * scale).round() as u32,
+ }),
+ );
+ t.insert(
+ "textStyle".to_string(),
+ serde_json::json!({ "fontSize": (16.0 * scale).round() as u32
}),
+ );
+ }
+ if let Some(g) = obj
+ .get_mut("grid")
+ .and_then(|g| g.as_array_mut())
+ .and_then(|grids| grids.first_mut())
+ .and_then(|g| g.as_object_mut())
+ {
+ g.insert("left".to_string(), serde_json::json!("12%"));
+ g.insert("top".to_string(), serde_json::json!("20%"));
+ g.insert("bottom".to_string(), serde_json::json!("10%"));
+ if !query.legend {
+ g.insert("right".to_string(), serde_json::json!("10%"));
+ } else if series_count > 20 {
+ g.insert("right".to_string(), serde_json::json!("25%"));
+ }
+ }
+ if !query.legend {
+ obj.remove("legend");
+ } else if let Some(leg) = obj
+ .get_mut("legend")
+ .and_then(|l| l.as_array_mut())
+ .and_then(|legends| legends.first_mut())
+ .and_then(|l| l.as_object_mut())
+ {
+ {
+ let available_height = query.height as f64 * 0.75;
+ let entry_height = available_height / series_count.max(1) as
f64;
+ let font_size = (entry_height * 0.55).clamp(6.0, 10.0 *
scale).round() as u32;
+ let item_gap = (entry_height * 0.2).clamp(1.0, 10.0).round()
as u32;
+ let item_height = font_size.max(4);
+ let item_width = (item_height as f64 * 1.5).round() as u32;
+
+ leg.insert(
+ "textStyle".to_string(),
+ serde_json::json!({ "fontSize": font_size }),
+ );
+ leg.insert("itemGap".to_string(), serde_json::json!(item_gap));
+ leg.insert("itemWidth".to_string(),
serde_json::json!(item_width));
+ leg.insert("itemHeight".to_string(),
serde_json::json!(item_height));
+ }
+ }
+ }
+ let chart: charming::Chart =
serde_json::from_value(chart_value).map_err(|e| {
+ IggyBenchDashboardServerError::InternalError(format!(
+ "Failed to rebuild chart for PNG: {e}"
+ ))
+ })?;
+
+ let png_bytes = data
+ .render_pool
+ .render_png(chart, query.width, query.height, is_dark)
+ .await
+ .map_err(IggyBenchDashboardServerError::InternalError)?;
+
+ std::fs::create_dir_all(&cache_dir).map_err(|e| {
+ IggyBenchDashboardServerError::InternalError(format!(
+ "Failed to create embed cache directory: {e}"
+ ))
+ })?;
+ if let Err(e) = std::fs::write(&cached_path, &png_bytes) {
+ warn!("Failed to cache PNG to {}: {}", cached_path.display(), e);
+ }
+
+ info!(
+ "{}: Generated and cached PNG for '{}' ({}x{})",
+ client_addr, uuid_str, query.width, query.height
+ );
+
+ Ok(HttpResponse::Ok().content_type("image/png").body(png_bytes))
+}
+
+#[get("/embed/{uuid}")]
+pub async fn embed_chart(
+ data: web::Data<AppState>,
+ uuid_str: web::Path<String>,
+ query: web::Query<EmbedQuery>,
+ req: HttpRequest,
+) -> Result<HttpResponse> {
+ let client_addr = get_client_addr(&req);
+ info!(
+ "{}: Embed chart request for '{}' (type={}, theme={})",
+ client_addr, uuid_str, query.chart_type, query.theme
+ );
+
+ let uuid = Uuid::parse_str(&uuid_str).map_err(|_| {
+ IggyBenchDashboardServerError::InvalidUuid(format!("Invalid UUID
format: '{uuid_str}'"))
+ })?;
+
+ let is_dark = query.theme != "light";
+ let chart_type = &query.chart_type;
+ if chart_type != "latency" && chart_type != "throughput" && chart_type !=
"distribution" {
+ return Err(IggyBenchDashboardServerError::BadRequest(format!(
+ "Invalid chart type: '{chart_type}'. Must be 'latency',
'throughput', or 'distribution'"
+ )));
+ }
+
+ let json_path = data.cache.get_benchmark_json_path(&uuid).ok_or_else(|| {
+ IggyBenchDashboardServerError::NotFound(format!("Benchmark
'{uuid_str}' not found"))
+ })?;
+
+ let json_content = std::fs::read_to_string(&json_path).map_err(|e| {
+ IggyBenchDashboardServerError::InternalError(format!(
+ "Failed to read report file '{}': {}",
+ json_path.display(),
+ e
+ ))
+ })?;
+
+ let report: bench_report::report::BenchmarkReport =
serde_json::from_str(&json_content)
+ .map_err(|e| {
+ IggyBenchDashboardServerError::InternalError(format!(
+ "Failed to deserialize report: {e}"
+ ))
+ })?;
+
+ let hardware_line = format!(
+ "{} @ {} (server {})",
+ report
+ .hardware
+ .identifier
+ .as_deref()
+ .unwrap_or("identifier"),
+ report.hardware.cpu_name,
+ report.params.gitref.as_deref().unwrap_or("version")
+ );
+
+ let chart = if chart_type == "latency" {
+ bench_report::create_latency_chart(&report, is_dark, false)
+ } else if chart_type == "throughput" {
+ bench_report::create_throughput_chart(&report, is_dark, false)
+ } else {
+ bench_report::create_latency_distribution_chart(&report, is_dark,
false)
+ };
+
+ let chart_json = serde_json::to_string(&chart).map_err(|e| {
+ IggyBenchDashboardServerError::InternalError(format!(
+ "Failed to serialize chart to JSON: {e}"
+ ))
+ })?;
+
+ let is_download = query.action.as_deref() == Some("download");
+ let bg_color = if is_dark { "#070C18" } else { "#ffffff" };
+
+ let hardware_line_js = hardware_line.replace('\\', "\\\\").replace('\'',
"\\'");
+ let adapt_layout_js = format!(
+ r#"
+ var hardwareLine = '{hardware_line_js}';
+ function adaptLayout() {{
+ var w = window.innerWidth;
+ var h = window.innerHeight;
+ var scale = Math.min(w / 1000, h / 600);
+
+ if (option.title && option.title.length) {{
+ var t = option.title[0];
+ t.textStyle = Object.assign(t.textStyle || {{}}, {{ fontSize:
Math.round(18 * scale) }});
+ if (t.subtext && t.subtext.indexOf(hardwareLine) === -1) {{
+ t.subtext = hardwareLine + '\n' + t.subtext;
+ }}
+ if (t.subtext) {{
+ t.subtextStyle = Object.assign(t.subtextStyle || {{}}, {{
+ fontSize: Math.round(11 * scale),
+ lineHeight: Math.round(15 * scale)
+ }});
+ }}
+ }}
+ if (option.grid && option.grid.length) {{
+ option.grid[0].top = '18%';
+ option.grid[0].left = '8%';
+ option.grid[0].bottom = '14%';
+ }}
+ if (option.dataZoom && option.dataZoom.length) {{
+ option.dataZoom[0].bottom = '3%';
+ }}
+ if (option.legend && option.legend.length) {{
+ option.legend[0].textStyle = Object.assign(option.legend[0].textStyle ||
{{}}, {{
+ fontSize: Math.round(10 * scale)
+ }});
+ }}
+
+ chart.setOption(option);
+ chart.resize();
+ }}"#
+ );
+
+ let html = if is_download {
+ format!(
+ r#"<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<title>Downloading chart...</title>
+<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
+<style>
+ * {{ margin: 0; padding: 0; box-sizing: border-box; }}
+ body {{ background: transparent; }}
+ #chart {{ width: 1200px; height: 800px; }}
+ #status {{ position: fixed; top: 50%; left: 50%; transform: translate(-50%,
-50%);
+ font-family: sans-serif; color: #888; font-size: 16px; }}
+</style>
+</head>
+<body>
+<div id="chart"></div>
+<div id="status">Generating PNG...</div>
+<script>
+ var chart = echarts.init(document.getElementById('chart'));
+ var option = {chart_json};
+ {adapt_layout_js}
+ adaptLayout();
+ chart.on('finished', function() {{
+ var url = chart.getDataURL({{ type: 'png', pixelRatio: 2, backgroundColor:
'rgba(0,0,0,0)' }});
+ var a = document.createElement('a');
+ a.href = url;
+ a.download = '{uuid_str}_{chart_type}.png';
+ document.body.appendChild(a);
+ a.click();
+ document.getElementById('status').textContent = 'Download started. You can
close this tab.';
+ }});
+</script>
+</body>
+</html>"#
+ )
+ } else {
+ format!(
+ r#"<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Iggy Benchmark Chart</title>
+<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
+<style>
+ * {{ margin: 0; padding: 0; box-sizing: border-box; }}
+ body {{ background: {bg_color}; overflow: hidden; }}
+ #chart {{ width: 100%; height: 100vh; }}
+</style>
+</head>
+<body>
+<div id="chart"></div>
+<script>
+ var chart = echarts.init(document.getElementById('chart'));
+ var option = {chart_json};
+ {adapt_layout_js}
+ adaptLayout();
+ window.addEventListener('resize', function() {{ adaptLayout(); }});
+</script>
+</body>
+</html>"#
+ )
+ };
+
+ Ok(HttpResponse::Ok().content_type("text/html").body(html))
+}
+
fn get_client_addr(req: &HttpRequest) -> String {
req.connection_info()
.peer_addr()
diff --git a/core/bench/dashboard/server/src/main.rs
b/core/bench/dashboard/server/src/main.rs
index acbdf03ff..4e95afe0c 100644
--- a/core/bench/dashboard/server/src/main.rs
+++ b/core/bench/dashboard/server/src/main.rs
@@ -20,6 +20,7 @@ mod cache;
mod error;
mod github;
mod handlers;
+mod render;
use crate::cache::CacheWatcher;
use actix_cors::Cors;
@@ -47,6 +48,7 @@ use tracing_subscriber::{
struct ServerState {
cache: Arc<BenchmarkCache>,
_watcher: Arc<CacheWatcher>,
+ render_pool: Arc<render::PngRenderPool>,
}
async fn index() -> actix_web::Result<NamedFile> {
@@ -106,9 +108,12 @@ async fn main() -> Result<(), std::io::Error> {
None
};
+ let render_pool = Arc::new(render::PngRenderPool::default_pool());
+
let state = ServerState {
cache: Arc::clone(&cache),
_watcher: Arc::clone(&watcher),
+ render_pool,
};
info!("Starting server on {}", addr);
@@ -148,6 +153,7 @@ async fn main() -> Result<(), std::io::Error> {
.wrap(Compress::default())
.app_data(web::Data::new(AppState {
cache: Arc::clone(&state.cache),
+ render_pool: Arc::clone(&state.render_pool),
}))
.service(handlers::health_check)
.service(handlers::list_hardware)
@@ -159,6 +165,8 @@ async fn main() -> Result<(), std::io::Error> {
.service(handlers::get_benchmark_report_light)
.service(handlers::get_benchmark_trend)
.service(handlers::get_test_artifacts_zip)
+ .service(handlers::embed_chart_png)
+ .service(handlers::embed_chart)
.service(
fs::Files::new("/", "frontend/dist")
.index_file("index.html")
diff --git a/core/bench/dashboard/server/src/render.rs
b/core/bench/dashboard/server/src/render.rs
new file mode 100644
index 000000000..ff1d62f75
--- /dev/null
+++ b/core/bench/dashboard/server/src/render.rs
@@ -0,0 +1,93 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use charming::Chart;
+use charming::renderer::image_renderer::{ImageFormat, ImageRenderer};
+use charming::theme::Theme;
+use std::sync::mpsc;
+use tracing::info;
+
+struct RenderJob {
+ chart: Chart,
+ width: u32,
+ height: u32,
+ dark: bool,
+ reply: tokio::sync::oneshot::Sender<Result<Vec<u8>, String>>,
+}
+
+/// Dedicated render thread for PNG generation.
+///
+/// charming's SSR uses deno_core (V8) which has global state that is not
+/// safe to use from multiple OS threads. All rendering is pinned to a single
+/// thread; actix workers send jobs via channel and await results without
blocking.
+/// Disk caching ensures only the first request for a given chart incurs
render cost.
+pub struct PngRenderPool {
+ sender: mpsc::Sender<RenderJob>,
+}
+
+impl PngRenderPool {
+ pub fn new() -> Self {
+ let (tx, rx) = mpsc::channel::<RenderJob>();
+
+ std::thread::Builder::new()
+ .name("png-render".to_string())
+ .spawn(move || {
+ for job in rx {
+ let result = Self::render(&job.chart, job.width,
job.height, job.dark);
+ let _ = job.reply.send(result);
+ }
+ })
+ .expect("failed to spawn png render thread");
+
+ info!("PNG render thread started");
+ Self { sender: tx }
+ }
+
+ pub fn default_pool() -> Self {
+ Self::new()
+ }
+
+ fn render(chart: &Chart, width: u32, height: u32, dark: bool) ->
Result<Vec<u8>, String> {
+ let mut renderer = ImageRenderer::new(width, height);
+ if dark {
+ renderer = renderer.theme(Theme::Dark);
+ }
+ renderer
+ .render_format(ImageFormat::Png, chart)
+ .map_err(|e| format!("PNG render failed: {e}"))
+ }
+
+ pub async fn render_png(
+ &self,
+ chart: Chart,
+ width: u32,
+ height: u32,
+ dark: bool,
+ ) -> Result<Vec<u8>, String> {
+ let (tx, rx) = tokio::sync::oneshot::channel();
+ self.sender
+ .send(RenderJob {
+ chart,
+ width,
+ height,
+ dark,
+ reply: tx,
+ })
+ .map_err(|_| "render pool shut down".to_string())?;
+ rx.await.map_err(|_| "render worker dropped".to_string())?
+ }
+}
diff --git a/core/bench/report/src/plotting/chart.rs
b/core/bench/report/src/plotting/chart.rs
index 982212691..5a2e02d67 100644
--- a/core/bench/report/src/plotting/chart.rs
+++ b/core/bench/report/src/plotting/chart.rs
@@ -271,6 +271,7 @@ impl IggyChart {
.data(data)
.show_symbol(false)
.smooth(true)
+ .z(1)
.line_style(LineStyle::new().width(width))
.item_style(ItemStyle::new().color(color));