Add button in admin backend to cleanup revisions of a specific pad

This commit is contained in:
Stefan Müller 2024-09-10 16:55:14 +02:00
parent 491d4af19e
commit 593d1021b6
6 changed files with 64 additions and 4 deletions

View file

@ -14,6 +14,7 @@
"ep_adminpads2_autoupdate.title": "Aktiviert oder deaktiviert automatische Aktualisierungen für die aktuelle Abfrage.", "ep_adminpads2_autoupdate.title": "Aktiviert oder deaktiviert automatische Aktualisierungen für die aktuelle Abfrage.",
"ep_adminpads2_confirm": "Willst du das Pad {{padID}} wirklich löschen?", "ep_adminpads2_confirm": "Willst du das Pad {{padID}} wirklich löschen?",
"ep_adminpads2_delete.value": "Löschen", "ep_adminpads2_delete.value": "Löschen",
"ep_adminpads2_cleanup": "Historie aufräumen",
"ep_adminpads2_last-edited": "Zuletzt bearbeitet", "ep_adminpads2_last-edited": "Zuletzt bearbeitet",
"ep_adminpads2_loading": "Lädt...", "ep_adminpads2_loading": "Lädt...",
"ep_adminpads2_manage-pads": "Pads verwalten", "ep_adminpads2_manage-pads": "Pads verwalten",

View file

@ -4,6 +4,7 @@
"ep_adminpads2_autoupdate.title": "Enables or disables automatic updates for the current query.", "ep_adminpads2_autoupdate.title": "Enables or disables automatic updates for the current query.",
"ep_adminpads2_confirm": "Do you really want to delete the pad {{padID}}?", "ep_adminpads2_confirm": "Do you really want to delete the pad {{padID}}?",
"ep_adminpads2_delete.value": "Delete", "ep_adminpads2_delete.value": "Delete",
"ep_adminpads2_cleanup": "Cleanup revisions",
"ep_adminpads2_last-edited": "Last edited", "ep_adminpads2_last-edited": "Last edited",
"ep_adminpads2_loading": "Loading…", "ep_adminpads2_loading": "Loading…",
"ep_adminpads2_manage-pads": "Manage pads", "ep_adminpads2_manage-pads": "Manage pads",

View file

@ -6,7 +6,7 @@ import {useDebounce} from "../utils/useDebounce.ts";
import {determineSorting} from "../utils/sorting.ts"; import {determineSorting} from "../utils/sorting.ts";
import * as Dialog from "@radix-ui/react-dialog"; import * as Dialog from "@radix-ui/react-dialog";
import {IconButton} from "../components/IconButton.tsx"; import {IconButton} from "../components/IconButton.tsx";
import {ChevronLeft, ChevronRight, Eye, Trash2} from "lucide-react"; import {ChevronLeft, ChevronRight, Eye, Trash2, FileStack} from "lucide-react";
import {SearchField} from "../components/SearchField.tsx"; import {SearchField} from "../components/SearchField.tsx";
export const PadPage = ()=>{ export const PadPage = ()=>{
@ -68,12 +68,30 @@ export const PadPage = ()=>{
results: newPads results: newPads
}) })
}) })
settingsSocket.on('results:cleanupPadRevisions', (data)=>{
let newPads = useStore.getState().pads?.results ?? []
newPads.forEach((pad)=>{
if (pad.padName === data.padId) {
pad.revisionNumber = data.keepRevisions
}
})
useStore.getState().setPads({
results: newPads,
total: useStore.getState().pads!.total
})
})
}, [settingsSocket, pads]); }, [settingsSocket, pads]);
const deletePad = (padID: string)=>{ const deletePad = (padID: string)=>{
settingsSocket?.emit('deletePad', padID) settingsSocket?.emit('deletePad', padID)
} }
const cleanupPad = (padID: string)=>{
settingsSocket?.emit('cleanupPadRevisions', padID)
}
return <div> return <div>
@ -150,6 +168,9 @@ export const PadPage = ()=>{
setPadToDelete(pad.padName) setPadToDelete(pad.padName)
setDeleteDialog(true) setDeleteDialog(true)
}}/> }}/>
<IconButton icon={<FileStack/>} title={<Trans i18nKey="ep_admin_pads:ep_adminpads2_cleanup"/>} onClick={()=>{
cleanupPad(pad.padName)
}}/>
<IconButton icon={<Eye/>} title="view" onClick={()=>window.open(`/p/${pad.padName}`, '_blank')}/> <IconButton icon={<Eye/>} title="view" onClick={()=>window.open(`/p/${pad.padName}`, '_blank')}/>
</div> </div>
</td> </td>

