Browse Source

move all features into one route

pull/1345/head
Bernd Storath 11 months ago
parent
commit
49837cc0ec
  1. 6
      src/app/app.vue
  2. 20
      src/app/components/Client/Charts.vue
  3. 4
      src/app/components/Client/Client.vue
  4. 2
      src/app/components/Client/ExpireDate.vue
  5. 2
      src/app/components/Client/LastSeen.vue
  6. 4
      src/app/components/Client/OneTimeLink.vue
  7. 2
      src/app/components/Client/OneTimeLinkBtn.vue
  8. 5
      src/app/components/Clients/CreateDialog.vue
  9. 2
      src/app/components/Clients/Sort.vue
  10. 4
      src/app/layouts/Header.vue
  11. 2
      src/app/stores/auth.ts
  12. 5
      src/app/stores/clients.ts
  13. 60
      src/app/stores/global.ts
  14. 38
      src/app/utils/api.ts
  15. 9
      src/server/api/features.get.ts
  16. 11
      src/server/api/ui-chart-type.get.ts
  17. 11
      src/server/api/ui-sort-clients.get.ts
  18. 11
      src/server/api/ui-traffic-stats.get.ts
  19. 11
      src/server/api/wg-enable-expire-time.get.ts
  20. 11
      src/server/api/wg-enable-one-time-links.get.ts

6
src/app/app.vue

@ -8,12 +8,8 @@
<script setup lang="ts"> <script setup lang="ts">
const globalStore = useGlobalStore(); const globalStore = useGlobalStore();
globalStore.fetchTrafficStats(); globalStore.fetchFeatures();
globalStore.fetchChartType();
globalStore.fetchRelease(); globalStore.fetchRelease();
globalStore.fetchOneTimeLinks();
globalStore.fetchSortClients();
globalStore.fetchExpireTime();
useHead({ useHead({
bodyAttrs: { bodyAttrs: {
class: 'bg-gray-50 dark:bg-neutral-800', class: 'bg-gray-50 dark:bg-neutral-800',

20
src/app/components/Client/Charts.vue

@ -1,13 +1,13 @@
<template> <template>
<div <div
v-if="globalStore.uiChartType" v-if="globalStore.features.trafficStats.type"
:class="`absolute z-0 bottom-0 left-0 right-0 h-6 ${globalStore.uiChartType === 1 && 'line-chart'}`" :class="`absolute z-0 bottom-0 left-0 right-0 h-6 ${globalStore.features.trafficStats.type === 1 && 'line-chart'}`"
> >
<UiChart :options="chartOptionsTX" :series="client.transferTxSeries" /> <UiChart :options="chartOptionsTX" :series="client.transferTxSeries" />
</div> </div>
<div <div
v-if="globalStore.uiChartType" v-if="globalStore.features.trafficStats.type"
:class="`absolute z-0 top-0 left-0 right-0 h-6 ${globalStore.uiChartType === 1 && 'line-chart'}`" :class="`absolute z-0 top-0 left-0 right-0 h-6 ${globalStore.features.trafficStats.type === 1 && 'line-chart'}`"
> >
<UiChart <UiChart
:options="chartOptionsRX" :options="chartOptionsRX"
@ -32,8 +32,10 @@ const chartOptionsTX = computed(() => {
...chartOptions, ...chartOptions,
colors: [CHART_COLORS.tx[theme.value]], colors: [CHART_COLORS.tx[theme.value]],
}; };
opts.chart.type = UI_CHART_TYPES[globalStore.uiChartType]?.type || undefined; opts.chart.type =
opts.stroke.width = UI_CHART_TYPES[globalStore.uiChartType]?.strokeWidth ?? 0; UI_CHART_TYPES[globalStore.features.trafficStats.type]?.type || undefined;
opts.stroke.width =
UI_CHART_TYPES[globalStore.features.trafficStats.type]?.strokeWidth ?? 0;
return opts; return opts;
}); });
@ -42,8 +44,10 @@ const chartOptionsRX = computed(() => {
...chartOptions, ...chartOptions,
colors: [CHART_COLORS.rx[theme.value]], colors: [CHART_COLORS.rx[theme.value]],
}; };
opts.chart.type = UI_CHART_TYPES[globalStore.uiChartType]?.type || undefined; opts.chart.type =
opts.stroke.width = UI_CHART_TYPES[globalStore.uiChartType]?.strokeWidth ?? 0; UI_CHART_TYPES[globalStore.features.trafficStats.type]?.type || undefined;
opts.stroke.width =
UI_CHART_TYPES[globalStore.features.trafficStats.type]?.strokeWidth ?? 0;
return opts; return opts;
}); });

4
src/app/components/Client/Client.vue

@ -14,7 +14,7 @@
> >
<ClientAddress :client="client" /> <ClientAddress :client="client" />
<ClientInlineTransfer <ClientInlineTransfer
v-if="!globalStore.uiTrafficStats" v-if="!globalStore.features.trafficStats.enabled"
:client="client" :client="client"
/> />
<ClientLastSeen :client="client" /> <ClientLastSeen :client="client" />
@ -25,7 +25,7 @@
<!-- Info --> <!-- Info -->
<div <div
v-if="globalStore.uiTrafficStats" v-if="globalStore.features.trafficStats.enabled"
class="flex gap-2 items-center shrink-0 text-gray-400 dark:text-neutral-400 text-xs mt-px justify-end" class="flex gap-2 items-center shrink-0 text-gray-400 dark:text-neutral-400 text-xs mt-px justify-end"
> >
<ClientTransfer :client="client" /> <ClientTransfer :client="client" />

2
src/app/components/Client/ExpireDate.vue

@ -1,6 +1,6 @@
<template> <template>
<div <div
v-show="globalStore.enableExpireTime" v-show="globalStore.features.clientExpiration.enabled"
class="block md:inline-block pb-1 md:pb-0 text-gray-500 dark:text-neutral-400 text-xs" class="block md:inline-block pb-1 md:pb-0 text-gray-500 dark:text-neutral-400 text-xs"
> >
<span class="group"> <span class="group">

2
src/app/components/Client/LastSeen.vue

@ -4,7 +4,7 @@
class="text-gray-400 dark:text-neutral-500 whitespace-nowrap" class="text-gray-400 dark:text-neutral-500 whitespace-nowrap"
:title="$t('lastSeen') + dateTime(new Date(client.latestHandshakeAt))" :title="$t('lastSeen') + dateTime(new Date(client.latestHandshakeAt))"
> >
{{ !globalStore.uiTrafficStats ? ' · ' : '' {{ !globalStore.features.trafficStats.enabled ? ' · ' : ''
}}{{ timeago(new Date(client.latestHandshakeAt)) }} }}{{ timeago(new Date(client.latestHandshakeAt)) }}
</span> </span>
</template> </template>

4
src/app/components/Client/OneTimeLink.vue

@ -1,6 +1,8 @@
<template> <template>
<div <div
v-if="globalStore.enableOneTimeLinks && client.oneTimeLink !== null" v-if="
globalStore.features.oneTimeLinks.enabled && client.oneTimeLink !== null
"
:ref="'client-' + client.id + '-link'" :ref="'client-' + client.id + '-link'"
class="text-gray-400 text-xs" class="text-gray-400 text-xs"
> >

2
src/app/components/Client/OneTimeLinkBtn.vue

@ -1,6 +1,6 @@
<template> <template>
<button <button
v-if="globalStore.enableOneTimeLinks" v-if="globalStore.features.oneTimeLinks.enabled"
:disabled="!client.downloadableConfig" :disabled="!client.downloadableConfig"
class="align-middle inline-block bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 p-2 rounded transition" class="align-middle inline-block bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 p-2 rounded transition"
:class="{ :class="{

5
src/app/components/Clients/CreateDialog.vue

@ -71,7 +71,10 @@
/> />
</p> </p>
</div> </div>
<div v-show="globalStore.enableExpireTime" class="mt-2"> <div
v-show="globalStore.features.clientExpiration.enabled"
class="mt-2"
>
<p class="text-sm text-gray-500"> <p class="text-sm text-gray-500">
<label <label
class="block text-gray-900 dark:text-neutral-200 text-sm font-bold mb-2" class="block text-gray-900 dark:text-neutral-200 text-sm font-bold mb-2"

2
src/app/components/Clients/Sort.vue

@ -1,6 +1,6 @@
<template> <template>
<button <button
v-if="globalStore.enableSortClient" v-if="globalStore.features.sortClients.enabled"
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" 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" @click="globalStore.sortClient = !globalStore.sortClient"
> >

4
src/app/layouts/Header.vue

@ -36,7 +36,7 @@
</button> </button>
<!-- Show / hide charts --> <!-- Show / hide charts -->
<label <label
v-if="globalStore.uiChartType > 0" v-if="globalStore.features.trafficStats.type > 0"
class="inline-flex items-center justify-center cursor-pointer w-8 h-8 rounded-full bg-gray-200 hover:bg-gray-300 dark:bg-neutral-700 dark:hover:bg-neutral-600 whitespace-nowrap transition group" class="inline-flex items-center justify-center cursor-pointer w-8 h-8 rounded-full bg-gray-200 hover:bg-gray-300 dark:bg-neutral-700 dark:hover:bg-neutral-600 whitespace-nowrap transition group"
:title="$t('toggleCharts')" :title="$t('toggleCharts')"
> >
@ -96,8 +96,6 @@ const currentRelease = ref<null | number>(null);
const latestRelease = ref<null | { version: number; changelog: string }>(null); const latestRelease = ref<null | { version: number; changelog: string }>(null);
const theme = useTheme(); const theme = useTheme();
globalStore.fetchChartType();
const uiShowCharts = ref(getItem('uiShowCharts') === '1'); const uiShowCharts = ref(getItem('uiShowCharts') === '1');
function toggleTheme() { function toggleTheme() {

2
src/app/stores/auth.ts

@ -5,7 +5,7 @@ export const useAuthStore = defineStore('Auth', () => {
* @throws if unsuccessful * @throws if unsuccessful
*/ */
async function signup(username: string, password: string) { async function signup(username: string, password: string) {
const response = await api.newAccount({ username, password }); const response = await api.createAccount({ username, password });
return response.success; return response.success;
} }

5
src/app/stores/clients.ts

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

60
src/app/stores/global.ts

@ -1,16 +1,26 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
export const useGlobalStore = defineStore('Global', () => { export const useGlobalStore = defineStore('Global', () => {
const uiChartType = ref(0);
const uiShowCharts = ref(getItem('uiShowCharts') === '1'); const uiShowCharts = ref(getItem('uiShowCharts') === '1');
const currentRelease = ref<null | number>(null); const currentRelease = ref<null | number>(null);
const latestRelease = ref<null | { version: number; changelog: string }>( const latestRelease = ref<null | { version: number; changelog: string }>(
null null
); );
const uiTrafficStats = ref(false); const features = ref({
const enableExpireTime = ref(false); trafficStats: {
const enableOneTimeLinks = ref(false); enabled: false,
const enableSortClient = ref(false); type: 0,
},
sortClients: {
enabled: false,
},
clientExpiration: {
enabled: false,
},
oneTimeLinks: {
enabled: false,
},
});
const sortClient = ref(true); // Sort clients by name, true = asc, false = desc const sortClient = ref(true); // Sort clients by name, true = asc, false = desc
const { availableLocales, locale } = useI18n(); const { availableLocales, locale } = useI18n();
@ -39,49 +49,23 @@ export const useGlobalStore = defineStore('Global', () => {
latestRelease.value = release.value!.latestRelease; latestRelease.value = release.value!.latestRelease;
} }
async function fetchChartType() { async function fetchFeatures() {
const { data: chartType } = await api.getChartType(); const { data: apiFeatures } = await api.getFeatures();
uiChartType.value = chartType.value ?? 0; if (apiFeatures.value) {
} features.value = apiFeatures.value;
async function fetchTrafficStats() {
const { data: trafficStats } = await api.getTrafficStats();
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;
} }
const updateCharts = computed(() => { const updateCharts = computed(() => {
return uiChartType.value > 0 && uiShowCharts.value; return features.value.trafficStats.type > 0 && uiShowCharts.value;
}); });
return { return {
uiChartType,
uiShowCharts, uiShowCharts,
uiTrafficStats,
updateCharts, updateCharts,
enableSortClient,
sortClient, sortClient,
enableExpireTime, features,
enableOneTimeLinks,
fetchRelease, fetchRelease,
fetchChartType, fetchFeatures,
fetchTrafficStats,
fetchOneTimeLinks,
fetchSortClients,
fetchExpireTime,
}; };
}); });

38
src/app/utils/api.ts

@ -11,30 +11,6 @@ class API {
}); });
} }
async getTrafficStats() {
return useFetch('/api/ui-traffic-stats', {
method: 'get',
});
}
async getChartType() {
return useFetch('/api/ui-chart-type', {
method: 'get',
});
}
async getEnableOneTimeLinks() {
return useFetch('/api/wg-enable-one-time-links', {
method: 'get',
});
}
async getEnableExpireTime() {
return useFetch('/api/wg-enable-expire-time', {
method: 'get',
});
}
async getSession() { async getSession() {
// TODO?: use useFetch // TODO?: use useFetch
return $fetch('/api/session', { return $fetch('/api/session', {
@ -152,13 +128,7 @@ class API {
}); });
} }
async getSortClients() { async createAccount({
return useFetch('/api/ui-sort-clients', {
method: 'get',
});
}
async newAccount({
username, username,
password, password,
}: { }: {
@ -170,6 +140,12 @@ class API {
body: { username, password }, body: { username, password },
}); });
} }
async getFeatures() {
return useFetch('/api/features', {
method: 'get',
});
}
} }
type WGClientReturn = Awaited< type WGClientReturn = Awaited<

