From 619d532315a66d2f52551ccb570e77e4544cf96f Mon Sep 17 00:00:00 2001
From: Bernd Storath <999999bst@gmail.com>
Date: Mon, 5 Aug 2024 13:25:00 +0200
Subject: [PATCH] typescript, vendors
---
src/app.vue | 207 ++++++++++++++++++-------------
src/assets/css/app.css | 6 +
src/package.json | 6 +-
src/plugins/apexcharts.client.ts | 5 +
src/pnpm-lock.yaml | 113 +++++++++++++++++
src/public/manifest.json | 11 ++
src/utils/api.ts | 19 ++-
src/utils/localStorage.ts | 25 ++++
8 files changed, 306 insertions(+), 86 deletions(-)
create mode 100644 src/assets/css/app.css
create mode 100644 src/plugins/apexcharts.client.ts
create mode 100644 src/public/manifest.json
create mode 100644 src/utils/localStorage.ts
diff --git a/src/app.vue b/src/app.vue
index 692137d6..57971bff 100644
--- a/src/app.vue
+++ b/src/app.vue
@@ -26,10 +26,8 @@
-
- {{ client.transferTxCurrent | bytes }}/s
+ {{ bytes(client.transferTxCurrent) }}/s
@@ -229,13 +227,13 @@
d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
- {{ client.transferRxCurrent | bytes }}/s
+ {{ bytes(client.transferRxCurrent) }}/s
- {{ !uiTrafficStats ? " · " : "" }}{{ new Date(client.latestHandshakeAt) | timeago }}
+ {{ !uiTrafficStats ? " · " : "" }}{{ timeago(new Date(client.latestHandshakeAt)) }}
@@ -254,8 +252,7 @@
clip-rule="evenodd" />
-
{{ client.transferTxCurrent |
- bytes }}/s
+
{{ bytes(client.transferTxCurrent) }}/s
{{ bytes(client.transferTx)
}}
@@ -275,8 +272,7 @@
clip-rule="evenodd" />
- {{ client.transferRxCurrent |
- bytes }}/s
+ {{ bytes(client.transferRxCurrent) }}/s
{{ bytes(client.transferRx)
}}
@@ -601,10 +597,36 @@
\ No newline at end of file
diff --git a/src/assets/css/app.css b/src/assets/css/app.css
new file mode 100644
index 00000000..22a02051
--- /dev/null
+++ b/src/assets/css/app.css
@@ -0,0 +1,6 @@
+[v-cloak] {
+ display: none;
+ }
+ .line-chart .apexcharts-svg{
+ transform: translateY(3px);
+ }
\ No newline at end of file
diff --git a/src/package.json b/src/package.json
index 29119379..15eabe8b 100644
--- a/src/package.json
+++ b/src/package.json
@@ -18,11 +18,15 @@
"dependencies": {
"@nuxtjs/i18n": "^8.3.3",
"@nuxtjs/tailwindcss": "^6.12.1",
+ "apexcharts": "^3.51.0",
"bcryptjs": "^2.4.3",
"debug": "^4.3.6",
+ "js-sha256": "^0.11.0",
"nuxt": "^3.12.4",
"qrcode": "^1.5.3",
- "vue": "latest"
+ "timeago.js": "^4.0.2",
+ "vue": "latest",
+ "vue3-apexcharts": "^1.5.3"
},
"devDependencies": {
"@nuxt/eslint": "^0.5.0",
diff --git a/src/plugins/apexcharts.client.ts b/src/plugins/apexcharts.client.ts
new file mode 100644
index 00000000..43a40726
--- /dev/null
+++ b/src/plugins/apexcharts.client.ts
@@ -0,0 +1,5 @@
+import VueApexCharts from "vue3-apexcharts";
+
+export default defineNuxtPlugin((nuxtApp) => {
+ nuxtApp.vueApp.use(VueApexCharts);
+});
\ No newline at end of file
diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml
index b060abb1..8b00f5ac 100644
--- a/src/pnpm-lock.yaml
+++ b/src/pnpm-lock.yaml
@@ -14,21 +14,33 @@ importers:
'@nuxtjs/tailwindcss':
specifier: ^6.12.1
version: 6.12.1(magicast@0.3.4)(rollup@4.19.2)
+ apexcharts:
+ specifier: ^3.51.0
+ version: 3.51.0
bcryptjs:
specifier: ^2.4.3
version: 2.4.3
debug:
specifier: ^4.3.6
version: 4.3.6
+ js-sha256:
+ specifier: ^0.11.0
+ version: 0.11.0
nuxt:
specifier: ^3.12.4
version: 3.12.4(@parcel/watcher@2.4.1)(@types/node@22.0.2)(eslint@9.8.0)(ioredis@5.4.1)(magicast@0.3.4)(optionator@0.9.4)(rollup@4.19.2)(terser@5.31.3)(typescript@5.5.4)(vite@5.3.5(@types/node@22.0.2)(terser@5.31.3))(vue-tsc@2.0.29(typescript@5.5.4))
qrcode:
specifier: ^1.5.3
version: 1.5.3
+ timeago.js:
+ specifier: ^4.0.2
+ version: 4.0.2
vue:
specifier: latest
version: 3.4.35(typescript@5.5.4)
+ vue3-apexcharts:
+ specifier: ^1.5.3
+ version: 1.5.3(apexcharts@3.51.0)(vue@3.4.35(typescript@5.5.4))
devDependencies:
'@nuxt/eslint':
specifier: ^0.5.0
@@ -1450,6 +1462,9 @@ packages:
'@vue/shared@3.4.35':
resolution: {integrity: sha512-hvuhBYYDe+b1G8KHxsQ0diDqDMA8D9laxWZhNAjE83VZb5UDaXl9Xnz7cGdDSyiHM90qqI/CyGMcpBpiDy6VVQ==}
+ '@yr/monotone-cubic-spline@1.0.3':
+ resolution: {integrity: sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==}
+
abbrev@1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
@@ -1518,6 +1533,9 @@ packages:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
+ apexcharts@3.51.0:
+ resolution: {integrity: sha512-WpCdVdGiJjf9SAyEeg2rl3q5OqCcNqiEmH0+filMraUiH6Vqyn5GFeMMyH0pon44xjNr1G0xzIRERKRmsGEuRA==}
+
aproba@2.0.0:
resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
@@ -2701,6 +2719,9 @@ packages:
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
hasBin: true
+ js-sha256@0.11.0:
+ resolution: {integrity: sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -3898,6 +3919,37 @@ packages:
svg-tags@1.0.0:
resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
+ svg.draggable.js@2.2.2:
+ resolution: {integrity: sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==}
+ engines: {node: '>= 0.8.0'}
+
+ svg.easing.js@2.0.0:
+ resolution: {integrity: sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==}
+ engines: {node: '>= 0.8.0'}
+
+ svg.filter.js@2.0.2:
+ resolution: {integrity: sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==}
+ engines: {node: '>= 0.8.0'}
+
+ svg.js@2.7.1:
+ resolution: {integrity: sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==}
+
+ svg.pathmorphing.js@0.1.3:
+ resolution: {integrity: sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==}
+ engines: {node: '>= 0.8.0'}
+
+ svg.resize.js@1.4.3:
+ resolution: {integrity: sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==}
+ engines: {node: '>= 0.8.0'}
+
+ svg.select.js@2.1.2:
+ resolution: {integrity: sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==}
+ engines: {node: '>= 0.8.0'}
+
+ svg.select.js@3.0.1:
+ resolution: {integrity: sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==}
+ engines: {node: '>= 0.8.0'}
+
svgo@3.3.2:
resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==}
engines: {node: '>=14.0.0'}
@@ -3952,6 +4004,9 @@ packages:
thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ timeago.js@4.0.2:
+ resolution: {integrity: sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==}
+
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@@ -4302,6 +4357,12 @@ packages:
peerDependencies:
typescript: '>=5.0.0'
+ vue3-apexcharts@1.5.3:
+ resolution: {integrity: sha512-yaHTPoj0iVKAtEVg8wEwIwwvf0VG+lPYNufCf3txRzYQOqdKPoZaZ9P3Dj3X+2A1XY9O1kcTk9HVqvLo+rppvQ==}
+ peerDependencies:
+ apexcharts: '> 3.0.0'
+ vue: '> 3.0.0'
+
vue@3.4.35:
resolution: {integrity: sha512-+fl/GLmI4GPileHftVlCdB7fUL4aziPcqTudpTGXCT8s+iZWuOCeNEB5haX6Uz2IpRrbEXOgIFbe+XciCuGbNQ==}
peerDependencies:
@@ -6046,6 +6107,8 @@ snapshots:
'@vue/shared@3.4.35': {}
+ '@yr/monotone-cubic-spline@1.0.3': {}
+
abbrev@1.1.1: {}
abort-controller@3.0.0:
@@ -6107,6 +6170,16 @@ snapshots:
normalize-path: 3.0.0
picomatch: 2.3.1
+ apexcharts@3.51.0:
+ dependencies:
+ '@yr/monotone-cubic-spline': 1.0.3
+ svg.draggable.js: 2.2.2
+ svg.easing.js: 2.0.0
+ svg.filter.js: 2.0.2
+ svg.pathmorphing.js: 0.1.3
+ svg.resize.js: 1.4.3
+ svg.select.js: 3.0.1
+
aproba@2.0.0: {}
archiver-utils@5.0.2:
@@ -7390,6 +7463,8 @@ snapshots:
jiti@1.21.6: {}
+ js-sha256@0.11.0: {}
+
js-tokens@4.0.0: {}
js-tokens@9.0.0: {}
@@ -8732,6 +8807,37 @@ snapshots:
svg-tags@1.0.0: {}
+ svg.draggable.js@2.2.2:
+ dependencies:
+ svg.js: 2.7.1
+
+ svg.easing.js@2.0.0:
+ dependencies:
+ svg.js: 2.7.1
+
+ svg.filter.js@2.0.2:
+ dependencies:
+ svg.js: 2.7.1
+
+ svg.js@2.7.1: {}
+
+ svg.pathmorphing.js@0.1.3:
+ dependencies:
+ svg.js: 2.7.1
+
+ svg.resize.js@1.4.3:
+ dependencies:
+ svg.js: 2.7.1
+ svg.select.js: 2.1.2
+
+ svg.select.js@2.1.2:
+ dependencies:
+ svg.js: 2.7.1
+
+ svg.select.js@3.0.1:
+ dependencies:
+ svg.js: 2.7.1
+
svgo@3.3.2:
dependencies:
'@trysound/sax': 0.2.0
@@ -8828,6 +8934,8 @@ snapshots:
dependencies:
any-promise: 1.3.0
+ timeago.js@4.0.2: {}
+
tiny-invariant@1.3.3: {}
tinyrainbow@1.2.0: {}
@@ -9194,6 +9302,11 @@ snapshots:
semver: 7.6.3
typescript: 5.5.4
+ vue3-apexcharts@1.5.3(apexcharts@3.51.0)(vue@3.4.35(typescript@5.5.4)):
+ dependencies:
+ apexcharts: 3.51.0
+ vue: 3.4.35(typescript@5.5.4)
+
vue@3.4.35(typescript@5.5.4):
dependencies:
'@vue/compiler-dom': 3.4.35
diff --git a/src/public/manifest.json b/src/public/manifest.json
new file mode 100644
index 00000000..45c96b2f
--- /dev/null
+++ b/src/public/manifest.json
@@ -0,0 +1,11 @@
+{
+ "name": "WireGuard",
+ "display": "standalone",
+ "background_color": "#fff",
+ "icons": [
+ {
+ "src": "/favicon.png",
+ "type": "image/png"
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/src/utils/api.ts b/src/utils/api.ts
index 6628bfd9..1fb203c5 100644
--- a/src/utils/api.ts
+++ b/src/utils/api.ts
@@ -1,6 +1,21 @@
/* eslint-disable no-unused-vars */
/* eslint-disable no-undef */
+export type APIClient = {
+ "id": string,
+ "name": string,
+ "enabled": boolean,
+ "address": string,
+ "publicKey": string,
+ "createdAt": string,
+ "updatedAt": string,
+ "downloadableConfig": boolean,
+ "persistentKeepalive": string,
+ "latestHandshakeAt": null,
+ "transferRx": number,
+ "transferTx": number
+}
+
class API {
async call({ method, path, body }: {
@@ -66,7 +81,7 @@ class API {
});
}
- async createSession({ password }: {password: string}) {
+ async createSession({ password }: {password: string|null}) {
return this.call({
method: 'post',
path: '/session',
@@ -85,7 +100,7 @@ class API {
return this.call({
method: 'get',
path: '/wireguard/client',
- }).then((clients) => clients.map((client) => ({
+ }).then((clients: APIClient[]) => clients.map((client) => ({
...client,
createdAt: new Date(client.createdAt),
updatedAt: new Date(client.updatedAt),
diff --git a/src/utils/localStorage.ts b/src/utils/localStorage.ts
new file mode 100644
index 00000000..7e7c692f
--- /dev/null
+++ b/src/utils/localStorage.ts
@@ -0,0 +1,25 @@
+export type Theme = 'light' | 'dark' | 'auto'
+
+export type LocalStorage = {
+ theme: Theme,
+ uiShowCharts: '1' | '0',
+ lang: string
+}
+
+export function getItem(item: K): LocalStorage[K]|null {
+if (import.meta.client) {
+ return localStorage.getItem(item) as LocalStorage[K]|null
+} else {
+ return null
+}
+}
+
+export function setItem(item: K, value: LocalStorage[K]) {
+ if (import.meta.client) {
+ localStorage.setItem(item, value)
+
+ return true
+ } else {
+ return false
+ }
+ }
\ No newline at end of file