1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Migrate tasks edit page to react

This commit is contained in:
viown 2025-02-22 16:45:48 +03:00
parent e80b890bd2
commit 524d1b6574
20 changed files with 501 additions and 330 deletions

View file

@ -15,6 +15,7 @@ export const ASYNC_ADMIN_ROUTES: AsyncRoute[] = [
{ path: 'playback/trickplay', type: AppType.Dashboard },
{ path: 'plugins/:pluginId', page: 'plugins/plugin', type: AppType.Dashboard },
{ path: 'tasks', type: AppType.Dashboard },
{ path: 'tasks/edit', type: AppType.Dashboard },
{ path: 'users', type: AppType.Dashboard },
{ path: 'users/access', type: AppType.Dashboard },
{ path: 'users/add', type: AppType.Dashboard },

View file

@ -93,12 +93,5 @@ export const LEGACY_ADMIN_ROUTES: LegacyRoute[] = [
controller: 'plugins/installed/index',
view: 'plugins/installed/index.html'
}
}, {
path: 'tasks/edit',
pageProps: {
appType: AppType.Dashboard,
controller: 'scheduledtasks/scheduledtask',
view: 'scheduledtasks/scheduledtask.html'
}
}
];

View file

@ -0,0 +1,173 @@
import React, { useCallback, useMemo, useState } from 'react';
import Page from 'components/Page';
import { useSearchParams } from 'react-router-dom';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import AddIcon from '@mui/icons-material/Add';
import IconButton from '@mui/material/IconButton';
import Tooltip from '@mui/material/Tooltip';
import RemoveCircleIcon from '@mui/icons-material/RemoveCircle';
import Loading from 'components/loading/LoadingComponent';
import { MRT_ColumnDef, MRT_Table, useMaterialReactTable } from 'material-react-table';
import type { TaskTriggerInfo } from '@jellyfin/sdk/lib/generated-client/models/task-trigger-info';
import globalize from '../../../../lib/globalize';
import { useTask } from 'apps/dashboard/features/tasks/api/useTask';
import { useUpdateTask } from 'apps/dashboard/features/tasks/api/useUpdateTask';
import ConfirmDialog from 'components/ConfirmDialog';
import TaskTriggerCell from 'apps/dashboard/features/tasks/components/TaskTriggerCell';
import NewTriggerForm from 'apps/dashboard/features/tasks/components/NewTriggerForm';
const TaskEdit = () => {
const [ searchParams ] = useSearchParams();
const updateTask = useUpdateTask();
const taskId = searchParams.get('id');
const { data: task, isLoading } = useTask({ taskId: taskId || '' });
const [ isAddTriggerDialogOpen, setIsAddTriggerDialogOpen ] = useState(false);
const [ isRemoveConfirmOpen, setIsRemoveConfirmOpen ] = useState(false);
const [ pendingDeleteTrigger, setPendingDeleteTrigger ] = useState<TaskTriggerInfo | null>(null);
const onCloseRemoveConfirmDialog = useCallback(() => {
setPendingDeleteTrigger(null);
setIsRemoveConfirmOpen(false);
}, []);
const onDeleteTrigger = useCallback((trigger: TaskTriggerInfo | null | undefined) => {
if (trigger) {
setPendingDeleteTrigger(trigger);
setIsRemoveConfirmOpen(true);
}
}, []);
const onConfirmDelete = useCallback(() => {
const triggersRemaining = task?.Triggers?.filter(trigger => trigger != pendingDeleteTrigger);
if (task?.Id && triggersRemaining) {
updateTask.mutate({
taskId: task.Id,
taskTriggerInfo: triggersRemaining
});
setIsRemoveConfirmOpen(false);
}
}, [task, pendingDeleteTrigger, updateTask]);
const showAddTriggerDialog = useCallback(() => {
setIsAddTriggerDialogOpen(true);
}, []);
const handleNewTriggerDialogClose = useCallback(() => {
setIsAddTriggerDialogOpen(false);
}, []);
const onNewTriggerSubmit = useCallback((trigger: TaskTriggerInfo) => {
if (task?.Triggers && task?.Id) {
const triggers = [...task.Triggers, trigger];
updateTask.mutate({
taskId: task.Id,
taskTriggerInfo: triggers
});
setIsAddTriggerDialogOpen(false);
}
}, [task, updateTask]);
const columns = useMemo<MRT_ColumnDef<TaskTriggerInfo>[]>(() => [
{
id: 'TriggerTime',
accessorFn: row => row,
Cell: TaskTriggerCell,
header: globalize.translate('LabelTime')
}
], []);
const table = useMaterialReactTable({
columns,
data: task?.Triggers || [],
enableSorting: false,
enableFilters: false,
enableColumnActions: false,
enablePagination: false,
state: {
isLoading
},
muiTableContainerProps: {
sx: {
maxHeight: 'calc(100% - 7rem)' // 2 x 3.5rem for header and footer
}
},
// Custom actions
enableRowActions: true,
positionActionsColumn: 'last',
displayColumnDefOptions: {
'mrt-row-actions': {
header: ''
}
},
renderRowActions: ({ row }) => {
return (
<Box sx={{
display: 'flex',
justifyContent: 'flex-end'
}}>
<Tooltip disableInteractive title={globalize.translate('ButtonRemove')}>
<IconButton
color='error'
// eslint-disable-next-line react/jsx-no-bind
onClick={() => onDeleteTrigger(row.original)}
>
<RemoveCircleIcon />
</IconButton>
</Tooltip>
</Box>
);
}
});
if (isLoading || !task) {
return <Loading />;
}
return (
<Page
id='scheduledTaskPage'
className='mainAnimatedPage type-interior'
>
<ConfirmDialog
open={isRemoveConfirmOpen}
title={globalize.translate('HeaderDeleteTaskTrigger')}
text={globalize.translate('MessageDeleteTaskTrigger')}
onCancel={onCloseRemoveConfirmDialog}
onConfirm={onConfirmDelete}
confirmButtonColor='error'
confirmButtonText={globalize.translate('ButtonRemove')}
/>
<NewTriggerForm
open={isAddTriggerDialogOpen}
title={globalize.translate('ButtonAddScheduledTaskTrigger')}
onClose={handleNewTriggerDialogClose}
onSubmit={onNewTriggerSubmit}
/>
<Box className='content-primary'>
<Box className='readOnlyContent'>
<Stack spacing={2}>
<Typography variant='h2'>{task.Name}</Typography>
<Typography variant='body1'>{task.Description}</Typography>
<Button
sx={{ alignSelf: 'flex-start' }}
startIcon={<AddIcon />}
onClick={showAddTriggerDialog}
>{globalize.translate('ButtonAddScheduledTaskTrigger')}</Button>
<MRT_Table table={table} />
</Stack>
</Box>
</Box>
</Page>
);
};
export default TaskEdit;

View file

@ -3,10 +3,10 @@ import Page from 'components/Page';
import globalize from 'lib/globalize';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import { QUERY_KEY, useTasks } from '../../features/scheduledtasks/api/useTasks';
import { getCategories, getTasksByCategory } from '../../features/scheduledtasks/utils/tasks';
import { QUERY_KEY, useTasks } from '../../features/tasks/api/useTasks';
import { getCategories, getTasksByCategory } from '../../features/tasks/utils/tasks';
import Loading from 'components/loading/LoadingComponent';
import Tasks from '../../features/scheduledtasks/components/Tasks';
import Tasks from '../../features/tasks/components/Tasks';
import type { TaskInfo } from '@jellyfin/sdk/lib/generated-client/models/task-info';
import { SessionMessageType } from '@jellyfin/sdk/lib/generated-client/models/session-message-type';
import serverNotifications from 'scripts/serverNotifications';