Skip to content

feat: System page, live Logi, dashboard icons, floating help - #56

Merged
keskad merged 3 commits into
masterfrom
feat/ux-system-page-help
Aug 7, 2026
Merged

feat: System page, live Logi, dashboard icons, floating help#56
keskad merged 3 commits into
masterfrom
feat/ux-system-page-help

Conversation

@keskad

@keskad keskad commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add admin System page (/admin/system) with hub reboot/shutdown, live logs link, OS UI (8090) / Grafana (3000) when ports are open, microinit service table, dcc-bus daemon controls, and BigFred version card; move power actions out of the admin menu and drop the Logi menu entry (route kept).
  • Expose microinit services/info/log WebSocket and system ports APIs in loco-server; rewrite Logi to live-stream from microinit (?service= deep-links); trigger layout presence sync on Centralki and Makiety.
  • Add dashboard widget heading icons, a draggable floating help FAB (Pulpit / Moje pojazdy / Wypożyczenia / Moje składy), and remove the intro text on Moje składy.

Test plan

  • As admin, open Administracja → System: power tiles (disabled when not init), Logi navigation, OS/Grafana tiles reflect port probes, microinit table + log icons, refresh dcc-bus, dcc-bus start/stop/restart, version card.
  • Open Centralki and Makiety and confirm GET /api/v1/layouts/{id}/presence fires (network tab).
  • Open Logi via System and via dcc-bus “view logs”; confirm live stream, pause/clear, and ?service= deep-link.
  • On Pulpit, confirm icons next to Użytkownicy online / Nastawnie / Pociągi / Pojazdy.
  • On Pulpit, Moje pojazdy, Wypożyczenia, Moje składy: drag help FAB, open dialog, verify disable-per-page and disable-global persistence in localStorage; Moje składy has no intro paragraph.
  • Non-admin users do not see System in the menu and cannot open /admin/system.

Made with Cursor

…g help

Add an admin System page for hub power, OS/Grafana links, microinit
status, and dcc-bus daemons; stream Logi from microinit; sync presence
on Centralki/Makiety; add dashboard heading icons and a draggable help FAB.

Co-authored-by: Cursor <cursoragent@cursor.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Pull Request introduces significant new features and improvements across the application. The new 'System' admin page, live microinit logs, and the floating help button are well-implemented and enhance both administrative capabilities and user experience. The refactoring of the logs section from static files to a live stream is a major functional upgrade.

Error string `json:"error,omitempty"`
}

// MicroinitHandler serves admin microinit service listing, info, and log WS.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The implementation of the MicroinitHandler for live log streaming via WebSocket is robust. The in-handler authentication for WebSocket connections is a good practice, and the inclusion of log history and a keepalive mechanism ensures a reliable and user-friendly experience.

return s.power.ShutdownMode(mode)
}

// Ports probes loopback TCP ports for bigfred-os-ui (8090) and Grafana (3000).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The addition of the Ports() method and the tcpPortOpen helper function provides a clean and effective way to check the availability of local admin UIs. This is a valuable diagnostic feature for the new System page.

* On reconnect the buffer is cleared before applying the new history
* snapshot — avoids duplicating the last N history lines.
*/
export function useMicroinitLogStream(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The useMicroinitLogStream hook is well-designed, handling connection states, history, live updates, and pausing effectively. Clearing the buffer on reconnect before new history arrives is a thoughtful detail that prevents duplicate log entries.

label: t("nav.administration.systemPower"),
icon: <PowerSettingsNewIcon fontSize="small" />,
onClick: () => setSystemPowerOpen(true),
id: "system",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The refactoring of the admin menu to include the new 'System' page and the removal of the old 'Logs' entry (now replaced by live streaming) streamlines the navigation and reflects the updated functionality. The integration of FloatingHelpButton is also a great UX addition.

export default function SystemPowerDialog({
open,
onClose,
presetMode,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: Making the SystemPowerDialog more flexible with the presetMode prop is a good improvement for reusability, allowing it to be adapted for specific power actions where needed.

};
}

export default function FloatingHelpButton() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The FloatingHelpButton is a significant UX enhancement. The drag-and-drop functionality with proper clamping, pointer event handling, and persistence via useHelpVisibility is well-implemented, providing an intuitive way for users to access help.

};
}

