created a basic home page #97

This commit is contained in:
Andre Henriques 2024-04-17 21:39:50 +01:00
parent a3913ccdf5
commit f41cdf78df
10 changed files with 173 additions and 11 deletions

View File

@ -0,0 +1,44 @@
package stats
import (
"time"
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/utils"
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
)
func HandlePublicStats(handle *Handle) {
handle.Post("/stats/public/main", func(c *Context) *Error {
if handle.DataMap["PublicMainLastUpdate"] != nil && handle.DataMap["PublicMainLastUpdate"].(int64) > time.Now().UnixMilli() {
c.ShowMessage = false
return c.SendJSON(handle.DataMap["PublicMain"])
}
number_of_models, err := GetDbVar[int](c, "count(*)", "models")
if err != nil {
return c.E500M("Could not get statistics", err)
}
number_of_classfications, err := GetDbVar[int](c, "count(*)", "tasks where task_type=$1", TASK_TYPE_CLASSIFICATION)
if err != nil {
return c.E500M("Could not get statistics", err)
}
number_of_images_processed, err := GetDbVar[int](c, "count(*)", "model_data_point")
if err != nil {
return c.E500M("Could not get statistics", err)
}
handle.DataMap["PublicMainLastUpdate"] = time.Now().UnixNano() + 60*60*1000*1000
handle.DataMap["PublicMain"] = struct {
NumberOfModels int `json:"number_of_models"`
NumberOfClassfications int `json:"number_of_classfications"`
NumberOfImagesProcessed int `json:"number_of_images_processed"`
}{
*number_of_models,
*number_of_classfications,
*number_of_images_processed,
}
c.ShowMessage = false
return c.SendJSON(handle.DataMap["PublicMain"])
})
}

9
logic/stats/index.go Normal file
View File

@ -0,0 +1,9 @@
package stats
import (
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
)
func HandleStats(handle *Handle) {
HandlePublicStats(handle)
}

View File

@ -46,6 +46,7 @@ type Handle struct {
gets []HandleFunc
posts []HandleFunc
deletes []HandleFunc
DataMap map[string]interface{}
Config Config
validate *validator.Validate
}
@ -523,7 +524,7 @@ func NewHandler(db db.Db, config Config) *Handle {
var posts []HandleFunc
var deletes []HandleFunc
validate := validator.New()
x := &Handle{db, gets, posts, deletes, config, validate}
x := &Handle{db, gets, posts, deletes, map[string]interface{}{}, config, validate}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

View File

@ -8,6 +8,7 @@ import (
"git.andr3h3nriqu3s.com/andr3/fyp/logic/db"
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models"
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/stats"
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks"
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/tasks/runner"
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/users"
@ -48,6 +49,7 @@ func main() {
UsersEndpints(db, handle)
HandleModels(handle)
HandleTasks(handle)
HandleStats(handle)
handle.Startup()
}

View File

@ -6,22 +6,22 @@
<nav>
<ul>
<li>
<a href="/"> Index </a>
<a href="/"> <span class="bi bi-house-fill"></span> Home </a>
</li>
{#if userStore.user}
<li>
<a href="/models"> Models </a>
<a href="/models"> <span class="bi bi-card-image"></span> Models </a>
</li>
{/if}
<li class="expand"></li>
{#if userStore.user}
<li>
<a href="/user/info"> User Info </a>
<a href="/logout"> Logout </a>
<a href="/user/info"> <span class="bi bi-person-fill"></span> {userStore.user.username} </a>
<a href="/logout"> <span class="bi bi-box-arrow-right"></span> Logout </a>
</li>
{:else}
<li>
<a href="/login"> Login </a>
<a href="/login"> <span class="bi bi-box-arrow-in-left"></span> Login</a>
</li>
{/if}
</ul>

View File

@ -3,9 +3,25 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Andada+Pro:ital,wght@0,400..840;1,400..840&family=Bebas+Neue&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css"
/>
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">

View File

@ -1,5 +1,6 @@
import { goto } from '$app/navigation';
import { userStore } from 'routes/UserStore.svelte';
import { notificationStore } from './NotificationsStore.svelte';
const API = '/api';
@ -102,7 +103,7 @@ export async function postFormData(url: string, body: FormData) {
export async function showMessage(
e: any,
messages: any,
messages: any = notificationStore,
message = 'Could not complete request'
): Promise<boolean> {
if (e == null) {

View File

@ -1 +1,48 @@
<h1>Main Web Page</h1>
<script>
import Spinner from 'src/lib/Spinner.svelte';
import Counter from './Counter.svelte';
import { post, showMessage } from 'src/lib/requests.svelte';
import { onMount } from 'svelte';
let _counters = $state(new Promise(() => {}));
async function publicStats() {
try {
const r = await post('stats/public/main', {});
_counters = Promise.resolve(r);
} catch (e) {
showMessage(e);
}
}
onMount(() => {
publicStats();
});
</script>
<div class="title">
<h1>Classify Your Images</h1>
<h2>A software as a service platform for image classification</h2>
</div>
<div class="counters">
{#await _counters}
<Spinner />
{:then counters}
<Counter value={counters.number_of_models}>Number of models created</Counter>
<Counter value={counters.number_of_classfications}>Number of images classified</Counter>
<Counter value={counters.number_of_images_processed}>Number of images processed</Counter>
{/await}
</div>
<style>
.title {
text-align: center;
}
.counters {
height: 180px;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@ -0,0 +1,41 @@
<script lang="ts">
import { cubicOut } from 'svelte/easing';
import { tweened } from 'svelte/motion';
const { value, children }: { value: number; children: unknown } = $props();
const t_value = tweened(0, {
duration: 300,
easing: cubicOut
});
$effect(() => {
t_value.set(value);
});
</script>
<div class="counter">
<div class="number">
{Math.floor($t_value)}
</div>
<div class="description">
<slot />
</div>
</div>
<style>
.counter {
width: 150px;
height: 150px;
box-shadow: 1px 1px 8px 2px #33333333;
border-radius: 30px;
padding: 20px;
margin: 0 10px;
text-align: center;
.number {
font-family: 'Bebas Neue';
font-size: 50px;
}
}
</style>

View File

@ -1,6 +1,7 @@
* {
box-sizing: border-box;
font-family: 'Roboto', sans-serif;
font-family: 'Andada Pro', sans-serif;
/* font-family: 'Roboto', sans-serif; */
}
:root {