Skip to content

Commit 0c63a5e

Browse files
committed
merge: main
2 parents 85fdf99 + b6d9b20 commit 0c63a5e

File tree

236 files changed

+11832
-3122
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

236 files changed

+11832
-3122
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,3 @@ yarn-error.log*
4040
# Misc
4141
.DS_Store
4242
*.pem
43-
44-
/db/data

db/.gitinclude

Whitespace-only changes.

db.compose.yml renamed to evoting.compose.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
services:
22
db:
33
image: postgres:16
4-
container_name: dev-metastate-db
4+
container_name: dev-evoting-db
55
environment:
6-
POSTGRES_USER: metastate
7-
POSTGRES_PASSWORD: metastate
8-
POSTGRES_DB: metastate
6+
POSTGRES_USER: evoting
7+
POSTGRES_PASSWORD: evoting
8+
POSTGRES_DB: evoting
99
volumes:
1010
- ./db/data:/var/lib/postgresql/data
1111
ports:

forward-local-net.sh

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,75 @@
11
#!/bin/bash
22

3-
# Find Minikube IP
4-
MINIKUBE_IP=$(minikube ip)
3+
set -euo pipefail
54

6-
# Find all NodePort services with their ports
7-
echo "[INFO] Fetching all NodePort services..."
5+
echo "[INFO] Getting NodePort services..."
86
NODEPORTS=$(kubectl get svc --all-namespaces \
9-
-o jsonpath='{range .items[?(@.spec.type=="NodePort")]}{.metadata.namespace} {.metadata.name} {.spec.ports[*].nodePort}{"\n"}{end}')
7+
-o jsonpath='{range .items[?(@.spec.type=="NodePort")]}{.metadata.namespace}{" "}{.metadata.name}{" "}{.spec.ports[*].nodePort}{"\n"}{end}')
8+
9+
if [[ -z "$NODEPORTS" ]]; then
10+
echo "[INFO] No NodePort services found."
11+
exit 0
12+
fi
13+
14+
echo ""
15+
echo "[INFO] Found NodePort services:"
16+
echo "$NODEPORTS"
17+
echo ""
18+
19+
echo "$NODEPORTS" | while IFS= read -r line; do
20+
[[ -z "$line" ]] && continue
1021

11-
# Loop through services and ports
12-
while read -r line; do
1322
NAMESPACE=$(echo "$line" | awk '{print $1}')
1423
NAME=$(echo "$line" | awk '{print $2}')
1524
PORTS=$(echo "$line" | cut -d' ' -f3-)
1625

26+
echo "────────────────────────────────────────────"
27+
echo "[SERVICE] $NAMESPACE/$NAME (NodePort(s): $PORTS)"
28+
1729
for PORT in $PORTS; do
18-
echo "[FORWARDING] $NAMESPACE/$NAME on port $PORT"
30+
echo "[INFO] Starting tunnel for $NAME (NodePort: $PORT)..."
31+
32+
# Launch minikube tunnel in background and capture output
33+
TMPFILE=$(mktemp)
34+
(minikube service "$NAME" -n "$NAMESPACE" --url >"$TMPFILE") &
35+
TUNNEL_PID=$!
36+
37+
echo "[INFO] Waiting for tunnel to start..."
38+
i=0
39+
while ! grep -q "http://" "$TMPFILE"; do
40+
sleep 0.2
41+
i=$((i + 1))
42+
if [[ $i -gt 50 ]]; then
43+
echo " [ERROR] Timed out waiting for tunnel to start"
44+
kill $TUNNEL_PID >/dev/null 2>&1 || true
45+
rm -f "$TMPFILE"
46+
continue 2
47+
fi
48+
done
1949

20-
# Check if socat already listening
21-
if lsof -i TCP:$PORT >/dev/null; then
22-
echo " [SKIP] Port $PORT already in use locally"
50+
RAW_URL=$(cat "$TMPFILE")
51+
TUNNELED_PORT=$(echo "$RAW_URL" | sed -E 's|.*:([0-9]+)$|\1|')
52+
53+
echo "[DEBUG] RAW_URL = '$RAW_URL'"
54+
echo "[INFO] Minikube is forwarding to: $RAW_URL"
55+
echo "[INFO] We will bind localhost:$PORT → localhost:$TUNNELED_PORT"
56+
57+
if lsof -iTCP:$PORT >/dev/null 2>&1; then
58+
echo " [SKIP] Port $PORT already in use locally"
2359
else
24-
# Run socat in background
25-
socat TCP4-LISTEN:$PORT,fork TCP4:$MINIKUBE_IP:$PORT &
26-
echo " [OK] Forwarded port $PORT from Minikube to local"
60+
echo "[INFO] Launching socat..."
61+
nohup socat TCP4-LISTEN:$PORT,fork,reuseaddr TCP4:127.0.0.1:$TUNNELED_PORT \
62+
>/tmp/socat-tunnel-$PORT.log 2>&1 &
63+
64+
SOCAT_PID=$!
65+
echo "[OK] socat launched with PID $SOCAT_PID"
66+
echo "[INFO] Log file: /tmp/socat-tunnel-$PORT.log"
2767
fi
68+
69+
rm -f "$TMPFILE"
70+
echo "[INFO] Leaving Minikube tunnel running in background (PID: $TUNNEL_PID)"
2871
done
29-
done <<<"$NODEPORTS"
72+
done
73+
74+
echo ""
75+
echo "[DONE] All NodePorts are now mapped to localhost properly."

infrastructure/control-panel/package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,16 @@
4040
"typescript": "^5.0.0",
4141
"typescript-eslint": "^8.20.0",
4242
"vite": "^7.0.4"
43+
},
44+
"dependencies": {
45+
"@hugeicons/core-free-icons": "^1.0.13",
46+
"@hugeicons/svelte": "^1.0.2",
47+
"@inlang/paraglide-js": "^2.0.0",
48+
"@xyflow/svelte": "^1.2.2",
49+
"clsx": "^2.1.1",
50+
"flowbite": "^3.1.2",
51+
"flowbite-svelte": "^1.10.7",
52+
"flowbite-svelte-icons": "^2.2.1",
53+
"tailwind-merge": "^3.0.2"
4354
}
4455
}

infrastructure/control-panel/project.inlang/cache/plugins/2sy648wh9sugi

Lines changed: 0 additions & 1 deletion
This file was deleted.

infrastructure/control-panel/project.inlang/cache/plugins/ygx0uiahq6uw

Lines changed: 0 additions & 16 deletions
This file was deleted.

infrastructure/control-panel/src/app.css

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,39 @@
11
@import 'tailwindcss';
22

