feat(cms): improve admin content editing

This commit is contained in:
Schubert Ferenc 2026-07-04 11:01:29 +02:00
parent 12d31f5468
commit a284bbc188
26 changed files with 362 additions and 147 deletions

View file

@ -4,11 +4,11 @@ import path from "path";
import { storageDirectory } from "@/lib/runtime/config";
import { listMediaFiles } from "@/lib/admin/media";
import { contentFileNames, defaultContent } from "./defaults";
import type { ContentDocuments, ContentKey, ContentSummary } from "./types";
import type { ContentBackup, ContentDocuments, ContentKey, ContentSummary } from "./types";
export const contentDirectory = path.join(storageDirectory, "content");
export const contentBackupDirectory = path.join(contentDirectory, "backups");
export const contentVersion = "0.4.0";
export const contentVersion = "0.4.1";
const contentKeys = Object.keys(contentFileNames) as ContentKey[];
@ -51,7 +51,7 @@ function filePathFor(key: ContentKey) {
function backupStamp() {
const date = new Date();
const pad = (value: number) => String(value).padStart(2, "0");
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}-${pad(date.getHours())}${pad(date.getMinutes())}`;
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}-${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
}
async function pruneBackups(key: ContentKey) {
@ -144,10 +144,33 @@ export async function getContentSummary(): Promise<ContentSummary> {
};
}
export async function listContentBackups(limit = 20): Promise<ContentBackup[]> {
await ensureContentStorage();
const entries = await readdir(contentBackupDirectory).catch(() => []);
const backups = await Promise.all(entries
.filter((entry) => entry.endsWith(".json"))
.map(async (entry) => {
const page = entry.split(".")[0] as ContentKey;
const fullPath = path.join(contentBackupDirectory, entry);
const fileStat = await stat(fullPath);
return {
page,
fileName: entry,
createdAt: fileStat.mtime.toISOString(),
};
}));
return backups
.filter((backup) => contentKeys.includes(backup.page))
.sort((left, right) => right.createdAt.localeCompare(left.createdAt))
.slice(0, limit);
}
export async function getContentSystemStatus() {
const [summary, media] = await Promise.all([getContentSummary(), listMediaFiles()]);
const [summary, media, backups] = await Promise.all([getContentSummary(), listMediaFiles(), listContentBackups()]);
return {
...summary,
mediaCount: media.length,
backups,
};
}