mirror of
https://github.com/moghtech/komodo.git
synced 2026-11-03 19:27:02 -06:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f79987c58 | ||
|
|
e859a919c5 | ||
|
|
2a1270dd74 | ||
|
|
f5a59b0333 | ||
|
|
cacea235f9 |
Generated
+12
-12
@@ -41,7 +41,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alerter"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -943,7 +943,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "command"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"komodo_client",
|
||||
"run_command",
|
||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "environment_file"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
@@ -1439,7 +1439,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "formatting"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"serror",
|
||||
]
|
||||
@@ -1571,7 +1571,7 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "git"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"command",
|
||||
@@ -2191,7 +2191,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_cli"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -2207,7 +2207,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_client"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2238,7 +2238,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_core"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2297,7 +2297,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_periphery"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2384,7 +2384,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "logger"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
@@ -3090,7 +3090,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "periphery_client"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
@@ -4865,7 +4865,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "update_logger"
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.16.6"
|
||||
version = "1.16.8"
|
||||
edition = "2021"
|
||||
authors = ["mbecker20 <becker.maxh@gmail.com>"]
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
@@ -92,13 +92,19 @@ async fn login(
|
||||
);
|
||||
|
||||
let config = core_config();
|
||||
let redirect = if !config.oidc_redirect.is_empty() {
|
||||
Redirect::to(
|
||||
auth_url
|
||||
.as_str()
|
||||
.replace(&config.oidc_provider, &config.oidc_redirect)
|
||||
.as_str(),
|
||||
)
|
||||
let redirect = if !config.oidc_redirect_host.is_empty() {
|
||||
let auth_url = auth_url.as_str();
|
||||
let (protocol, rest) = auth_url
|
||||
.split_once("://")
|
||||
.context("Invalid URL: Missing protocol (eg 'https://')")?;
|
||||
let host = rest
|
||||
.split_once(['/', '?'])
|
||||
.map(|(host, _)| host)
|
||||
.unwrap_or(rest);
|
||||
Redirect::to(&auth_url.replace(
|
||||
&format!("{protocol}://{host}"),
|
||||
&config.oidc_redirect_host,
|
||||
))
|
||||
} else {
|
||||
Redirect::to(auth_url.as_str())
|
||||
};
|
||||
|
||||
@@ -78,7 +78,7 @@ pub fn core_config() -> &'static CoreConfig {
|
||||
},
|
||||
oidc_enabled: env.komodo_oidc_enabled.unwrap_or(config.oidc_enabled),
|
||||
oidc_provider: env.komodo_oidc_provider.unwrap_or(config.oidc_provider),
|
||||
oidc_redirect: env.komodo_oidc_redirect.unwrap_or(config.oidc_redirect),
|
||||
oidc_redirect_host: env.komodo_oidc_redirect_host.unwrap_or(config.oidc_redirect_host),
|
||||
oidc_client_id: maybe_read_item_from_file(env.komodo_oidc_client_id_file,env
|
||||
.komodo_oidc_client_id)
|
||||
.unwrap_or(config.oidc_client_id),
|
||||
|
||||
@@ -31,7 +31,7 @@ use crate::{
|
||||
use super::periphery_client;
|
||||
|
||||
const BUILDER_POLL_RATE_SECS: u64 = 2;
|
||||
const BUILDER_POLL_MAX_TRIES: usize = 30;
|
||||
const BUILDER_POLL_MAX_TRIES: usize = 60;
|
||||
|
||||
#[instrument(skip_all, fields(builder_id = builder.id, update_id = update.id))]
|
||||
pub async fn get_builder_periphery(
|
||||
|
||||
@@ -132,11 +132,6 @@ impl RepoExecution for BuildRepo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct RepoWebhookPath {
|
||||
pub option: RepoWebhookOption,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum RepoWebhookOption {
|
||||
@@ -244,11 +239,6 @@ impl StackExecution for DeployStack {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct StackWebhookPath {
|
||||
pub option: StackWebhookOption,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum StackWebhookOption {
|
||||
@@ -340,11 +330,6 @@ impl SyncExecution for RunSync {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SyncWebhookPath {
|
||||
pub option: SyncWebhookOption,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum SyncWebhookOption {
|
||||
@@ -410,7 +395,7 @@ fn procedure_locks() -> &'static ListenerLockCache {
|
||||
|
||||
pub async fn handle_procedure_webhook<B: super::VerifyBranch>(
|
||||
procedure: Procedure,
|
||||
target_branch: String,
|
||||
target_branch: &str,
|
||||
body: String,
|
||||
) -> anyhow::Result<()> {
|
||||
// Acquire and hold lock to make a task queue for
|
||||
@@ -457,7 +442,7 @@ fn action_locks() -> &'static ListenerLockCache {
|
||||
|
||||
pub async fn handle_action_webhook<B: super::VerifyBranch>(
|
||||
action: Action,
|
||||
target_branch: String,
|
||||
target_branch: &str,
|
||||
body: String,
|
||||
) -> anyhow::Result<()> {
|
||||
// Acquire and hold lock to make a task queue for
|
||||
|
||||
@@ -3,7 +3,9 @@ use komodo_client::entities::{
|
||||
action::Action, build::Build, procedure::Procedure, repo::Repo,
|
||||
resource::Resource, stack::Stack, sync::ResourceSync,
|
||||
};
|
||||
use reqwest::StatusCode;
|
||||
use serde::Deserialize;
|
||||
use serror::AddStatusCode;
|
||||
use tracing::Instrument;
|
||||
|
||||
use crate::resource::KomodoResource;
|
||||
@@ -12,8 +14,8 @@ use super::{
|
||||
resources::{
|
||||
handle_action_webhook, handle_build_webhook,
|
||||
handle_procedure_webhook, handle_repo_webhook,
|
||||
handle_stack_webhook, handle_sync_webhook, RepoWebhookPath,
|
||||
StackWebhookPath, SyncWebhookPath,
|
||||
handle_stack_webhook, handle_sync_webhook, RepoWebhookOption,
|
||||
StackWebhookOption, SyncWebhookOption,
|
||||
},
|
||||
CustomSecret, VerifyBranch, VerifySecret,
|
||||
};
|
||||
@@ -24,7 +26,14 @@ struct Id {
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Branch {
|
||||
struct IdAndOption<T> {
|
||||
id: String,
|
||||
option: T,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct IdAndBranch {
|
||||
id: String,
|
||||
#[serde(default = "default_branch")]
|
||||
branch: String,
|
||||
}
|
||||
@@ -64,7 +73,7 @@ pub fn router<P: VerifySecret + VerifyBranch>() -> Router {
|
||||
.route(
|
||||
"/repo/:id/:option",
|
||||
post(
|
||||
|Path(Id { id }), Path(RepoWebhookPath { option }), headers: HeaderMap, body: String| async move {
|
||||
|Path(IdAndOption::<RepoWebhookOption> { id, option }), headers: HeaderMap, body: String| async move {
|
||||
let repo =
|
||||
auth_webhook::<P, Repo>(&id, headers, &body).await?;
|
||||
tokio::spawn(async move {
|
||||
@@ -90,7 +99,7 @@ pub fn router<P: VerifySecret + VerifyBranch>() -> Router {
|
||||
.route(
|
||||
"/stack/:id/:option",
|
||||
post(
|
||||
|Path(Id { id }), Path(StackWebhookPath { option }), headers: HeaderMap, body: String| async move {
|
||||
|Path(IdAndOption::<StackWebhookOption> { id, option }), headers: HeaderMap, body: String| async move {
|
||||
let stack =
|
||||
auth_webhook::<P, Stack>(&id, headers, &body).await?;
|
||||
tokio::spawn(async move {
|
||||
@@ -116,7 +125,7 @@ pub fn router<P: VerifySecret + VerifyBranch>() -> Router {
|
||||
.route(
|
||||
"/sync/:id/:option",
|
||||
post(
|
||||
|Path(Id { id }), Path(SyncWebhookPath { option }), headers: HeaderMap, body: String| async move {
|
||||
|Path(IdAndOption::<SyncWebhookOption> { id, option }), headers: HeaderMap, body: String| async move {
|
||||
let sync =
|
||||
auth_webhook::<P, ResourceSync>(&id, headers, &body).await?;
|
||||
tokio::spawn(async move {
|
||||
@@ -142,19 +151,19 @@ pub fn router<P: VerifySecret + VerifyBranch>() -> Router {
|
||||
.route(
|
||||
"/procedure/:id/:branch",
|
||||
post(
|
||||
|Path(Id { id }), Path(Branch { branch }), headers: HeaderMap, body: String| async move {
|
||||
|Path(IdAndBranch { id, branch }), headers: HeaderMap, body: String| async move {
|
||||
let procedure =
|
||||
auth_webhook::<P, Procedure>(&id, headers, &body).await?;
|
||||
tokio::spawn(async move {
|
||||
let span = info_span!("ProcedureWebhook", id);
|
||||
async {
|
||||
let res = handle_procedure_webhook::<P>(
|
||||
procedure, branch, body,
|
||||
procedure, &branch, body,
|
||||
)
|
||||
.await;
|
||||
if let Err(e) = res {
|
||||
warn!(
|
||||
"Failed at running webhook for procedure {id} | {e:#}"
|
||||
"Failed at running webhook for procedure {id} | target branch: {branch} | {e:#}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -168,19 +177,19 @@ pub fn router<P: VerifySecret + VerifyBranch>() -> Router {
|
||||
.route(
|
||||
"/action/:id/:branch",
|
||||
post(
|
||||
|Path(Id { id }), Path(Branch { branch }), headers: HeaderMap, body: String| async move {
|
||||
|Path(IdAndBranch { id, branch }), headers: HeaderMap, body: String| async move {
|
||||
let action =
|
||||
auth_webhook::<P, Action>(&id, headers, &body).await?;
|
||||
tokio::spawn(async move {
|
||||
let span = info_span!("ActionWebhook", id);
|
||||
async {
|
||||
let res = handle_action_webhook::<P>(
|
||||
action, branch, body,
|
||||
action, &branch, body,
|
||||
)
|
||||
.await;
|
||||
if let Err(e) = res {
|
||||
warn!(
|
||||
"Failed at running webhook for action {id} | {e:#}"
|
||||
"Failed at running webhook for action {id} | target branch: {branch} | {e:#}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -202,7 +211,10 @@ where
|
||||
P: VerifySecret,
|
||||
R: KomodoResource + CustomSecret,
|
||||
{
|
||||
let resource = crate::resource::get::<R>(id).await?;
|
||||
P::verify_secret(headers, body, R::custom_secret(&resource))?;
|
||||
let resource = crate::resource::get::<R>(id)
|
||||
.await
|
||||
.status_code(StatusCode::BAD_REQUEST)?;
|
||||
P::verify_secret(headers, body, R::custom_secret(&resource))
|
||||
.status_code(StatusCode::UNAUTHORIZED)?;
|
||||
Ok(resource)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::sync::OnceLock;
|
||||
use std::{collections::HashMap, sync::OnceLock};
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use bollard::{
|
||||
@@ -40,7 +40,7 @@ impl DockerClient {
|
||||
pub async fn list_containers(
|
||||
&self,
|
||||
) -> anyhow::Result<Vec<ContainerListItem>> {
|
||||
let containers = self
|
||||
let mut containers = self
|
||||
.docker
|
||||
.list_containers(Some(ListContainersOptions::<String> {
|
||||
all: true,
|
||||
@@ -96,6 +96,24 @@ impl DockerClient {
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let container_id_to_network = containers
|
||||
.iter()
|
||||
.filter_map(|c| Some((c.id.clone()?, c.network_mode.clone()?)))
|
||||
.collect::<HashMap<_, _>>();
|
||||
// Fix containers which use `container:container_id` network_mode,
|
||||
// by replacing with the referenced network mode.
|
||||
containers.iter_mut().for_each(|container| {
|
||||
let Some(network_name) = &container.network_mode else {
|
||||
return;
|
||||
};
|
||||
let Some(container_id) =
|
||||
network_name.strip_prefix("container:")
|
||||
else {
|
||||
return;
|
||||
};
|
||||
container.network_mode =
|
||||
container_id_to_network.get(container_id).cloned();
|
||||
});
|
||||
Ok(containers)
|
||||
}
|
||||
|
||||
|
||||
@@ -108,8 +108,8 @@ pub struct Env {
|
||||
pub komodo_oidc_enabled: Option<bool>,
|
||||
/// Override `oidc_provider`
|
||||
pub komodo_oidc_provider: Option<String>,
|
||||
/// Override `oidc_redirect`
|
||||
pub komodo_oidc_redirect: Option<String>,
|
||||
/// Override `oidc_redirect_host`
|
||||
pub komodo_oidc_redirect_host: Option<String>,
|
||||
/// Override `oidc_client_id`
|
||||
pub komodo_oidc_client_id: Option<String>,
|
||||
/// Override `oidc_client_id` from file
|
||||
@@ -325,18 +325,22 @@ pub struct CoreConfig {
|
||||
|
||||
/// Configure OIDC provider address for
|
||||
/// communcation directly with Komodo Core.
|
||||
///
|
||||
/// Note. Needs to be reachable from Komodo Core.
|
||||
/// Eg. `https://accounts.example.internal/application/o/komodo`
|
||||
///
|
||||
/// `https://accounts.example.internal/application/o/komodo`
|
||||
#[serde(default)]
|
||||
pub oidc_provider: String,
|
||||
|
||||
/// Configure OIDC user redirect address.
|
||||
/// This is the address users are redirected to in their browser,
|
||||
/// and may be different from `oidc_provider`.
|
||||
/// If not provided, the `oidc_provider` will be used.
|
||||
/// Eg. `https://accounts.example.external/application/o/komodo`
|
||||
/// Configure OIDC user redirect host.
|
||||
///
|
||||
/// This is the host address users are redirected to in their browser,
|
||||
/// and may be different from `oidc_provider` host.
|
||||
/// DO NOT include the `path` part, this must be inferred.
|
||||
/// If not provided, the host will be the same as `oidc_provider`.
|
||||
/// Eg. `https://accounts.example.external`
|
||||
#[serde(default)]
|
||||
pub oidc_redirect: String,
|
||||
pub oidc_redirect_host: String,
|
||||
|
||||
/// Set OIDC client id
|
||||
#[serde(default)]
|
||||
@@ -580,7 +584,7 @@ impl CoreConfig {
|
||||
local_auth: config.local_auth,
|
||||
oidc_enabled: config.oidc_enabled,
|
||||
oidc_provider: config.oidc_provider,
|
||||
oidc_redirect: config.oidc_redirect,
|
||||
oidc_redirect_host: config.oidc_redirect_host,
|
||||
oidc_client_id: empty_or_redacted(&config.oidc_client_id),
|
||||
oidc_client_secret: empty_or_redacted(
|
||||
&config.oidc_client_secret,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "komodo_client",
|
||||
"version": "1.16.6",
|
||||
"version": "1.16.8",
|
||||
"description": "Komodo client package",
|
||||
"homepage": "https://komo.do",
|
||||
"main": "dist/lib.js",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Generated by typeshare 1.11.0
|
||||
Generated by typeshare 1.12.0
|
||||
*/
|
||||
|
||||
export interface MongoIdObj {
|
||||
|
||||
+3
-2
@@ -78,8 +78,9 @@ KOMODO_JWT_TTL="1-day"
|
||||
KOMODO_OIDC_ENABLED=false
|
||||
## Must reachable from Komodo Core container
|
||||
# KOMODO_OIDC_PROVIDER=https://oidc.provider.internal/application/o/komodo
|
||||
## Must be reachable by users (optional if it is the same as above).
|
||||
# KOMODO_OIDC_REDIRECT=https://oidc.provider.external/application/o/komodo
|
||||
## Change the host to one reachable be reachable by users (optional if it is the same as above).
|
||||
## DO NOT include the `path` part of the URL.
|
||||
# KOMODO_OIDC_REDIRECT_HOST=https://oidc.provider.external
|
||||
## Your client credentials
|
||||
# KOMODO_OIDC_CLIENT_ID= # Alt: KOMODO_OIDC_CLIENT_ID_FILE
|
||||
# KOMODO_OIDC_CLIENT_SECRET= # Alt: KOMODO_OIDC_CLIENT_SECRET_FILE
|
||||
|
||||
@@ -152,15 +152,18 @@ oidc_enabled = false
|
||||
## Optional, no default.
|
||||
oidc_provider = "https://oidc.provider.internal/application/o/komodo"
|
||||
|
||||
## Configure OIDC user redirect address.
|
||||
## Configure OIDC user redirect host.
|
||||
##
|
||||
## This is the address users are redirected to in their browser,
|
||||
## and may be different from `oidc_provider` depending on your networking.
|
||||
## This is the host address users are redirected to in their browser,
|
||||
## and may be different from `oidc_provider` host depending on your networking.
|
||||
## If not provided (or empty string ""), the `oidc_provider` will be used.
|
||||
##
|
||||
## Env: KOMODO_OIDC_REDIRECT
|
||||
## Note. DO NOT include the `path` part of the URL.
|
||||
## Example: `https://oidc.provider.external`
|
||||
##
|
||||
## Env: KOMODO_OIDC_REDIRECT_HOST
|
||||
## Optional, no default.
|
||||
oidc_redirect = ""
|
||||
oidc_redirect_host = ""
|
||||
|
||||
## Give the OIDC Client ID.
|
||||
## Env: KOMODO_OIDC_CLIENT_ID or KOMODO_OIDC_CLIENT_ID_FILE
|
||||
|
||||
@@ -30,7 +30,7 @@ https://${HOST}/listener/${AUTH_TYPE}/${RESOURCE_TYPE}/${ID_OR_NAME}/${EXECUTION
|
||||
- **`EXECUTION`**:
|
||||
- Which executions are available depends on the `RESOURCE_TYPE`. Builds only have the `/build` action.
|
||||
Repos can select between `/pull`, `/clone`, or `/build`. Stacks have `/deploy` and `/refresh`, and Resource Syncs have `/sync` and `/refresh`.
|
||||
- For **Procedures and Actions**, this will be the **branch to listen to for pushes**, or `__ALL__` to trigger
|
||||
- For **Procedures and Actions**, this will be the **branch to listen to for pushes**, or `__ANY__` to trigger
|
||||
on pushes to any branch.
|
||||
|
||||
## Create the webhook on the Git Provider
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Generated by typeshare 1.11.0
|
||||
Generated by typeshare 1.12.0
|
||||
*/
|
||||
/** The levels of permission that a User or UserGroup can have on a resource. */
|
||||
export var PermissionLevel;
|
||||
|
||||
@@ -118,17 +118,17 @@ export const ActionConfig = ({ id }: { id: string }) => {
|
||||
value={branch}
|
||||
onChange={(e) => setBranch(e.target.value)}
|
||||
className="w-[200px]"
|
||||
disabled={branch === "__ALL__"}
|
||||
disabled={branch === "__ANY__"}
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-muted-foreground text-sm">
|
||||
All branches:
|
||||
No branch check:
|
||||
</div>
|
||||
<Switch
|
||||
checked={branch === "__ALL__"}
|
||||
checked={branch === "__ANY__"}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked) {
|
||||
setBranch("__ALL__");
|
||||
setBranch("__ANY__");
|
||||
} else {
|
||||
setBranch("main");
|
||||
}
|
||||
|
||||
@@ -238,17 +238,17 @@ const ProcedureConfigInner = ({
|
||||
value={branch}
|
||||
onChange={(e) => setBranch(e.target.value)}
|
||||
className="w-[200px]"
|
||||
disabled={branch === "__ALL__"}
|
||||
disabled={branch === "__ANY__"}
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-muted-foreground text-sm">
|
||||
All branches:
|
||||
No branch check:
|
||||
</div>
|
||||
<Switch
|
||||
checked={branch === "__ALL__"}
|
||||
checked={branch === "__ANY__"}
|
||||
onCheckedChange={(checked) => {
|
||||
if (checked) {
|
||||
setBranch("__ALL__");
|
||||
setBranch("__ANY__");
|
||||
} else {
|
||||
setBranch("main");
|
||||
}
|
||||
|
||||
@@ -109,23 +109,34 @@ export const StackServices = ({
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Networks" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{server_id &&
|
||||
row.original.container?.networks.map((network, i) => (
|
||||
<Fragment key={network}>
|
||||
<DockerResourceLink
|
||||
type="network"
|
||||
server_id={server_id}
|
||||
name={network}
|
||||
/>
|
||||
{i !== row.original.container!.networks.length - 1 && (
|
||||
<div className="text-muted-foreground">|</div>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
cell: ({ row }) =>
|
||||
(row.original.container?.networks.length ?? 0) > 0 ? (
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{server_id &&
|
||||
row.original.container?.networks.map((network, i) => (
|
||||
<Fragment key={network}>
|
||||
<DockerResourceLink
|
||||
type="network"
|
||||
server_id={server_id}
|
||||
name={network}
|
||||
/>
|
||||
{i !==
|
||||
row.original.container!.networks.length - 1 && (
|
||||
<div className="text-muted-foreground">|</div>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
server_id &&
|
||||
row.original.container?.network_mode && (
|
||||
<DockerResourceLink
|
||||
type="network"
|
||||
server_id={server_id}
|
||||
name={row.original.container.network_mode}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -791,22 +791,31 @@ export const DockerContainersSection = ({
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Networks" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-x-2 flex-wrap">
|
||||
{row.original.networks.map((network, i) => (
|
||||
<Fragment key={network}>
|
||||
<DockerResourceLink
|
||||
type="network"
|
||||
server_id={server_id}
|
||||
name={network}
|
||||
/>
|
||||
{i !== row.original.networks.length - 1 && (
|
||||
<div className="text-muted-foreground">|</div>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
cell: ({ row }) =>
|
||||
row.original.networks.length > 0 ? (
|
||||
<div className="flex items-center gap-x-2 flex-wrap">
|
||||
{row.original.networks.map((network, i) => (
|
||||
<Fragment key={network}>
|
||||
<DockerResourceLink
|
||||
type="network"
|
||||
server_id={server_id}
|
||||
name={network}
|
||||
/>
|
||||
{i !== row.original.networks.length - 1 && (
|
||||
<div className="text-muted-foreground">|</div>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
row.original.network_mode && (
|
||||
<DockerResourceLink
|
||||
type="network"
|
||||
server_id={server_id}
|
||||
name={row.original.network_mode}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -125,22 +125,31 @@ export const ContainersPage = () => {
|
||||
header: ({ column }) => (
|
||||
<SortableHeader column={column} title="Networks" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-x-2 flex-wrap">
|
||||
{row.original.networks.map((network, i) => (
|
||||
<Fragment key={network}>
|
||||
<DockerResourceLink
|
||||
type="network"
|
||||
server_id={row.original.server_id!}
|
||||
name={network}
|
||||
/>
|
||||
{i !== row.original.networks.length - 1 && (
|
||||
<div className="text-muted-foreground">|</div>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
cell: ({ row }) =>
|
||||
row.original.networks.length > 0 ? (
|
||||
<div className="flex items-center gap-x-2 flex-wrap">
|
||||
{row.original.networks.map((network, i) => (
|
||||
<Fragment key={network}>
|
||||
<DockerResourceLink
|
||||
type="network"
|
||||
server_id={row.original.server_id!}
|
||||
name={network}
|
||||
/>
|
||||
{i !== row.original.networks.length - 1 && (
|
||||
<div className="text-muted-foreground">|</div>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
row.original.network_mode && (
|
||||
<DockerResourceLink
|
||||
type="network"
|
||||
server_id={row.original.server_id!}
|
||||
name={row.original.network_mode}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
// {
|
||||
// accessorKey: "volumes.0",
|
||||
|
||||
Reference in New Issue
Block a user