feat: basic admin interface
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
import type { RegistrationMode } from '~~/drizzle/schema';
|
||||
|
||||
type InstanceSettings = {
|
||||
registration: RegistrationMode;
|
||||
registrationLocked: boolean;
|
||||
};
|
||||
|
||||
const REGISTRATION_OPTIONS: { value: RegistrationMode; label: string; description: string }[] = [
|
||||
{
|
||||
value: 'open',
|
||||
label: 'Open',
|
||||
description: 'Anyone who can reach this instance can create an account.',
|
||||
},
|
||||
{
|
||||
value: 'invite',
|
||||
label: 'Invite only',
|
||||
description: 'New accounts need an invite link from an admin. Invite links are not available yet, so until then nobody can register.',
|
||||
},
|
||||
{
|
||||
value: 'closed',
|
||||
label: 'Closed',
|
||||
description: 'Nobody can register. Admins create accounts under Users.',
|
||||
},
|
||||
];
|
||||
|
||||
const { isAdmin } = useAuth();
|
||||
|
||||
if (!isAdmin.value) {
|
||||
await navigateTo('/settings/profile');
|
||||
}
|
||||
|
||||
const { data: instance } = await useFetch<InstanceSettings>('/api/admin/instance', {
|
||||
key: 'admin_instance',
|
||||
});
|
||||
|
||||
const saving = ref(false);
|
||||
const error = ref('');
|
||||
|
||||
const locked = computed(() => !!instance.value?.registrationLocked);
|
||||
const current = computed(() => REGISTRATION_OPTIONS.find(o => o.value === instance.value?.registration));
|
||||
|
||||
const setRegistration = async (registration: RegistrationMode) => {
|
||||
if (saving.value || locked.value || !instance.value || instance.value.registration === registration) return;
|
||||
|
||||
saving.value = true;
|
||||
error.value = '';
|
||||
|
||||
try {
|
||||
instance.value = await $fetch<InstanceSettings>('/api/admin/instance', {
|
||||
method: 'PUT',
|
||||
body: { registration },
|
||||
});
|
||||
// the sign in pages read this to decide whether to offer registering
|
||||
clearNuxtData('instance');
|
||||
} catch (err) {
|
||||
console.error('Failed to change registration:', err);
|
||||
error.value = 'Registration could not be changed. Try again.';
|
||||
}
|
||||
|
||||
saving.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col py-4 overflow-auto [scrollbar-width:thin] [scrollbar-color:#888_transparent] [scrollbar-gutter:stable]">
|
||||
<div class="flex flex-col gap-7 w-full max-w-3xl">
|
||||
<section class="flex flex-col gap-3">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div class="flex flex-col gap-0.5 flex-1 min-w-70">
|
||||
<h2 class="font-medium">Registration</h2>
|
||||
<p class="text-[13px] text-[var(--text-secondary)]">
|
||||
{{ current?.description ?? 'The instance settings could not be loaded.' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div role="group" aria-label="Registration mode"
|
||||
class="flex gap-0.5 p-0.5 rounded-lg bg-[var(--bg-container)]">
|
||||
<button v-for="option in REGISTRATION_OPTIONS" :key="option.value" type="button"
|
||||
:aria-pressed="instance?.registration === option.value"
|
||||
:disabled="saving || locked || !instance" @click="setRegistration(option.value)"
|
||||
class="flex items-center h-7.5 px-3 text-sm rounded-md disabled:cursor-not-allowed transition-colors duration-200"
|
||||
:class="instance?.registration === option.value
|
||||
? 'bg-[var(--color-accent)] text-[var(--color-accent-text)] font-medium'
|
||||
: 'text-[var(--text-secondary)] enabled:@hover:bg-[var(--color-hover)]'">
|
||||
{{ option.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="locked" class="flex gap-2 text-[13px] leading-normal text-[var(--text-secondary)]">
|
||||
<span class="i-mynaui-lock text-4 mt-0.5 flex-shrink-0" aria-hidden="true"></span>
|
||||
<span>
|
||||
Registration is turned off by the <code class="font-mono text-xs">DISABLE_SIGNUP</code>
|
||||
environment variable. Remove it and restart the server to change this here.
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p v-if="error" role="alert" class="text-sm text-red-400">{{ error }}</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user