View file

@ -13,6 +13,7 @@ const settings = require('../../utils/Settings');
const UpdateCheck = require('../../utils/UpdateCheck'); const UpdateCheck = require('../../utils/UpdateCheck');
const padManager = require('../../db/PadManager'); const padManager = require('../../db/PadManager');
const api = require('../../db/API'); const api = require('../../db/API');
const cleanup = require('../../utils/Cleanup');
const queryPadLimit = 12; const queryPadLimit = 12;
@ -252,6 +253,26 @@ exports.socketio = (hookName: string, {io}: any) => {
} }
}) })
socket.on('cleanupPadRevisions', async (padId: string) => {
const padExists = await padManager.doesPadExists(padId);
if (padExists) {
logger.info(`Cleanup pad revisions: ${padId}`);
try {
const result = await cleanup.deleteRevisions(padId, settings.cleanup.keepRevisions)
if (result) {
socket.emit('results:cleanupPadRevisions', {
padId: padId,
keepRevisions: settings.cleanup.keepRevisions,
});
logger.info('successful cleaned up pad: ', padId)
}
} catch (err: any) {
logger.error(`Error in pad ${padId}: ${err.stack || err}`);
return;
}
}
})
socket.on('restartServer', async () => { socket.on('restartServer', async () => {
logger.info('Admin request to restart server through a socket on /admin/settings'); logger.info('Admin request to restart server through a socket on /admin/settings');
settings.reloadSettings(); settings.reloadSettings();

View file

@ -39,7 +39,7 @@ const createRevision = async (aChangeset: AChangeSet, timestamp: number, isKeyRe
}; };
} }
exports.deleteRevisions = async (padId: string, keepRevisions: number): Promise<void> => { exports.deleteRevisions = async (padId: string, keepRevisions: number): Promise<boolean> => {
logger.debug('Start cleanup revisions', padId) logger.debug('Start cleanup revisions', padId)
@ -48,6 +48,11 @@ exports.deleteRevisions = async (padId: string, keepRevisions: number): Promise<
logger.debug('Initial pad is valid') logger.debug('Initial pad is valid')
if (pad.head < keepRevisions) {
logger.debug('Pad has not enough revisions')
return false
}
padMessageHandler.kickSessionsFromPad(padId) padMessageHandler.kickSessionsFromPad(padId)
const cleanupUntilRevision = pad.head - keepRevisions const cleanupUntilRevision = pad.head - keepRevisions
@ -116,6 +121,8 @@ exports.deleteRevisions = async (padId: string, keepRevisions: number): Promise<
let newPad = await padManager.getPad(padId); let newPad = await padManager.getPad(padId);
await newPad.check(); await newPad.check();
return true
} }
exports.checkTodos = async () => { exports.checkTodos = async () => {
@ -139,8 +146,10 @@ exports.checkTodos = async () => {
} }
try { try {
await exports.deleteRevisions(padId, settings.keepRevisions) const result = await exports.deleteRevisions(padId, settings.keepRevisions)
if (result) {
logger.info('successful cleaned up pad: ', padId) logger.info('successful cleaned up pad: ', padId)
}
} catch (err: any) { } catch (err: any) {
logger.error(`Error in pad ${padId}: ${err.stack || err}`); logger.error(`Error in pad ${padId}: ${err.stack || err}`);
return; return;

View file

@ -380,6 +380,13 @@ exports.sso = {
*/ */
exports.showSettingsInAdminPage = true; exports.showSettingsInAdminPage = true;
/*
* Settings for cleanup of pads
*/
exports.cleanup = {
keepRevisions: 100,
}
/* /*
* By default, when caret is moved out of viewport, it scrolls the minimum * By default, when caret is moved out of viewport, it scrolls the minimum
* height needed to make this line visible. * height needed to make this line visible.