M1.5 frontend: admin Settings UI + config store + register gating
CI & Build / Python lint (push) Successful in 3s
CI & Build / Python tests (push) Successful in 8s
CI & Build / TypeScript typecheck (push) Successful in 10s
CI & Build / Build & push image (push) Successful in 31s

- config store (public /api/config: site_name, allow_registration, version),
  loaded in the router guard; site name drives the board header.
- session User gains is_admin.
- /settings route with requiresAdmin guard + admin-only gear link in the header;
  SettingsView renders grouped typed fields (text/number/toggle), saves via
  PATCH /api/settings with saved/error feedback, refreshes public config.
- Register link hidden + /register route blocked when registration is closed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
This commit is contained in:
2026-07-19 18:28:56 -04:00
co-authored by Claude Opus 4.8
parent b46bda38ee
commit 68f7b260de
7 changed files with 208 additions and 3 deletions
+3 -1
View File
@@ -2,11 +2,13 @@
import { ref } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useSessionStore } from "../stores/session";
import { useConfigStore } from "../stores/config";
import BaseInput from "../components/BaseInput.vue";
import BaseButton from "../components/BaseButton.vue";
import type { ApiError } from "../api/client";
const session = useSessionStore();
const config = useConfigStore();
const router = useRouter();
const route = useRoute();
@@ -72,7 +74,7 @@ async function submit() {
<BaseButton type="submit" :loading="loading">Sign in</BaseButton>
</form>
<p class="mt-6 text-center text-sm text-neutral-500 dark:text-neutral-400">
<p v-if="config.allowRegistration" class="mt-6 text-center text-sm text-neutral-500 dark:text-neutral-400">
No account?
<RouterLink to="/register" class="font-semibold text-brand-700 hover:underline dark:text-brand"
>Create one</RouterLink