From a529e9af0c05f9f26278de26fd834abec9ecaef8 Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar Date: Fri, 13 Mar 2026 09:44:32 +0000 Subject: [PATCH] ci: consolidate CI into single job; fix sidebar footer (#14) --- .gitea/workflows/ci.yml | 102 ++++------------ README.md | 4 +- compliance-dashboard/assets/main.css | 115 +++++++++++++++++- .../src/components/sidebar.rs | 33 +++-- 4 files changed, 165 insertions(+), 89 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 785a911..d4b88bf 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -2,11 +2,9 @@ name: CI on: push: - branches: - - "**" - pull_request: branches: - main + pull_request: env: CARGO_TERM_COLOR: always @@ -23,10 +21,10 @@ concurrency: jobs: # --------------------------------------------------------------------------- - # Stage 1: Code quality checks (run in parallel) + # Stage 1: Lint, audit, and test (single job to share cargo cache) # --------------------------------------------------------------------------- - fmt: - name: Format + check: + name: Check runs-on: docker container: image: rust:1.94-bookworm @@ -37,105 +35,59 @@ jobs: git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" git fetch --depth=1 origin "${GITHUB_SHA}" git checkout FETCH_HEAD - - run: rustup component add rustfmt - # Format check does not compile, so sccache is not needed here. - - run: cargo fmt --all --check - env: - RUSTC_WRAPPER: "" - - clippy: - name: Clippy - runs-on: docker - container: - image: rust:1.94-bookworm - steps: - - name: Checkout - run: | - git init - git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" - git fetch --depth=1 origin "${GITHUB_SHA}" - git checkout FETCH_HEAD - - name: Install sccache + - name: Install tools run: | + rustup component add rustfmt clippy curl -fsSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \ | tar xz --strip-components=1 -C /usr/local/bin/ sccache-v0.9.1-x86_64-unknown-linux-musl/sccache chmod +x /usr/local/bin/sccache - - run: rustup component add clippy - # Lint the agent (native only). + cargo install cargo-audit --locked + env: + RUSTC_WRAPPER: "" + + # Format (no compilation needed) + - name: Format + run: cargo fmt --all --check + env: + RUSTC_WRAPPER: "" + + # Clippy (compiles once, sccache reuses across feature sets) - name: Clippy (agent) run: cargo clippy -p compliance-agent -- -D warnings - # Lint the dashboard for both feature sets independently. - # sccache deduplicates shared crates between the two compilations. - name: Clippy (dashboard server) run: cargo clippy -p compliance-dashboard --features server --no-default-features -- -D warnings - name: Clippy (dashboard web) run: cargo clippy -p compliance-dashboard --features web --no-default-features -- -D warnings - name: Clippy (mcp) run: cargo clippy -p compliance-mcp -- -D warnings - - name: Show sccache stats - run: sccache --show-stats - if: always() - audit: - name: Security Audit - runs-on: docker - if: github.ref == 'refs/heads/main' - container: - image: rust:1.94-bookworm - steps: - - name: Checkout - run: | - git init - git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" - git fetch --depth=1 origin "${GITHUB_SHA}" - git checkout FETCH_HEAD - - run: cargo install cargo-audit - env: - RUSTC_WRAPPER: "" - - run: cargo audit + # Security audit + - name: Security Audit + run: cargo audit env: RUSTC_WRAPPER: "" - # --------------------------------------------------------------------------- - # Stage 2: Tests (only after all quality checks pass) - # --------------------------------------------------------------------------- - test: - name: Tests - runs-on: docker - needs: [fmt, clippy, audit] - container: - image: rust:1.94-bookworm - steps: - - name: Checkout - run: | - git init - git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" - git fetch --depth=1 origin "${GITHUB_SHA}" - git checkout FETCH_HEAD - - name: Install sccache - run: | - curl -fsSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \ - | tar xz --strip-components=1 -C /usr/local/bin/ sccache-v0.9.1-x86_64-unknown-linux-musl/sccache - chmod +x /usr/local/bin/sccache - - name: Run tests (core + agent) + # Tests (reuses compilation artifacts from clippy) + - name: Tests (core + agent) run: cargo test -p compliance-core -p compliance-agent - - name: Run tests (dashboard server) + - name: Tests (dashboard server) run: cargo test -p compliance-dashboard --features server --no-default-features - - name: Run tests (dashboard web) + - name: Tests (dashboard web) run: cargo test -p compliance-dashboard --features web --no-default-features + - name: Show sccache stats run: sccache --show-stats if: always() # --------------------------------------------------------------------------- - # Stage 3: Deploy (only on main, after tests pass) + # Stage 2: Deploy (only on main, after checks pass) # Each service only deploys when its relevant files changed. # --------------------------------------------------------------------------- detect-changes: name: Detect Changes runs-on: docker if: github.ref == 'refs/heads/main' - needs: [test] + needs: [check] container: image: alpine:latest outputs: diff --git a/README.md b/README.md index 698d9f9..c7da379 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@

- Rust + Rust Dioxus MongoDB Axum @@ -94,7 +94,7 @@ Compliance Scanner is an autonomous agent that continuously monitors git reposit ### Prerequisites -- Rust 1.89+ +- Rust 1.94+ - [Dioxus CLI](https://dioxuslabs.com/learn/0.7/getting_started) (`dx`) - MongoDB - Docker & Docker Compose (optional) diff --git a/compliance-dashboard/assets/main.css b/compliance-dashboard/assets/main.css index 2470dbc..71f7e6b 100644 --- a/compliance-dashboard/assets/main.css +++ b/compliance-dashboard/assets/main.css @@ -262,13 +262,120 @@ code { color: var(--accent); } -.sidebar-footer { - padding: 14px 20px; +.sidebar-spacer { + flex: 1; +} + +.sidebar-user { + display: flex; + align-items: center; + gap: 10px; + padding: 12px 16px; border-top: 1px solid var(--border); - font-family: var(--font-mono); +} + +.sidebar.collapsed .sidebar-user { + justify-content: center; + flex-direction: column; + gap: 6px; + padding: 12px 8px; +} + +.user-avatar { + width: 36px; + height: 36px; + border-radius: 50%; + background: linear-gradient(135deg, rgba(56, 189, 248, 0.2), rgba(139, 92, 246, 0.15)); + border: 2px solid rgba(56, 189, 248, 0.2); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + transition: border-color 0.2s; +} + +.user-avatar:hover { + border-color: rgba(56, 189, 248, 0.4); +} + +.avatar-initials { + font-size: 14px; + font-weight: 700; + color: var(--accent); + line-height: 1; + text-transform: uppercase; +} + +.avatar-img { + width: 100%; + height: 100%; + border-radius: 50%; + object-fit: cover; +} + +.user-info { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 2px; +} + +.user-name { + font-size: 13px; + font-weight: 600; + color: var(--text-primary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.logout-link { font-size: 11px; color: var(--text-tertiary); - letter-spacing: 0.02em; + text-decoration: none; + transition: color 0.15s; +} + +.logout-link:hover { + color: #fca5a5; +} + +.logout-btn-icon { + display: flex; + align-items: center; + justify-content: center; + color: var(--text-tertiary); + text-decoration: none; + transition: color 0.15s; +} + +.logout-btn-icon:hover { + color: #fca5a5; +} + +.sidebar-legal { + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + padding: 8px 16px 14px; + font-size: 11px; +} + +.sidebar-legal a { + color: var(--text-tertiary); + text-decoration: none; + transition: color 0.15s; +} + +.sidebar-legal a:hover { + color: var(--text-secondary); +} + +.legal-dot { + color: var(--text-tertiary); + opacity: 0.5; } .sidebar-toggle { diff --git a/compliance-dashboard/src/components/sidebar.rs b/compliance-dashboard/src/components/sidebar.rs index 4522fae..b8a3177 100644 --- a/compliance-dashboard/src/components/sidebar.rs +++ b/compliance-dashboard/src/components/sidebar.rs @@ -109,6 +109,8 @@ pub fn Sidebar() -> Element { span { "Docs" } } } + // Spacer pushes footer to the bottom + div { class: "sidebar-spacer" } button { class: "sidebar-toggle", onclick: move |_| collapsed.set(!collapsed()), @@ -122,9 +124,8 @@ pub fn Sidebar() -> Element { let auth_info = use_context::>(); let info = auth_info(); let initials = info.name.chars().next().unwrap_or('U').to_uppercase().to_string(); - let user_class = if collapsed() { "sidebar-user sidebar-user-collapsed" } else { "sidebar-user" }; rsx! { - div { class: "{user_class}", + div { class: "sidebar-user", div { class: "user-avatar", if info.avatar_url.is_empty() { span { class: "avatar-initials", "{initials}" } @@ -133,13 +134,29 @@ pub fn Sidebar() -> Element { } } if !collapsed() { - span { class: "user-name", "{info.name}" } + div { class: "user-info", + span { class: "user-name", "{info.name}" } + a { + href: "/logout", + class: "logout-link", + "Sign out" + } + } } - a { - href: "/logout", - class: if collapsed() { "logout-btn logout-btn-collapsed" } else { "logout-btn" }, - title: "Sign out", - Icon { icon: BsBoxArrowRight, width: 16, height: 16 } + if collapsed() { + a { + href: "/logout", + class: "logout-btn-icon", + title: "Sign out", + Icon { icon: BsBoxArrowRight, width: 14, height: 14 } + } + } + } + if !collapsed() { + div { class: "sidebar-legal", + a { href: "/privacy", "Privacy" } + span { class: "legal-dot", "ยท" } + a { href: "/impressum", "Impressum" } } } }