diff --git a/core/src/api/update.rs b/core/src/api/update.rs index 267f385e3..2d5e3030d 100644 --- a/core/src/api/update.rs +++ b/core/src/api/update.rs @@ -27,8 +27,12 @@ pub fn router() -> Router { .map(|v| v.as_str().unwrap_or("0").parse().unwrap_or(0)) .unwrap_or(0); let target = serde_json::from_str::(&value.to_string()).ok(); + let show_builds = value + .get("show_builds") + .map(|b| b.as_bool().unwrap_or_default()) + .unwrap_or_default(); let updates = state - .list_updates(target, offset, &user) + .list_updates(target, offset, show_builds, &user) .await .map_err(handle_anyhow_error)?; response!(Json(updates)) @@ -82,14 +86,42 @@ impl State { &self, target: Option, offset: u64, + show_builds: bool, user: &RequestUser, ) -> anyhow::Result> { let filter = match target { Some(target) => { - self.permission_on_update_target(&target, user).await?; - Some(doc! { - "target": to_bson(&target).unwrap() - }) + if let (UpdateTarget::Deployment(id), true) = (&target, show_builds) { + let deployment = self + .get_deployment_check_permissions(id, user, PermissionLevel::Read) + .await?; + if let Some(build_id) = &deployment.branch { + let build = self + .get_build_check_permissions(build_id, user, PermissionLevel::Read) + .await; + if let Ok(_) = build { + Some(doc! { + "$or": [ + {"target": to_bson(&target).unwrap()}, + {"target": { "type": "Build", "id": build_id }, "operation": "build_build"} + ], + }) + } else { + Some(doc! { + "target": to_bson(&target).unwrap() + }) + } + } else { + Some(doc! { + "target": to_bson(&target).unwrap() + }) + } + } else { + self.permission_on_update_target(&target, user).await?; + Some(doc! { + "target": to_bson(&target).unwrap() + }) + } } None => { if user.is_admin { diff --git a/frontend/src/components/deployment/Updates.tsx b/frontend/src/components/deployment/Updates.tsx index 613ef96cb..df86c10df 100644 --- a/frontend/src/components/deployment/Updates.tsx +++ b/frontend/src/components/deployment/Updates.tsx @@ -4,16 +4,14 @@ import Grid from "../shared/layout/Grid"; import Update from "../update/Update"; import { useAppState } from "../../state/StateProvider"; import { combineClasses } from "../../util/helpers"; -import { useParams } from "@solidjs/router"; import { Operation } from "../../types"; import Flex from "../shared/layout/Flex"; import Loading from "../shared/loading/Loading"; const Updates: Component<{}> = (p) => { - const { ws, deployments } = useAppState(); - const params = useParams(); - const updates = useUpdates({ type: "Deployment", id: params.id }); - const buildID = () => deployments.get(params.id)?.deployment.build_id; + const { ws, params, deployment } = useAppState(); + const updates = useUpdates({ type: "Deployment", id: params.id! }, true); + const buildID = () => deployment()?.deployment.build_id; let unsub = () => {}; createEffect(() => { unsub(); diff --git a/frontend/src/state/StateProvider.tsx b/frontend/src/state/StateProvider.tsx index e62af971b..040799a30 100644 --- a/frontend/src/state/StateProvider.tsx +++ b/frontend/src/state/StateProvider.tsx @@ -1,4 +1,4 @@ -import { useNavigate } from "@solidjs/router"; +import { Params, useNavigate, useParams } from "@solidjs/router"; import { createContext, ParentComponent, useContext } from "solid-js"; import { useWindowKeyDown } from "../util/hooks"; import { @@ -13,16 +13,19 @@ import { } from "./hooks"; import connectToWs from "./ws"; import { useUser } from "./UserProvider"; -import { PermissionLevel } from "../types"; +import { Build, DeploymentWithContainerState, PermissionLevel, ServerWithStatus } from "../types"; export type State = { usernames: ReturnType; servers: ReturnType; + server: () => ServerWithStatus | undefined; getPermissionOnServer: (id: string) => PermissionLevel; serverStats: ReturnType; ungroupedServerIds: () => string[] | undefined; + build: () => Build | undefined; builds: ReturnType; getPermissionOnBuild: (id: string) => PermissionLevel; + deployment: () => DeploymentWithContainerState | undefined; deployments: ReturnType; getPermissionOnDeployment: (id: string) => PermissionLevel; groups: ReturnType; @@ -30,6 +33,7 @@ export type State = { procedures: ReturnType; getPermissionOnProcedure: (id: string) => PermissionLevel; updates: ReturnType; + params: { id?: string }; }; const context = createContext< @@ -41,6 +45,7 @@ const context = createContext< export const AppStateProvider: ParentComponent = (p) => { const { user, logout } = useUser(); + const params = useParams<{ id?: string }>(); const navigate = useNavigate(); const userId = (user()._id as any).$oid as string; const servers = useServers(); @@ -52,6 +57,7 @@ export const AppStateProvider: ParentComponent = (p) => { const state: State = { usernames, servers, + server: () => servers.get(params.id!), getPermissionOnServer: (id: string) => { const server = servers.get(id)!; const permissions = server.server.permissions![userId] as @@ -77,6 +83,7 @@ export const AppStateProvider: ParentComponent = (p) => { }); }, builds, + build: () => builds.get(params.id!), getPermissionOnBuild: (id: string) => { const build = builds.get(id)!; const permissions = build.permissions![userId] as @@ -88,6 +95,7 @@ export const AppStateProvider: ParentComponent = (p) => { return PermissionLevel.None; } }, + deployment: () => deployments.get(params.id!), deployments, getPermissionOnDeployment: (id: string) => { const deployment = deployments.get(id)!; @@ -126,6 +134,7 @@ export const AppStateProvider: ParentComponent = (p) => { } }, updates: useUpdates(), + params, }; // createEffect(() => { diff --git a/frontend/src/state/hooks.ts b/frontend/src/state/hooks.ts index c1d23bd1c..742210ad9 100644 --- a/frontend/src/state/hooks.ts +++ b/frontend/src/state/hooks.ts @@ -124,9 +124,9 @@ export function useDeployments() { }; } -export function useUpdates(target?: UpdateTarget) { +export function useUpdates(target?: UpdateTarget, show_builds?: boolean) { const updates = useArrayWithId( - () => client.list_updates(0, target), + () => client.list_updates(0, target, show_builds), ["_id", "$oid"] ); const [noMore, setNoMore] = createSignal(false); diff --git a/frontend/src/util/client.ts b/frontend/src/util/client.ts index 005c0d8fe..7c73662b8 100644 --- a/frontend/src/util/client.ts +++ b/frontend/src/util/client.ts @@ -404,13 +404,14 @@ export class Client { } // updates - - list_updates(offset: number, target?: UpdateTarget): Promise { + // show_builds is only relevant for Deployment targets, must pass show_builds = true to include build updates of attached build_id + list_updates(offset: number, target?: UpdateTarget, show_builds?: boolean): Promise { return this.get( `/api/update/list${generateQuery({ offset, type: target && target.type, id: target && target.id, + show_builds, })}` ); } diff --git a/lib/periphery_client/src/lib.rs b/lib/periphery_client/src/lib.rs index af7035edd..5957d5786 100644 --- a/lib/periphery_client/src/lib.rs +++ b/lib/periphery_client/src/lib.rs @@ -87,21 +87,24 @@ impl PeripheryClient { Ok(socket) } - async fn get_text(&self, server: &Server, endpoint: &str, timeout_ms: impl Into>) -> anyhow::Result { + async fn get_text( + &self, + server: &Server, + endpoint: &str, + timeout_ms: impl Into>, + ) -> anyhow::Result { let mut req = self .http_client .get(format!("{}{endpoint}", server.address)); - + if let Some(timeout) = timeout_ms.into() { req = req.timeout(Duration::from_millis(timeout)) } - let res = req.send() - .await - .context(format!( - "failed at get request to server {} | not reachable", - server.name - ))?; + let res = req.send().await.context(format!( + "failed at get request to server {} | not reachable", + server.name + ))?; let status = res.status(); if status == StatusCode::OK { let text = res.text().await.context("failed at parsing response")?;