foreman-tasks 0.17.0 → 0.17.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/foreman_tasks/tasks.css.scss +3 -3
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +50 -30
- data/app/controllers/foreman_tasks/tasks_controller.rb +8 -17
- data/app/models/foreman_tasks/task.rb +6 -4
- data/app/models/foreman_tasks/task/search.rb +0 -25
- data/app/models/setting/foreman_tasks.rb +19 -23
- data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -0
- data/app/views/foreman_tasks/layouts/react.html.erb +4 -1
- data/config/routes.rb +17 -3
- data/db/migrate/20180927120509_add_user_id.foreman_tasks.rb +4 -2
- data/lib/foreman_tasks/dynflow.rb +1 -1
- data/lib/foreman_tasks/dynflow/console_authorizer.rb +13 -2
- data/lib/foreman_tasks/engine.rb +1 -1
- data/lib/foreman_tasks/version.rb +1 -1
- data/package.json +1 -0
- data/test/controllers/tasks_controller_test.rb +35 -4
- data/test/unit/dynflow_console_authorizer_test.rb +1 -1
- data/test/unit/otp_manager_test.rb +24 -17
- data/test/unit/task_test.rb +48 -2
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +29 -16
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskHelper.js +3 -17
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +18 -5
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskHelper.test.js +1 -56
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +24 -44
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +22 -10
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +6 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +1 -1
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +2 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboard.js +6 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardActions.js +2 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardHelper.js +10 -41
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardReducer.js +0 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboard.test.js +1 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboardReducer.test.js.snap +1 -6
- data/webpack/ForemanTasks/Components/TasksTable/SubTasksPage.js +30 -0
- data/webpack/ForemanTasks/Components/TasksTable/TaskTableFormmatters.js +53 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksIndexPage.js +10 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +119 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +67 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +5 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +64 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +63 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.scss +29 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableReducer.js +35 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSchema.js +67 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +39 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/SubTasksPage.test.js +20 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksIndexPage.test.js +12 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +42 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.test.js +9 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +48 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableHelpers.test.js +28 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +26 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableReducer.test.js +37 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +49 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +42 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTable.test.js.snap +72 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +115 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +194 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableReducer.test.js.snap +32 -0
- data/webpack/ForemanTasks/Components/TasksTable/index.js +32 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +39 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +45 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.js +23 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.test.js +27 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.js +23 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.test.js +27 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +28 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/CancelButton.test.js.snap +15 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ResumeButton.test.js.snap +15 -0
- data/webpack/ForemanTasks/ForemanTasks.js +1 -17
- data/webpack/ForemanTasks/ForemanTasksReducers.js +2 -0
- data/webpack/ForemanTasks/Routes/ForemanTasksRouter.test.js +5 -1
- data/webpack/ForemanTasks/Routes/ForemanTasksRoutes.js +9 -3
- data/webpack/ForemanTasks/Routes/ForemanTasksRoutes.test.js +1 -1
- data/webpack/ForemanTasks/Routes/ShowTask/__tests__/ShowTask.test.js +5 -1
- data/webpack/ForemanTasks/Routes/__snapshots__/ForemanTasksRoutes.test.js.snap +18 -2
- data/webpack/ForemanTasks/__snapshots__/ForemanTasks.test.js.snap +1 -54
- data/webpack/__mocks__/foremanReact/common/helpers.js +1 -0
- data/webpack/__mocks__/foremanReact/common/urlHelpers.js +1 -0
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
- data/webpack/__mocks__/foremanReact/components/common/MessageBox.js +4 -0
- data/webpack/__mocks__/foremanReact/components/common/dates/LongDateTime.js +5 -0
- data/webpack/__mocks__/foremanReact/components/common/dates/RelativeDateTime.js +3 -0
- data/webpack/__mocks__/foremanReact/components/common/table.js +4 -0
- data/webpack/__mocks__/foremanReact/components/common/table/actionsHelpers/actionTypeCreator.js +7 -0
- data/webpack/__mocks__/foremanReact/constants.js +24 -0
- data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +8 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +10 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/components/ExportButton/ExportButton.js +5 -0
- data/webpack/index.js +5 -0
- metadata +49 -9
- data/app/views/foreman_tasks/tasks/index.html.erb +0 -46
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskHelper.test.js.snap +0 -37
- data/webpack/ForemanTasks/Routes/IndexTasks/IndexTasks.js +0 -10
- data/webpack/ForemanTasks/Routes/IndexTasks/__tests__/IndexTasks.test.js +0 -10
- data/webpack/ForemanTasks/Routes/IndexTasks/__tests__/__snapshots__/IndexTasks.test.js.snap +0 -12
- data/webpack/ForemanTasks/Routes/IndexTasks/index.js +0 -1
- data/webpack/ForemanTasks/Routes/IndexTasks/indexTasks.scss +0 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
import { getURIQuery } from 'foremanReact/common/helpers';
|
2
|
+
import { getTableItemsAction } from 'foremanReact/components/common/table';
|
3
|
+
import API from 'foremanReact/API';
|
4
|
+
import { addToast } from 'foremanReact/redux/actions/toasts';
|
5
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
6
|
+
import { TASKS_TABLE_ID } from './TasksTableConstants';
|
7
|
+
import { getApiPathname } from './TasksTableHelpers';
|
8
|
+
import { fetchTasksSummary } from '../TasksDashboard/TasksDashboardActions';
|
9
|
+
|
10
|
+
export const getTableItems = url =>
|
11
|
+
getTableItemsAction(TASKS_TABLE_ID, getURIQuery(url), getApiPathname(url));
|
12
|
+
|
13
|
+
export const cancelTask = (id, name, url) => async dispatch => {
|
14
|
+
await dispatch(cancelTaskRequest(id, name));
|
15
|
+
dispatch(getTableItems(url));
|
16
|
+
dispatch(fetchTasksSummary(getURIQuery(url).time));
|
17
|
+
};
|
18
|
+
|
19
|
+
export const cancelTaskRequest = (id, name) => async dispatch => {
|
20
|
+
dispatch(
|
21
|
+
addToast({
|
22
|
+
type: 'info',
|
23
|
+
message: `${__('Trying to cancel')} "${name}" ${__('task')}`,
|
24
|
+
})
|
25
|
+
);
|
26
|
+
try {
|
27
|
+
await API.post(`/foreman_tasks/tasks/${id}/cancel`);
|
28
|
+
dispatch(
|
29
|
+
addToast({
|
30
|
+
type: 'success',
|
31
|
+
message: `"${name}" ${__('task cancelled')}`,
|
32
|
+
})
|
33
|
+
);
|
34
|
+
} catch ({ response }) {
|
35
|
+
dispatch(
|
36
|
+
addToast({
|
37
|
+
type: 'error',
|
38
|
+
message: `"${name}" ${__('task cannot be cancelled at the moment.')}`,
|
39
|
+
})
|
40
|
+
);
|
41
|
+
}
|
42
|
+
};
|
43
|
+
|
44
|
+
export const resumeTask = (id, name, url) => async dispatch => {
|
45
|
+
await dispatch(resumeTaskRequest(id, name));
|
46
|
+
dispatch(getTableItems(url));
|
47
|
+
dispatch(fetchTasksSummary(getURIQuery(url).time));
|
48
|
+
};
|
49
|
+
|
50
|
+
export const resumeTaskRequest = (id, name) => async dispatch => {
|
51
|
+
try {
|
52
|
+
await API.post(`/foreman_tasks/tasks/${id}/resume`);
|
53
|
+
dispatch(
|
54
|
+
addToast({
|
55
|
+
type: 'success',
|
56
|
+
message: __(`"${name}" ${__('Task execution was resumed')}`),
|
57
|
+
})
|
58
|
+
);
|
59
|
+
} catch ({ response }) {
|
60
|
+
dispatch(
|
61
|
+
addToast({
|
62
|
+
type: 'error',
|
63
|
+
message: __(`Task "${name}" has to be resumable.`),
|
64
|
+
})
|
65
|
+
);
|
66
|
+
}
|
67
|
+
};
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import URI from 'urijs';
|
2
|
+
import { translate as __, documentLocale } from 'foremanReact/common/I18n';
|
3
|
+
import humanizeDuration from 'humanize-duration';
|
4
|
+
import { isoCompatibleDate } from 'foremanReact/common/helpers';
|
5
|
+
|
6
|
+
export const updateURlQuery = (query, history) => {
|
7
|
+
const uri = new URI(history.location.pathname + history.location.search);
|
8
|
+
uri.setSearch(query);
|
9
|
+
history.push(uri.search());
|
10
|
+
};
|
11
|
+
|
12
|
+
export const getApiPathname = url => {
|
13
|
+
const uri = new URI(url);
|
14
|
+
return uri.pathname().replace('foreman_tasks/', 'foreman_tasks/api/');
|
15
|
+
};
|
16
|
+
|
17
|
+
export const resolveSearchQuery = (search, history) => {
|
18
|
+
const uriQuery = {
|
19
|
+
search,
|
20
|
+
page: 1,
|
21
|
+
};
|
22
|
+
updateURlQuery(uriQuery, history);
|
23
|
+
};
|
24
|
+
|
25
|
+
export const addSearchToURL = (path, query) => {
|
26
|
+
const url = new URI(path);
|
27
|
+
url.addSearch({ ...query, include_permissions: true });
|
28
|
+
return url.toString();
|
29
|
+
};
|
30
|
+
|
31
|
+
export const getDuration = (start, finish) => {
|
32
|
+
if (!start && !finish)
|
33
|
+
return { text: __('N/A'), tooltip: __('No start or end dates') };
|
34
|
+
|
35
|
+
if (!start && finish) {
|
36
|
+
return { text: __('N/A'), tooltip: __('Task was canceled') };
|
37
|
+
}
|
38
|
+
|
39
|
+
const dateOptions = {
|
40
|
+
largest: 1,
|
41
|
+
language: documentLocale(),
|
42
|
+
fallbacks: ['en'],
|
43
|
+
round: true,
|
44
|
+
};
|
45
|
+
|
46
|
+
const startDate = new Date(isoCompatibleDate(start));
|
47
|
+
|
48
|
+
if (!finish) {
|
49
|
+
const finishDate = new Date();
|
50
|
+
const duration = finishDate - startDate;
|
51
|
+
return {
|
52
|
+
text: `${__('More than')} ${humanizeDuration(duration, dateOptions)}`,
|
53
|
+
};
|
54
|
+
}
|
55
|
+
|
56
|
+
const finishDate = new Date(isoCompatibleDate(finish));
|
57
|
+
const duration = finishDate - startDate;
|
58
|
+
return {
|
59
|
+
text:
|
60
|
+
duration > 0 && duration < 1000
|
61
|
+
? __('Less than a second')
|
62
|
+
: humanizeDuration(duration, dateOptions),
|
63
|
+
};
|
64
|
+
};
|
@@ -0,0 +1,63 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { getURIsearch } from 'foremanReact/common/urlHelpers';
|
4
|
+
import { Spinner } from 'patternfly-react';
|
5
|
+
import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
|
6
|
+
import { getURIQuery } from 'foremanReact/common/helpers';
|
7
|
+
import ExportButton from 'foremanReact/routes/common/PageLayout/components/ExportButton/ExportButton';
|
8
|
+
import { STATUS } from 'foremanReact/constants';
|
9
|
+
import TasksDashboard from '../TasksDashboard';
|
10
|
+
import TasksTable from './TasksTable';
|
11
|
+
import { resolveSearchQuery, addSearchToURL } from './TasksTableHelpers';
|
12
|
+
import { TASKS_SEARCH_PROPS } from './TasksTableConstants';
|
13
|
+
import './TasksTablePage.scss';
|
14
|
+
|
15
|
+
const TasksTablePage = ({ getBreadcrumbs, history, ...props }) => {
|
16
|
+
const url = history.location.pathname + history.location.search;
|
17
|
+
const uriQuery = getURIQuery(url);
|
18
|
+
const onSearch = searchQuery => {
|
19
|
+
resolveSearchQuery(searchQuery, history);
|
20
|
+
props.getTableItems(url);
|
21
|
+
};
|
22
|
+
|
23
|
+
return (
|
24
|
+
<div className="tasks-table-wrapper">
|
25
|
+
<PageLayout
|
26
|
+
searchable
|
27
|
+
searchProps={TASKS_SEARCH_PROPS}
|
28
|
+
onSearch={onSearch}
|
29
|
+
breadcrumbOptions={getBreadcrumbs(props.actionName)}
|
30
|
+
toastNotifications="foreman-tasks-cancel"
|
31
|
+
toolbarButtons={
|
32
|
+
<React.Fragment>
|
33
|
+
{props.status === STATUS.PENDING && <Spinner size="lg" loading />}
|
34
|
+
<ExportButton
|
35
|
+
url={addSearchToURL('/foreman_tasks/tasks.csv', uriQuery)}
|
36
|
+
/>
|
37
|
+
</React.Fragment>
|
38
|
+
}
|
39
|
+
searchQuery={getURIsearch()}
|
40
|
+
beforeToolbarComponent={<TasksDashboard history={history} />}
|
41
|
+
>
|
42
|
+
<TasksTable history={history} {...props} />
|
43
|
+
</PageLayout>
|
44
|
+
</div>
|
45
|
+
);
|
46
|
+
};
|
47
|
+
|
48
|
+
TasksTablePage.propTypes = {
|
49
|
+
getTableItems: PropTypes.func.isRequired,
|
50
|
+
getBreadcrumbs: PropTypes.func.isRequired,
|
51
|
+
actionName: PropTypes.string,
|
52
|
+
isSubTask: PropTypes.bool,
|
53
|
+
status: PropTypes.oneOf(Object.keys(STATUS)),
|
54
|
+
history: PropTypes.object.isRequired,
|
55
|
+
};
|
56
|
+
|
57
|
+
TasksTablePage.defaultProps = {
|
58
|
+
actionName: '',
|
59
|
+
isSubTask: false,
|
60
|
+
status: STATUS.PENDING,
|
61
|
+
};
|
62
|
+
|
63
|
+
export default TasksTablePage;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
.tasks-pagination {
|
2
|
+
margin-top: -6px;
|
3
|
+
}
|
4
|
+
.tasks-table {
|
5
|
+
margin-bottom: 70px;
|
6
|
+
}
|
7
|
+
|
8
|
+
.tasks-table-wrapper {
|
9
|
+
.export-csv {
|
10
|
+
float: right;
|
11
|
+
}
|
12
|
+
.search-bar {
|
13
|
+
padding-bottom: 20px;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
.param-name {
|
18
|
+
display: inline-block;
|
19
|
+
width: 10em;
|
20
|
+
}
|
21
|
+
|
22
|
+
.task-details pre {
|
23
|
+
white-space: pre;
|
24
|
+
word-break: normal;
|
25
|
+
}
|
26
|
+
|
27
|
+
.tasks-time-row .time-label {
|
28
|
+
float: left;
|
29
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import Immutable from 'seamless-immutable';
|
2
|
+
import { combineReducers } from 'redux';
|
3
|
+
import { createTableReducer } from 'foremanReact/components/common/table';
|
4
|
+
import createTableActionTypes from 'foremanReact/components/common/table/actionsHelpers/actionTypeCreator';
|
5
|
+
import { TASKS_TABLE_ID } from './TasksTableConstants';
|
6
|
+
|
7
|
+
export const TasksTableQueryReducer = (state = {}, action) => {
|
8
|
+
const {
|
9
|
+
type,
|
10
|
+
payload: {
|
11
|
+
subtotal,
|
12
|
+
page,
|
13
|
+
per_page: perPageString,
|
14
|
+
action_name: actionName,
|
15
|
+
} = {},
|
16
|
+
} = action;
|
17
|
+
const ACTION_TYPES = createTableActionTypes(TASKS_TABLE_ID);
|
18
|
+
switch (type) {
|
19
|
+
case ACTION_TYPES.SUCCESS:
|
20
|
+
return Immutable.merge(state, {
|
21
|
+
itemCount: subtotal,
|
22
|
+
actionName,
|
23
|
+
pagination: {
|
24
|
+
page: Number(page),
|
25
|
+
perPage: Number(perPageString),
|
26
|
+
},
|
27
|
+
});
|
28
|
+
default:
|
29
|
+
return state;
|
30
|
+
}
|
31
|
+
};
|
32
|
+
export default combineReducers({
|
33
|
+
tasksTableContent: createTableReducer(TASKS_TABLE_ID),
|
34
|
+
tasksTableQuery: TasksTableQueryReducer,
|
35
|
+
});
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import {
|
2
|
+
column,
|
3
|
+
sortableColumn,
|
4
|
+
headerFormatterWithProps,
|
5
|
+
cellFormatter,
|
6
|
+
} from 'foremanReact/components/common/table';
|
7
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
8
|
+
import {
|
9
|
+
dateCellFormmatter,
|
10
|
+
actionCellFormatter,
|
11
|
+
actionNameCellFormatter,
|
12
|
+
durationCellFormmatter,
|
13
|
+
} from './TaskTableFormmatters';
|
14
|
+
|
15
|
+
const headFormat = [headerFormatterWithProps];
|
16
|
+
const cellFormat = [cellFormatter];
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Generate a table schema to the Hardware Tasks page.
|
20
|
+
* @param {Function} setSort a Redux async action that sets new sort values
|
21
|
+
* @param {String} by by which column the table is sorted.
|
22
|
+
* If none then set it to undefined/null.
|
23
|
+
* @param {String} order in what order to sort a column. If none then set it to undefined/null.
|
24
|
+
* Otherwise, 'ASC' for ascending and 'DESC' for descending
|
25
|
+
* @param {function} cancelTask A function to run when the cancel cell is clicked
|
26
|
+
* @return {Array}
|
27
|
+
*/
|
28
|
+
const createTasksTableSchema = (setSort, by, order, taskActions) => {
|
29
|
+
const sortController = {
|
30
|
+
apply: setSort,
|
31
|
+
property: by,
|
32
|
+
order,
|
33
|
+
};
|
34
|
+
|
35
|
+
return [
|
36
|
+
column(
|
37
|
+
'action',
|
38
|
+
__('Action'),
|
39
|
+
headFormat,
|
40
|
+
[actionNameCellFormatter('foreman_tasks/tasks')],
|
41
|
+
{ className: 'col-md-4' }
|
42
|
+
),
|
43
|
+
column('state', __('State'), headFormat, cellFormat, {
|
44
|
+
className: 'col-md-1',
|
45
|
+
}),
|
46
|
+
column('result', __('Result'), headFormat, cellFormat, {
|
47
|
+
className: 'col-md-1',
|
48
|
+
}),
|
49
|
+
sortableColumn('started_at', __('Started at'), 3, sortController, [
|
50
|
+
dateCellFormmatter,
|
51
|
+
]),
|
52
|
+
sortableColumn('duration', __('Duration'), 3, sortController, [
|
53
|
+
durationCellFormmatter,
|
54
|
+
]),
|
55
|
+
column(
|
56
|
+
'available_actions',
|
57
|
+
__('Operation'),
|
58
|
+
headFormat,
|
59
|
+
[actionCellFormatter(taskActions)],
|
60
|
+
{
|
61
|
+
className: 'col-md-1',
|
62
|
+
}
|
63
|
+
),
|
64
|
+
];
|
65
|
+
};
|
66
|
+
|
67
|
+
export default createTasksTableSchema;
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
2
|
+
import { selectForemanTasks } from '../../ForemanTasksSelectors';
|
3
|
+
import { getDuration } from './TasksTableHelpers';
|
4
|
+
|
5
|
+
export const selectTasksTable = state =>
|
6
|
+
selectForemanTasks(state).tasksTable || {};
|
7
|
+
|
8
|
+
export const selectTasksTableContent = state =>
|
9
|
+
selectTasksTable(state).tasksTableContent || {};
|
10
|
+
|
11
|
+
export const selectTasksTableQuery = state =>
|
12
|
+
selectTasksTable(state).tasksTableQuery || {};
|
13
|
+
|
14
|
+
export const selectPagitation = state =>
|
15
|
+
selectTasksTableQuery(state).pagination || {};
|
16
|
+
|
17
|
+
export const selectItemCount = state =>
|
18
|
+
selectTasksTableQuery(state).itemCount || 0;
|
19
|
+
|
20
|
+
export const selectActionName = state =>
|
21
|
+
selectTasksTableQuery(state).actionName || '';
|
22
|
+
|
23
|
+
export const selectResults = state => {
|
24
|
+
const { results } = selectTasksTableContent(state);
|
25
|
+
if (!results) return [];
|
26
|
+
return results.map(result => ({
|
27
|
+
...result,
|
28
|
+
username: result.username || '',
|
29
|
+
state: result.state + (result.frozen ? ` ${__('Disabled')}` : ''),
|
30
|
+
duration: getDuration(result.started_at, result.ended_at),
|
31
|
+
}));
|
32
|
+
};
|
33
|
+
|
34
|
+
export const selectStatus = state => selectTasksTableContent(state).status;
|
35
|
+
|
36
|
+
export const selectError = state => selectTasksTableContent(state).error;
|
37
|
+
|
38
|
+
export const selectSort = state =>
|
39
|
+
selectTasksTableQuery(state).sort || { by: 'started_at', order: 'DESC' };
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
|
2
|
+
import { SubTasksPage } from '../SubTasksPage';
|
3
|
+
import { minProps } from './TasksTable.fixtures';
|
4
|
+
|
5
|
+
const fixtures = {
|
6
|
+
'render with minimal props': {
|
7
|
+
...minProps,
|
8
|
+
|
9
|
+
match: {
|
10
|
+
params: {
|
11
|
+
id: 'some-id',
|
12
|
+
},
|
13
|
+
},
|
14
|
+
},
|
15
|
+
};
|
16
|
+
|
17
|
+
describe('SubTasksPage', () => {
|
18
|
+
describe('rendering', () =>
|
19
|
+
testComponentSnapshotsWithFixtures(SubTasksPage, fixtures));
|
20
|
+
});
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
|
2
|
+
import { TasksIndexPage } from '../TasksIndexPage';
|
3
|
+
import { minProps } from './TasksTable.fixtures';
|
4
|
+
|
5
|
+
const fixtures = {
|
6
|
+
'render with minimal props': minProps,
|
7
|
+
};
|
8
|
+
|
9
|
+
describe('TasksIndexPage', () => {
|
10
|
+
describe('rendering', () =>
|
11
|
+
testComponentSnapshotsWithFixtures(TasksIndexPage, fixtures));
|
12
|
+
});
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { STATUS } from 'foremanReact/constants';
|
2
|
+
|
3
|
+
export const minProps = {
|
4
|
+
getTableItems: jest.fn(),
|
5
|
+
getBreadcrumbs: jest.fn(),
|
6
|
+
itemCount: 2,
|
7
|
+
cancelTask: jest.fn(),
|
8
|
+
resumeTask: jest.fn(),
|
9
|
+
pagination: {
|
10
|
+
page: 1,
|
11
|
+
perPage: 10,
|
12
|
+
},
|
13
|
+
history: { location: { search: '' } },
|
14
|
+
location: { pathname: '' },
|
15
|
+
status: STATUS.RESOLVED,
|
16
|
+
results: ['a', 'b'],
|
17
|
+
sort: {
|
18
|
+
by: 'q',
|
19
|
+
order: 'w',
|
20
|
+
},
|
21
|
+
};
|
22
|
+
|
23
|
+
export default {
|
24
|
+
'render with minimal Props': {
|
25
|
+
...minProps,
|
26
|
+
},
|
27
|
+
'render with no results': {
|
28
|
+
...minProps,
|
29
|
+
results: [],
|
30
|
+
status: STATUS.RESOLVED,
|
31
|
+
},
|
32
|
+
'render with error Props': {
|
33
|
+
...minProps,
|
34
|
+
results: ['a'],
|
35
|
+
status: STATUS.ERROR,
|
36
|
+
},
|
37
|
+
'render with loading Props': {
|
38
|
+
...minProps,
|
39
|
+
results: ['a'],
|
40
|
+
status: STATUS.PENDING,
|
41
|
+
},
|
42
|
+
};
|