Skip to content

Commit 5b47524

Browse files
authored
feat: rebrand atlas frontend (#63)
* feat: rebrand atlas frontend * Fix CI and make Docker stack portable * Fix clippy warning in atlas-server * Address review feedback * style: format contracts handler test
1 parent 3133fbb commit 5b47524

36 files changed

Lines changed: 1818 additions & 743 deletions

.env.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ ENABLE_DA_TRACKING=false
6363
# FAUCET_AMOUNT=0.01
6464
# FAUCET_COOLDOWN_MINUTES=30
6565

66+
# Optional: force Docker to emulate/build a specific architecture.
67+
# Leave unset for native host builds.
68+
# Common values:
69+
# DOCKER_DEFAULT_PLATFORM=linux/amd64
70+
# DOCKER_DEFAULT_PLATFORM=linux/arm64
71+
# DOCKER_DEFAULT_PLATFORM=linux/arm64/v8
72+
6673
# Optional snapshot feature (daily pg_dump backups)
6774
# SNAPSHOT_ENABLED=false
6875
# SNAPSHOT_TIME=03:00 # UTC time (HH:MM) to run daily pg_dump

.github/workflows/ci.yml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ jobs:
2222
uses: actions/checkout@v4
2323

2424
- name: Setup Rust
25-
uses: dtolnay/rust-toolchain@stable
25+
uses: dtolnay/rust-toolchain@master
2626
with:
27+
toolchain: stable
2728
components: rustfmt
2829

2930
- name: Format
@@ -40,8 +41,9 @@ jobs:
4041
uses: actions/checkout@v4
4142

4243
- name: Setup Rust
43-
uses: dtolnay/rust-toolchain@stable
44+
uses: dtolnay/rust-toolchain@master
4445
with:
46+
toolchain: stable
4547
components: clippy
4648

4749
- name: Cache Cargo
@@ -63,7 +65,9 @@ jobs:
6365
uses: actions/checkout@v4
6466

6567
- name: Setup Rust
66-
uses: dtolnay/rust-toolchain@stable
68+
uses: dtolnay/rust-toolchain@master
69+
with:
70+
toolchain: stable
6771

6872
- name: Cache Cargo
6973
uses: Swatinem/rust-cache@v2
@@ -102,7 +106,9 @@ jobs:
102106
uses: actions/checkout@v4
103107

104108
- name: Setup Rust
105-
uses: dtolnay/rust-toolchain@stable
109+
uses: dtolnay/rust-toolchain@master
110+
with:
111+
toolchain: stable
106112

107113
- name: Cache Cargo
108114
uses: Swatinem/rust-cache@v2
@@ -194,7 +200,9 @@ jobs:
194200
fetch-depth: 0
195201

196202
- name: Setup Rust
197-
uses: dtolnay/rust-toolchain@stable
203+
uses: dtolnay/rust-toolchain@master
204+
with:
205+
toolchain: stable
198206

199207
- name: Cache Cargo
200208
uses: Swatinem/rust-cache@v2

backend/crates/atlas-server/src/api/handlers/contracts.rs

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ fn validate_compiler_version(version: &str) -> Result<(), AtlasError> {
324324
/// Uses an atomic write (temp → rename) so concurrent requests for the same
325325
/// version don't corrupt the cached binary.
326326
async fn get_solc_binary(version: &str, cache_dir: &str) -> Result<PathBuf, AtlasError> {
327-
let target = solc_binary_target(OS, ARCH)?;
327+
let target = solc_binary_target(OS, ARCH, version)?;
328328
let filename = format!("solc-{target}-{version}");
329329
let cache_path = PathBuf::from(cache_dir).join(&filename);
330330

@@ -396,16 +396,48 @@ async fn get_solc_binary(version: &str, cache_dir: &str) -> Result<PathBuf, Atla
396396
Ok(cache_path)
397397
}
398398

399-
fn solc_binary_target(os: &str, arch: &str) -> Result<&'static str, AtlasError> {
399+
fn solc_version_triplet(version: &str) -> Option<(u64, u64, u64)> {
400+
let version = version.strip_prefix('v')?;
401+
let version = version.split_once("+commit.")?.0;
402+
let mut parts = version.split('.');
403+
404+
let major = parts.next()?.parse().ok()?;
405+
let minor = parts.next()?.parse().ok()?;
406+
let patch = parts.next()?.parse().ok()?;
407+
408+
if parts.next().is_some() {
409+
return None;
410+
}
411+
412+
Some((major, minor, patch))
413+
}
414+
415+
fn solc_binary_target(os: &str, arch: &str, version: &str) -> Result<&'static str, AtlasError> {
400416
match (os, arch) {
401417
("linux", "x86_64") => Ok("linux-amd64"),
418+
("linux", "aarch64") => {
419+
let Some(version_triplet) = solc_version_triplet(version) else {
420+
return Err(AtlasError::Verification(format!(
421+
"failed to determine native solc target for compiler version {version}"
422+
)));
423+
};
424+
425+
if version_triplet >= (0, 8, 31) {
426+
Ok("linux-arm64")
427+
} else {
428+
Err(AtlasError::Verification(format!(
429+
"compiler version {version} is not available for linux-arm64; \
430+
official Solidity linux-arm64 binaries start at v0.8.31"
431+
)))
432+
}
433+
}
402434
// Solidity's official static macOS binaries are currently published under
403435
// macosx-amd64. Apple Silicon can execute them natively via Rosetta.
404436
("macos", "x86_64") | ("macos", "aarch64") => Ok("macosx-amd64"),
405437
_ => Err(AtlasError::Verification(format!(
406438
"unsupported platform for native solc download: {os}/{arch}. \
407-
Official Solidity static binaries are currently available for linux/x86_64 \
408-
and macOS. For Docker on Apple Silicon, run atlas-server as linux/amd64."
439+
Official Solidity static binaries are currently available for \
440+
linux/x86_64, linux/aarch64, and macOS."
409441
))),
410442
}
411443
}
@@ -1004,23 +1036,34 @@ mod tests {
10041036
#[test]
10051037
fn solc_binary_target_supports_linux_amd64() {
10061038
assert_eq!(
1007-
solc_binary_target("linux", "x86_64").unwrap(),
1039+
solc_binary_target("linux", "x86_64", "v0.8.20+commit.a1b79de6").unwrap(),
10081040
"linux-amd64"
10091041
);
10101042
}
10111043

1044+
#[test]
1045+
fn solc_binary_target_supports_linux_arm64() {
1046+
assert_eq!(
1047+
solc_binary_target("linux", "aarch64", "v0.8.31+commit.2d38a763").unwrap(),
1048+
"linux-arm64"
1049+
);
1050+
}
1051+
10121052
#[test]
10131053
fn solc_binary_target_supports_macos_arm64_via_rosetta() {
10141054
assert_eq!(
1015-
solc_binary_target("macos", "aarch64").unwrap(),
1055+
solc_binary_target("macos", "aarch64", "v0.8.20+commit.a1b79de6").unwrap(),
10161056
"macosx-amd64"
10171057
);
10181058
}
10191059

10201060
#[test]
1021-
fn solc_binary_target_rejects_linux_arm64() {
1022-
let err = solc_binary_target("linux", "aarch64").unwrap_err();
1023-
assert!(matches!(err, AtlasError::Verification(_)));
1061+
fn solc_binary_target_rejects_old_linux_arm64_versions() {
1062+
let err = solc_binary_target("linux", "aarch64", "v0.8.30+commit.73712a01").unwrap_err();
1063+
1064+
assert!(
1065+
matches!(err, AtlasError::Verification(message) if message.contains("not available for linux-arm64"))
1066+
);
10241067
}
10251068

10261069
#[test]

backend/crates/atlas-server/src/main.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ pub(crate) fn postgres_connection_config(db_url: &str) -> Result<PostgresConnect
120120
"dbname" if !value.is_empty() => {
121121
database_name = value.into_owned();
122122
}
123+
"dbname" => {}
123124
"host" => {
124125
set_pg_env(&mut env_vars, "PGHOST", value.as_ref());
125126
}
@@ -749,6 +750,29 @@ mod tests {
749750
assert_eq!(env_value(&config, "PGDATABASE"), Some("query_db"));
750751
}
751752

753+
#[test]
754+
fn postgres_connection_config_ignores_empty_dbname_query_without_path() {
755+
let err = match postgres_connection_config("postgres://user:secret@localhost:5432/?dbname=")
756+
{
757+
Ok(_) => panic!("expected empty dbname query without path database to fail"),
758+
Err(err) => err,
759+
};
760+
761+
assert!(err.to_string().contains("must include a database name"));
762+
}
763+
764+
#[test]
765+
fn postgres_connection_config_ignores_empty_dbname_query_with_path_database() {
766+
let config = postgres_connection_config(
767+
"postgres://user:secret@localhost:5432/base_db?dbname=&host=query-host",
768+
)
769+
.unwrap();
770+
771+
assert_eq!(config.database_name, "base_db");
772+
assert_eq!(env_value(&config, "PGHOST"), Some("query-host"));
773+
assert_eq!(env_value(&config, "PGDATABASE"), Some("base_db"));
774+
}
775+
752776
#[test]
753777
fn portable_pg_dump_flags_omit_source_ownership_and_acls() {
754778
assert_eq!(

docker-compose.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ services:
1616
retries: 5
1717

1818
atlas-server:
19-
# Contract verification downloads Solidity's official linux-amd64 binary.
20-
# Keep atlas-server on amd64 locally so verification works on Apple Silicon.
21-
platform: linux/amd64
2219
build:
2320
context: ./backend
2421
dockerfile: Dockerfile
@@ -40,6 +37,8 @@ services:
4037
FAUCET_ENABLED: ${FAUCET_ENABLED:-false}
4138
CHAIN_NAME: ${CHAIN_NAME:-Unknown}
4239
CHAIN_LOGO_URL: ${CHAIN_LOGO_URL:-}
40+
CHAIN_LOGO_URL_LIGHT: ${CHAIN_LOGO_URL_LIGHT:-}
41+
CHAIN_LOGO_URL_DARK: ${CHAIN_LOGO_URL_DARK:-}
4342
ACCENT_COLOR: ${ACCENT_COLOR:-}
4443
BACKGROUND_COLOR_DARK: ${BACKGROUND_COLOR_DARK:-}
4544
BACKGROUND_COLOR_LIGHT: ${BACKGROUND_COLOR_LIGHT:-}

frontend/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ const StatusPage = lazy(() => import('./pages/StatusPage'));
2424

2525
function PageLoader() {
2626
return (
27-
<div className="flex items-center justify-center h-64">
28-
<span className="text-gray-500 text-sm">Loading...</span>
27+
<div className="card flex h-64 items-center justify-center">
28+
<span className="kicker">Loading route</span>
2929
</div>
3030
);
3131
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import darkLogo from './evolve-logo.svg';
2+
import lightLogo from './evolve-logo-light.svg';
3+
import type { Theme } from '../context/theme-context';
4+
5+
export function getDefaultLogo(theme: Theme): string {
6+
return theme === 'light' ? lightLogo : darkLogo;
7+
}
8+
9+
export { darkLogo as defaultDarkLogo, lightLogo as defaultLightLogo };

0 commit comments

Comments
 (0)