mirror of
https://github.com/seriousm4x/UpSnap.git
synced 2026-07-24 06:24:07 -04:00
add basic frontend connection
This commit is contained in:
@@ -59,6 +59,19 @@ func init() {
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "s8c5z7n0",
|
||||
"name": "netmask",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "gdctb8hj",
|
||||
@@ -109,19 +122,6 @@ func init() {
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "s8c5z7n0",
|
||||
"name": "netmask",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"listRule": "",
|
||||
|
||||
@@ -17,15 +17,18 @@
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"prettier": "^2.8.3",
|
||||
"prettier-plugin-svelte": "^2.9.0",
|
||||
"svelte": "^3.55.0",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"svelte": "^3.55.0",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"vite": "^4.0.4"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"bootstrap": "5.3.0-alpha1",
|
||||
"date-fns": "^2.29.3",
|
||||
"pocketbase": "^0.10.0",
|
||||
"sass": "^1.57.1"
|
||||
"sass": "^1.57.1",
|
||||
"svelte-fa": "^3.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
29
frontend/pnpm-lock.yaml
generated
29
frontend/pnpm-lock.yaml
generated
@@ -1,10 +1,12 @@
|
||||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
'@fortawesome/free-solid-svg-icons': ^6.2.1
|
||||
'@popperjs/core': ^2.11.6
|
||||
'@sveltejs/adapter-auto': ^1.0.1
|
||||
'@sveltejs/kit': ^1.1.1
|
||||
bootstrap: 5.3.0-alpha1
|
||||
date-fns: ^2.29.3
|
||||
eslint: ^8.32.0
|
||||
eslint-config-prettier: ^8.6.0
|
||||
eslint-plugin-svelte3: ^4.0.0
|
||||
@@ -13,14 +15,18 @@ specifiers:
|
||||
prettier-plugin-svelte: ^2.9.0
|
||||
sass: ^1.57.1
|
||||
svelte: ^3.55.0
|
||||
svelte-fa: ^3.0.3
|
||||
svelte-preprocess: ^4.10.7
|
||||
vite: ^4.0.4
|
||||
|
||||
dependencies:
|
||||
'@fortawesome/free-solid-svg-icons': 6.2.1
|
||||
'@popperjs/core': 2.11.6
|
||||
bootstrap: 5.3.0-alpha1_@popperjs+core@2.11.6
|
||||
date-fns: 2.29.3
|
||||
pocketbase: 0.10.0
|
||||
sass: 1.57.1
|
||||
svelte-fa: 3.0.3
|
||||
|
||||
devDependencies:
|
||||
'@sveltejs/adapter-auto': 1.0.1_@sveltejs+kit@1.1.1
|
||||
@@ -251,6 +257,20 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@fortawesome/fontawesome-common-types/6.2.1:
|
||||
resolution: {integrity: sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==}
|
||||
engines: {node: '>=6'}
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
|
||||
/@fortawesome/free-solid-svg-icons/6.2.1:
|
||||
resolution: {integrity: sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==}
|
||||
engines: {node: '>=6'}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@fortawesome/fontawesome-common-types': 6.2.1
|
||||
dev: false
|
||||
|
||||
/@humanwhocodes/config-array/0.11.8:
|
||||
resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==}
|
||||
engines: {node: '>=10.10.0'}
|
||||
@@ -520,6 +540,11 @@ packages:
|
||||
which: 2.0.2
|
||||
dev: true
|
||||
|
||||
/date-fns/2.29.3:
|
||||
resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
|
||||
engines: {node: '>=0.11'}
|
||||
dev: false
|
||||
|
||||
/debug/4.3.4:
|
||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
@@ -1308,6 +1333,10 @@ packages:
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/svelte-fa/3.0.3:
|
||||
resolution: {integrity: sha512-GIikJjcVCD+5Y/x9hZc2R4gvuA0gVftacuWu1a+zVQWSFjFYZ+hhU825x+QNs2slsppfrgmFiUyU9Sz9gj4Rdw==}
|
||||
dev: false
|
||||
|
||||
/svelte-hmr/0.15.1_svelte@3.55.1:
|
||||
resolution: {integrity: sha512-BiKB4RZ8YSwRKCNVdNxK/GfY+r4Kjgp9jCLEy0DuqAKfmQtpL38cQK3afdpjw4sqSs4PLi3jIPJIFp259NkZtA==}
|
||||
engines: {node: ^12.20 || ^14.13.1 || >= 16}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
|
||||
31
frontend/src/components/DeviceCard.svelte
Normal file
31
frontend/src/components/DeviceCard.svelte
Normal file
@@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import { parseISO, formatDistance } from 'date-fns';
|
||||
import Fa from 'svelte-fa';
|
||||
import { faPowerOff } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export let device;
|
||||
export let now;
|
||||
</script>
|
||||
|
||||
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3 g-4">
|
||||
<div class="card border-0 rounded-5 px-2 bg-body-secondary text-dark-emphasis">
|
||||
<div class="card-body">
|
||||
<p
|
||||
class="m-0 fs-4"
|
||||
class:text-danger={device.status == 'offline' ? true : false}
|
||||
class:text-success={device.status == 'online' ? true : false}
|
||||
class:text-warning={device.status == 'pending' ? true : false}
|
||||
>
|
||||
<Fa icon={faPowerOff} />
|
||||
</p>
|
||||
<p class="m-0 fw-bold fs-5">{device.name} ({device.status})</p>
|
||||
<p class="m-0 text-muted">{device.ip}</p>
|
||||
</div>
|
||||
<div class="card-footer mb-2 bg-transparent fst-italic">
|
||||
Last change: {formatDistance(parseISO(device.updated), now, {
|
||||
includeSeconds: true,
|
||||
addSuffix: true
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,50 +0,0 @@
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Navbar</a>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon" />
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Link</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a
|
||||
class="nav-link dropdown-toggle"
|
||||
href="#"
|
||||
role="button"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Dropdown
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#">Action</a></li>
|
||||
<li><a class="dropdown-item" href="#">Another action</a></li>
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
<li><a class="dropdown-item" href="#">Something else here</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled">Disabled</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="d-flex" role="search">
|
||||
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" />
|
||||
<button class="btn btn-outline-success" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
import Navbar from '@components/Navbar.svelte';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<script>
|
||||
if (document) {
|
||||
theme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? 'dark'
|
||||
: 'light';
|
||||
document.documentElement.setAttribute('data-bs-theme', theme);
|
||||
}
|
||||
</script>
|
||||
</svelte:head>
|
||||
|
||||
<Navbar />
|
||||
|
||||
<slot />
|
||||
|
||||
@@ -1,16 +1,41 @@
|
||||
<script>
|
||||
import PocketBase from 'pocketbase';
|
||||
import { onMount } from 'svelte';
|
||||
import DeviceCard from '@components/DeviceCard.svelte';
|
||||
|
||||
let devices = [];
|
||||
let devices = {};
|
||||
|
||||
onMount(async () => {
|
||||
const pb = new PocketBase('http://127.0.0.1:8090');
|
||||
|
||||
// get all devices in pocketbase
|
||||
const result = await pb.collection('devices').getFullList();
|
||||
devices = result;
|
||||
result.forEach(device => {
|
||||
devices[device.id] = device
|
||||
});
|
||||
|
||||
// subscribe to database events
|
||||
pb.collection('devices').subscribe('*', function (e) {
|
||||
devices[e.record.id] = e.record
|
||||
});
|
||||
});
|
||||
|
||||
// update device date
|
||||
let now = Date.now();
|
||||
let clear;
|
||||
$: {
|
||||
clearInterval(clear)
|
||||
clear = setInterval(() => {
|
||||
now = Date.now()
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{#each devices as device}
|
||||
{device.name}
|
||||
{/each}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{#each Object.entries(devices) as [_, device]}
|
||||
<DeviceCard {device} {now} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,40 @@
|
||||
// @import "../../node_modules/bootstrap/scss/functions";
|
||||
// @import "../../node_modules/bootstrap/scss/variables";
|
||||
// @import "../../node_modules/bootstrap/scss/variables-dark";
|
||||
// @import "../../node_modules/bootstrap/scss/maps";
|
||||
// @import "../../node_modules/bootstrap/scss/mixins";
|
||||
// @import "../../node_modules/bootstrap/scss/root";
|
||||
// @import "../../node_modules/bootstrap/scss/utilities";
|
||||
// @import "../../node_modules/bootstrap/scss/reboot";
|
||||
// @import "../../node_modules/bootstrap/scss/type";
|
||||
// @import "../../node_modules/bootstrap/scss/images";
|
||||
// @import "../../node_modules/bootstrap/scss/containers";
|
||||
// @import "../../node_modules/bootstrap/scss/grid";
|
||||
// @import "../../node_modules/bootstrap/scss/helpers";
|
||||
// @import "../../node_modules/bootstrap/scss/utilities/api";
|
||||
@import "../../node_modules/bootstrap/scss/bootstrap";
|
||||
// import bootstrap functions and variables
|
||||
@import '../../node_modules/bootstrap/scss/functions';
|
||||
@import '../../node_modules/bootstrap/scss/variables';
|
||||
@import '../../node_modules/bootstrap/scss/variables-dark';
|
||||
|
||||
// custom colors
|
||||
$gray-1000: #111;
|
||||
$grays: (
|
||||
'100': $gray-100,
|
||||
'200': $gray-200,
|
||||
'300': $gray-300,
|
||||
'400': $gray-400,
|
||||
'500': $gray-500,
|
||||
'600': $gray-600,
|
||||
'700': $gray-700,
|
||||
'800': $gray-800,
|
||||
'900': $gray-900,
|
||||
'1000': $gray-1000
|
||||
) !default;
|
||||
|
||||
$body-bg-dark: $gray-1000;
|
||||
|
||||
// import rest
|
||||
@import '../../node_modules/bootstrap/scss/maps';
|
||||
@import '../../node_modules/bootstrap/scss/mixins';
|
||||
@import '../../node_modules/bootstrap/scss/root';
|
||||
@import '../../node_modules/bootstrap/scss/utilities';
|
||||
@import '../../node_modules/bootstrap/scss/reboot';
|
||||
@import '../../node_modules/bootstrap/scss/type';
|
||||
@import '../../node_modules/bootstrap/scss/images';
|
||||
@import '../../node_modules/bootstrap/scss/containers';
|
||||
@import '../../node_modules/bootstrap/scss/grid';
|
||||
@import '../../node_modules/bootstrap/scss/helpers';
|
||||
@import '../../node_modules/bootstrap/scss/card';
|
||||
|
||||
@import '../../node_modules/bootstrap/scss/utilities/api';
|
||||
|
||||
.text-success {
|
||||
color: $teal-500 !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user