Compare commits

..

1 Commits

Author SHA1 Message Date
54ffb809c4 CHARAKTERBOGEN-2 (E1): Trait-Katalog in 4 Kategorien + 10 neue Traits + Warnsignale
- de.ts: traits-Array -> traitCategories (4 Kategorien: Sozialverhalten / Eignung &
  Umgang / Hobbys & Eigenarten / Wesen & Temperament); alle 15 bestehenden Keys
  erhalten (stored auf Live-Tieren); 10 neue Keys additiv; warn:true auf
  schwer-vergesellschaftbar + territorial.
- format/traits.ts: TraitEntry/TraitCategory-Interface, TRAIT_CATEGORIES-Export,
  ALL_TRAITS via flatMap, neuer isWarnTrait()-Helper.
- Charakterbogen.tsx: grouped-Rendering nach Kategorie (section + h4); warn-Chips
  mit trait-chip--warn-Klasse + trait-warn-badge.
- charakterbogen.css: .trait-category__heading + .trait-chip--warn (amber) +
  .trait-warn-badge.
- format/__tests__/traits.test.ts: 14 neue Vitest-Tests (Kategorien, Keys, warn,
  traitLabel/traitLabels).
- Gate: vitest 122/122, tsc clean, build clean, eslint clean.
2026-06-06 22:32:16 +02:00
10 changed files with 336 additions and 2249 deletions

View File

