fix(cards): Sitzung, Entwurf und Datei-Aufräumen beim Öffnen und Speichern
- Gäste/abgelaufene Sitzung: Appwrite antwortet mit 404; withLogin und openSavedCard melden dann an (Dialog, einmal wiederholen) statt „nicht gefunden“ zu zeigen. - Öffnen einer Karte fragt vor dem Verwerfen eines ungespeicherten Entwurfs nach; ein fehlgeschlagenes Öffnen setzt einen gefüllten Editor nicht zurück. - Update ohne Bildwechsel schickt kein imageFileId mehr (veralteter Stand zeigte sonst auf eine gelöschte Datei). - Uploads werden nur nach eindeutiger Ablehnung (4xx ohne 408/429) gelöscht, nicht bei Netzfehler, 5xx oder 429. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
09de06e797
commit
0c51689dfd
7 files changed
+546
-57
No files matched your search
@@ -87,6 +87,15 @@ async function deleteQuietly(api: CardsApi, fileIds: string[]): Promise<void> {
|
||||
await Promise.allSettled(fileIds.map((id) => api.deleteFile(id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Server hat eine Anfrage eindeutig abgelehnt (4xx außer Zeitüberschreitung 408 und Drosselung 429): es wurde nichts
|
||||
* geschrieben. Netzfehler, 5xx und alles ohne Statuscode lassen offen, ob die Zeile doch angekommen ist.
|
||||
*/
|
||||
function isDefinitiveFailure(err: unknown): boolean {
|
||||
const code = typeof err === 'object' && err !== null ? (err as { code?: unknown }).code : undefined;
|
||||
return typeof code === 'number' && code >= 400 && code < 500 && code !== 408 && code !== 429;
|
||||
}
|
||||
|
||||
export function createCardsService(api: CardsApi, userId: () => string) {
|
||||
async function save(input: SaveInput): Promise<SavedCard> {
|
||||
// Ohne Nutzer wirft das hier, bevor etwas hochgeladen wird.
|
||||
@@ -109,25 +118,36 @@ export function createCardsService(api: CardsApi, userId: () => string) {
|
||||
let row: CardRow;
|
||||
// Die Zeile gab es nicht mehr (anderer Tab, anderes Konto): dann wurde eine neue Karte angelegt, die alten Dateien sind Müll.
|
||||
let replacedMissingCard = false;
|
||||
// Scheitert ein Upload, hängt noch keine Zeile an den Dateien. Beim Schreiben der Zeile ist der Ausgang bei
|
||||
// Netzfehler/5xx dagegen offen (sie kann angekommen sein): dann bleiben die Uploads lieber liegen, als dass
|
||||
// eine Zeile auf gelöschte Dateien zeigt.
|
||||
let writingRow = false;
|
||||
try {
|
||||
const imageFileId = imageFile ? await upload(imageFile) : (prev as SavedCardRef).imageFileId;
|
||||
const newImageId = imageFile ? await upload(imageFile) : null;
|
||||
const previewFileId = await upload(previewFile);
|
||||
const data: CardRowData = { name, config, imageFileId, previewFileId };
|
||||
writingRow = true;
|
||||
if (!prev) {
|
||||
row = await api.createRow(data, permissions);
|
||||
// Ohne vorherige Karte wird immer ein Bild hochgeladen (uploadImage).
|
||||
row = await api.createRow({ name, config, imageFileId: newImageId as string, previewFileId }, permissions);
|
||||
} else {
|
||||
// Ohne Bildwechsel steht kein imageFileId im Update: der Schnappschuss des Editors kann veraltet sein
|
||||
// (Bild in einem anderen Tab ersetzt) und würde die Zeile auf eine gelöschte Datei zurücksetzen.
|
||||
const update: Partial<CardRowData> = { name, config, previewFileId };
|
||||
if (newImageId) update.imageFileId = newImageId;
|
||||
try {
|
||||
row = await api.updateRow(prev.id, data);
|
||||
row = await api.updateRow(prev.id, update);
|
||||
} catch (err) {
|
||||
if (errorType(err) !== 'row_not_found') throw err;
|
||||
replacedMissingCard = true;
|
||||
// Ohne Bildwechsel zeigt `data` auf die Datei der verschwundenen Karte; die neue Karte bekommt ein eigenes Bild.
|
||||
const ownImageId = imageFile ? imageFileId : await upload(toUploadFile(input.image, 'image'));
|
||||
row = await api.createRow({ ...data, imageFileId: ownImageId }, permissions);
|
||||
// Ohne Bildwechsel gibt es noch keine Bilddatei der neuen Karte; die der verschwundenen gehört ihr nicht.
|
||||
writingRow = false;
|
||||
const ownImageId = newImageId ?? (await upload(toUploadFile(input.image, 'image')));
|
||||
writingRow = true;
|
||||
row = await api.createRow({ name, config, imageFileId: ownImageId, previewFileId }, permissions);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
await deleteQuietly(api, uploaded);
|
||||
if (!writingRow || isDefinitiveFailure(err)) await deleteQuietly(api, uploaded);
|
||||
throw err;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user