9
src/server/api/features.get.ts

@ -0,0 +1,9 @@
export default defineEventHandler(async () => {
const system = await Database.getSystem();
return {
trafficStats: system.trafficStats,
sortClients: system.sortClients,
clientExpiration: system.clientExpiration,
oneTimeLinks: system.oneTimeLinks,
};
});

11
src/server/api/ui-chart-type.get.ts

@ -1,11 +0,0 @@
export default defineEventHandler(async (event) => {
setHeader(event, 'Content-Type', 'application/json');
const system = await Database.getSystem();
if (!system)
throw createError({
statusCode: 500,
statusMessage: 'Invalid',
});
return system.trafficStats.type;
});

11
src/server/api/ui-sort-clients.get.ts

@ -1,11 +0,0 @@
export default defineEventHandler(async (event) => {
setHeader(event, 'Content-Type', 'application/json');
const system = await Database.getSystem();
if (!system)
throw createError({
statusCode: 500,
statusMessage: 'Invalid',
});
return system.sortClients.enabled;
});

11
src/server/api/ui-traffic-stats.get.ts

@ -1,11 +0,0 @@
export default defineEventHandler(async (event) => {
setHeader(event, 'Content-Type', 'application/json');
const system = await Database.getSystem();
if (!system)
throw createError({
statusCode: 500,
statusMessage: 'Invalid',
});
return system.trafficStats.enabled;
});

11
src/server/api/wg-enable-expire-time.get.ts

@ -1,11 +0,0 @@
export default defineEventHandler(async (event) => {
setHeader(event, 'Content-Type', 'application/json');
const system = await Database.getSystem();
if (!system)
throw createError({
statusCode: 500,
statusMessage: 'Invalid',
});
return system.clientExpiration.enabled;
});

11
src/server/api/wg-enable-one-time-links.get.ts

@ -1,11 +0,0 @@
export default defineEventHandler(async (event) => {
setHeader(event, 'Content-Type', 'application/json');
const system = await Database.getSystem();
if (!system)
throw createError({
statusCode: 500,
statusMessage: 'Invalid',
});
return system.oneTimeLinks.enabled;
});
Loading…
Cancel
Save