@@ -573,32 +573,27 @@ namespace GerbilManager.Tests
[Fact] [Fact]
public void SeedGen3g_existing_varieties_preserve_id_name_binding() public void SeedGen3g_existing_varieties_preserve_id_name_binding()
{ {
// CATALOG-RESEED regression: ID->Name bindings for all 66 existing entries must be // SEED-HELL bounce regression: the 61 existing entries must NOT change their
// stable. 4 new Dilute Fuchs varieties appended (IDs 67-70). CP-Fuchs (ID 58) and // Id->Name binding after GEN-3g. The 5 new entries (IDs 62-66) are appended.
// the CP-*-Hell entries (IDs 62-66) must survive with their original names intact. // A hand-assigned Gerbil.ColorVarietyId pointing to "CP-Fuchs" (ID 58) must
using var db = NewDb(); // EnsureCreated applies HasData including 70-entry seed // still map to CP-Fuchs after the migration runs (append-only, no rename-shift).
using var db = NewDb(); // EnsureCreated applies HasData including new 66-entry seed
// ID 58 = CP-Fuchs — must still be CP-Fuchs (no rename-shift from new entries) // ID 58 (index 57 in old catalog, 0-based) = CP-Fuchs — must still be CP-Fuchs
var cpFuchsId = new Guid("00000000-0000-0000-0000-000000000058"); var cpFuchsId = new Guid("00000000-0000-0000-0000-000000000058");
var cpFuchs = db.ColorVarieties.Find(cpFuchsId); var cpFuchs = db.ColorVarieties.Find(cpFuchsId);
Assert.NotNull(cpFuchs); Assert.NotNull(cpFuchs);
Assert.Equal("CP-Fuchs", cpFuchs!.Name); Assert.Equal("CP-Fuchs", cpFuchs!.Name);
// Existing CP-*-Hell entries (IDs 62-66) unchanged // New entries at IDs 62-66 exist with correct names
Assert.Equal("CP-Agouti-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000062"))!.Name); Assert.Equal("CP-Agouti-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000062"))!.Name);
Assert.Equal("CP-Silberagouti-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000063"))!.Name); Assert.Equal("CP-Silberagouti-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000063"))!.Name);
Assert.Equal("CP-Algierfuchs-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000064"))!.Name); Assert.Equal("CP-Algierfuchs-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000064"))!.Name);
Assert.Equal("CP-Polarfuchs-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000065"))!.Name); Assert.Equal("CP-Polarfuchs-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000065"))!.Name);
Assert.Equal("CP-Orangeschimmel-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000066"))!.Name); Assert.Equal("CP-Orangeschimmel-Hell", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000066"))!.Name);
// 4 new Dilute Fuchs varieties appended (IDs 67-70) // Total count is exactly 66
Assert.Equal("Dilute Algierfuchs", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000067"))!.Name); Assert.Equal(66, db.ColorVarieties.Count());
Assert.Equal("Dilute Goldfuchs", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000068"))!.Name);
Assert.Equal("Dilute Rotfuchs", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000069"))!.Name);
Assert.Equal("Dilute Polarfuchs", db.ColorVarieties.Find(new Guid("00000000-0000-0000-0000-000000000070"))!.Name);
// Total count is exactly 70
Assert.Equal(70, db.ColorVarieties.Count());
} }
[Theory] [Theory]

View File

@@ -282,97 +282,79 @@ public class ApplicationContext : DbContext
/// </summary> /// </summary>
private static void SeedColorVarieties(ModelBuilder modelBuilder) private static void SeedColorVarieties(ModelBuilder modelBuilder)
{ {
// CATALOG-RESEED (AR-5 / colorVarietySeed.backend.json): 70 entries, frozen symbols. // GEN-3g (Kevin): 5 CP-*-Hell variants appended at the end (IDs 62-66).
// ID = array_index + 1 (stable, never changes — live FKs safe). // Existing 61 entries are UNCHANGED (same ID->Name binding preserved).
// SortOrder comes from colorVarietySeed.backend.json (decoupled from ID). // SortOrder for new entries is appended; Kevin's frontend catalog handles
// New entries appended at end (IDs 67-70: Dilute Algierfuchs/Goldfuchs/Rotfuchs/Polarfuchs). // the interleaved display order via its own sortOrder values.
// GUARDRAIL: DO NOT reseed from colorVarietySeed.generated.json — it uses bracket display (string Name, string Genotype)[] catalog =
// notation (e[f]/c[chm]) which breaks CR-11 GenotypePotentiallyMatches() (frozen vs brackets).
(string Name, string Genotype, int SortOrder)[] catalog =
{ {
// --- C-locus white / partial albino (IDs 1-3) --- ("Pink Eyed White (PEW)", "AA chch DD EE GG pp spsp rere"),
("Pink Eyed White (PEW)", "AA chch DD EE GG pp spsp rere", 0), ("Hermelin", "aa chch DD EE GG PP spsp rere"),
("Hermelin", "aa chch DD EE GG PP spsp rere", 1), ("Himalaya", "AA chch DD EE GG PP spsp rere"),
("Himalaya", "AA chch DD EE GG PP spsp rere", 2), ("Zobel", "aa cchmcchm DD EE gg PP spsp rere"),
// --- Zobel / colourpoint dark (ID 4) --- ("Rotaugenschimmel", "AA CC DD efef GG pp spsp rere"),
("Zobel", "aa cchmcchm DD EE gg PP spsp rere", 3), ("Agouti", "AA CC DD EE GG PP spsp rere"),
// --- Schimmel family (IDs 5) --- ("Schwarz", "aa CC DD EE GG PP spsp rere"),
("Rotaugenschimmel", "AA CC DD efef GG pp spsp rere", 4), ("Silberagouti", "AA CC DD EE gg PP spsp rere"),
// --- Standard colours (IDs 6-15) --- ("Anthrazit", "aa CC DD EE gg PP spsp rere"),
("Agouti", "AA CC DD EE GG PP spsp rere", 5), ("Algierfuchs", "AA CC DD ee GG PP spsp rere"),
("Schwarz", "aa CC DD EE GG PP spsp rere", 6), ("Blau", "aa CC dd EE GG PP spsp rere"),
("Silberagouti","AA CC DD EE gg PP spsp rere", 7), ("Gold", "AA CC DD EE GG pp spsp rere"),
("Anthrazit", "aa CC DD EE gg PP spsp rere", 8), ("Platin", "aa CC DD EE GG pp spsp rere"),
("Algierfuchs", "AA CC DD ee GG PP spsp rere", 9), ("Goldfuchs", "AA CC DD ee GG pp spsp rere"),
("Blau", "aa CC dd EE GG PP spsp rere", 10), ("Rotfuchs", "aa CC DD ee GG pp spsp rere"),
("Gold", "AA CC DD EE GG pp spsp rere", 11), ("dd Gold", "AA CC dd EE GG pp spsp rere"),
("Platin", "aa CC DD EE GG pp spsp rere", 12), ("dd Platin", "aa CC dd EE GG pp spsp rere"),
("Goldfuchs", "AA CC DD ee GG pp spsp rere", 13), ("Altweiss (REW)", "aa CC DD EE gg pp spsp rere"),
("Rotfuchs", "aa CC DD ee GG pp spsp rere", 14), ("Apricot (Blassfuchs)", "AA CC DD ee gg pp spsp rere"),
// --- Dilute (dd) standard (IDs 16-17) --- ("Blaufuchs", "aa CC DD ee gg PP spsp rere"),
("Dilute Gold", "AA CC dd EE GG pp spsp rere", 15), ("C-Separator", "aa CC DD ee gg pp spsp rere"),
("Dilute Platin","aa CC dd EE GG pp spsp rere", 16), ("Elfenbein", "AA CC DD EE gg pp spsp rere"),
// --- REW / Apricot / misc C-locus (IDs 18-28) --- ("Kohlfuchs", "aa CC DD ee GG PP spsp rere"),
("Altweiss (REW)", "aa CC DD EE gg pp spsp rere", 17), ("Polarfuchs", "AA CC DD ee gg PP spsp rere"),
("Apricot (Blassfuchs)","AA CC DD ee gg pp spsp rere", 18), ("Saphir", "aa CC DD EE GG pp spsp rere"),
("Blaufuchs", "aa CC DD ee gg PP spsp rere", 19), ("Orangeschimmel", "AA CC DD efef GG PP spsp rere"),
("C-Separator", "aa CC DD ee gg pp spsp rere", 20), ("Topas", "AA CC DD EE GG pp spsp rere"),
("Elfenbein", "AA CC DD EE gg pp spsp rere", 21), ("Platin-Hell", "aa CC DD EE GG pp spsp rere"),
("Kohlfuchs", "aa CC DD ee GG PP spsp rere", 22), ("Agouti dd", "AA CC dd EE GG PP spsp rere"),
("Polarfuchs", "AA CC DD ee gg PP spsp rere", 23), ("Silberagouti dd", "AA CC dd EE gg PP spsp rere"),
("Saphir", "aa CC DD EE GG pp spsp rere", 24), ("Kohlfuchs dd", "aa CC dd ee GG PP spsp rere"),
("Orangeschimmel","AA CC DD efef GG PP spsp rere", 25), ("Anthrazit dd", "aa CC dd EE gg PP spsp rere"),
("Topas", "AA CC DD EE GG pp spsp rere", 26), ("Silberschimmel", "AA CC DD efef gg PP spsp rere"),
("Platin-Hell", "aa CC DD EE GG pp spsp rere", 27), ("Polarfuchsschimmel", "AA CC DD efef gg PP spsp rere"),
// --- Dilute (dd) varieties (IDs 29-32) --- ("Algierfuchsschimmel", "AA CC DD efef GG PP spsp rere"),
("Dilute Agouti", "AA CC dd EE GG PP spsp rere", 28), ("Kohlfuchsschimmel", "aa CC DD efef GG PP spsp rere"),
("Dilute Silberagouti","AA CC dd EE gg PP spsp rere", 29), ("Blaufuchsschimmel", "aa CC DD efef gg PP spsp rere"),
("Dilute Kohlfuchs", "aa CC dd ee GG PP spsp rere", 30), ("Kohlfuchs, hell", "aa CC DD ee GG PP spsp rere"),
("Dilute Anthrazit", "aa CC dd EE gg PP spsp rere", 31), ("Goldfuchs, hell", "AA CC DD ee GG pp spsp rere"),
// --- Schimmel / Fuchsschimmel (IDs 33-37) --- ("Goldfuchsschimmel", "AA CC DD efef GG pp spsp rere"),
("Silberschimmel", "AA CC DD efef gg PP spsp rere", 36), ("Gold-Hell", "AA CC DD EE GG pp spsp rere"),
("Polarfuchsschimmel", "AA CC DD efef gg PP spsp rere", 37), ("Blaufuchs, hell", "aa CC DD ee gg PP spsp rere"),
("Algierfuchsschimmel", "AA CC DD efef GG PP spsp rere", 38), ("Rotfuchsschimmel", "aa CC DD efef GG pp spsp rere"),
("Kohlfuchsschimmel", "aa CC DD efef GG PP spsp rere", 39), ("Polarfuchs, hell", "AA CC DD ee gg PP spsp rere"),
("Blaufuchsschimmel", "aa CC DD efef gg PP spsp rere", 40), ("Kohlfuchsschimmel, hell", "aa CC DD efef GG PP spsp rere"),
// --- Hell variants (IDs 38-48) --- ("Rotfuchs, hell", "aa CC DD ee GG pp spsp rere"),
("Kohlfuchs, hell", "aa CC DD ee GG PP spsp rere", 41), ("Kohlfuchs-Hell", "aa CC DD ee GG PP spsp rere"),
("Goldfuchs, hell", "AA CC DD ee GG pp spsp rere", 42), ("Algierfuchs, hell", "AA CC DD ee GG PP spsp rere"),
("Goldfuchsschimmel", "AA CC DD efef GG pp spsp rere", 43), ("Topas dd", "AA CC dd EE GG pp spsp rere"),
("Gold-Hell", "AA CC DD EE GG pp spsp rere", 44), ("Blaufuchs dd", "aa CC dd ee gg pp spsp rere"),
("Blaufuchs, hell", "aa CC DD ee gg PP spsp rere", 45), ("Marder", "aa cchmcchm DD EE GG PP spsp rere"),
("Rotfuchsschimmel", "aa CC DD efef GG pp spsp rere", 46), ("Siam", "aa cchmch DD EE GG PP spsp rere"),
("Polarfuchs, hell", "AA CC DD ee gg PP spsp rere", 47), ("Zobel-Hell", "aa cchmch DD EE gg PP spsp rere"),
("Kohlfuchsschimmel, hell","aa CC DD efef GG PP spsp rere", 48), ("CP-Agouti", "AA cchmcchm DD EE GG PP spsp rere"),
("Rotfuchs, hell", "aa CC DD ee GG pp spsp rere", 49), ("CP-Silberagouti", "AA cchmcchm DD EE gg PP spsp rere"),
("Kohlfuchs-Hell", "aa CC DD ee GG PP spsp rere", 50), ("CP-Algierfuchs", "AA cchmcchm DD ee GG PP spsp rere"),
("Algierfuchs, hell", "AA CC DD ee GG PP spsp rere", 51), ("CP-Polarfuchs", "AA cchmcchm DD ee gg PP spsp rere"),
// --- Dilute (dd) renamed variants (IDs 49-50) --- ("CP-Fuchs", "AA cchmcchm dd ee GG PP spsp rere"),
("Dilute Topas", "AA CC dd EE GG pp spsp rere", 52), ("CP-Fuchs-Hell", "AA cchmch dd ee GG PP spsp rere"),
("Dilute Blaufuchs","aa CC dd ee gg pp spsp rere", 53), ("CP-Blaufuchs", "AA cchmcchm dd ee gg PP spsp rere"),
// --- Marder / Siam / CP- series (IDs 51-66) --- ("CP-Orangeschimmel", "AA cchmcchm DD efef GG PP spsp rere"),
("Marder", "aa cchmcchm DD EE GG PP spsp rere", 54), // GEN-3g: 5 new CP-*-Hell variants appended (IDs 62-66, no ID->Name drift)
("Siam", "aa cchmch DD EE GG PP spsp rere", 55), ("CP-Agouti-Hell", "AA cchmch DD EE GG PP spsp rere"),
("Zobel-Hell","aa cchmch DD EE gg PP spsp rere", 56), ("CP-Silberagouti-Hell", "AA cchmch DD EE gg PP spsp rere"),
("CP-Agouti", "AA cchmcchm DD EE GG PP spsp rere", 57), ("CP-Algierfuchs-Hell", "AA cchmch DD ee GG PP spsp rere"),
("CP-Silberagouti","AA cchmcchm DD EE gg PP spsp rere", 59), ("CP-Polarfuchs-Hell", "AA cchmch DD ee gg PP spsp rere"),
("CP-Algierfuchs", "AA cchmcchm DD ee GG PP spsp rere", 61), ("CP-Orangeschimmel-Hell","AA cchmch DD efef GG PP spsp rere"),
("CP-Polarfuchs", "AA cchmcchm DD ee gg PP spsp rere", 63),
("CP-Fuchs", "AA cchmcchm dd ee GG PP spsp rere", 65),
("CP-Fuchs-Hell", "AA cchmch dd ee GG PP spsp rere", 66),
("CP-Blaufuchs", "AA cchmcchm dd ee gg PP spsp rere", 67),
("CP-Orangeschimmel","AA cchmcchm DD efef GG PP spsp rere", 68),
// GEN-3g / CATALOG-RESEED: CP-*-Hell interleaved (IDs 62-66, SortOrders from backend.json)
("CP-Agouti-Hell", "AA cchmch DD EE GG PP spsp rere", 58),
("CP-Silberagouti-Hell", "AA cchmch DD EE gg PP spsp rere", 60),
("CP-Algierfuchs-Hell", "AA cchmch DD ee GG PP spsp rere", 62),
("CP-Polarfuchs-Hell", "AA cchmch DD ee gg PP spsp rere", 64),
("CP-Orangeschimmel-Hell","AA cchmch DD efef GG PP spsp rere", 69),
// CATALOG-RESEED: 4 new Dilute (dd) Fuchs varieties appended (IDs 67-70)
("Dilute Algierfuchs","AA CC dd ee GG PP spsp rere", 32),
("Dilute Goldfuchs", "AA CC dd ee GG pp spsp rere", 33),
("Dilute Rotfuchs", "aa CC dd ee GG pp spsp rere", 34),
("Dilute Polarfuchs", "AA CC dd ee gg PP spsp rere", 35),
}; };
var rows = new ColorVariety[catalog.Length]; var rows = new ColorVariety[catalog.Length];
@@ -380,11 +362,11 @@ public class ApplicationContext : DbContext
{ {
rows[i] = new ColorVariety rows[i] = new ColorVariety
{ {
// Stable, deterministic GUIDs — ID = array_index + 1 (never reorder existing entries). // Stable, deterministic GUIDs so the HasData seed is migration-stable.
Id = new Guid($"00000000-0000-0000-0000-{(i + 1):D12}"), Id = new Guid($"00000000-0000-0000-0000-{(i + 1):D12}"),
Name = catalog[i].Name, Name = catalog[i].Name,
CanonicalGenotype = catalog[i].Genotype, CanonicalGenotype = catalog[i].Genotype,
SortOrder = catalog[i].SortOrder, SortOrder = i,
}; };
} }
modelBuilder.Entity<ColorVariety>().HasData(rows); modelBuilder.Entity<ColorVariety>().HasData(rows);

View File

@@ -1,598 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
namespace GerbilManagerWebAPI.Migrations
{
/// <inheritdoc />
public partial class ReseedColorVarietiesAR5 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000016"),
column: "Name",
value: "Dilute Gold");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000017"),
column: "Name",
value: "Dilute Platin");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000029"),
column: "Name",
value: "Dilute Agouti");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000030"),
column: "Name",
value: "Dilute Silberagouti");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000031"),
column: "Name",
value: "Dilute Kohlfuchs");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000032"),
column: "Name",
value: "Dilute Anthrazit");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000033"),
column: "SortOrder",
value: 36);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000034"),
column: "SortOrder",
value: 37);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000035"),
column: "SortOrder",
value: 38);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000036"),
column: "SortOrder",
value: 39);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000037"),
column: "SortOrder",
value: 40);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000038"),
column: "SortOrder",
value: 41);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000039"),
column: "SortOrder",
value: 42);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000040"),
column: "SortOrder",
value: 43);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000041"),
column: "SortOrder",
value: 44);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000042"),
column: "SortOrder",
value: 45);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000043"),
column: "SortOrder",
value: 46);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000044"),
column: "SortOrder",
value: 47);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000045"),
column: "SortOrder",
value: 48);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000046"),
column: "SortOrder",
value: 49);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000047"),
column: "SortOrder",
value: 50);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000048"),
column: "SortOrder",
value: 51);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000049"),
columns: new[] { "Name", "SortOrder" },
values: new object[] { "Dilute Topas", 52 });
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000050"),
columns: new[] { "Name", "SortOrder" },
values: new object[] { "Dilute Blaufuchs", 53 });
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000051"),
column: "SortOrder",
value: 54);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000052"),
column: "SortOrder",
value: 55);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000053"),
column: "SortOrder",
value: 56);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000054"),
column: "SortOrder",
value: 57);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000055"),
column: "SortOrder",
value: 59);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000056"),
column: "SortOrder",
value: 61);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000057"),
column: "SortOrder",
value: 63);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000058"),
column: "SortOrder",
value: 65);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000059"),
column: "SortOrder",
value: 66);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000060"),
column: "SortOrder",
value: 67);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000061"),
column: "SortOrder",
value: 68);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000062"),
column: "SortOrder",
value: 58);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000063"),
column: "SortOrder",
value: 60);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000064"),
column: "SortOrder",
value: 62);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000066"),
column: "SortOrder",
value: 69);
migrationBuilder.InsertData(
table: "ColorVarieties",
columns: new[] { "Id", "CanonicalGenotype", "Name", "SortOrder" },
values: new object[,]
{
{ new Guid("00000000-0000-0000-0000-000000000067"), "AA CC dd ee GG PP spsp rere", "Dilute Algierfuchs", 32 },
{ new Guid("00000000-0000-0000-0000-000000000068"), "AA CC dd ee GG pp spsp rere", "Dilute Goldfuchs", 33 },
{ new Guid("00000000-0000-0000-0000-000000000069"), "aa CC dd ee GG pp spsp rere", "Dilute Rotfuchs", 34 },
{ new Guid("00000000-0000-0000-0000-000000000070"), "AA CC dd ee gg PP spsp rere", "Dilute Polarfuchs", 35 }
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000067"));
migrationBuilder.DeleteData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000068"));
migrationBuilder.DeleteData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000069"));
migrationBuilder.DeleteData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000070"));
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000016"),
column: "Name",
value: "dd Gold");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000017"),
column: "Name",
value: "dd Platin");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000029"),
column: "Name",
value: "Agouti dd");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000030"),
column: "Name",
value: "Silberagouti dd");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000031"),
column: "Name",
value: "Kohlfuchs dd");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000032"),
column: "Name",
value: "Anthrazit dd");
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000033"),
column: "SortOrder",
value: 32);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000034"),
column: "SortOrder",
value: 33);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000035"),
column: "SortOrder",
value: 34);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000036"),
column: "SortOrder",
value: 35);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000037"),
column: "SortOrder",
value: 36);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000038"),
column: "SortOrder",
value: 37);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000039"),
column: "SortOrder",
value: 38);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000040"),
column: "SortOrder",
value: 39);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000041"),
column: "SortOrder",
value: 40);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000042"),
column: "SortOrder",
value: 41);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000043"),
column: "SortOrder",
value: 42);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000044"),
column: "SortOrder",
value: 43);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000045"),
column: "SortOrder",
value: 44);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000046"),
column: "SortOrder",
value: 45);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000047"),
column: "SortOrder",
value: 46);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000048"),
column: "SortOrder",
value: 47);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000049"),
columns: new[] { "Name", "SortOrder" },
values: new object[] { "Topas dd", 48 });
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000050"),
columns: new[] { "Name", "SortOrder" },
values: new object[] { "Blaufuchs dd", 49 });
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000051"),
column: "SortOrder",
value: 50);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000052"),
column: "SortOrder",
value: 51);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000053"),
column: "SortOrder",
value: 52);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000054"),
column: "SortOrder",
value: 53);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000055"),
column: "SortOrder",
value: 54);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000056"),
column: "SortOrder",
value: 55);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000057"),
column: "SortOrder",
value: 56);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000058"),
column: "SortOrder",
value: 57);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000059"),
column: "SortOrder",
value: 58);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000060"),
column: "SortOrder",
value: 59);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000061"),
column: "SortOrder",
value: 60);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000062"),
column: "SortOrder",
value: 61);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000063"),
column: "SortOrder",
value: 62);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000064"),
column: "SortOrder",
value: 63);
migrationBuilder.UpdateData(
table: "ColorVarieties",
keyColumn: "Id",
keyValue: new Guid("00000000-0000-0000-0000-000000000066"),
column: "SortOrder",
value: 65);
}
}
}

