From 6208234593839b61a199f542adad829ebd4d4c39 Mon Sep 17 00:00:00 2001 From: surajgour-d11 Date: Fri, 31 Jan 2025 14:36:10 +0530 Subject: [PATCH 1/8] feat: viewport poc Signed-off-by: surajgour-d11 --- cmd/deploy/model.go | 41 +++++ cmd/deploy/service.go | 168 ++++++++++++++++-- cmd/deploy/view.go | 48 +++++ go.mod | 13 ++ go.sum | 27 +++ internal/service/service.go | 40 +---- pkg/ui/styles.go | 15 ++ .../dream11/oam/dto/v1/provider_account.pb.go | 2 +- .../provideraccount/v1/provider_account.pb.go | 2 +- .../v1/provider_account_grpc.pb.go | 2 +- proto/gen/go/dream11/od/auth/v1/auth.pb.go | 2 +- .../gen/go/dream11/od/auth/v1/auth_grpc.pb.go | 2 +- .../dream11/od/component/v1/component.pb.go | 2 +- .../od/component/v1/component_grpc.pb.go | 2 +- .../gen/go/dream11/od/dto/v1/component.pb.go | 2 +- .../go/dream11/od/dto/v1/component_task.pb.go | 2 +- .../go/dream11/od/dto/v1/environment.pb.go | 2 +- .../dream11/od/dto/v1/provisioning_type.pb.go | 2 +- proto/gen/go/dream11/od/dto/v1/service.pb.go | 2 +- .../go/dream11/od/dto/v1/service_task.pb.go | 2 +- .../od/environment/v1/environment.pb.go | 2 +- .../od/environment/v1/environment_grpc.pb.go | 2 +- .../go/dream11/od/service/v1/service.pb.go | 2 +- .../dream11/od/service/v1/service_grpc.pb.go | 2 +- 24 files changed, 320 insertions(+), 66 deletions(-) create mode 100644 cmd/deploy/model.go create mode 100644 cmd/deploy/view.go create mode 100644 pkg/ui/styles.go diff --git a/cmd/deploy/model.go b/cmd/deploy/model.go new file mode 100644 index 00000000..9930203d --- /dev/null +++ b/cmd/deploy/model.go @@ -0,0 +1,41 @@ +package deploy + +import ( + "github.com/charmbracelet/bubbles/spinner" + "github.com/charmbracelet/bubbles/viewport" +) + +type ServiceSetView struct { + Ready bool + Cursor int + Header Header + Status string + ServiceView []ServiceView +} + +type ServiceView struct { + Ready bool + Cursor int + Header Header + Status string + ComponentsView []ComponentView +} + +type ComponentView struct { + Toggle bool + Header Header + Status string + LogView LogView +} + +type Header struct { + Toggle bool + Text string + Spinner spinner.Model +} + +type LogView struct { + Toggle bool + Content string + LogViewPort viewport.Model +} diff --git a/cmd/deploy/service.go b/cmd/deploy/service.go index 428bac58..95e1190f 100644 --- a/cmd/deploy/service.go +++ b/cmd/deploy/service.go @@ -4,8 +4,15 @@ import ( "context" "encoding/json" "errors" + "fmt" + "github.com/charmbracelet/bubbles/viewport" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/dream11/odin/pkg/constant" + "io" "os" "regexp" + "strings" "github.com/dream11/odin/internal/service" "github.com/dream11/odin/pkg/config" @@ -47,23 +54,150 @@ func init() { func execute(cmd *cobra.Command) { env = config.EnsureEnvPresent(env) + // Add program in context ctx := cmd.Context() + program := tea.NewProgram( + &ServiceView{ + ComponentsView: append( + []ComponentView{ + { + Toggle: false, + }, + }, + ), + }, + tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer" + tea.WithMouseCellMotion(), // turn on mouse support, so we can track the mouse wheel + ) - if (serviceName == "" && serviceVersion == "" && labels == "") && (definitionFile != "" && provisioningFile != "") { - deployUsingFiles(ctx) - } else if (serviceName != "" && serviceVersion != "" && labels == "") && (definitionFile == "" && provisioningFile == "") { - deployUsingServiceNameAndVersion(ctx) - } else if (serviceName != "" && labels != "" && serviceVersion == "") && (definitionFile == "" && provisioningFile == "") { - if err := validateLabels(labels); err != nil { - log.Fatal("Invalid labels format: ", err) + go func() { + if (serviceName == "" && serviceVersion == "" && labels == "") && (definitionFile != "" && provisioningFile != "") { + deployUsingFiles(ctx, program) + } else if (serviceName != "" && serviceVersion != "" && labels == "") && (definitionFile == "" && provisioningFile == "") { + deployUsingServiceNameAndVersion(ctx) + } else if (serviceName != "" && labels != "" && serviceVersion == "") && (definitionFile == "" && provisioningFile == "") { + if err := validateLabels(labels); err != nil { + log.Fatal("Invalid labels format: ", err) + } + deployUsingServiceNameAndLabels(ctx) + } else { + log.Fatal("Invalid combination of flags. Use either (service name and version) or (service name and labels) or (definitionFile and provisioningFile).") } - deployUsingServiceNameAndLabels(ctx) - } else { - log.Fatal("Invalid combination of flags. Use either (service name and version) or (service name and labels) or (definitionFile and provisioningFile).") + }() + + if _, err := program.Run(); err != nil { + os.Exit(1) } } -func deployUsingFiles(ctx context.Context) { +func (s *ServiceView) Init() tea.Cmd { + return nil +} + +func (s *ServiceView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + // Handle updates + case ServiceView: + s.Header = msg.Header + s.Status = msg.Status + s.Cursor = msg.Cursor + prevCollapsed := make([]bool, len(s.ComponentsView)) + for i := range s.ComponentsView { + if i < len(prevCollapsed) { + prevCollapsed[i] = s.ComponentsView[i].Toggle + } + } + + for i := range s.ComponentsView { + if i < len(prevCollapsed) { + s.ComponentsView[i].Toggle = prevCollapsed[i] + s.ComponentsView[i].Header = msg.ComponentsView[i].Header + s.ComponentsView[i].Status = msg.ComponentsView[i].Status + s.ComponentsView[i].LogView.Content = msg.ComponentsView[i].LogView.Content + } + } + // Handle key presses + case tea.KeyMsg: + switch msg.String() { + case "up": + if s.Cursor > 0 { + s.Cursor-- + } + break + + case "down": + if s.Cursor < len(s.ComponentsView)-1 { + s.Cursor++ + } + break + + case "enter", " ": + s.ComponentsView[s.Cursor].Toggle = !s.ComponentsView[s.Cursor].Toggle + break + + case "q": + return s, tea.Quit + } + + // Handle window resizes + case tea.WindowSizeMsg: + headerHeight := lipgloss.Height(s.Header.Text) + if !s.Ready { + s.ComponentsView[s.Cursor].LogView.LogViewPort = viewport.New(msg.Width, msg.Height-headerHeight) + s.ComponentsView[s.Cursor].LogView.LogViewPort.MouseWheelDelta = 1 + s.ComponentsView[s.Cursor].LogView.LogViewPort.YPosition = headerHeight + s.Ready = true + } else { + s.ComponentsView[s.Cursor].LogView.LogViewPort.Width = msg.Width - 20 + s.ComponentsView[s.Cursor].LogView.LogViewPort.Height = msg.Height - headerHeight - 20 + } + } + + // Handle keyboard and mouse events in the viewport + s.ComponentsView[s.Cursor].LogView.LogViewPort.SetContent(s.ComponentsView[s.Cursor].LogView.Content) + vpcmd := s.updateViewPort(msg) + + return s, tea.Batch(vpcmd...) +} + +func (s *ServiceView) updateViewPort(msg tea.Msg) []tea.Cmd { + var cmds []tea.Cmd + var cmd tea.Cmd + for i := range s.ComponentsView { + s.ComponentsView[i].LogView.LogViewPort, cmd = s.ComponentsView[i].LogView.LogViewPort.Update(msg) + cmds = append(cmds, cmd) + } + return cmds +} + +func (s *ServiceView) View() string { + if !s.Ready { + return "\n Initializing..." + } + var builder strings.Builder + builder.WriteString(fmt.Sprintf("%s\n", s.Header.Text)) + + for i, componentView := range s.ComponentsView { + cursor := " " + if i == s.Cursor { + if componentView.Toggle { + cursor = ">" + } else { + cursor = "V" + } + } + + if !componentView.Toggle { + builder.WriteString(fmt.Sprintf("%s %s \n", cursor, componentView.Header.Text)) + } else { + builder.WriteString(fmt.Sprintf("%s\n%s\n%s\n", cursor, componentView.Header.Text, componentView.LogView.LogViewPort.View())) + } + } + + return builder.String() +} + +func deployUsingFiles(ctx context.Context, program *tea.Program) { definitionData, err := os.ReadFile(definitionFile) if err != nil { log.Fatal("Error while reading definition file ", err) @@ -85,7 +219,7 @@ func deployUsingFiles(ctx context.Context) { ComponentProvisioningConfig: compProvConfigs, } - err = serviceClient.DeployService(&ctx, &serviceProto.DeployServiceRequest{ + stream, err := serviceClient.DeployService(&ctx, &serviceProto.DeployServiceRequest{ EnvName: env, ServiceDefinition: &definitionProto, ProvisioningConfig: provisioningProto, @@ -94,6 +228,16 @@ func deployUsingFiles(ctx context.Context) { if err != nil { log.Fatal("Failed to deploy service ", err) } + for { + response, err := stream.Recv() + if err != nil { + if errors.Is(err, context.Canceled) || err == io.EOF { + break + } + log.Errorf("TraceID: %s", ctx.Value(constant.TraceIDKey)) + } + program.Send(GetServiceView(response)) + } } func deployUsingServiceNameAndVersion(ctx context.Context) { diff --git a/cmd/deploy/view.go b/cmd/deploy/view.go new file mode 100644 index 00000000..90745772 --- /dev/null +++ b/cmd/deploy/view.go @@ -0,0 +1,48 @@ +package deploy + +import ( + "fmt" + "github.com/dream11/odin/pkg/ui" + v1 "github.com/dream11/odin/proto/gen/go/dream11/od/service/v1" +) + +func GetServiceView(response *v1.DeployServiceResponse) ServiceView { + serviceName := response.GetServiceResponse().Name + + serviceHeaderText := fmt.Sprintf("Deploying service %s ", serviceName) + if response.GetServiceResponse().ServiceStatus.GetServiceStatus() == "SUCCESSFUL" { + serviceHeaderText = fmt.Sprintf("Service %s deployed successfully", serviceName) + } else if response.GetServiceResponse().ServiceStatus.GetServiceStatus() == "FAILED" { + serviceHeaderText = fmt.Sprintf("Failed to deploy service %s", serviceName) + } + + serviceView := ServiceView{ + Header: Header{ + Text: ui.TitleStyle.Render(serviceHeaderText), + }, + Status: response.GetServiceResponse().ServiceStatus.GetServiceStatus(), + ComponentsView: make([]ComponentView, 0), + } + for _, component := range response.GetServiceResponse().GetComponentsStatus() { + componentHeaderText := fmt.Sprintf("Deploying component %s", component.GetComponentName()) + if component.GetComponentStatus() == "SUCCESSFUL" { + componentHeaderText = fmt.Sprintf("Component %s deployed successfully", component.GetComponentName()) + } else if component.GetComponentStatus() == "FAILED" { + componentHeaderText = fmt.Sprintf("Failed to deploy component %s", component.GetComponentName()) + } + + errorMessage := "Awaiting component logs" + if component.GetError() != "" { + errorMessage = component.GetError() + } + componentView := ComponentView{ + Header: Header{Text: ui.TitleStyle.Render(componentHeaderText)}, + Status: component.GetComponentStatus(), + LogView: LogView{ + Content: ui.InfoStyle.Render(errorMessage), + }, + } + serviceView.ComponentsView = append(serviceView.ComponentsView, componentView) + } + return serviceView +} diff --git a/go.mod b/go.mod index be97b484..c99244b9 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,8 @@ toolchain go1.22.3 require ( github.com/briandowns/spinner v1.23.1 + github.com/charmbracelet/bubbles v0.20.0 + github.com/charmbracelet/bubbletea v1.2.4 github.com/google/uuid v1.6.0 github.com/mitchellh/cli v1.1.5 github.com/olekukonko/tablewriter v0.0.5 @@ -18,13 +20,23 @@ require ( github.com/Masterminds/semver/v3 v3.1.1 // indirect github.com/Masterminds/sprig/v3 v3.2.1 // indirect github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/charmbracelet/lipgloss v1.0.0 // indirect + github.com/charmbracelet/x/ansi v0.4.5 // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.15.2 // indirect github.com/posener/complete v1.1.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.6.0 // indirect @@ -34,6 +46,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect + golang.org/x/sync v0.10.0 // indirect ) require ( diff --git a/go.sum b/go.sum index 2a2a23ce..bce133b6 100644 --- a/go.sum +++ b/go.sum @@ -6,15 +6,29 @@ github.com/Masterminds/sprig/v3 v3.2.1 h1:n6EPaDyLSvCEa3frruQvAiHuNp2dhBlMSmkEr+ github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/briandowns/spinner v1.23.1 h1:t5fDPmScwUjozhDj4FA46p5acZWIPXYE30qW2Ptu650= github.com/briandowns/spinner v1.23.1/go.mod h1:LaZeM4wm2Ywy6vO571mvhQNRcWfRUnXOs0RcKV0wYKM= +github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= +github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= +github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE= +github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM= +github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= +github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= +github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM= +github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= @@ -52,6 +66,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -61,6 +77,8 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -72,6 +90,12 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= @@ -129,8 +153,11 @@ golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/service/service.go b/internal/service/service.go index 9b04f208..c7d9de5a 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -22,47 +22,13 @@ type Service struct{} var responseMap = make(map[string]string) // DeployService deploys service -func (e *Service) DeployService(ctx *context.Context, request *serviceProto.DeployServiceRequest) error { +func (e *Service) DeployService(ctx *context.Context, request *serviceProto.DeployServiceRequest) (serviceProto.ServiceService_DeployServiceClient, error) { conn, requestCtx, err := grpcClient(ctx) if err != nil { - return err + return nil, err } client := serviceProto.NewServiceServiceClient(conn) - stream, err := client.DeployService(*requestCtx, request) - if err != nil { - return err - } - - log.Info("Deploying Service...") - spinnerInstance := spinner.New(spinner.CharSets[constant.SpinnerType], constant.SpinnerDelay) - err = spinnerInstance.Color(constant.SpinnerColor, constant.SpinnerStyle) - if err != nil { - return err - } - - var message string - for { - response, err := stream.Recv() - spinnerInstance.Stop() - if err != nil { - if errors.Is(err, context.Canceled) || err == io.EOF { - break - } - log.Errorf("TraceID: %s", (*requestCtx).Value(constant.TraceIDKey)) - return err - } - - if response != nil { - - message = util.GenerateResponseMessage(response.GetServiceResponse()) - logFailedComponentMessagesOnce(response.GetServiceResponse()) - spinnerInstance.Prefix = fmt.Sprintf(" %s ", message) - spinnerInstance.Start() - } - } - - log.Info(message) - return err + return client.DeployService(*requestCtx, request) } func logFailedComponentMessagesOnce(response *serviceProto.ServiceResponse) { diff --git a/pkg/ui/styles.go b/pkg/ui/styles.go new file mode 100644 index 00000000..a711e172 --- /dev/null +++ b/pkg/ui/styles.go @@ -0,0 +1,15 @@ +package ui + +import "github.com/charmbracelet/lipgloss" + +var TitleStyle = func() lipgloss.Style { + b := lipgloss.RoundedBorder() + b.Right = "├" + return lipgloss.NewStyle().BorderStyle(b).Padding(0, 1) +}() + +var InfoStyle = func() lipgloss.Style { + b := lipgloss.RoundedBorder() + b.Left = "┤" + return TitleStyle.BorderStyle(b) +}() diff --git a/proto/gen/go/dream11/oam/dto/v1/provider_account.pb.go b/proto/gen/go/dream11/oam/dto/v1/provider_account.pb.go index e62b689d..5c2052c2 100644 --- a/proto/gen/go/dream11/oam/dto/v1/provider_account.pb.go +++ b/proto/gen/go/dream11/oam/dto/v1/provider_account.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/oam/dto/v1/provider_account.proto package v1 diff --git a/proto/gen/go/dream11/oam/provideraccount/v1/provider_account.pb.go b/proto/gen/go/dream11/oam/provideraccount/v1/provider_account.pb.go index 0e92fef9..ad377710 100644 --- a/proto/gen/go/dream11/oam/provideraccount/v1/provider_account.pb.go +++ b/proto/gen/go/dream11/oam/provideraccount/v1/provider_account.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/oam/provideraccount/v1/provider_account.proto package v1 diff --git a/proto/gen/go/dream11/oam/provideraccount/v1/provider_account_grpc.pb.go b/proto/gen/go/dream11/oam/provideraccount/v1/provider_account_grpc.pb.go index 66fa33eb..058d5d5c 100644 --- a/proto/gen/go/dream11/oam/provideraccount/v1/provider_account_grpc.pb.go +++ b/proto/gen/go/dream11/oam/provideraccount/v1/provider_account_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.29.3 +// - protoc v5.26.1 // source: dream11/oam/provideraccount/v1/provider_account.proto package v1 diff --git a/proto/gen/go/dream11/od/auth/v1/auth.pb.go b/proto/gen/go/dream11/od/auth/v1/auth.pb.go index c00c872d..81dba86b 100644 --- a/proto/gen/go/dream11/od/auth/v1/auth.pb.go +++ b/proto/gen/go/dream11/od/auth/v1/auth.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/auth/v1/auth.proto package v1 diff --git a/proto/gen/go/dream11/od/auth/v1/auth_grpc.pb.go b/proto/gen/go/dream11/od/auth/v1/auth_grpc.pb.go index 85bc99fd..dce36b78 100644 --- a/proto/gen/go/dream11/od/auth/v1/auth_grpc.pb.go +++ b/proto/gen/go/dream11/od/auth/v1/auth_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.29.3 +// - protoc v5.26.1 // source: dream11/od/auth/v1/auth.proto package v1 diff --git a/proto/gen/go/dream11/od/component/v1/component.pb.go b/proto/gen/go/dream11/od/component/v1/component.pb.go index 7c566b81..dc0b79b1 100644 --- a/proto/gen/go/dream11/od/component/v1/component.pb.go +++ b/proto/gen/go/dream11/od/component/v1/component.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/component/v1/component.proto package v1 diff --git a/proto/gen/go/dream11/od/component/v1/component_grpc.pb.go b/proto/gen/go/dream11/od/component/v1/component_grpc.pb.go index da28f65f..5989ad67 100644 --- a/proto/gen/go/dream11/od/component/v1/component_grpc.pb.go +++ b/proto/gen/go/dream11/od/component/v1/component_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.29.3 +// - protoc v5.26.1 // source: dream11/od/component/v1/component.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/component.pb.go b/proto/gen/go/dream11/od/dto/v1/component.pb.go index 21e614ab..6b17f5c4 100644 --- a/proto/gen/go/dream11/od/dto/v1/component.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/component.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/dto/v1/component.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/component_task.pb.go b/proto/gen/go/dream11/od/dto/v1/component_task.pb.go index 053445e0..41778f2d 100644 --- a/proto/gen/go/dream11/od/dto/v1/component_task.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/component_task.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/dto/v1/component_task.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/environment.pb.go b/proto/gen/go/dream11/od/dto/v1/environment.pb.go index d8e0d070..fa67eb85 100644 --- a/proto/gen/go/dream11/od/dto/v1/environment.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/environment.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/dto/v1/environment.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/provisioning_type.pb.go b/proto/gen/go/dream11/od/dto/v1/provisioning_type.pb.go index 51ae9600..4f70b6ae 100644 --- a/proto/gen/go/dream11/od/dto/v1/provisioning_type.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/provisioning_type.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/dto/v1/provisioning_type.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/service.pb.go b/proto/gen/go/dream11/od/dto/v1/service.pb.go index ea012c09..7344ef6a 100644 --- a/proto/gen/go/dream11/od/dto/v1/service.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/service.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/dto/v1/service.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/service_task.pb.go b/proto/gen/go/dream11/od/dto/v1/service_task.pb.go index 513c5c38..5576de04 100644 --- a/proto/gen/go/dream11/od/dto/v1/service_task.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/service_task.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/dto/v1/service_task.proto package v1 diff --git a/proto/gen/go/dream11/od/environment/v1/environment.pb.go b/proto/gen/go/dream11/od/environment/v1/environment.pb.go index c0e13e7f..45839571 100644 --- a/proto/gen/go/dream11/od/environment/v1/environment.pb.go +++ b/proto/gen/go/dream11/od/environment/v1/environment.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/environment/v1/environment.proto package v1 diff --git a/proto/gen/go/dream11/od/environment/v1/environment_grpc.pb.go b/proto/gen/go/dream11/od/environment/v1/environment_grpc.pb.go index 88e64bcd..e5f7e77d 100644 --- a/proto/gen/go/dream11/od/environment/v1/environment_grpc.pb.go +++ b/proto/gen/go/dream11/od/environment/v1/environment_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.29.3 +// - protoc v5.26.1 // source: dream11/od/environment/v1/environment.proto package v1 diff --git a/proto/gen/go/dream11/od/service/v1/service.pb.go b/proto/gen/go/dream11/od/service/v1/service.pb.go index 41801a01..505509b2 100644 --- a/proto/gen/go/dream11/od/service/v1/service.pb.go +++ b/proto/gen/go/dream11/od/service/v1/service.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.29.3 +// protoc v5.26.1 // source: dream11/od/service/v1/service.proto package v1 diff --git a/proto/gen/go/dream11/od/service/v1/service_grpc.pb.go b/proto/gen/go/dream11/od/service/v1/service_grpc.pb.go index c80cb4cc..daab0198 100644 --- a/proto/gen/go/dream11/od/service/v1/service_grpc.pb.go +++ b/proto/gen/go/dream11/od/service/v1/service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.29.3 +// - protoc v5.26.1 // source: dream11/od/service/v1/service.proto package v1 From 9d6589517ca64fc985ad72e3e9ea72773fe03299 Mon Sep 17 00:00:00 2001 From: surajgour-d11 Date: Sun, 2 Feb 2025 09:03:37 +0530 Subject: [PATCH 2/8] fix: display & style rendering issues Signed-off-by: surajgour-d11 --- cmd/deploy/model.go | 10 ++----- cmd/deploy/service.go | 69 ++++++++++++++++++++++++++----------------- cmd/deploy/view.go | 7 ++--- pkg/ui/styles.go | 39 +++++++++++++++++++----- pkg/util/text.go | 29 ++++++++++++++++++ 5 files changed, 108 insertions(+), 46 deletions(-) create mode 100644 pkg/util/text.go diff --git a/cmd/deploy/model.go b/cmd/deploy/model.go index 9930203d..9290668d 100644 --- a/cmd/deploy/model.go +++ b/cmd/deploy/model.go @@ -5,15 +5,9 @@ import ( "github.com/charmbracelet/bubbles/viewport" ) -type ServiceSetView struct { - Ready bool - Cursor int - Header Header - Status string - ServiceView []ServiceView -} - type ServiceView struct { + Height int + Width int Ready bool Cursor int Header Header diff --git a/cmd/deploy/service.go b/cmd/deploy/service.go index 95e1190f..d2872c1e 100644 --- a/cmd/deploy/service.go +++ b/cmd/deploy/service.go @@ -9,6 +9,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/dream11/odin/pkg/constant" + "github.com/dream11/odin/pkg/ui" "io" "os" "regexp" @@ -57,15 +58,7 @@ func execute(cmd *cobra.Command) { // Add program in context ctx := cmd.Context() program := tea.NewProgram( - &ServiceView{ - ComponentsView: append( - []ComponentView{ - { - Toggle: false, - }, - }, - ), - }, + &ServiceView{}, tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer" tea.WithMouseCellMotion(), // turn on mouse support, so we can track the mouse wheel ) @@ -100,7 +93,6 @@ func (s *ServiceView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case ServiceView: s.Header = msg.Header s.Status = msg.Status - s.Cursor = msg.Cursor prevCollapsed := make([]bool, len(s.ComponentsView)) for i := range s.ComponentsView { if i < len(prevCollapsed) { @@ -108,12 +100,26 @@ func (s *ServiceView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } - for i := range s.ComponentsView { + for i := range msg.ComponentsView { if i < len(prevCollapsed) { s.ComponentsView[i].Toggle = prevCollapsed[i] s.ComponentsView[i].Header = msg.ComponentsView[i].Header s.ComponentsView[i].Status = msg.ComponentsView[i].Status s.ComponentsView[i].LogView.Content = msg.ComponentsView[i].LogView.Content + //s.ComponentsView[i].LogView.LogViewPort.SetContent(s.ComponentsView[i].LogView.Content) + } else { + s.ComponentsView = append(s.ComponentsView, ComponentView{ + Toggle: msg.ComponentsView[i].Toggle, + Header: msg.ComponentsView[i].Header, + Status: msg.ComponentsView[i].Status, + LogView: LogView{ + Content: msg.ComponentsView[i].LogView.Content, + LogViewPort: viewport.New(s.Width, 10), + }, + }) + //s.ComponentsView[i].LogView.LogViewPort.SetContent(s.ComponentsView[i].LogView.Content) + s.ComponentsView[i].LogView.LogViewPort.MouseWheelDelta = 1 + s.ComponentsView[i].LogView.LogViewPort.YPosition = s.Height + len(s.ComponentsView)*s.Height } } // Handle key presses @@ -132,7 +138,9 @@ func (s *ServiceView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { break case "enter", " ": - s.ComponentsView[s.Cursor].Toggle = !s.ComponentsView[s.Cursor].Toggle + if s.Cursor < len(s.ComponentsView) { + s.ComponentsView[s.Cursor].Toggle = !s.ComponentsView[s.Cursor].Toggle + } break case "q": @@ -143,18 +151,20 @@ func (s *ServiceView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.WindowSizeMsg: headerHeight := lipgloss.Height(s.Header.Text) if !s.Ready { - s.ComponentsView[s.Cursor].LogView.LogViewPort = viewport.New(msg.Width, msg.Height-headerHeight) - s.ComponentsView[s.Cursor].LogView.LogViewPort.MouseWheelDelta = 1 - s.ComponentsView[s.Cursor].LogView.LogViewPort.YPosition = headerHeight + s.Height = msg.Height + s.Width = msg.Width s.Ready = true } else { - s.ComponentsView[s.Cursor].LogView.LogViewPort.Width = msg.Width - 20 - s.ComponentsView[s.Cursor].LogView.LogViewPort.Height = msg.Height - headerHeight - 20 + s.Height = msg.Height + s.Width = msg.Width - headerHeight + for i := range s.ComponentsView { + s.ComponentsView[i].LogView.LogViewPort.Width = msg.Width + s.ComponentsView[i].LogView.LogViewPort.Height = 10 + } } } // Handle keyboard and mouse events in the viewport - s.ComponentsView[s.Cursor].LogView.LogViewPort.SetContent(s.ComponentsView[s.Cursor].LogView.Content) vpcmd := s.updateViewPort(msg) return s, tea.Batch(vpcmd...) @@ -175,22 +185,25 @@ func (s *ServiceView) View() string { return "\n Initializing..." } var builder strings.Builder - builder.WriteString(fmt.Sprintf("%s\n", s.Header.Text)) + builder.WriteString(fmt.Sprintf("%s\n", ui.H1Style.Render(s.Header.Text))) for i, componentView := range s.ComponentsView { - cursor := " " + var componentHeaderText string + if i == s.Cursor { - if componentView.Toggle { - cursor = ">" - } else { - cursor = "V" - } + componentHeaderText = ui.SelectedStyle(ui.H2Style).Render(componentView.Header.Text) + } else { + componentHeaderText = ui.H2Style.Render(componentView.Header.Text) } if !componentView.Toggle { - builder.WriteString(fmt.Sprintf("%s %s \n", cursor, componentView.Header.Text)) + builder.WriteString(fmt.Sprintf("%s \n", componentHeaderText)) } else { - builder.WriteString(fmt.Sprintf("%s\n%s\n%s\n", cursor, componentView.Header.Text, componentView.LogView.LogViewPort.View())) + builder.WriteString(fmt.Sprintf("%s \n", componentHeaderText)) + // Render logs + logsText := strings.Split(s.ComponentsView[i].LogView.Content, "\\n") + componentView.LogView.LogViewPort.SetContent(ui.InfoStyle.Render(strings.Join(logsText, "\n"))) + builder.WriteString(fmt.Sprintf("%s \n", componentView.LogView.LogViewPort.View())) } } @@ -235,6 +248,8 @@ func deployUsingFiles(ctx context.Context, program *tea.Program) { break } log.Errorf("TraceID: %s", ctx.Value(constant.TraceIDKey)) + log.Fatal("Failed to deploy service ", err) + program.Quit() } program.Send(GetServiceView(response)) } diff --git a/cmd/deploy/view.go b/cmd/deploy/view.go index 90745772..f54e36cd 100644 --- a/cmd/deploy/view.go +++ b/cmd/deploy/view.go @@ -2,7 +2,6 @@ package deploy import ( "fmt" - "github.com/dream11/odin/pkg/ui" v1 "github.com/dream11/odin/proto/gen/go/dream11/od/service/v1" ) @@ -18,7 +17,7 @@ func GetServiceView(response *v1.DeployServiceResponse) ServiceView { serviceView := ServiceView{ Header: Header{ - Text: ui.TitleStyle.Render(serviceHeaderText), + Text: serviceHeaderText, }, Status: response.GetServiceResponse().ServiceStatus.GetServiceStatus(), ComponentsView: make([]ComponentView, 0), @@ -36,10 +35,10 @@ func GetServiceView(response *v1.DeployServiceResponse) ServiceView { errorMessage = component.GetError() } componentView := ComponentView{ - Header: Header{Text: ui.TitleStyle.Render(componentHeaderText)}, + Header: Header{Text: componentHeaderText}, Status: component.GetComponentStatus(), LogView: LogView{ - Content: ui.InfoStyle.Render(errorMessage), + Content: errorMessage, }, } serviceView.ComponentsView = append(serviceView.ComponentsView, componentView) diff --git a/pkg/ui/styles.go b/pkg/ui/styles.go index a711e172..7effaf2b 100644 --- a/pkg/ui/styles.go +++ b/pkg/ui/styles.go @@ -2,14 +2,39 @@ package ui import "github.com/charmbracelet/lipgloss" -var TitleStyle = func() lipgloss.Style { - b := lipgloss.RoundedBorder() - b.Right = "├" - return lipgloss.NewStyle().BorderStyle(b).Padding(0, 1) +var H1Style = func() lipgloss.Style { + return lipgloss.NewStyle(). + Foreground(lipgloss.Color("#a556f4")). + Border(lipgloss.RoundedBorder(), true, false). + Padding(1, 2). + Align(lipgloss.Center) +}() + +var H2Style = func() lipgloss.Style { + return lipgloss.NewStyle(). + Foreground(lipgloss.Color("#7d56f4")). + MarginLeft(5). + Border(lipgloss.NormalBorder(), true, false). + Align(lipgloss.Center) }() var InfoStyle = func() lipgloss.Style { - b := lipgloss.RoundedBorder() - b.Left = "┤" - return TitleStyle.BorderStyle(b) + return lipgloss.NewStyle(). + Foreground(lipgloss.Color("#fafafa")). + MarginLeft(10). + Padding(1, 2). + Align(lipgloss.Left) }() + +var SelectedStyle = func(style lipgloss.Style) lipgloss.Style { + return style. + Background(style.GetForeground()). + Foreground(lipgloss.Color("#fafafa")). + Bold(true) +} + +//var GreenBorder = func(style lipgloss.Style) lipgloss.Style { +// return style. +// Border(lipgloss.DoubleBorder()). +// BorderForeground(lipgloss.Color("#00ff00")) +//} diff --git a/pkg/util/text.go b/pkg/util/text.go new file mode 100644 index 00000000..1ac50959 --- /dev/null +++ b/pkg/util/text.go @@ -0,0 +1,29 @@ +package util + +import ( + "fmt" + "github.com/dream11/odin/cmd/deploy" + "strings" +) + +func GetServiceHeader(s deploy.ServiceView) string { + var header strings.Builder + var action string + switch s.Action { + case "VALIDATE": + action = "validating" + case "DEPLOY": + action = "deployment" + case "UNDEPLOY": + action = "un-deployment" + } + switch s.Status { + case "IN_PROGRESS": + header.WriteString(fmt.Sprintf("Service: %s %s in progress", s.Name, action)) + case "SUCCESSFUL": + header.WriteString(fmt.Sprintf("Service: %s %s successful", s.Name, action)) + case "FAILED": + header.WriteString(fmt.Sprintf("Service: %s %s failed", s.Name, action)) + } + return header.String() +} From 82c1cc7e85b945adc000df02011e89c3d0e3e22c Mon Sep 17 00:00:00 2001 From: surajgour-d11 Date: Sun, 2 Feb 2025 22:11:10 +0530 Subject: [PATCH 3/8] chore: code cleaup Signed-off-by: surajgour-d11 --- cmd/deploy/model.go | 53 ++++++++++-------- cmd/deploy/service.go | 123 +++++++++++++++++++----------------------- cmd/deploy/view.go | 35 ++++-------- go.mod | 1 + go.sum | 2 + pkg/util/text.go | 21 ++++---- 6 files changed, 111 insertions(+), 124 deletions(-) diff --git a/cmd/deploy/model.go b/cmd/deploy/model.go index 9290668d..4633ea7d 100644 --- a/cmd/deploy/model.go +++ b/cmd/deploy/model.go @@ -1,35 +1,46 @@ package deploy import ( - "github.com/charmbracelet/bubbles/spinner" + "github.com/charmbracelet/bubbles/progress" "github.com/charmbracelet/bubbles/viewport" ) +type Model struct { + ServiceDisplayMeta ServiceDisplayMeta + ServiceView ServiceView +} + +type ServiceDisplayMeta struct { + Height int + Width int + Ready bool + Cursor int + ElapsedTime int + TotalCompletionTime int + Progress progress.Model + ComponentDisplayMeta []ComponentDisplayMeta +} + +type ComponentDisplayMeta struct { + Height int + Width int + Toggle bool + ElapsedTime int + TotalCompletionTime int + Progress progress.Model + LogViewPort viewport.Model +} + type ServiceView struct { - Height int - Width int - Ready bool - Cursor int - Header Header + Name string Status string + Action string ComponentsView []ComponentView } type ComponentView struct { - Toggle bool - Header Header + Name string Status string - LogView LogView -} - -type Header struct { - Toggle bool - Text string - Spinner spinner.Model -} - -type LogView struct { - Toggle bool - Content string - LogViewPort viewport.Model + Action string + Content string } diff --git a/cmd/deploy/service.go b/cmd/deploy/service.go index d2872c1e..7b54211b 100644 --- a/cmd/deploy/service.go +++ b/cmd/deploy/service.go @@ -10,6 +10,7 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/dream11/odin/pkg/constant" "github.com/dream11/odin/pkg/ui" + "github.com/dream11/odin/pkg/util" "io" "os" "regexp" @@ -58,7 +59,11 @@ func execute(cmd *cobra.Command) { // Add program in context ctx := cmd.Context() program := tea.NewProgram( - &ServiceView{}, + &Model{ + ServiceView: ServiceView{ + Name: "Initiating service deployment", + }, + }, tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer" tea.WithMouseCellMotion(), // turn on mouse support, so we can track the mouse wheel ) @@ -83,127 +88,111 @@ func execute(cmd *cobra.Command) { } } -func (s *ServiceView) Init() tea.Cmd { +func (m *Model) Init() tea.Cmd { + m.ServiceDisplayMeta.Cursor = 0 return nil } -func (s *ServiceView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { +func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { // Handle updates - case ServiceView: - s.Header = msg.Header - s.Status = msg.Status - prevCollapsed := make([]bool, len(s.ComponentsView)) - for i := range s.ComponentsView { - if i < len(prevCollapsed) { - prevCollapsed[i] = s.ComponentsView[i].Toggle - } - } - - for i := range msg.ComponentsView { - if i < len(prevCollapsed) { - s.ComponentsView[i].Toggle = prevCollapsed[i] - s.ComponentsView[i].Header = msg.ComponentsView[i].Header - s.ComponentsView[i].Status = msg.ComponentsView[i].Status - s.ComponentsView[i].LogView.Content = msg.ComponentsView[i].LogView.Content - //s.ComponentsView[i].LogView.LogViewPort.SetContent(s.ComponentsView[i].LogView.Content) - } else { - s.ComponentsView = append(s.ComponentsView, ComponentView{ - Toggle: msg.ComponentsView[i].Toggle, - Header: msg.ComponentsView[i].Header, - Status: msg.ComponentsView[i].Status, - LogView: LogView{ - Content: msg.ComponentsView[i].LogView.Content, - LogViewPort: viewport.New(s.Width, 10), + case Model: + m.ServiceView = msg.ServiceView + if len(m.ServiceView.ComponentsView) > len(m.ServiceDisplayMeta.ComponentDisplayMeta) { + for i := len(m.ServiceDisplayMeta.ComponentDisplayMeta); i < len(m.ServiceView.ComponentsView); i++ { + m.ServiceDisplayMeta.ComponentDisplayMeta = append(m.ServiceDisplayMeta.ComponentDisplayMeta, ComponentDisplayMeta{ + LogViewPort: viewport.Model{ + Width: m.ServiceDisplayMeta.Width, + Height: 10, }, }) - //s.ComponentsView[i].LogView.LogViewPort.SetContent(s.ComponentsView[i].LogView.Content) - s.ComponentsView[i].LogView.LogViewPort.MouseWheelDelta = 1 - s.ComponentsView[i].LogView.LogViewPort.YPosition = s.Height + len(s.ComponentsView)*s.Height } } // Handle key presses case tea.KeyMsg: switch msg.String() { case "up": - if s.Cursor > 0 { - s.Cursor-- + if m.ServiceDisplayMeta.Cursor > 0 { + m.ServiceDisplayMeta.Cursor-- } break case "down": - if s.Cursor < len(s.ComponentsView)-1 { - s.Cursor++ + if m.ServiceDisplayMeta.Cursor < len(m.ServiceDisplayMeta.ComponentDisplayMeta)-1 { + m.ServiceDisplayMeta.Cursor++ } break case "enter", " ": - if s.Cursor < len(s.ComponentsView) { - s.ComponentsView[s.Cursor].Toggle = !s.ComponentsView[s.Cursor].Toggle + if m.ServiceDisplayMeta.Cursor < len(m.ServiceDisplayMeta.ComponentDisplayMeta) { + m.ServiceDisplayMeta.ComponentDisplayMeta[m.ServiceDisplayMeta.Cursor].Toggle = + !m.ServiceDisplayMeta.ComponentDisplayMeta[m.ServiceDisplayMeta.Cursor].Toggle } break case "q": - return s, tea.Quit + return m, tea.Quit } // Handle window resizes case tea.WindowSizeMsg: - headerHeight := lipgloss.Height(s.Header.Text) - if !s.Ready { - s.Height = msg.Height - s.Width = msg.Width - s.Ready = true + m.ServiceDisplayMeta.Height = msg.Height + m.ServiceDisplayMeta.Width = msg.Width + if !m.ServiceDisplayMeta.Ready { + m.ServiceDisplayMeta.Ready = true } else { - s.Height = msg.Height - s.Width = msg.Width - headerHeight - for i := range s.ComponentsView { - s.ComponentsView[i].LogView.LogViewPort.Width = msg.Width - s.ComponentsView[i].LogView.LogViewPort.Height = 10 + for i := range m.ServiceDisplayMeta.ComponentDisplayMeta { + m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Width = msg.Width + m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Height = + min(msg.Height-len(m.ServiceDisplayMeta.ComponentDisplayMeta)*(lipgloss.Height(m.ServiceView.ComponentsView[i].Name)), + 10) } } } - // Handle keyboard and mouse events in the viewport - vpcmd := s.updateViewPort(msg) + viewPortCmd := m.updateViewPort(msg) - return s, tea.Batch(vpcmd...) + return m, tea.Batch(viewPortCmd...) } -func (s *ServiceView) updateViewPort(msg tea.Msg) []tea.Cmd { +func (m *Model) updateViewPort(msg tea.Msg) []tea.Cmd { var cmds []tea.Cmd var cmd tea.Cmd - for i := range s.ComponentsView { - s.ComponentsView[i].LogView.LogViewPort, cmd = s.ComponentsView[i].LogView.LogViewPort.Update(msg) + for i := range m.ServiceDisplayMeta.ComponentDisplayMeta { + m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort, cmd = + m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Update(msg) cmds = append(cmds, cmd) } return cmds } -func (s *ServiceView) View() string { - if !s.Ready { +func (m *Model) View() string { + if !m.ServiceDisplayMeta.Ready { return "\n Initializing..." } var builder strings.Builder - builder.WriteString(fmt.Sprintf("%s\n", ui.H1Style.Render(s.Header.Text))) - for i, componentView := range s.ComponentsView { - var componentHeaderText string + // Build Service View + serviceHeader := util.GetHeaderText(m.ServiceView.Name, m.ServiceView.Action, m.ServiceView.Status, "Service") + builder.WriteString(ui.H1Style.Render(serviceHeader)) - if i == s.Cursor { - componentHeaderText = ui.SelectedStyle(ui.H2Style).Render(componentView.Header.Text) + for i, componentView := range m.ServiceView.ComponentsView { + componentHeader := util.GetHeaderText(componentView.Name, componentView.Action, componentView.Status, "Component") + var componentHeaderText string + if i == m.ServiceDisplayMeta.Cursor { + componentHeaderText = ui.SelectedStyle(ui.H2Style).Render(componentHeader) } else { - componentHeaderText = ui.H2Style.Render(componentView.Header.Text) + componentHeaderText = ui.H2Style.Render(componentHeader) } - if !componentView.Toggle { + if !m.ServiceDisplayMeta.ComponentDisplayMeta[i].Toggle { builder.WriteString(fmt.Sprintf("%s \n", componentHeaderText)) } else { builder.WriteString(fmt.Sprintf("%s \n", componentHeaderText)) // Render logs - logsText := strings.Split(s.ComponentsView[i].LogView.Content, "\\n") - componentView.LogView.LogViewPort.SetContent(ui.InfoStyle.Render(strings.Join(logsText, "\n"))) - builder.WriteString(fmt.Sprintf("%s \n", componentView.LogView.LogViewPort.View())) + logsText := strings.Split(componentView.Content, "\\n") + m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.SetContent(ui.InfoStyle.Render(strings.Join(logsText, "\n"))) + builder.WriteString(fmt.Sprintf("%s \n", m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.View())) } } @@ -251,7 +240,7 @@ func deployUsingFiles(ctx context.Context, program *tea.Program) { log.Fatal("Failed to deploy service ", err) program.Quit() } - program.Send(GetServiceView(response)) + program.Send(GetServiceDeployModel(response)) } } diff --git a/cmd/deploy/view.go b/cmd/deploy/view.go index f54e36cd..3fe61c25 100644 --- a/cmd/deploy/view.go +++ b/cmd/deploy/view.go @@ -1,47 +1,32 @@ package deploy import ( - "fmt" v1 "github.com/dream11/odin/proto/gen/go/dream11/od/service/v1" ) -func GetServiceView(response *v1.DeployServiceResponse) ServiceView { +func GetServiceDeployModel(response *v1.DeployServiceResponse) Model { serviceName := response.GetServiceResponse().Name - serviceHeaderText := fmt.Sprintf("Deploying service %s ", serviceName) - if response.GetServiceResponse().ServiceStatus.GetServiceStatus() == "SUCCESSFUL" { - serviceHeaderText = fmt.Sprintf("Service %s deployed successfully", serviceName) - } else if response.GetServiceResponse().ServiceStatus.GetServiceStatus() == "FAILED" { - serviceHeaderText = fmt.Sprintf("Failed to deploy service %s", serviceName) - } - serviceView := ServiceView{ - Header: Header{ - Text: serviceHeaderText, - }, + Name: serviceName, + Action: response.GetServiceResponse().ServiceStatus.GetServiceAction(), Status: response.GetServiceResponse().ServiceStatus.GetServiceStatus(), ComponentsView: make([]ComponentView, 0), } for _, component := range response.GetServiceResponse().GetComponentsStatus() { - componentHeaderText := fmt.Sprintf("Deploying component %s", component.GetComponentName()) - if component.GetComponentStatus() == "SUCCESSFUL" { - componentHeaderText = fmt.Sprintf("Component %s deployed successfully", component.GetComponentName()) - } else if component.GetComponentStatus() == "FAILED" { - componentHeaderText = fmt.Sprintf("Failed to deploy component %s", component.GetComponentName()) - } - errorMessage := "Awaiting component logs" if component.GetError() != "" { errorMessage = component.GetError() } componentView := ComponentView{ - Header: Header{Text: componentHeaderText}, - Status: component.GetComponentStatus(), - LogView: LogView{ - Content: errorMessage, - }, + Name: component.GetComponentName(), + Action: component.GetComponentAction(), + Status: component.GetComponentStatus(), + Content: errorMessage, } serviceView.ComponentsView = append(serviceView.ComponentsView, componentView) } - return serviceView + return Model{ + ServiceView: serviceView, + } } diff --git a/go.mod b/go.mod index c99244b9..836b5cea 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/charmbracelet/harmonica v0.2.0 // indirect github.com/charmbracelet/lipgloss v1.0.0 // indirect github.com/charmbracelet/x/ansi v0.4.5 // indirect github.com/charmbracelet/x/term v0.2.1 // indirect diff --git a/go.sum b/go.sum index bce133b6..09cef3e6 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQW github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE= github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM= +github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= +github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM= diff --git a/pkg/util/text.go b/pkg/util/text.go index 1ac50959..e6808a06 100644 --- a/pkg/util/text.go +++ b/pkg/util/text.go @@ -2,28 +2,27 @@ package util import ( "fmt" - "github.com/dream11/odin/cmd/deploy" "strings" ) -func GetServiceHeader(s deploy.ServiceView) string { +func GetHeaderText(name string, action string, status string, element string) string { var header strings.Builder - var action string - switch s.Action { + var actionText string + switch action { case "VALIDATE": - action = "validating" + actionText = "validating" case "DEPLOY": - action = "deployment" + actionText = "deployment" case "UNDEPLOY": - action = "un-deployment" + actionText = "un-deployment" } - switch s.Status { + switch status { case "IN_PROGRESS": - header.WriteString(fmt.Sprintf("Service: %s %s in progress", s.Name, action)) + header.WriteString(fmt.Sprintf("%s: %s %s in progress", element, name, actionText)) case "SUCCESSFUL": - header.WriteString(fmt.Sprintf("Service: %s %s successful", s.Name, action)) + header.WriteString(fmt.Sprintf("%s: %s %s successful", element, name, actionText)) case "FAILED": - header.WriteString(fmt.Sprintf("Service: %s %s failed", s.Name, action)) + header.WriteString(fmt.Sprintf("%s: %s %s failed", element, name, actionText)) } return header.String() } From 0f447d7742f241f5b984679531a105bf2698c9f6 Mon Sep 17 00:00:00 2001 From: surajgour-d11 Date: Mon, 3 Feb 2025 14:51:04 +0530 Subject: [PATCH 4/8] feat: styling update Signed-off-by: surajgour-d11 --- cmd/deploy/model.go | 13 ++++----- cmd/deploy/service.go | 66 +++++++++++++++++++++++++++++++++++-------- pkg/ui/styles.go | 40 ++++++++++++++------------ pkg/util/text.go | 28 ------------------ pkg/util/util.go | 22 +++++++++++++++ 5 files changed, 104 insertions(+), 65 deletions(-) delete mode 100644 pkg/util/text.go diff --git a/cmd/deploy/model.go b/cmd/deploy/model.go index 4633ea7d..101f4c32 100644 --- a/cmd/deploy/model.go +++ b/cmd/deploy/model.go @@ -2,6 +2,7 @@ package deploy import ( "github.com/charmbracelet/bubbles/progress" + "github.com/charmbracelet/bubbles/spinner" "github.com/charmbracelet/bubbles/viewport" ) @@ -22,13 +23,11 @@ type ServiceDisplayMeta struct { } type ComponentDisplayMeta struct { - Height int - Width int - Toggle bool - ElapsedTime int - TotalCompletionTime int - Progress progress.Model - LogViewPort viewport.Model + Height int + Width int + Toggle bool + Spinner spinner.Model + LogViewPort viewport.Model } type ServiceView struct { diff --git a/cmd/deploy/service.go b/cmd/deploy/service.go index 7b54211b..6be3f507 100644 --- a/cmd/deploy/service.go +++ b/cmd/deploy/service.go @@ -5,6 +5,8 @@ import ( "encoding/json" "errors" "fmt" + "github.com/charmbracelet/bubbles/progress" + "github.com/charmbracelet/bubbles/spinner" "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" @@ -64,8 +66,8 @@ func execute(cmd *cobra.Command) { Name: "Initiating service deployment", }, }, - tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer" - tea.WithMouseCellMotion(), // turn on mouse support, so we can track the mouse wheel + tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer" + //tea.WithMouseCellMotion(), // turn on mouse support, so we can track the mouse wheel ) go func() { @@ -89,11 +91,15 @@ func execute(cmd *cobra.Command) { } func (m *Model) Init() tea.Cmd { + m.ServiceDisplayMeta.Progress = progress.New(progress.WithDefaultScaledGradient()) + m.ServiceDisplayMeta.Progress.PercentageStyle = ui.ProgressBarStyle + m.ServiceDisplayMeta.Progress.SetPercent(100) m.ServiceDisplayMeta.Cursor = 0 return nil } func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var updateCmds []tea.Cmd switch msg := msg.(type) { // Handle updates case Model: @@ -106,19 +112,29 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { Height: 10, }, }) + m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner = spinner.New() + m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Style = ui.SpinnerStyle + m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Spinner = spinner.Points } } // Handle key presses case tea.KeyMsg: + anyToggled := false + for _, component := range m.ServiceDisplayMeta.ComponentDisplayMeta { + if component.Toggle { + anyToggled = true + break + } + } switch msg.String() { case "up": - if m.ServiceDisplayMeta.Cursor > 0 { + if m.ServiceDisplayMeta.Cursor > 0 && !anyToggled { m.ServiceDisplayMeta.Cursor-- } break case "down": - if m.ServiceDisplayMeta.Cursor < len(m.ServiceDisplayMeta.ComponentDisplayMeta)-1 { + if m.ServiceDisplayMeta.Cursor < len(m.ServiceDisplayMeta.ComponentDisplayMeta)-1 && !anyToggled { m.ServiceDisplayMeta.Cursor++ } break @@ -148,11 +164,16 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { 10) } } + case spinner.TickMsg: + spinnerUpdateCmds := m.updateSpinners(msg) + return m, tea.Batch(spinnerUpdateCmds...) } + // Handle keyboard and mouse events in the viewport - viewPortCmd := m.updateViewPort(msg) + updateCmds = append(updateCmds, m.tickSpinners()...) + updateCmds = append(updateCmds, m.updateViewPort(msg)...) - return m, tea.Batch(viewPortCmd...) + return m, tea.Batch(updateCmds...) } func (m *Model) updateViewPort(msg tea.Msg) []tea.Cmd { @@ -166,6 +187,25 @@ func (m *Model) updateViewPort(msg tea.Msg) []tea.Cmd { return cmds } +func (m *Model) updateSpinners(msg tea.Msg) []tea.Cmd { + var cmds []tea.Cmd + var cmd tea.Cmd + for i := range m.ServiceDisplayMeta.ComponentDisplayMeta { + m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner, cmd = + m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Update(msg) + cmds = append(cmds, cmd) + } + return cmds +} + +func (m *Model) tickSpinners() []tea.Cmd { + var cmds []tea.Cmd + for i := range m.ServiceDisplayMeta.ComponentDisplayMeta { + cmds = append(cmds, m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Tick) + } + return cmds +} + func (m *Model) View() string { if !m.ServiceDisplayMeta.Ready { return "\n Initializing..." @@ -174,7 +214,9 @@ func (m *Model) View() string { // Build Service View serviceHeader := util.GetHeaderText(m.ServiceView.Name, m.ServiceView.Action, m.ServiceView.Status, "Service") - builder.WriteString(ui.H1Style.Render(serviceHeader)) + builder.WriteString(fmt.Sprintf("%s\n", ui.H1Style.Render(serviceHeader))) + m.ServiceDisplayMeta.Progress.Width = lipgloss.Width(serviceHeader) + builder.WriteString(fmt.Sprintf("%s\n", m.ServiceDisplayMeta.Progress.ViewAs(100.0))) for i, componentView := range m.ServiceView.ComponentsView { componentHeader := util.GetHeaderText(componentView.Name, componentView.Action, componentView.Status, "Component") @@ -184,11 +226,11 @@ func (m *Model) View() string { } else { componentHeaderText = ui.H2Style.Render(componentHeader) } - - if !m.ServiceDisplayMeta.ComponentDisplayMeta[i].Toggle { - builder.WriteString(fmt.Sprintf("%s \n", componentHeaderText)) - } else { - builder.WriteString(fmt.Sprintf("%s \n", componentHeaderText)) + if m.ServiceView.ComponentsView[i].Status != "IN_PROGRESS" { + m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Spinner = spinner.Pulse + } + builder.WriteString(fmt.Sprintf("%s %s\n", componentHeaderText, m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.View())) + if m.ServiceDisplayMeta.ComponentDisplayMeta[i].Toggle { // Render logs logsText := strings.Split(componentView.Content, "\\n") m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.SetContent(ui.InfoStyle.Render(strings.Join(logsText, "\n"))) diff --git a/pkg/ui/styles.go b/pkg/ui/styles.go index 7effaf2b..cc64d8bf 100644 --- a/pkg/ui/styles.go +++ b/pkg/ui/styles.go @@ -4,37 +4,41 @@ import "github.com/charmbracelet/lipgloss" var H1Style = func() lipgloss.Style { return lipgloss.NewStyle(). - Foreground(lipgloss.Color("#a556f4")). - Border(lipgloss.RoundedBorder(), true, false). - Padding(1, 2). - Align(lipgloss.Center) + Foreground(lipgloss.Color("#BC88D3")). + Margin(1). + Align(lipgloss.Left) }() var H2Style = func() lipgloss.Style { return lipgloss.NewStyle(). - Foreground(lipgloss.Color("#7d56f4")). - MarginLeft(5). - Border(lipgloss.NormalBorder(), true, false). - Align(lipgloss.Center) + Foreground(lipgloss.Color("#E8D2F2")). + Margin(1, 1, 0, 5). + Align(lipgloss.Left) }() var InfoStyle = func() lipgloss.Style { return lipgloss.NewStyle(). - Foreground(lipgloss.Color("#fafafa")). - MarginLeft(10). - Padding(1, 2). + Foreground(lipgloss.Color("#E8D2F2")). + MarginLeft(5). + BorderLeft(true). + BorderStyle(lipgloss.RoundedBorder()). + PaddingLeft(2). Align(lipgloss.Left) }() var SelectedStyle = func(style lipgloss.Style) lipgloss.Style { return style. - Background(style.GetForeground()). - Foreground(lipgloss.Color("#fafafa")). + Underline(true). Bold(true) } -//var GreenBorder = func(style lipgloss.Style) lipgloss.Style { -// return style. -// Border(lipgloss.DoubleBorder()). -// BorderForeground(lipgloss.Color("#00ff00")) -//} +var SpinnerStyle = func() lipgloss.Style { + return lipgloss.NewStyle(). + PaddingBottom(1). + Foreground(lipgloss.Color("#D9D9D9")) +}() + +var ProgressBarStyle = func() lipgloss.Style { + return lipgloss.NewStyle(). + Foreground(lipgloss.Color("#E88D4C")) +}() diff --git a/pkg/util/text.go b/pkg/util/text.go deleted file mode 100644 index e6808a06..00000000 --- a/pkg/util/text.go +++ /dev/null @@ -1,28 +0,0 @@ -package util - -import ( - "fmt" - "strings" -) - -func GetHeaderText(name string, action string, status string, element string) string { - var header strings.Builder - var actionText string - switch action { - case "VALIDATE": - actionText = "validating" - case "DEPLOY": - actionText = "deployment" - case "UNDEPLOY": - actionText = "un-deployment" - } - switch status { - case "IN_PROGRESS": - header.WriteString(fmt.Sprintf("%s: %s %s in progress", element, name, actionText)) - case "SUCCESSFUL": - header.WriteString(fmt.Sprintf("%s: %s %s successful", element, name, actionText)) - case "FAILED": - header.WriteString(fmt.Sprintf("%s: %s %s failed", element, name, actionText)) - } - return header.String() -} diff --git a/pkg/util/util.go b/pkg/util/util.go index 8ddf8a5d..9ac4eeef 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -166,3 +166,25 @@ func ConvertJSONToYAML(jsonStr string) (string, error) { // Return the YAML string return string(yamlData), nil } + +func GetHeaderText(name string, action string, status string, element string) string { + var header strings.Builder + var actionText string + switch action { + case "VALIDATE": + actionText = "validation" + case "DEPLOY": + actionText = "deployment" + case "UNDEPLOY": + actionText = "un-deployment" + } + switch status { + case "IN_PROGRESS": + header.WriteString(fmt.Sprintf("%s: %s %s in progress", element, name, actionText)) + case "SUCCESSFUL": + header.WriteString(fmt.Sprintf("%s: %s %s successful", element, name, actionText)) + case "FAILED": + header.WriteString(fmt.Sprintf("%s: %s %s failed", element, name, actionText)) + } + return header.String() +} From 494fcbabc86ed78c94e9dc10532ba30fa2832765 Mon Sep 17 00:00:00 2001 From: surajgour-d11 Date: Mon, 3 Feb 2025 16:40:19 +0530 Subject: [PATCH 5/8] feat: styling update Signed-off-by: surajgour-d11 --- cmd/deploy/model.go | 1 + cmd/deploy/service.go | 20 ++++++++++---------- cmd/deploy/view.go | 1 + pkg/ui/styles.go | 16 ++++++++++++++++ pkg/util/util.go | 5 +++++ 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/cmd/deploy/model.go b/cmd/deploy/model.go index 101f4c32..429ae9a8 100644 --- a/cmd/deploy/model.go +++ b/cmd/deploy/model.go @@ -34,6 +34,7 @@ type ServiceView struct { Name string Status string Action string + TraceId string ComponentsView []ComponentView } diff --git a/cmd/deploy/service.go b/cmd/deploy/service.go index 6be3f507..b797f512 100644 --- a/cmd/deploy/service.go +++ b/cmd/deploy/service.go @@ -10,7 +10,6 @@ import ( "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" - "github.com/dream11/odin/pkg/constant" "github.com/dream11/odin/pkg/ui" "github.com/dream11/odin/pkg/util" "io" @@ -103,6 +102,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { // Handle updates case Model: + m.ServiceDisplayMeta.Ready = true m.ServiceView = msg.ServiceView if len(m.ServiceView.ComponentsView) > len(m.ServiceDisplayMeta.ComponentDisplayMeta) { for i := len(m.ServiceDisplayMeta.ComponentDisplayMeta); i < len(m.ServiceView.ComponentsView); i++ { @@ -154,14 +154,11 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.WindowSizeMsg: m.ServiceDisplayMeta.Height = msg.Height m.ServiceDisplayMeta.Width = msg.Width - if !m.ServiceDisplayMeta.Ready { - m.ServiceDisplayMeta.Ready = true - } else { + if m.ServiceDisplayMeta.Ready { for i := range m.ServiceDisplayMeta.ComponentDisplayMeta { m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Width = msg.Width m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Height = - min(msg.Height-len(m.ServiceDisplayMeta.ComponentDisplayMeta)*(lipgloss.Height(m.ServiceView.ComponentsView[i].Name)), - 10) + max(util.GetAvailableViewPortHeight(msg.Height, lipgloss.Height("text"), len(m.ServiceDisplayMeta.ComponentDisplayMeta)), 10) } } case spinner.TickMsg: @@ -208,15 +205,16 @@ func (m *Model) tickSpinners() []tea.Cmd { func (m *Model) View() string { if !m.ServiceDisplayMeta.Ready { - return "\n Initializing..." + return ui.H1Style.Render("Initializing service deployment...") } var builder strings.Builder // Build Service View serviceHeader := util.GetHeaderText(m.ServiceView.Name, m.ServiceView.Action, m.ServiceView.Status, "Service") builder.WriteString(fmt.Sprintf("%s\n", ui.H1Style.Render(serviceHeader))) - m.ServiceDisplayMeta.Progress.Width = lipgloss.Width(serviceHeader) + m.ServiceDisplayMeta.Progress.Width = lipgloss.Width(serviceHeader) + 6 // to accommodate the percentage text builder.WriteString(fmt.Sprintf("%s\n", m.ServiceDisplayMeta.Progress.ViewAs(100.0))) + builder.WriteString(fmt.Sprintf("Trace Id: %s\n", ui.TextStyle.Render(m.ServiceView.TraceId))) for i, componentView := range m.ServiceView.ComponentsView { componentHeader := util.GetHeaderText(componentView.Name, componentView.Action, componentView.Status, "Component") @@ -238,6 +236,10 @@ func (m *Model) View() string { } } + // Add Footer with operating instructions + builder.WriteString("\n\n") + builder.WriteString(ui.FooterStyle.Render("Use ↑ and ↓ to navigate components, Enter to toggle logs, q to quit")) + return builder.String() } @@ -278,8 +280,6 @@ func deployUsingFiles(ctx context.Context, program *tea.Program) { if errors.Is(err, context.Canceled) || err == io.EOF { break } - log.Errorf("TraceID: %s", ctx.Value(constant.TraceIDKey)) - log.Fatal("Failed to deploy service ", err) program.Quit() } program.Send(GetServiceDeployModel(response)) diff --git a/cmd/deploy/view.go b/cmd/deploy/view.go index 3fe61c25..797e57f8 100644 --- a/cmd/deploy/view.go +++ b/cmd/deploy/view.go @@ -11,6 +11,7 @@ func GetServiceDeployModel(response *v1.DeployServiceResponse) Model { Name: serviceName, Action: response.GetServiceResponse().ServiceStatus.GetServiceAction(), Status: response.GetServiceResponse().ServiceStatus.GetServiceStatus(), + TraceId: "random-trace-id", ComponentsView: make([]ComponentView, 0), } for _, component := range response.GetServiceResponse().GetComponentsStatus() { diff --git a/pkg/ui/styles.go b/pkg/ui/styles.go index cc64d8bf..188168ea 100644 --- a/pkg/ui/styles.go +++ b/pkg/ui/styles.go @@ -16,6 +16,22 @@ var H2Style = func() lipgloss.Style { Align(lipgloss.Left) }() +var TextStyle = func() lipgloss.Style { + return lipgloss.NewStyle(). + Foreground(lipgloss.Color("#E8D2F2")). + Italic(true). + Align(lipgloss.Left) +}() + +var FooterStyle = func() lipgloss.Style { + return lipgloss.NewStyle(). + Foreground(lipgloss.Color("#E8D2F2")). + Bold(false). + Italic(true). + Faint(true). + Align(lipgloss.Left) +}() + var InfoStyle = func() lipgloss.Style { return lipgloss.NewStyle(). Foreground(lipgloss.Color("#E8D2F2")). diff --git a/pkg/util/util.go b/pkg/util/util.go index 9ac4eeef..7ee57100 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -188,3 +188,8 @@ func GetHeaderText(name string, action string, status string, element string) st } return header.String() } + +func GetAvailableViewPortHeight(totalHeight int, headerHeight int, numberOfComponents int) int { + bottomPadding := 12 + return totalHeight - ((headerHeight + 2) + numberOfComponents*(headerHeight+1)) - bottomPadding +} From 0da62663d50706a735d6d834f723b9f20ee51787 Mon Sep 17 00:00:00 2001 From: surajgour-d11 Date: Mon, 3 Feb 2025 16:40:19 +0530 Subject: [PATCH 6/8] feat: styling update Signed-off-by: surajgour-d11 --- cmd/deploy/service.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/deploy/service.go b/cmd/deploy/service.go index b797f512..18734abf 100644 --- a/cmd/deploy/service.go +++ b/cmd/deploy/service.go @@ -65,8 +65,7 @@ func execute(cmd *cobra.Command) { Name: "Initiating service deployment", }, }, - tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer" - //tea.WithMouseCellMotion(), // turn on mouse support, so we can track the mouse wheel + tea.WithAltScreen(), ) go func() { From 22244768de4505063a113c32aace3e5d1027d2cc Mon Sep 17 00:00:00 2001 From: surajgour-d11 Date: Tue, 4 Feb 2025 11:53:09 +0530 Subject: [PATCH 7/8] chore: refactoring Signed-off-by: surajgour-d11 --- cmd/deploy/model.go | 46 ---- cmd/deploy/service.go | 213 +----------------- cmd/deploy/view.go | 33 --- internal/service/service.go | 42 +++- internal/ui/deploy.go | 166 ++++++++++++++ internal/ui/deploymodel.go | 75 ++++++ {pkg => internal}/ui/styles.go | 0 .../dream11/oam/dto/v1/provider_account.pb.go | 2 +- .../provideraccount/v1/provider_account.pb.go | 2 +- .../v1/provider_account_grpc.pb.go | 2 +- proto/gen/go/dream11/od/auth/v1/auth.pb.go | 2 +- .../gen/go/dream11/od/auth/v1/auth_grpc.pb.go | 2 +- .../dream11/od/component/v1/component.pb.go | 2 +- .../od/component/v1/component_grpc.pb.go | 2 +- .../gen/go/dream11/od/dto/v1/component.pb.go | 2 +- .../go/dream11/od/dto/v1/component_task.pb.go | 2 +- .../go/dream11/od/dto/v1/environment.pb.go | 2 +- .../dream11/od/dto/v1/provisioning_type.pb.go | 2 +- proto/gen/go/dream11/od/dto/v1/service.pb.go | 2 +- .../go/dream11/od/dto/v1/service_task.pb.go | 2 +- .../od/environment/v1/environment.pb.go | 2 +- .../od/environment/v1/environment_grpc.pb.go | 2 +- .../go/dream11/od/service/v1/service.pb.go | 2 +- .../dream11/od/service/v1/service_grpc.pb.go | 2 +- 24 files changed, 309 insertions(+), 300 deletions(-) delete mode 100644 cmd/deploy/model.go delete mode 100644 cmd/deploy/view.go create mode 100644 internal/ui/deploy.go create mode 100644 internal/ui/deploymodel.go rename {pkg => internal}/ui/styles.go (100%) diff --git a/cmd/deploy/model.go b/cmd/deploy/model.go deleted file mode 100644 index 429ae9a8..00000000 --- a/cmd/deploy/model.go +++ /dev/null @@ -1,46 +0,0 @@ -package deploy - -import ( - "github.com/charmbracelet/bubbles/progress" - "github.com/charmbracelet/bubbles/spinner" - "github.com/charmbracelet/bubbles/viewport" -) - -type Model struct { - ServiceDisplayMeta ServiceDisplayMeta - ServiceView ServiceView -} - -type ServiceDisplayMeta struct { - Height int - Width int - Ready bool - Cursor int - ElapsedTime int - TotalCompletionTime int - Progress progress.Model - ComponentDisplayMeta []ComponentDisplayMeta -} - -type ComponentDisplayMeta struct { - Height int - Width int - Toggle bool - Spinner spinner.Model - LogViewPort viewport.Model -} - -type ServiceView struct { - Name string - Status string - Action string - TraceId string - ComponentsView []ComponentView -} - -type ComponentView struct { - Name string - Status string - Action string - Content string -} diff --git a/cmd/deploy/service.go b/cmd/deploy/service.go index 18734abf..428bac58 100644 --- a/cmd/deploy/service.go +++ b/cmd/deploy/service.go @@ -4,18 +4,8 @@ import ( "context" "encoding/json" "errors" - "fmt" - "github.com/charmbracelet/bubbles/progress" - "github.com/charmbracelet/bubbles/spinner" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - "github.com/dream11/odin/pkg/ui" - "github.com/dream11/odin/pkg/util" - "io" "os" "regexp" - "strings" "github.com/dream11/odin/internal/service" "github.com/dream11/odin/pkg/config" @@ -57,192 +47,23 @@ func init() { func execute(cmd *cobra.Command) { env = config.EnsureEnvPresent(env) - // Add program in context ctx := cmd.Context() - program := tea.NewProgram( - &Model{ - ServiceView: ServiceView{ - Name: "Initiating service deployment", - }, - }, - tea.WithAltScreen(), - ) - - go func() { - if (serviceName == "" && serviceVersion == "" && labels == "") && (definitionFile != "" && provisioningFile != "") { - deployUsingFiles(ctx, program) - } else if (serviceName != "" && serviceVersion != "" && labels == "") && (definitionFile == "" && provisioningFile == "") { - deployUsingServiceNameAndVersion(ctx) - } else if (serviceName != "" && labels != "" && serviceVersion == "") && (definitionFile == "" && provisioningFile == "") { - if err := validateLabels(labels); err != nil { - log.Fatal("Invalid labels format: ", err) - } - deployUsingServiceNameAndLabels(ctx) - } else { - log.Fatal("Invalid combination of flags. Use either (service name and version) or (service name and labels) or (definitionFile and provisioningFile).") - } - }() - - if _, err := program.Run(); err != nil { - os.Exit(1) - } -} - -func (m *Model) Init() tea.Cmd { - m.ServiceDisplayMeta.Progress = progress.New(progress.WithDefaultScaledGradient()) - m.ServiceDisplayMeta.Progress.PercentageStyle = ui.ProgressBarStyle - m.ServiceDisplayMeta.Progress.SetPercent(100) - m.ServiceDisplayMeta.Cursor = 0 - return nil -} - -func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - var updateCmds []tea.Cmd - switch msg := msg.(type) { - // Handle updates - case Model: - m.ServiceDisplayMeta.Ready = true - m.ServiceView = msg.ServiceView - if len(m.ServiceView.ComponentsView) > len(m.ServiceDisplayMeta.ComponentDisplayMeta) { - for i := len(m.ServiceDisplayMeta.ComponentDisplayMeta); i < len(m.ServiceView.ComponentsView); i++ { - m.ServiceDisplayMeta.ComponentDisplayMeta = append(m.ServiceDisplayMeta.ComponentDisplayMeta, ComponentDisplayMeta{ - LogViewPort: viewport.Model{ - Width: m.ServiceDisplayMeta.Width, - Height: 10, - }, - }) - m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner = spinner.New() - m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Style = ui.SpinnerStyle - m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Spinner = spinner.Points - } - } - // Handle key presses - case tea.KeyMsg: - anyToggled := false - for _, component := range m.ServiceDisplayMeta.ComponentDisplayMeta { - if component.Toggle { - anyToggled = true - break - } - } - switch msg.String() { - case "up": - if m.ServiceDisplayMeta.Cursor > 0 && !anyToggled { - m.ServiceDisplayMeta.Cursor-- - } - break - - case "down": - if m.ServiceDisplayMeta.Cursor < len(m.ServiceDisplayMeta.ComponentDisplayMeta)-1 && !anyToggled { - m.ServiceDisplayMeta.Cursor++ - } - break - - case "enter", " ": - if m.ServiceDisplayMeta.Cursor < len(m.ServiceDisplayMeta.ComponentDisplayMeta) { - m.ServiceDisplayMeta.ComponentDisplayMeta[m.ServiceDisplayMeta.Cursor].Toggle = - !m.ServiceDisplayMeta.ComponentDisplayMeta[m.ServiceDisplayMeta.Cursor].Toggle - } - break - - case "q": - return m, tea.Quit - } - - // Handle window resizes - case tea.WindowSizeMsg: - m.ServiceDisplayMeta.Height = msg.Height - m.ServiceDisplayMeta.Width = msg.Width - if m.ServiceDisplayMeta.Ready { - for i := range m.ServiceDisplayMeta.ComponentDisplayMeta { - m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Width = msg.Width - m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Height = - max(util.GetAvailableViewPortHeight(msg.Height, lipgloss.Height("text"), len(m.ServiceDisplayMeta.ComponentDisplayMeta)), 10) - } - } - case spinner.TickMsg: - spinnerUpdateCmds := m.updateSpinners(msg) - return m, tea.Batch(spinnerUpdateCmds...) - } - - // Handle keyboard and mouse events in the viewport - updateCmds = append(updateCmds, m.tickSpinners()...) - updateCmds = append(updateCmds, m.updateViewPort(msg)...) - return m, tea.Batch(updateCmds...) -} - -func (m *Model) updateViewPort(msg tea.Msg) []tea.Cmd { - var cmds []tea.Cmd - var cmd tea.Cmd - for i := range m.ServiceDisplayMeta.ComponentDisplayMeta { - m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort, cmd = - m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Update(msg) - cmds = append(cmds, cmd) - } - return cmds -} - -func (m *Model) updateSpinners(msg tea.Msg) []tea.Cmd { - var cmds []tea.Cmd - var cmd tea.Cmd - for i := range m.ServiceDisplayMeta.ComponentDisplayMeta { - m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner, cmd = - m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Update(msg) - cmds = append(cmds, cmd) - } - return cmds -} - -func (m *Model) tickSpinners() []tea.Cmd { - var cmds []tea.Cmd - for i := range m.ServiceDisplayMeta.ComponentDisplayMeta { - cmds = append(cmds, m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Tick) - } - return cmds -} - -func (m *Model) View() string { - if !m.ServiceDisplayMeta.Ready { - return ui.H1Style.Render("Initializing service deployment...") - } - var builder strings.Builder - - // Build Service View - serviceHeader := util.GetHeaderText(m.ServiceView.Name, m.ServiceView.Action, m.ServiceView.Status, "Service") - builder.WriteString(fmt.Sprintf("%s\n", ui.H1Style.Render(serviceHeader))) - m.ServiceDisplayMeta.Progress.Width = lipgloss.Width(serviceHeader) + 6 // to accommodate the percentage text - builder.WriteString(fmt.Sprintf("%s\n", m.ServiceDisplayMeta.Progress.ViewAs(100.0))) - builder.WriteString(fmt.Sprintf("Trace Id: %s\n", ui.TextStyle.Render(m.ServiceView.TraceId))) - - for i, componentView := range m.ServiceView.ComponentsView { - componentHeader := util.GetHeaderText(componentView.Name, componentView.Action, componentView.Status, "Component") - var componentHeaderText string - if i == m.ServiceDisplayMeta.Cursor { - componentHeaderText = ui.SelectedStyle(ui.H2Style).Render(componentHeader) - } else { - componentHeaderText = ui.H2Style.Render(componentHeader) - } - if m.ServiceView.ComponentsView[i].Status != "IN_PROGRESS" { - m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Spinner = spinner.Pulse - } - builder.WriteString(fmt.Sprintf("%s %s\n", componentHeaderText, m.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.View())) - if m.ServiceDisplayMeta.ComponentDisplayMeta[i].Toggle { - // Render logs - logsText := strings.Split(componentView.Content, "\\n") - m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.SetContent(ui.InfoStyle.Render(strings.Join(logsText, "\n"))) - builder.WriteString(fmt.Sprintf("%s \n", m.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.View())) + if (serviceName == "" && serviceVersion == "" && labels == "") && (definitionFile != "" && provisioningFile != "") { + deployUsingFiles(ctx) + } else if (serviceName != "" && serviceVersion != "" && labels == "") && (definitionFile == "" && provisioningFile == "") { + deployUsingServiceNameAndVersion(ctx) + } else if (serviceName != "" && labels != "" && serviceVersion == "") && (definitionFile == "" && provisioningFile == "") { + if err := validateLabels(labels); err != nil { + log.Fatal("Invalid labels format: ", err) } + deployUsingServiceNameAndLabels(ctx) + } else { + log.Fatal("Invalid combination of flags. Use either (service name and version) or (service name and labels) or (definitionFile and provisioningFile).") } - - // Add Footer with operating instructions - builder.WriteString("\n\n") - builder.WriteString(ui.FooterStyle.Render("Use ↑ and ↓ to navigate components, Enter to toggle logs, q to quit")) - - return builder.String() } -func deployUsingFiles(ctx context.Context, program *tea.Program) { +func deployUsingFiles(ctx context.Context) { definitionData, err := os.ReadFile(definitionFile) if err != nil { log.Fatal("Error while reading definition file ", err) @@ -264,7 +85,7 @@ func deployUsingFiles(ctx context.Context, program *tea.Program) { ComponentProvisioningConfig: compProvConfigs, } - stream, err := serviceClient.DeployService(&ctx, &serviceProto.DeployServiceRequest{ + err = serviceClient.DeployService(&ctx, &serviceProto.DeployServiceRequest{ EnvName: env, ServiceDefinition: &definitionProto, ProvisioningConfig: provisioningProto, @@ -273,16 +94,6 @@ func deployUsingFiles(ctx context.Context, program *tea.Program) { if err != nil { log.Fatal("Failed to deploy service ", err) } - for { - response, err := stream.Recv() - if err != nil { - if errors.Is(err, context.Canceled) || err == io.EOF { - break - } - program.Quit() - } - program.Send(GetServiceDeployModel(response)) - } } func deployUsingServiceNameAndVersion(ctx context.Context) { diff --git a/cmd/deploy/view.go b/cmd/deploy/view.go deleted file mode 100644 index 797e57f8..00000000 --- a/cmd/deploy/view.go +++ /dev/null @@ -1,33 +0,0 @@ -package deploy - -import ( - v1 "github.com/dream11/odin/proto/gen/go/dream11/od/service/v1" -) - -func GetServiceDeployModel(response *v1.DeployServiceResponse) Model { - serviceName := response.GetServiceResponse().Name - - serviceView := ServiceView{ - Name: serviceName, - Action: response.GetServiceResponse().ServiceStatus.GetServiceAction(), - Status: response.GetServiceResponse().ServiceStatus.GetServiceStatus(), - TraceId: "random-trace-id", - ComponentsView: make([]ComponentView, 0), - } - for _, component := range response.GetServiceResponse().GetComponentsStatus() { - errorMessage := "Awaiting component logs" - if component.GetError() != "" { - errorMessage = component.GetError() - } - componentView := ComponentView{ - Name: component.GetComponentName(), - Action: component.GetComponentAction(), - Status: component.GetComponentStatus(), - Content: errorMessage, - } - serviceView.ComponentsView = append(serviceView.ComponentsView, componentView) - } - return Model{ - ServiceView: serviceView, - } -} diff --git a/internal/service/service.go b/internal/service/service.go index c7d9de5a..158f38a5 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -5,7 +5,10 @@ import ( "context" "errors" "fmt" + tea "github.com/charmbracelet/bubbletea" + "github.com/dream11/odin/internal/ui" "io" + "os" "github.com/briandowns/spinner" "github.com/dream11/odin/pkg/constant" @@ -21,14 +24,47 @@ type Service struct{} var responseMap = make(map[string]string) +var program = tea.NewProgram( + &ui.ServiceDeployModel{ + ServiceView: ui.ServiceView{ + Name: "Initiating service deployment", + }, + }, + tea.WithAltScreen(), +) + // DeployService deploys service -func (e *Service) DeployService(ctx *context.Context, request *serviceProto.DeployServiceRequest) (serviceProto.ServiceService_DeployServiceClient, error) { +func (e *Service) DeployService(ctx *context.Context, request *serviceProto.DeployServiceRequest) error { conn, requestCtx, err := grpcClient(ctx) if err != nil { - return nil, err + return err } client := serviceProto.NewServiceServiceClient(conn) - return client.DeployService(*requestCtx, request) + stream, err := client.DeployService(*requestCtx, request) + if err != nil { + return err + } + + go func() { + for { + response, err := stream.Recv() + if err != nil { + if errors.Is(err, context.Canceled) || err == io.EOF { + break + } + log.Errorf("TraceID: %s", (*requestCtx).Value(constant.TraceIDKey)) + program.Quit() + } + if response != nil { + program.Send(ui.GetServiceDeployModel(response)) + } + } + }() + + if _, err := program.Run(); err != nil { + os.Exit(1) + } + return err } func logFailedComponentMessagesOnce(response *serviceProto.ServiceResponse) { diff --git a/internal/ui/deploy.go b/internal/ui/deploy.go new file mode 100644 index 00000000..58511004 --- /dev/null +++ b/internal/ui/deploy.go @@ -0,0 +1,166 @@ +package ui + +import ( + "fmt" + "github.com/charmbracelet/bubbles/progress" + "github.com/charmbracelet/bubbles/spinner" + "github.com/charmbracelet/bubbles/viewport" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/dream11/odin/pkg/util" + "strings" +) + +func (s *ServiceDeployModel) Init() tea.Cmd { + s.ServiceDisplayMeta.Progress = progress.New(progress.WithDefaultScaledGradient()) + s.ServiceDisplayMeta.Progress.PercentageStyle = ProgressBarStyle + s.ServiceDisplayMeta.Progress.SetPercent(100) + s.ServiceDisplayMeta.Cursor = 0 + return nil +} + +func (s *ServiceDeployModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var updateCmds []tea.Cmd + switch msg := msg.(type) { + // Handle updates + case ServiceDeployModel: + s.ServiceDisplayMeta.Ready = true + s.ServiceView = msg.ServiceView + if len(s.ServiceView.ComponentsView) > len(s.ServiceDisplayMeta.ComponentDisplayMeta) { + for i := len(s.ServiceDisplayMeta.ComponentDisplayMeta); i < len(s.ServiceView.ComponentsView); i++ { + s.ServiceDisplayMeta.ComponentDisplayMeta = append(s.ServiceDisplayMeta.ComponentDisplayMeta, ComponentDisplayMeta{ + LogViewPort: viewport.Model{ + Width: s.ServiceDisplayMeta.Width, + Height: 10, + }, + }) + s.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner = spinner.New() + s.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Style = SpinnerStyle + s.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Spinner = spinner.Points + } + } + // Handle key presses + case tea.KeyMsg: + anyToggled := false + for _, component := range s.ServiceDisplayMeta.ComponentDisplayMeta { + if component.Toggle { + anyToggled = true + break + } + } + switch msg.String() { + case "up": + if s.ServiceDisplayMeta.Cursor > 0 && !anyToggled { + s.ServiceDisplayMeta.Cursor-- + } + break + + case "down": + if s.ServiceDisplayMeta.Cursor < len(s.ServiceDisplayMeta.ComponentDisplayMeta)-1 && !anyToggled { + s.ServiceDisplayMeta.Cursor++ + } + break + + case "enter", " ": + if s.ServiceDisplayMeta.Cursor < len(s.ServiceDisplayMeta.ComponentDisplayMeta) { + s.ServiceDisplayMeta.ComponentDisplayMeta[s.ServiceDisplayMeta.Cursor].Toggle = + !s.ServiceDisplayMeta.ComponentDisplayMeta[s.ServiceDisplayMeta.Cursor].Toggle + } + break + + case "q": + return s, tea.Quit + } + + // Handle window resizes + case tea.WindowSizeMsg: + s.ServiceDisplayMeta.Height = msg.Height + s.ServiceDisplayMeta.Width = msg.Width + if s.ServiceDisplayMeta.Ready { + for i := range s.ServiceDisplayMeta.ComponentDisplayMeta { + s.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Width = msg.Width + s.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Height = + max(util.GetAvailableViewPortHeight(msg.Height, lipgloss.Height("text"), len(s.ServiceDisplayMeta.ComponentDisplayMeta)), 10) + } + } + case spinner.TickMsg: + spinnerUpdateCmds := s.updateSpinners(msg) + return s, tea.Batch(spinnerUpdateCmds...) + } + + // Handle keyboard and mouse events in the viewport + updateCmds = append(updateCmds, s.tickSpinners()...) + updateCmds = append(updateCmds, s.updateViewPort(msg)...) + + return s, tea.Batch(updateCmds...) +} + +func (s *ServiceDeployModel) View() string { + if !s.ServiceDisplayMeta.Ready { + return H1Style.Render("Initializing service deployment...") + } + var builder strings.Builder + + // Build Service View + serviceHeader := util.GetHeaderText(s.ServiceView.Name, s.ServiceView.Action, s.ServiceView.Status, "Service") + builder.WriteString(fmt.Sprintf("%s\n", H1Style.Render(serviceHeader))) + s.ServiceDisplayMeta.Progress.Width = lipgloss.Width(serviceHeader) + 6 // to accommodate the percentage text + builder.WriteString(fmt.Sprintf("%s\n", s.ServiceDisplayMeta.Progress.ViewAs(100.0))) + builder.WriteString(fmt.Sprintf("Trace Id: %s\n", TextStyle.Render(s.ServiceView.TraceId))) + + for i, componentView := range s.ServiceView.ComponentsView { + componentHeader := util.GetHeaderText(componentView.Name, componentView.Action, componentView.Status, "Component") + var componentHeaderText string + if i == s.ServiceDisplayMeta.Cursor { + componentHeaderText = SelectedStyle(H2Style).Render(componentHeader) + } else { + componentHeaderText = H2Style.Render(componentHeader) + } + if s.ServiceView.ComponentsView[i].Status != "IN_PROGRESS" { + s.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Spinner = spinner.Pulse + } + builder.WriteString(fmt.Sprintf("%s %s\n", componentHeaderText, s.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.View())) + if s.ServiceDisplayMeta.ComponentDisplayMeta[i].Toggle { + // Render logs + logsText := strings.Split(componentView.Content, "\\n") + s.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.SetContent(InfoStyle.Render(strings.Join(logsText, "\n"))) + builder.WriteString(fmt.Sprintf("%s \n", s.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.View())) + } + } + + // Add Footer with operating instructions + builder.WriteString("\n\n") + builder.WriteString(FooterStyle.Render("Use ↑ and ↓ to navigate components, Enter to toggle logs, q to quit")) + + return builder.String() +} + +func (s *ServiceDeployModel) updateViewPort(msg tea.Msg) []tea.Cmd { + var cmds []tea.Cmd + var cmd tea.Cmd + for i := range s.ServiceDisplayMeta.ComponentDisplayMeta { + s.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort, cmd = + s.ServiceDisplayMeta.ComponentDisplayMeta[i].LogViewPort.Update(msg) + cmds = append(cmds, cmd) + } + return cmds +} + +func (s *ServiceDeployModel) updateSpinners(msg tea.Msg) []tea.Cmd { + var cmds []tea.Cmd + var cmd tea.Cmd + for i := range s.ServiceDisplayMeta.ComponentDisplayMeta { + s.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner, cmd = + s.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Update(msg) + cmds = append(cmds, cmd) + } + return cmds +} + +func (s *ServiceDeployModel) tickSpinners() []tea.Cmd { + var cmds []tea.Cmd + for i := range s.ServiceDisplayMeta.ComponentDisplayMeta { + cmds = append(cmds, s.ServiceDisplayMeta.ComponentDisplayMeta[i].Spinner.Tick) + } + return cmds +} diff --git a/internal/ui/deploymodel.go b/internal/ui/deploymodel.go new file mode 100644 index 00000000..b1efbaf2 --- /dev/null +++ b/internal/ui/deploymodel.go @@ -0,0 +1,75 @@ +package ui + +import ( + "github.com/charmbracelet/bubbles/progress" + "github.com/charmbracelet/bubbles/spinner" + "github.com/charmbracelet/bubbles/viewport" + v1 "github.com/dream11/odin/proto/gen/go/dream11/od/service/v1" +) + +type ServiceDeployModel struct { + ServiceDisplayMeta ServiceDisplayMeta + ServiceView ServiceView +} + +type ServiceDisplayMeta struct { + Height int + Width int + Ready bool + Cursor int + ElapsedTime int + TotalCompletionTime int + Progress progress.Model + ComponentDisplayMeta []ComponentDisplayMeta +} + +type ComponentDisplayMeta struct { + Height int + Width int + Toggle bool + Spinner spinner.Model + LogViewPort viewport.Model +} + +type ServiceView struct { + Name string + Status string + Action string + TraceId string + ComponentsView []ComponentView +} + +type ComponentView struct { + Name string + Status string + Action string + Content string +} + +func GetServiceDeployModel(response *v1.DeployServiceResponse) ServiceDeployModel { + serviceName := response.GetServiceResponse().Name + + serviceView := ServiceView{ + Name: serviceName, + Action: response.GetServiceResponse().ServiceStatus.GetServiceAction(), + Status: response.GetServiceResponse().ServiceStatus.GetServiceStatus(), + TraceId: "random-trace-id", + ComponentsView: make([]ComponentView, 0), + } + for _, component := range response.GetServiceResponse().GetComponentsStatus() { + errorMessage := "Awaiting component logs" + if component.GetError() != "" { + errorMessage = component.GetError() + } + componentView := ComponentView{ + Name: component.GetComponentName(), + Action: component.GetComponentAction(), + Status: component.GetComponentStatus(), + Content: errorMessage, + } + serviceView.ComponentsView = append(serviceView.ComponentsView, componentView) + } + return ServiceDeployModel{ + ServiceView: serviceView, + } +} diff --git a/pkg/ui/styles.go b/internal/ui/styles.go similarity index 100% rename from pkg/ui/styles.go rename to internal/ui/styles.go diff --git a/proto/gen/go/dream11/oam/dto/v1/provider_account.pb.go b/proto/gen/go/dream11/oam/dto/v1/provider_account.pb.go index 5c2052c2..e62b689d 100644 --- a/proto/gen/go/dream11/oam/dto/v1/provider_account.pb.go +++ b/proto/gen/go/dream11/oam/dto/v1/provider_account.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/oam/dto/v1/provider_account.proto package v1 diff --git a/proto/gen/go/dream11/oam/provideraccount/v1/provider_account.pb.go b/proto/gen/go/dream11/oam/provideraccount/v1/provider_account.pb.go index ad377710..0e92fef9 100644 --- a/proto/gen/go/dream11/oam/provideraccount/v1/provider_account.pb.go +++ b/proto/gen/go/dream11/oam/provideraccount/v1/provider_account.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/oam/provideraccount/v1/provider_account.proto package v1 diff --git a/proto/gen/go/dream11/oam/provideraccount/v1/provider_account_grpc.pb.go b/proto/gen/go/dream11/oam/provideraccount/v1/provider_account_grpc.pb.go index 058d5d5c..66fa33eb 100644 --- a/proto/gen/go/dream11/oam/provideraccount/v1/provider_account_grpc.pb.go +++ b/proto/gen/go/dream11/oam/provideraccount/v1/provider_account_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.26.1 +// - protoc v5.29.3 // source: dream11/oam/provideraccount/v1/provider_account.proto package v1 diff --git a/proto/gen/go/dream11/od/auth/v1/auth.pb.go b/proto/gen/go/dream11/od/auth/v1/auth.pb.go index 81dba86b..c00c872d 100644 --- a/proto/gen/go/dream11/od/auth/v1/auth.pb.go +++ b/proto/gen/go/dream11/od/auth/v1/auth.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/auth/v1/auth.proto package v1 diff --git a/proto/gen/go/dream11/od/auth/v1/auth_grpc.pb.go b/proto/gen/go/dream11/od/auth/v1/auth_grpc.pb.go index dce36b78..85bc99fd 100644 --- a/proto/gen/go/dream11/od/auth/v1/auth_grpc.pb.go +++ b/proto/gen/go/dream11/od/auth/v1/auth_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.26.1 +// - protoc v5.29.3 // source: dream11/od/auth/v1/auth.proto package v1 diff --git a/proto/gen/go/dream11/od/component/v1/component.pb.go b/proto/gen/go/dream11/od/component/v1/component.pb.go index dc0b79b1..7c566b81 100644 --- a/proto/gen/go/dream11/od/component/v1/component.pb.go +++ b/proto/gen/go/dream11/od/component/v1/component.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/component/v1/component.proto package v1 diff --git a/proto/gen/go/dream11/od/component/v1/component_grpc.pb.go b/proto/gen/go/dream11/od/component/v1/component_grpc.pb.go index 5989ad67..da28f65f 100644 --- a/proto/gen/go/dream11/od/component/v1/component_grpc.pb.go +++ b/proto/gen/go/dream11/od/component/v1/component_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.26.1 +// - protoc v5.29.3 // source: dream11/od/component/v1/component.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/component.pb.go b/proto/gen/go/dream11/od/dto/v1/component.pb.go index 6b17f5c4..21e614ab 100644 --- a/proto/gen/go/dream11/od/dto/v1/component.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/component.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/dto/v1/component.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/component_task.pb.go b/proto/gen/go/dream11/od/dto/v1/component_task.pb.go index 41778f2d..053445e0 100644 --- a/proto/gen/go/dream11/od/dto/v1/component_task.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/component_task.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/dto/v1/component_task.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/environment.pb.go b/proto/gen/go/dream11/od/dto/v1/environment.pb.go index fa67eb85..d8e0d070 100644 --- a/proto/gen/go/dream11/od/dto/v1/environment.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/environment.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/dto/v1/environment.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/provisioning_type.pb.go b/proto/gen/go/dream11/od/dto/v1/provisioning_type.pb.go index 4f70b6ae..51ae9600 100644 --- a/proto/gen/go/dream11/od/dto/v1/provisioning_type.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/provisioning_type.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/dto/v1/provisioning_type.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/service.pb.go b/proto/gen/go/dream11/od/dto/v1/service.pb.go index 7344ef6a..ea012c09 100644 --- a/proto/gen/go/dream11/od/dto/v1/service.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/service.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/dto/v1/service.proto package v1 diff --git a/proto/gen/go/dream11/od/dto/v1/service_task.pb.go b/proto/gen/go/dream11/od/dto/v1/service_task.pb.go index 5576de04..513c5c38 100644 --- a/proto/gen/go/dream11/od/dto/v1/service_task.pb.go +++ b/proto/gen/go/dream11/od/dto/v1/service_task.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/dto/v1/service_task.proto package v1 diff --git a/proto/gen/go/dream11/od/environment/v1/environment.pb.go b/proto/gen/go/dream11/od/environment/v1/environment.pb.go index 45839571..c0e13e7f 100644 --- a/proto/gen/go/dream11/od/environment/v1/environment.pb.go +++ b/proto/gen/go/dream11/od/environment/v1/environment.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/environment/v1/environment.proto package v1 diff --git a/proto/gen/go/dream11/od/environment/v1/environment_grpc.pb.go b/proto/gen/go/dream11/od/environment/v1/environment_grpc.pb.go index e5f7e77d..88e64bcd 100644 --- a/proto/gen/go/dream11/od/environment/v1/environment_grpc.pb.go +++ b/proto/gen/go/dream11/od/environment/v1/environment_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.26.1 +// - protoc v5.29.3 // source: dream11/od/environment/v1/environment.proto package v1 diff --git a/proto/gen/go/dream11/od/service/v1/service.pb.go b/proto/gen/go/dream11/od/service/v1/service.pb.go index 505509b2..41801a01 100644 --- a/proto/gen/go/dream11/od/service/v1/service.pb.go +++ b/proto/gen/go/dream11/od/service/v1/service.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.1 -// protoc v5.26.1 +// protoc v5.29.3 // source: dream11/od/service/v1/service.proto package v1 diff --git a/proto/gen/go/dream11/od/service/v1/service_grpc.pb.go b/proto/gen/go/dream11/od/service/v1/service_grpc.pb.go index daab0198..c80cb4cc 100644 --- a/proto/gen/go/dream11/od/service/v1/service_grpc.pb.go +++ b/proto/gen/go/dream11/od/service/v1/service_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v5.26.1 +// - protoc v5.29.3 // source: dream11/od/service/v1/service.proto package v1 From 89470d8ed4fddb37f84b0e4905eacafc722e3c58 Mon Sep 17 00:00:00 2001 From: surajgour-d11 Date: Tue, 4 Feb 2025 13:14:41 +0530 Subject: [PATCH 8/8] fix: add traceId Signed-off-by: surajgour-d11 --- internal/service/service.go | 2 +- internal/ui/deploy.go | 5 +---- internal/ui/deploymodel.go | 6 +++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/internal/service/service.go b/internal/service/service.go index 158f38a5..892cd30a 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -56,7 +56,7 @@ func (e *Service) DeployService(ctx *context.Context, request *serviceProto.Depl program.Quit() } if response != nil { - program.Send(ui.GetServiceDeployModel(response)) + program.Send(ui.GetServiceDeployModel(response, (*requestCtx).Value(constant.TraceIDKey).(string))) } } }() diff --git a/internal/ui/deploy.go b/internal/ui/deploy.go index 58511004..adce5fc3 100644 --- a/internal/ui/deploy.go +++ b/internal/ui/deploy.go @@ -53,20 +53,17 @@ func (s *ServiceDeployModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if s.ServiceDisplayMeta.Cursor > 0 && !anyToggled { s.ServiceDisplayMeta.Cursor-- } - break case "down": if s.ServiceDisplayMeta.Cursor < len(s.ServiceDisplayMeta.ComponentDisplayMeta)-1 && !anyToggled { s.ServiceDisplayMeta.Cursor++ } - break case "enter", " ": if s.ServiceDisplayMeta.Cursor < len(s.ServiceDisplayMeta.ComponentDisplayMeta) { s.ServiceDisplayMeta.ComponentDisplayMeta[s.ServiceDisplayMeta.Cursor].Toggle = !s.ServiceDisplayMeta.ComponentDisplayMeta[s.ServiceDisplayMeta.Cursor].Toggle } - break case "q": return s, tea.Quit @@ -106,7 +103,7 @@ func (s *ServiceDeployModel) View() string { builder.WriteString(fmt.Sprintf("%s\n", H1Style.Render(serviceHeader))) s.ServiceDisplayMeta.Progress.Width = lipgloss.Width(serviceHeader) + 6 // to accommodate the percentage text builder.WriteString(fmt.Sprintf("%s\n", s.ServiceDisplayMeta.Progress.ViewAs(100.0))) - builder.WriteString(fmt.Sprintf("Trace Id: %s\n", TextStyle.Render(s.ServiceView.TraceId))) + builder.WriteString(fmt.Sprintf("Trace Id: %s\n", TextStyle.Render(s.ServiceView.TraceID))) for i, componentView := range s.ServiceView.ComponentsView { componentHeader := util.GetHeaderText(componentView.Name, componentView.Action, componentView.Status, "Component") diff --git a/internal/ui/deploymodel.go b/internal/ui/deploymodel.go index b1efbaf2..d191f8a1 100644 --- a/internal/ui/deploymodel.go +++ b/internal/ui/deploymodel.go @@ -35,7 +35,7 @@ type ServiceView struct { Name string Status string Action string - TraceId string + TraceID string ComponentsView []ComponentView } @@ -46,14 +46,14 @@ type ComponentView struct { Content string } -func GetServiceDeployModel(response *v1.DeployServiceResponse) ServiceDeployModel { +func GetServiceDeployModel(response *v1.DeployServiceResponse, traceID string) ServiceDeployModel { serviceName := response.GetServiceResponse().Name serviceView := ServiceView{ Name: serviceName, Action: response.GetServiceResponse().ServiceStatus.GetServiceAction(), Status: response.GetServiceResponse().ServiceStatus.GetServiceStatus(), - TraceId: "random-trace-id", + TraceID: traceID, ComponentsView: make([]ComponentView, 0), } for _, component := range response.GetServiceResponse().GetComponentsStatus() {