Add loading spinners for async operations
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/calmcacil/wg-admin/internal/config"
|
"github.com/calmcacil/wg-admin/internal/config"
|
||||||
|
"github.com/calmcacil/wg-admin/internal/tui/components"
|
||||||
"github.com/calmcacil/wg-admin/internal/validation"
|
"github.com/calmcacil/wg-admin/internal/validation"
|
||||||
"github.com/calmcacil/wg-admin/internal/wireguard"
|
"github.com/calmcacil/wg-admin/internal/wireguard"
|
||||||
"github.com/charmbracelet/bubbles/spinner"
|
"github.com/charmbracelet/bubbles/spinner"
|
||||||
@@ -142,6 +143,13 @@ func (s *AddScreen) Update(msg tea.Msg) (Screen, tea.Cmd) {
|
|||||||
|
|
||||||
// View renders the add screen
|
// View renders the add screen
|
||||||
func (s *AddScreen) View() string {
|
func (s *AddScreen) View() string {
|
||||||
|
// Breadcrumb: Clients > Add
|
||||||
|
breadcrumb := components.RenderBreadcrumb([]components.BreadcrumbItem{
|
||||||
|
{Label: "Clients", ID: "list"},
|
||||||
|
{Label: "Add", ID: "add"},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
if s.quitting {
|
if s.quitting {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -158,6 +166,8 @@ func (s *AddScreen) View() string {
|
|||||||
|
|
||||||
content := lipgloss.JoinVertical(
|
content := lipgloss.JoinVertical(
|
||||||
lipgloss.Left,
|
lipgloss.Left,
|
||||||
|
breadcrumb,
|
||||||
|
"",
|
||||||
addTitleStyle.Render("Add New WireGuard Client"),
|
addTitleStyle.Render("Add New WireGuard Client"),
|
||||||
s.form.View(),
|
s.form.View(),
|
||||||
addHelpStyle.Render("Press Enter to submit • Esc to cancel"),
|
addHelpStyle.Render("Press Enter to submit • Esc to cancel"),
|
||||||
|
|||||||
@@ -144,6 +144,12 @@ func (s *DetailScreen) View() string {
|
|||||||
|
|
||||||
// renderContent renders the main detail screen content
|
// renderContent renders the main detail screen content
|
||||||
func (s *DetailScreen) renderContent() string {
|
func (s *DetailScreen) renderContent() string {
|
||||||
|
// Breadcrumb: Clients > Client Name
|
||||||
|
breadcrumb := components.RenderBreadcrumb([]components.BreadcrumbItem{
|
||||||
|
{Label: "Clients", ID: "list"},
|
||||||
|
{Label: s.client.Name, ID: "detail"},
|
||||||
|
})
|
||||||
|
|
||||||
statusText := s.status
|
statusText := s.status
|
||||||
if s.status == wireguard.StatusConnected {
|
if s.status == wireguard.StatusConnected {
|
||||||
statusText = theme.StyleSuccess.Bold(true).Render("● " + s.status)
|
statusText = theme.StyleSuccess.Bold(true).Render("● " + s.status)
|
||||||
@@ -154,6 +160,8 @@ func (s *DetailScreen) renderContent() string {
|
|||||||
// Build content
|
// Build content
|
||||||
content := lipgloss.JoinVertical(
|
content := lipgloss.JoinVertical(
|
||||||
lipgloss.Left,
|
lipgloss.Left,
|
||||||
|
breadcrumb,
|
||||||
|
"",
|
||||||
theme.StyleTitle.Render(fmt.Sprintf("Client Details: %s", s.client.Name)),
|
theme.StyleTitle.Render(fmt.Sprintf("Client Details: %s", s.client.Name)),
|
||||||
"",
|
"",
|
||||||
s.renderField("Status", statusText),
|
s.renderField("Status", statusText),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package screens
|
package screens
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/calmcacil/wg-admin/internal/tui/components"
|
||||||
"github.com/charmbracelet/bubbletea"
|
"github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
)
|
)
|
||||||
@@ -37,6 +38,10 @@ func (s *HelpScreen) Update(msg tea.Msg) (Screen, tea.Cmd) {
|
|||||||
|
|
||||||
// View renders the help screen
|
// View renders the help screen
|
||||||
func (s *HelpScreen) View() string {
|
func (s *HelpScreen) View() string {
|
||||||
|
// Breadcrumb: Help
|
||||||
|
breadcrumb := components.RenderBreadcrumb([]components.BreadcrumbItem{{Label: "Help", ID: "help"}})
|
||||||
|
|
||||||
|
|
||||||
// Styles
|
// Styles
|
||||||
borderStyle := lipgloss.NewStyle().
|
borderStyle := lipgloss.NewStyle().
|
||||||
BorderStyle(lipgloss.RoundedBorder()).
|
BorderStyle(lipgloss.RoundedBorder()).
|
||||||
@@ -105,7 +110,7 @@ func (s *HelpScreen) View() string {
|
|||||||
footer := footerStyle.Render("Press q or Esc to return")
|
footer := footerStyle.Render("Press q or Esc to return")
|
||||||
|
|
||||||
// Combine all
|
// Combine all
|
||||||
return borderStyle.Render(
|
return breadcrumb + "\n\n" + borderStyle.Render(
|
||||||
lipgloss.JoinVertical(lipgloss.Left, header, content, footer),
|
lipgloss.JoinVertical(lipgloss.Left, header, content, footer),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,17 +135,7 @@ func (s *ListScreen) Update(msg tea.Msg) (Screen, tea.Cmd) {
|
|||||||
return s, cmd
|
return s, cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *ListScreen) renderBreadcrumb() string {
|
|
||||||
return components.RenderBreadcrumb([]components.BreadcrumbItem{
|
|
||||||
{Label: "Clients", ID: "list"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// View renders the list screen
|
// View renders the list screen
|
||||||
func (s *ListScreen) View() string {
|
|
||||||
breadcrumb := s.renderBreadcrumb()
|
|
||||||
|
|
||||||
func (s *ListScreen) View() string {
|
func (s *ListScreen) View() string {
|
||||||
// Breadcrumb: Home
|
// Breadcrumb: Home
|
||||||
breadcrumb := components.RenderBreadcrumb([]components.BreadcrumbItem{
|
breadcrumb := components.RenderBreadcrumb([]components.BreadcrumbItem{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/calmcacil/wg-admin/internal/tui/components"
|
||||||
"github.com/calmcacil/wg-admin/internal/wireguard"
|
"github.com/calmcacil/wg-admin/internal/wireguard"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
@@ -63,13 +64,16 @@ func (s *QRScreen) Update(msg tea.Msg) (Screen, tea.Cmd) {
|
|||||||
|
|
||||||
// View renders the QR screen
|
// View renders the QR screen
|
||||||
func (s *QRScreen) View() string {
|
func (s *QRScreen) View() string {
|
||||||
|
// Breadcrumb: Clients > Client > QR Code
|
||||||
|
breadcrumb := components.RenderBreadcrumb([]components.BreadcrumbItem{{Label: "Clients", ID: "list"}, {Label: s.clientName, ID: "detail"}, {Label: "QR Code", ID: "qr"}})
|
||||||
|
|
||||||
if s.errorMsg != "" {
|
if s.errorMsg != "" {
|
||||||
return s.renderError()
|
return s.renderError()
|
||||||
}
|
}
|
||||||
if s.qrCode == "" {
|
if s.qrCode == "" {
|
||||||
return "Loading QR code..."
|
return "Loading QR code..."
|
||||||
}
|
}
|
||||||
return s.renderQR()
|
return breadcrumb + "\n" + s.renderQR()
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadConfig loads the client configuration
|
// loadConfig loads the client configuration
|
||||||
|
|||||||
@@ -181,8 +181,14 @@ func (s *RestoreScreen) View() string {
|
|||||||
|
|
||||||
// renderContent renders the main restore screen content
|
// renderContent renders the main restore screen content
|
||||||
func (s *RestoreScreen) renderContent() string {
|
func (s *RestoreScreen) renderContent() string {
|
||||||
|
// Breadcrumb: Clients > Restore
|
||||||
|
breadcrumb := components.RenderBreadcrumb([]components.BreadcrumbItem{{Label: "Clients", ID: "list"}, {Label: "Restore", ID: "restore"}})
|
||||||
|
|
||||||
|
|
||||||
var content strings.Builder
|
var content strings.Builder
|
||||||
|
|
||||||
|
content.WriteString(breadcrumb)
|
||||||
|
content.WriteString("\n")
|
||||||
content.WriteString(restoreTitleStyle.Render("Restore WireGuard Configuration"))
|
content.WriteString(restoreTitleStyle.Render("Restore WireGuard Configuration"))
|
||||||
content.WriteString("\n\n")
|
content.WriteString("\n\n")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user