Commit afd50c29 authored by Stefan Probst's avatar Stefan Probst
Browse files

feat: allow reverting item versions

parent b327f8dc
import type { PropsWithChildren } from 'react'
import { Fragment } from 'react'
import { useGetLoggedInUser } from '@/api/sshoc'
import { useAuth } from '@/modules/auth/AuthContext'
export default function ProtectedView({
children,
}: PropsWithChildren<unknown>): JSX.Element | null {
roles,
}: PropsWithChildren<{
roles?: Array<'contributor' | 'moderator' | 'administrator'>
}>): JSX.Element | null {
const { session } = useAuth()
const user = useGetLoggedInUser(
{ enabled: session?.accessToken != null },
{ token: session?.accessToken },
)
if (session === null) return null
if (Array.isArray(roles)) {
const role = user.data?.role
if (role == null || !(roles as Array<string>).includes(role)) return null
}
return <Fragment>{children}</Fragment>
}
......@@ -12,7 +12,7 @@ function AnchorComponent(
<a
ref={ref}
className={cx(
'text-primary-800 hover:text-primary-700 transition-colors duration-150',
'text-primary-750 hover:text-secondary-600 transition-colors duration-150',
className,
)}
{...props}
......
import Link from 'next/link'
import { useRouter } from 'next/router'
import { Fragment } from 'react'
import { useQueryClient } from 'react-query'
import type {
DatasetDto,
......@@ -8,6 +10,19 @@ import type {
TrainingMaterialDto,
WorkflowDto,
} from '@/api/sshoc'
import {
useRevertDataset,
useRevertPublication,
useRevertTool,
useRevertTrainingMaterial,
useRevertWorkflow,
} from '@/api/sshoc'
import { Button } from '@/elements/Button/Button'
import { toast } from '@/elements/Toast/useToast'
import { useAuth } from '@/modules/auth/AuthContext'
import ProtectedView from '@/modules/auth/ProtectedView'
import { useErrorHandlers } from '@/modules/error/useErrorHandlers'
import { Anchor } from '@/modules/ui/Anchor'
export interface ItemHistoryProps {
item:
......@@ -34,7 +49,7 @@ export function ItemHistory(props: ItemHistoryProps): JSX.Element {
) : null}
<div className="my-2">
<h2 className="sr-only">Current version</h2>
<ItemVersion version={props.item} />
<ItemVersion version={props.item} isCurrentApprovedVersion />
</div>
{props.item.olderVersions != null &&
props.item.olderVersions.length > 0 ? (
......@@ -55,6 +70,7 @@ interface ItemVersionProps {
version:
| Exclude<ItemHistoryProps['item']['newerVersions'], undefined>[number]
| Exclude<ItemHistoryProps['item']['olderVersions'], undefined>[number]
isCurrentApprovedVersion?: boolean
}
/**
......@@ -63,9 +79,74 @@ interface ItemVersionProps {
*/
function ItemVersion(props: ItemVersionProps) {
const { version } = props
type ItemCategory = Exclude<typeof version.category, 'step' | undefined>
const router = useRouter()
const auth = useAuth()
const handleError = useErrorHandlers()
const queryClient = useQueryClient()
const operations = {
dataset: {
op: useRevertDataset,
getByIdKey: 'getDataset',
getAllKey: 'getDatasets',
},
publication: {
op: useRevertPublication,
getByIdKey: 'getPublication',
getAllKey: 'getPublications',
},
'tool-or-service': {
op: useRevertTool,
getByIdKey: 'getTool',
getAllKey: 'getTools',
},
'training-material': {
op: useRevertTrainingMaterial,
getByIdKey: 'getTrainingMaterial',
getAllKey: 'getTrainingMaterials',
},
workflow: {
op: useRevertWorkflow,
getByIdKey: 'getWorkflow',
getAllKey: 'getWorkflows',
},
}
const { op, getByIdKey, getAllKey } = operations[
version.category as ItemCategory
]
const revert = op({
onSuccess() {
toast.success('Successfully reverted to version.')
queryClient.invalidateQueries({ queryKey: ['itemSearch'] })
queryClient.invalidateQueries({ queryKey: [getAllKey] })
queryClient.invalidateQueries({
queryKey: [getByIdKey, version.persistentId],
})
router.push({
pathname: ['', version.category, version.persistentId].join('/'),
})
},
onError(error) {
toast.error('Failed to revert to version.')
if (error instanceof Error) {
handleError(error)
}
},
})
function onRevert() {
revert.mutate([
{ id: version.persistentId!, versionId: version.id! },
{ token: auth.session?.accessToken },
])
}
return (
<article className="px-4 py-4 border border-gray-200 rounded bg-gray-75">
<article className="flex justify-between px-4 py-4 border border-gray-200 rounded bg-gray-75">
<Link
href={{
pathname: [
......@@ -84,6 +165,33 @@ function ItemVersion(props: ItemVersionProps) {
</h3>
</a>
</Link>
<div className="flex items-center space-x-4">
<ProtectedView>
{/* TODO: This should check for status=approved once we get status for versions. */}
{props.isCurrentApprovedVersion === true ? (
<Link
passHref
href={{
pathname: [
'',
version.category,
version.persistentId,
'edit',
].join('/'),
}}
>
<Anchor className="text-ui-base">Edit</Anchor>
</Link>
) : null}
</ProtectedView>
<ProtectedView roles={['moderator', 'administrator']}>
{props.isCurrentApprovedVersion !== true ? (
<Button variant="link" onPress={onRevert}>
Revert to this version
</Button>
) : null}
</ProtectedView>
</div>
</article>
)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment