Browse Source

App.vue: Formatting

pull/937/head
Daniil Isakov 3 years ago
committed by Sergei Birukov
parent
commit
b232c4862b
  1. 266
      webui/src/App.vue

266
webui/src/App.vue

@ -1,12 +1,12 @@
<script>
import { ref, reactive } from "vue";
import { ref, reactive } from 'vue';
class API {
async call({ method, path, body }) {
const res = await fetch(`./api${path}`, {
method,
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
});
@ -26,79 +26,82 @@ class API {
async getRelease() {
return this.call({
method: "get",
path: "/release",
method: 'get',
path: '/release',
});
}
async getSession() {
return this.call({
method: "get",
path: "/session",
method: 'get',
path: '/session',
});
}
async createSession({ password }) {
return this.call({
method: "post",
path: "/session",
method: 'post',
path: '/session',
body: { password },
});
}
async deleteSession() {
return this.call({
method: "delete",
path: "/session",
method: 'delete',
path: '/session',
});
}
async getClients() {
return this.call({
method: "get",
path: "/wireguard/client",
method: 'get',
path: '/wireguard/client',
}).then((clients) =>
clients.map((client) => ({
...client,
createdAt: new Date(client.createdAt),
updatedAt: new Date(client.updatedAt),
latestHandshakeAt: client.latestHandshakeAt !== null ? new Date(client.latestHandshakeAt) : null,
latestHandshakeAt:
client.latestHandshakeAt !== null
? new Date(client.latestHandshakeAt)
: null,
}))
);
}
async createClient({ name }) {
return this.call({
method: "post",
path: "/wireguard/client",
method: 'post',
path: '/wireguard/client',
body: { name },
});
}
async deleteClient({ clientId }) {
return this.call({
method: "delete",
method: 'delete',
path: `/wireguard/client/${clientId}`,
});
}
async enableClient({ clientId }) {
return this.call({
method: "post",
method: 'post',
path: `/wireguard/client/${clientId}/enable`,
});
}
async disableClient({ clientId }) {
return this.call({
method: "post",
method: 'post',
path: `/wireguard/client/${clientId}/disable`,
});
}
async updateClientName({ clientId, name }) {
return this.call({
method: "put",
method: 'put',
path: `/wireguard/client/${clientId}/name/`,
body: { name },
});
@ -106,7 +109,7 @@ class API {
async updateClientAddress({ clientId, address }) {
return this.call({
method: "put",
method: 'put',
path: `/wireguard/client/${clientId}/address/`,
body: { address },
});
@ -124,7 +127,7 @@ export default {
const clientsPersist = reactive({});
const clientDelete = ref(null);
const clientCreate = ref(null);
const clientCreateName = ref("");
const clientCreateName = ref('');
const clientEditName = ref(null);
const clientEditNameId = ref(null);
const clientEditAddress = ref(null);
@ -138,8 +141,8 @@ export default {
const chartOptions = reactive({
chart: {
background: "transparent",
type: "bar",
background: 'transparent',
type: 'bar',
stacked: false,
toolbar: {
show: false,
@ -149,8 +152,8 @@ export default {
},
},
colors: [
"#DDDDDD", // rx
"#EEEEEE", // tx
'#DDDDDD', // rx
'#EEEEEE', // tx
],
dataLabels: {
enabled: false,
@ -206,11 +209,11 @@ export default {
const dateTime = (value) => {
return new Intl.DateTimeFormat(undefined, {
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
minute: "numeric",
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
}).format(value);
};
@ -219,9 +222,11 @@ export default {
const clientsData = await api.getClients();
clients.value = clientsData.map((client) => {
if (client.name.includes("@") && client.name.includes(".")) {
if (client.name.includes('@') && client.name.includes('.')) {
// FIXME: add "sha512"
client.avatar = `https://www.gravatar.com/avatar/${sha512(client.name)}?d=blank`;
client.avatar = `https://www.gravatar.com/avatar/${sha512(
client.name
)}?d=blank`;
}
if (!clientsPersist[client.id]) {
@ -244,10 +249,14 @@ export default {
client.transferTx - clientsPersist[client.id].transferTxPrevious;
clientsPersist[client.id].transferTxPrevious = client.transferTx;
clientsPersist[client.id].transferRxHistory.push(clientsPersist[client.id].transferRxCurrent);
clientsPersist[client.id].transferRxHistory.push(
clientsPersist[client.id].transferRxCurrent
);
clientsPersist[client.id].transferRxHistory.shift();
clientsPersist[client.id].transferTxHistory.push(clientsPersist[client.id].transferTxCurrent);
clientsPersist[client.id].transferTxHistory.push(
clientsPersist[client.id].transferTxCurrent
);
clientsPersist[client.id].transferTxHistory.shift();
}
@ -256,7 +265,10 @@ export default {
client.transferTxHistory = clientsPersist[client.id].transferTxHistory;
client.transferRxHistory = clientsPersist[client.id].transferRxHistory;
client.transferMax = Math.max(...client.transferTxHistory, ...client.transferRxHistory);
client.transferMax = Math.max(
...client.transferTxHistory,
...client.transferRxHistory
);
client.hoverTx = clientsPersist[client.id].hoverTx;
client.hoverRx = clientsPersist[client.id].hoverRx;
@ -272,7 +284,8 @@ export default {
if (authenticating.value) return;
authenticating.value = true;
api.createSession({
api
.createSession({
password: password.value,
})
.then(async () => {
@ -293,7 +306,8 @@ export default {
const logout = (e) => {
e.preventDefault();
api.deleteSession()
api
.deleteSession()
.then(() => {
authenticated.value = false;
clients.value = null;
@ -307,48 +321,54 @@ export default {
const name = clientCreateName.value;
if (!name) return;
api.createClient({ name })
api
.createClient({ name })
.catch((err) => alert(err.message || err.toString()))
.finally(() => refresh().catch(console.error));
};
const deleteClient = (client) => {
api.deleteClient({ clientId: client.id })
api
.deleteClient({ clientId: client.id })
.catch((err) => alert(err.message || err.toString()))
.finally(() => refresh().catch(console.error));
};
const enableClient = (client) => {
api.enableClient({ clientId: client.id })
api
.enableClient({ clientId: client.id })
.catch((err) => alert(err.message || err.toString()))
.finally(() => refresh().catch(console.error));
};
const disableClient = (client) => {
api.disableClient({ clientId: client.id })
api
.disableClient({ clientId: client.id })
.catch((err) => alert(err.message || err.toString()))
.finally(() => refresh().catch(console.error));
};
const updateClientName = (client, name) => {
api.updateClientName({ clientId: client.id, name })
api
.updateClientName({ clientId: client.id, name })
.catch((err) => alert(err.message || err.toString()))
.finally(() => refresh().catch(console.error));
};
const updateClientAddress = (client, address) => {
api.updateClientAddress({ clientId: client.id, address })
api
.updateClientAddress({ clientId: client.id, address })
.catch((err) => alert(err.message || err.toString()))
.finally(() => refresh().catch(console.error));
};
const toggleTheme = () => {
if (isDark.value) {
localStorage.theme = "light";
document.documentElement.classList.remove("dark");
localStorage.theme = 'light';
document.documentElement.classList.remove('dark');
} else {
localStorage.theme = "dark";
document.documentElement.classList.add("dark");
localStorage.theme = 'dark';
document.documentElement.classList.add('dark');
}
isDark.value = !isDark.value;
};
@ -394,7 +414,7 @@ export default {
},
mounted() {
this.isDark = false;
if (localStorage.theme === "dark") {
if (localStorage.theme === 'dark') {
this.isDark = true;
}
@ -423,13 +443,17 @@ export default {
Promise.resolve()
.then(async () => {
const currentReleaseData = await this.api.getRelease();
const latestReleaseData = await fetch("https://wg-easy.github.io/wg-easy/changelog.json")
const latestReleaseData = await fetch(
'https://wg-easy.github.io/wg-easy/changelog.json'
)
.then((res) => res.json())
.then((releases) => {
const releasesArray = Object.entries(releases).map(([version, changelog]) => ({
const releasesArray = Object.entries(releases).map(
([version, changelog]) => ({
version: parseInt(version, 10),
changelog,
}));
})
);
releasesArray.sort((a, b) => {
return b.version - a.version;
});
@ -484,7 +508,11 @@ export default {
</svg>
</span>
<h1 class="text-4xl dark:text-neutral-200 font-medium mt-2 mb-2">
<img src="./assets/img/logo.png" width="32" class="inline align-middle dark:bg" />
<img
src="./assets/img/logo.png"
width="32"
class="inline align-middle dark:bg"
/>
<span class="align-middle">WireGuard</span>
</h1>
<h2 class="text-sm text-gray-400 dark:text-neutral-400 mb-10"></h2>
@ -510,7 +538,9 @@ export default {
</div>
</div>
<div class="shadow-md rounded-lg bg-white dark:bg-neutral-700 overflow-hidden">
<div
class="shadow-md rounded-lg bg-white dark:bg-neutral-700 overflow-hidden"
>
<div
class="flex flex-row flex-auto items-center p-3 px-5 border-b-2 border-gray-100 dark:border-neutral-600"
>
@ -575,7 +605,9 @@ export default {
</apexchart>
</div> -->
<div class="relative p-5 z-10 flex flex-col md:flex-row justify-between">
<div
class="relative p-5 z-10 flex flex-col md:flex-row justify-between"
>
<div class="flex items-center pb-2 md:pb-0">
<div class="h-10 w-10 mr-5 rounded-full bg-gray-50 relative">
<svg
@ -599,7 +631,8 @@ export default {
<div
v-if="
client.latestHandshakeAt &&
new Date() - new Date(client.latestHandshakeAt) < 1000 * 60 * 10
new Date() - new Date(client.latestHandshakeAt) <
1000 * 60 * 10
"
>
<div
@ -615,7 +648,9 @@ export default {
<!-- Name -->
<div
class="text-gray-700 dark:text-neutral-200 group"
:title="'Created on ' + dateTime(new Date(client.createdAt))"
:title="
'Created on ' + dateTime(new Date(client.createdAt))
"
>
<!-- Show -->
<input
@ -646,7 +681,10 @@ export default {
clientEditName = client.name;
clientEditNameId = client.id;
setTimeout(
() => $refs['client-' + client.id + '-name'][0].select(),
() =>
$refs[
'client-' + client.id + '-name'
][0].select(),
1
);
"
@ -702,7 +740,10 @@ export default {
clientEditAddress = client.address;
clientEditAddressId = client.id;
setTimeout(
() => $refs['client-' + client.id + '-address'][0].select(),
() =>
$refs[
'client-' + client.id + '-address'
][0].select(),
1
);
"
@ -774,7 +815,10 @@ export default {
<!-- Last seen -->
<span
v-if="client.latestHandshakeAt"
:title="'Last seen on ' + dateTime(new Date(client.latestHandshakeAt))"
:title="
'Last seen on ' +
dateTime(new Date(client.latestHandshakeAt))
"
>
<!-- FIXME: add "timeago" -->
<!-- · {{ new Date(client.latestHandshakeAt) | timeago }} -->
@ -810,7 +854,9 @@ export default {
<button
class="align-middle bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 hover:bg-red-800 dark:hover:bg-red-800 hover:text-white dark:hover:text-white p-2 rounded transition"
title="Show QR Code"
@click="qrcode = `./api/wireguard/client/${client.id}/qrcode.svg`"
@click="
qrcode = `./api/wireguard/client/${client.id}/qrcode.svg`
"
>
<svg
class="w-5"
@ -830,7 +876,9 @@ export default {
<!-- Download Config -->
<a
:href="'./api/wireguard/client/' + client.id + '/configuration'"
:href="
'./api/wireguard/client/' + client.id + '/configuration'
"
download
class="align-middle inline-block bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 hover:bg-red-800 dark:hover:bg-red-800 hover:text-white dark:hover:text-white p-2 rounded transition"
title="Download Configuration"
@ -875,7 +923,9 @@ export default {
</div>
</div>
<div v-if="clients && clients.length === 0">
<p class="text-center m-10 text-gray-400 dark:text-neutral-400 text-sm">
<p
class="text-center m-10 text-gray-400 dark:text-neutral-400 text-sm"
>
There are no clients yet.<br /><br />
<button
@click="
@ -903,7 +953,10 @@ export default {
</button>
</p>
</div>
<div v-if="clients === null" class="text-gray-200 dark:text-red-300 p-5">
<div
v-if="clients === null"
class="text-gray-200 dark:text-red-300 p-5"
>
<svg
class="w-5 animate-spin mx-auto"
xmlns="http://www.w3.org/2000/svg"
@ -974,11 +1027,15 @@ export default {
To: "opacity-0"
-->
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 dark:bg-black opacity-75 dark:opacity-50"></div>
<div
class="absolute inset-0 bg-gray-500 dark:bg-black opacity-75 dark:opacity-50"
></div>
</div>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true"
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>&#8203;</span
>
<!--
@ -997,7 +1054,9 @@ export default {
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white dark:bg-neutral-700 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div
class="bg-white dark:bg-neutral-700 px-4 pt-5 pb-4 sm:p-6 sm:pb-4"
>
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-800 sm:mx-0 sm:h-10 sm:w-10"
@ -1018,7 +1077,9 @@ export default {
/>
</svg>
</div>
<div class="flex-grow mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<div
class="flex-grow mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"
>
<h3
class="text-lg leading-6 font-medium text-gray-900 dark:text-neutral-200"
id="modal-headline"
@ -1038,7 +1099,9 @@ export default {
</div>
</div>
</div>
<div class="bg-gray-50 dark:bg-neutral-700 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<div
class="bg-gray-50 dark:bg-neutral-700 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"
>
<button
v-if="clientCreateName.length"
type="button"
@ -1085,11 +1148,15 @@ export default {
To: "opacity-0"
-->
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 dark:bg-black opacity-75 dark:opacity-50"></div>
<div
class="absolute inset-0 bg-gray-500 dark:bg-black opacity-75 dark:opacity-50"
></div>
</div>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true"
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>&#8203;</span
>
<!--
@ -1108,7 +1175,9 @@ export default {
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white dark:bg-neutral-700 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div
class="bg-white dark:bg-neutral-700 px-4 pt-5 pb-4 sm:p-6 sm:pb-4"
>
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10"
@ -1139,14 +1208,17 @@ export default {
</h3>
<div class="mt-2">
<p class="text-sm text-gray-500 dark:text-neutral-300">
Are you sure you want to delete <strong>{{ clientDelete.name }}</strong
Are you sure you want to delete
<strong>{{ clientDelete.name }}</strong
>? This action cannot be undone.
</p>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 dark:bg-neutral-600 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<div
class="bg-gray-50 dark:bg-neutral-600 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"
>
<button
type="button"
@click="
@ -1171,7 +1243,11 @@ export default {
</div>
<div v-if="authenticated === false">
<h1 class="text-4xl font-medium my-16 text-gray-700 dark:text-neutral-200 text-center">WireGuard</h1>
<h1
class="text-4xl font-medium my-16 text-gray-700 dark:text-neutral-200 text-center"
>
WireGuard
</h1>
<form
@submit="login"
@ -1243,14 +1319,24 @@ export default {
</form>
</div>
<div v-if="authenticated === null" class="text-gray-300 dark:text-red-300 pt-24 pb-12">
<div
v-if="authenticated === null"
class="text-gray-300 dark:text-red-300 pt-24 pb-12"
>
<svg
class="w-5 animate-spin mx-auto"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<circle
class="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
></circle>
<path
class="opacity-75"
fill="currentColor"
@ -1260,11 +1346,31 @@ export default {
</div>
</div>
<p v-cloak class="text-center m-10 text-gray-300 dark:text-neutral-600 text-xs">
<p
v-cloak
class="text-center m-10 text-gray-300 dark:text-neutral-600 text-xs"
>
Made by
<a target="_blank" class="hover:underline" href="https://emilenijssen.nl/?ref=wg-easy">Emile Nijssen</a> ·
<a class="hover:underline" href="https://github.com/sponsors/WeeJeWel" target="_blank">Donate</a> ·
<a class="hover:underline" href="https://github.com/wg-easy/wg-easy" target="_blank">GitHub</a>
<a
target="_blank"
class="hover:underline"
href="https://emilenijssen.nl/?ref=wg-easy"
>Emile Nijssen</a
>
·
<a
class="hover:underline"
href="https://github.com/sponsors/WeeJeWel"
target="_blank"
>Donate</a
>
·
<a
class="hover:underline"
href="https://github.com/wg-easy/wg-easy"
target="_blank"
>GitHub</a
>
</p>
</main>
</template>

Loading…
Cancel
Save