Browse Source

update frontend

pull/1244/head
Bernd Storath 12 months ago
parent
commit
331b546480
  1. 4
      src/app.vue
  2. 38
      src/components/Client/ExpireDate.vue
  3. 19
      src/components/Client/OneTimeLink.vue
  4. 3
      src/components/Client/OneTimeLinkBtn.vue
  5. 12
      src/components/Clients/Sort.vue
  6. 12
      src/i18n.config.ts
  7. 8
      src/pages/login.vue
  8. 2
      src/server/utils/WireGuard.ts
  9. 4
      src/stores/auth.ts
  10. 2
      src/stores/clients.ts
  11. 29
      src/stores/global.ts
  12. 2
      src/stores/modal.ts
  13. 2
      src/utils/api.ts

4
src/app.vue

@ -11,6 +11,10 @@ const globalStore = useGlobalStore();
globalStore.fetchTrafficStats();
globalStore.fetchChartType();
globalStore.fetchRelease();
globalStore.fetchOneTimeLinks();
globalStore.fetchSortClients();
globalStore.fetchExpireTime();
globalStore.fetchRememberMe();
useHead({
bodyAttrs: {
class: 'bg-gray-50 dark:bg-neutral-800',

38
src/components/Client/ExpireDate.vue

@ -7,40 +7,37 @@
<!-- Show -->
<input
v-show="clientEditExpireDateId === client.id"
ref="clientExpireDateInput"
v-model="clientEditExpireDate"
v-on:keyup.enter="
type="text"
class="rounded border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 outline-none w-70 text-black dark:text-neutral-300 dark:placeholder:text-neutral-500 text-xs p-0"
@keyup.enter="
updateClientExpireDate(client, clientEditExpireDate);
clientEditExpireDate = null;
clientEditExpireDateId = null;
"
v-on:keyup.escape="
@keyup.escape="
clientEditExpireDate = null;
clientEditExpireDateId = null;
"
:ref="'client-' + client.id + '-expire'"
type="text"
class="rounded border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 outline-none w-70 text-black dark:text-neutral-300 dark:placeholder:text-neutral-500 text-xs p-0"
/>
<span
v-show="clientEditExpireDateId !== client.id"
class="inline-block"
>{{ client.expiredAt | expiredDateFormat }}</span
>{{ expiredDateFormat(client.expireAt) }}</span
>
<!-- Edit -->
<span
v-show="clientEditExpireDateId !== client.id"
class="cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity"
@click="
clientEditExpireDate = client.expiredAt
? client.expiredAt.toISOString().slice(0, 10)
clientEditExpireDate = client.expireAt
? client.expireAt.slice(0, 10)
: 'yyyy-mm-dd';
clientEditExpireDateId = client.id;
setTimeout(
() => $refs['client-' + client.id + '-expire'][0].select(),
1
);
nextTick(() => clientExpireDateInput?.select());
"
class="cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -66,6 +63,11 @@ defineProps<{ client: LocalClient }>();
const globalStore = useGlobalStore();
const clientsStore = useClientsStore();
const clientEditExpireDate = ref<string | null>(null);
const clientEditExpireDateId = ref<string | null>(null);
const { t, locale } = useI18n();
const clientExpireDateInput = ref<HTMLInputElement | null>(null);
function updateClientExpireDate(
client: LocalClient,
@ -76,4 +78,14 @@ function updateClientExpireDate(
.catch((err) => alert(err.message || err.toString()))
.finally(() => clientsStore.refresh().catch(console.error));
}
function expiredDateFormat(value: string | null) {
if (value === null) return t('Permanent');
const dateTime = new Date(value);
return dateTime.toLocaleDateString(locale.value, {
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
</script>

19
src/components/Client/OneTimeLink.vue

@ -1,21 +1,26 @@
<template>
<div
v-if="
enableOneTimeLinks &&
globalStore.enableOneTimeLinks &&
client.oneTimeLink !== null &&
client.oneTimeLink !== ''
"
:ref="'client-' + client.id + '-link'"
class="text-gray-400 text-xs"
>
<a :href="'./cnf/' + client.oneTimeLink + ''"
>{{ document.location.protocol }}//{{ document.location.host }}/cnf/{{
client.oneTimeLink
}}</a
>
<a :href="'./cnf/' + client.oneTimeLink + ''">{{ path }}</a>
</div>
</template>
<script setup lang="ts">
defineProps<{ client: LocalClient }>();
const props = defineProps<{ client: LocalClient }>();
const globalStore = useGlobalStore();
const path = computed(() => {
if (import.meta.client) {
return `${document.location.protocol}//${document.location.host}/cnf/${props.client.oneTimeLink}`;
}
return '';
});
</script>

3
src/components/Client/OneTimeLinkBtn.vue

@ -1,6 +1,6 @@
<template>
<button
v-if="enableOneTimeLinks"
v-if="globalStore.enableOneTimeLinks"
:disabled="!client.downloadableConfig"
class="align-middle inline-block bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 p-2 rounded transition"
:class="{
@ -36,6 +36,7 @@
defineProps<{ client: LocalClient }>();
const clientsStore = useClientsStore();
const globalStore = useGlobalStore();
function showOneTimeLink(client: LocalClient) {
api

12
src/components/Clients/Sort.vue

@ -1,11 +1,11 @@
<template>
<button
v-if="enableSortClient"
@click="sortClient = !sortClient"
v-if="globalStore.enableSortClient"
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 dark:text-neutral-200 max-md:border-x-0 border-2 border-gray-100 dark:border-neutral-600 py-2 px-4 md:rounded inline-flex items-center transition"
@click="globalStore.sortClient = !globalStore.sortClient"
>
<svg
v-if="sortClient === true"
v-if="globalStore.sortClient === true"
inline
class="w-4 md:mr-2"
xmlns="http://www.w3.org/2000/svg"
@ -24,7 +24,7 @@
/>
</svg>
<svg
v-if="sortClient === false"
v-if="globalStore.sortClient === false"
inline
class="w-4 md:mr-2"
xmlns="http://www.w3.org/2000/svg"
@ -46,4 +46,6 @@
</button>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
const globalStore = useGlobalStore();
</script>

12
src/i18n.config.ts

@ -40,6 +40,12 @@ export default defineI18nConfig(() => ({
backup: 'Backup',
titleRestoreConfig: 'Restore your configuration',
titleBackupConfig: 'Backup your configuration',
rememberMe: 'Remember me',
titleRememberMe: 'Stay logged after closing the browser',
sort: 'Sort',
ExpireDate: 'Expire Date',
Permanent: 'Permanent',
OneTimeLink: 'Generate short one time link',
},
ua: {
name: 'Ім`я',
@ -118,6 +124,12 @@ export default defineI18nConfig(() => ({
backup: 'Резервная копия',
titleRestoreConfig: 'Восстановить конфигурацию',
titleBackupConfig: 'Создать резервную копию конфигурации',
rememberMe: 'Запомнить меня',
titleRememberMe: 'Оставаться в системе после закрытия браузера',
sort: 'Сортировка',
ExpireDate: 'Дата истечения срока',
Permanent: 'Бессрочно',
OneTimeLink: 'Создать короткую одноразовую ссылку',
},
tr: {
// Müslüm Barış Korkmazer @babico

8
src/pages/login.vue

@ -28,11 +28,11 @@
/>
<label
v-if="rememberMeEnabled"
v-if="globalStore.rememberMeEnabled"
class="inline-block mb-5 cursor-pointer whitespace-nowrap"
:title="$t('titleRememberMe')"
>
<input type="checkbox" class="sr-only" v-model="remember" />
<input v-model="remember" type="checkbox" class="sr-only" />
<div
v-if="remember"
@ -76,8 +76,10 @@
<script setup lang="ts">
const authenticating = ref(false);
const remember = ref(false);
const password = ref<null | string>(null);
const authStore = useAuthStore();
const globalStore = useGlobalStore();
async function login(e: Event) {
e.preventDefault();
@ -87,7 +89,7 @@ async function login(e: Event) {
authenticating.value = true;
try {
const res = await authStore.login(password.value);
const res = await authStore.login(password.value, remember.value);
if (res) {
await navigateTo('/');
}

2
src/server/utils/WireGuard.ts

@ -166,7 +166,7 @@ ${
publicKey: client.publicKey,
createdAt: new Date(client.createdAt),
updatedAt: new Date(client.updatedAt),
expiredAt: client.expireAt !== null ? new Date(client.expireAt) : null,
expireAt: client.expireAt !== null ? new Date(client.expireAt) : null,
allowedIPs: client.allowedIPs,
oneTimeLink: client.oneTimeLink ?? null,
oneTimeLinkExpiresAt: client.oneTimeLinkExpiresAt ?? null,

4
src/stores/auth.ts

@ -4,8 +4,8 @@ export const useAuthStore = defineStore('Auth', () => {
/**
* @throws if unsuccessful
*/
async function login(password: string) {
const response = await api.createSession({ password });
async function login(password: string, remember: boolean) {
const response = await api.createSession({ password, remember });
requiresPassword.value = response.requiresPassword;
return true as const;
}

2
src/stores/clients.ts

@ -108,7 +108,7 @@ export const useClientsStore = defineStore('Clients', () => {
};
});
if (globalStore.enableSortClient) {
if (globalStore.enableSortClient && transformedClients !== undefined) {
transformedClients = sortByProperty(
transformedClients,
'name',

29
src/stores/global.ts

@ -9,7 +9,8 @@ export const useGlobalStore = defineStore('Global', () => {
);
const uiTrafficStats = ref(false);
const rememberMeEnabled = ref(false);
const enableExpireTime = ref(false);
const enableOneTimeLinks = ref(false);
const enableSortClient = ref(false);
const sortClient = ref(true); // Sort clients by name, true = asc, false = desc
@ -46,6 +47,26 @@ export const useGlobalStore = defineStore('Global', () => {
uiTrafficStats.value = trafficStats.value ?? false;
}
async function fetchOneTimeLinks() {
const { data: oneTimeLinks } = await api.getEnableOneTimeLinks();
enableOneTimeLinks.value = oneTimeLinks.value ?? false;
}
async function fetchSortClients() {
const { data: sortClients } = await api.getSortClients();
enableSortClient.value = sortClients.value ?? false;
}
async function fetchExpireTime() {
const { data: expireTime } = await api.getEnableExpireTime();
enableExpireTime.value = expireTime.value ?? false;
}
async function fetchRememberMe() {
const { data: rememberMe } = await api.getRememberMeEnabled();
rememberMeEnabled.value = rememberMe.value ?? false;
}
const updateCharts = computed(() => {
return uiChartType.value > 0 && uiShowCharts.value;
});
@ -58,8 +79,14 @@ export const useGlobalStore = defineStore('Global', () => {
rememberMeEnabled,
enableSortClient,
sortClient,
enableExpireTime,
enableOneTimeLinks,
fetchRelease,
fetchChartType,
fetchTrafficStats,
fetchOneTimeLinks,
fetchSortClients,
fetchExpireTime,
fetchRememberMe,
};
});

2
src/stores/modal.ts

@ -5,7 +5,7 @@ export const useModalStore = defineStore('Modal', () => {
const clientDelete = ref<null | WGClient>(null);
const clientCreate = ref<null | boolean>(null);
const clientCreateName = ref<string>('');
const clientExpireDate = ref(null);
const clientExpireDate = ref<string | null>(null);
const qrcode = ref<null | string>(null);
function createClient() {

2
src/utils/api.ts

@ -78,7 +78,7 @@ class API {
expireDate,
}: {
name: string;
expireDate: string;
expireDate: string | null;
}) {
return $fetch('/api/wireguard/client', {
method: 'post',

Loading…
Cancel
Save