Add winner archive, host image upload and live demo data
Deliver the demo-ready feature set and seed data so the live site can be presented end to end: - Winner archive: ArchivedWinner domain, admin CRUD endpoints/view/manager and public archive surface, backed by AddArchivedWinners migration. - Host presentation: host image upload and artist name on SiteSettings with public image endpoint and supporting migrations. - Clip submissions: idempotent table-ensure migration plus current-season demo clips for review workflows. - Demo seed data: sponsors, share links and 2025 archived winners, with a guarded RemoveDemoSeasons cleanup; all seeds guard against real data. - EnsureRuntimeSchemaParity migration to align runtime schema defensively. - Admin/home UI refinements; remove unused team role permissions modal and dead share-quick-links code. All seed and schema migrations are idempotent (IF NOT EXISTS / ON CONFLICT) and skip when real season data is present. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Ban, CheckCircle2, Link2, Loader2, ShieldAlert, Trash2, UserRoundCheck, WandSparkles } from '@lucide/vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
|
||||
import Button from '../ui/Button.vue'
|
||||
import NativeSelect from '../ui/NativeSelect.vue'
|
||||
@@ -25,7 +26,6 @@ const props = defineProps<{
|
||||
platforms: string[]
|
||||
} | null
|
||||
trackingReviewNotes?: string
|
||||
selectedNominationHasBlockingFlag?: boolean
|
||||
streamUrl?: string
|
||||
canApproveSelected: boolean
|
||||
blacklistSaving: boolean
|
||||
@@ -159,12 +159,23 @@ function avgViewerWindowLabel(nomination: AdminNominationReviewGroup) {
|
||||
class="rounded-[24px] border p-4"
|
||||
:class="nomination.trackingReviewStatus === 'overridden' ? 'border-emerald-100 bg-emerald-50/70' : nomination.requiresManualReview ? 'border-amber-100 bg-amber-50/70' : 'border-violet-100 bg-white'"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<ShieldAlert class="h-4 w-4" :class="nomination.requiresManualReview ? 'text-amber-700' : 'text-violet-600'" />
|
||||
<p class="text-[11px] font-semibold uppercase tracking-[0.18em]" :class="nomination.requiresManualReview ? 'text-amber-800' : 'text-violet-500'">Tracking Review</p>
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<ShieldAlert class="h-4 w-4" :class="nomination.requiresManualReview ? 'text-amber-700' : 'text-violet-600'" />
|
||||
<p class="text-[11px] font-semibold uppercase tracking-[0.18em]" :class="nomination.requiresManualReview ? 'text-amber-800' : 'text-violet-500'">Tracking Review</p>
|
||||
</div>
|
||||
<RouterLink
|
||||
to="/admin/tracking-rules"
|
||||
class="inline-flex items-center rounded-full border border-violet-200 bg-white px-3 py-1.5 text-xs font-semibold text-violet-700 transition hover:border-violet-300 hover:bg-violet-50"
|
||||
>
|
||||
Zur Konfiguration
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
<p class="mt-2 text-sm font-semibold text-slate-900">{{ props.trackerStatusMeta(nomination.trackerStatus).hint }}</p>
|
||||
<p class="mt-2 text-xs leading-5 text-slate-500">
|
||||
Diese Tracking-Metriken blockieren keine Annahme oder Verwerfung. Sie zeigen nur, welche Review-Regel und welches Zeitfenster aktuell angewandt werden.
|
||||
</p>
|
||||
|
||||
<div v-if="nomination.trackingFlags.length" class="mt-3 flex flex-wrap gap-2">
|
||||
<span
|
||||
@@ -172,7 +183,7 @@ function avgViewerWindowLabel(nomination: AdminNominationReviewGroup) {
|
||||
:key="flag.key"
|
||||
class="rounded-full border border-amber-200 bg-white px-3 py-1 text-xs font-semibold text-amber-800"
|
||||
>
|
||||
{{ flag.label }}<span v-if="flag.blocksApproval"> · blockiert</span>
|
||||
{{ flag.label }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -190,7 +201,7 @@ function avgViewerWindowLabel(nomination: AdminNominationReviewGroup) {
|
||||
</span>
|
||||
</div>
|
||||
<strong class="mt-1 block text-sm text-violet-900">{{ metric.value }}</strong>
|
||||
<p class="mt-1 text-xs text-slate-500">{{ metric.required ? 'Pflichtmetrik' : 'Optionale Metrik' }} · {{ metric.windowLabel }}</p>
|
||||
<p class="mt-1 text-xs text-slate-500">Review-Regel · {{ metric.required ? 'Pflichtmetrik' : 'Optionale Metrik' }} · {{ metric.windowLabel }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -271,12 +282,7 @@ function avgViewerWindowLabel(nomination: AdminNominationReviewGroup) {
|
||||
</p>
|
||||
|
||||
<p v-if="!canApproveSelected" class="mt-3 rounded-2xl border border-rose-100 bg-rose-50 px-4 py-3 text-sm text-rose-700">
|
||||
<span v-if="selectedNominationHasBlockingFlag && nomination.trackingReviewStatus !== 'overridden'">
|
||||
Mindestens ein Tracking-Flag blockiert die Freigabe. Bitte zuerst einen Override setzen.
|
||||
</span>
|
||||
<span v-else>
|
||||
Anzeigename, Handle, Plattform und Tier sind Pflicht.
|
||||
</span>
|
||||
Anzeigename, Handle, Plattform und Tier sind Pflicht.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user