feat: sidebar
This commit is contained in:
parent
53da4a34cf
commit
0141c54c64
@ -11,6 +11,15 @@ import (
|
|||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type sourceViews struct {
|
||||||
|
url *tview.TextView
|
||||||
|
status *tview.TextView
|
||||||
|
health *tview.TextView
|
||||||
|
cpu *tview.TextView
|
||||||
|
mem *tview.TextView
|
||||||
|
rx *tview.TextView
|
||||||
|
}
|
||||||
|
|
||||||
// Actor is responsible for managing the terminal user interface.
|
// Actor is responsible for managing the terminal user interface.
|
||||||
type Actor struct {
|
type Actor struct {
|
||||||
app *tview.Application
|
app *tview.Application
|
||||||
@ -18,7 +27,7 @@ type Actor struct {
|
|||||||
ch chan action
|
ch chan action
|
||||||
commandCh chan Command
|
commandCh chan Command
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
sourceView *tview.Table
|
sourceViews sourceViews
|
||||||
destView *tview.Table
|
destView *tview.Table
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,12 +50,59 @@ func StartActor(ctx context.Context, params StartActorParams) (*Actor, error) {
|
|||||||
|
|
||||||
app := tview.NewApplication()
|
app := tview.NewApplication()
|
||||||
|
|
||||||
sourceView := tview.NewTable()
|
sidebar := tview.NewFlex()
|
||||||
sourceView.SetTitle("source")
|
sidebar.SetDirection(tview.FlexRow)
|
||||||
|
|
||||||
|
sourceView := tview.NewFlex()
|
||||||
|
sourceView.SetDirection(tview.FlexColumn)
|
||||||
sourceView.SetBorder(true)
|
sourceView.SetBorder(true)
|
||||||
|
sourceView.SetTitle("Ingress RTMP server")
|
||||||
|
sidebar.AddItem(sourceView, 8, 0, false)
|
||||||
|
|
||||||
|
leftCol := tview.NewFlex()
|
||||||
|
leftCol.SetDirection(tview.FlexRow)
|
||||||
|
rightCol := tview.NewFlex()
|
||||||
|
rightCol.SetDirection(tview.FlexRow)
|
||||||
|
sourceView.AddItem(leftCol, 8, 0, false)
|
||||||
|
sourceView.AddItem(rightCol, 0, 1, false)
|
||||||
|
|
||||||
|
urlHeaderTextView := tview.NewTextView().SetDynamicColors(true).SetText("[grey]" + headerURL)
|
||||||
|
leftCol.AddItem(urlHeaderTextView, 1, 0, false)
|
||||||
|
urlTextView := tview.NewTextView().SetDynamicColors(true).SetText("[white]" + dash)
|
||||||
|
rightCol.AddItem(urlTextView, 1, 0, false)
|
||||||
|
|
||||||
|
statusHeaderTextView := tview.NewTextView().SetDynamicColors(true).SetText("[grey]" + headerStatus)
|
||||||
|
leftCol.AddItem(statusHeaderTextView, 1, 0, false)
|
||||||
|
statusTextView := tview.NewTextView().SetDynamicColors(true).SetText("[white]" + dash)
|
||||||
|
rightCol.AddItem(statusTextView, 1, 0, false)
|
||||||
|
|
||||||
|
healthHeaderTextView := tview.NewTextView().SetDynamicColors(true).SetText("[grey]" + headerHealth)
|
||||||
|
leftCol.AddItem(healthHeaderTextView, 1, 0, false)
|
||||||
|
healthTextView := tview.NewTextView().SetDynamicColors(true).SetText("[white]" + dash)
|
||||||
|
rightCol.AddItem(healthTextView, 1, 0, false)
|
||||||
|
|
||||||
|
cpuHeaderTextView := tview.NewTextView().SetDynamicColors(true).SetText("[grey]" + headerCPU)
|
||||||
|
leftCol.AddItem(cpuHeaderTextView, 1, 0, false)
|
||||||
|
cpuTextView := tview.NewTextView().SetDynamicColors(true).SetText("[white]" + dash)
|
||||||
|
rightCol.AddItem(cpuTextView, 1, 0, false)
|
||||||
|
|
||||||
|
memHeaderTextView := tview.NewTextView().SetDynamicColors(true).SetText("[grey]" + headerMem)
|
||||||
|
leftCol.AddItem(memHeaderTextView, 1, 0, false)
|
||||||
|
memTextView := tview.NewTextView().SetDynamicColors(true).SetText("[white]" + dash)
|
||||||
|
rightCol.AddItem(memTextView, 1, 0, false)
|
||||||
|
|
||||||
|
rxHeaderTextView := tview.NewTextView().SetDynamicColors(true).SetText("[grey]" + headerRx)
|
||||||
|
leftCol.AddItem(rxHeaderTextView, 1, 0, false)
|
||||||
|
rxTextView := tview.NewTextView().SetDynamicColors(true).SetText("[white]" + dash)
|
||||||
|
rightCol.AddItem(rxTextView, 1, 0, false)
|
||||||
|
|
||||||
|
aboutView := tview.NewBox()
|
||||||
|
aboutView.SetBorder(true)
|
||||||
|
aboutView.SetTitle("Actions")
|
||||||
|
sidebar.AddItem(aboutView, 0, 1, false)
|
||||||
|
|
||||||
destView := tview.NewTable()
|
destView := tview.NewTable()
|
||||||
destView.SetTitle("destinations")
|
destView.SetTitle("Egress streams")
|
||||||
destView.SetBorder(true)
|
destView.SetBorder(true)
|
||||||
destView.SetSelectable(true, false)
|
destView.SetSelectable(true, false)
|
||||||
destView.SetWrapSelection(true, false)
|
destView.SetWrapSelection(true, false)
|
||||||
@ -64,8 +120,8 @@ func StartActor(ctx context.Context, params StartActorParams) (*Actor, error) {
|
|||||||
|
|
||||||
flex := tview.NewFlex().
|
flex := tview.NewFlex().
|
||||||
SetDirection(tview.FlexColumn).
|
SetDirection(tview.FlexColumn).
|
||||||
AddItem(sourceView, 0, 1, false).
|
AddItem(sidebar, 40, 0, false).
|
||||||
AddItem(destView, 0, 1, false)
|
AddItem(destView, 0, 6, false)
|
||||||
|
|
||||||
pages := tview.NewPages()
|
pages := tview.NewPages()
|
||||||
pages.AddPage("main", flex, true, true)
|
pages.AddPage("main", flex, true, true)
|
||||||
@ -80,7 +136,14 @@ func StartActor(ctx context.Context, params StartActorParams) (*Actor, error) {
|
|||||||
logger: params.Logger,
|
logger: params.Logger,
|
||||||
app: app,
|
app: app,
|
||||||
pages: pages,
|
pages: pages,
|
||||||
sourceView: sourceView,
|
sourceViews: sourceViews{
|
||||||
|
url: urlTextView,
|
||||||
|
status: statusTextView,
|
||||||
|
health: healthTextView,
|
||||||
|
cpu: cpuTextView,
|
||||||
|
mem: memTextView,
|
||||||
|
rx: rxTextView,
|
||||||
|
},
|
||||||
destView: destView,
|
destView: destView,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,31 +255,34 @@ func (a *Actor) redrawFromState(state domain.AppState) {
|
|||||||
SetSelectable(false)
|
SetSelectable(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
a.sourceView.Clear()
|
a.sourceViews.url.SetText(state.Source.RTMPURL)
|
||||||
a.sourceView.SetCell(0, 0, headerCell("[grey]"+headerName, 3))
|
|
||||||
a.sourceView.SetCell(0, 1, headerCell("[grey]"+headerURL, 3))
|
|
||||||
a.sourceView.SetCell(0, 2, headerCell("[grey]"+headerStatus, 2))
|
|
||||||
a.sourceView.SetCell(0, 3, headerCell("[grey]"+headerContainer, 2))
|
|
||||||
a.sourceView.SetCell(0, 4, headerCell("[grey]"+headerHealth, 2))
|
|
||||||
a.sourceView.SetCell(0, 5, headerCell("[grey]"+headerCPU, 1))
|
|
||||||
a.sourceView.SetCell(0, 6, headerCell("[grey]"+headerMem, 1))
|
|
||||||
a.sourceView.SetCell(0, 7, headerCell("[grey]"+headerRx, 1))
|
|
||||||
|
|
||||||
a.sourceView.SetCell(1, 0, tview.NewTableCell("Local server"))
|
|
||||||
a.sourceView.SetCell(1, 1, tview.NewTableCell(state.Source.RTMPURL))
|
|
||||||
|
|
||||||
if state.Source.Live {
|
if state.Source.Live {
|
||||||
a.sourceView.SetCell(1, 2, tview.NewTableCell("[black:green]receiving"))
|
a.sourceViews.status.SetText("[black:green]receiving")
|
||||||
} else if state.Source.Container.State == "running" && state.Source.Container.HealthState == "healthy" {
|
} else if state.Source.Container.State == "running" && state.Source.Container.HealthState == "healthy" {
|
||||||
a.sourceView.SetCell(1, 2, tview.NewTableCell("[black:yellow]ready"))
|
a.sourceViews.status.SetText("[black:yellow]ready")
|
||||||
} else {
|
} else {
|
||||||
a.sourceView.SetCell(1, 2, tview.NewTableCell("[white:red]not ready"))
|
a.sourceViews.status.SetText("[white:red]not ready")
|
||||||
}
|
}
|
||||||
a.sourceView.SetCell(1, 3, tview.NewTableCell("[white]"+state.Source.Container.State))
|
|
||||||
a.sourceView.SetCell(1, 4, tview.NewTableCell("[white]"+cmp.Or(state.Source.Container.HealthState, "starting")))
|
a.sourceViews.health.SetText("[white]" + cmp.Or(state.Source.Container.HealthState, dash))
|
||||||
a.sourceView.SetCell(1, 5, tview.NewTableCell("[white]"+fmt.Sprintf("%.1f", state.Source.Container.CPUPercent)))
|
|
||||||
a.sourceView.SetCell(1, 6, tview.NewTableCell("[white]"+fmt.Sprintf("%.1f", float64(state.Source.Container.MemoryUsageBytes)/1024/1024)))
|
cpuPercent := dash
|
||||||
a.sourceView.SetCell(1, 7, tview.NewTableCell("[white]"+fmt.Sprintf("%d", state.Source.Container.RxRate)))
|
if state.Source.Container.State == "running" {
|
||||||
|
cpuPercent = fmt.Sprintf("%.1f", state.Source.Container.CPUPercent)
|
||||||
|
}
|
||||||
|
a.sourceViews.cpu.SetText("[white]" + cpuPercent)
|
||||||
|
|
||||||
|
memUsage := dash
|
||||||
|
if state.Source.Container.State == "running" {
|
||||||
|
memUsage = fmt.Sprintf("%.1f", float64(state.Source.Container.MemoryUsageBytes)/1024/1024)
|
||||||
|
}
|
||||||
|
a.sourceViews.mem.SetText("[white]" + memUsage)
|
||||||
|
|
||||||
|
rxRate := dash
|
||||||
|
if state.Source.Container.State == "running" {
|
||||||
|
rxRate = fmt.Sprintf("%d", state.Source.Container.RxRate)
|
||||||
|
}
|
||||||
|
a.sourceViews.rx.SetText("[white]" + rxRate)
|
||||||
|
|
||||||
a.destView.Clear()
|
a.destView.Clear()
|
||||||
a.destView.SetCell(0, 0, headerCell("[grey]"+headerName, 3))
|
a.destView.SetCell(0, 0, headerCell("[grey]"+headerName, 3))
|
||||||
@ -230,7 +296,7 @@ func (a *Actor) redrawFromState(state domain.AppState) {
|
|||||||
|
|
||||||
for i, dest := range state.Destinations {
|
for i, dest := range state.Destinations {
|
||||||
a.destView.SetCell(i+1, 0, tview.NewTableCell(dest.Name))
|
a.destView.SetCell(i+1, 0, tview.NewTableCell(dest.Name))
|
||||||
a.destView.SetCell(i+1, 1, tview.NewTableCell(truncate(dest.URL, 50)).SetReference(dest.URL))
|
a.destView.SetCell(i+1, 1, tview.NewTableCell(dest.URL).SetReference(dest.URL).SetMaxWidth(20))
|
||||||
switch dest.Status {
|
switch dest.Status {
|
||||||
case domain.DestinationStatusLive:
|
case domain.DestinationStatusLive:
|
||||||
a.destView.SetCell(
|
a.destView.SetCell(
|
||||||
@ -293,10 +359,3 @@ func (a *Actor) redrawFromState(state domain.AppState) {
|
|||||||
func (a *Actor) Close() {
|
func (a *Actor) Close() {
|
||||||
a.app.Stop()
|
a.app.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func truncate(s string, max int) string {
|
|
||||||
if len(s) <= max {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return s[:max] + "…"
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user