feat(control): show display block version in control block

closes #54
This commit is contained in:
E44
2026-06-12 10:59:09 +02:00
parent 9284a8f72a
commit a827a3e588
7 changed files with 63 additions and 24 deletions
@@ -26,7 +26,7 @@
close_pinned_display close_pinned_display
}: { }: {
display_id_group: DisplayIdGroup; display_id_group: DisplayIdGroup;
get_display_menu_options: (display_id: string) => MenuOption[]; get_display_menu_options: (display_id: string, display_version: string|undefined) => MenuOption[];
close_pinned_display: () => void; close_pinned_display: () => void;
} = $props(); } = $props();
@@ -20,7 +20,7 @@
close_pinned_display close_pinned_display
}: { }: {
display_id_object: DisplayIdObject; display_id_object: DisplayIdObject;
get_display_menu_options: (display_id: string) => MenuOption[]; get_display_menu_options: (display_id: string, display_version: string|undefined) => MenuOption[];
close_pinned_display: () => void; close_pinned_display: () => void;
} = $props(); } = $props();
@@ -136,7 +136,7 @@
click_function={(e) => { click_function={(e) => {
e.stopPropagation(); e.stopPropagation();
}} }}
menu_options={get_display_menu_options(display_id_object.id)} menu_options={get_display_menu_options(display_id_object.id, $display?.version)}
> >
<Menu /> <Menu />
</Button> </Button>
+12 -6
View File
@@ -186,15 +186,21 @@ export async function get_thumbnail_blob(ip: string, path_to_file: string): Prom
return raw_response.blob; return raw_response.blob;
} }
export async function ping_ip(ip: string): Promise<DisplayStatus> { export async function ping_ip(ip: string): Promise<{ status: DisplayStatus; version?: string }> {
const raw_response = await request_control(`/ping?ip=${ip}`, { method: 'GET' }); const raw_response = await request_control(`/ping?ip=${ip}`, { method: 'GET' });
if (!raw_response.ok || !raw_response.json) return null; if (!raw_response.ok || !raw_response.json) return { status: null };
const status = raw_response.json.status; const raw_status = raw_response.json.status;
if (typeof status === 'string') { if (typeof raw_status === 'string') {
return to_display_status(status); const status = to_display_status(raw_status);
const version = raw_response.json.version;
if (typeof version === 'string') {
return { status, version };
} else {
return { status };
} }
return null; }
return { status: null };
} }
async function request_display( async function request_display(
+11 -7
View File
@@ -40,22 +40,26 @@ async function update_all_display_status(only_loading_displays: boolean) {
} }
export async function update_display_status(display: Display): Promise<DisplayStatus> { export async function update_display_status(display: Display): Promise<DisplayStatus> {
const new_status = await ping_ip(display.ip); const resp = await ping_ip(display.ip);
if (new_status === null && display.status !== null) return null; if (resp.version && display.version !== resp.version) {
if (new_status !== display.status) { display.version = resp.version;
await db.displays.put(display); // save
}
if (resp.status === null && display.status !== null) return null;
if (resp.status !== display.status) {
// status change // status change
if (new_status === 'app_offline') { if (resp.status === 'app_offline') {
loading_display_ids.push(display.id); loading_display_ids.push(display.id);
} else { } else {
remove_display_from_loading_displays(display.id); remove_display_from_loading_displays(display.id);
if (new_status === 'app_online') { if (resp.status === 'app_online') {
on_display_start(display); on_display_start(display);
} }
} }
display.status = new_status; display.status = resp.status;
await db.displays.put(display); // save await db.displays.put(display); // save
} }
return new_status; return resp.status;
} }
export function remove_display_from_loading_displays(display_id: string) { export function remove_display_from_loading_displays(display_id: string) {
+1
View File
@@ -96,6 +96,7 @@ export type Display = {
group_id: string; group_id: string;
name: string; name: string;
status: DisplayStatus; status: DisplayStatus;
version?: string;
}; };
export type DisplayGroup = { export type DisplayGroup = {
@@ -21,7 +21,7 @@
import { type Display, type DisplayGroup, type MenuOption } from '$lib/ts/types'; import { type Display, type DisplayGroup, type MenuOption } from '$lib/ts/types';
import Button from '$lib/components/Button.svelte'; import Button from '$lib/components/Button.svelte';
import OnlineState from '../lib/components/OnlineState.svelte'; import OnlineState from '../lib/components/OnlineState.svelte';
import { Menu, Pencil, PinOff, Trash2, VideoOff, ZoomIn, ZoomOut } from 'lucide-svelte'; import { History, Menu, Pencil, PinOff, Trash2, VideoOff, ZoomIn, ZoomOut } from 'lucide-svelte';
import { selected_display_ids } from '$lib/ts/stores/select'; import { selected_display_ids } from '$lib/ts/stores/select';
import { dragHandleZone } from 'svelte-dnd-action'; import { dragHandleZone } from 'svelte-dnd-action';
import DisplayGroupObject from '../lib/components/DisplayGroupObject.svelte'; import DisplayGroupObject from '../lib/components/DisplayGroupObject.svelte';
@@ -68,8 +68,13 @@
pinned_pane_size = 0; pinned_pane_size = 0;
} }
function get_display_menu_options(display_id: string): MenuOption[] { function get_display_menu_options(display_id: string, display_version: string|undefined): MenuOption[] {
return [ return [
{
icon: History,
name: display_version ?? "Version unbekannt",
disabled: true,
},
{ {
icon: Pencil, icon: Pencil,
name: 'Bildschirm bearbeiten', name: 'Bildschirm bearbeiten',
@@ -165,7 +170,7 @@
click_function={(e) => { click_function={(e) => {
e.stopPropagation(); e.stopPropagation();
}} }}
menu_options={get_display_menu_options($pinned_display_id)} menu_options={get_display_menu_options($pinned_display_id, $pinned_display?.version)}
> >
<Menu /> <Menu />
</Button> </Button>
+26 -3
View File
@@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/json"
"log/slog" "log/slog"
"net" "net"
"net/http" "net/http"
@@ -83,17 +84,39 @@ func pingRoute(ctx echo.Context) error {
return ctx.JSON(http.StatusOK, PingResponse{Status: "host_offline"}) return ctx.JSON(http.StatusOK, PingResponse{Status: "host_offline"})
} }
conn, err := net.DialTimeout("tcp", ip+":1323", 5*time.Second) client := http.Client{
Timeout: 5 * time.Second,
}
resp, err := client.Get("http://" + ip + ":1323/api/ping")
if err != nil { if err != nil {
return ctx.JSON(http.StatusOK, PingResponse{Status: "app_offline"}) return ctx.JSON(http.StatusOK, PingResponse{Status: "app_offline"})
} }
conn.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return ctx.JSON(http.StatusOK, PingResponse{Status: "app_offline"})
}
return ctx.JSON(http.StatusOK, PingResponse{Status: "app_online"}) var appPing AppPingResponse
if err := json.NewDecoder(resp.Body).Decode(&appPing); err != nil {
return ctx.JSON(http.StatusOK, PingResponse{
Status: "app_offline",
})
}
return ctx.JSON(http.StatusOK, PingResponse{
Status: "app_online",
Version: appPing.Version,
})
}
type AppPingResponse struct {
Version string `json:"version"`
} }
type PingResponse struct { type PingResponse struct {
Status string `json:"status"` Status string `json:"status"`
Version string `json:"version"`
Error string `json:"error"` Error string `json:"error"`
} }