feat: implement service history view and tracking
This commit is contained in:
110
cmd/cli/main.go
110
cmd/cli/main.go
@@ -15,17 +15,28 @@ import (
|
||||
)
|
||||
|
||||
var baseStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.NormalBorder()).
|
||||
BorderStyle(lipgloss.NormalBorder()).
|
||||
BorderForeground(lipgloss.Color("240"))
|
||||
|
||||
type viewState int
|
||||
|
||||
const (
|
||||
viewList viewState = iota
|
||||
viewDetail
|
||||
)
|
||||
|
||||
type model struct {
|
||||
table table.Model
|
||||
services []models.Service
|
||||
user string
|
||||
err error
|
||||
message string
|
||||
width int
|
||||
height int
|
||||
table table.Model
|
||||
services []models.Service
|
||||
user string
|
||||
err error
|
||||
message string
|
||||
width int
|
||||
height int
|
||||
state viewState
|
||||
history []models.HistoryEntry
|
||||
historyTable table.Model
|
||||
}
|
||||
|
||||
type tickMsg time.Time
|
||||
@@ -37,6 +48,10 @@ func tick() tea.Cmd {
|
||||
}
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
// If in detail view, only tick (no auto refresh of history for now to keep it simple)
|
||||
if m.state == viewDetail {
|
||||
return tick()
|
||||
}
|
||||
return tea.Batch(fetchServices, tick())
|
||||
}
|
||||
|
||||
@@ -48,8 +63,25 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "esc", "q", "ctrl+c":
|
||||
if m.state == viewDetail {
|
||||
m.state = viewList
|
||||
m.table.Focus()
|
||||
return m, nil
|
||||
}
|
||||
return m, tea.Quit
|
||||
case "d":
|
||||
if m.state == viewList {
|
||||
selected := m.table.SelectedRow()
|
||||
if selected != nil {
|
||||
serviceName := selected[0]
|
||||
m.state = viewDetail
|
||||
return m, fetchHistoryCmd(serviceName)
|
||||
}
|
||||
}
|
||||
case "enter":
|
||||
if m.state == viewDetail {
|
||||
return m, nil
|
||||
}
|
||||
selected := m.table.SelectedRow()
|
||||
if selected == nil {
|
||||
return m, nil
|
||||
@@ -139,10 +171,29 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
m.table.SetRows(rows)
|
||||
m.message = "Refreshed"
|
||||
case []models.HistoryEntry:
|
||||
m.history = msg
|
||||
rows := []table.Row{}
|
||||
for _, h := range msg {
|
||||
rows = append(rows, table.Row{
|
||||
h.Action,
|
||||
h.User,
|
||||
h.Timestamp.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
m.historyTable.SetRows(rows)
|
||||
// Update footer logic to resize history table if needed
|
||||
m.historyTable.SetWidth(m.width - 10)
|
||||
m.historyTable.SetHeight(m.table.Height())
|
||||
case error:
|
||||
m.err = msg
|
||||
}
|
||||
m.table, cmd = m.table.Update(msg)
|
||||
|
||||
if m.state == viewList {
|
||||
m.table, cmd = m.table.Update(msg)
|
||||
} else {
|
||||
m.historyTable, cmd = m.historyTable.Update(msg)
|
||||
}
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
@@ -191,12 +242,23 @@ func (m model) View() string {
|
||||
Align(lipgloss.Center).
|
||||
Width(contentWidth)
|
||||
|
||||
var mainView string
|
||||
if m.state == viewList {
|
||||
mainView = m.table.View()
|
||||
} else {
|
||||
// History View
|
||||
mainView = lipgloss.JoinVertical(lipgloss.Left,
|
||||
"History for selected service:",
|
||||
m.historyTable.View(),
|
||||
)
|
||||
}
|
||||
|
||||
// Render Content
|
||||
content := lipgloss.JoinVertical(lipgloss.Left,
|
||||
headerStyle.Render("🛡️ ENV-GUARD v1.0"),
|
||||
infoStyle.Render(userInfo),
|
||||
m.table.View(),
|
||||
footerStyle.Render("[↑/↓] Navigate [Enter] Toggle Lock [r] Refresh [q] Quit"),
|
||||
mainView,
|
||||
footerStyle.Render("[↑/↓] Navigate [Enter] Toggle Lock [d] History [r] Refresh [q] Quit"),
|
||||
)
|
||||
|
||||
// Create Border Style locally
|
||||
@@ -221,6 +283,16 @@ func fetchServices() tea.Msg {
|
||||
return services
|
||||
}
|
||||
|
||||
func fetchHistoryCmd(serviceName string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
hist, err := api.GetHistory(serviceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return hist
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
serverURL := flag.String("server", "http://localhost:8080", "URL of the EnvGuard server")
|
||||
flag.Parse()
|
||||
@@ -257,9 +329,23 @@ func main() {
|
||||
Bold(false)
|
||||
t.SetStyles(s)
|
||||
|
||||
// History Table
|
||||
hCols := []table.Column{
|
||||
{Title: "ACTION", Width: 10},
|
||||
{Title: "USER", Width: 15},
|
||||
{Title: "TIME", Width: 20},
|
||||
}
|
||||
ht := table.New(
|
||||
table.WithColumns(hCols),
|
||||
table.WithFocused(true),
|
||||
table.WithHeight(10),
|
||||
)
|
||||
ht.SetStyles(s)
|
||||
|
||||
m := model{
|
||||
table: t,
|
||||
user: user,
|
||||
table: t,
|
||||
historyTable: ht,
|
||||
user: user,
|
||||
}
|
||||
|
||||
if _, err := tea.NewProgram(m, tea.WithAltScreen()).Run(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user