fix(aufgaben): Ideen aus Aufgabenliste und Inbox heraushalten

Der Fehler fiel erst in den aufgenommenen Bildern auf: Ideen standen
mitten in der Aufgabenliste, obwohl der ganze Sinn der getrennten
Ideenseite ist, dass sie das nicht tun. Ohne Termin hätten sie dort
entweder unsichtbar unten gestanden oder mit erfundenem Termin oben.

Der Filter kennt jetzt ohneIdeen; ein ausdrücklich gewählter Typ gewinnt,
wer nach Ideen filtert, sieht sie also weiterhin.

Die Startseite filterte Ideen bisher von Hand nach dem Laden — das
erledigt jetzt dieselbe Abfrage wie überall sonst.

Ein E2E-Test hält den Fall fest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-10 16:33:33 +02:00
co-authored by Claude Opus 5
parent 7c8fe10f35
commit 144457b9f0
5 changed files with 45 additions and 9 deletions
+28
View File
@@ -107,6 +107,34 @@ test.describe('Aufgaben', () => {
await expect(page.locator('li').filter({ hasText: titel })).toHaveCount(0)
})
test('hält Ideen aus der Aufgabenliste heraus', async ({ page }) => {
const idee = `${PRAEFIX} Nur eine Idee`
const aufgabe = `${PRAEFIX} Eine echte Aufgabe`
await db.aufgabe.createMany({
data: [
{ titel: idee, typ: 'IDEE' },
{ titel: aufgabe, typ: 'AUFGABE' },
],
})
await anmelden(page)
// In der Aufgabenliste hat die Idee nichts zu suchen.
await page.goto('/aufgaben')
await expect(page.locator('li').filter({ hasText: aufgabe })).toBeVisible()
await expect(page.locator('li').filter({ hasText: idee })).toHaveCount(0)
// Auch nicht in der Inbox, obwohl beide keinen Bereich haben.
await page.goto('/inbox')
await expect(page.locator('li').filter({ hasText: aufgabe })).toBeVisible()
await expect(page.locator('li').filter({ hasText: idee })).toHaveCount(0)
// Wer ausdrücklich danach filtert, sieht sie sehr wohl.
await page.goto('/aufgaben?typ=IDEE')
await expect(page.locator('li').filter({ hasText: idee })).toBeVisible()
await expect(page.locator('li').filter({ hasText: aufgabe })).toHaveCount(0)
})
test('filtert nach Bereich und über die Adresszeile', async ({ page }) => {
await anmelden(page)
const bereich = await db.bereich.findFirst({
+2
View File
@@ -56,6 +56,8 @@ function filterAus(
: { nurOffen: true }),
...(typ && TYP_WERTE.includes(typ) ? { typ: typ as AufgabenTyp } : {}),
...(einer('suche') ? { suche: einer('suche') } : {}),
// Ideen haben ihre eigene Seite; wer sie hier sehen will, filtert danach.
ohneIdeen: true,
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ export default async function InboxSeite() {
await verlangeAnmeldung('/inbox')
const [aufgaben, bereiche, projekte] = await Promise.all([
aufgabenLaden({ nurInbox: true, nurOffen: true }),
aufgabenLaden({ nurInbox: true, nurOffen: true, ohneIdeen: true }),
bereicheLaden(),
projekteZurAuswahlLaden(),
])
+4 -8
View File
@@ -25,7 +25,7 @@ export default async function StartSeite() {
const heute = jetzt()
const [alleOffenen, bereiche, projekte, zahlen, bereichsListe] = await Promise.all([
aufgabenLaden({ nurOffen: true }, 200),
aufgabenLaden({ nurOffen: true, ohneIdeen: true }, 200),
bereicheLaden(),
projekteZurAuswahlLaden(),
zaehlstaende(),
@@ -35,11 +35,9 @@ export default async function StartSeite() {
}),
])
// Was jetzt zählt: überfällig, heute oder morgen fällig. Ideen bleiben draußen.
// Was jetzt zählt: überfällig, heute oder morgen fällig.
const dran = alleOffenen.filter(
(a) =>
a.typ !== 'IDEE' &&
(a.ueberfaellig || a.faelligkeit === 'heute' || a.faelligkeit === 'morgen'),
(a) => a.ueberfaellig || a.faelligkeit === 'heute' || a.faelligkeit === 'morgen',
)
const anrede = benutzer.name?.split(' ')[0] ?? benutzer.email
@@ -109,9 +107,7 @@ export default async function StartSeite() {
) : (
<ul className="grid gap-4 sm:grid-cols-2">
{bereichsListe.map((bereich) => {
const offeneHier = alleOffenen.filter(
(a) => a.bereich?.id === bereich.id && a.typ !== 'IDEE',
)
const offeneHier = alleOffenen.filter((a) => a.bereich?.id === bereich.id)
return (
<li key={bereich.id}>
<Card>
+10
View File
@@ -38,6 +38,12 @@ export type AufgabenFilter = {
nurInbox?: boolean | undefined
/** Nur was noch Arbeit bedeutet. */
nurOffen?: boolean | undefined
/**
* Ideen heraushalten. Sie haben ihre eigene Ansicht und sollen sich nicht
* in die Aufgabenliste drängen — sie hätten dort keinen Termin und stünden
* entweder unsichtbar unten oder mit erfundenem Termin oben.
*/
ohneIdeen?: boolean | undefined
/** Freitext über Titel und Notiz. */
suche?: string | undefined
}
@@ -49,7 +55,11 @@ function alsWhere(filter: AufgabenFilter): Prisma.AufgabeWhereInput {
else if (filter.bereichId) where.bereichId = filter.bereichId
if (filter.projektId) where.projektId = filter.projektId
// Ein ausdrücklich gewählter Typ gewinnt: wer nach Ideen filtert, will sie
// auch sehen.
if (filter.typ) where.typ = filter.typ
else if (filter.ohneIdeen) where.typ = { not: 'IDEE' }
if (filter.status) where.status = filter.status
else if (filter.nurOffen) where.status = { in: ['OFFEN', 'GEPLANT', 'WARTET'] }