View File

@@ -321,14 +321,14 @@ namespace GerbilManagerWebAPI.Migrations
{ {
Id = new Guid("00000000-0000-0000-0000-000000000016"), Id = new Guid("00000000-0000-0000-0000-000000000016"),
CanonicalGenotype = "AA CC dd EE GG pp spsp rere", CanonicalGenotype = "AA CC dd EE GG pp spsp rere",
Name = "Dilute Gold", Name = "dd Gold",
SortOrder = 15 SortOrder = 15
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000017"), Id = new Guid("00000000-0000-0000-0000-000000000017"),
CanonicalGenotype = "aa CC dd EE GG pp spsp rere", CanonicalGenotype = "aa CC dd EE GG pp spsp rere",
Name = "Dilute Platin", Name = "dd Platin",
SortOrder = 16 SortOrder = 16
}, },
new new
@@ -412,28 +412,28 @@ namespace GerbilManagerWebAPI.Migrations
{ {
Id = new Guid("00000000-0000-0000-0000-000000000029"), Id = new Guid("00000000-0000-0000-0000-000000000029"),
CanonicalGenotype = "AA CC dd EE GG PP spsp rere", CanonicalGenotype = "AA CC dd EE GG PP spsp rere",
Name = "Dilute Agouti", Name = "Agouti dd",
SortOrder = 28 SortOrder = 28
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000030"), Id = new Guid("00000000-0000-0000-0000-000000000030"),
CanonicalGenotype = "AA CC dd EE gg PP spsp rere", CanonicalGenotype = "AA CC dd EE gg PP spsp rere",
Name = "Dilute Silberagouti", Name = "Silberagouti dd",
SortOrder = 29 SortOrder = 29
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000031"), Id = new Guid("00000000-0000-0000-0000-000000000031"),
CanonicalGenotype = "aa CC dd ee GG PP spsp rere", CanonicalGenotype = "aa CC dd ee GG PP spsp rere",
Name = "Dilute Kohlfuchs", Name = "Kohlfuchs dd",
SortOrder = 30 SortOrder = 30
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000032"), Id = new Guid("00000000-0000-0000-0000-000000000032"),
CanonicalGenotype = "aa CC dd EE gg PP spsp rere", CanonicalGenotype = "aa CC dd EE gg PP spsp rere",
Name = "Dilute Anthrazit", Name = "Anthrazit dd",
SortOrder = 31 SortOrder = 31
}, },
new new
@@ -441,224 +441,224 @@ namespace GerbilManagerWebAPI.Migrations
Id = new Guid("00000000-0000-0000-0000-000000000033"), Id = new Guid("00000000-0000-0000-0000-000000000033"),
CanonicalGenotype = "AA CC DD efef gg PP spsp rere", CanonicalGenotype = "AA CC DD efef gg PP spsp rere",
Name = "Silberschimmel", Name = "Silberschimmel",
SortOrder = 36 SortOrder = 32
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000034"), Id = new Guid("00000000-0000-0000-0000-000000000034"),
CanonicalGenotype = "AA CC DD efef gg PP spsp rere", CanonicalGenotype = "AA CC DD efef gg PP spsp rere",
Name = "Polarfuchsschimmel", Name = "Polarfuchsschimmel",
SortOrder = 37 SortOrder = 33
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000035"), Id = new Guid("00000000-0000-0000-0000-000000000035"),
CanonicalGenotype = "AA CC DD efef GG PP spsp rere", CanonicalGenotype = "AA CC DD efef GG PP spsp rere",
Name = "Algierfuchsschimmel", Name = "Algierfuchsschimmel",
SortOrder = 38 SortOrder = 34
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000036"), Id = new Guid("00000000-0000-0000-0000-000000000036"),
CanonicalGenotype = "aa CC DD efef GG PP spsp rere", CanonicalGenotype = "aa CC DD efef GG PP spsp rere",
Name = "Kohlfuchsschimmel", Name = "Kohlfuchsschimmel",
SortOrder = 39 SortOrder = 35
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000037"), Id = new Guid("00000000-0000-0000-0000-000000000037"),
CanonicalGenotype = "aa CC DD efef gg PP spsp rere", CanonicalGenotype = "aa CC DD efef gg PP spsp rere",
Name = "Blaufuchsschimmel", Name = "Blaufuchsschimmel",
SortOrder = 40 SortOrder = 36
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000038"), Id = new Guid("00000000-0000-0000-0000-000000000038"),
CanonicalGenotype = "aa CC DD ee GG PP spsp rere", CanonicalGenotype = "aa CC DD ee GG PP spsp rere",
Name = "Kohlfuchs, hell", Name = "Kohlfuchs, hell",
SortOrder = 41 SortOrder = 37
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000039"), Id = new Guid("00000000-0000-0000-0000-000000000039"),
CanonicalGenotype = "AA CC DD ee GG pp spsp rere", CanonicalGenotype = "AA CC DD ee GG pp spsp rere",
Name = "Goldfuchs, hell", Name = "Goldfuchs, hell",
SortOrder = 42 SortOrder = 38
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000040"), Id = new Guid("00000000-0000-0000-0000-000000000040"),
CanonicalGenotype = "AA CC DD efef GG pp spsp rere", CanonicalGenotype = "AA CC DD efef GG pp spsp rere",
Name = "Goldfuchsschimmel", Name = "Goldfuchsschimmel",
SortOrder = 43 SortOrder = 39
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000041"), Id = new Guid("00000000-0000-0000-0000-000000000041"),
CanonicalGenotype = "AA CC DD EE GG pp spsp rere", CanonicalGenotype = "AA CC DD EE GG pp spsp rere",
Name = "Gold-Hell", Name = "Gold-Hell",
SortOrder = 44 SortOrder = 40
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000042"), Id = new Guid("00000000-0000-0000-0000-000000000042"),
CanonicalGenotype = "aa CC DD ee gg PP spsp rere", CanonicalGenotype = "aa CC DD ee gg PP spsp rere",
Name = "Blaufuchs, hell", Name = "Blaufuchs, hell",
SortOrder = 45 SortOrder = 41
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000043"), Id = new Guid("00000000-0000-0000-0000-000000000043"),
CanonicalGenotype = "aa CC DD efef GG pp spsp rere", CanonicalGenotype = "aa CC DD efef GG pp spsp rere",
Name = "Rotfuchsschimmel", Name = "Rotfuchsschimmel",
SortOrder = 46 SortOrder = 42
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000044"), Id = new Guid("00000000-0000-0000-0000-000000000044"),
CanonicalGenotype = "AA CC DD ee gg PP spsp rere", CanonicalGenotype = "AA CC DD ee gg PP spsp rere",
Name = "Polarfuchs, hell", Name = "Polarfuchs, hell",
SortOrder = 47 SortOrder = 43
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000045"), Id = new Guid("00000000-0000-0000-0000-000000000045"),
CanonicalGenotype = "aa CC DD efef GG PP spsp rere", CanonicalGenotype = "aa CC DD efef GG PP spsp rere",
Name = "Kohlfuchsschimmel, hell", Name = "Kohlfuchsschimmel, hell",
SortOrder = 48 SortOrder = 44
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000046"), Id = new Guid("00000000-0000-0000-0000-000000000046"),
CanonicalGenotype = "aa CC DD ee GG pp spsp rere", CanonicalGenotype = "aa CC DD ee GG pp spsp rere",
Name = "Rotfuchs, hell", Name = "Rotfuchs, hell",
SortOrder = 49 SortOrder = 45
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000047"), Id = new Guid("00000000-0000-0000-0000-000000000047"),
CanonicalGenotype = "aa CC DD ee GG PP spsp rere", CanonicalGenotype = "aa CC DD ee GG PP spsp rere",
Name = "Kohlfuchs-Hell", Name = "Kohlfuchs-Hell",
SortOrder = 50 SortOrder = 46
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000048"), Id = new Guid("00000000-0000-0000-0000-000000000048"),
CanonicalGenotype = "AA CC DD ee GG PP spsp rere", CanonicalGenotype = "AA CC DD ee GG PP spsp rere",
Name = "Algierfuchs, hell", Name = "Algierfuchs, hell",
SortOrder = 51 SortOrder = 47
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000049"), Id = new Guid("00000000-0000-0000-0000-000000000049"),
CanonicalGenotype = "AA CC dd EE GG pp spsp rere", CanonicalGenotype = "AA CC dd EE GG pp spsp rere",
Name = "Dilute Topas", Name = "Topas dd",
SortOrder = 52 SortOrder = 48
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000050"), Id = new Guid("00000000-0000-0000-0000-000000000050"),
CanonicalGenotype = "aa CC dd ee gg pp spsp rere", CanonicalGenotype = "aa CC dd ee gg pp spsp rere",
Name = "Dilute Blaufuchs", Name = "Blaufuchs dd",
SortOrder = 53 SortOrder = 49
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000051"), Id = new Guid("00000000-0000-0000-0000-000000000051"),
CanonicalGenotype = "aa cchmcchm DD EE GG PP spsp rere", CanonicalGenotype = "aa cchmcchm DD EE GG PP spsp rere",
Name = "Marder", Name = "Marder",
SortOrder = 54 SortOrder = 50
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000052"), Id = new Guid("00000000-0000-0000-0000-000000000052"),
CanonicalGenotype = "aa cchmch DD EE GG PP spsp rere", CanonicalGenotype = "aa cchmch DD EE GG PP spsp rere",
Name = "Siam", Name = "Siam",
SortOrder = 55 SortOrder = 51
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000053"), Id = new Guid("00000000-0000-0000-0000-000000000053"),
CanonicalGenotype = "aa cchmch DD EE gg PP spsp rere", CanonicalGenotype = "aa cchmch DD EE gg PP spsp rere",
Name = "Zobel-Hell", Name = "Zobel-Hell",
SortOrder = 56 SortOrder = 52
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000054"), Id = new Guid("00000000-0000-0000-0000-000000000054"),
CanonicalGenotype = "AA cchmcchm DD EE GG PP spsp rere", CanonicalGenotype = "AA cchmcchm DD EE GG PP spsp rere",
Name = "CP-Agouti", Name = "CP-Agouti",
SortOrder = 57 SortOrder = 53
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000055"), Id = new Guid("00000000-0000-0000-0000-000000000055"),
CanonicalGenotype = "AA cchmcchm DD EE gg PP spsp rere", CanonicalGenotype = "AA cchmcchm DD EE gg PP spsp rere",
Name = "CP-Silberagouti", Name = "CP-Silberagouti",
SortOrder = 59 SortOrder = 54
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000056"), Id = new Guid("00000000-0000-0000-0000-000000000056"),
CanonicalGenotype = "AA cchmcchm DD ee GG PP spsp rere", CanonicalGenotype = "AA cchmcchm DD ee GG PP spsp rere",
Name = "CP-Algierfuchs", Name = "CP-Algierfuchs",
SortOrder = 61 SortOrder = 55
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000057"), Id = new Guid("00000000-0000-0000-0000-000000000057"),
CanonicalGenotype = "AA cchmcchm DD ee gg PP spsp rere", CanonicalGenotype = "AA cchmcchm DD ee gg PP spsp rere",
Name = "CP-Polarfuchs", Name = "CP-Polarfuchs",
SortOrder = 63 SortOrder = 56
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000058"), Id = new Guid("00000000-0000-0000-0000-000000000058"),
CanonicalGenotype = "AA cchmcchm dd ee GG PP spsp rere", CanonicalGenotype = "AA cchmcchm dd ee GG PP spsp rere",
Name = "CP-Fuchs", Name = "CP-Fuchs",
SortOrder = 65 SortOrder = 57
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000059"), Id = new Guid("00000000-0000-0000-0000-000000000059"),
CanonicalGenotype = "AA cchmch dd ee GG PP spsp rere", CanonicalGenotype = "AA cchmch dd ee GG PP spsp rere",
Name = "CP-Fuchs-Hell", Name = "CP-Fuchs-Hell",
SortOrder = 66 SortOrder = 58
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000060"), Id = new Guid("00000000-0000-0000-0000-000000000060"),
CanonicalGenotype = "AA cchmcchm dd ee gg PP spsp rere", CanonicalGenotype = "AA cchmcchm dd ee gg PP spsp rere",
Name = "CP-Blaufuchs", Name = "CP-Blaufuchs",
SortOrder = 67 SortOrder = 59
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000061"), Id = new Guid("00000000-0000-0000-0000-000000000061"),
CanonicalGenotype = "AA cchmcchm DD efef GG PP spsp rere", CanonicalGenotype = "AA cchmcchm DD efef GG PP spsp rere",
Name = "CP-Orangeschimmel", Name = "CP-Orangeschimmel",
SortOrder = 68 SortOrder = 60
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000062"), Id = new Guid("00000000-0000-0000-0000-000000000062"),
CanonicalGenotype = "AA cchmch DD EE GG PP spsp rere", CanonicalGenotype = "AA cchmch DD EE GG PP spsp rere",
Name = "CP-Agouti-Hell", Name = "CP-Agouti-Hell",
SortOrder = 58 SortOrder = 61
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000063"), Id = new Guid("00000000-0000-0000-0000-000000000063"),
CanonicalGenotype = "AA cchmch DD EE gg PP spsp rere", CanonicalGenotype = "AA cchmch DD EE gg PP spsp rere",
Name = "CP-Silberagouti-Hell", Name = "CP-Silberagouti-Hell",
SortOrder = 60 SortOrder = 62
}, },
new new
{ {
Id = new Guid("00000000-0000-0000-0000-000000000064"), Id = new Guid("00000000-0000-0000-0000-000000000064"),
CanonicalGenotype = "AA cchmch DD ee GG PP spsp rere", CanonicalGenotype = "AA cchmch DD ee GG PP spsp rere",
Name = "CP-Algierfuchs-Hell", Name = "CP-Algierfuchs-Hell",
SortOrder = 62 SortOrder = 63
}, },
new new
{ {
@@ -672,35 +672,7 @@ namespace GerbilManagerWebAPI.Migrations
Id = new Guid("00000000-0000-0000-0000-000000000066"), Id = new Guid("00000000-0000-0000-0000-000000000066"),
CanonicalGenotype = "AA cchmch DD efef GG PP spsp rere", CanonicalGenotype = "AA cchmch DD efef GG PP spsp rere",
Name = "CP-Orangeschimmel-Hell", Name = "CP-Orangeschimmel-Hell",
SortOrder = 69 SortOrder = 65
},
new
{
Id = new Guid("00000000-0000-0000-0000-000000000067"),
CanonicalGenotype = "AA CC dd ee GG PP spsp rere",
Name = "Dilute Algierfuchs",
SortOrder = 32
},
new
{
Id = new Guid("00000000-0000-0000-0000-000000000068"),
CanonicalGenotype = "AA CC dd ee GG pp spsp rere",
Name = "Dilute Goldfuchs",
SortOrder = 33
},
new
{
Id = new Guid("00000000-0000-0000-0000-000000000069"),
CanonicalGenotype = "aa CC dd ee GG pp spsp rere",
Name = "Dilute Rotfuchs",
SortOrder = 34
},
new
{
Id = new Guid("00000000-0000-0000-0000-000000000070"),
CanonicalGenotype = "AA CC dd ee gg PP spsp rere",
Name = "Dilute Polarfuchs",
SortOrder = 35
}); });
}); });