3+
@font-face {
4+
font-family: 'Archivo';
5+
src: url('/fonts/Archivo-VariableFont_wdth,wght.ttf') format('truetype');
6+
font-weight: 100 900;
7+
font-style: normal;
8+
}
9+
10+
@layer base {
11+
/* Typography */
12+
h1 {
13+
@apply text-[90px]/[1.5] font-semibold text-black;
14+
}
15+
16+
h2 {
17+
@apply text-6xl/[1.5] font-semibold text-black;
18+
}
19+
20+
h3 {
21+
@apply text-3xl/[1.5] font-semibold text-black;
22+
}
23+
24+
h4 {
25+
@apply text-xl/[1.5] font-semibold text-black;
26+
}
27+
28+
p {
29+
@apply text-base/[1.5] font-normal text-black;
30+
}
31+
32+
.small {
33+
@apply text-xs/[1.5] font-normal text-black;
34+
}
35+
}
36+
337
@theme {
438
/* Custom theme */
539
--color-primary: #8e52ff;
@@ -32,4 +66,6 @@
3266
--color-danger-300: #ff968e;
3367
--color-danger-400: #ff7b77;
3468
--color-danger-500: #ff5255;
69+
70+
--color-green: #0fb340;
3571
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { ComponentProps } from 'svelte';
2+
import { LiveDataFlow } from '..';
3+
4+
export default {
5+
title: 'UI/LiveDataFlow',
6+
component: LiveDataFlow,
7+
tags: ['autodocs'],
8+
render: (args: { Component: LiveDataFlow; props: ComponentProps<typeof LiveDataFlow> }) => ({
9+
Component: LiveDataFlow,
10+
props: args
11+
})
12+
};
13+
14+
export const Default = {
15+
args: {
16+
events: [
17+
{ id: 1, from: 'alice', to: 'pictique' },
18+
{ id: 2, from: 'pictique', to: 'bob' }
19+
]
20+
}
21+
};
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<script lang="ts">
2+
import { Database01FreeIcons, PauseFreeIcons, PlayFreeIcons } from '@hugeicons/core-free-icons';
3+
import { HugeiconsIcon } from '@hugeicons/svelte';
4+
5+
interface IEvent {
6+
id: string;
7+
from: string;
8+
to: string;
9+
imageSrc?: string;
10+
vaultName?: string;
11+
}
12+
13+
interface IDataFlowProps {
14+
events: IEvent[];
15+
}
16+
17+
let { events }: IDataFlowProps = $props();
18+
let isPaused = $state(false);
19+
</script>
20+
21+
<article class="bg-gray flex h-[80vh] w-full flex-col items-center rounded-md px-16 py-6">
22+
<div class="mb-20.5 flex w-full items-center justify-between">
23+
<h4 class="text-xl">Live Monitoring</h4>
24+
<button
25+
onclick={() => (isPaused = !isPaused)}
26+
class="font-geist text-black-700 flex items-center gap-2 rounded-4xl border border-[#e5e5e5] bg-white px-4 py-3 text-base font-medium"
27+
>
28+
{#if isPaused}
29+
<HugeiconsIcon icon={PlayFreeIcons} size="24px" />
30+
{:else}
31+
<HugeiconsIcon icon={PauseFreeIcons} size="24px" />
32+
{/if}
33+
{isPaused ? 'Resume Live Feed' : 'Pause Live Feed'}
34+
</button>
35+
</div>
36+
<div class="relative z-10 flex w-full items-center justify-between">
37+
<!-- svelte-ignore element_invalid_self_closing_tag -->
38+
<div
39+
class="border-s-green border-b-green border-e-green absolute start-[50%] top-[55%] z-[-1] h-[175px] w-[88%] translate-x-[-50%] rounded-md border border-t-transparent bg-transparent"
40+
>
41+
<div
42+
class="dot bg-green absolute start-[-1px] top-0 h-2.5 w-2.5 rounded-full"
43+
style="--dot-animation-state: {isPaused ? 'paused' : 'running'}"
44+
/>
45+
</div>
46+
47+
<div
48+
class="flex flex-col items-center justify-center gap-2 rounded-md border border-black/10 bg-white p-3"
49+
>
50+
<HugeiconsIcon icon={Database01FreeIcons} />
51+
<div class="text-sm font-semibold">{events[0].from}</div>
52+
<div class="text-xs text-gray-500">{events[0].vaultName}</div>
53+
</div>
54+
55+
<div
56+
class="absolute start-[50%] top-[200px] translate-x-[-50%] rounded-md bg-white p-3 text-center shadow"
57+
>
58+
<img src="/" alt="Icon" />
59+
<div class="text-xs text-gray-700">{events[1].from}</div>
60+
</div>
61+
62+
<div
63+
class="border-green flex flex-col items-center justify-center gap-2 rounded-md border bg-white p-3"
64+
>
65+
<HugeiconsIcon icon={Database01FreeIcons} />
66+
<div class="text-sm font-semibold">{events[2].from}</div>
67+
<div class="text-xs text-gray-500">{events[2].vaultName}</div>
68+
</div>
69+
</div>
70+
</article>
71+
72+
<style>
73+
.dot {
74+
offset-path: rect(0px 100% 175px 0px round 0%);
75+
offset-distance: 0%;
76+
offset-rotate: auto;
77+
animation: move 10s linear infinite;
78+
animation-play-state: var(--dot-animation-state, running);
79+
}
80+
81+
@keyframes move {
82+
0% {
83+
offset-distance: 100%;
84+
opacity: 1;
85+
}
86+
50% {
87+
opacity: 1;
88+
}
89+
55% {
90+
opacity: 0.4;
91+
}
92+
60% {
93+
opacity: 0;
94+
}
95+
100% {
96+
offset-distance: 0%;
97+
opacity: 0;
98+
}
99+
}
100+
</style>

0 commit comments

Comments
 (0)