Add metrics password override and implement frontend UI indicators
Backend changes: - Added WG_METRICS_PASSWORD environment variable override - Updated applyGeneralOverrides() to include metrics password - Updated /api/admin/overrides endpoint to include metrics password Frontend changes: - Added override indicators (warning icons with tooltips) to all form fields - Updated TextField, NumberField, NullTextField, SwitchField, HostField, ArrayField components - Added overridden prop support to all form components - Fetched /api/admin/overrides in all admin pages (interface, general, config, hooks) - Warning icon displays when field is overridden by environment variable - ArrayField shows banner when overridden - Updated documentation with WG_METRICS_PASSWORD Co-authored-by: kaaax0815 <32197462+kaaax0815@users.noreply.github.com>
This commit is contained in:
@@ -51,6 +51,7 @@ These environment variables allow you to override settings that would normally b
|
||||
| Env | Example | Description |
|
||||
| ----------------------- | ----------------- | ------------------------- |
|
||||
| `WG_SESSION_TIMEOUT` | `3600` | Session timeout (seconds) |
|
||||
| `WG_METRICS_PASSWORD` | `mypassword123` | Metrics endpoint password |
|
||||
| `WG_METRICS_PROMETHEUS` | `true` or `false` | Enable Prometheus metrics |
|
||||
| `WG_METRICS_JSON` | `true` or `false` | Enable JSON metrics |
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div v-if="overridden" class="flex items-center gap-2 p-2 bg-amber-50 dark:bg-amber-900/20 rounded-lg text-amber-700 dark:text-amber-400 text-sm">
|
||||
<IconsWarning class="size-4" />
|
||||
<span>This field is overridden by an environment variable</span>
|
||||
</div>
|
||||
<div v-if="data?.length === 0">
|
||||
{{ emptyText || $t('form.noItems') }}
|
||||
</div>
|
||||
@@ -35,7 +39,11 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
const data = defineModel<string[]>();
|
||||
defineProps<{ emptyText?: string[]; name: string }>();
|
||||
defineProps<{
|
||||
emptyText?: string[];
|
||||
name: string;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
function update(e: Event, i: number) {
|
||||
const v = (e.target as HTMLInputElement).value;
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip v-if="overridden" text="This field is overridden by an environment variable">
|
||||
<IconsWarning class="size-4 ml-1 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<BaseInput
|
||||
@@ -38,6 +41,7 @@ defineProps<{
|
||||
description?: string;
|
||||
placeholder?: string;
|
||||
url: '/api/admin/ip-info' | '/api/setup/4';
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
const data = defineModel<string | null>({
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip v-if="overridden" text="This field is overridden by an environment variable">
|
||||
<IconsWarning class="size-4 ml-1 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseInput
|
||||
:id="id"
|
||||
@@ -24,6 +27,7 @@ defineProps<{
|
||||
description?: string;
|
||||
autocomplete?: string;
|
||||
placeholder?: string;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
const data = defineModel<string | null>({
|
||||
|
||||
@@ -6,12 +6,20 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip v-if="overridden" text="This field is overridden by an environment variable">
|
||||
<IconsWarning class="size-4 ml-1 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseInput :id="id" v-model.number="data" :name="id" type="number" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ id: string; label: string; description?: string }>();
|
||||
defineProps<{
|
||||
id: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
const data = defineModel<number>();
|
||||
</script>
|
||||
|
||||
@@ -6,11 +6,19 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip v-if="overridden" text="This field is overridden by an environment variable">
|
||||
<IconsWarning class="size-4 ml-1 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseSwitch :id="id" v-model="data" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ id: string; label: string; description?: string }>();
|
||||
defineProps<{
|
||||
id: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
const data = defineModel<boolean>();
|
||||
</script>
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
<BaseTooltip v-if="overridden" text="This field is overridden by an environment variable">
|
||||
<IconsWarning class="size-4 ml-1 text-amber-500" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseInput
|
||||
:id="id"
|
||||
@@ -24,6 +27,7 @@ defineProps<{
|
||||
description?: string;
|
||||
autocomplete?: string;
|
||||
disabled?: boolean;
|
||||
overridden?: boolean;
|
||||
}>();
|
||||
|
||||
const data = defineModel<string>();
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
:label="$t('general.host')"
|
||||
:description="$t('admin.config.hostDesc')"
|
||||
url="/api/admin/ip-info"
|
||||
:overridden="overrides.host"
|
||||
/>
|
||||
<FormNumberField
|
||||
id="port"
|
||||
v-model="data.port"
|
||||
:label="$t('general.port')"
|
||||
:description="$t('admin.config.portDesc')"
|
||||
:overridden="overrides.port"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
@@ -24,13 +26,18 @@
|
||||
<FormArrayField
|
||||
v-model="data.defaultAllowedIps"
|
||||
name="defaultAllowedIps"
|
||||
:overridden="overrides.defaultAllowedIps"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading :description="$t('admin.config.dnsDesc')">
|
||||
{{ $t('general.dns') }}
|
||||
</FormHeading>
|
||||
<FormArrayField v-model="data.defaultDns" name="defaultDns" />
|
||||
<FormArrayField
|
||||
v-model="data.defaultDns"
|
||||
name="defaultDns"
|
||||
:overridden="overrides.defaultDns"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading>{{ $t('form.sectionAdvanced') }}</FormHeading>
|
||||
@@ -39,12 +46,14 @@
|
||||
v-model="data.defaultMtu"
|
||||
:label="$t('general.mtu')"
|
||||
:description="$t('admin.config.mtuDesc')"
|
||||
:overridden="overrides.defaultMtu"
|
||||
/>
|
||||
<FormNumberField
|
||||
id="defaultPersistentKeepalive"
|
||||
v-model="data.defaultPersistentKeepalive"
|
||||
:label="$t('general.persistentKeepalive')"
|
||||
:description="$t('admin.config.persistentKeepaliveDesc')"
|
||||
:overridden="overrides.defaultPersistentKeepalive"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup v-if="globalStore.information?.isAwg">
|
||||
@@ -118,6 +127,12 @@ const { data: _data, refresh } = await useFetch(`/api/admin/userconfig`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const { data: overridesData } = await useFetch(`/api/admin/overrides`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const overrides = computed(() => overridesData.value?.userConfig || {});
|
||||
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
v-model="data.sessionTimeout"
|
||||
:label="$t('admin.general.sessionTimeout')"
|
||||
:description="$t('admin.general.sessionTimeoutDesc')"
|
||||
:overridden="overrides.sessionTimeout"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
@@ -16,18 +17,21 @@
|
||||
v-model="data.metricsPassword"
|
||||
:label="$t('admin.general.metricsPassword')"
|
||||
:description="$t('admin.general.metricsPasswordDesc')"
|
||||
:overridden="overrides.metricsPassword"
|
||||
/>
|
||||
<FormSwitchField
|
||||
id="prometheus"
|
||||
v-model="data.metricsPrometheus"
|
||||
:label="$t('admin.general.prometheus')"
|
||||
:description="$t('admin.general.prometheusDesc')"
|
||||
:overridden="overrides.metricsPrometheus"
|
||||
/>
|
||||
<FormSwitchField
|
||||
id="json"
|
||||
v-model="data.metricsJson"
|
||||
:label="$t('admin.general.json')"
|
||||
:description="$t('admin.general.jsonDesc')"
|
||||
:overridden="overrides.metricsJson"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
@@ -43,6 +47,13 @@
|
||||
const { data: _data, refresh } = await useFetch(`/api/admin/general`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const { data: overridesData } = await useFetch(`/api/admin/overrides`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const overrides = computed(() => overridesData.value?.general || {});
|
||||
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
|
||||
@@ -6,21 +6,25 @@
|
||||
id="PreUp"
|
||||
v-model="data.preUp"
|
||||
:label="$t('hooks.preUp')"
|
||||
:overridden="overrides.preUp"
|
||||
/>
|
||||
<FormTextField
|
||||
id="PostUp"
|
||||
v-model="data.postUp"
|
||||
:label="$t('hooks.postUp')"
|
||||
:overridden="overrides.postUp"
|
||||
/>
|
||||
<FormTextField
|
||||
id="PreDown"
|
||||
v-model="data.preDown"
|
||||
:label="$t('hooks.preDown')"
|
||||
:overridden="overrides.preDown"
|
||||
/>
|
||||
<FormTextField
|
||||
id="PostDown"
|
||||
v-model="data.postDown"
|
||||
:label="$t('hooks.postDown')"
|
||||
:overridden="overrides.postDown"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
@@ -37,6 +41,12 @@ const { data: _data, refresh } = await useFetch(`/api/admin/hooks`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const { data: overridesData } = await useFetch(`/api/admin/overrides`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const overrides = computed(() => overridesData.value?.hooks || {});
|
||||
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
|
||||
@@ -7,18 +7,21 @@
|
||||
v-model="data.mtu"
|
||||
:label="$t('general.mtu')"
|
||||
:description="$t('admin.interface.mtuDesc')"
|
||||
:overridden="overrides.mtu"
|
||||
/>
|
||||
<FormNumberField
|
||||
id="port"
|
||||
v-model="data.port"
|
||||
:label="$t('general.port')"
|
||||
:description="$t('admin.interface.portDesc')"
|
||||
:overridden="overrides.port"
|
||||
/>
|
||||
<FormTextField
|
||||
id="device"
|
||||
v-model="data.device"
|
||||
:label="$t('admin.interface.device')"
|
||||
:description="$t('admin.interface.deviceDesc')"
|
||||
:overridden="overrides.device"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup v-if="globalStore.information?.isAwg">
|
||||
@@ -164,6 +167,12 @@ const { data: _data, refresh } = await useFetch(`/api/admin/interface`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const { data: overridesData } = await useFetch(`/api/admin/overrides`, {
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
const overrides = computed(() => overridesData.value?.interface || {});
|
||||
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
|
||||
@@ -17,6 +17,7 @@ export default definePermissionEventHandler('admin', 'any', async () => {
|
||||
},
|
||||
general: {
|
||||
sessionTimeout: WG_GENERAL_OVERRIDE_ENV.SESSION_TIMEOUT !== undefined,
|
||||
metricsPassword: WG_GENERAL_OVERRIDE_ENV.METRICS_PASSWORD !== undefined,
|
||||
metricsPrometheus: WG_GENERAL_OVERRIDE_ENV.METRICS_PROMETHEUS !== undefined,
|
||||
metricsJson: WG_GENERAL_OVERRIDE_ENV.METRICS_JSON !== undefined,
|
||||
},
|
||||
|
||||
@@ -97,6 +97,8 @@ export const WG_GENERAL_OVERRIDE_ENV = {
|
||||
SESSION_TIMEOUT: process.env.WG_SESSION_TIMEOUT
|
||||
? Number.parseInt(process.env.WG_SESSION_TIMEOUT, 10)
|
||||
: undefined,
|
||||
/** Override metrics password */
|
||||
METRICS_PASSWORD: process.env.WG_METRICS_PASSWORD,
|
||||
/** Override metrics Prometheus enabled status */
|
||||
METRICS_PROMETHEUS: process.env.WG_METRICS_PROMETHEUS === 'true' ? true :
|
||||
process.env.WG_METRICS_PROMETHEUS === 'false' ? false :
|
||||
@@ -165,11 +167,12 @@ export function applyUserConfigOverrides<
|
||||
* Apply environment variable overrides to a general config object
|
||||
*/
|
||||
export function applyGeneralOverrides<
|
||||
T extends { sessionTimeout: number; metricsPrometheus: boolean; metricsJson: boolean },
|
||||
T extends { sessionTimeout: number; metricsPassword: string | null; metricsPrometheus: boolean; metricsJson: boolean },
|
||||
>(generalConfig: T): T {
|
||||
return {
|
||||
...generalConfig,
|
||||
sessionTimeout: WG_GENERAL_OVERRIDE_ENV.SESSION_TIMEOUT ?? generalConfig.sessionTimeout,
|
||||
metricsPassword: WG_GENERAL_OVERRIDE_ENV.METRICS_PASSWORD ?? generalConfig.metricsPassword,
|
||||
metricsPrometheus: WG_GENERAL_OVERRIDE_ENV.METRICS_PROMETHEUS ?? generalConfig.metricsPrometheus,
|
||||
metricsJson: WG_GENERAL_OVERRIDE_ENV.METRICS_JSON ?? generalConfig.metricsJson,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user