From 7506138ca89395a2733d675603bceda5c2631474 Mon Sep 17 00:00:00 2001 From: KArtHiK Date: Sat, 14 Feb 2026 09:01:28 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=94=EF=B8=8FHandle=20stream=20for=20deplo?= =?UTF-8?q?yment=20duration=20tick=20with=20start=20and=20end=20time?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/web/handler/project/events.go | 22 +++++- app/web/views/components/common/time.templ | 69 +++++++++++++++++- .../components/vdeployment/duration.templ | 72 +++++++++++++++++++ .../views/components/vdeployment/info.templ | 34 ++++----- .../views/components/vdeployment/list.templ | 7 +- 5 files changed, 175 insertions(+), 29 deletions(-) create mode 100644 app/web/views/components/vdeployment/duration.templ diff --git a/app/web/handler/project/events.go b/app/web/handler/project/events.go index 668631d..2cf35da 100644 --- a/app/web/handler/project/events.go +++ b/app/web/handler/project/events.go @@ -54,13 +54,29 @@ func renderFunc(ctx context.Context, w io.Writer, event *sse.Event) error { log.Ctx(ctx).Err(err).Msg("sse render: error rendering deployment full status") return err } + if d.Started > 0 { + if err := vdeployment.DeploymentStarted(d.UID, d.Started, true).Render(ctx, w); err != nil { + log.Ctx(ctx).Err(err).Msg("sse render: error rendering deployment started") + return err + } + } + if d.Stopped > 0 { + if err := vdeployment.DeploymentDuration(d.UID, d.Started, d.Stopped, true).Render(ctx, w); err != nil { + log.Ctx(ctx).Err(err).Msg("sse render: error rendering deployment duration") + return err + } + if err := vdeployment.DeploymentStopped(d.UID, d.Stopped, true).Render(ctx, w); err != nil { + log.Ctx(ctx).Err(err).Msg("sse render: error rendering deployment stopped") + return err + } + } case enum.SSETypeApplicationDeploymentUpdated: - d := new(types.Application) - if err := json.Unmarshal(event.Data, d); err != nil { + app := new(types.Application) + if err := json.Unmarshal(event.Data, app); err != nil { log.Ctx(ctx).Err(err).Msg("sse render: error unmarshalling application") return err } - if err := vapplication.AppDeploymentStatus(d, true).Render(ctx, w); err != nil { + if err := vapplication.AppDeploymentStatus(app, true).Render(ctx, w); err != nil { log.Ctx(ctx).Err(err).Msg("sse render: error rendering application status") return err } diff --git a/app/web/views/components/common/time.templ b/app/web/views/components/common/time.templ index 8352f06..c99be60 100644 --- a/app/web/views/components/common/time.templ +++ b/app/web/views/components/common/time.templ @@ -1,6 +1,45 @@ package common -import "fmt" +import ( + "fmt" + "strings" + "time" +) + +// durationString formats a duration between two Unix milli timestamps as h/m/s, rounded to the nearest second. +func durationString(startTime int64, endTime int64) string { + if startTime <= 0 { + return "0s" + } + + effectiveEnd := endTime + if effectiveEnd <= 0 { + effectiveEnd = time.Now().UTC().UnixMilli() + } + + diffMillis := effectiveEnd - startTime + if diffMillis < 0 { + return "0s" + } + + secs := (diffMillis + 500) / 1000 // round to nearest second + h := secs / 3600 + m := (secs % 3600) / 60 + s := secs % 60 + + parts := make([]string, 0, 3) + if h > 0 { + parts = append(parts, fmt.Sprintf("%dh", h)) + } + if m > 0 { + parts = append(parts, fmt.Sprintf("%dm", m)) + } + if len(parts) == 0 || s > 0 { + parts = append(parts, fmt.Sprintf("%ds", s)) + } + + return strings.Join(parts, " ") +} templ Date(t int64) { @@ -26,6 +65,30 @@ templ TimeAgo(t int64) { } +templ TimeDiffTick(startTime int64, endTime int64) { + if startTime > 0 { + + + + } +} + templ TimeDiff(startTime int64, endTime int64) { } + +templ TimeDiffStatic(startTime int64, endTime int64) { + { durationString(startTime, endTime) } +} diff --git a/app/web/views/components/vdeployment/duration.templ b/app/web/views/components/vdeployment/duration.templ new file mode 100644 index 0000000..c8847cf --- /dev/null +++ b/app/web/views/components/vdeployment/duration.templ @@ -0,0 +1,72 @@ +package vdeployment + +import "fmt" +import "github.com/cloudness-io/cloudness/app/web/views/components/common" + +func getSwapAttributes(swap bool) templ.Attributes { + if swap { + return templ.Attributes{ + "hx-swap-oob": "true", + } + } + return templ.Attributes{} +} + +func getDeploymentDurationID(deploymentUID int64) string { + return fmt.Sprintf("deployment-duration-%d", deploymentUID) +} + +func getDeploymentStartedID(deploymentUID int64) string { + return fmt.Sprintf("deployment-started-%d", deploymentUID) +} + +func getDeploymentStoppedID(deploymentUID int64) string { + return fmt.Sprintf("deployment-stopped-%d", deploymentUID) +} + +templ DeploymentDuration(deploymentUID, started, stopped int64, swap bool) { +
+ if stopped > 0 { + if swap { + @common.TimeDiffStatic(started, stopped) + } else { + @common.TimeDiff(started, stopped) + } + } else { + @common.TimeDiffTick(started, stopped) + } +
+} + +templ DeploymentStarted(deploymentUID, started int64, swap bool) { +
+ if started > 0 { + @common.DateTimeYear(started) + } else { + - + } +
+} + +templ DeploymentStopped(deploymentUID, stopped int64, swap bool) { +
+ if stopped > 0 { + @common.DateTimeYear(stopped) + } else { + - + } +
+} diff --git a/app/web/views/components/vdeployment/info.templ b/app/web/views/components/vdeployment/info.templ index e2b7535..328c4a4 100644 --- a/app/web/views/components/vdeployment/info.templ +++ b/app/web/views/components/vdeployment/info.templ @@ -61,27 +61,23 @@ func getDescription(app *types.Application, d *types.Deployment) []*DescriptionG term: "Triggered By", details: triggeredBy(d), }) - if d.Started > 0 { + desc = append(desc, &DescriptionGridItems{ + term: "Started", + details: DeploymentStarted(d.UID, d.Started, false), + }) + desc = append(desc, &DescriptionGridItems{ + term: "Ended", + details: DeploymentStopped(d.UID, d.Stopped, false), + }) + desc = append(desc, &DescriptionGridItems{ + term: "Duration", + details: DeploymentDuration(d.UID, d.Started, d.Stopped, false), + }) + if d.Error != "" { desc = append(desc, &DescriptionGridItems{ - term: "Started", - details: common.DateTimeYear(d.Started), + term: "Error", + details: shared.TextComp(d.Error), }) - if d.IsDone() { - desc = append(desc, &DescriptionGridItems{ - term: "Ended", - details: common.DateTimeYear(d.Stopped), - }) - desc = append(desc, &DescriptionGridItems{ - term: "Duration", - details: common.TimeDiff(d.Started, d.Stopped), - }) - } - if d.Error != "" { - desc = append(desc, &DescriptionGridItems{ - term: "Error", - details: shared.TextComp(d.Error), - }) - } } return desc } diff --git a/app/web/views/components/vdeployment/list.templ b/app/web/views/components/vdeployment/list.templ index b563f0b..484d22e 100644 --- a/app/web/views/components/vdeployment/list.templ +++ b/app/web/views/components/vdeployment/list.templ @@ -5,7 +5,6 @@ import ( "github.com/cloudness-io/cloudness/app/web/views/components/common" "github.com/cloudness-io/cloudness/app/web/views/shared" "github.com/cloudness-io/cloudness/types" - "time" ) templ List(app *types.Application, deployments []*types.Deployment) { @@ -33,11 +32,7 @@ templ List(app *types.Application, deployments []*types.Deployment) {
@common.DateTime(deployment.Created) if deployment.Started > 0 { - if deployment.Stopped > 0 { - @common.TimeDiff(deployment.Started, deployment.Stopped) - } else { - @common.TimeDiff(deployment.Started, time.Now().UTC().UnixMilli()) - } + @DeploymentDuration(deployment.UID, deployment.Started, deployment.Stopped, false) }