Created ability for Admins to review deleted tasks and restore them if needed

This commit is contained in:
NPS Agent
2026-05-12 09:53:51 +09:30
parent 60a1cf1b67
commit 62cfeb0da4
8 changed files with 115 additions and 24 deletions
+31 -7
View File
@@ -10,7 +10,7 @@ const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
const ACCENTS = ['#2A6FDB', '#1F8A5B', '#D97757', '#7A5AF8'];
function useApiData(authed) {
const [data, setData] = React.useState({ tasks: [], users: [], audit: [], workspace: null });
const [data, setData] = React.useState({ tasks: [], users: [], audit: [], workspace: null, deletedTasks: [] });
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
@@ -19,14 +19,15 @@ function useApiData(authed) {
let mounted = true;
const load = async () => {
try {
const [tasks, users, audit, workspace] = await Promise.all([
const [tasks, users, audit, workspace, deletedTasks] = await Promise.all([
api.getTasks(),
api.getUsers(),
api.getAudit(),
api.getWorkspace()
api.getWorkspace(),
api.getDeletedTasks().catch(() => []) // Catch if not admin or error
]);
if (mounted) {
setData({ tasks, users, audit, workspace });
setData({ tasks, users, audit, workspace, deletedTasks });
setLoading(false);
}
} catch (e) {
@@ -56,7 +57,7 @@ function App() {
return 'rod';
});
const { tasks, users: dbUsers, audit, workspace, loading } = useApiData(authed);
const { tasks, users: dbUsers, audit, workspace, deletedTasks, loading } = useApiData(authed);
const [tab, setTab] = React.useState('overview');
React.useEffect(() => {
@@ -170,7 +171,7 @@ function App() {
try {
const t = tasks.find(x => x.id === taskId);
await api.deleteTask(taskId);
await api.addAudit({ actor: meId, action: 'task_deleted', summary: 'Deleted task' + (t ? ': ' + t.title : ''), target: taskId });
await api.addAudit({ actor: meId, action: 'task_deleted', summary: 'Permanently deleted task' + (t ? ': ' + t.title : ''), target: taskId });
setOpenTaskId(null);
} catch(e) {
console.error(e);
@@ -178,6 +179,17 @@ function App() {
}
};
const restoreTask = async (taskId) => {
try {
await api.restoreTask(taskId);
await api.addAudit({ actor: meId, action: 'task_restored', summary: 'Restored task from trash', target: taskId });
if (tab === 'deleted') setTab('overview');
} catch(e) {
console.error(e);
alert("Failed to restore task: " + e.message);
}
};
const dismissHU = (id) => setHeadsUp(h => h.filter(x => x.id !== id));
const openTaskFromAnywhere = (id) => { setOpenTaskId(id); setShowLogs(false); };
@@ -227,7 +239,19 @@ function App() {
onMoveTask={moveTask}
/>
)}
{tab !== 'overview' && (
{tab === 'deleted' && (
<DeletedScreen
tasks={deletedTasks.map(t => ({
...t,
assignee: t.assignee_id,
addedBy: t.added_by,
addedAt: t.added_at,
tags: t.tags.map(tagObj => tagObj.tag)
}))}
onRestore={restoreTask}
/>
)}
{tab !== 'overview' && tab !== 'deleted' && (
<UserScreen
user={merge(tab)} tasks={frontendTasks} density={t.density}
onOpen={(task) => setOpenTaskId(task.id)}