diff --git a/frontend/cloud-ui/src/app/deployment-targets/deployment-targets.component.html b/frontend/cloud-ui/src/app/deployment-targets/deployment-targets.component.html
index ea5bd1d0..c6162c5e 100644
--- a/frontend/cloud-ui/src/app/deployment-targets/deployment-targets.component.html
+++ b/frontend/cloud-ui/src/app/deployment-targets/deployment-targets.component.html
@@ -72,6 +72,7 @@
-->
Deployment Target |
+ Status |
Type |
@if (fullVersion) {
Creation Date |
@@ -97,10 +98,28 @@
-->
- ![Docker]()
+
+ ![Docker]()
+ @if (dt.currentStatus) {
+
+ } @else {
+
+ }
+
{{ dt.name }}
|
+
+
+ @if (dt.currentStatus) {
+
+ OK
+ } @else {
+
+ Unknown
+ }
+
+ |
diff --git a/frontend/cloud-ui/src/app/types/deployment-target.ts b/frontend/cloud-ui/src/app/types/deployment-target.ts
index 37ccd912..117d5923 100644
--- a/frontend/cloud-ui/src/app/types/deployment-target.ts
+++ b/frontend/cloud-ui/src/app/types/deployment-target.ts
@@ -5,4 +5,9 @@ export interface DeploymentTarget extends BaseModel, Named {
name: string;
type: string;
geolocation?: Geolocation;
+ currentStatus?: DeploymentTargetStatus;
+}
+
+export interface DeploymentTargetStatus extends BaseModel {
+ message: string;
}
diff --git a/internal/db/deployment_targets.go b/internal/db/deployment_targets.go
index 95a17d91..f0e10bf9 100644
--- a/internal/db/deployment_targets.go
+++ b/internal/db/deployment_targets.go
@@ -14,15 +14,28 @@ import (
const (
deploymentTargetOutputExpr = `
- id, created_at, name, type,
- CASE WHEN geolocation_lat IS NOT NULL AND geolocation_lon IS NOT NULL
- THEN (geolocation_lat, geolocation_lon) END AS geolocation
+ dt.id, dt.created_at, dt.name, dt.type,
+ CASE WHEN dt.geolocation_lat IS NOT NULL AND dt.geolocation_lon IS NOT NULL
+ THEN (dt.geolocation_lat, dt.geolocation_lon) END AS geolocation
`
+ deploymentTargetWithStatusOutputExpr = deploymentTargetOutputExpr + `,
+ CASE WHEN status.id IS NOT NULL
+ THEN (status.id, status.created_at, status.message) END AS current_status
+ `
+ deploymentTargetFromExpr = `
+ FROM DeploymentTarget dt LEFT JOIN DeploymentTargetStatus status ON dt.id = status.deployment_target_id
+ WHERE (
+ status.id IS NULL OR status.created_at = (
+ SELECT max(s.created_at) FROM DeploymentTargetStatus s WHERE s.deployment_target_id = status.deployment_target_id
+ )
+ )
+`
)
func GetDeploymentTargets(ctx context.Context) ([]types.DeploymentTarget, error) {
db := internalctx.GetDb(ctx)
- if rows, err := db.Query(ctx, "SELECT "+deploymentTargetOutputExpr+" FROM DeploymentTarget"); err != nil {
+ if rows, err := db.Query(ctx,
+ "SELECT "+deploymentTargetWithStatusOutputExpr+" "+deploymentTargetFromExpr); err != nil {
return nil, fmt.Errorf("failed to query DeploymentTargets: %w", err)
} else if result, err := pgx.CollectRows(rows, pgx.RowToStructByName[types.DeploymentTarget]); err != nil {
return nil, fmt.Errorf("failed to get DeploymentTargets: %w", err)
@@ -34,7 +47,7 @@ func GetDeploymentTargets(ctx context.Context) ([]types.DeploymentTarget, error)
func GetDeploymentTarget(ctx context.Context, id string) (*types.DeploymentTarget, error) {
db := internalctx.GetDb(ctx)
rows, err := db.Query(ctx,
- "SELECT "+deploymentTargetOutputExpr+" FROM DeploymentTarget WHERE id = @id",
+ "SELECT "+deploymentTargetWithStatusOutputExpr+" "+deploymentTargetFromExpr+" AND dt.id = @id",
pgx.NamedArgs{"id": id})
if err != nil {
return nil, fmt.Errorf("failed to query DeploymentTargets: %w", err)
@@ -56,14 +69,14 @@ func CreateDeploymentTarget(ctx context.Context, dt *types.DeploymentTarget) err
maps.Copy(args, pgx.NamedArgs{"lat": dt.Geolocation.Lat, "lon": dt.Geolocation.Lon})
}
rows, err := db.Query(ctx,
- "INSERT INTO DeploymentTarget (name, type, geolocation_lat, geolocation_lon) "+
+ "INSERT INTO DeploymentTarget AS dt (name, type, geolocation_lat, geolocation_lon) "+
"VALUES (@name, @type, @lat, @lon) RETURNING "+
deploymentTargetOutputExpr,
args)
if err != nil {
return fmt.Errorf("failed to query DeploymentTargets: %w", err)
}
- result, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[types.DeploymentTarget])
+ result, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByNameLax[types.DeploymentTarget])
if err != nil {
return fmt.Errorf("could not save DeploymentTarget: %w", err)
} else {
@@ -79,13 +92,14 @@ func UpdateDeploymentTarget(ctx context.Context, dt *types.DeploymentTarget) err
maps.Copy(args, pgx.NamedArgs{"lat": dt.Geolocation.Lat, "lon": dt.Geolocation.Lon})
}
rows, err := db.Query(ctx,
- "UPDATE DeploymentTarget SET name = @name, geolocation_lat = @lat, geolocation_lon = @lon "+
+ "UPDATE DeploymentTarget AS dt SET name = @name, geolocation_lat = @lat, geolocation_lon = @lon "+
" WHERE id = @id RETURNING "+
deploymentTargetOutputExpr,
args)
if err != nil {
return fmt.Errorf("could not update DeploymentTarget: %w", err)
- } else if updated, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[types.DeploymentTarget]); err != nil {
+ } else if updated, err :=
+ pgx.CollectExactlyOneRow(rows, pgx.RowToStructByNameLax[types.DeploymentTarget]); err != nil {
return fmt.Errorf("could not get updated DeploymentTarget: %w", err)
} else {
*dt = updated
diff --git a/internal/handlers/deployment_targets.go b/internal/handlers/deployment_targets.go
index bd2632fc..4fb2ada9 100644
--- a/internal/handlers/deployment_targets.go
+++ b/internal/handlers/deployment_targets.go
@@ -95,7 +95,7 @@ func deploymentTargetMiddelware(wh http.Handler) http.Handler {
if errors.Is(err, apierrors.NotFound) {
w.WriteHeader(http.StatusNotFound)
} else if err != nil {
- internalctx.GetLogger(r.Context()).Error("failed to get application", zap.Error(err))
+ internalctx.GetLogger(r.Context()).Error("failed to get DeploymentTarget", zap.Error(err))
w.WriteHeader(http.StatusInternalServerError)
} else {
ctx = internalctx.WithDeploymentTarget(ctx, deploymentTarget)
diff --git a/internal/types/data.go b/internal/types/data.go
index 8e4e5099..b3ccab88 100644
--- a/internal/types/data.go
+++ b/internal/types/data.go
@@ -10,7 +10,7 @@ type Application struct {
}
type ApplicationVersion struct {
- // unfortunately Base nested type doesn't work when ApplicationVersion is a nested row in an SQL query
+ // TODO unfortunately Base nested type doesn't work when ApplicationVersion is a nested row in an SQL query
ID string `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"createdAt"`
Name string `db:"name" json:"name"`
@@ -20,7 +20,16 @@ type ApplicationVersion struct {
type DeploymentTarget struct {
Base
- Name string `db:"name" json:"name"`
- Type DeploymentType `db:"type" json:"type"`
- Geolocation *Geolocation `db:"geolocation" json:"geolocation,omitempty"`
+ Name string `db:"name" json:"name"`
+ Type DeploymentType `db:"type" json:"type"`
+ Geolocation *Geolocation `db:"geolocation" json:"geolocation,omitempty"`
+ CurrentStatus *DeploymentTargetStatus `db:"current_status" json:"currentStatus,omitempty"`
+}
+
+type DeploymentTargetStatus struct {
+ // TODO unfortunately Base nested type doesn't work when ApplicationVersion is a nested row in an SQL query
+ ID string `db:"id" json:"id"`
+ CreatedAt time.Time `db:"created_at" json:"createdAt"`
+ Message string `db:"message" json:"message"`
+ DeploymentTargetId string `db:"deployment_target_id" json:"-"`
}
|