Rendering status as HTML tables.
This commit is contained in:
		
							parent
							
								
									885b7790d7
								
							
						
					
					
						commit
						4c52fb0f12
					
				| @ -140,7 +140,11 @@ func main() { | ||||
| 		Handler: func(w http.ResponseWriter, r *http.Request, conn net.Conn) { | ||||
| 			websession := websessions.NewSession(conn) | ||||
| 			defer websessions.SessionClosed(websession) | ||||
| 			websession.WriteNotifications() | ||||
| 			location, err := converge.GetUserLocation(r) | ||||
| 			if err != nil { | ||||
| 				panic(err) | ||||
| 			} | ||||
| 			websession.WriteNotifications(location) | ||||
| 		}, | ||||
| 		Text: true, | ||||
| 	} | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"converge/pkg/server/converge" | ||||
| 	templates2 "converge/pkg/server/templates" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| @ -24,6 +25,11 @@ func pageHandler(w http.ResponseWriter, r *http.Request) { | ||||
| 	} | ||||
| 	username, _ := os.LookupEnv("CONVERGE_USERNAME") | ||||
| 
 | ||||
| 	location, err := converge.GetUserLocation(r) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	switch r.URL.Path { | ||||
| 	case "": | ||||
| 		fallthrough | ||||
| @ -36,7 +42,7 @@ func pageHandler(w http.ResponseWriter, r *http.Request) { | ||||
| 	case "downloads.html": | ||||
| 		templates2.DownloadsTab().Render(r.Context(), w) | ||||
| 	case "sessions.html": | ||||
| 		templates2.SessionsTab().Render(r.Context(), w) | ||||
| 		templates2.SessionsTab(nil, location).Render(r.Context(), w) | ||||
| 	default: | ||||
| 		http.NotFound(w, r) | ||||
| 	} | ||||
|  | ||||
| @ -2,11 +2,14 @@ package main | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"converge/pkg/comms" | ||||
| 	"converge/pkg/models" | ||||
| 	templates2 "converge/pkg/server/templates" | ||||
| 	"github.com/a-h/templ" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type RenderFunc func() templ.Component | ||||
| @ -29,6 +32,11 @@ func render(dir string, name string, render RenderFunc) { | ||||
| func main() { | ||||
| 	dir := "html/docs" | ||||
| 
 | ||||
| 	netherlands, err := time.LoadLocation("Europe/Amsterdam") | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	fullindex := func() templ.Component { | ||||
| 		return templates2.Index("s", "example.com", "converge") | ||||
| 	} | ||||
| @ -41,5 +49,37 @@ func main() { | ||||
| 	render(dir, "usage.html", usage) | ||||
| 	render(dir, "downloads.html", templates2.Downloads) | ||||
| 
 | ||||
| 	render(dir, "sessions.html", templates2.SessionsTab) | ||||
| 	render(dir, "sessions-none.html", func() templ.Component { | ||||
| 		return templates2.SessionsTab(nil, netherlands) | ||||
| 	}) | ||||
| 	render(dir, "sessions.html", func() templ.Component { | ||||
| 
 | ||||
| 		japan, err := time.LoadLocation("Asia/Tokyo") | ||||
| 		if err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 
 | ||||
| 		state := models.State{} | ||||
| 		agent := models.Agent{ | ||||
| 			PublicId:  "id", | ||||
| 			StartTime: time.Now().In(japan), | ||||
| 			AgentInfo: comms.AgentInfo{ | ||||
| 				Username: "ci", | ||||
| 				Hostname: "container123", | ||||
| 				Pwd:      "/home/ci", | ||||
| 				OS:       "linux", | ||||
| 				Shell:    "/bin/bash", | ||||
| 			}, | ||||
| 			ExpiryTime: time.Now().In(japan).Add(10 * time.Minute), | ||||
| 		} | ||||
| 		state.Agents = append(state.Agents, agent) | ||||
| 		client := models.Client{ | ||||
| 			PublicId:    "c1", | ||||
| 			ClientId:    3, | ||||
| 			StartTime:   time.Now().In(japan), | ||||
| 			SessionType: "sftp", | ||||
| 		} | ||||
| 		state.Clients = append(state.Clients, client) | ||||
| 		return templates2.SessionsTab(&state, netherlands) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| @ -27,7 +27,5 @@ spec: | ||||
|           - name: CONVERGE_PASSWORD | ||||
|             # change this password in your final deployment | ||||
|             value: "abc123" | ||||
|           - name: TZ | ||||
|             value: Europe/Amsterdam | ||||
|         | ||||
| 
 | ||||
|  | ||||
| @ -6,6 +6,7 @@ import ( | ||||
| 	"converge/pkg/server/templates" | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
| @ -57,7 +58,25 @@ func (sessions *WebSessions) NewSession(wsConnection net.Conn) *WebSession { | ||||
| 	return session | ||||
| } | ||||
| 
 | ||||
| func (session *WebSession) WriteNotifications() { | ||||
| func GetUserLocation(r *http.Request) (*time.Location, error) { | ||||
| 	// Try to get timezone from a custom header
 | ||||
| 	tzName := r.Header.Get("X-Timezone") | ||||
| 
 | ||||
| 	// If not found in header, try to get from query parameter
 | ||||
| 	if tzName == "" { | ||||
| 		tzName = r.URL.Query().Get("tz") | ||||
| 	} | ||||
| 
 | ||||
| 	// If still not found, default to UTC
 | ||||
| 	if tzName == "" { | ||||
| 		tzName = "UTC" | ||||
| 	} | ||||
| 
 | ||||
| 	// Load the location
 | ||||
| 	return time.LoadLocation(tzName) | ||||
| } | ||||
| 
 | ||||
| func (session *WebSession) WriteNotifications(location *time.Location) { | ||||
| 	timer := time.NewTicker(10 * time.Second) | ||||
| 	defer timer.Stop() | ||||
| 	for { | ||||
| @ -66,8 +85,8 @@ func (session *WebSession) WriteNotifications() { | ||||
| 			if !ok { | ||||
| 				log.Println("channel closed") | ||||
| 			} | ||||
| 			log.Println("Got notification: ", notification.Ascii) | ||||
| 			err := templates.State(notification).Render(context.Background(), session.conn) | ||||
| 			//log.Println("Got notification: ", notification)
 | ||||
| 			err := templates.State(notification, location).Render(context.Background(), session.conn) | ||||
| 			if err != nil { | ||||
| 				log.Printf("WS connection closed: %v", err) | ||||
| 				return | ||||
|  | ||||
| @ -1,34 +1,94 @@ | ||||
| package templates | ||||
| 
 | ||||
| import	"converge/pkg/models" | ||||
| import ( | ||||
|   "converge/pkg/models" | ||||
|   "strconv" | ||||
|   "time" | ||||
|   _ "time/tzdata" | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| templ Sessions(state *models.State) { | ||||
| templ Sessions(state *models.State, loc *time.Location) { | ||||
|   <div hx-ext="ws" ws-connect="/ws/sessions"> | ||||
|       <h1>sessions</h1> | ||||
| 
 | ||||
|       <div id="status"> | ||||
|         if state != nil { | ||||
|            @State(state) | ||||
|            @State(state, loc) | ||||
|         } else { | ||||
|            "Loading..." | ||||
|            Loading... | ||||
|         } | ||||
|       </div> | ||||
|   </div> | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| templ State(state *models.State) { | ||||
| templ State(state *models.State, location *time.Location) { | ||||
|    <div id="status"> | ||||
|    <pre> | ||||
|      { state.Ascii } | ||||
|    </pre> | ||||
| 
 | ||||
|    <h3>agents</h3> | ||||
| 
 | ||||
|    if len(state.Agents) == 0 { | ||||
|      <p>-</p> | ||||
|    } else { | ||||
|         <table class="table"> | ||||
|            <thead> | ||||
|            <tr> | ||||
|                <th>id</th> | ||||
|                <th>start time</th> | ||||
|                <th>expiry time</th> | ||||
|                <th>username</th> | ||||
|                <th>host</th> | ||||
|                <th>OS</th> | ||||
|                <th>shell</th> | ||||
|            </tr> | ||||
|            </thead> | ||||
|    for _, agent := range state.Agents { | ||||
|            <tr> | ||||
|                <td>{agent.PublicId}</td> | ||||
|                <td>{agent.StartTime.In(location).Format(time.DateTime)}</td> | ||||
|                <td>{agent.ExpiryTime.In(location).Format(time.DateTime)}</td> | ||||
|                <td>{agent.AgentInfo.Username}</td> | ||||
|                <td>{agent.AgentInfo.Hostname}</td> | ||||
|                <td>{agent.AgentInfo.OS}</td> | ||||
|                <td>{agent.AgentInfo.Shell}</td> | ||||
|            </tr> | ||||
|    } | ||||
|         </table> | ||||
| 
 | ||||
|    } | ||||
| 
 | ||||
| 
 | ||||
|    <h3>clients</h3> | ||||
| 
 | ||||
|    if len(state.Clients) == 0 { | ||||
|         <p>-</p> | ||||
|       } else { | ||||
|           <table class="table"> | ||||
|               <thead> | ||||
|               <tr> | ||||
|                   <th>agent id</th> | ||||
|                   <th>id</th> | ||||
|                   <th>start time</th> | ||||
|                   <th>session type</th> | ||||
|               </tr> | ||||
|               </thead> | ||||
|    for _, client := range state.Clients { | ||||
|               <tr> | ||||
|                   <td>{client.PublicId}</td> | ||||
|                   <td>{strconv.Itoa(client.ClientId)}</td> | ||||
|                   <td>{client.StartTime.In(location).Format(time.DateTime)}</td> | ||||
|                   <td>{client.SessionType}</td> | ||||
|               </tr> | ||||
|    } | ||||
|           </table> | ||||
|    } | ||||
|    </div> | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| templ SessionsTab() { | ||||
| templ SessionsTab(state *models.State, loc *time.Location) { | ||||
|     @BasePage(4) { | ||||
|         @Sessions(nil) | ||||
|         @Sessions(state, loc) | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user