mirror of
https://github.com/Xevion/banner.git
synced 2026-01-31 14:23:36 -06:00
Compare commits
7 Commits
v0.6.0
...
ebb7a97c11
| Author | SHA1 | Date | |
|---|---|---|---|
| ebb7a97c11 | |||
| 2df0ba0ec5 | |||
| dd148e08a0 | |||
| 3494341e3f | |||
| acccaa54d4 | |||
| 6863ee58d0 | |||
| 550401b85c |
@@ -0,0 +1,11 @@
|
||||
# cargo-audit configuration
|
||||
# https://github.com/rustsec/rustsec/tree/main/cargo-audit
|
||||
|
||||
[advisories]
|
||||
# Transitive dependencies we can't control
|
||||
ignore = [
|
||||
# rsa: Marvin Attack timing sidechannel (via sqlx-mysql, no fix available)
|
||||
"RUSTSEC-2023-0071",
|
||||
# derivative: unmaintained (via poise)
|
||||
"RUSTSEC-2024-0388",
|
||||
]
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
||||
"changelog-sections": [
|
||||
{ "type": "feat", "section": "Features" },
|
||||
{ "type": "fix", "section": "Bug Fixes" },
|
||||
{ "type": "perf", "section": "Performance Improvements" },
|
||||
{ "type": "refactor", "section": "Code Refactoring" },
|
||||
{ "type": "docs", "section": "Documentation" },
|
||||
{ "type": "ci", "section": "Continuous Integration" },
|
||||
{ "type": "build", "section": "Build System" },
|
||||
{ "type": "chore", "section": "Miscellaneous" },
|
||||
{ "type": "style", "section": "Styles", "hidden": true },
|
||||
{ "type": "test", "section": "Tests", "hidden": true }
|
||||
],
|
||||
"bump-minor-pre-major": true,
|
||||
"always-update": true,
|
||||
"bump-patch-for-minor-pre-major": true,
|
||||
"include-v-in-tag": true,
|
||||
"include-component-in-tag": false,
|
||||
"plugins": ["sentence-case"],
|
||||
"packages": {
|
||||
".": {
|
||||
"release-type": "rust",
|
||||
"exclude-paths": [".vscode", "docs"],
|
||||
"extra-files": [
|
||||
{
|
||||
"type": "toml",
|
||||
"path": "Cargo.lock",
|
||||
"jsonpath": "$.package[?(@.name=='banner')].version"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
".": "0.6.0"
|
||||
}
|
||||
Vendored
+147
-27
@@ -11,9 +11,9 @@ env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
check:
|
||||
rust-quality:
|
||||
name: Rust Quality
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -22,44 +22,164 @@ jobs:
|
||||
with:
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
- name: Check formatting
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
cargo fmt --all -- --check
|
||||
else
|
||||
cargo fmt --all -- --check || echo "::warning::Rust formatting issues found (not failing on push)"
|
||||
fi
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --no-default-features -- -D warnings
|
||||
|
||||
frontend-quality:
|
||||
name: Frontend Quality
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: web
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Check formatting
|
||||
working-directory: web
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
bun run format:check
|
||||
else
|
||||
bun run format:check || echo "::warning::Frontend formatting issues found (not failing on push)"
|
||||
fi
|
||||
|
||||
- name: Lint
|
||||
working-directory: web
|
||||
run: bun run lint
|
||||
|
||||
- name: Type check
|
||||
working-directory: web
|
||||
run: bun run typecheck
|
||||
|
||||
rust-tests:
|
||||
name: Rust Tests
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
env:
|
||||
POSTGRES_USER: banner
|
||||
POSTGRES_PASSWORD: banner
|
||||
POSTGRES_DB: banner
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
env:
|
||||
DATABASE_URL: postgresql://banner:banner@localhost:5432/banner
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Cache Rust dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --no-default-features
|
||||
|
||||
frontend-tests:
|
||||
name: Frontend Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: web
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Run tests
|
||||
working-directory: web
|
||||
run: bun run test
|
||||
|
||||
docker-build:
|
||||
name: Docker Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
security:
|
||||
name: Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install cargo-audit
|
||||
uses: taiki-e/install-action@cargo-audit
|
||||
|
||||
- name: Rust security audit
|
||||
run: cargo audit
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install frontend dependencies
|
||||
working-directory: web
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Check Rust formatting
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
- name: Check TypeScript formatting
|
||||
- name: Frontend security audit
|
||||
working-directory: web
|
||||
run: bun run format:check
|
||||
run: bun audit --audit-level=moderate
|
||||
continue-on-error: true
|
||||
|
||||
- name: TypeScript type check
|
||||
working-directory: web
|
||||
run: bun run typecheck
|
||||
- name: Trivy filesystem scan
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: fs
|
||||
scan-ref: .
|
||||
format: sarif
|
||||
output: trivy-results.sarif
|
||||
severity: CRITICAL,HIGH
|
||||
exit-code: 0
|
||||
|
||||
- name: ESLint
|
||||
working-directory: web
|
||||
run: bun run lint
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --all-features -- --deny warnings
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --all-features
|
||||
|
||||
- name: Build frontend
|
||||
working-directory: web
|
||||
run: bun run build
|
||||
|
||||
- name: Build backend
|
||||
run: cargo build --release --bin banner
|
||||
- name: Upload Trivy results
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
if: always() && hashFiles('trivy-results.sarif') != ''
|
||||
with:
|
||||
sarif_file: trivy-results.sarif
|
||||
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
name: Release Please
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
workflow_run:
|
||||
workflows: ["CI"]
|
||||
types:
|
||||
- completed
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
name: Create Release PR
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: googleapis/release-please-action@v4
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
||||
config-file: .github/release-please-config.json
|
||||
manifest-file: .github/release-please-manifest.json
|
||||
Vendored
+1
-3
@@ -1,6 +1,4 @@
|
||||
.env
|
||||
/target
|
||||
|
||||
# ts-rs bindings
|
||||
web/src/lib/bindings/**/*.ts
|
||||
!web/src/lib/bindings/index.ts
|
||||
|
||||
|
||||
Generated
+153
-316
@@ -182,14 +182,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
|
||||
dependencies = [
|
||||
"axum-core",
|
||||
"base64 0.22.1",
|
||||
"base64",
|
||||
"bytes",
|
||||
"form_urlencoded",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper 1.7.0",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
@@ -202,7 +202,7 @@ dependencies = [
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
"sha1",
|
||||
"sync_wrapper 1.0.2",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-tungstenite 0.28.0",
|
||||
"tower",
|
||||
@@ -219,12 +219,12 @@ checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper 1.0.2",
|
||||
"sync_wrapper",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -242,8 +242,8 @@ dependencies = [
|
||||
"form_urlencoded",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
@@ -278,7 +278,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"axum-extra",
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"clap",
|
||||
@@ -293,14 +293,14 @@ dependencies = [
|
||||
"governor",
|
||||
"html-escape",
|
||||
"htmlize",
|
||||
"http 1.3.1",
|
||||
"http",
|
||||
"mime_guess",
|
||||
"num-format",
|
||||
"poise",
|
||||
"rand 0.9.2",
|
||||
"rapidhash",
|
||||
"regex",
|
||||
"reqwest 0.12.23",
|
||||
"reqwest",
|
||||
"reqwest-middleware",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
@@ -322,12 +322,6 @@ dependencies = [
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
@@ -340,12 +334,6 @@ version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.4"
|
||||
@@ -473,6 +461,12 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.42"
|
||||
@@ -545,9 +539,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "command_attr"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fcc89439e1bb4e19050a9586a767781a3060000d2f3296fd2a40597ad9421c5"
|
||||
checksum = "8208103c5e25a091226dfa8d61d08d0561cc14f31b25691811ba37d4ec9b157b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1146,15 +1140,6 @@ dependencies = [
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fxhash"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
@@ -1172,8 +1157,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1238,25 +1225,6 @@ dependencies = [
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.12"
|
||||
@@ -1268,7 +1236,7 @@ dependencies = [
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http 1.3.1",
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
@@ -1363,17 +1331,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
@@ -1385,17 +1342,6 @@ dependencies = [
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 0.2.12",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
@@ -1403,7 +1349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 1.3.1",
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1414,8 +1360,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@@ -1431,30 +1377,6 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.3.27",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.10",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.7.0"
|
||||
@@ -1465,9 +1387,9 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"h2 0.4.12",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
@@ -1478,34 +1400,21 @@ dependencies = [
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"hyper 0.14.32",
|
||||
"rustls 0.21.12",
|
||||
"tokio",
|
||||
"tokio-rustls 0.24.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
|
||||
dependencies = [
|
||||
"http 1.3.1",
|
||||
"hyper 1.7.0",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls 0.23.31",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tower-service",
|
||||
"webpki-roots 1.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1516,7 +1425,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper 1.7.0",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
@@ -1530,20 +1439,20 @@ version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"base64",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"hyper 1.7.0",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"ipnet",
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.0",
|
||||
"system-configuration 0.6.1",
|
||||
"socket2",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -1709,7 +1618,7 @@ version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
@@ -1795,7 +1704,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
]
|
||||
@@ -1844,6 +1753,12 @@ version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "lru-slab"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.2.0"
|
||||
@@ -2048,7 +1963,7 @@ version = "0.10.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
@@ -2357,7 +2272,7 @@ version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
"memchr",
|
||||
"unicase",
|
||||
]
|
||||
@@ -2377,6 +2292,61 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg_aliases",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.31",
|
||||
"socket2",
|
||||
"thiserror 2.0.16",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.3",
|
||||
"lru-slab",
|
||||
"rand 0.9.2",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.31",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror 2.0.16",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
@@ -2466,7 +2436,7 @@ version = "11.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2475,7 +2445,7 @@ version = "0.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2507,90 +2477,54 @@ version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.3.27",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.32",
|
||||
"hyper-rustls 0.24.2",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls 0.21.12",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 0.1.2",
|
||||
"system-configuration 0.5.1",
|
||||
"tokio",
|
||||
"tokio-rustls 0.24.1",
|
||||
"tokio-util",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots 0.25.4",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"base64",
|
||||
"bytes",
|
||||
"cookie",
|
||||
"cookie_store",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"h2 0.4.12",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper 1.7.0",
|
||||
"hyper-rustls 0.27.7",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"native-tls",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls 0.23.31",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.2",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots 1.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2601,8 +2535,8 @@ checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"http 1.3.1",
|
||||
"reqwest 0.12.23",
|
||||
"http",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
"tower-service",
|
||||
@@ -2683,6 +2617,12 @@ version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
@@ -2698,25 +2638,13 @@ version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.21.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"rustls-webpki 0.101.7",
|
||||
"sct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.22.4"
|
||||
@@ -2745,34 +2673,16 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
|
||||
dependencies = [
|
||||
"web-time",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.101.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.8"
|
||||
@@ -2831,16 +2741,6 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secrecy"
|
||||
version = "0.8.0"
|
||||
@@ -2857,7 +2757,7 @@ version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@@ -2980,26 +2880,26 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serenity"
|
||||
version = "0.12.4"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d72ec4323681bf9a3cabe40fd080abc2435859b502a1b5aa9bf693f125bfa76"
|
||||
checksum = "9bde37f42765dfdc34e2a039e0c84afbf79a3101c1941763b0beb816c2f17541"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.9.4",
|
||||
"base64",
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"command_attr",
|
||||
"dashmap 5.5.3",
|
||||
"flate2",
|
||||
"futures",
|
||||
"fxhash",
|
||||
"levenshtein",
|
||||
"mime_guess",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"reqwest 0.11.27",
|
||||
"reqwest",
|
||||
"rustc-hash",
|
||||
"secrecy",
|
||||
"serde",
|
||||
"serde_cow",
|
||||
@@ -3107,16 +3007,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.0"
|
||||
@@ -3174,7 +3064,7 @@ version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"base64",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc",
|
||||
@@ -3250,8 +3140,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.9.4",
|
||||
"base64",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
@@ -3293,8 +3183,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.9.4",
|
||||
"base64",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"crc",
|
||||
@@ -3406,12 +3296,6 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.2"
|
||||
@@ -3432,36 +3316,15 @@ dependencies = [
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation",
|
||||
"system-configuration-sys 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"system-configuration-sys 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3621,7 +3484,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"socket2 0.6.0",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
@@ -3647,16 +3510,6 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
||||
dependencies = [
|
||||
"rustls 0.21.12",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.25.0"
|
||||
@@ -3780,7 +3633,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper 1.0.2",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@@ -3794,12 +3647,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"bitflags 2.9.4",
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http",
|
||||
"http-body",
|
||||
"iri-string",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
@@ -3942,7 +3795,7 @@ dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http 1.3.1",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
@@ -3962,7 +3815,7 @@ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http 1.3.1",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand 0.9.2",
|
||||
@@ -4270,12 +4123,6 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.25.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.11"
|
||||
@@ -4642,16 +4489,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.45.0"
|
||||
|
||||
@@ -38,7 +38,7 @@ check *flags:
|
||||
],
|
||||
},
|
||||
biome: {
|
||||
peers: ["svelte-check", "web-test"],
|
||||
peers: ["svelte-check", "biome-lint", "web-test"],
|
||||
format: () => run(["bun", "run", "--cwd", "web", "format"]),
|
||||
recheck: [
|
||||
{ name: "biome", cmd: ["bun", "run", "--cwd", "web", "format:check"] },
|
||||
@@ -53,7 +53,9 @@ check *flags:
|
||||
{ name: "rust-test", cmd: ["cargo", "nextest", "run", "-E", "not test(export_bindings)"] },
|
||||
{ name: "svelte-check", cmd: ["bun", "run", "--cwd", "web", "check"] },
|
||||
{ name: "biome", cmd: ["bun", "run", "--cwd", "web", "format:check"] },
|
||||
{ name: "biome-lint", cmd: ["bun", "run", "--cwd", "web", "lint"] },
|
||||
{ name: "web-test", cmd: ["bun", "run", "--cwd", "web", "test"] },
|
||||
{ name: "actionlint", cmd: ["actionlint"] },
|
||||
// { name: "sqlx-prepare", cmd: ["cargo", "sqlx", "prepare", "--check"] },
|
||||
];
|
||||
|
||||
|
||||
+1
-1
@@ -633,7 +633,7 @@
|
||||
|
||||
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
||||
|
||||
"svelte": ["svelte@5.49.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.2", "esm-env": "^1.2.1", "esrap": "^2.2.1", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-Fn2mCc3XX0gnnbBYzWOTrZHi5WnF9KvqmB1+KGlUWoJkdioPmFYtg2ALBr6xl2dcnFTz3Vi7/mHpbKSVg/imVg=="],
|
||||
"svelte": ["svelte@5.49.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.2", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-jj95WnbKbXsXXngYj28a4zx8jeZx50CN/J4r0CEeax2pbfdsETv/J1K8V9Hbu3DCXnpHz5qAikICuxEooi7eNQ=="],
|
||||
|
||||
"svelte-check": ["svelte-check@4.3.5", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q=="],
|
||||
|
||||
|
||||
+17
-15
@@ -7,33 +7,35 @@
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"typecheck": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"lint": "biome check .",
|
||||
"test": "vitest run",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome format ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@fontsource-variable/inter": "^5.2.5",
|
||||
"@lucide/svelte": "^0.563.0",
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"@sveltejs/kit": "^2.16.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"@fontsource-variable/inter": "^5.2.8",
|
||||
"@lucide/svelte": "^0.563.1",
|
||||
"@sveltejs/adapter-static": "^3.0.10",
|
||||
"@sveltejs/kit": "^2.50.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.1.1",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@tanstack/table-core": "^8.21.3",
|
||||
"@types/d3-scale": "^4.0.9",
|
||||
"@types/d3-shape": "^3.1.8",
|
||||
"@types/d3-time-format": "^4.0.3",
|
||||
"@types/node": "^25.1.0",
|
||||
"bits-ui": "^1.3.7",
|
||||
"bits-ui": "^1.8.0",
|
||||
"clsx": "^2.1.1",
|
||||
"jsdom": "^26.0.0",
|
||||
"svelte": "^5.19.0",
|
||||
"svelte-check": "^4.1.4",
|
||||
"tailwind-merge": "^3.0.1",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"typescript": "^5.7.2",
|
||||
"vite": "^6.3.5",
|
||||
"vitest": "^3.0.5"
|
||||
"jsdom": "^26.1.0",
|
||||
"svelte": "^5.49.1",
|
||||
"svelte-check": "^4.3.5",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^6.4.1",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@icons-pack/svelte-simple-icons": "^6.5.0",
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#!/usr/bin/env bun
|
||||
import { extname, join } from "path";
|
||||
import { constants, brotliCompressSync, gzipSync } from "zlib";
|
||||
import { $ } from "bun";
|
||||
/**
|
||||
* Pre-compress static assets with maximum compression levels.
|
||||
* Run after `bun run build`.
|
||||
@@ -7,10 +10,7 @@
|
||||
* These are embedded alongside originals by rust-embed and served via
|
||||
* content negotiation in src/web/assets.rs.
|
||||
*/
|
||||
import { readdir, stat, readFile, writeFile } from "fs/promises";
|
||||
import { join, extname } from "path";
|
||||
import { gzipSync, brotliCompressSync, constants } from "zlib";
|
||||
import { $ } from "bun";
|
||||
import { readFile, readdir, stat, writeFile } from "fs/promises";
|
||||
|
||||
// Must match COMPRESSION_MIN_SIZE in src/web/encoding.rs
|
||||
const MIN_SIZE = 512;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* A match candidate in the detail view.
|
||||
*/
|
||||
export type CandidateResponse = { id: number, rmpLegacyId: number, firstName: string | null, lastName: string | null, department: string | null, avgRating: number | null, avgDifficulty: number | null, numRatings: number | null, wouldTakeAgainPct: number | null, score: number | null, scoreBreakdown: { [key in string]?: number } | null, status: string, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type CodeDescription = { code: string, description: string, };
|
||||
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { DbMeetingTime } from "./DbMeetingTime";
|
||||
import type { InstructorResponse } from "./InstructorResponse";
|
||||
|
||||
export type CourseResponse = { crn: string, subject: string, courseNumber: string, title: string, termCode: string, sequenceNumber: string | null, instructionalMethod: string | null, campus: string | null, enrollment: number, maxEnrollment: number, waitCount: number, waitCapacity: number, creditHours: number | null, creditHourLow: number | null, creditHourHigh: number | null, crossList: string | null, crossListCapacity: number | null, crossListCount: number | null, linkIdentifier: string | null, isSectionLinked: boolean | null, partOfTerm: string | null, meetingTimes: Array<DbMeetingTime>, attributes: Array<string>, instructors: Array<InstructorResponse>, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* Represents a meeting time stored as JSONB in the courses table.
|
||||
*/
|
||||
export type DbMeetingTime = { begin_time: string | null, end_time: string | null, start_date: string, end_date: string, monday: boolean, tuesday: boolean, wednesday: boolean, thursday: boolean, friday: boolean, saturday: boolean, sunday: boolean, building: string | null, building_description: string | null, room: string | null, campus: string | null, meeting_type: string, meeting_schedule_type: string, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* Instructor summary in the detail view.
|
||||
*/
|
||||
export type InstructorDetail = { id: number, displayName: string, email: string, rmpMatchStatus: string, subjectsTaught: Array<string>, courseCount: number, };
|
||||
@@ -0,0 +1,9 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { CandidateResponse } from "./CandidateResponse";
|
||||
import type { InstructorDetail } from "./InstructorDetail";
|
||||
import type { LinkedRmpProfile } from "./LinkedRmpProfile";
|
||||
|
||||
/**
|
||||
* Response for `GET /api/admin/instructors/{id}` and `POST .../match`.
|
||||
*/
|
||||
export type InstructorDetailResponse = { instructor: InstructorDetail, currentMatches: Array<LinkedRmpProfile>, candidates: Array<CandidateResponse>, };
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { TopCandidateResponse } from "./TopCandidateResponse";
|
||||
|
||||
/**
|
||||
* An instructor row in the paginated list.
|
||||
*/
|
||||
export type InstructorListItem = { id: number, displayName: string, email: string, rmpMatchStatus: string, rmpLinkCount: number, candidateCount: number, courseSubjectCount: number, topCandidate: TopCandidateResponse | null, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type InstructorResponse = { instructorId: number, bannerId: string, displayName: string, email: string, isPrimary: boolean, rmpRating: number | null, rmpNumRatings: number | null, rmpLegacyId: number | null, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* Aggregate status counts for the instructor list.
|
||||
*/
|
||||
export type InstructorStats = { total: number, unmatched: number, auto: number, confirmed: number, rejected: number, withCandidates: number, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* A linked RMP profile in the detail view.
|
||||
*/
|
||||
export type LinkedRmpProfile = { linkId: number, legacyId: number, firstName: string | null, lastName: string | null, department: string | null, avgRating: number | null, avgDifficulty: number | null, numRatings: number | null, wouldTakeAgainPct: number | null, };
|
||||
@@ -0,0 +1,8 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { InstructorListItem } from "./InstructorListItem";
|
||||
import type { InstructorStats } from "./InstructorStats";
|
||||
|
||||
/**
|
||||
* Response for `GET /api/admin/instructors`.
|
||||
*/
|
||||
export type ListInstructorsResponse = { instructors: Array<InstructorListItem>, total: number, page: number, perPage: number, stats: InstructorStats, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* Simple acknowledgement response for mutating operations.
|
||||
*/
|
||||
export type OkResponse = { ok: boolean, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* Response for `POST /api/admin/rmp/rescore`.
|
||||
*/
|
||||
export type RescoreResponse = { totalUnmatched: number, candidatesCreated: number, candidatesRescored: number, autoMatched: number, skippedUnparseable: number, skippedNoCandidates: number, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ScraperStatsResponse = { period: string, totalScrapes: number, successfulScrapes: number, failedScrapes: number, successRate: number | null, avgDurationMs: number | null, totalCoursesChanged: number, totalCoursesFetched: number, totalAuditsGenerated: number, pendingJobs: number, lockedJobs: number, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { CourseResponse } from "./CourseResponse";
|
||||
|
||||
export type SearchResponse = { courses: Array<CourseResponse>, totalCount: number, offset: number, limit: number, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ServiceStatus } from "./ServiceStatus";
|
||||
|
||||
export type ServiceInfo = { name: string, status: ServiceStatus, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* Health status of a service.
|
||||
*/
|
||||
export type ServiceStatus = "starting" | "active" | "connected" | "disabled" | "error";
|
||||
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ServiceInfo } from "./ServiceInfo";
|
||||
import type { ServiceStatus } from "./ServiceStatus";
|
||||
|
||||
export type StatusResponse = { status: ServiceStatus, version: string, commit: string, services: { [key in string]?: ServiceInfo }, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { SubjectResultEntry } from "./SubjectResultEntry";
|
||||
|
||||
export type SubjectDetailResponse = { subject: string, results: Array<SubjectResultEntry>, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type SubjectResultEntry = { id: number, completedAt: string, durationMs: number, success: boolean, errorMessage: string | null, coursesFetched: number | null, coursesChanged: number | null, coursesUnchanged: number | null, auditsGenerated: number | null, metricsGenerated: number | null, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type SubjectSummary = { subject: string, subjectDescription: string | null, trackedCourseCount: number, scheduleState: string, currentIntervalSecs: number, timeMultiplier: number, lastScraped: string, nextEligibleAt: string | null, cooldownRemainingSecs: number | null, avgChangeRatio: number, consecutiveZeroChanges: number, recentRuns: number, recentFailures: number, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { SubjectSummary } from "./SubjectSummary";
|
||||
|
||||
export type SubjectsResponse = { subjects: Array<SubjectSummary>, };
|
||||
@@ -0,0 +1,12 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { TimelineSlot } from "./TimelineSlot";
|
||||
|
||||
export type TimelineResponse = {
|
||||
/**
|
||||
* 15-minute slots with per-subject enrollment totals, sorted by time.
|
||||
*/
|
||||
slots: Array<TimelineSlot>,
|
||||
/**
|
||||
* All subject codes present in the returned data.
|
||||
*/
|
||||
subjects: Array<string>, };
|
||||
@@ -0,0 +1,11 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type TimelineSlot = {
|
||||
/**
|
||||
* ISO-8601 timestamp at the start of this 15-minute bucket.
|
||||
*/
|
||||
time: string,
|
||||
/**
|
||||
* Subject code → total enrollment in this slot.
|
||||
*/
|
||||
subjects: { [key in string]?: bigint }, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type TimeseriesPoint = { timestamp: string, scrapeCount: number, successCount: number, errorCount: number, coursesChanged: number, avgDurationMs: number, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { TimeseriesPoint } from "./TimeseriesPoint";
|
||||
|
||||
export type TimeseriesResponse = { period: string, bucket: string, points: Array<TimeseriesPoint>, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* A top-candidate summary shown in the instructor list view.
|
||||
*/
|
||||
export type TopCandidateResponse = { rmpLegacyId: number, score: number | null, scoreBreakdown: { [key in string]?: number } | null, firstName: string | null, lastName: string | null, department: string | null, avgRating: number | null, numRatings: number | null, };
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* A user authenticated via Discord OAuth.
|
||||
*/
|
||||
export type User = { discordId: string, discordUsername: string, discordAvatarHash: string | null, isAdmin: boolean, createdAt: string, updatedAt: string, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type JsonValue = number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null;
|
||||
@@ -1,31 +1,31 @@
|
||||
<script lang="ts">
|
||||
import type { CourseResponse } from "$lib/api";
|
||||
import { useClipboard } from "$lib/composables/useClipboard.svelte";
|
||||
import {
|
||||
formatTime,
|
||||
RMP_CONFIDENCE_THRESHOLD,
|
||||
formatCreditHours,
|
||||
formatDate,
|
||||
formatMeetingDaysLong,
|
||||
formatTime,
|
||||
isMeetingTimeTBA,
|
||||
isTimeTBA,
|
||||
ratingStyle,
|
||||
rmpUrl,
|
||||
RMP_CONFIDENCE_THRESHOLD,
|
||||
} from "$lib/course";
|
||||
import { themeStore } from "$lib/stores/theme.svelte";
|
||||
import { useClipboard } from "$lib/composables/useClipboard.svelte";
|
||||
import { cn, tooltipContentClass, formatNumber } from "$lib/utils";
|
||||
import { Tooltip } from "bits-ui";
|
||||
import SimpleTooltip from "./SimpleTooltip.svelte";
|
||||
import { cn, formatNumber, tooltipContentClass } from "$lib/utils";
|
||||
import {
|
||||
Info,
|
||||
Copy,
|
||||
Calendar,
|
||||
Check,
|
||||
Copy,
|
||||
Download,
|
||||
ExternalLink,
|
||||
Info,
|
||||
Star,
|
||||
Triangle,
|
||||
ExternalLink,
|
||||
Calendar,
|
||||
Download,
|
||||
} from "@lucide/svelte";
|
||||
import { Tooltip } from "bits-ui";
|
||||
import SimpleTooltip from "./SimpleTooltip.svelte";
|
||||
|
||||
let { course }: { course: CourseResponse } = $props();
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<script lang="ts">
|
||||
import type { CourseResponse } from "$lib/api";
|
||||
import { FlexRender, createSvelteTable } from "$lib/components/ui/data-table/index.js";
|
||||
import { useClipboard } from "$lib/composables/useClipboard.svelte";
|
||||
import { useOverlayScrollbars } from "$lib/composables/useOverlayScrollbars.svelte";
|
||||
import {
|
||||
RMP_CONFIDENCE_THRESHOLD,
|
||||
abbreviateInstructor,
|
||||
concernAccentColor,
|
||||
formatLocationDisplay,
|
||||
@@ -13,40 +17,36 @@ import {
|
||||
isMeetingTimeTBA,
|
||||
isTimeTBA,
|
||||
openSeats,
|
||||
seatsColor,
|
||||
seatsDotColor,
|
||||
ratingStyle,
|
||||
rmpUrl,
|
||||
RMP_CONFIDENCE_THRESHOLD,
|
||||
seatsColor,
|
||||
seatsDotColor,
|
||||
} from "$lib/course";
|
||||
import { themeStore } from "$lib/stores/theme.svelte";
|
||||
import { useClipboard } from "$lib/composables/useClipboard.svelte";
|
||||
import { useOverlayScrollbars } from "$lib/composables/useOverlayScrollbars.svelte";
|
||||
import CourseDetail from "./CourseDetail.svelte";
|
||||
import { fade, fly, slide } from "svelte/transition";
|
||||
import { flip } from "svelte/animate";
|
||||
import { createSvelteTable, FlexRender } from "$lib/components/ui/data-table/index.js";
|
||||
import { cn, formatNumber, tooltipContentClass } from "$lib/utils";
|
||||
import {
|
||||
getCoreRowModel,
|
||||
getSortedRowModel,
|
||||
type ColumnDef,
|
||||
type SortingState,
|
||||
type VisibilityState,
|
||||
type Updater,
|
||||
} from "@tanstack/table-core";
|
||||
import {
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
ArrowUp,
|
||||
ArrowUpDown,
|
||||
Columns3,
|
||||
Check,
|
||||
Columns3,
|
||||
ExternalLink,
|
||||
RotateCcw,
|
||||
Star,
|
||||
Triangle,
|
||||
ExternalLink,
|
||||
} from "@lucide/svelte";
|
||||
import { DropdownMenu, ContextMenu, Tooltip } from "bits-ui";
|
||||
import { cn, tooltipContentClass, formatNumber } from "$lib/utils";
|
||||
import {
|
||||
type ColumnDef,
|
||||
type SortingState,
|
||||
type Updater,
|
||||
type VisibilityState,
|
||||
getCoreRowModel,
|
||||
getSortedRowModel,
|
||||
} from "@tanstack/table-core";
|
||||
import { ContextMenu, DropdownMenu, Tooltip } from "bits-ui";
|
||||
import { flip } from "svelte/animate";
|
||||
import { fade, fly, slide } from "svelte/transition";
|
||||
import CourseDetail from "./CourseDetail.svelte";
|
||||
import SimpleTooltip from "./SimpleTooltip.svelte";
|
||||
|
||||
let {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import { TriangleAlert, RotateCcw } from "@lucide/svelte";
|
||||
import { RotateCcw, TriangleAlert } from "@lucide/svelte";
|
||||
|
||||
interface Props {
|
||||
/** Heading shown in the error card */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import { Search, User, Clock } from "@lucide/svelte";
|
||||
import { authStore } from "$lib/auth.svelte";
|
||||
import { Clock, Search, User } from "@lucide/svelte";
|
||||
import ThemeToggle from "./ThemeToggle.svelte";
|
||||
|
||||
const staticTabs = [
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { Select } from "bits-ui";
|
||||
import { ChevronUp, ChevronDown } from "@lucide/svelte";
|
||||
import type { Action } from "svelte/action";
|
||||
import { formatNumber } from "$lib/utils";
|
||||
import { ChevronDown, ChevronUp } from "@lucide/svelte";
|
||||
import { Select } from "bits-ui";
|
||||
import type { Action } from "svelte/action";
|
||||
|
||||
const slideIn: Action<HTMLElement, number> = (node, direction) => {
|
||||
if (direction !== 0) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { Term, Subject } from "$lib/api";
|
||||
import type { Subject, Term } from "$lib/api";
|
||||
import SimpleTooltip from "./SimpleTooltip.svelte";
|
||||
import TermCombobox from "./TermCombobox.svelte";
|
||||
import SubjectCombobox from "./SubjectCombobox.svelte";
|
||||
import TermCombobox from "./TermCombobox.svelte";
|
||||
|
||||
let {
|
||||
terms,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import SimpleTooltip from "$lib/components/SimpleTooltip.svelte";
|
||||
import { relativeTime } from "$lib/time";
|
||||
import { formatNumber } from "$lib/utils";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
export interface SearchMeta {
|
||||
totalCount: number;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import { Tooltip } from "bits-ui";
|
||||
import type { Snippet } from "svelte";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
let {
|
||||
text,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { Combobox } from "bits-ui";
|
||||
import { Check, ChevronsUpDown } from "@lucide/svelte";
|
||||
import { fly } from "svelte/transition";
|
||||
import type { Subject } from "$lib/api";
|
||||
import { formatNumber } from "$lib/utils";
|
||||
import { Check, ChevronsUpDown } from "@lucide/svelte";
|
||||
import { Combobox } from "bits-ui";
|
||||
import { fly } from "svelte/transition";
|
||||
|
||||
let {
|
||||
subjects,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { Combobox } from "bits-ui";
|
||||
import { Check, ChevronsUpDown } from "@lucide/svelte";
|
||||
import { fly } from "svelte/transition";
|
||||
import type { Term } from "$lib/api";
|
||||
import { Check, ChevronsUpDown } from "@lucide/svelte";
|
||||
import { Combobox } from "bits-ui";
|
||||
import { fly } from "svelte/transition";
|
||||
|
||||
let {
|
||||
terms,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { tick } from "svelte";
|
||||
import { Moon, Sun } from "@lucide/svelte";
|
||||
import { themeStore } from "$lib/stores/theme.svelte";
|
||||
import { Moon, Sun } from "@lucide/svelte";
|
||||
import { tick } from "svelte";
|
||||
import SimpleTooltip from "./SimpleTooltip.svelte";
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
<script lang="ts">
|
||||
import { scaleLinear, scaleTime } from "d3-scale";
|
||||
import { onMount } from "svelte";
|
||||
import { scaleTime, scaleLinear } from "d3-scale";
|
||||
|
||||
import type { TimeSlot, ChartContext } from "$lib/timeline/types";
|
||||
import {
|
||||
PADDING,
|
||||
DEFAULT_AXIS_RATIO,
|
||||
CHART_HEIGHT_RATIO,
|
||||
MIN_SPAN_MS,
|
||||
MAX_SPAN_MS,
|
||||
DEFAULT_SPAN_MS,
|
||||
ZOOM_FACTOR,
|
||||
ZOOM_KEY_FACTOR,
|
||||
ZOOM_EASE,
|
||||
ZOOM_SETTLE_THRESHOLD,
|
||||
PAN_FRICTION,
|
||||
PAN_STOP_THRESHOLD,
|
||||
PAN_STOP_THRESHOLD_Y,
|
||||
VELOCITY_SAMPLE_WINDOW,
|
||||
VELOCITY_MIN_DT,
|
||||
PAN_STEP_RATIO,
|
||||
PAN_STEP_CTRL_RATIO,
|
||||
PAN_EASE,
|
||||
PAN_SETTLE_THRESHOLD_PX,
|
||||
YRATIO_STEP,
|
||||
YRATIO_MIN,
|
||||
YRATIO_MAX,
|
||||
YRATIO_SETTLE_THRESHOLD,
|
||||
FOLLOW_EASE,
|
||||
MIN_MAXY,
|
||||
MAX_DT,
|
||||
DEFAULT_DT,
|
||||
TAP_MAX_DURATION_MS,
|
||||
TAP_MAX_DISTANCE_PX,
|
||||
} from "$lib/timeline/constants";
|
||||
import { createTimelineStore } from "$lib/timeline/store.svelte";
|
||||
import {
|
||||
createAnimMap,
|
||||
syncAnimTargets,
|
||||
stepAnimations,
|
||||
pruneAnimMap,
|
||||
stepAnimations,
|
||||
syncAnimTargets,
|
||||
} from "$lib/timeline/animation";
|
||||
import {
|
||||
getVisibleSlots,
|
||||
findSlotByTime,
|
||||
snapToSlot,
|
||||
enabledTotalClasses,
|
||||
} from "$lib/timeline/viewport";
|
||||
CHART_HEIGHT_RATIO,
|
||||
DEFAULT_AXIS_RATIO,
|
||||
DEFAULT_DT,
|
||||
DEFAULT_SPAN_MS,
|
||||
FOLLOW_EASE,
|
||||
MAX_DT,
|
||||
MAX_SPAN_MS,
|
||||
MIN_MAXY,
|
||||
MIN_SPAN_MS,
|
||||
PADDING,
|
||||
PAN_EASE,
|
||||
PAN_FRICTION,
|
||||
PAN_SETTLE_THRESHOLD_PX,
|
||||
PAN_STEP_CTRL_RATIO,
|
||||
PAN_STEP_RATIO,
|
||||
PAN_STOP_THRESHOLD,
|
||||
PAN_STOP_THRESHOLD_Y,
|
||||
TAP_MAX_DISTANCE_PX,
|
||||
TAP_MAX_DURATION_MS,
|
||||
VELOCITY_MIN_DT,
|
||||
VELOCITY_SAMPLE_WINDOW,
|
||||
YRATIO_MAX,
|
||||
YRATIO_MIN,
|
||||
YRATIO_SETTLE_THRESHOLD,
|
||||
YRATIO_STEP,
|
||||
ZOOM_EASE,
|
||||
ZOOM_FACTOR,
|
||||
ZOOM_KEY_FACTOR,
|
||||
ZOOM_SETTLE_THRESHOLD,
|
||||
} from "$lib/timeline/constants";
|
||||
import {
|
||||
drawGrid,
|
||||
drawHoverColumn,
|
||||
drawStackedArea,
|
||||
drawNowLine,
|
||||
drawStackedArea,
|
||||
drawTimeAxis,
|
||||
stackVisibleSlots,
|
||||
} from "$lib/timeline/renderer";
|
||||
import { createTimelineStore } from "$lib/timeline/store.svelte";
|
||||
import type { ChartContext, TimeSlot } from "$lib/timeline/types";
|
||||
import {
|
||||
enabledTotalClasses,
|
||||
findSlotByTime,
|
||||
getVisibleSlots,
|
||||
snapToSlot,
|
||||
} from "$lib/timeline/viewport";
|
||||
import TimelineDrawer from "./TimelineDrawer.svelte";
|
||||
import TimelineTooltip from "./TimelineTooltip.svelte";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Filter, X } from "@lucide/svelte";
|
||||
import { getSubjectColor } from "$lib/timeline/data";
|
||||
import { DRAWER_WIDTH } from "$lib/timeline/constants";
|
||||
import { getSubjectColor } from "$lib/timeline/data";
|
||||
import { Filter, X } from "@lucide/svelte";
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { timeFormat } from "d3-time-format";
|
||||
import { getSubjectColor } from "$lib/timeline/data";
|
||||
import type { TimeSlot } from "$lib/timeline/types";
|
||||
import { enabledTotalClasses } from "$lib/timeline/viewport";
|
||||
import { timeFormat } from "d3-time-format";
|
||||
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { onMount } from "svelte";
|
||||
import { OverlayScrollbars, type PartialOptions } from "overlayscrollbars";
|
||||
import { themeStore } from "$lib/stores/theme.svelte";
|
||||
import { OverlayScrollbars, type PartialOptions } from "overlayscrollbars";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
/**
|
||||
* Set up OverlayScrollbars on an element with automatic theme reactivity.
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import type { CourseResponse, DbMeetingTime, InstructorResponse } from "$lib/api";
|
||||
import {
|
||||
formatTime,
|
||||
formatTimeRange,
|
||||
abbreviateInstructor,
|
||||
formatCreditHours,
|
||||
formatDate,
|
||||
formatDateShort,
|
||||
formatMeetingDays,
|
||||
formatMeetingDaysLong,
|
||||
formatMeetingDaysVerbose,
|
||||
formatMeetingTime,
|
||||
formatMeetingTimeTooltip,
|
||||
formatMeetingTimesTooltip,
|
||||
abbreviateInstructor,
|
||||
formatCreditHours,
|
||||
formatTime,
|
||||
formatTimeRange,
|
||||
getPrimaryInstructor,
|
||||
isMeetingTimeTBA,
|
||||
isTimeTBA,
|
||||
formatDate,
|
||||
formatDateShort,
|
||||
formatMeetingDaysLong,
|
||||
} from "$lib/course";
|
||||
import type { DbMeetingTime, CourseResponse, InstructorResponse } from "$lib/api";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
function makeMeetingTime(overrides: Partial<DbMeetingTime> = {}): DbMeetingTime {
|
||||
return {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DbMeetingTime, CourseResponse, InstructorResponse } from "$lib/api";
|
||||
import type { CourseResponse, DbMeetingTime, InstructorResponse } from "$lib/api";
|
||||
|
||||
/** Convert "0900" to "9:00 AM" */
|
||||
export function formatTime(time: string | null): string {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { termToBanner, termToFriendly } from "./term-format";
|
||||
|
||||
describe("termToFriendly", () => {
|
||||
it("converts spring term correctly", () => {
|
||||
expect(termToFriendly("202610")).toBe("spring-26");
|
||||
expect(termToFriendly("202510")).toBe("spring-25");
|
||||
});
|
||||
|
||||
it("converts summer term correctly", () => {
|
||||
expect(termToFriendly("202620")).toBe("summer-26");
|
||||
expect(termToFriendly("202520")).toBe("summer-25");
|
||||
});
|
||||
|
||||
it("converts fall term correctly", () => {
|
||||
expect(termToFriendly("202630")).toBe("fall-26");
|
||||
expect(termToFriendly("202530")).toBe("fall-25");
|
||||
});
|
||||
|
||||
it("returns null for invalid codes", () => {
|
||||
expect(termToFriendly("20261")).toBe(null);
|
||||
expect(termToFriendly("2026100")).toBe(null);
|
||||
expect(termToFriendly("202640")).toBe(null); // Invalid semester code
|
||||
expect(termToFriendly("")).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("termToBanner", () => {
|
||||
it("converts spring term correctly", () => {
|
||||
expect(termToBanner("spring-26")).toBe("202610");
|
||||
expect(termToBanner("spring-25")).toBe("202510");
|
||||
});
|
||||
|
||||
it("converts summer term correctly", () => {
|
||||
expect(termToBanner("summer-26")).toBe("202620");
|
||||
expect(termToBanner("summer-25")).toBe("202520");
|
||||
});
|
||||
|
||||
it("converts fall term correctly", () => {
|
||||
expect(termToBanner("fall-26")).toBe("202630");
|
||||
expect(termToBanner("fall-25")).toBe("202530");
|
||||
});
|
||||
|
||||
it("returns null for invalid formats", () => {
|
||||
expect(termToBanner("winter-26")).toBe(null);
|
||||
expect(termToBanner("spring26")).toBe(null);
|
||||
expect(termToBanner("spring-2026")).toBe(null);
|
||||
expect(termToBanner("26-spring")).toBe(null);
|
||||
expect(termToBanner("")).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("round-trip conversion", () => {
|
||||
it("converts back and forth correctly", () => {
|
||||
const bannerCodes = ["202610", "202620", "202630", "202510"];
|
||||
|
||||
for (const code of bannerCodes) {
|
||||
const friendly = termToFriendly(code);
|
||||
expect(friendly).not.toBeNull();
|
||||
const backToBanner = termToBanner(friendly!);
|
||||
expect(backToBanner).toBe(code);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Convert between Banner's internal term codes (e.g., "202620") and human-friendly format (e.g., "summer-26")
|
||||
*/
|
||||
|
||||
export type SemesterName = "spring" | "summer" | "fall";
|
||||
|
||||
const SEMESTER_CODES: Record<string, SemesterName> = {
|
||||
"10": "spring",
|
||||
"20": "summer",
|
||||
"30": "fall",
|
||||
};
|
||||
|
||||
const SEMESTER_TO_CODE: Record<SemesterName, string> = {
|
||||
spring: "10",
|
||||
summer: "20",
|
||||
fall: "30",
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert Banner term code (e.g., "202620") to friendly format (e.g., "summer-26")
|
||||
*/
|
||||
export function termToFriendly(bannerCode: string): string | null {
|
||||
if (bannerCode.length !== 6) return null;
|
||||
|
||||
const year = bannerCode.substring(0, 4);
|
||||
const semesterCode = bannerCode.substring(4, 6);
|
||||
const semester = SEMESTER_CODES[semesterCode];
|
||||
|
||||
if (!semester) return null;
|
||||
|
||||
const shortYear = year.substring(2, 4);
|
||||
return `${semester}-${shortYear}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert friendly format (e.g., "summer-26") to Banner term code (e.g., "202620")
|
||||
*/
|
||||
export function termToBanner(friendly: string): string | null {
|
||||
const match = friendly.match(/^(spring|summer|fall)-(\d{2})$/);
|
||||
if (!match) return null;
|
||||
|
||||
const [, semester, shortYear] = match;
|
||||
const semesterCode = SEMESTER_TO_CODE[semester as SemesterName];
|
||||
if (!semesterCode) return null;
|
||||
|
||||
const fullYear = `20${shortYear}`;
|
||||
return `${fullYear}${semesterCode}`;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
* targets. This module owns the AnimMap lifecycle: syncing targets,
|
||||
* stepping current values, and pruning offscreen entries.
|
||||
*/
|
||||
import { VALUE_EASE, MAXY_EASE, SETTLE_THRESHOLD, MIN_MAXY } from "./constants";
|
||||
import { MAXY_EASE, MIN_MAXY, SETTLE_THRESHOLD, VALUE_EASE } from "./constants";
|
||||
import type { AnimEntry, TimeSlot } from "./types";
|
||||
|
||||
export type AnimMap = Map<number, Map<string, AnimEntry>>;
|
||||
|
||||
@@ -4,28 +4,28 @@
|
||||
* Every function takes a {@link ChartContext} plus any data it needs.
|
||||
* No Svelte reactivity, no side-effects beyond drawing on the context.
|
||||
*/
|
||||
import { stack, area, curveMonotoneX, type Series } from "d3-shape";
|
||||
import { type Series, area, curveMonotoneX, stack } from "d3-shape";
|
||||
import { timeFormat } from "d3-time-format";
|
||||
|
||||
import { getSubjectColor } from "./data";
|
||||
import type { AnimMap } from "./animation";
|
||||
import { getStackSubjects } from "./viewport";
|
||||
import type { ChartContext, TimeSlot } from "./types";
|
||||
import {
|
||||
GRID_ALPHA,
|
||||
HOUR_GRID_ALPHA,
|
||||
NOW_LINE_WIDTH,
|
||||
NOW_LINE_COLOR,
|
||||
NOW_TRIANGLE_HEIGHT,
|
||||
NOW_TRIANGLE_HALF_WIDTH,
|
||||
NOW_LABEL_FONT,
|
||||
HOVER_HIGHLIGHT_ALPHA,
|
||||
AREA_FILL_ALPHA,
|
||||
AREA_STROKE_ALPHA,
|
||||
SLOT_INTERVAL_MS,
|
||||
SETTLE_THRESHOLD,
|
||||
AXIS_FONT,
|
||||
GRID_ALPHA,
|
||||
HOUR_GRID_ALPHA,
|
||||
HOVER_HIGHLIGHT_ALPHA,
|
||||
NOW_LABEL_FONT,
|
||||
NOW_LINE_COLOR,
|
||||
NOW_LINE_WIDTH,
|
||||
NOW_TRIANGLE_HALF_WIDTH,
|
||||
NOW_TRIANGLE_HEIGHT,
|
||||
SETTLE_THRESHOLD,
|
||||
SLOT_INTERVAL_MS,
|
||||
} from "./constants";
|
||||
import { getSubjectColor } from "./data";
|
||||
import type { ChartContext, TimeSlot } from "./types";
|
||||
import { getStackSubjects } from "./viewport";
|
||||
|
||||
// ── Formatters (allocated once) ─────────────────────────────────────
|
||||
const fmtHour = timeFormat("%-I %p");
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* the missing segments when the view expands into unloaded territory.
|
||||
* Fetches are throttled so rapid panning/zooming doesn't flood the API.
|
||||
*/
|
||||
import { client, type TimelineRange } from "$lib/api";
|
||||
import { type TimelineRange, client } from "$lib/api";
|
||||
import { SLOT_INTERVAL_MS } from "./constants";
|
||||
import type { TimeSlot } from "./types";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Pure viewport utility functions: binary search, visible-slot slicing,
|
||||
* hit-testing, and snapping for the timeline canvas.
|
||||
*/
|
||||
import { SLOT_INTERVAL_MS, RENDER_MARGIN_SLOTS } from "./constants";
|
||||
import { RENDER_MARGIN_SLOTS, SLOT_INTERVAL_MS } from "./constants";
|
||||
import type { TimeSlot } from "./types";
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/state";
|
||||
import { authStore } from "$lib/auth.svelte";
|
||||
import PageTransition from "$lib/components/PageTransition.svelte";
|
||||
import ErrorBoundaryFallback from "$lib/components/ErrorBoundaryFallback.svelte";
|
||||
import PageTransition from "$lib/components/PageTransition.svelte";
|
||||
import {
|
||||
Activity,
|
||||
ClipboardList,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { client, type AdminStatus } from "$lib/api";
|
||||
import { type AdminStatus, client } from "$lib/api";
|
||||
import { formatNumber } from "$lib/utils";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let status = $state<AdminStatus | null>(null);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { slide, fade } from "svelte/transition";
|
||||
import {
|
||||
client,
|
||||
type CandidateResponse,
|
||||
type InstructorDetailResponse,
|
||||
type InstructorListItem,
|
||||
type InstructorStats,
|
||||
type InstructorDetailResponse,
|
||||
type CandidateResponse,
|
||||
client,
|
||||
} from "$lib/api";
|
||||
import SimpleTooltip from "$lib/components/SimpleTooltip.svelte";
|
||||
import { formatInstructorName, isRatingValid, ratingStyle } from "$lib/course";
|
||||
import { themeStore } from "$lib/stores/theme.svelte";
|
||||
import {
|
||||
@@ -19,7 +18,8 @@ import {
|
||||
Search,
|
||||
X,
|
||||
} from "@lucide/svelte";
|
||||
import SimpleTooltip from "$lib/components/SimpleTooltip.svelte";
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import { fade, slide } from "svelte/transition";
|
||||
import CandidateCard from "./CandidateCard.svelte";
|
||||
|
||||
// --- State ---
|
||||
|
||||
@@ -3,6 +3,7 @@ import { type ScrapeJob, client } from "$lib/api";
|
||||
import { FlexRender, createSvelteTable } from "$lib/components/ui/data-table/index.js";
|
||||
import { formatAbsoluteDate } from "$lib/date";
|
||||
import { formatDuration } from "$lib/time";
|
||||
import { type ConnectionState, ScrapeJobsStore } from "$lib/ws";
|
||||
import { ArrowDown, ArrowUp, ArrowUpDown, TriangleAlert } from "@lucide/svelte";
|
||||
import {
|
||||
type ColumnDef,
|
||||
@@ -12,7 +13,6 @@ import {
|
||||
getSortedRowModel,
|
||||
} from "@tanstack/table-core";
|
||||
import { onMount } from "svelte";
|
||||
import { type ConnectionState, ScrapeJobsStore } from "$lib/ws";
|
||||
|
||||
let jobs = $state<ScrapeJob[]>([]);
|
||||
let connectionState = $state<ConnectionState>("disconnected");
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { client } from "$lib/api";
|
||||
import type { User } from "$lib/bindings";
|
||||
import { Shield, ShieldOff } from "@lucide/svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let users = $state<User[]>([]);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
import "overlayscrollbars/overlayscrollbars.css";
|
||||
import "./layout.css";
|
||||
import { page } from "$app/state";
|
||||
import PageTransition from "$lib/components/PageTransition.svelte";
|
||||
import { authStore } from "$lib/auth.svelte";
|
||||
import ErrorBoundaryFallback from "$lib/components/ErrorBoundaryFallback.svelte";
|
||||
import NavBar from "$lib/components/NavBar.svelte";
|
||||
import PageTransition from "$lib/components/PageTransition.svelte";
|
||||
import { useOverlayScrollbars } from "$lib/composables/useOverlayScrollbars.svelte";
|
||||
import { initNavigation } from "$lib/stores/navigation.svelte";
|
||||
import { themeStore } from "$lib/stores/theme.svelte";
|
||||
import { authStore } from "$lib/auth.svelte";
|
||||
import { Tooltip } from "bits-ui";
|
||||
import ErrorBoundaryFallback from "$lib/components/ErrorBoundaryFallback.svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import {
|
||||
type Subject,
|
||||
type SearchResponse,
|
||||
type SortColumn,
|
||||
type SortDirection,
|
||||
type Subject,
|
||||
client,
|
||||
} from "$lib/api";
|
||||
import type { SortingState } from "@tanstack/table-core";
|
||||
import CourseTable from "$lib/components/CourseTable.svelte";
|
||||
import Footer from "$lib/components/Footer.svelte";
|
||||
import Pagination from "$lib/components/Pagination.svelte";
|
||||
import SearchFilters from "$lib/components/SearchFilters.svelte";
|
||||
import SearchStatus, { type SearchMeta } from "$lib/components/SearchStatus.svelte";
|
||||
import CourseTable from "$lib/components/CourseTable.svelte";
|
||||
import Pagination from "$lib/components/Pagination.svelte";
|
||||
import Footer from "$lib/components/Footer.svelte";
|
||||
import { termToBanner, termToFriendly } from "$lib/term-format";
|
||||
import type { SortingState } from "@tanstack/table-core";
|
||||
import { untrack } from "svelte";
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
// Read initial state from URL params (intentionally captured once)
|
||||
const initialParams = untrack(() => new URLSearchParams(data.url.search));
|
||||
|
||||
// Filter state
|
||||
let selectedTerm = $state(untrack(() => initialParams.get("term") ?? data.terms[0]?.code ?? ""));
|
||||
// Filter state - only set term from URL if present (no auto-default)
|
||||
const urlTerm = initialParams.get("term");
|
||||
const bannerTerm = urlTerm ? (termToBanner(urlTerm) ?? "") : "";
|
||||
let selectedTerm = $state(bannerTerm);
|
||||
let selectedSubjects: string[] = $state(untrack(() => initialParams.getAll("subject")));
|
||||
let query = $state(initialParams.get("q") ?? "");
|
||||
let openOnly = $state(initialParams.get("open") === "true");
|
||||
@@ -160,7 +163,10 @@ async function performSearch(
|
||||
sort.length > 0 ? (sort[0].desc ? "desc" : "asc") : undefined;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.set("term", term);
|
||||
const friendlyTerm = termToFriendly(term);
|
||||
if (friendlyTerm) {
|
||||
params.set("term", friendlyTerm);
|
||||
}
|
||||
for (const s of subjects) {
|
||||
params.append("subject", s);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
import { BannerApiClient } from "$lib/api";
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export const load: PageLoad = async ({ url, fetch }) => {
|
||||
const client = new BannerApiClient(undefined, fetch);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { type ServiceInfo, type ServiceStatus, type StatusResponse, client } from "$lib/api";
|
||||
import Footer from "$lib/components/Footer.svelte";
|
||||
import SimpleTooltip from "$lib/components/SimpleTooltip.svelte";
|
||||
import { relativeTime } from "$lib/time";
|
||||
import { formatNumber } from "$lib/utils";
|
||||
import {
|
||||
Activity,
|
||||
Bot,
|
||||
@@ -12,11 +16,7 @@ import {
|
||||
WifiOff,
|
||||
XCircle,
|
||||
} from "@lucide/svelte";
|
||||
import SimpleTooltip from "$lib/components/SimpleTooltip.svelte";
|
||||
import Footer from "$lib/components/Footer.svelte";
|
||||
import { type ServiceStatus, type ServiceInfo, type StatusResponse, client } from "$lib/api";
|
||||
import { relativeTime } from "$lib/time";
|
||||
import { formatNumber } from "$lib/utils";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
const REFRESH_INTERVAL = import.meta.env.DEV ? 3000 : 30000;
|
||||
const REQUEST_TIMEOUT = 10000;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import TimelineCanvas from "$lib/components/TimelineCanvas.svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
// Prevent body scroll while this page is mounted via a CSS class
|
||||
// (avoids conflicting with other components that may manage overflow).
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import { defineConfig } from "vite";
|
||||
import { resolve } from "node:path";
|
||||
import { readFileSync, existsSync } from "node:fs";
|
||||
|
||||
function getVersion() {
|
||||
const filename = "Cargo.toml";
|
||||
|
||||
Reference in New Issue
Block a user