feat(board): freie Reihenfolge im Projektbrett
Karten lassen sich innerhalb einer Spalte anordnen, die Position bleibt am Projekt. Das Aufgabenbrett kann das laengst - dass ausgerechnet das Projektbrett der gewaehlten Sortierung folgte, war ein Bruch. Die Sortierung im Kopf ist in dieser Ansicht deshalb abgeschaltet. Sie stehen zu lassen, ohne dass sie wirkt, waere irrefuehrend. Umsortieren fasst das Aenderungsdatum nicht an. Sonst schoebe ein Aufraeumen im Brett saemtliche Projekte in "Zuletzt geaendert" nach oben - das Brett wuerde die Liste umsortieren, ohne dass sich inhaltlich etwas geaendert hat. Ein Statuswechsel dagegen ist eine echte Aenderung und darf das Datum setzen. Nur er kommt auch in den Verlauf; ein blosser Rangwechsel nicht, sonst bestuende der Verlauf bald aus nichts anderem. Dabei fiel auf, dass neu angelegte, importierte und per Status verschobene Projekte gar keine Position bekamen und sich alle auf 0 stapelten. Der Rang wird jetzt an allen vier Stellen gesetzt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-1
@@ -1,4 +1,4 @@
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { Prisma, type ProjectStatus } from "@prisma/client";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { slugify } from "@/lib/utils";
|
||||
|
||||
@@ -28,6 +28,25 @@ export async function uniqueSlug(
|
||||
return `${base}-${Date.now()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Naechste freie Position am Ende einer Statusspalte im Brett.
|
||||
*
|
||||
* Muss bei jedem Anlegen und bei jedem Statuswechsel gesetzt werden – sonst
|
||||
* stehen alle auf 0 und das Brett zeigt eine Reihenfolge, die sich bei jedem
|
||||
* Laden anders ergeben kann.
|
||||
*/
|
||||
export async function nextProjectPosition(
|
||||
ownerId: string,
|
||||
status: ProjectStatus,
|
||||
): Promise<number> {
|
||||
const last = await prisma.project.findFirst({
|
||||
where: { ownerId, status },
|
||||
orderBy: { position: "desc" },
|
||||
select: { position: true },
|
||||
});
|
||||
return (last?.position ?? -1) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbindungsfelder, die an den Browser gehen duerfen.
|
||||
* tokenCipher ist bewusst nicht dabei.
|
||||
|
||||
@@ -35,6 +35,41 @@ export const projectCreateSchema = z.object({
|
||||
|
||||
export const projectUpdateSchema = projectCreateSchema.partial();
|
||||
|
||||
/**
|
||||
* Neue Reihenfolge im Brett. Uebergeben wird je betroffener Spalte die
|
||||
* vollstaendige Liste in ihrer neuen Reihenfolge – daraus ergeben sich Status
|
||||
* und Position eindeutig, und der Aufruf laesst sich gefahrlos wiederholen.
|
||||
*/
|
||||
export const projectReorderSchema = z.object({
|
||||
columns: z
|
||||
.record(z.enum(STATUS), z.array(z.string().min(1)).max(500))
|
||||
.refine((value) => Object.keys(value).length > 0, "Keine Spalte angegeben"),
|
||||
});
|
||||
|
||||
/** Dieselbe Aenderung fuer mehrere Projekte auf einmal. */
|
||||
export const projectBulkSchema = z
|
||||
.object({
|
||||
ids: z.array(z.string().min(1)).min(1).max(200),
|
||||
action: z.enum(["status", "tags", "favorite", "delete"]),
|
||||
status: z.enum(STATUS).optional(),
|
||||
/** Bei action "tags": ergaenzen oder entfernen. */
|
||||
tags: z.array(z.string().trim().min(1).max(30)).max(12).optional(),
|
||||
tagMode: z.enum(["add", "remove"]).default("add"),
|
||||
favorite: z.boolean().optional(),
|
||||
})
|
||||
.refine((value) => value.action !== "status" || value.status !== undefined, {
|
||||
message: "Ohne Zielstatus laesst sich nichts verschieben",
|
||||
path: ["status"],
|
||||
})
|
||||
.refine((value) => value.action !== "tags" || (value.tags?.length ?? 0) > 0, {
|
||||
message: "Ohne Tags gibt es nichts zu aendern",
|
||||
path: ["tags"],
|
||||
})
|
||||
.refine((value) => value.action !== "favorite" || value.favorite !== undefined, {
|
||||
message: "Kein Zielzustand angegeben",
|
||||
path: ["favorite"],
|
||||
});
|
||||
|
||||
// ── Repositories ─────────────────────────────────────────────
|
||||
|
||||
export const repositoryCreateSchema = z.object({
|
||||
|
||||
Reference in New Issue
Block a user