Skip to content

Commit

Permalink
Add pagination to log lines #148
Browse files Browse the repository at this point in the history
  • Loading branch information
NHAS committed Nov 24, 2024
1 parent 314331e commit b7dd238
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 62 deletions.
12 changes: 11 additions & 1 deletion adminui/frontend/src/pages/Dashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { useUsersStore } from '@/stores/users'
import { useDevicesStore } from '@/stores/devices'
import { useTokensStore } from '@/stores/registration_tokens'
import { useInstanceDetailsStore } from '@/stores/serverInfo'
import { usePagination } from '@/composables/usePagination'
import PaginationControls from '@/components/PaginationControls.vue'
const devicesStore = useDevicesStore()
devicesStore.load(false)
Expand All @@ -25,6 +27,11 @@ const usersLackingMfa = computed(() => allUsers.value.filter(x => x.mfa_type ==
const allDevices = computed(() => devicesStore.devices ?? [])
const lockedDevices = computed(() => allDevices.value.filter(x => x.is_locked))
const allLogLines = computed(() => instanceDetails.logLines?.log_lines ?? [])
const { next: nextPage, prev: prevPage, totalPages, currentItems: currentLogLines, activePage } = usePagination(allLogLines, 20)
</script>

<template>
Expand Down Expand Up @@ -115,14 +122,17 @@ const lockedDevices = computed(() => allDevices.value.filter(x => x.is_locked))
<h2 class="card-title">Recent Log Messages</h2>
<table class="table w-full">
<tbody>
<tr class="hover" v-for="(line, index) in instanceDetails.log" :key="'log-line-' + index">
<tr class="hover" v-for="(line, index) in currentLogLines" :key="'log-line-' + index">
<td>
{{ line }}
</td>
</tr>
</tbody>
</table>
<EmptyTable v-if="instanceDetails.log.length == 0" text="No log lines yet" />
<div class="mt-2 w-full text-center">
<PaginationControls @next="() => nextPage()" @prev="() => prevPage()" :current-page="activePage" :total-pages="totalPages" />
</div>
</div>
</div>
</div>
Expand Down
72 changes: 13 additions & 59 deletions adminui/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import (
"encoding/json"
"log"
"net/http"
"sort"
"strings"
"sync"
"time"

"github.com/NHAS/wag/internal/data"
"github.com/gorilla/websocket"
"golang.org/x/exp/maps"
)

var upgrader = websocket.Upgrader{
Expand All @@ -24,10 +22,10 @@ type Acknowledgement struct {
ID string
}

func (au *AdminUI) notificationsWS(notifications <-chan Notification) func(w http.ResponseWriter, r *http.Request) {
func (au *AdminUI) notificationsWS(notifications <-chan NotificationDTO) func(w http.ResponseWriter, r *http.Request) {

var mapLck sync.RWMutex
servingConnections := map[string]chan<- Notification{}
servingConnections := map[string]chan<- NotificationDTO{}

go func() {

Expand All @@ -43,7 +41,7 @@ func (au *AdminUI) notificationsWS(notifications <-chan Notification) func(w htt
notificationsMapLck.Unlock()

for key := range servingConnections {
go func(key string, notification Notification) {
go func(key string, notification NotificationDTO) {
servingConnections[key] <- notification
}(key, notification)
}
Expand All @@ -58,7 +56,7 @@ func (au *AdminUI) notificationsWS(notifications <-chan Notification) func(w htt
return
}

connectionChan := make(chan Notification)
connectionChan := make(chan NotificationDTO)
defer func() {
mapLck.Lock()
delete(servingConnections, r.RemoteAddr)
Expand Down Expand Up @@ -94,56 +92,12 @@ type githubResponse struct {
Url string `json:"html_url"`
}

type Notification struct {
ID string
Heading string
Message []string
Url string
Time time.Time
Color string
OpenNewTab bool
}

var (
notificationsMapLck sync.RWMutex
notificationsMap = map[string]Notification{}
notificationsMap = map[string]NotificationDTO{}
)

func (au *AdminUI) getNotifications() []Notification {

notificationsMapLck.RLock()

// Make sure we have any historic errors on display as a notification
errs, err := au.ctrl.GetClusterErrors()
if err == nil {
for _, e := range errs {
if _, ok := notificationsMap[e.ErrorID]; !ok {
notificationsMap[e.ErrorID] = Notification{
ID: e.ErrorID,
Heading: "Node Error",
Message: []string{"Node " + e.NodeID, e.Error},
Url: "/cluster/events/",
Time: e.Time,
OpenNewTab: false,
Color: "#db0b3c",
}

}
}
}

notfs := maps.Values(notificationsMap)

notificationsMapLck.RUnlock()

sort.Slice(notfs, func(i, j int) bool {
return notfs[i].Time.After(notfs[j].Time)
})

return notfs
}

func (au *AdminUI) startUpdateChecker(notifications chan<- Notification) {
func (au *AdminUI) startUpdateChecker(notifications chan<- NotificationDTO) {
go func() {

for {
Expand All @@ -161,7 +115,7 @@ func (au *AdminUI) startUpdateChecker(notifications chan<- Notification) {
return
}

notifications <- Notification{
notifications <- NotificationDTO{
Heading: gr.TagName,
Message: strings.Split(gr.Body, "\r\n"),
Url: gr.Url,
Expand All @@ -175,13 +129,13 @@ func (au *AdminUI) startUpdateChecker(notifications chan<- Notification) {
}()
}

func (au *AdminUI) receiveErrorNotifications(notifications chan<- Notification) func(key string, current, previous data.EventError, et data.EventType) error {
func (au *AdminUI) receiveErrorNotifications(notifications chan<- NotificationDTO) func(key string, current, previous data.EventError, et data.EventType) error {

return func(key string, current, previous data.EventError, et data.EventType) error {
switch et {
case data.CREATED:

msg := Notification{
msg := NotificationDTO{
ID: current.ErrorID,
Heading: "Node Error",
Message: []string{"Node " + current.NodeID, current.Error},
Expand All @@ -202,15 +156,15 @@ func (au *AdminUI) receiveErrorNotifications(notifications chan<- Notification)
}
}

func (au *AdminUI) monitorClusterMembers(notifications chan<- Notification) {
func (au *AdminUI) monitorClusterMembers(notifications chan<- NotificationDTO) {
for {
currentMembers, err := au.ctrl.GetClusterMembers()
if err != nil {
log.Println("unable to get cluster members, err: ", err)
} else {

if len(currentMembers) == 2 {
notifications <- Notification{
notifications <- NotificationDTO{
ID: "monitor_node_number",
Heading: "Unsafe Cluster Size!",
Message: []string{"A wag cluster of two nodes doubles the risk of cluster failure.",
Expand Down Expand Up @@ -241,7 +195,7 @@ func (au *AdminUI) monitorClusterMembers(notifications chan<- Notification) {
delete(notificationsMap, "node_degrading_"+currentMembers[i].ID.String())
notificationsMapLck.Unlock()

notifications <- Notification{
notifications <- NotificationDTO{
ID: "node_dead_" + currentMembers[i].ID.String(),
Heading: "Node " + currentMembers[i].ID.String() + " dead",
Message: []string{currentMembers[i].ID.String() + " has not sent ping in 15 seconds and is assumed dead"},
Expand All @@ -252,7 +206,7 @@ func (au *AdminUI) monitorClusterMembers(notifications chan<- Notification) {
}

} else if lastPing.Before(time.Now().Add(-6 * time.Second)) {
notifications <- Notification{
notifications <- NotificationDTO{
ID: "node_degrading_" + currentMembers[i].ID.String(),
Heading: "Node " + currentMembers[i].ID.String() + " degraded",
Message: []string{currentMembers[i].ID.String() + " has exceeded expected liveness ping (5 seconds)"},
Expand Down
12 changes: 12 additions & 0 deletions adminui/structs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package adminui

import (
"time"

"github.com/NHAS/wag/internal/acls"
"github.com/NHAS/wag/internal/data"
"github.com/go-playground/validator/v10"
Expand Down Expand Up @@ -158,3 +160,13 @@ type MFAMethodDTO struct {
FriendlyName string `json:"friendly_name"`
Method string `json:"method"`
}

type NotificationDTO struct {
ID string
Heading string
Message []string
Url string
Time time.Time
Color string
OpenNewTab bool
}
4 changes: 2 additions & 2 deletions adminui/ui_webserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,8 @@ func New(firewall *router.Firewall, errs chan<- error) (ui *AdminUI, err error)
protectedRoutes.HandleFunc("GET /api/settings/login", adminUI.getLoginSettings)
protectedRoutes.HandleFunc("GET /api/settings/all_mfa_methods", adminUI.getAllMfaMethods)

notifications := make(chan Notification, 1)
protectedRoutes.HandleFunc("/notifications", adminUI.notificationsWS(notifications))
notifications := make(chan NotificationDTO, 1)
protectedRoutes.HandleFunc("GET /notifications", adminUI.notificationsWS(notifications))
data.RegisterEventListener(data.NodeErrors, true, adminUI.receiveErrorNotifications(notifications))
go adminUI.monitorClusterMembers(notifications)

Expand Down

0 comments on commit b7dd238

Please sign in to comment.