ui.go (125 lines of code) (raw):

// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "fmt" "os" "strconv" "github.com/GoogleCloudPlatform/autopilot-cost-calculator/cluster" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) var ( baseStyle = lipgloss.NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderForeground(lipgloss.Color("240")) pinkTextStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("225")).Background(lipgloss.Color("128")) blueTextStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("225")).Background(lipgloss.Color("32")) redTextStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("225")).Background(lipgloss.Color("160")) greenTextStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("25")).Background(lipgloss.Color("192")) ) type tableModel struct { table table.Model } func (m tableModel) Init() tea.Cmd { return nil } func (m tableModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Quit right away after drawing return m, tea.Quit } func (m tableModel) View() string { return baseStyle.Render(m.table.View()) + "\n" } func DisplayNodeTable(nodes map[string]cluster.Node) { columns := []table.Column{ {Title: "Name", Width: 55}, {Title: "Type", Width: 15}, {Title: "Region", Width: 20}, {Title: "Accelerator", Width: 25}, {Title: "Spot?", Width: 10}, } var rows []table.Row for _, node := range nodes { rows = append(rows, table.Row{node.Name, node.InstanceType, node.Region, node.Accelerator, strconv.FormatBool(node.Spot)}) } tbl := table.New( table.WithColumns(columns), table.WithRows(rows), table.WithFocused(false), table.WithHeight(len(rows)), ) stl := table.DefaultStyles() stl.Header = stl.Header. BorderStyle(lipgloss.NormalBorder()). BorderForeground(lipgloss.Color("255")). BorderBottom(true). Bold(false) stl.Selected = stl.Selected. Foreground(lipgloss.Color("255")). // Background(lipgloss.Color("57")). Bold(false) tbl.SetStyles(stl) program := tea.NewProgram(tableModel{tbl}) _, err := program.Run() if err != nil { fmt.Printf("Error: %v\n", err) os.Exit(1) } } func DisplayWorkloadTable(nodes map[string]cluster.Node, oneYearDiscount float64, threeYearDiscount float64, clusterFee float64) { columns := []table.Column{ {Title: "Node", Width: 55}, {Title: "Workload", Width: 40}, {Title: "Containers", Width: 10}, {Title: "Spot", Width: 10}, {Title: "mCPU", Width: 10}, {Title: "Memory MiB", Width: 10}, {Title: "Storage MiB", Width: 12}, {Title: "Compute Class", Width: 13}, {Title: "Price $/H", Width: 10}, } var rows []table.Row totalCost := 0.0 // Cluster fee is fixed amount totalCostSpot := 0.0 for _, node := range nodes { for _, workload := range node.Workloads { // Nodes on spot don't amount for 1 or 3 year commit discounts if node.Spot { totalCostSpot += workload.Cost } else { totalCost += workload.Cost } rows = append(rows, table.Row{ node.Name, workload.Name, strconv.Itoa(workload.Containers), strconv.FormatBool(node.Spot), strconv.FormatInt(workload.Cpu, 10), strconv.FormatInt(workload.Memory, 10), strconv.FormatInt(workload.Storage, 10), cluster.ComputeClasses[workload.ComputeClass], strconv.FormatFloat(workload.Cost, 'G', 7, 64), }, ) } } rows = append(rows, table.Row{"Total cost per cluster per hour", "", "", "", "", "", "", "", strconv.FormatFloat(totalCost+clusterFee, 'G', 7, 64)}) rows = append(rows, table.Row{"... 1 year commit", "", "", "", "", "", "", "", strconv.FormatFloat((totalCostSpot+totalCost*oneYearDiscount)+clusterFee, 'G', 7, 64)}) rows = append(rows, table.Row{"... with 3 year commit", "", "", "", "", "", "", "", strconv.FormatFloat((totalCostSpot+totalCost*threeYearDiscount)+clusterFee, 'G', 7, 64)}) tbl := table.New( table.WithColumns(columns), table.WithRows(rows), table.WithFocused(false), table.WithHeight(len(rows)), ) stl := table.DefaultStyles() stl.Header = stl.Header. BorderStyle(lipgloss.NormalBorder()). BorderForeground(lipgloss.Color("255")). BorderBottom(true). Bold(false) stl.Selected = stl.Selected. Foreground(lipgloss.Color("255")). // Background(lipgloss.Color("57")). Bold(false) tbl.SetStyles(stl) program := tea.NewProgram(tableModel{tbl}) _, err := program.Run() if err != nil { fmt.Printf("Error: %v\n", err) os.Exit(1) } }