Compare commits
1 Commits
0d4b560df8
...
feature/ux
| Author | SHA1 | Date | |
|---|---|---|---|
| d116b8d8f1 |
@@ -545,32 +545,6 @@ namespace GerbilManager.Tests
|
||||
finally { try { Directory.Delete(dir, recursive: true); } catch { } }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SeedGen3g_existing_varieties_preserve_id_name_binding()
|
||||
{
|
||||
// SEED-HELL bounce regression: the 61 existing entries must NOT change their
|
||||
// Id->Name binding after GEN-3g. The 5 new entries (IDs 62-66) are appended.
|
||||
// A hand-assigned Gerbil.ColorVarietyId pointing to "CP-Fuchs" (ID 58) must
|
||||
// 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 (index 57 in old catalog, 0-based) = CP-Fuchs — must still be CP-Fuchs
|
||||
var cpFuchsId = new Guid("00000000-0000-0000-0000-000000000058");
|
||||
var cpFuchs = db.ColorVarieties.Find(cpFuchsId);
|
||||
Assert.NotNull(cpFuchs);
|
||||
Assert.Equal("CP-Fuchs", cpFuchs!.Name);
|
||||
|
||||
// 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-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-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);
|
||||
|
||||
// Total count is exactly 66
|
||||
Assert.Equal(66, db.ColorVarieties.Count());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("01.02.2020", 2020, 2, 1)]
|
||||
[InlineData("5.3.21", 2021, 3, 5)]
|
||||
|
||||
@@ -231,10 +231,6 @@ public class ApplicationContext : DbContext
|
||||
/// </summary>
|
||||
private static void SeedColorVarieties(ModelBuilder modelBuilder)
|
||||
{
|
||||
// GEN-3g (Kevin): 5 CP-*-Hell variants appended at the end (IDs 62-66).
|
||||
// Existing 61 entries are UNCHANGED (same ID->Name binding preserved).
|
||||
// SortOrder for new entries is appended; Kevin's frontend catalog handles
|
||||
// the interleaved display order via its own sortOrder values.
|
||||
(string Name, string Genotype)[] catalog =
|
||||
{
|
||||
("Pink Eyed White (PEW)", "AA chch DD EE GG pp spsp rere"),
|
||||
@@ -298,12 +294,6 @@ public class ApplicationContext : DbContext
|
||||
("CP-Fuchs-Hell", "AA cchmch dd ee GG PP spsp rere"),
|
||||
("CP-Blaufuchs", "AA cchmcchm dd ee gg PP spsp rere"),
|
||||
("CP-Orangeschimmel", "AA cchmcchm DD efef GG PP spsp rere"),
|
||||
// GEN-3g: 5 new CP-*-Hell variants appended (IDs 62-66, no ID->Name drift)
|
||||
("CP-Agouti-Hell", "AA cchmch DD EE GG PP spsp rere"),
|
||||
("CP-Silberagouti-Hell", "AA cchmch DD EE gg PP spsp rere"),
|
||||
("CP-Algierfuchs-Hell", "AA cchmch DD ee GG PP spsp rere"),
|
||||
("CP-Polarfuchs-Hell", "AA cchmch DD ee gg PP spsp rere"),
|
||||
("CP-Orangeschimmel-Hell","AA cchmch DD efef GG PP spsp rere"),
|
||||
};
|
||||
|
||||
var rows = new ColorVariety[catalog.Length];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,58 +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 ReseedColorVarietiesGen3g : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.InsertData(
|
||||
table: "ColorVarieties",
|
||||
columns: new[] { "Id", "CanonicalGenotype", "Name", "SortOrder" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("00000000-0000-0000-0000-000000000062"), "AA cchmch DD EE GG PP spsp rere", "CP-Agouti-Hell", 61 },
|
||||
{ new Guid("00000000-0000-0000-0000-000000000063"), "AA cchmch DD EE gg PP spsp rere", "CP-Silberagouti-Hell", 62 },
|
||||
{ new Guid("00000000-0000-0000-0000-000000000064"), "AA cchmch DD ee GG PP spsp rere", "CP-Algierfuchs-Hell", 63 },
|
||||
{ new Guid("00000000-0000-0000-0000-000000000065"), "AA cchmch DD ee gg PP spsp rere", "CP-Polarfuchs-Hell", 64 },
|
||||
{ new Guid("00000000-0000-0000-0000-000000000066"), "AA cchmch DD efef GG PP spsp rere", "CP-Orangeschimmel-Hell", 65 }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ColorVarieties",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("00000000-0000-0000-0000-000000000062"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ColorVarieties",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("00000000-0000-0000-0000-000000000063"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ColorVarieties",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("00000000-0000-0000-0000-000000000064"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ColorVarieties",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("00000000-0000-0000-0000-000000000065"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ColorVarieties",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("00000000-0000-0000-0000-000000000066"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -605,41 +605,6 @@ namespace GerbilManagerWebAPI.Migrations
|
||||
CanonicalGenotype = "AA cchmcchm DD efef GG PP spsp rere",
|
||||
Name = "CP-Orangeschimmel",
|
||||
SortOrder = 60
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("00000000-0000-0000-0000-000000000062"),
|
||||
CanonicalGenotype = "AA cchmch DD EE GG PP spsp rere",
|
||||
Name = "CP-Agouti-Hell",
|
||||
SortOrder = 61
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("00000000-0000-0000-0000-000000000063"),
|
||||
CanonicalGenotype = "AA cchmch DD EE gg PP spsp rere",
|
||||
Name = "CP-Silberagouti-Hell",
|
||||
SortOrder = 62
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("00000000-0000-0000-0000-000000000064"),
|
||||
CanonicalGenotype = "AA cchmch DD ee GG PP spsp rere",
|
||||
Name = "CP-Algierfuchs-Hell",
|
||||
SortOrder = 63
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("00000000-0000-0000-0000-000000000065"),
|
||||
CanonicalGenotype = "AA cchmch DD ee gg PP spsp rere",
|
||||
Name = "CP-Polarfuchs-Hell",
|
||||
SortOrder = 64
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("00000000-0000-0000-0000-000000000066"),
|
||||
CanonicalGenotype = "AA cchmch DD efef GG PP spsp rere",
|
||||
Name = "CP-Orangeschimmel-Hell",
|
||||
SortOrder = 65
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
54
gerbil-manager-web/e2e/genotype-table.spec.ts
Normal file
54
gerbil-manager-web/e2e/genotype-table.spec.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* UX-MOBILE-2: Genotyp-Tabellen-Overflow — die Tabelle scrollt horizontal,
|
||||
* die Seite selbst bleibt NICHT breiter als der Viewport (kein horizontaler
|
||||
* Page-Overflow auf 390px).
|
||||
*/
|
||||
import { de, expect, skipUnlessMock, test } from './fixtures'
|
||||
|
||||
const tl = de.pages.litters
|
||||
|
||||
test('Phone: Genotyp-Detail-Tabelle scrollt im eigenen Wrapper, kein Page-Overflow', async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
skipUnlessMock()
|
||||
if (testInfo.project.name !== 'phone') return
|
||||
|
||||
// Wurf w-kruemel hat beide Eltern mit Genotypen → BreedingResultView rendert.
|
||||
await page.goto('/wuerfe/w-kruemel')
|
||||
await expect(page.getByRole('heading', { name: 'Wurf K' })).toBeVisible()
|
||||
await expect(page.getByText(tl.detail.expectedColors).first()).toBeVisible()
|
||||
|
||||
// Genotyp-Detail-Tabelle ausklappen.
|
||||
await page.getByRole('button', { name: de.pages.genetik.showGenotypes }).click()
|
||||
|
||||
// Scroll-Wrapper und Tabelle müssen vorhanden und sichtbar sein.
|
||||
const wrapper = page.locator('.genotype-table-scroll').first()
|
||||
await expect(wrapper).toBeVisible()
|
||||
await expect(wrapper.locator('.genotype-table')).toBeVisible()
|
||||
|
||||
// Wrapper ist selbst scrollbar (Tabelle breiter als der sichtbare Bereich).
|
||||
const wrapperScrollable = await wrapper.evaluate(
|
||||
(el) => el.scrollWidth > el.clientWidth,
|
||||
)
|
||||
expect(wrapperScrollable).toBe(true)
|
||||
|
||||
// Die Seite selbst darf NICHT breiter als der Viewport sein.
|
||||
const pageOverflow = await page.evaluate(
|
||||
() => document.documentElement.scrollWidth > document.documentElement.clientWidth,
|
||||
)
|
||||
expect(pageOverflow).toBe(false)
|
||||
})
|
||||
|
||||
test('Desktop: Genotyp-Detail-Tabelle zeigt Wrapper auch auf breitem Viewport', async ({
|
||||
page,
|
||||
}, testInfo) => {
|
||||
skipUnlessMock()
|
||||
if (testInfo.project.name !== 'desktop') return
|
||||
|
||||
await page.goto('/wuerfe/w-kruemel')
|
||||
await expect(page.getByText(tl.detail.expectedColors).first()).toBeVisible()
|
||||
await page.getByRole('button', { name: de.pages.genetik.showGenotypes }).click()
|
||||
|
||||
await expect(page.locator('.genotype-table-scroll').first()).toBeVisible()
|
||||
await expect(page.locator('.genotype-table').first()).toBeVisible()
|
||||
})
|
||||
@@ -65,28 +65,30 @@ export default function BreedingResultView({ result, title }: BreedingResultView
|
||||
</button>
|
||||
|
||||
{showGenotypes && (
|
||||
<table className="genotype-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t.genotypeLabel}</th>
|
||||
<th>{t.genotypePreview}</th>
|
||||
<th>{t.probability}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{result.offspring.map((o) => (
|
||||
<tr key={o.genotype}>
|
||||
<td>
|
||||
<code>{o.genotype}</code>
|
||||
</td>
|
||||
<td>{o.farbschlag}</td>
|
||||
<td>
|
||||
{o.probability.percent} <small>({o.probability.text})</small>
|
||||
</td>
|
||||
<div className="genotype-table-scroll">
|
||||
<table className="genotype-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t.genotypeLabel}</th>
|
||||
<th>{t.genotypePreview}</th>
|
||||
<th>{t.probability}</th>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
{result.offspring.map((o) => (
|
||||
<tr key={o.genotype}>
|
||||
<td>
|
||||
<code>{o.genotype}</code>
|
||||
</td>
|
||||
<td>{o.farbschlag}</td>
|
||||
<td>
|
||||
{o.probability.percent} <small>({o.probability.text})</small>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -77,6 +77,10 @@ a {
|
||||
padding: 1rem;
|
||||
max-width: 60rem;
|
||||
width: 100%;
|
||||
/* UX-MOBILE-2: prevent any wide content (e.g. genotype table) from making
|
||||
the page body scroll horizontally. The .genotype-table-scroll wrapper
|
||||
provides the per-table horizontal scroll. */
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Tab-Leiste unten */
|
||||
@@ -559,8 +563,14 @@ textarea {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* UX-MOBILE-2: scroll wrapper so genotype table scrolls horizontally on mobile
|
||||
instead of overflowing the page. */
|
||||
.genotype-table-scroll {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.genotype-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 0.75rem;
|
||||
font-size: 0.9rem;
|
||||
@@ -571,6 +581,7 @@ textarea {
|
||||
text-align: left;
|
||||
padding: 0.4rem 0.5rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.genotype-table code {
|
||||
|
||||
Reference in New Issue
Block a user