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. 62
      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">
const globalStore = useGlobalStore();
globalStore.fetchTrafficStats();
globalStore.fetchChartType();
globalStore.fetchFeatures();
globalStore.fetchRelease();
globalStore.fetchOneTimeLinks();
globalStore.fetchSortClients();
globalStore.fetchExpireTime();
useHead({
bodyAttrs: {
class: 'bg-gray-50 dark:bg-neutral-800',

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

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

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

@ -14,7 +14,7 @@
>
<ClientAddress :client="client" />
<ClientInlineTransfer
v-if="!globalStore.uiTrafficStats"
v-if="!globalStore.features.trafficStats.enabled"
:client="client"
/>
<ClientLastSeen :client="client" />
@ -25,7 +25,7 @@
<!-- Info -->
<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"
>
<ClientTransfer :client="client" />

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

@ -1,6 +1,6 @@
<template>
<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"
>
<span class="group">

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

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

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

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

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

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

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

@ -71,7 +71,10 @@
/>
</p>
</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">
<label
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>
<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"
@click="globalStore.sortClient = !globalStore.sortClient"
>

4
src/app/layouts/Header.vue

@ -36,7 +36,7 @@
</button>
<!-- Show / hide charts -->
<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"
:title="$t('toggleCharts')"
>
@ -96,8 +96,6 @@ const currentRelease = ref<null | number>(null);
const latestRelease = ref<null | { version: number; changelog: string }>(null);
const theme = useTheme();
globalStore.fetchChartType();
const uiShowCharts = ref(getItem('uiShowCharts') === '1');
function toggleTheme() {

2
src/app/stores/auth.ts

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

62
src/app/stores/global.ts

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

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() {
// TODO?: use useFetch
return $fetch('/api/session', {
@ -152,13 +128,7 @@ class API {
});
}
async getSortClients() {
return useFetch('/api/ui-sort-clients', {
method: 'get',
});
}
async newAccount({
async createAccount({
username,
password,
}: {
@ -170,6 +140,12 @@ class API {
body: { username, password },
});
}
async getFeatures() {
return useFetch('/api/features', {
method: 'get',
});
}
}
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