export function useHelpVisibility() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The useHelpVisibility hook effectively manages the visibility, position, and persistence of the help button and dialog. Using localStorage for user preferences like position and disabled states is appropriate and well-handled, including error mitigation for localStorage operations.

@@ -1,27 +1,16 @@
{
"title": "Logs",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The complete rewrite of the diagnostics translation files to support live microinit logs instead of static file logs represents a significant functional upgrade and aligns with the new backend capabilities.

Use auth.Effective for microinit log WS (sudo admins) and close the
follow connection on client disconnect. Restore dictated Polish help
texts with icon slots.

Co-authored-by: Cursor <cursoragent@cursor.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes introduce a new 'System' administration page, integrate live microinit logs, add dashboard icons, and implement a floating help button. The backend services for microinit control and system port probing are well-structured, including robust authentication for WebSocket streams. The frontend components and hooks effectively manage state and user interaction for these new features. The refactoring of the diagnostics page to use live microinit logs is a significant functional improvement.

}

wsConn, err := websocket.Accept(w, r, &websocket.AcceptOptions{
InsecureSkipVerify: true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ [LOW] PRIORITY:LOW: The InsecureSkipVerify: true option for websocket.Accept is used here. While this might be acceptable for internal communication with microinit where TLS might not be configured or necessary, it's generally a security-sensitive flag. Consider adding a comment to explain the rationale behind this choice, e.g., "Used for internal microinit connections where TLS is not enforced or managed by BigFred."

// reports unavailable (tests / --no-supervisor).
func NewMicroinitControl(mgr ServiceManager) *MicroinitControl {
m, ok := mgr.(*manager)
if !ok || m == nil || m.supervisor == nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ [LOW] PRIORITY:LOW: The NewMicroinitControl function relies on a type assertion mgr.(*manager) to access the underlying supervisor client. This creates a tight coupling between MicroinitControl and the concrete implementation of ServiceManager. While the comment explains this is intentional for the microinit-backed manager, it's a design point to be aware of for future refactoring of the ServiceManager interface or its implementations.

gap: 1,
}}
>
<DirectionsRailwayIcon fontSize="small" color="action" aria-hidden />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: Adding icons to the dashboard widget headings significantly improves the visual clarity and user experience, making it easier to quickly identify sections.

export default function SystemPowerDialog({
open,
onClose,
presetMode,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The addition of the presetMode prop makes the SystemPowerDialog more flexible and reusable, allowing it to be configured for specific power actions or to offer all options.

}

/** Shared BigFred version table used by VersionPage and SystemPage. */
export default function VersionCard() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: Extracting the version display into a reusable VersionCard component is a good practice for modularity and consistency across different admin pages.

[],
);

if (!visible || !entry) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The implementation of the draggable floating help button, including pointer event handling for dragging and click detection, and position clamping, is robust and well-executed.

"supervisord.config": "supervisord.conf",
"redis.stdout": "stdout",
"redis.stderr": "stderr"
"title": "Logs",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The complete rewrite of the diagnostics translations reflects a significant and positive shift from a file-based log viewer to a live-streaming service-based log viewer, aligning with the PR's goal of "live Logi."

@@ -1,27 +1,16 @@
{
"title": "Logs",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The complete rewrite of the diagnostics translations reflects a significant and positive shift from a file-based log viewer to a live-streaming service-based log viewer, aligning with the PR's goal of "live Logi."

@@ -1,27 +1,16 @@
{
"title": "Logi",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The complete rewrite of the diagnostics translations reflects a significant and positive shift from a file-based log viewer to a live-streaming service-based log viewer, aligning with the PR's goal of "live Logi."

Add MicrodnsServiceDef via EnsureInfra (like redis/alloy), seed
microdns.json on first run, and expose --microdns-bin. Skip on Android;
best-effort when binary is missing. Foreign OS microdns drop-ins are left alone.

Co-authored-by: Cursor <cursoragent@cursor.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Pull Request introduces significant new features and architectural improvements, including a new 'System' admin page, live microinit log streaming, dashboard widget icons, and a floating help system. The changes demonstrate a strong focus on enhancing diagnostics, maintainability, and user experience. The refactoring of microinit and microdns management into more modular and robust components is particularly commendable.


history, err := h.fetchLogHistory(serviceID, microinitLogHistoryLines)
if err != nil {
_ = writeMicroinitWS(wsConn, ctx, microinitWSMessage{Type: "error", Error: err.Error()})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ [LOW] PRIORITY:LOW: The _ = writeMicroinitWS(...) calls ignore potential errors when writing to the WebSocket. While defer wsConn.Close() and the read goroutine provide some cleanup, explicitly checking and logging errors from writeMicroinitWS could provide better insight into WebSocket write failures, especially if the connection is already in a half-open state.

if errors.As(err, &opErr) {
return true
}
msg := err.Error()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ [LOW] PRIORITY:LOW: The isClosedConn function relies on string matching for error messages (strings.Contains(msg, "closed")). This can be brittle as error messages might change across Go versions or different network implementations. Relying more on errors.Is(err, net.ErrClosed) and specific error types (like net.OpError) is generally more robust.

},
onOpen: () => {
// Clear before history arrives so reconnect does not append duplicates.
setLines([]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ [LOW] PRIORITY:LOW: In onOpen, setLines([]) is called to clear previous logs before history arrives. While this prevents duplicates on reconnect, if the 'history' message is delayed or fails to arrive, the log view might appear empty for a moment before live lines or an error state is shown. This is a minor UX consideration.


function defaultPosition(): HelpPosition {
if (typeof window === "undefined") return { x: 24, y: 24 };
return {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ [LOW] PRIORITY:LOW: The defaultPosition for the floating help button is calculated based on window.innerWidth and window.innerHeight. While the onResize handler in FloatingHelpButton addresses dynamic resizing, the initial placement might be less ideal if the window size changes significantly before the button is interacted with or if the localStorage value is cleared. Consider a more central or less edge-dependent initial default.

Disable: !redisMgmt.Managed,
},
Telemetry: telemetryCfg,
Microdns: microinit.MicrodnsConfig{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The refactoring to replace the direct microinit.EnsureMicrodnsConfig() call with a structured microinit.MicrodnsConfig within InfraConfig is a good architectural improvement. It centralizes configuration management and makes the system more modular and testable.

export default function SystemPowerDialog({
open,
onClose,
presetMode,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: Making the SystemPowerDialog more flexible with the presetMode prop is a good improvement. It allows the dialog to be reused in contexts where only a specific power action (shutdown or reboot) is relevant, simplifying the user interface for those cases.

@@ -0,0 +1,96 @@
import {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: Extracting the version display into a reusable VersionCard component is a good practice for UI modularity and reusability, especially as this information is now displayed on the new System page.

@@ -0,0 +1,57 @@
import { Alert, CircularProgress, Stack } from "@mui/material";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The new DccBusProgramList and DccBusProgramRow components provide a clear and interactive interface for managing DCC bus daemon controls, which is a valuable addition to the admin UI.

@@ -0,0 +1,143 @@
import { useCallback, useEffect, useRef, useState } from "react";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The implementation of a draggable floating help button with persistence for its position and visibility settings (per-route and global) is a significant enhancement to the application's user experience and accessibility.

@@ -1,27 +1,16 @@
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ [POSITIVE] POSITIVE: The complete rewrite of the diagnostics translations reflects the shift from static file-based logs to dynamic, service-oriented live log streams from microinit. This is a necessary and positive update to align with the new backend functionality.

@keskad
keskad merged commit 167a8ae into master Aug 7, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant