Skip to content

Commit 2efdf64

Browse files
committed
ISPN-14305 Execute a task
1 parent 063fed0 commit 2efdf64

File tree

6 files changed

+285
-121
lines changed

6 files changed

+285
-121
lines changed

src/app/CacheManagers/TasksTableDisplay.tsx

Lines changed: 115 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ import {
88
EmptyStateIcon,
99
EmptyStateVariant,
1010
Pagination,
11-
Stack,
12-
StackItem,
1311
Text,
1412
TextContent,
1513
TextVariants,
16-
Title
14+
Title,
15+
Toolbar,
16+
ToolbarItem,
17+
ToolbarContent,
18+
ToolbarItemVariant
1719
} from '@patternfly/react-core';
20+
import { TableComposable, Thead, Tr, Th, Tbody, Td, IAction, ActionsColumn } from '@patternfly/react-table';
1821
import { SearchIcon } from '@patternfly/react-icons';
1922
import displayUtils from '@services/displayUtils';
2023
import {
@@ -25,71 +28,66 @@ import {
2528
global_spacer_xs
2629
} from '@patternfly/react-tokens';
2730
import { useTranslation } from 'react-i18next';
28-
import { ConsoleServices } from '@services/ConsoleServices';
31+
import { useFetchTask } from '@app/services/tasksHook';
32+
import { ExecuteTasks } from '@app/Tasks/ExecuteTasks';
2933

3034
const TasksTableDisplay = (props: { setTasksCount: (number) => void; isVisible: boolean }) => {
31-
const [tasks, setTasks] = useState<Task[]>([]);
35+
const { tasks, loading, error, reload } = useFetchTask();
3236
const [filteredTasks, setFilteredTasks] = useState<Task[]>([]);
33-
3437
const [tasksPagination, setTasksPagination] = useState({
3538
page: 1,
3639
perPage: 10
3740
});
3841
const [rows, setRows] = useState<(string | any)[]>([]);
42+
const [taskToExecute, setTaskToExecute] = useState<Task>();
3943
const { t } = useTranslation();
4044
const brandname = t('brandname.brandname');
4145

42-
const columns = [
43-
{ title: t('cache-managers.task-name') },
44-
{
45-
title: t('cache-managers.task-type')
46-
},
47-
{
48-
title: t('cache-managers.context-name')
49-
},
50-
{
51-
title: t('cache-managers.operation-name')
52-
},
53-
{
54-
title: t('cache-managers.parameters')
55-
},
46+
const columnNames = {
47+
name: t('cache-managers.tasks.task-name'),
48+
type: t('cache-managers.tasks.task-type'),
49+
context: t('cache-managers.tasks.context-name'),
50+
operation: t('cache-managers.tasks.operation-name'),
51+
parameters: t('cache-managers.tasks.parameters'),
52+
allowedRoles: t('cache-managers.tasks.allowed-role')
53+
};
54+
55+
const rowActionItem = (row): IAction[] => [
5656
{
57-
title: t('cache-managers.allowed-role')
57+
title: t('cache-managers.tasks.execute'),
58+
onClick: () => {
59+
setTaskToExecute(row);
60+
}
5861
}
5962
];
6063

6164
useEffect(() => {
62-
ConsoleServices.tasks()
63-
.getTasks()
64-
.then((maybeTasks) => {
65-
if (maybeTasks.isRight()) {
66-
setTasks(maybeTasks.value);
67-
setFilteredTasks(maybeTasks.value);
68-
props.setTasksCount(maybeTasks.value.length);
69-
const initSlice = (tasksPagination.page - 1) * tasksPagination.perPage;
70-
updateRows(maybeTasks.value.slice(initSlice, initSlice + tasksPagination.perPage));
71-
} else {
72-
// TODO: deal loading, error, empty status
73-
}
74-
});
75-
}, []);
65+
if (tasks) {
66+
setFilteredTasks(tasks);
67+
props.setTasksCount(tasks.length);
68+
}
69+
}, [loading, tasks, error]);
70+
71+
useEffect(() => {
72+
if (filteredTasks) {
73+
const initSlice = (tasksPagination.page - 1) * tasksPagination.perPage;
74+
const updateRows = filteredTasks.slice(initSlice, initSlice + tasksPagination.perPage);
75+
updateRows.length > 0 ? setRows(updateRows) : setRows([]);
76+
}
77+
}, [tasksPagination, filteredTasks]);
7678

7779
const onSetPage = (_event, pageNumber) => {
7880
setTasksPagination({
79-
page: pageNumber,
80-
perPage: tasksPagination.perPage
81+
...tasksPagination,
82+
page: pageNumber
8183
});
82-
const initSlice = (pageNumber - 1) * tasksPagination.perPage;
83-
updateRows(filteredTasks.slice(initSlice, initSlice + tasksPagination.perPage));
8484
};
8585

8686
const onPerPageSelect = (_event, perPage) => {
8787
setTasksPagination({
88-
page: tasksPagination.page,
88+
page: 1,
8989
perPage: perPage
9090
});
91-
const initSlice = (tasksPagination.page - 1) * perPage;
92-
updateRows(filteredTasks.slice(initSlice, initSlice + perPage));
9391
};
9492

9593
const taskType = (type: string) => {
@@ -112,6 +110,9 @@ const TasksTableDisplay = (props: { setTasksCount: (number) => void; isVisible:
112110
};
113111

114112
const taskParameters = (params: [string]) => {
113+
if (params.length == 0) {
114+
return <TextContent>{'-'}</TextContent>;
115+
}
115116
return (
116117
<TextContent>
117118
{params.map((param, index) => (
@@ -125,7 +126,7 @@ const TasksTableDisplay = (props: { setTasksCount: (number) => void; isVisible:
125126

126127
const taskAllowedRoles = (allowedRole: string) => {
127128
if (allowedRole == null || allowedRole.trim().length == 0) {
128-
return <TextContent>{t('cache-managers.allowed-role-null')}</TextContent>;
129+
return <TextContent>{t('cache-managers.tasks.allowed-role-null')}</TextContent>;
129130
}
130131
return (
131132
<TextContent>
@@ -134,78 +135,85 @@ const TasksTableDisplay = (props: { setTasksCount: (number) => void; isVisible:
134135
);
135136
};
136137

137-
const updateRows = (tasks: Task[]) => {
138-
let rows: { heightAuto: boolean; cells: (string | any)[] }[];
138+
if (!props.isVisible) {
139+
return <span />;
140+
}
139141

140-
if (tasks.length == 0) {
141-
rows = [
142-
{
143-
heightAuto: true,
144-
cells: [
145-
{
146-
props: { colSpan: 8 },
147-
title: (
142+
return (
143+
<React.Fragment>
144+
<Toolbar id="counters-table-toolbar">
145+
<ToolbarContent>
146+
<ToolbarItem variant={ToolbarItemVariant.pagination}>
147+
<Pagination
148+
itemCount={filteredTasks.length}
149+
perPage={tasksPagination.perPage}
150+
page={tasksPagination.page}
151+
onSetPage={onSetPage}
152+
widgetId="pagination-tasks"
153+
onPerPageSelect={onPerPageSelect}
154+
isCompact
155+
/>
156+
</ToolbarItem>
157+
</ToolbarContent>
158+
</Toolbar>
159+
<TableComposable
160+
className={'tasks-table'}
161+
aria-label={t('cache-managers.tasks.tasks-table-label')}
162+
variant={'compact'}
163+
>
164+
<Thead>
165+
<Tr>
166+
<Th colSpan={1}>{columnNames.name}</Th>
167+
<Th colSpan={1}>{columnNames.type}</Th>
168+
<Th colSpan={1}>{columnNames.context}</Th>
169+
<Th colSpan={1}>{columnNames.operation}</Th>
170+
<Th colSpan={1}>{columnNames.parameters}</Th>
171+
<Th colSpan={1}>{columnNames.allowedRoles}</Th>
172+
</Tr>
173+
</Thead>
174+
<Tbody>
175+
{tasks.length == 0 ? (
176+
<Tr>
177+
<Td colSpan={6}>
148178
<Bullseye>
149179
<EmptyState variant={EmptyStateVariant.small}>
150180
<EmptyStateIcon icon={SearchIcon} />
151181
<Title headingLevel="h2" size="lg">
152-
{t('cache-managers.no-tasks-status')}
182+
{t('cache-managers.tasks.no-tasks-status')}
153183
</Title>
154-
<EmptyStateBody>{t('cache-managers.no-tasks-body')}</EmptyStateBody>
184+
<EmptyStateBody>{t('cache-managers.tasks.no-tasks-body')}</EmptyStateBody>
155185
</EmptyState>
156186
</Bullseye>
157-
)
158-
}
159-
]
160-
}
161-
];
162-
} else {
163-
rows = tasks.map((task) => {
164-
return {
165-
heightAuto: true,
166-
cells: [
167-
{ title: task.name },
168-
{ title: taskType(task.type) },
169-
{ title: task.task_context_name },
170-
{ title: task.task_operation_name },
171-
{ title: taskParameters(task.parameters) },
172-
{ title: taskAllowedRoles(task.allowed_role) }
173-
]
174-
//TODO {title: <TasksActionLinks name={task.name}/>}]
175-
};
176-
});
177-
}
178-
setRows(rows);
179-
};
180-
181-
if (!props.isVisible) {
182-
return <span />;
183-
}
184-
185-
return (
186-
<Stack>
187-
<StackItem>
188-
<Pagination
189-
itemCount={filteredTasks.length}
190-
perPage={tasksPagination.perPage}
191-
page={tasksPagination.page}
192-
onSetPage={onSetPage}
193-
widgetId="pagination-tasks"
194-
onPerPageSelect={onPerPageSelect}
195-
isCompact
196-
/>
197-
<Table
198-
aria-label={t('cache-managers.tasks-table-label')}
199-
cells={columns}
200-
rows={rows}
201-
className={'tasks-table'}
202-
variant={TableVariant.compact}
203-
>
204-
<TableHeader />
205-
<TableBody />
206-
</Table>
207-
</StackItem>
208-
</Stack>
187+
</Td>
188+
</Tr>
189+
) : (
190+
rows.map((row) => {
191+
return (
192+
<Tr key={row.name}>
193+
<Td dataLabel={columnNames.name}>{row.name}</Td>
194+
<Td dataLabel={columnNames.type}>{taskType(row.type)}</Td>
195+
<Td dataLabel={columnNames.context}>{row.task_context_name}</Td>
196+
<Td dataLabel={columnNames.operation}>{row.task_operation_name}</Td>
197+
<Td dataLabel={columnNames.parameters}>{taskParameters(row.parameters)}</Td>
198+
<Td dataLabel={columnNames.allowedRoles}>{taskAllowedRoles(row.allowed_role)}</Td>
199+
<Td isActionCell>
200+
<ActionsColumn items={rowActionItem(row)} />
201+
</Td>
202+
</Tr>
203+
);
204+
})
205+
)}
206+
</Tbody>
207+
</TableComposable>
208+
<ExecuteTasks
209+
task={taskToExecute}
210+
isModalOpen={taskToExecute != undefined}
211+
closeModal={() => {
212+
setTaskToExecute(undefined);
213+
reload();
214+
}}
215+
/>
216+
</React.Fragment>
209217
);
210218
};
211219

src/app/Tasks/ExecuteTasks.tsx

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React, { useEffect, useState } from 'react';
2+
import {
3+
Button,
4+
ButtonVariant,
5+
Form,
6+
FormGroup,
7+
Modal,
8+
ModalVariant,
9+
Text,
10+
TextContent,
11+
TextInput
12+
} from '@patternfly/react-core';
13+
import { useExecuteTask } from '@app/services/tasksHook';
14+
import { useTranslation } from 'react-i18next';
15+
16+
const ExecuteTasks = (props: { task; isModalOpen: boolean; closeModal: () => void }) => {
17+
const { t } = useTranslation();
18+
const [paramsValue, setParamsValue] = useState({});
19+
const { onExecute } = useExecuteTask(props.task?.name, paramsValue);
20+
21+
useEffect(() => {
22+
const obj = props.task?.parameters?.reduce((o, key) => ({ ...o, [key]: '' }), {});
23+
setParamsValue(obj);
24+
}, [props.task]);
25+
26+
const onValueChange = (parameter, value) => {
27+
setParamsValue((prevState) => ({
28+
...prevState,
29+
[parameter]: value
30+
}));
31+
};
32+
33+
return (
34+
<Modal
35+
height={'1000px'}
36+
id={'execute-task-modal'}
37+
variant={ModalVariant.medium}
38+
isOpen={props.isModalOpen}
39+
title={t('cache-managers.tasks.execution')}
40+
onClose={props.closeModal}
41+
aria-label={t('cache-managers.tasks.execution')}
42+
disableFocusTrap={true}
43+
actions={[
44+
<Button
45+
key={'Confirm'}
46+
aria-label={'Confirm'}
47+
variant={ButtonVariant.primary}
48+
onClick={() => {
49+
onExecute();
50+
props.closeModal();
51+
}}
52+
>
53+
{t('cache-managers.tasks.execute')}
54+
</Button>,
55+
<Button key={'Cancel'} aria-label={'Cancel'} variant={ButtonVariant.link} onClick={props.closeModal}>
56+
{t('cache-managers.tasks.cancel')}
57+
</Button>
58+
]}
59+
>
60+
<TextContent>
61+
<Text>
62+
There are multiple parameters on the script <strong>{props.task?.name}</strong>. Select a parameter to run
63+
script.
64+
</Text>
65+
</TextContent>
66+
{props.task !== undefined && (
67+
<Form style={{ paddingTop: '3%' }} isHorizontal onSubmit={(e) => e.preventDefault()}>
68+
{props.task.parameters?.map((p) => {
69+
return (
70+
<FormGroup key={p} isStack label={p}>
71+
<TextInput type="text" onChange={(val) => onValueChange(p, val)} />
72+
</FormGroup>
73+
);
74+
})}
75+
</Form>
76+
)}
77+
</Modal>
78+
);
79+
};
80+
81+
export { ExecuteTasks };

0 commit comments

Comments
 (0)