View File

@@ -1,5 +1,5 @@
import { de } from '../strings/de' import { de } from '../strings/de'
import { ALL_TRAITS } from '../format/traits' import { ALL_TRAITS, TRAIT_CATEGORIES } from '../format/traits'
import './charakterbogen.css' import './charakterbogen.css'
export interface CharakterbogenProps { export interface CharakterbogenProps {
@@ -10,12 +10,6 @@ export interface CharakterbogenProps {
onNoteChange: (note: string) => void onNoteChange: (note: string) => void
} }
/**
* FEAT-14: character sheet — a checkbox grid of traits + a free note.
* Controlled & reusable: rendered on the animal detail page (persisted) and in
* the Abgabe listing composer (feeds the AI sale-text). German labels from
* de.character.traits; the stored value is the trait KEY.
*/
export default function Charakterbogen({ export default function Charakterbogen({
traits, traits,
note, note,
@@ -29,26 +23,32 @@ export default function Charakterbogen({
const next = new Set(selected) const next = new Set(selected)
if (next.has(key)) next.delete(key) if (next.has(key)) next.delete(key)
else next.add(key) else next.add(key)
// Preserve the vocabulary order for stable output. // Preserve vocabulary (category) order for stable output.
onTraitsChange(ALL_TRAITS.filter((tr) => next.has(tr.key)).map((tr) => tr.key)) onTraitsChange(ALL_TRAITS.filter((tr) => next.has(tr.key)).map((tr) => tr.key))
} }
return ( return (
<div className="charakterbogen"> <div className="charakterbogen">
{TRAIT_CATEGORIES.map((cat) => (
<section key={cat.category} className="trait-category">
<h4 className="trait-category__heading">{cat.category}</h4>
<ul className="trait-grid"> <ul className="trait-grid">
{ALL_TRAITS.map((tr) => ( {cat.traits.map((tr) => (
<li key={tr.key}> <li key={tr.key}>
<label className="trait-chip"> <label className={`trait-chip${tr.warn ? ' trait-chip--warn' : ''}`}>
<input <input
type="checkbox" type="checkbox"
checked={selected.has(tr.key)} checked={selected.has(tr.key)}
onChange={() => toggle(tr.key)} onChange={() => toggle(tr.key)}
/> />
<span>{tr.label}</span> <span>{tr.label}</span>
{tr.warn && <span className="trait-warn-badge">{t.warnLabel}</span>}
</label> </label>
</li> </li>
))} ))}
</ul> </ul>
</section>
))}
<label className="field"> <label className="field">
<span>{t.noteLabel}</span> <span>{t.noteLabel}</span>
<textarea <textarea

View File

@@ -1,8 +1,21 @@
/* FEAT-14 Charakterbogen — trait checkbox grid (mobile-first). */ /* CHARAKTERBOGEN-2 — categorised trait grid with warn-signal styling (mobile-first). */
.trait-category {
margin-bottom: 0.25rem;
}
.trait-category__heading {
font-size: 0.78rem;
font-weight: 600;
color: var(--color-muted, #666);
text-transform: uppercase;
letter-spacing: 0.04em;
margin: 0.75rem 0 0.35rem;
}
.charakterbogen .trait-grid { .charakterbogen .trait-grid {
list-style: none; list-style: none;
margin: 0 0 0.75rem; margin: 0 0 0.5rem;
padding: 0; padding: 0;
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
@@ -39,3 +52,16 @@
min-height: 0; min-height: 0;
flex: 0 0 auto; flex: 0 0 auto;
} }
.trait-chip--warn {
border-color: #d97706;
background: #fff7ed;
}
.trait-warn-badge {
margin-left: auto;
font-size: 0.68rem;
font-weight: 600;
color: #d97706;
white-space: nowrap;
}

View File

@@ -0,0 +1,91 @@
import { describe, it, expect } from 'vitest'
import { ALL_TRAITS, TRAIT_CATEGORIES, traitLabel, traitLabels, isWarnTrait } from '../traits'
describe('trait catalog', () => {
it('has 4 categories', () => {
expect(TRAIT_CATEGORIES).toHaveLength(4)
})
it('category names match spec', () => {
const names = TRAIT_CATEGORIES.map((c) => c.category)
expect(names).toEqual([
'Sozialverhalten',
'Eignung & Umgang',
'Hobbys & Eigenarten',
'Wesen & Temperament',
])
})
it('ALL_TRAITS flattens all categories', () => {
const total = TRAIT_CATEGORIES.reduce((sum, c) => sum + c.traits.length, 0)
expect(ALL_TRAITS).toHaveLength(total)
})
it('all keys are unique', () => {
const keys = ALL_TRAITS.map((t) => t.key)
expect(new Set(keys).size).toBe(keys.length)
})
it('existing 15 keys are still present (stored on live animals)', () => {
const legacy = [
'zutraulich', 'handzahm', 'neugierig', 'aufgeschlossen', 'ruhig', 'lebhaft',
'verschmust', 'eigenstaendig', 'anfaengergeeignet', 'futterfreudig',
'buddelt', 'klettert', 'laufrad', 'vertraeglich', 'schreckhaft',
]
const allKeys = new Set(ALL_TRAITS.map((t) => t.key))
for (const key of legacy) {
expect(allKeys.has(key), `missing legacy key: ${key}`).toBe(true)
}
})
it('new keys are present', () => {
const newKeys = [
'dominant', 'rangniedrig', 'sozialkompetent', 'schwer-vergesellschaftbar',
'erfahrene-halter', 'beobachtungstier', 'familiengeeignet',
'schredder', 'nestbauer', 'territorial',
]
const allKeys = new Set(ALL_TRAITS.map((t) => t.key))
for (const key of newKeys) {
expect(allKeys.has(key), `missing new key: ${key}`).toBe(true)
}
})
it('warn traits are schwer-vergesellschaftbar and territorial', () => {
expect(isWarnTrait('schwer-vergesellschaftbar')).toBe(true)
expect(isWarnTrait('territorial')).toBe(true)
})
it('non-warn traits return false from isWarnTrait', () => {
expect(isWarnTrait('zutraulich')).toBe(false)
expect(isWarnTrait('dominant')).toBe(false)
expect(isWarnTrait('beobachtungstier')).toBe(false)
expect(isWarnTrait('schreckhaft')).toBe(false)
})
it('unknown key returns false from isWarnTrait', () => {
expect(isWarnTrait('not-a-real-key')).toBe(false)
})
it('traitLabel returns German label for known key', () => {
expect(traitLabel('zutraulich')).toBe('zutraulich')
expect(traitLabel('dominant')).toBe('dominant (Leittier)')
expect(traitLabel('schwer-vergesellschaftbar')).toBe('schwer vergesellschaftbar')
expect(traitLabel('territorial')).toBe('territorial')
})
it('traitLabel returns the key itself for unknown key', () => {
expect(traitLabel('not-a-real-key')).toBe('not-a-real-key')
})
it('traitLabels maps a list of keys to labels', () => {
expect(traitLabels(['zutraulich', 'dominant'])).toEqual([
'zutraulich',
'dominant (Leittier)',
])
})
it('traitLabels handles null and undefined gracefully', () => {
expect(traitLabels(null)).toEqual([])
expect(traitLabels(undefined)).toEqual([])
})
})

View File

@@ -1,9 +1,23 @@
/** FEAT-14: map character trait KEYS (stored) <-> German LABELS (de.character.traits). */ /** CHARAKTERBOGEN-2: map character trait KEYS (stored) <-> German LABELS (de.character.traitCategories). */
import { de } from '../strings/de' import { de } from '../strings/de'
export const ALL_TRAITS = de.character.traits export interface TraitEntry {
key: string
label: string
warn?: true
}
const LABEL_BY_KEY = new Map<string, string>(de.character.traits.map((t) => [t.key, t.label])) export interface TraitCategory {
category: string
traits: readonly TraitEntry[]
}
export const TRAIT_CATEGORIES: ReadonlyArray<TraitCategory> =
de.character.traitCategories as unknown as ReadonlyArray<TraitCategory>
export const ALL_TRAITS: readonly TraitEntry[] = TRAIT_CATEGORIES.flatMap((c) => c.traits)
const LABEL_BY_KEY = new Map<string, string>(ALL_TRAITS.map((t) => [t.key, t.label]))
export function traitLabel(key: string): string { export function traitLabel(key: string): string {
return LABEL_BY_KEY.get(key) ?? key return LABEL_BY_KEY.get(key) ?? key
@@ -13,3 +27,7 @@ export function traitLabel(key: string): string {
export function traitLabels(keys: readonly string[] | null | undefined): string[] { export function traitLabels(keys: readonly string[] | null | undefined): string[] {
return (keys ?? []).map(traitLabel) return (keys ?? []).map(traitLabel)
} }
export function isWarnTrait(key: string): boolean {
return ALL_TRAITS.some((t) => t.key === key && t.warn === true)
}

View File

@@ -784,9 +784,9 @@ export const de = {
}, },
unknownFarbschlag: 'Unbekannter Farbschlag', unknownFarbschlag: 'Unbekannter Farbschlag',
}, },
// ── FEAT-14 (Kevin): Charakterbogen — Eigenschaften + Notiz, speist den KI-Verkaufstext ── // ── FEAT-14 / CHARAKTERBOGEN-2: Charakterbogen — Eigenschaften + Notiz, speist KI-Verkaufstext ──
// Traits: stabile KEYS (gespeichert) + deutsche LABELS (UI + KI-Prompt). // Traits: stabile KEYS (gespeichert, NIEMALS umbenennen) + deutsche LABELS (UI + KI-Prompt).
// Erweitern = eine Zeile in der Liste; Julian verfeinert die Auswahl. // Neue Traits = neuen Eintrag hinzufügen; warn:true = Warnsignal (visuell abgesetzt).
character: { character: {
sectionTitle: 'Charakter & Eigenschaften', sectionTitle: 'Charakter & Eigenschaften',
noteLabel: 'Notizen zum Charakter', noteLabel: 'Notizen zum Charakter',
@@ -794,6 +794,40 @@ export const de = {
save: 'Charakter speichern', save: 'Charakter speichern',
saved: 'Charakter gespeichert.', saved: 'Charakter gespeichert.',
none: 'Noch keine Eigenschaften ausgewählt.', none: 'Noch keine Eigenschaften ausgewählt.',
warnLabel: '⚠ Warnsignal',
traitCategories: [
{
category: 'Sozialverhalten',
traits: [
{ key: 'dominant', label: 'dominant (Leittier)' },
{ key: 'rangniedrig', label: 'rangniedrig / unterwürfig' },
{ key: 'sozialkompetent', label: 'sozialkompetent / gut sozialisiert' },
{ key: 'schwer-vergesellschaftbar', label: 'schwer vergesellschaftbar', warn: true },
],
},
{
category: 'Eignung & Umgang',
traits: [
{ key: 'anfaengergeeignet', label: 'anfängergeeignet' },
{ key: 'erfahrene-halter', label: 'für erfahrene Halter' },
{ key: 'beobachtungstier', label: 'reines Beobachtungstier' },
{ key: 'familiengeeignet', label: 'familiengeeignet / stressresistent' },
],
},
{
category: 'Hobbys & Eigenarten',
traits: [
{ key: 'futterfreudig', label: 'futterfreudig' },
{ key: 'buddelt', label: 'buddelt gern' },
{ key: 'klettert', label: 'klettert gern' },
{ key: 'laufrad', label: 'läuft gern im Laufrad' },
{ key: 'schredder', label: 'Schredder-Meister' },
{ key: 'nestbauer', label: 'Nestbauer / Architekt' },
{ key: 'territorial', label: 'territorial', warn: true },
],
},
{
category: 'Wesen & Temperament',
traits: [ traits: [
{ key: 'zutraulich', label: 'zutraulich' }, { key: 'zutraulich', label: 'zutraulich' },
{ key: 'handzahm', label: 'handzahm' }, { key: 'handzahm', label: 'handzahm' },
@@ -803,15 +837,12 @@ export const de = {
{ key: 'lebhaft', label: 'lebhaft / aktiv' }, { key: 'lebhaft', label: 'lebhaft / aktiv' },
{ key: 'verschmust', label: 'verschmust' }, { key: 'verschmust', label: 'verschmust' },
{ key: 'eigenstaendig', label: 'eigenständig' }, { key: 'eigenstaendig', label: 'eigenständig' },
{ key: 'anfaengergeeignet', label: 'anfängergeeignet' },
{ key: 'futterfreudig', label: 'futterfreudig' },
{ key: 'buddelt', label: 'buddelt gern' },
{ key: 'klettert', label: 'klettert gern' },
{ key: 'laufrad', label: 'läuft gern im Laufrad' },
{ key: 'vertraeglich', label: 'gut verträglich' }, { key: 'vertraeglich', label: 'gut verträglich' },
{ key: 'schreckhaft', label: 'schreckhaft' }, { key: 'schreckhaft', label: 'schreckhaft' },
], ],
}, },
],
},
// ── UX-MOBILE-1 (Kevin): FilterPanel — einklappbare Filter auf Mobil ── // ── UX-MOBILE-1 (Kevin): FilterPanel — einklappbare Filter auf Mobil ──
filterPanel: { filterPanel: {
toggleButton: 'Filter', toggleButton: 'Filter',