Improve admin candidate modal UX and add clip menu visibility toggle

- Widen AdminCandidateEditorModal to size lg for better readability
- Rename "Clip-Compilation" section to "Clip / Compilation", update copy to reflect single clips too, drop upload hint and Clip-Plattform field, rename label to "Link"
- Fix NativeSelect dropdown clipping inside overflow-y-auto modals by teleporting the menu to body with fixed positioning, flip-up logic, and dynamic maxHeight capped to viewport
- Add ClipAdminMenuVisible setting (backend domain, contracts, endpoint, migration) with matching frontend types, defaults, form wiring, and toggle in the Clip-Workflow modal — hides the Clips nav item from the admin sidebar when disabled

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
AzuTear
2026-06-27 18:39:35 +02:00
parent 494eba5edd
commit 18b61bed52
119 changed files with 15638 additions and 367 deletions
+46
View File
@@ -16,6 +16,8 @@ public sealed class AwardsDbContext(DbContextOptions<AwardsDbContext> options) :
public DbSet<RiskFlag> RiskFlags => Set<RiskFlag>();
public DbSet<AdminAuditEntry> AdminAuditEntries => Set<AdminAuditEntry>();
public DbSet<ClipSubmission> ClipSubmissions => Set<ClipSubmission>();
public DbSet<ShowactApplication> ShowactApplications => Set<ShowactApplication>();
public DbSet<Sponsor> Sponsors => Set<Sponsor>();
public DbSet<SiteSettings> SiteSettings => Set<SiteSettings>();
public DbSet<TeamMember> TeamMembers => Set<TeamMember>();
public DbSet<TeamRolePermission> TeamRolePermissions => Set<TeamRolePermission>();
@@ -40,6 +42,8 @@ public sealed class AwardsDbContext(DbContextOptions<AwardsDbContext> options) :
entity.Property(item => item.ImprintUrl).HasMaxLength(400);
entity.Property(item => item.ContactUrl).HasMaxLength(400);
entity.Property(item => item.SponsorsUrl).HasMaxLength(400);
entity.Property(item => item.ShowactsUrl).HasMaxLength(400);
entity.Property(item => item.ShowactsContent).HasDefaultValue(string.Empty);
entity.Property(item => item.DemoLoginEmail).HasMaxLength(180);
entity.Property(item => item.DemoLoginPasswordHash).HasMaxLength(120);
entity.Property(item => item.DemoLoginPasswordSalt).HasMaxLength(80);
@@ -51,6 +55,14 @@ public sealed class AwardsDbContext(DbContextOptions<AwardsDbContext> options) :
entity.Property(item => item.TwitchScope).HasMaxLength(300);
entity.Property(item => item.MaintenanceTitle).HasMaxLength(120);
entity.Property(item => item.MaintenanceMessage).HasMaxLength(600);
entity.Property(item => item.WorkflowRulesJson).HasDefaultValue("[]");
entity.Property(item => item.NominationLinkBlacklistJson).HasDefaultValue("[]");
entity.Property(item => item.ClipSubmissionsEnabled).HasDefaultValue(false);
entity.Property(item => item.ClipReviewEnabled).HasDefaultValue(true);
entity.Property(item => item.ClipSubmissionDisabledMessage).HasMaxLength(240);
entity.Property(item => item.ShowactApplicationsEnabled).HasDefaultValue(false);
entity.Property(item => item.ShowactApplicationDisabledMessage).HasMaxLength(240);
entity.Property(item => item.SponsorsVisible).HasDefaultValue(true);
});
modelBuilder.Entity<TeamMember>(entity =>
@@ -88,6 +100,12 @@ public sealed class AwardsDbContext(DbContextOptions<AwardsDbContext> options) :
entity.Property(item => item.DisplayName).HasMaxLength(120);
entity.Property(item => item.ChannelSlug).HasMaxLength(120);
entity.Property(item => item.Platform).HasMaxLength(40);
entity.Property(item => item.AcceptanceStatus).HasMaxLength(30).HasDefaultValue("open");
entity.Property(item => item.AcceptanceNote).HasMaxLength(500);
entity.Property(item => item.ClipCompilationUrl).HasMaxLength(500);
entity.Property(item => item.ClipCompilationTitle).HasMaxLength(200);
entity.Property(item => item.ClipCompilationPlatform).HasMaxLength(40);
entity.Property(item => item.ClipEmbedStatus).HasMaxLength(30).HasDefaultValue("unchecked");
});
modelBuilder.Entity<Nomination>(entity =>
@@ -169,6 +187,34 @@ public sealed class AwardsDbContext(DbContextOptions<AwardsDbContext> options) :
.OnDelete(DeleteBehavior.SetNull);
});
modelBuilder.Entity<ShowactApplication>(entity =>
{
entity.Property(item => item.ArtistName).HasMaxLength(120);
entity.Property(item => item.ContactEmail).HasMaxLength(180);
entity.Property(item => item.ContactDiscord).HasMaxLength(120);
entity.Property(item => item.PlatformUrl).HasMaxLength(500);
entity.Property(item => item.PerformanceType).HasMaxLength(80);
entity.Property(item => item.Description).HasMaxLength(1000);
entity.Property(item => item.TechnicalNotes).HasMaxLength(1000);
entity.Property(item => item.ReferenceUrl).HasMaxLength(500);
entity.Property(item => item.Status).HasMaxLength(20);
entity.Property(item => item.ReviewNote).HasMaxLength(500);
entity.Property(item => item.ReviewedByTwitchId).HasMaxLength(120);
entity.Property(item => item.CreatedFromIp).HasMaxLength(80);
entity.Property(item => item.UserAgent).HasMaxLength(400);
entity.HasIndex(item => new { item.SeasonId, item.Status });
});
modelBuilder.Entity<Sponsor>(entity =>
{
entity.Property(item => item.Name).HasMaxLength(120);
entity.Property(item => item.WebsiteUrl).HasMaxLength(500);
entity.Property(item => item.LogoUrl).HasMaxLength(500);
entity.Property(item => item.Description).HasMaxLength(500);
entity.Property(item => item.Tier).HasMaxLength(80);
entity.HasIndex(item => new { item.SeasonId, item.IsVisible, item.SortOrder });
});
SeedData.Apply(modelBuilder);
}
}