🪇 Implements major structure and service refactors

This commit is contained in:
Rune Harlyk
2024-08-19 20:13:57 +02:00
committed by Rune Harlyk
parent 9978918bf9
commit 3da1717341
23 changed files with 139 additions and 121 deletions
@@ -24,6 +24,9 @@
import { page } from '$app/stores'; import { page } from '$app/stores';
import { user } from '$lib/stores/user'; import { user } from '$lib/stores/user';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import { useFeatureFlags } from '$lib/stores/featureFlags';
const features = useFeatureFlags();
const appName = $page.data.app_name; const appName = $page.data.app_name;
@@ -70,7 +73,7 @@
title: 'Camera', title: 'Camera',
icon: Camera, icon: Camera,
href: '/peripherals/camera', href: '/peripherals/camera',
feature: $page.data.features.camera, feature: $features.camera,
}, },
{ {
title: 'Servo', title: 'Servo',
@@ -82,20 +85,20 @@
title: 'IMU', title: 'IMU',
icon: Rotate3d, icon: Rotate3d,
href: '/peripherals/imu', href: '/peripherals/imu',
feature: $page.data.features.imu || $page.data.features.mag || $page.data.features.bmp, feature: $features.imu || $features.mag || $features.bmp,
} }
] ]
}, },
{ {
title: 'Connections', title: 'Connections',
icon: Remote, icon: Remote,
feature: $page.data.features.ntp, feature: $features.ntp,
submenu: [ submenu: [
{ {
title: 'NTP', title: 'NTP',
icon: NTP, icon: NTP,
href: '/connections/ntp', href: '/connections/ntp',
feature: $page.data.features.ntp, feature: $features.ntp,
} }
] ]
@@ -125,7 +128,7 @@
title: 'Users', title: 'Users',
icon: Users, icon: Users,
href: '/user', href: '/user',
feature: $page.data.features.security && $user.admin, feature: $features.security && $user.admin,
}, },
{ {
@@ -151,7 +154,7 @@
title: 'System Metrics', title: 'System Metrics',
icon: Metrics, icon: Metrics,
href: '/system/metrics', href: '/system/metrics',
feature: $page.data.features.analytics, feature: $features.analytics,
}, },
{ {
@@ -159,10 +162,10 @@
icon: Update, icon: Update,
href: '/system/update', href: '/system/update',
feature: feature:
($page.data.features.ota || ($features.ota ||
$page.data.features.upload_firmware || $features.upload_firmware ||
$page.data.features.download_firmware) && $features.download_firmware) &&
(!$page.data.features.security || $user.admin), (!$features.security || $user.admin),
} }
] ]
} }
@@ -245,7 +248,7 @@
<div class="flex-col" /> <div class="flex-col" />
<div class="flex-grow" /> <div class="flex-grow" />
{#if $page.data.features.security} {#if $features.security}
<div class="flex items-center"> <div class="flex items-center">
<Avatar class="h-8 w-8" /> <Avatar class="h-8 w-8" />
<span class="flex-grow px-4 text-xl font-bold">{$user.username}</span> <span class="flex-grow px-4 text-xl font-bold">{$user.username}</span>
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { daisyColor } from "$lib/DaisyUiHelper"; import { daisyColor } from "$lib/utilities";
import { Chart, registerables } from "chart.js"; import { Chart, registerables } from "chart.js";
import { onMount } from "svelte"; import { onMount } from "svelte";
import { cubicOut } from "svelte/easing"; import { cubicOut } from "svelte/easing";
+17
View File
@@ -0,0 +1,17 @@
import { api } from '$lib/api';
import { notifications } from '$lib/components/toasts/notifications';
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
export function useFeatureFlags() {
const featureFlags = writable<Record<string, boolean>>({});
onMount(async () => {
const result = await api.get<Record<string, boolean>>('/api/features');
if (result.isOk()) featureFlags.set(result.inner);
else {
notifications.error('Feature flag could not fetched', 2500);
}
});
return featureFlags;
}
+20 -29
View File
@@ -1,36 +1,27 @@
import { type IMU } from '$lib/types/models';
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
import type { IMU } from '$lib/types/models';
let imu_data = {
x: <number[]>[],
y: <number[]>[],
z: <number[]>[],
imu_temp: <number[]>[],
altitude: <number[]>[],
pressure: <number[]>[],
bmp_temp: <number[]>[]
};
const maxIMUData = 100; const maxIMUData = 100;
function createIMU() { export const imu = (() => {
const { subscribe, update } = writable(imu_data); const { subscribe, update } = writable({
x: [] as number[],
y: [] as number[],
z: [] as number[],
imu_temp: [] as number[],
altitude: [] as number[],
pressure: [] as number[],
bmp_temp: [] as number[]
});
return { const addData = (content: IMU) => {
subscribe, update((data) => {
addData: (content: IMU) => { (Object.keys(content) as (keyof IMU)[]).forEach((key) => {
update((imu_data) => ({ data[key] = [...data[key], content[key]].slice(-maxIMUData);
...imu_data, });
x: [...imu_data.x, content.x].slice(-maxIMUData), return data;
y: [...imu_data.y, content.y].slice(-maxIMUData), });
z: [...imu_data.z, content.z].slice(-maxIMUData),
imu_temp: [...imu_data.imu_temp, content.imu_temp].slice(-maxIMUData),
altitude: [...imu_data.altitude, content.altitude].slice(-maxIMUData),
pressure: [...imu_data.pressure, content.pressure].slice(-maxIMUData),
bmp_temp: [...imu_data.bmp_temp, content.bmp_temp].slice(-maxIMUData)
}));
}
}; };
}
export const imu = createIMU(); return { subscribe, addData };
})();
+1
View File
@@ -6,3 +6,4 @@ export * from './fullscreen';
export * from './telemetry'; export * from './telemetry';
export * from './analytics'; export * from './analytics';
export * from './user'; export * from './user';
export * from './featureFlags';
+12 -27
View File
@@ -1,55 +1,40 @@
import { writable } from 'svelte/store';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { jwtDecode } from 'jwt-decode'; import { jwtDecode } from 'jwt-decode';
import { persistentStore } from '$lib/utilities';
export type userProfile = { export type UserProfile = {
username: string; username: string;
admin: boolean; admin: boolean;
bearer_token: string; bearer_token: string;
}; };
type decodedJWT = { type DecodedJWT = Omit<UserProfile, 'bearer_token'>;
username: string;
admin: boolean;
};
let empty = { const emptyUser: UserProfile = {
username: '', username: '',
admin: false, admin: false,
bearer_token: '' bearer_token: ''
}; };
function createStore() { function createUserStore() {
const { subscribe, set } = writable(empty); const store = persistentStore<UserProfile>('user', emptyUser);
// retrieve store from sessionStorage / localStorage if available
const userdata = localStorage.getItem('user');
if (userdata) {
set(JSON.parse(userdata));
}
return { return {
subscribe, subscribe: store.subscribe,
init: (access_token: string) => { init: (access_token: string) => {
const decoded: decodedJWT = jwtDecode(access_token); const decoded: DecodedJWT = jwtDecode(access_token);
const userdata = { const userProfile: UserProfile = {
bearer_token: access_token, bearer_token: access_token,
username: decoded.username, username: decoded.username,
admin: decoded.admin admin: decoded.admin
}; };
set(userdata); store.set(userProfile);
// persist store in sessionStorage / localStorage
localStorage.setItem('user', JSON.stringify(userdata));
}, },
invalidate: () => { invalidate: () => {
console.log('Log out user'); store.set(emptyUser);
set(empty);
// remove localStorage "user"
localStorage.removeItem('user');
// redirect to login page
goto('/'); goto('/');
} }
}; };
} }
export const user = createStore(); export const user = createUserStore();
@@ -1,4 +1,4 @@
export function daisyColor(name: string, opacity: number = 100) { export const daisyColor = (name: string, opacity: number = 100) => {
const color = getComputedStyle(document.documentElement).getPropertyValue(name); const color = getComputedStyle(document.documentElement).getPropertyValue(name);
return `oklch(${color} / ${opacity}%)`; return `oklch(${color} / ${opacity}%)`;
} };
+3
View File
@@ -5,3 +5,6 @@ export * from './math-utilities';
export * from './buffer-utilities'; export * from './buffer-utilities';
export * from './model-utilities'; export * from './model-utilities';
export * from './location-utilities'; export * from './location-utilities';
export * from './position-utilities';
export * from './string-utilities';
export * from './color-utilities';
+6 -6
View File
@@ -3,14 +3,14 @@ import { browser } from '$app/environment';
export const isEmbeddedApp = import.meta.env.VITE_EMBEDDED_BUILD === 'true'; export const isEmbeddedApp = import.meta.env.VITE_EMBEDDED_BUILD === 'true';
export const persistentStore = (key: string, initialValue: any) => { export const persistentStore = <T>(key: string, initialValue: T) => {
const savedValue = browser ? JSON.parse(localStorage.getItem(key) as string) : null; const savedValue = browser ? localStorage.getItem(key) : null;
const data = savedValue !== null ? savedValue : initialValue; const data: T = savedValue !== null ? JSON.parse(savedValue) : initialValue;
const store = writable(data); const store = writable<T>(data);
store.subscribe((value) => { store.subscribe((value) => {
browser && localStorage.setItem(key, JSON.stringify(value)); if (browser) localStorage.setItem(key, JSON.stringify(value));
}); });
return store; return store;
}; };
+15 -12
View File
@@ -6,14 +6,14 @@
import { notifications } from '$lib/components/toasts/notifications'; import { notifications } from '$lib/components/toasts/notifications';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
import '../app.css'; import '../app.css';
import Menu from './menu.svelte'; import Menu from '../lib/components/menu.svelte';
import Statusbar from './statusbar.svelte'; import Statusbar from '../lib/components/statusbar/statusbar.svelte';
import Login from './login.svelte'; import Login from '../lib/components/login.svelte';
import { import {
telemetry, telemetry,
analytics, analytics,
user, user,
type userProfile, type UserProfile,
ModesEnum, ModesEnum,
kinematicData, kinematicData,
mode, mode,
@@ -24,12 +24,15 @@
} from '$lib/stores'; } from '$lib/stores';
import type { Analytics, Battery, DownloadOTA } from '$lib/types/models'; import type { Analytics, Battery, DownloadOTA } from '$lib/types/models';
import { api } from '$lib/api'; import { api } from '$lib/api';
import { useFeatureFlags } from '$lib/stores/featureFlags';
const features = useFeatureFlags();
onMount(async () => { onMount(async () => {
if ($user.bearer_token !== '') { if ($user.bearer_token !== '') {
await validateUser($user); await validateUser($user);
} }
const ws_token = $page.data.features.security ? '?access_token=' + $user.bearer_token : ''; const ws_token = $features.security ? '?access_token=' + $user.bearer_token : '';
socket.init(`ws://${window.location.host}/ws/events${ws_token}`); socket.init(`ws://${window.location.host}/ws/events${ws_token}`);
addEventListeners(); addEventListeners();
@@ -53,10 +56,10 @@
socket.on('angles', (angles: number[]) => { socket.on('angles', (angles: number[]) => {
if (angles.length) servoAngles.set(angles); if (angles.length) servoAngles.set(angles);
}); });
if ($page.data.features.analytics) socket.on('analytics', handleAnalytics); if ($features.analytics) socket.on('analytics', handleAnalytics);
if ($page.data.features.battery) socket.on('battery', handleBattery); if ($features.battery) socket.on('battery', handleBattery);
if ($page.data.features.download_firmware) socket.on('otastatus', handleOAT); if ($features.download_firmware) socket.on('otastatus', handleOAT);
if ($page.data.features.sonar) socket.on('sonar', (data) => console.log(data)); if ($features.sonar) socket.on('sonar', (data) => console.log(data));
}; };
const removeEventListeners = () => { const removeEventListeners = () => {
@@ -68,7 +71,7 @@
socket.off('otastatus', handleOAT); socket.off('otastatus', handleOAT);
}; };
async function validateUser(userdata: userProfile) { async function validateUser(userdata: UserProfile) {
const result = await api.get('/api/verifyAuthorization'); const result = await api.get('/api/verifyAuthorization');
if (result.isErr()) { if (result.isErr()) {
user.invalidate(); user.invalidate();
@@ -81,7 +84,7 @@
}; };
const handleClose = () => { const handleClose = () => {
// notifications.error('Connection to device lost', 5000); notifications.error('Connection to device lost', 5000);
telemetry.setRSSI(0); telemetry.setRSSI(0);
}; };
@@ -102,7 +105,7 @@
<title>{$page.data.title}</title> <title>{$page.data.title}</title>
</svelte:head> </svelte:head>
{#if $page.data.features.security && $user.bearer_token === ''} {#if $features.security && $user.bearer_token === ''}
<Login /> <Login />
{:else} {:else}
<div class="drawer"> <div class="drawer">
-3
View File
@@ -13,10 +13,7 @@ const registerFetchIntercept = async () => {
export const load = async () => { export const load = async () => {
await registerFetchIntercept(); await registerFetchIntercept();
const result = await fetch('/api/features');
const features = await result.json();
return { return {
features,
title: 'Spot micro controller', title: 'Spot micro controller',
github: 'runeharlyk/SpotMicroESP32-Leika', github: 'runeharlyk/SpotMicroESP32-Leika',
app_name: 'Spot Micro Controller', app_name: 'Spot Micro Controller',
+5 -2
View File
@@ -16,6 +16,9 @@
import Stopwatch from '~icons/tabler/24-hours'; import Stopwatch from '~icons/tabler/24-hours';
import type { NTPSettings, NTPStatus } from '$lib/types/models'; import type { NTPSettings, NTPStatus } from '$lib/types/models';
import { api } from '$lib/api'; import { api } from '$lib/api';
import { useFeatureFlags } from '$lib/stores/featureFlags';
const features = useFeatureFlags();
let ntpSettings: NTPSettings; let ntpSettings: NTPSettings;
let ntpStatus: NTPStatus; let ntpStatus: NTPStatus;
@@ -45,7 +48,7 @@
onDestroy(() => clearInterval(interval)); onDestroy(() => clearInterval(interval));
onMount(() => { onMount(() => {
if (!$page.data.features.security || $user.admin) { if (!$features.security || $user.admin) {
getNTPSettings(); getNTPSettings();
} }
}); });
@@ -209,7 +212,7 @@
{/await} {/await}
</div> </div>
{#if !$page.data.features.security || $user.admin} {#if !$features.security || $user.admin}
<Collapsible open={false} on:closed={getNTPSettings}> <Collapsible open={false} on:closed={getNTPSettings}>
<span slot="title">Change NTP Settings</span> <span slot="title">Change NTP Settings</span>
<form <form
+2 -5
View File
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import SettingsCard from "$lib/components/SettingsCard.svelte"; import SettingsCard from "$lib/components/SettingsCard.svelte";
import MdiConnection from '~icons/mdi/connection'; import MdiConnection from '~icons/mdi/connection';
import { onDestroy, onMount } from "svelte"; import { onMount } from "svelte";
import { socket } from "$lib/stores"; import { socket } from "$lib/stores";
import type { I2CDevice } from "$lib/types/models"; import type { I2CDevice } from "$lib/types/models";
@@ -18,10 +18,7 @@
onMount(() => { onMount(() => {
socket.on('i2cScan', handleScan); socket.on('i2cScan', handleScan);
socket.sendEvent('i2cScan', ""); socket.sendEvent('i2cScan', "");
}) return () => socket.off('i2cScan', handleScan);
onDestroy(() => {
socket.off('i2cScan', handleScan);
}) })
const handleScan = (data: any) => { const handleScan = (data: any) => {
+8 -6
View File
@@ -6,10 +6,12 @@
import { cubicOut } from "svelte/easing"; import { cubicOut } from "svelte/easing";
import { slide } from "svelte/transition"; import { slide } from "svelte/transition";
import { onDestroy, onMount } from "svelte"; import { onDestroy, onMount } from "svelte";
import { daisyColor } from "$lib/DaisyUiHelper"; import { daisyColor } from "$lib/utilities";
import { socket } from "$lib/stores"; import { socket } from "$lib/stores";
import type { IMU } from "$lib/types/models"; import type { IMU } from "$lib/types/models";
import { page } from "$app/stores"; import { useFeatureFlags } from "$lib/stores/featureFlags";
const features = useFeatureFlags();
Chart.register(...registerables); Chart.register(...registerables);
@@ -242,7 +244,7 @@
}) })
const updateData = () => { const updateData = () => {
if ($page.data.features.imu) { if ($features.imu) {
angleChart.data.labels = $imu.x; angleChart.data.labels = $imu.x;
angleChart.data.datasets[0].data = $imu.x; angleChart.data.datasets[0].data = $imu.x;
angleChart.data.datasets[1].data = $imu.y; angleChart.data.datasets[1].data = $imu.y;
@@ -252,7 +254,7 @@
angleChart.update('none'); angleChart.update('none');
} }
if ($page.data.features.bmp) { if ($features.bmp) {
tempChart.data.labels = $imu.bmp_temp; tempChart.data.labels = $imu.bmp_temp;
tempChart.data.datasets[0].data = $imu.bmp_temp; tempChart.data.datasets[0].data = $imu.bmp_temp;
tempChart.options.scales!.y!.min = Math.min(...$imu.bmp_temp) - 1; tempChart.options.scales!.y!.min = Math.min(...$imu.bmp_temp) - 1;
@@ -272,7 +274,7 @@
<SettingsCard collapsible={false}> <SettingsCard collapsible={false}>
<Rotate3d slot="icon" class="lex-shrink-0 mr-2 h-6 w-6 self-end" /> <Rotate3d slot="icon" class="lex-shrink-0 mr-2 h-6 w-6 self-end" />
<span slot="title">IMU</span> <span slot="title">IMU</span>
{#if $page.data.features.imu} {#if $features.imu}
<div class="w-full overflow-x-auto"> <div class="w-full overflow-x-auto">
<div <div
class="flex w-full flex-col space-y-1 h-60" class="flex w-full flex-col space-y-1 h-60"
@@ -282,7 +284,7 @@
</div> </div>
</div> </div>
{/if} {/if}
{#if $page.data.features.bmp} {#if $features.bmp}
<div class="w-full overflow-x-auto"> <div class="w-full overflow-x-auto">
<div <div
class="flex w-full flex-col space-y-1 h-60" class="flex w-full flex-col space-y-1 h-60"
+4 -2
View File
@@ -1,9 +1,11 @@
<script lang="ts"> <script lang="ts">
import SystemMetrics from './SystemMetrics.svelte'; import SystemMetrics from './SystemMetrics.svelte';
import { page } from '$app/stores';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { useFeatureFlags } from '$lib/stores/featureFlags';
if (!$page.data.features.analytics) { const features = useFeatureFlags();
if (!$features.analytics) {
goto('/'); goto('/');
} }
</script> </script>
@@ -6,7 +6,7 @@
import { cubicOut } from 'svelte/easing'; import { cubicOut } from 'svelte/easing';
import { Chart, registerables } from 'chart.js'; import { Chart, registerables } from 'chart.js';
import Metrics from '~icons/tabler/report-analytics'; import Metrics from '~icons/tabler/report-analytics';
import { daisyColor } from '$lib/DaisyUiHelper'; import { daisyColor } from '$lib/utilities';
import { analytics } from '$lib/stores/analytics'; import { analytics } from '$lib/stores/analytics';
Chart.register(...registerables); Chart.register(...registerables);
@@ -29,6 +29,10 @@
import { api } from '$lib/api'; import { api } from '$lib/api';
import { convertSeconds } from '$lib/utilities'; import { convertSeconds } from '$lib/utilities';
import { useFeatureFlags } from '$lib/stores/featureFlags';
const features = useFeatureFlags()
let systemInformation: SystemInformation; let systemInformation: SystemInformation;
async function getSystemStatus() { async function getSystemStatus() {
@@ -295,12 +299,12 @@
</div> </div>
<div class="mt-4 flex flex-wrap justify-end gap-2"> <div class="mt-4 flex flex-wrap justify-end gap-2">
{#if $page.data.features.sleep} {#if $features.sleep}
<button class="btn btn-primary inline-flex items-center" on:click={confirmSleep} <button class="btn btn-primary inline-flex items-center" on:click={confirmSleep}
><Sleep class="mr-2 h-5 w-5" /><span>Sleep</span></button ><Sleep class="mr-2 h-5 w-5" /><span>Sleep</span></button
> >
{/if} {/if}
{#if !$page.data.features.security || $user.admin} {#if !$features.security || $user.admin}
<button class="btn btn-primary inline-flex items-center" on:click={confirmRestart} <button class="btn btn-primary inline-flex items-center" on:click={confirmRestart}
><Power class="mr-2 h-5 w-5" /><span>Restart</span></button ><Power class="mr-2 h-5 w-5" /><span>Restart</span></button
> >
+5 -3
View File
@@ -2,15 +2,17 @@
import UploadFirmware from './UploadFirmware.svelte'; import UploadFirmware from './UploadFirmware.svelte';
import GithubFirmwareManager from './GithubFirmwareManager.svelte'; import GithubFirmwareManager from './GithubFirmwareManager.svelte';
import { user } from '$lib/stores/user'; import { user } from '$lib/stores/user';
import { page } from '$app/stores'; import { useFeatureFlags } from '$lib/stores';
const features = useFeatureFlags();
</script> </script>
<div class="mx-0 my-1 flex flex-col space-y-4 sm:mx-8 sm:my-8"> <div class="mx-0 my-1 flex flex-col space-y-4 sm:mx-8 sm:my-8">
{#if $page.data.features.download_firmware && (!$page.data.features.security || $user.admin)} {#if $features.download_firmware && (!$features.security || $user.admin)}
<GithubFirmwareManager /> <GithubFirmwareManager />
{/if} {/if}
{#if $page.data.features.upload_firmware && (!$page.data.features.security || $user.admin)} {#if $features.upload_firmware && (!$features.security || $user.admin)}
<UploadFirmware /> <UploadFirmware />
{/if} {/if}
</div> </div>
@@ -16,6 +16,9 @@
import InfoDialog from '$lib/components/InfoDialog.svelte'; import InfoDialog from '$lib/components/InfoDialog.svelte';
import Check from '~icons/tabler/check'; import Check from '~icons/tabler/check';
import { api } from '$lib/api'; import { api } from '$lib/api';
import { useFeatureFlags } from '$lib/stores';
const features = useFeatureFlags();
async function getGithubAPI() { async function getGithubAPI() {
const headers = { const headers = {
@@ -45,7 +48,7 @@
// check if the asset is of type *.bin // check if the asset is of type *.bin
if ( if (
assets[i].name.includes('.bin') && assets[i].name.includes('.bin') &&
assets[i].name.includes($page.data.features.firmware_built_target) assets[i].name.includes($features.firmware_built_target)
) { ) {
url = assets[i].browser_download_url; url = assets[i].browser_download_url;
} }
@@ -99,7 +102,7 @@
<tbody> <tbody>
{#each githubReleases as release} {#each githubReleases as release}
<tr <tr
class={compareVersions($page.data.features.firmware_version, release.tag_name) === 0 class={compareVersions($features.firmware_version, release.tag_name) === 0
? 'bg-primary text-primary-content' ? 'bg-primary text-primary-content'
: 'bg-base-100 h-14'} : 'bg-base-100 h-14'}
> >
@@ -124,7 +127,7 @@
{/if} {/if}
</td> </td>
<td align="center"> <td align="center">
{#if compareVersions($page.data.features.firmware_version, release.tag_name) != 0} {#if compareVersions($features.firmware_version, release.tag_name) != 0}
<button <button
class="btn btn-ghost btn-circle btn-sm" class="btn btn-ghost btn-circle btn-sm"
on:click={() => { on:click={() => {
+5 -2
View File
@@ -14,6 +14,9 @@
import Devices from '~icons/tabler/devices'; import Devices from '~icons/tabler/devices';
import type { ApSettings, ApStatus } from '$lib/types/models'; import type { ApSettings, ApStatus } from '$lib/types/models';
import { api } from '$lib/api'; import { api } from '$lib/api';
import { useFeatureFlags } from '$lib/stores';
const features = useFeatureFlags();
let apSettings: ApSettings; let apSettings: ApSettings;
let apStatus: ApStatus; let apStatus: ApStatus;
@@ -47,7 +50,7 @@
onDestroy(() => clearInterval(interval)); onDestroy(() => clearInterval(interval));
onMount(() => { onMount(() => {
if (!$page.data.features.security || $user.admin) { if (!$features.security || $user.admin) {
getAPSettings(); getAPSettings();
} }
}); });
@@ -221,7 +224,7 @@
{/await} {/await}
</div> </div>
{#if !$page.data.features.security || $user.admin} {#if !$features.security || $user.admin}
<div class="bg-base-200 relative grid w-full max-w-2xl self-center overflow-hidden"> <div class="bg-base-200 relative grid w-full max-w-2xl self-center overflow-hidden">
<div <div
class="min-h-16 flex w-full items-center justify-between space-x-3 p-0 text-xl font-medium" class="min-h-16 flex w-full items-center justify-between space-x-3 p-0 text-xl font-medium"
+1 -1
View File
@@ -7,7 +7,7 @@
import Cancel from '~icons/tabler/x'; import Cancel from '~icons/tabler/x';
import Reload from '~icons/tabler/reload'; import Reload from '~icons/tabler/reload';
import { onMount, onDestroy } from 'svelte'; import { onMount, onDestroy } from 'svelte';
import RssiIndicator from '$lib/components/RSSIIndicator.svelte'; import RssiIndicator from '$lib/components/statusbar/RSSIIndicator.svelte';
import type { NetworkItem } from '$lib/types/models'; import type { NetworkItem } from '$lib/types/models';
import { api } from '$lib/api'; import { api } from '$lib/api';
import type { NetworkList } from '$lib/models'; import type { NetworkList } from '$lib/models';
+5 -3
View File
@@ -33,9 +33,11 @@
import Check from '~icons/tabler/check'; import Check from '~icons/tabler/check';
import InfoDialog from '$lib/components/InfoDialog.svelte'; import InfoDialog from '$lib/components/InfoDialog.svelte';
import type { KnownNetworkItem, WifiSettings, WifiStatus } from '$lib/types/models'; import type { KnownNetworkItem, WifiSettings, WifiStatus } from '$lib/types/models';
import { socket } from '$lib/stores'; import { socket, useFeatureFlags } from '$lib/stores';
import { api } from '$lib/api'; import { api } from '$lib/api';
const features = useFeatureFlags();
let networkEditable: KnownNetworkItem = { let networkEditable: KnownNetworkItem = {
ssid: '', ssid: '',
password: '', password: '',
@@ -435,7 +437,7 @@
{/await} {/await}
</div> </div>
{#if !$page.data.features.security || $user.admin} {#if !$features.security || $user.admin}
<div class="bg-base-200 relative grid w-full max-w-2xl self-center overflow-hidden"> <div class="bg-base-200 relative grid w-full max-w-2xl self-center overflow-hidden">
<div <div
class="min-h-16 flex w-full items-center justify-between space-x-3 p-0 text-xl font-medium" class="min-h-16 flex w-full items-center justify-between space-x-3 p-0 text-xl font-medium"
@@ -489,7 +491,7 @@
<div> <div>
<div class="font-bold">{dndNetworkList[index].ssid}</div> <div class="font-bold">{dndNetworkList[index].ssid}</div>
</div> </div>
{#if !$page.data.features.security || $user.admin} {#if !$features.security || $user.admin}
<div class="flex-grow" /> <div class="flex-grow" />
<div class="space-x-0 px-0 mx-0"> <div class="space-x-0 px-0 mx-0">
<button <button