Admin tools: fix minor bugs

This commit is contained in:
yu-i-i
2026-02-03 19:37:57 +01:00
parent 30a26809ea
commit 98bca90a22
11 changed files with 36 additions and 21 deletions

View File

@@ -279,6 +279,7 @@ async function deleteProject(projectId, options = {}) {
{ projectId, userId: project.owner_ref }, { projectId, userId: project.owner_ref },
'successfully deleted project' 'successfully deleted project'
) )
return { deletedAt: deleterData.deletedAt, deleterId: deleterData.deleterId }
} catch (err) { } catch (err) {
logger.warn({ err }, 'problem deleting project') logger.warn({ err }, 'problem deleting project')
throw err throw err

View File

@@ -69,6 +69,10 @@ export default {
AuthorizationMiddleware.ensureUserIsSiteAdmin, AuthorizationMiddleware.ensureUserIsSiteAdmin,
ProjectListController.purgeDeletedProject ProjectListController.purgeDeletedProject
) )
webRouter.delete('/admin/project/:project_id',
AuthorizationMiddleware.ensureUserIsSiteAdmin,
ProjectListController.deleteProject
)
webRouter.post('/admin/project/:project_id/undelete', webRouter.post('/admin/project/:project_id/undelete',
AuthorizationMiddleware.ensureUserIsSiteAdmin, AuthorizationMiddleware.ensureUserIsSiteAdmin,
ProjectListController.undeleteProject ProjectListController.undeleteProject

View File

@@ -117,7 +117,7 @@ function _sortAndPaginate(projects, sort, page) {
throw new OError('Invalid sorting criteria', { sort }) throw new OError('Invalid sorting criteria', { sort })
} }
// sorting by owner is not implemented, it is mot needed // sorting by owner is not implemented, it is not needed
const sortedProjects = const sortedProjects =
sort.by === 'title' sort.by === 'title'
? [...projects].sort((a, b) => ? [...projects].sort((a, b) =>
@@ -162,7 +162,7 @@ function _formatDeletedProjectInfo(deletedProject, maxDate) {
trashed, trashed,
deleted: true, deleted: true,
deletedAt: deletedProject.deleterData?.deletedAt?.toISOString(), deletedAt: deletedProject.deleterData?.deletedAt?.toISOString(),
deletedBy: deletedProject.deleterData?.deleterId, deleterId: deletedProject.deleterData?.deleterId,
} }
} }
@@ -212,6 +212,14 @@ async function untrashProjectForUser(req, res) {
res.sendStatus(200) res.sendStatus(200)
} }
async function deleteProject(req, res) {
const projectId = req.params.project_id
const deleterId = SessionManager.getLoggedInUserId(req.session)
const options = { deleterUser: {_id: deleterId } }
const deletedProjectData = await ProjectDeleter.promises.deleteProject(projectId, options)
return res.json(deletedProjectData)
}
async function undeleteProject(req, res) { async function undeleteProject(req, res) {
const projectId = req.params.project_id const projectId = req.params.project_id
const { userId } = req.body const { userId } = req.body
@@ -232,6 +240,7 @@ async function purgeDeletedProject(req, res) {
export default { export default {
manageProjectsPage: expressify(manageProjectsPage), manageProjectsPage: expressify(manageProjectsPage),
getProjectsJson: expressify(getProjectsJson), getProjectsJson: expressify(getProjectsJson),
deleteProject: expressify(deleteProject),
undeleteProject: expressify(undeleteProject), undeleteProject: expressify(undeleteProject),
purgeDeletedProject: expressify(purgeDeletedProject), purgeDeletedProject: expressify(purgeDeletedProject),
trashProjectForUser: expressify(trashProjectForUser), trashProjectForUser: expressify(trashProjectForUser),

View File

@@ -34,11 +34,13 @@ function DeleteProjectButton({ project, children }: DeleteProjectButtonProps) {
}, [isMounted]) }, [isMounted])
const handleDeleteProject = useCallback(async () => { const handleDeleteProject = useCallback(async () => {
await deleteProject(project.id) return deleteProject(project.id).then(data => {
toggleSelectedProject(project.id, false) toggleSelectedProject(project.id, false)
updateProjectViewData({ updateProjectViewData({
...project, ...project,
deleted: true, ...data,
deleted: true,
})
}) })
}, [project, toggleSelectedProject, updateProjectViewData]) }, [project, toggleSelectedProject, updateProjectViewData])

View File

@@ -35,7 +35,6 @@ function RestoreProjectButton({
}, [isMounted]) }, [isMounted])
const handleRestoreProject = useCallback(() => { const handleRestoreProject = useCallback(() => {
// const ownerId = project.owner ?? getMeta('ol-user_id')
return undeleteProject(project.id, project.owner).then(data => { return undeleteProject(project.id, project.owner).then(data => {
toggleSelectedProject(project.id, false) toggleSelectedProject(project.id, false)
updateProjectViewData({ updateProjectViewData({

View File

@@ -19,7 +19,7 @@ function ProjectListTableRow({ project, selected, filter }: ProjectListTableRowP
const ownerName = getUserNameById(project.owner) const ownerName = getUserNameById(project.owner)
const actorName = filter !== 'deleted' ? const actorName = filter !== 'deleted' ?
getUserNameById(project.lastUpdatedBy) : getUserNameById(project.lastUpdatedBy) :
getUserNameById(project.deletedBy) getUserNameById(project.deleterId)
const eventDate = filter !== 'deleted' ? project.lastUpdated : project.deletedAt const eventDate = filter !== 'deleted' ? project.lastUpdated : project.deletedAt
return ( return (

View File

@@ -28,11 +28,13 @@ function DeleteProjectsButton() {
} }
const handleDeleteProject = async (project: Project) => { const handleDeleteProject = async (project: Project) => {
await deleteProject(project.id) return deleteProject(project.id).then(data => {
toggleSelectedProject(project.id, false) toggleSelectedProject(project.id, false)
updateProjectViewData({ updateProjectViewData({
...project, ...project,
deleted: true, ...data,
deleted: true,
})
}) })
} }

View File

@@ -184,7 +184,7 @@ export function ProjectListProvider({ projectsOwnerId, children }: ProjectListPr
const loadMoreProjects = useCallback(() => { const loadMoreProjects = useCallback(() => {
setMaxVisibleProjects(v => v + loadMoreCount) setMaxVisibleProjects(v => v + loadMoreCount)
}, [maxVisibleProjects]) }, [loadMoreCount])
const [selectedProjectIds, setSelectedProjectIds] = useState( const [selectedProjectIds, setSelectedProjectIds] = useState(
() => new Set<string>() () => new Set<string>()
@@ -213,9 +213,8 @@ export function ProjectListProvider({ projectsOwnerId, children }: ProjectListPr
return visibleProjects.filter(project => selectedProjectIds.has(project.id)) return visibleProjects.filter(project => selectedProjectIds.has(project.id))
}, [selectedProjectIds, visibleProjects]) }, [selectedProjectIds, visibleProjects])
const selectOrUnselectAllProjects = useCallback( const selectOrUnselectAllProjects = useCallback(
(checked: any) => { (checked: boolean) => {
setSelectedProjectIds(prevSelectedProjectIds => { setSelectedProjectIds(prevSelectedProjectIds => {
const selectedProjectIds = new Set(prevSelectedProjectIds) const selectedProjectIds = new Set(prevSelectedProjectIds)
for (const project of visibleProjects) { for (const project of visibleProjects) {

View File

@@ -20,7 +20,7 @@ export function getProjects(
} }
export function deleteProject(projectId: string) { export function deleteProject(projectId: string) {
return deleteJSON(`/project/${projectId}`) return deleteJSON(`/admin/project/${projectId}`)
} }
export function purgeProject(projectId: string) { export function purgeProject(projectId: string) {

View File

@@ -10,7 +10,6 @@ const order = (order: SortingOrder, projects: Project[]) => {
function cmp(a, b) { function cmp(a, b) {
const aEmpty = a == null || a === "" const aEmpty = a == null || a === ""
const bEmpty = b == null || b === "" const bEmpty = b == null || b === ""
if (aEmpty && bEmpty) return Compare.SORT_KEEP_ORDER
if (aEmpty) return Compare.SORT_A_AFTER_B if (aEmpty) return Compare.SORT_A_AFTER_B
if (bEmpty) return Compare.SORT_A_BEFORE_B if (bEmpty) return Compare.SORT_A_BEFORE_B
return a.localeCompare(b) return a.localeCompare(b)
@@ -57,7 +56,7 @@ export const defaultComparator = (
if (value1 !== value2) { if (value1 !== value2) {
if (value1 === undefined) return Compare.SORT_A_BEFORE_B if (value1 === undefined) return Compare.SORT_A_BEFORE_B
if (value2 === undefined) return Compare.SORT_A_AFTER_B if (value2 === undefined) return Compare.SORT_A_AFTER_B
return value1 < value2 ? Compare.SORT_A_BEFORE_B : Compare.SORT_A_AFTER_B return value1.localeCompare(value2)
} }
return Compare.SORT_KEEP_ORDER return Compare.SORT_KEEP_ORDER

View File

@@ -40,7 +40,7 @@ export type ProjectApi = {
trashed: boolean trashed: boolean
deleted: boolean deleted: boolean
inactive?: boolean inactive?: boolean
deletedBy?: string deleterId?: string
deletedAt?: Date deletedAt?: Date
} }