feat(zuweisungen): Zum Dry-Run springt zur Dry-Run-Karte (#032)

Der Link im Zell-Dialog der Zuweisungsmatrix fuehrte nur auf den Kopf
der Schluesselseite; die Dry-Run-Karte liegt weit unten, und wer aus der
Matrix kommt, will genau dorthin. Die Karte traegt jetzt id="dry-run"
(Karte nimmt dafuer eine optionale id an), der Link zeigt auf
/schluessel/<id>#dry-run. scroll-mt haelt die Karte unter der festen
Kopfleiste der schmalen Ansicht.

E2E: der Matrix-Test klickt den Link und prueft Adresse und Sichtbarkeit
der Karte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 17:29:49 +02:00
co-authored by Claude Opus 5.5
parent b4804390c4
commit be9837ba50
4 changed files with 17 additions and 1 deletions
+4
View File
@@ -457,6 +457,10 @@ export default async function SchluesselSeite({
!imWiderruf && !imWiderruf &&
(s.publicVerwendungen.length > 0 || (rechte.privat && s.privateVerwendungen.length > 0)) && ( (s.publicVerwendungen.length > 0 || (rechte.privat && s.privateVerwendungen.length > 0)) && (
<Karte <Karte
// Sprungziel fuer „Zum Dry-Run“ aus der Zuweisungsmatrix; scroll-mt haelt die Karte
// unter der festen Kopfleiste der schmalen Ansicht (#032).
id="dry-run"
className="scroll-mt-20"
titel="Dry-Run-Vorschau" titel="Dry-Run-Vorschau"
untertitel="Erst prüfen, dann anwenden – auf den Hosts ändert sich vorher nichts" untertitel="Erst prüfen, dann anwenden – auf den Hosts ändert sich vorher nichts"
> >
+4
View File
@@ -13,6 +13,7 @@ export function Karte({
className, className,
innen = "normal", innen = "normal",
as: Element = "section", as: Element = "section",
id,
}: { }: {
titel?: ReactNode; titel?: ReactNode;
untertitel?: ReactNode; untertitel?: ReactNode;
@@ -22,9 +23,12 @@ export function Karte({
/** „ohne“ für Inhalte, die bis an den Rand reichen (z. B. Tabellen mit eigenem Abstand). */ /** „ohne“ für Inhalte, die bis an den Rand reichen (z. B. Tabellen mit eigenem Abstand). */
innen?: "normal" | "ohne"; innen?: "normal" | "ohne";
as?: "section" | "div" | "article"; as?: "section" | "div" | "article";
/** Sprungziel für Links von anderen Seiten (z. B. `#dry-run`, #032). */
id?: string;
}) { }) {
return ( return (
<Element <Element
id={id}
className={clsx( className={clsx(
"border-border bg-surface min-w-0 rounded-karte border", "border-border bg-surface min-w-0 rounded-karte border",
innen === "normal" && "p-5 sm:p-6", innen === "normal" && "p-5 sm:p-6",
+1 -1
View File
@@ -175,7 +175,7 @@ export function ZellenDialog({
zeigt und schreibt die Änderung. zeigt und schreibt die Änderung.
</p> </p>
<Button <Button
href={`/schluessel/${schluessel.id}`} href={`/schluessel/${schluessel.id}#dry-run`}
klein klein
className="self-start" className="self-start"
icon={<ArrowRight className="size-4" />} icon={<ArrowRight className="size-4" />}
+8
View File
@@ -128,6 +128,14 @@ test("Matrix zeigt Gruppen-Zuweisung, filtert, weist zu und exportiert", async (
`"${name} Backup";"SHA256:${name}";"${name}-h2";"root";"Public Key";"${name}-g";"restrict";"noch nicht ausgerollt"`, `"${name} Backup";"SHA256:${name}";"${name}-h2";"root";"Public Key";"${name}-g";"restrict";"noch nicht ausgerollt"`,
); );
expect(text).toContain(`"${name}-h3";"deploy";"Public Key";""`); expect(text).toContain(`"${name}-h3";"deploy";"Public Key";""`);
// „Zum Dry-Run“ springt direkt zur Dry-Run-Karte der Schluesselseite (#032).
await matrix.getByRole("button", { name: new RegExp(`auf ${name}-h3: Public Key direkt`) }).click();
await dialog.getByRole("link", { name: "Zum Dry-Run" }).click();
await expect(page).toHaveURL(new RegExp(`/schluessel/${ids.schluessel}#dry-run$`));
const karte = page.locator("#dry-run");
await expect(karte).toContainText("Dry-Run-Vorschau");
await expect(karte).toBeInViewport();
}); });
test("Leser sieht die Matrix, aber keinen Zuweisen-Knopf", async ({ page }) => { test("Leser sieht die Matrix, aber keinen Zuweisen-Knopf", async ({ page }) => {