Browse Source

fix even more stuff

pull/1666/head
Bernd Storath 6 months ago
parent
commit
5a115e33e3
  1. 3
      src/app/app.vue
  2. 3
      src/app/components/Base/Dialog.vue
  3. 44
      src/app/components/ClientCard/OneTimeLink.vue
  4. 40
      src/app/components/ClientCard/OneTimeLinkBtn.vue
  5. 4
      src/app/components/ClientCard/QRCode.vue
  6. 41
      src/app/components/ClientCard/Switch.vue
  7. 4
      src/app/components/Form/DateField.vue
  8. 9
      src/app/components/Form/Label.vue
  9. 4
      src/app/components/Form/NullTextField.vue
  10. 4
      src/app/components/Form/NumberField.vue
  11. 4
      src/app/components/Form/PasswordField.vue
  12. 4
      src/app/components/Form/SwitchField.vue
  13. 4
      src/app/components/Form/TextField.vue
  14. 15
      src/app/components/Icons/Link.vue
  15. 3
      src/app/components/Ui/Footer.vue
  16. 2
      src/app/pages/setup/4.vue
  17. 21
      src/app/stores/global.ts
  18. 1
      src/server/utils/Database.ts
  19. 4
      src/server/utils/WireGuard.ts
  20. 2
      src/server/utils/types.ts

3
src/app/app.vue

