release: add post-production workspace 0.9.0

This commit is contained in:
hnzio committed 2026-10-30 17:33:13 +01:00
1 parent abc31d920f
commit a6c8606f3c
46 files changed
+10783 -3415

No files matched your search

+66 -2
View File
@@ -5,21 +5,52 @@ import {
createPiece,
deletePieceTemplate,
duplicatePiece,
getPiece,
listPieceTemplates,
savePiece,
setPieceArchived,
setPieceDeleted,
setPieceFavorite
setPieceFavorite,
uploadPieceImage,
type EditablePieceStatus,
type PieceEditor
} from '#lib/server/content.js';
import { fundusSearch, loadFundusWorkspace } from '#lib/server/fundus-workspace.js';
export const load: PageServerLoad = ({ locals, url }) => {
requireUser(locals.user);
const workspace = loadFundusWorkspace(url);
const selectedId = url.searchParams.get('selected') ?? workspace.pieces[0]?.id ?? '';
return {
...loadFundusWorkspace(url),
...workspace,
selectedPiece: workspace.pieces.some((piece) => piece.id === selectedId)
? getPiece(selectedId)
: null,
templates: listPieceTemplates()
};
};
function preservedInput(piece: PieceEditor, data: FormData) {
return {
...piece,
title: String(data.get('title') || ''),
summary: String(data.get('summary') || ''),
status: String(data.get('status') || piece.status) as EditablePieceStatus,
formatId: String(data.get('formatId') || '') || null,
durationSeconds: Math.round(Number(data.get('durationMinutes')) * 60),
intro: String(data.get('intro') || ''),
moderationNotes: String(data.get('moderationNotes') || ''),
topicIds: piece.topicIds,
categoryIds: piece.categoryIds,
sources: piece.sources,
tools: piece.tools.map((tool) => ({
toolId: tool.toolId,
workUrl: tool.workUrl,
note: tool.note
}))
};
}
function actionError(cause: unknown) {
const code = cause instanceof Error ? cause.message : '';
if (code === 'CONFLICT') return 'Das Piece wurde inzwischen geändert. Bitte Seite neu laden.';
@@ -92,5 +123,38 @@ export const actions = {
} catch (cause) {
return fail(409, { intent: 'delete', error: actionError(cause) });
}
},
quickSave: async ({ locals, request }) => {
requireUser(locals.user);
const data = await request.formData();
const id = String(data.get('pieceId') || '');
const piece = getPiece(id);
if (!piece || piece.status === 'archived')
return fail(404, { intent: 'quickSave', error: 'Das Piece wurde nicht gefunden.' });
try {
const saved = savePiece(id, Number(data.get('revision')), preservedInput(piece, data));
return { intent: 'quickSave', success: 'Schnelländerungen gespeichert.', ...saved };
} catch (cause) {
return fail(409, { intent: 'quickSave', error: actionError(cause) });
}
},
quickUpload: async ({ locals, request }) => {
requireUser(locals.user);
const data = await request.formData();
const image = data.get('image');
if (!(image instanceof File))
return fail(400, { intent: 'quickUpload', error: 'Bitte ein Bild auswählen.' });
try {
await uploadPieceImage(
String(data.get('pieceId') || ''),
Number(data.get('revision')),
image,
String(data.get('altText') || ''),
false
);
return { intent: 'quickUpload', success: 'Bild hochgeladen.' };
} catch (cause) {
return fail(400, { intent: 'quickUpload', error: actionError(cause) });
}
}
} satisfies Actions;