diff --git a/admin/public/ep_admin_pads/de.json b/admin/public/ep_admin_pads/de.json
index afb553caf..67dd73ddf 100644
--- a/admin/public/ep_admin_pads/de.json
+++ b/admin/public/ep_admin_pads/de.json
@@ -14,6 +14,7 @@
"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_delete.value": "Löschen",
+ "ep_adminpads2_cleanup": "Historie aufräumen",
"ep_adminpads2_last-edited": "Zuletzt bearbeitet",
"ep_adminpads2_loading": "Lädt...",
"ep_adminpads2_manage-pads": "Pads verwalten",
diff --git a/admin/public/ep_admin_pads/en.json b/admin/public/ep_admin_pads/en.json
index 8a9044b1b..76354c640 100644
--- a/admin/public/ep_admin_pads/en.json
+++ b/admin/public/ep_admin_pads/en.json
@@ -4,6 +4,7 @@
"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_delete.value": "Delete",
+ "ep_adminpads2_cleanup": "Cleanup revisions",
"ep_adminpads2_last-edited": "Last edited",
"ep_adminpads2_loading": "Loading…",
"ep_adminpads2_manage-pads": "Manage pads",
diff --git a/admin/src/pages/PadPage.tsx b/admin/src/pages/PadPage.tsx
index e663603cd..595dd9376 100644
--- a/admin/src/pages/PadPage.tsx
+++ b/admin/src/pages/PadPage.tsx
@@ -6,7 +6,7 @@ import {useDebounce} from "../utils/useDebounce.ts";
import {determineSorting} from "../utils/sorting.ts";
import * as Dialog from "@radix-ui/react-dialog";
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";
export const PadPage = ()=>{
@@ -68,12 +68,30 @@ export const PadPage = ()=>{
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]);
const deletePad = (padID: string)=>{
settingsSocket?.emit('deletePad', padID)
}
+ const cleanupPad = (padID: string)=>{
+ settingsSocket?.emit('cleanupPadRevisions', padID)
+ }
return
@@ -150,6 +168,9 @@ export const PadPage = ()=>{
setPadToDelete(pad.padName)
setDeleteDialog(true)
}}/>
+ } title={} onClick={()=>{
+ cleanupPad(pad.padName)
+ }}/>
} title="view" onClick={()=>window.open(`/p/${pad.padName}`, '_blank')}/>
diff --git a/src/node/hooks/express/adminsettings.ts b/src/node/hooks/express/adminsettings.ts
index 63d901f21..3d30e8fb5 100644
--- a/src/node/hooks/express/adminsettings.ts
+++ b/src/node/hooks/express/adminsettings.ts
@@ -13,6 +13,7 @@ const settings = require('../../utils/Settings');
const UpdateCheck = require('../../utils/UpdateCheck');
const padManager = require('../../db/PadManager');
const api = require('../../db/API');
+const cleanup = require('../../utils/Cleanup');
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 () => {
logger.info('Admin request to restart server through a socket on /admin/settings');
settings.reloadSettings();
diff --git a/src/node/utils/Cleanup.ts b/src/node/utils/Cleanup.ts
index fcff58d9b..d0fa0db7d 100644
--- a/src/node/utils/Cleanup.ts
+++ b/src/node/utils/Cleanup.ts
@@ -39,7 +39,7 @@ const createRevision = async (aChangeset: AChangeSet, timestamp: number, isKeyRe
};
}
-exports.deleteRevisions = async (padId: string, keepRevisions: number): Promise => {
+exports.deleteRevisions = async (padId: string, keepRevisions: number): Promise => {
logger.debug('Start cleanup revisions', padId)
@@ -48,6 +48,11 @@ exports.deleteRevisions = async (padId: string, keepRevisions: number): Promise<
logger.debug('Initial pad is valid')
+ if (pad.head < keepRevisions) {
+ logger.debug('Pad has not enough revisions')
+ return false
+ }
+
padMessageHandler.kickSessionsFromPad(padId)
const cleanupUntilRevision = pad.head - keepRevisions
@@ -116,6 +121,8 @@ exports.deleteRevisions = async (padId: string, keepRevisions: number): Promise<
let newPad = await padManager.getPad(padId);
await newPad.check();
+
+ return true
}
exports.checkTodos = async () => {
@@ -139,8 +146,10 @@ exports.checkTodos = async () => {
}
try {
- await exports.deleteRevisions(padId, settings.keepRevisions)
- logger.info('successful cleaned up pad: ', padId)
+ const result = await exports.deleteRevisions(padId, settings.keepRevisions)
+ if (result) {
+ logger.info('successful cleaned up pad: ', padId)
+ }
} catch (err: any) {
logger.error(`Error in pad ${padId}: ${err.stack || err}`);
return;
diff --git a/src/node/utils/Settings.ts b/src/node/utils/Settings.ts
index 4ff117ad3..535ccbd8c 100644
--- a/src/node/utils/Settings.ts
+++ b/src/node/utils/Settings.ts
@@ -380,6 +380,13 @@ exports.sso = {
*/
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
* height needed to make this line visible.