From c5fb826dbe389a8e05f0de25b9317e6b58b9c278 Mon Sep 17 00:00:00 2001 From: DTTerastar Date: Mon, 9 Sep 2024 09:40:22 -0400 Subject: [PATCH] Settings ui and service --- Controllers/SettingsController.cs | 75 ++++++++++++ src/ui/src/lib/images/settings.svg | 1 + src/ui/src/lib/stores.ts | 33 ++++- src/ui/src/lib/types.ts | 32 ++++- src/ui/src/routes/+layout.svelte | 6 + src/ui/src/routes/settings/+page.svelte | 156 ++++++++++++++++++++++++ 6 files changed, 299 insertions(+), 4 deletions(-) create mode 100644 Controllers/SettingsController.cs create mode 100644 src/ui/src/lib/images/settings.svg create mode 100644 src/ui/src/routes/settings/+page.svelte diff --git a/Controllers/SettingsController.cs b/Controllers/SettingsController.cs new file mode 100644 index 00000000..975c8e53 --- /dev/null +++ b/Controllers/SettingsController.cs @@ -0,0 +1,75 @@ +using Microsoft.AspNetCore.Mvc; +using System.IO; +using System.Text.Json; + +[ApiController] +[Route("api/settings")] +public class SettingsController : ControllerBase +{ + private const string SettingsFilePath = "settings.json"; + + [HttpGet] + public ActionResult GetSettings() + { + if (!System.IO.File.Exists(SettingsFilePath)) + { + return new Settings(); + } + + var json = System.IO.File.ReadAllText(SettingsFilePath); + return JsonSerializer.Deserialize(json); + } + + [HttpPost] + public IActionResult SaveSettings([FromBody] Settings settings) + { + var json = JsonSerializer.Serialize(settings); + System.IO.File.WriteAllText(SettingsFilePath, json); + return Ok(); + } +} + +public class Settings +{ + public Updating Updating { get; set; } + public Scanning Scanning { get; set; } + public Counting Counting { get; set; } + public Filtering Filtering { get; set; } + public Calibration Calibration { get; set; } +} + +public class Updating +{ + public bool AutoUpdate { get; set; } + public bool PreRelease { get; set; } +} + +public class Scanning +{ + public int? ForgetAfterMs { get; set; } +} + +public class Counting +{ + public string IdPrefixes { get; set; } + public double? StartCountingDistance { get; set; } + public double? StopCountingDistance { get; set; } + public int? IncludeDevicesAge { get; set; } +} + +public class Filtering +{ + public string IncludeIds { get; set; } + public string ExcludeIds { get; set; } + public double? MaxReportDistance { get; set; } + public double? EarlyReportDistance { get; set; } + public int? SkipReportAge { get; set; } +} + +public class Calibration +{ + public int? RssiAt1m { get; set; } + public int? RssiAdjustment { get; set; } + public double? AbsorptionFactor { get; set; } + public int? IBeaconRssiAt1m { get; set; } +} \ No newline at end of file diff --git a/src/ui/src/lib/images/settings.svg b/src/ui/src/lib/images/settings.svg new file mode 100644 index 00000000..fb211293 --- /dev/null +++ b/src/ui/src/lib/images/settings.svg @@ -0,0 +1 @@ + diff --git a/src/ui/src/lib/stores.ts b/src/ui/src/lib/stores.ts index 621e97bf..cc33da52 100644 --- a/src/ui/src/lib/stores.ts +++ b/src/ui/src/lib/stores.ts @@ -1,6 +1,6 @@ import { readable, writable, derived } from 'svelte/store'; import { base } from '$app/paths'; -import type { Device, Config, Node } from './types'; +import type { Device, Config, Node, Settings } from './types'; export const showAll: SvelteStore = writable(false); export const config = writable(); @@ -54,8 +54,8 @@ export const devices = readable([], function start(set) { function fetchDevices() { fetch(`${base}/api/state/devices`) .then((d) => d.json()) - .then((r) => { - deviceMap = new Map(r.map((device) => [device.id, device])); + .then((r: Device[]) => { + deviceMap = new Map(r.map((device: Device) => [device.id, device])); updateDevicesFromMap(); }) .catch((ex) => { @@ -133,3 +133,30 @@ export const calibration = readable({}, function start(set) { clearInterval(interval); }; }); + +export const settings = (() => { + const { subscribe, set, update } = writable(null); + + return { + subscribe, + set, + update, + load: async () => { + const response = await fetch(`${base}/api/settings`); + if (!response.ok) throw new Error("Something went wrong loading settings (error="+response.status+" "+response.statusText+")"); + const data = await response.json(); + set(data); + }, + save: async (newSettings: Settings) => { + const response = await fetch(`${base}/api/settings`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(newSettings), + }); + const data = await response.json(); + set(data); + }, + }; +})(); \ No newline at end of file diff --git a/src/ui/src/lib/types.ts b/src/ui/src/lib/types.ts index 4ad9462b..7fc4155e 100644 --- a/src/ui/src/lib/types.ts +++ b/src/ui/src/lib/types.ts @@ -122,6 +122,36 @@ export interface Release { name: string; } + +export type Settings = { + updating: { + autoUpdate: boolean; + preRelease: boolean; + }; + scanning: { + forgetAfterMs: number | null; + }; + counting: { + idPrefixes: string | null; + startCountingDistance: number | null; + stopCountingDistance: number | null; + includeDevicesAge: number | null; + }; + filtering: { + includeIds: string | null; + excludeIds: string | null; + maxReportDistance: number | null; + earlyReportDistance: number | null; + skipReportAge: number | null; + }; + calibration: { + rssiAt1m: number | null; + rssiAdjustment: number | null; + absorptionFactor: number | null; + iBeaconRssiAt1m: number | null; + }; +}; + export function isNode(d: Device | Node | null): d is Node { return (d as Node)?.telemetry !== undefined; -} +} \ No newline at end of file diff --git a/src/ui/src/routes/+layout.svelte b/src/ui/src/routes/+layout.svelte index 00bf2504..75f33552 100644 --- a/src/ui/src/routes/+layout.svelte +++ b/src/ui/src/routes/+layout.svelte @@ -14,6 +14,7 @@ import nodes from '$lib/images/nodes.svg'; import devices from '$lib/images/devices.svg'; import calibration from '$lib/images/calibration.svg'; + import settings from '$lib/images/settings.svg'; initializeStores(); @@ -62,6 +63,11 @@ Calibration + + Settings + Settings + + GitHub diff --git a/src/ui/src/routes/settings/+page.svelte b/src/ui/src/routes/settings/+page.svelte new file mode 100644 index 00000000..64691bc1 --- /dev/null +++ b/src/ui/src/routes/settings/+page.svelte @@ -0,0 +1,156 @@ + + + +

Settings

+
+

Globally Set Node Settings

+

These settings will be set in every node, even new nodes.

+ {#if loading} +
+
+ +

Loading settings...

+
+
+ {:else if error} +
+

Error: {error}

+
+ {:else if $settings} +
+
+

Updating

+ + +
+ +
+

Scanning

+
+ +
+
+ +
+

Counting

+
+ + + + + + + +
+
+ +
+

Filtering

+
+ + + + + + + + + +
+
+ +
+

Calibration

+
+ + + + + + + +
+
+ +
+ +
+
+ {:else} +
+

No settings available.

+
+ {/if} +