@ -16,6 +16,9 @@ const toast = useToast();
const toastRef = useTemplateRef('toastRef');
toast.setToast(toastRef);
// make sure to fetch release early
useGlobalStore();
useHead({
bodyAttrs: {
class: 'bg-gray-50 dark:bg-neutral-800',

3
src/app/components/Base/Dialog.vue

@ -3,7 +3,7 @@
<DialogTrigger :class="triggerClass"><slot name="trigger" /></DialogTrigger>
<DialogPortal>
<DialogOverlay
class="data-[state=open]:animate-overlayShow fixed inset-0 z-30 bg-gray-500 opacity-75 dark:bg-black dark:opacity-50"
class="fixed inset-0 z-30 bg-gray-500 opacity-75 dark:bg-black dark:opacity-50"
/>
<DialogContent
class="fixed left-1/2 top-1/2 z-[100] max-h-[85vh] w-[90vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-md p-6 shadow-2xl focus:outline-none dark:bg-neutral-700"
@ -27,6 +27,5 @@
</template>
<script lang="ts" setup>
// TODO: improve
defineProps<{ triggerClass?: string }>();
</script>

44
src/app/components/ClientCard/OneTimeLink.vue

@ -7,11 +7,45 @@
<script setup lang="ts">
const props = defineProps<{ client: LocalClient }>();
const path = computed(() => {
if (import.meta.client) {
// TODO: show how long its still valid
return `${document.location.protocol}//${document.location.host}/cnf/${props.client.oneTimeLink?.oneTimeLink}`;
const path = ref('Loading...');
const timer = ref<NodeJS.Timeout | null>(null);
const { localeProperties } = useI18n();
onMounted(() => {
timer.value = setInterval(() => {
if (props.client.oneTimeLink === null) {
return;
}
const timeLeft =
new Date(props.client.oneTimeLink.expiresAt).getTime() - Date.now();
if (timeLeft <= 0) {
path.value = `${document.location.protocol}//${document.location.host}/cnf/${props.client.oneTimeLink.oneTimeLink} (00:00)`;
return;
}
const formatter = new Intl.DateTimeFormat(localeProperties.value.language, {
minute: '2-digit',
second: '2-digit',
hourCycle: 'h23',
});
const minutes = Math.floor(timeLeft / 60000);
const seconds = Math.floor((timeLeft % 60000) / 1000);
const date = new Date(0);
date.setMinutes(minutes);
date.setSeconds(seconds);
path.value = `${document.location.protocol}//${document.location.host}/cnf/${props.client.oneTimeLink.oneTimeLink} (${formatter.format(date)})`;
}, 1000);
});
onUnmounted(() => {
if (timer.value) {
clearTimeout(timer.value);
}
return 'Loading...';
});
</script>

40
src/app/components/ClientCard/OneTimeLinkBtn.vue

@ -2,37 +2,31 @@
<button
class="inline-block rounded bg-gray-100 p-2 align-middle transition hover:bg-red-800 hover:text-white dark:bg-neutral-600 dark:text-neutral-300 dark:hover:bg-red-800 dark:hover:text-white"
:title="$t('client.otlDesc')"
@click="showOneTimeLink(client)"
@click="showOneTimeLink"
>
<svg
class="w-5"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13.213 9.787a3.391 3.391 0 0 0-4.795 0l-3.425 3.426a3.39 3.39 0 0 0 4.795 4.794l.321-.304m-.321-4.49a3.39 3.39 0 0 0 4.795 0l3.424-3.426a3.39 3.39 0 0 0-4.794-4.795l-1.028.961"
/>
</svg>
<IconsLink class="w-5" />
</button>
</template>
<script setup lang="ts">
// TODO: improve
defineProps<{ client: LocalClient }>();
const props = defineProps<{ client: LocalClient }>();
const clientsStore = useClientsStore();
function showOneTimeLink(client: LocalClient) {
// TODO: improve
$fetch(`/api/client/${client.id}/generateOneTimeLink`, {
const _showOneTimeLink = useSubmit(
`/api/client/${props.client.id}/generateOneTimeLink`,
{
method: 'post',
})
.catch((err) => alert(err.message || err.toString()))
.finally(() => clientsStore.refresh().catch(console.error));
},
{
revert: async () => {
await clientsStore.refresh();
},
noSuccessToast: true,
}
);
function showOneTimeLink() {
return _showOneTimeLink(undefined);
}
</script>

4
src/app/components/ClientCard/QRCode.vue

@ -1,11 +1,11 @@
<template>
<ClientsQRCodeDialog :qr-code="`./api/client/${client.id}/qrcode.svg`">
<button
<div
class="rounded bg-gray-100 p-2 align-middle transition hover:bg-red-800 hover:text-white dark:bg-neutral-600 dark:text-neutral-300 dark:hover:bg-red-800 dark:hover:text-white"
:title="$t('client.showQR')"
>
<IconsQRCode class="w-5" />
</button>
</div>
</ClientsQRCodeDialog>
</template>

41
src/app/components/ClientCard/Switch.vue

@ -17,22 +17,37 @@ const enabled = ref(props.client.enabled);
const clientsStore = useClientsStore();
async function toggleClient() {
// Improve
try {
if (props.client.enabled) {
await $fetch(`/api/client/${props.client.id}/disable`, {
const _disableClient = useSubmit(
`/api/client/${props.client.id}/disable`,
{
method: 'post',
});
} else {
await $fetch(`/api/client/${props.client.id}/enable`, {
},
{
revert: async () => {
await clientsStore.refresh();
},
noSuccessToast: true,
}
);
const _enableClient = useSubmit(
`/api/client/${props.client.id}/enable`,
{
method: 'post',
});
},
{
revert: async () => {
await clientsStore.refresh();
},
noSuccessToast: true,
}
} catch (err) {
alert(err);
} finally {
clientsStore.refresh().catch(console.error);
);
async function toggleClient() {
if (props.client.enabled) {
await _disableClient(undefined);
} else {
await _enableClient(undefined);
}
}
</script>

4
src/app/components/Form/DateField.vue

@ -1,7 +1,7 @@
<template>
<Label :for="id" class="font-semibold md:align-middle md:leading-10">
<FormLabel :for="id">
{{ label }}
</Label>
</FormLabel>
<BaseInput :id="id" v-model="data" :name="id" type="date" />
</template>

9
src/app/components/Form/Label.vue

@ -0,0 +1,9 @@
<template>
<RLabel :for="id" class="md:align-middle md:leading-10"><slot /></RLabel>
</template>
<script lang="ts" setup>
import { Label as RLabel } from 'radix-vue';
defineProps<{ id: string }>();
</script>

4
src/app/components/Form/NullTextField.vue

@ -1,8 +1,8 @@
<template>
<div class="flex items-center">
<Label :for="id" class="font-semibold md:align-middle md:leading-10">
<FormLabel :for="id">
{{ label }}
</Label>
</FormLabel>
<BaseTooltip v-if="description" :text="description">
<IconsInfo class="size-4" />
</BaseTooltip>

4
src/app/components/Form/NumberField.vue

@ -1,8 +1,8 @@
<template>
<div class="flex items-center">
<Label :for="id" class="font-semibold md:align-middle md:leading-10">
<FormLabel :for="id">
{{ label }}
</Label>
</FormLabel>
<BaseTooltip v-if="description" :text="description">
<IconsInfo class="size-4" />
</BaseTooltip>

4
src/app/components/Form/PasswordField.vue

@ -1,7 +1,7 @@
<template>
<Label :for="id" class="font-semibold md:align-middle md:leading-10">
<FormLabel :for="id">
{{ label }}
</Label>
</FormLabel>
<BaseInput
:id="id"
v-model.trim="data"

4
src/app/components/Form/SwitchField.vue

@ -1,8 +1,8 @@
<template>
<div class="flex items-center">
<Label :for="id" class="font-semibold md:align-middle md:leading-10">
<FormLabel :for="id">
{{ label }}
</Label>
</FormLabel>
<BaseTooltip v-if="description" :text="description">
<IconsInfo class="size-4" />
</BaseTooltip>

4
src/app/components/Form/TextField.vue

@ -1,8 +1,8 @@
<template>
<div class="flex items-center">
<Label :for="id" class="font-semibold md:align-middle md:leading-10">
<FormLabel :for="id">
{{ label }}
</Label>
</FormLabel>
<BaseTooltip v-if="description" :text="description">
<IconsInfo class="size-4" />
</BaseTooltip>

15
src/app/components/Icons/Link.vue

@ -0,0 +1,15 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13.213 9.787a3.391 3.391 0 0 0-4.795 0l-3.425 3.426a3.39 3.39 0 0 0 4.795 4.794l.321-.304m-.321-4.49a3.39 3.39 0 0 0 4.795 0l3.424-3.426a3.39 3.39 0 0 0-4.794-4.795l-1.028.961"
/>
</svg>
</template>

3
src/app/components/Ui/Footer.vue

@ -7,7 +7,7 @@
href="https://github.com/wg-easy/wg-easy"
>WireGuard Easy</a
>
({{ globalStore.currentRelease }}) © 2021-2025 by
({{ globalStore.release?.currentRelease }}) © 2021-2025 by
<a
class="hover:underline"
target="_blank"
@ -34,5 +34,4 @@
<script lang="ts" setup>
const globalStore = useGlobalStore();
globalStore.fetchRelease();
</script>

2
src/app/pages/setup/4.vue

@ -47,7 +47,7 @@ const _submit = useSubmit(
{
revert: async (success) => {
if (success) {
await navigateTo('/setup/5');
await navigateTo('/setup/success');
}
},
}

21
src/app/stores/global.ts

@ -5,22 +5,6 @@ export const useGlobalStore = defineStore('Global', () => {
const sortClient = ref(true); // Sort clients by name, true = asc, false = desc
const currentRelease = ref<null | string>(null);
const latestRelease = ref<null | { version: string; changelog: string }>(
null
);
const updateAvailable = ref(false);
async function fetchRelease() {
if (!release.value) {
return;
}
currentRelease.value = release.value.currentRelease;
latestRelease.value = release.value.latestRelease;
updateAvailable.value = release.value.updateAvailable;
}
const uiShowCharts = ref(getItem('uiShowCharts') === '1');
function toggleCharts() {
@ -31,10 +15,7 @@ export const useGlobalStore = defineStore('Global', () => {
return {
sortClient,
currentRelease,
latestRelease,
updateAvailable,
fetchRelease,
release,
uiShowCharts,
toggleCharts,
uiChartType,

1
src/server/utils/Database.ts

@ -21,5 +21,4 @@ connect().then((db) => {
WireGuard.Startup();
});
// TODO: check if old config exists and tell user about migration path
export default provider;

4
src/server/utils/WireGuard.ts

@ -208,15 +208,15 @@ class WireGuard {
await Database.clients.toggle(client.id, false);
}
}
// One Time Link Feature
for (const client of clients) {
if (
client.oneTimeLink !== null &&
new Date() > new Date(client.oneTimeLink.expiresAt)
) {
console.log(client);
WG_DEBUG(`Client ${client.id} One Time Link expired.`);
await Database.oneTimeLinks.delete(client.id);
await Database.oneTimeLinks.delete(client.oneTimeLink.id);
}
}

2
src/server/utils/types.ts

@ -19,8 +19,6 @@ export const safeStringRefine = z
{ message: t('zod.stringMalformed') }
);
// TODO: create custom getValidatedRouterParams and readValidatedBody wrapper
export const EnabledSchema = z.boolean({ message: t('zod.enabled') });
export const MtuSchema = z

Loading…
Cancel
Save