fix(apps): repair netbird login and iframe focus
This commit is contained in:
parent
eeb08fc78f
commit
bd69ef41d5
@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.7.74-alpha (2026-05-19)
|
||||||
|
|
||||||
|
- App-session right panels now re-focus the iframe after load and when the frame area is activated, so wheel/touch scrolling works immediately after switching tabs or selecting an app on shorter screens.
|
||||||
|
- NetBird now launches through a unified local origin on port `8087` that proxies the dashboard plus `/oauth2`, `/api`, relay, WebSocket, and gRPC routes to `netbird-server`, fixing the embedded login flow that previously ended in `Unauthenticated` or `404 page not found` after logout.
|
||||||
|
- Existing NetBird installs are repaired on adopt/start by rewriting `config.yaml`, `dashboard.env`, and the local nginx proxy config, then creating the missing `netbird-dashboard` and `netbird` proxy containers when needed while preserving NetBird data.
|
||||||
|
- Saleor is still pending and is not included in this release; its registry/installer work remains local until it can be validated separately.
|
||||||
|
- Validation passed with catalog JSON checks, `npm run type-check`, `cargo fmt --all --check --manifest-path core/Cargo.toml`, and `cargo check -p archipelago --manifest-path core/Cargo.toml`.
|
||||||
|
|
||||||
## v1.7.73-alpha (2026-05-19)
|
## v1.7.73-alpha (2026-05-19)
|
||||||
|
|
||||||
- Mobile app launches for iframe-blocked apps now open the direct app URL in a new browser tab immediately instead of landing in a broken in-shell webview that requires a second tap.
|
- Mobile app launches for iframe-blocked apps now open the direct app URL in a new browser tab immediately instead of landing in a broken in-shell webview that requires a second tap.
|
||||||
|
|||||||
2
core/Cargo.lock
generated
2
core/Cargo.lock
generated
@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "archipelago"
|
name = "archipelago"
|
||||||
version = "1.7.72-alpha"
|
version = "1.7.74-alpha"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"archipelago-container",
|
"archipelago-container",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "archipelago"
|
name = "archipelago"
|
||||||
version = "1.7.73-alpha"
|
version = "1.7.74-alpha"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Archipelago Bitcoin Node OS - Native backend"
|
description = "Archipelago Bitcoin Node OS - Native backend"
|
||||||
authors = ["Archipelago Team"]
|
authors = ["Archipelago Team"]
|
||||||
|
|||||||
@ -495,7 +495,11 @@ pub(super) fn all_container_names(package_id: &str) -> Vec<String> {
|
|||||||
"indeedhub-ffmpeg".into(),
|
"indeedhub-ffmpeg".into(),
|
||||||
"indeedhub".into(),
|
"indeedhub".into(),
|
||||||
],
|
],
|
||||||
"netbird" => vec!["netbird".into(), "netbird-server".into()],
|
"netbird" => vec![
|
||||||
|
"netbird".into(),
|
||||||
|
"netbird-dashboard".into(),
|
||||||
|
"netbird-server".into(),
|
||||||
|
],
|
||||||
"nostr-vpn" => vec![
|
"nostr-vpn" => vec![
|
||||||
"nostr-vpn".into(),
|
"nostr-vpn".into(),
|
||||||
"archy-nostr-vpn".into(),
|
"archy-nostr-vpn".into(),
|
||||||
|
|||||||
@ -288,7 +288,7 @@ pub(super) fn startup_order(package_id: &str) -> &'static [&'static str] {
|
|||||||
"btcpay-server" | "btcpayserver" | "btcpay" => {
|
"btcpay-server" | "btcpayserver" | "btcpay" => {
|
||||||
&["archy-btcpay-db", "archy-nbxplorer", "btcpay-server"]
|
&["archy-btcpay-db", "archy-nbxplorer", "btcpay-server"]
|
||||||
}
|
}
|
||||||
"netbird" => &["netbird-server", "netbird"],
|
"netbird" => &["netbird-server", "netbird-dashboard", "netbird"],
|
||||||
"penpot" | "penpot-frontend" => &[
|
"penpot" | "penpot-frontend" => &[
|
||||||
"penpot-postgres",
|
"penpot-postgres",
|
||||||
"penpot-valkey",
|
"penpot-valkey",
|
||||||
@ -392,7 +392,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn netbird_start_order_starts_server_before_dashboard() {
|
fn netbird_start_order_starts_server_before_dashboard() {
|
||||||
assert_eq!(startup_order("netbird"), &["netbird-server", "netbird"]);
|
assert_eq!(
|
||||||
|
startup_order("netbird"),
|
||||||
|
&["netbird-server", "netbird-dashboard", "netbird"]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -98,6 +98,7 @@ async fn repair_stack_before_adopt(stack_name: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"indeedhub" => repair_indeedhub_network_aliases().await,
|
"indeedhub" => repair_indeedhub_network_aliases().await,
|
||||||
|
"netbird" => repair_netbird_unified_origin().await,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,6 +145,73 @@ pub(in crate::api::rpc::package) async fn repair_indeedhub_network_aliases() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn repair_netbird_unified_origin() {
|
||||||
|
let host_ip = detect_netbird_public_host_ip()
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(|| "127.0.0.1".to_string());
|
||||||
|
let _ = write_netbird_config_files(&host_ip).await;
|
||||||
|
|
||||||
|
let names = tokio::process::Command::new("podman")
|
||||||
|
.args(["ps", "-a", "--format", "{{.Names}}"])
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.map(|o| String::from_utf8_lossy(&o.stdout).to_string())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let has_proxy = names.lines().any(|n| n.trim() == "netbird");
|
||||||
|
let has_dashboard = names.lines().any(|n| n.trim() == "netbird-dashboard");
|
||||||
|
if has_proxy && has_dashboard {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if has_proxy && !has_dashboard {
|
||||||
|
let _ = tokio::process::Command::new("podman")
|
||||||
|
.args(["rm", "-f", "netbird"])
|
||||||
|
.output()
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = tokio::process::Command::new("podman")
|
||||||
|
.args(["network", "create", "netbird-net"])
|
||||||
|
.output()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let _ = tokio::process::Command::new("podman")
|
||||||
|
.args([
|
||||||
|
"run",
|
||||||
|
"-d",
|
||||||
|
"--name",
|
||||||
|
"netbird-dashboard",
|
||||||
|
"--network",
|
||||||
|
"netbird-net",
|
||||||
|
"--restart=unless-stopped",
|
||||||
|
"--env-file",
|
||||||
|
"/var/lib/archipelago/netbird/dashboard.env",
|
||||||
|
NETBIRD_DASHBOARD_IMAGE,
|
||||||
|
])
|
||||||
|
.output()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let _ = tokio::process::Command::new("podman")
|
||||||
|
.args([
|
||||||
|
"run",
|
||||||
|
"-d",
|
||||||
|
"--name",
|
||||||
|
"netbird",
|
||||||
|
"--network",
|
||||||
|
"netbird-net",
|
||||||
|
"--restart=unless-stopped",
|
||||||
|
"-p",
|
||||||
|
"8087:80",
|
||||||
|
"-v",
|
||||||
|
"/var/lib/archipelago/netbird/nginx.conf:/etc/nginx/conf.d/default.conf:ro",
|
||||||
|
NETBIRD_PROXY_IMAGE,
|
||||||
|
])
|
||||||
|
.output()
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
async fn run_required_stack_command(
|
async fn run_required_stack_command(
|
||||||
stack_name: &str,
|
stack_name: &str,
|
||||||
label: &str,
|
label: &str,
|
||||||
@ -313,6 +381,7 @@ const REGISTRY: &str = "146.59.87.168:3000/lfg2025";
|
|||||||
|
|
||||||
const NETBIRD_DASHBOARD_IMAGE: &str = "docker.io/netbirdio/dashboard:v2.38.0";
|
const NETBIRD_DASHBOARD_IMAGE: &str = "docker.io/netbirdio/dashboard:v2.38.0";
|
||||||
const NETBIRD_SERVER_IMAGE: &str = "docker.io/netbirdio/netbird-server:0.71.2";
|
const NETBIRD_SERVER_IMAGE: &str = "docker.io/netbirdio/netbird-server:0.71.2";
|
||||||
|
const NETBIRD_PROXY_IMAGE: &str = "docker.io/library/nginx:1.27-alpine";
|
||||||
|
|
||||||
/// Pull an image with retry and exponential backoff (3 attempts).
|
/// Pull an image with retry and exponential backoff (3 attempts).
|
||||||
async fn pull_image_with_retry(image: &str) -> Result<()> {
|
async fn pull_image_with_retry(image: &str) -> Result<()> {
|
||||||
@ -1364,8 +1433,12 @@ impl RpcHandler {
|
|||||||
|
|
||||||
/// Install self-hosted NetBird (dashboard + combined management/signal/relay server).
|
/// Install self-hosted NetBird (dashboard + combined management/signal/relay server).
|
||||||
pub(super) async fn install_netbird_stack(&self) -> Result<serde_json::Value> {
|
pub(super) async fn install_netbird_stack(&self) -> Result<serde_json::Value> {
|
||||||
if let Some(adopted) =
|
if let Some(adopted) = adopt_stack_if_exists(
|
||||||
adopt_stack_if_exists("netbird", "netbird", &["netbird", "netbird-server"]).await?
|
"netbird",
|
||||||
|
"netbird",
|
||||||
|
&["netbird-server", "netbird-dashboard", "netbird"],
|
||||||
|
)
|
||||||
|
.await?
|
||||||
{
|
{
|
||||||
return Ok(adopted);
|
return Ok(adopted);
|
||||||
}
|
}
|
||||||
@ -1375,18 +1448,22 @@ impl RpcHandler {
|
|||||||
|
|
||||||
self.set_install_phase("netbird", InstallPhase::PullingImage)
|
self.set_install_phase("netbird", InstallPhase::PullingImage)
|
||||||
.await;
|
.await;
|
||||||
for (i, image) in [NETBIRD_DASHBOARD_IMAGE, NETBIRD_SERVER_IMAGE]
|
for (i, image) in [
|
||||||
.iter()
|
NETBIRD_DASHBOARD_IMAGE,
|
||||||
.enumerate()
|
NETBIRD_SERVER_IMAGE,
|
||||||
|
NETBIRD_PROXY_IMAGE,
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
{
|
{
|
||||||
self.set_install_progress("netbird", i as u64, 2).await;
|
self.set_install_progress("netbird", i as u64, 3).await;
|
||||||
pull_image_with_retry(image)
|
pull_image_with_retry(image)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("Failed to pull NetBird image: {}", image))?;
|
.with_context(|| format!("Failed to pull NetBird image: {}", image))?;
|
||||||
}
|
}
|
||||||
self.set_install_progress("netbird", 2, 2).await;
|
self.set_install_progress("netbird", 3, 3).await;
|
||||||
|
|
||||||
for name in ["netbird", "netbird-server"] {
|
for name in ["netbird", "netbird-dashboard", "netbird-server"] {
|
||||||
let _ = tokio::process::Command::new("podman")
|
let _ = tokio::process::Command::new("podman")
|
||||||
.args(["rm", "-f", name])
|
.args(["rm", "-f", name])
|
||||||
.status()
|
.status()
|
||||||
@ -1407,58 +1484,7 @@ impl RpcHandler {
|
|||||||
let host_ip = detect_netbird_public_host_ip()
|
let host_ip = detect_netbird_public_host_ip()
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|| self.config.host_ip.clone());
|
.unwrap_or_else(|| self.config.host_ip.clone());
|
||||||
let dashboard_origin = format!("http://{}:8087", host_ip);
|
write_netbird_config_files(&host_ip).await?;
|
||||||
let mgmt_origin = format!("http://{}:8086", host_ip);
|
|
||||||
let relay_secret = read_or_generate_b64_secret("netbird-relay-auth-secret").await;
|
|
||||||
let encryption_key = read_or_generate_b64_secret("netbird-store-encryption-key").await;
|
|
||||||
let config = format!(
|
|
||||||
r#"server:
|
|
||||||
listenAddress: ":80"
|
|
||||||
exposedAddress: "{mgmt_origin}"
|
|
||||||
stunPorts:
|
|
||||||
- 3478
|
|
||||||
metricsPort: 9090
|
|
||||||
healthcheckAddress: ":9000"
|
|
||||||
logLevel: "info"
|
|
||||||
logFile: "console"
|
|
||||||
authSecret: "{relay_secret}"
|
|
||||||
dataDir: "/var/lib/netbird"
|
|
||||||
auth:
|
|
||||||
issuer: "{mgmt_origin}/oauth2"
|
|
||||||
localAuthDisabled: false
|
|
||||||
signKeyRefreshEnabled: true
|
|
||||||
dashboardRedirectURIs:
|
|
||||||
- "{dashboard_origin}/nb-auth"
|
|
||||||
- "{dashboard_origin}/nb-silent-auth"
|
|
||||||
cliRedirectURIs:
|
|
||||||
- "http://localhost:53000/"
|
|
||||||
store:
|
|
||||||
engine: "sqlite"
|
|
||||||
encryptionKey: "{encryption_key}"
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
tokio::fs::write("/var/lib/archipelago/netbird/config.yaml", config)
|
|
||||||
.await
|
|
||||||
.context("Failed to write NetBird config.yaml")?;
|
|
||||||
|
|
||||||
let dashboard_env = format!(
|
|
||||||
r#"NETBIRD_MGMT_API_ENDPOINT={mgmt_origin}
|
|
||||||
NETBIRD_MGMT_GRPC_API_ENDPOINT={mgmt_origin}
|
|
||||||
AUTH_AUDIENCE=netbird-dashboard
|
|
||||||
AUTH_CLIENT_ID=netbird-dashboard
|
|
||||||
AUTH_CLIENT_SECRET=
|
|
||||||
AUTH_AUTHORITY={mgmt_origin}/oauth2
|
|
||||||
USE_AUTH0=false
|
|
||||||
AUTH_SUPPORTED_SCOPES=openid profile email groups
|
|
||||||
AUTH_REDIRECT_URI=/nb-auth
|
|
||||||
AUTH_SILENT_REDIRECT_URI=/nb-silent-auth
|
|
||||||
NGINX_SSL_PORT=443
|
|
||||||
LETSENCRYPT_DOMAIN=none
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
tokio::fs::write("/var/lib/archipelago/netbird/dashboard.env", dashboard_env)
|
|
||||||
.await
|
|
||||||
.context("Failed to write NetBird dashboard.env")?;
|
|
||||||
|
|
||||||
let _ = tokio::process::Command::new("podman")
|
let _ = tokio::process::Command::new("podman")
|
||||||
.args(["network", "create", "netbird-net"])
|
.args(["network", "create", "netbird-net"])
|
||||||
@ -1499,19 +1525,39 @@ LETSENCRYPT_DOMAIN=none
|
|||||||
"run",
|
"run",
|
||||||
"-d",
|
"-d",
|
||||||
"--name",
|
"--name",
|
||||||
"netbird",
|
"netbird-dashboard",
|
||||||
"--network",
|
"--network",
|
||||||
"netbird-net",
|
"netbird-net",
|
||||||
"--restart=unless-stopped",
|
"--restart=unless-stopped",
|
||||||
"-p",
|
|
||||||
"8087:80",
|
|
||||||
"--env-file",
|
"--env-file",
|
||||||
"/var/lib/archipelago/netbird/dashboard.env",
|
"/var/lib/archipelago/netbird/dashboard.env",
|
||||||
NETBIRD_DASHBOARD_IMAGE,
|
NETBIRD_DASHBOARD_IMAGE,
|
||||||
]);
|
]);
|
||||||
run_required_stack_command("netbird", "create dashboard", &mut dashboard_cmd).await?;
|
run_required_stack_command("netbird", "create dashboard", &mut dashboard_cmd).await?;
|
||||||
|
|
||||||
wait_for_stack_containers("netbird", &["netbird-server", "netbird"], 60).await?;
|
let mut proxy_cmd = tokio::process::Command::new("podman");
|
||||||
|
proxy_cmd.args([
|
||||||
|
"run",
|
||||||
|
"-d",
|
||||||
|
"--name",
|
||||||
|
"netbird",
|
||||||
|
"--network",
|
||||||
|
"netbird-net",
|
||||||
|
"--restart=unless-stopped",
|
||||||
|
"-p",
|
||||||
|
"8087:80",
|
||||||
|
"-v",
|
||||||
|
"/var/lib/archipelago/netbird/nginx.conf:/etc/nginx/conf.d/default.conf:ro",
|
||||||
|
NETBIRD_PROXY_IMAGE,
|
||||||
|
]);
|
||||||
|
run_required_stack_command("netbird", "create unified proxy", &mut proxy_cmd).await?;
|
||||||
|
|
||||||
|
wait_for_stack_containers(
|
||||||
|
"netbird",
|
||||||
|
&["netbird-server", "netbird-dashboard", "netbird"],
|
||||||
|
60,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
self.set_install_phase("netbird", InstallPhase::WaitingHealthy)
|
self.set_install_phase("netbird", InstallPhase::WaitingHealthy)
|
||||||
.await;
|
.await;
|
||||||
@ -1546,6 +1592,104 @@ async fn read_or_generate_b64_secret(name: &str) -> String {
|
|||||||
secret
|
secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn write_netbird_config_files(host_ip: &str) -> Result<()> {
|
||||||
|
let public_origin = format!("http://{}:8087", host_ip);
|
||||||
|
let server_origin = format!("http://{}:8086", host_ip);
|
||||||
|
let relay_secret = read_or_generate_b64_secret("netbird-relay-auth-secret").await;
|
||||||
|
let encryption_key = read_or_generate_b64_secret("netbird-store-encryption-key").await;
|
||||||
|
let config = format!(
|
||||||
|
r#"server:
|
||||||
|
listenAddress: ":80"
|
||||||
|
exposedAddress: "{public_origin}"
|
||||||
|
stunPorts:
|
||||||
|
- 3478
|
||||||
|
metricsPort: 9090
|
||||||
|
healthcheckAddress: ":9000"
|
||||||
|
logLevel: "info"
|
||||||
|
logFile: "console"
|
||||||
|
authSecret: "{relay_secret}"
|
||||||
|
dataDir: "/var/lib/netbird"
|
||||||
|
auth:
|
||||||
|
issuer: "{public_origin}/oauth2"
|
||||||
|
localAuthDisabled: false
|
||||||
|
signKeyRefreshEnabled: true
|
||||||
|
dashboardRedirectURIs:
|
||||||
|
- "{public_origin}/nb-auth"
|
||||||
|
- "{public_origin}/nb-silent-auth"
|
||||||
|
cliRedirectURIs:
|
||||||
|
- "http://localhost:53000/"
|
||||||
|
store:
|
||||||
|
engine: "sqlite"
|
||||||
|
encryptionKey: "{encryption_key}"
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
tokio::fs::write("/var/lib/archipelago/netbird/config.yaml", config)
|
||||||
|
.await
|
||||||
|
.context("Failed to write NetBird config.yaml")?;
|
||||||
|
|
||||||
|
let dashboard_env = format!(
|
||||||
|
r#"NETBIRD_MGMT_API_ENDPOINT={public_origin}
|
||||||
|
NETBIRD_MGMT_GRPC_API_ENDPOINT={public_origin}
|
||||||
|
AUTH_AUDIENCE=netbird-dashboard
|
||||||
|
AUTH_CLIENT_ID=netbird-dashboard
|
||||||
|
AUTH_CLIENT_SECRET=
|
||||||
|
AUTH_AUTHORITY={public_origin}/oauth2
|
||||||
|
USE_AUTH0=false
|
||||||
|
AUTH_SUPPORTED_SCOPES=openid profile email groups
|
||||||
|
AUTH_REDIRECT_URI=/nb-auth
|
||||||
|
AUTH_SILENT_REDIRECT_URI=/nb-silent-auth
|
||||||
|
NETBIRD_TOKEN_SOURCE=accessToken
|
||||||
|
NGINX_SSL_PORT=443
|
||||||
|
LETSENCRYPT_DOMAIN=none
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
tokio::fs::write("/var/lib/archipelago/netbird/dashboard.env", dashboard_env)
|
||||||
|
.await
|
||||||
|
.context("Failed to write NetBird dashboard.env")?;
|
||||||
|
|
||||||
|
let nginx_conf = format!(
|
||||||
|
r#"server {{
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
location ~ ^/(relay|ws-proxy/) {{
|
||||||
|
proxy_pass http://netbird-server:80;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_read_timeout 1d;
|
||||||
|
}}
|
||||||
|
|
||||||
|
location ~ ^/(api|oauth2)/ {{
|
||||||
|
proxy_pass http://netbird-server:80;
|
||||||
|
}}
|
||||||
|
|
||||||
|
location ~ ^/(signalexchange\.SignalExchange|management\.ManagementService)/ {{
|
||||||
|
grpc_pass grpc://netbird-server:80;
|
||||||
|
grpc_read_timeout 1d;
|
||||||
|
grpc_send_timeout 1d;
|
||||||
|
}}
|
||||||
|
|
||||||
|
location / {{
|
||||||
|
proxy_pass http://netbird-dashboard:80;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
# Direct server remains available for diagnostics at {server_origin}.
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
tokio::fs::write("/var/lib/archipelago/netbird/nginx.conf", nginx_conf)
|
||||||
|
.await
|
||||||
|
.context("Failed to write NetBird nginx.conf")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn detect_netbird_public_host_ip() -> Option<String> {
|
async fn detect_netbird_public_host_ip() -> Option<String> {
|
||||||
let output = tokio::process::Command::new("hostname")
|
let output = tokio::process::Command::new("hostname")
|
||||||
.args(["-I"])
|
.args(["-I"])
|
||||||
|
|||||||
@ -62,6 +62,7 @@ impl DockerPackageScanner {
|
|||||||
"indeedhub-build_relay_1",
|
"indeedhub-build_relay_1",
|
||||||
"indeedhub-build_ffmpeg-worker_1",
|
"indeedhub-build_ffmpeg-worker_1",
|
||||||
"netbird-server",
|
"netbird-server",
|
||||||
|
"netbird-dashboard",
|
||||||
"buildx_buildkit_default",
|
"buildx_buildkit_default",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -169,6 +169,7 @@ fn image_var_for_app(app_id: &str) -> Option<&'static str> {
|
|||||||
"portainer" => Some("PORTAINER_IMAGE"),
|
"portainer" => Some("PORTAINER_IMAGE"),
|
||||||
"tailscale" => Some("TAILSCALE_IMAGE"),
|
"tailscale" => Some("TAILSCALE_IMAGE"),
|
||||||
"netbird" => Some("NETBIRD_DASHBOARD_IMAGE"),
|
"netbird" => Some("NETBIRD_DASHBOARD_IMAGE"),
|
||||||
|
"netbird-dashboard" => Some("NETBIRD_DASHBOARD_IMAGE"),
|
||||||
"netbird-server" => Some("NETBIRD_SERVER_IMAGE"),
|
"netbird-server" => Some("NETBIRD_SERVER_IMAGE"),
|
||||||
|
|
||||||
// Fedimint
|
// Fedimint
|
||||||
@ -302,7 +303,8 @@ pub fn containers_for_stack(app_id: &str) -> Vec<(&'static str, &'static str)> {
|
|||||||
("penpot-frontend", "PENPOT_FRONTEND_IMAGE"),
|
("penpot-frontend", "PENPOT_FRONTEND_IMAGE"),
|
||||||
],
|
],
|
||||||
"netbird" => vec![
|
"netbird" => vec![
|
||||||
("netbird", "NETBIRD_DASHBOARD_IMAGE"),
|
("netbird", "NETBIRD_PROXY_IMAGE"),
|
||||||
|
("netbird-dashboard", "NETBIRD_DASHBOARD_IMAGE"),
|
||||||
("netbird-server", "NETBIRD_SERVER_IMAGE"),
|
("netbird-server", "NETBIRD_SERVER_IMAGE"),
|
||||||
],
|
],
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
|
|||||||
4
neode-ui/package-lock.json
generated
4
neode-ui/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "neode-ui",
|
"name": "neode-ui",
|
||||||
"version": "1.7.73-alpha",
|
"version": "1.7.74-alpha",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "neode-ui",
|
"name": "neode-ui",
|
||||||
"version": "1.7.73-alpha",
|
"version": "1.7.74-alpha",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/dompurify": "^3.0.5",
|
"@types/dompurify": "^3.0.5",
|
||||||
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "neode-ui",
|
"name": "neode-ui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.7.73-alpha",
|
"version": "1.7.74-alpha",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "./start-dev.sh",
|
"start": "./start-dev.sh",
|
||||||
|
|||||||
@ -9,7 +9,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<div v-if="appUrl && !iframeBlocked" class="absolute inset-0 app-session-frame-scroll-host">
|
<div
|
||||||
|
v-if="appUrl && !iframeBlocked"
|
||||||
|
class="absolute inset-0 app-session-frame-scroll-host"
|
||||||
|
tabindex="-1"
|
||||||
|
@pointerdown="focusIframe"
|
||||||
|
@focusin="focusIframe"
|
||||||
|
>
|
||||||
<iframe
|
<iframe
|
||||||
ref="iframeRef"
|
ref="iframeRef"
|
||||||
:key="refreshKey"
|
:key="refreshKey"
|
||||||
@ -17,7 +23,7 @@
|
|||||||
class="w-full h-full border-0 iframe-scrollbar-hide"
|
class="w-full h-full border-0 iframe-scrollbar-hide"
|
||||||
title="App content"
|
title="App content"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@load="$emit('iframeLoad')"
|
@load="handleIframeLoad"
|
||||||
@error="$emit('iframeError')"
|
@error="$emit('iframeError')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -84,7 +90,7 @@ const props = defineProps<{
|
|||||||
refreshKey: number
|
refreshKey: number
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
defineEmits<{
|
const emit = defineEmits<{
|
||||||
iframeLoad: []
|
iframeLoad: []
|
||||||
iframeError: []
|
iframeError: []
|
||||||
refresh: []
|
refresh: []
|
||||||
@ -93,10 +99,20 @@ defineEmits<{
|
|||||||
|
|
||||||
const iframeRef = ref<HTMLIFrameElement | null>(null)
|
const iframeRef = ref<HTMLIFrameElement | null>(null)
|
||||||
|
|
||||||
|
function focusIframe() {
|
||||||
|
iframeRef.value?.focus({ preventScroll: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleIframeLoad() {
|
||||||
|
emit('iframeLoad')
|
||||||
|
await nextTick()
|
||||||
|
requestAnimationFrame(focusIframe)
|
||||||
|
}
|
||||||
|
|
||||||
watch(() => [props.appUrl, props.refreshKey, props.iframeBlocked], async () => {
|
watch(() => [props.appUrl, props.refreshKey, props.iframeBlocked], async () => {
|
||||||
if (!props.appUrl || props.iframeBlocked) return
|
if (!props.appUrl || props.iframeBlocked) return
|
||||||
await nextTick()
|
await nextTick()
|
||||||
iframeRef.value?.focus({ preventScroll: true })
|
requestAnimationFrame(focusIframe)
|
||||||
}, { immediate: true })
|
}, { immediate: true })
|
||||||
|
|
||||||
defineExpose({ iframeRef })
|
defineExpose({ iframeRef })
|
||||||
|
|||||||
@ -180,6 +180,31 @@ init()
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
|
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
|
||||||
|
<!-- v1.7.74-alpha -->
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center gap-2 mb-3">
|
||||||
|
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.74-alpha</span>
|
||||||
|
<span class="text-xs text-white/40">May 19, 2026</span>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||||
|
<p>App-session right panels now re-focus the iframe after load and when the frame area is activated, so scrolling works immediately after selecting an app or switching tabs on shorter screens.</p>
|
||||||
|
<p>NetBird now uses a unified local launch origin on port 8087 that serves the dashboard and proxies auth/API routes to the server, fixing the Unauthenticated and 404 logout/login loop.</p>
|
||||||
|
<p>Existing NetBird installs are repaired during adopt/start by rewriting the config files and creating the missing dashboard/proxy containers while preserving data.</p>
|
||||||
|
<p>Saleor is not in this release yet; it remains pending for separate validation.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- v1.7.73-alpha -->
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center gap-2 mb-3">
|
||||||
|
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.73-alpha</span>
|
||||||
|
<span class="text-xs text-white/40">May 19, 2026</span>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
|
||||||
|
<p>Mobile apps that block iframe embedding now open directly in a browser tab instead of first landing in a broken in-shell webview.</p>
|
||||||
|
<p>App Store search covers all apps while searching, My Apps search can surface matching installable App Store entries, and mobile My Apps/Websites tab switching updates the view reliably.</p>
|
||||||
|
<p>NetBird installs prefer a 100.x tailnet address when available, and app sessions gained iframe auto-focus plus a scroll host for right-frame scrolling.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- v1.7.72-alpha -->
|
<!-- v1.7.72-alpha -->
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-center gap-2 mb-3">
|
<div class="flex items-center gap-2 mb-3">
|
||||||
|
|||||||
@ -50,6 +50,7 @@ PORTAINER_IMAGE="$ARCHY_REGISTRY/portainer:latest"
|
|||||||
TAILSCALE_IMAGE="$ARCHY_REGISTRY/tailscale:stable"
|
TAILSCALE_IMAGE="$ARCHY_REGISTRY/tailscale:stable"
|
||||||
NETBIRD_DASHBOARD_IMAGE="docker.io/netbirdio/dashboard:v2.38.0"
|
NETBIRD_DASHBOARD_IMAGE="docker.io/netbirdio/dashboard:v2.38.0"
|
||||||
NETBIRD_SERVER_IMAGE="docker.io/netbirdio/netbird-server:0.71.2"
|
NETBIRD_SERVER_IMAGE="docker.io/netbirdio/netbird-server:0.71.2"
|
||||||
|
NETBIRD_PROXY_IMAGE="docker.io/library/nginx:1.27-alpine"
|
||||||
ALPINE_TOR_IMAGE="$ARCHY_REGISTRY/alpine-tor:0.4.8.13"
|
ALPINE_TOR_IMAGE="$ARCHY_REGISTRY/alpine-tor:0.4.8.13"
|
||||||
ADGUARDHOME_IMAGE="$ARCHY_REGISTRY/adguardhome:v0.107.55"
|
ADGUARDHOME_IMAGE="$ARCHY_REGISTRY/adguardhome:v0.107.55"
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user