foreman-tasks 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/js_tests.yml +5 -1
  3. data/app/controllers/foreman_tasks/api/tasks_controller.rb +1 -2
  4. data/app/models/setting/foreman_tasks.rb +8 -8
  5. data/app/services/foreman_tasks/dashboard_table_filter.rb +5 -1
  6. data/lib/foreman_tasks/version.rb +1 -1
  7. data/test/controllers/api/tasks_controller_test.rb +10 -0
  8. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.scss +4 -0
  9. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.js +53 -0
  10. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.test.js +14 -0
  11. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +27 -19
  12. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +14 -0
  13. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.test.js +1 -34
  14. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/{StoppedTasksCardHelper.js → StoppedTasksCardTable.js} +28 -1
  15. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardTable.test.js +54 -0
  16. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/OtherInfo.test.js.snap +48 -0
  17. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCard.test.js.snap +60 -1367
  18. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCardTable.test.js.snap +960 -0
  19. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +14 -11
  20. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +2 -0
  21. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardSelectors.js +17 -11
  22. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardSelectors.test.js +26 -14
  23. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboard.test.js.snap +14 -11
  24. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboardSelectors.test.js.snap +38 -22
  25. metadata +8 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24da58e2837688da28a18832b72b154ac74868157f6176f942119b8b856987c8
4
- data.tar.gz: 3031305c5f86f3b03aed95a4501670cbd2dbd595db38f638354ff046f416823a
3
+ metadata.gz: dc7a0cd7f208321abcb3a5360623c6a639cbe6ae7e4f00c89987db5c18de95cb
4
+ data.tar.gz: 7cc406baeb19a74bb7ac645349050d192ff1d3f62edb7895eada9744f1d39fd4
5
5
  SHA512:
6
- metadata.gz: a6a21ff8c4b9336f63118c2cdf6a4f11bf25ff882fe1dbd1b17d05f9722705c9cebabb522792416758c3fede1a8507d720cac0317076d8e833bfbb95a83fa8a4
7
- data.tar.gz: bef5dd6cac70ac43d53e83950668e930883649d42966b10ff6303e0d581431d3f11028ae24c7ecc9ed0e2875214f4a512cfbaa46f1da81fd912d6a6f25da2db2
6
+ metadata.gz: 04ec2f1a2096462df40eea233da31072e713dfa2d75314a0a7c271a7b48cca32a46f9785b831f684dda45ad1c5efcf65da1c2941aad8c6f39deee25bf324f54f
7
+ data.tar.gz: 5d8dbdeeff9b3bb1287707cc2abb13847fcece48f986e81240ec687b280811c2249200ea497901061ed789f9481a1ba8ec639918ab5010b0cf52ea341b5b34a5
@@ -18,10 +18,14 @@ jobs:
18
18
  - name: Setup Node
19
19
  uses: actions/setup-node@v1
20
20
  with:
21
- node-version: ${{ matrix.node-version }}
21
+ node-version: ${{ matrix.node-version }}
22
22
  - name: Npm install
23
23
  run: npm install
24
24
  - name: Run plugin linter
25
25
  run: npm run lint
26
26
  - name: Run plugin tests
27
27
  run: npm run test
28
+ - name: Publish Coveralls
29
+ uses: coverallsapp/github-action@master
30
+ with:
31
+ github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -221,7 +221,7 @@ module ForemanTasks
221
221
  end
222
222
 
223
223
  def search_tasks(search_params)
224
- scope = resource_scope_for_index.select('DISTINCT foreman_tasks_tasks.*')
224
+ scope = resource_scope_for_index
225
225
  scope = ordering_scope(scope, search_params)
226
226
  scope = search_scope(scope, search_params)
227
227
  scope = active_scope(scope, search_params)
@@ -287,7 +287,6 @@ module ForemanTasks
287
287
  sort_by = ordering_params[:sort_by] || 'started_at'
288
288
  sort_by = 'foreman_tasks_tasks.' + sort_by if sort_by == 'started_at'
289
289
  sort_order = ordering_params[:sort_order] || 'DESC'
290
- scope = scope.select("foreman_tasks_tasks.*, coalesce(ended_at, current_timestamp) - coalesce(coalesce(started_at, ended_at), current_timestamp) as duration")
291
290
  scope.order("#{sort_by} #{sort_order}")
292
291
  end
293
292
 
@@ -1,18 +1,18 @@
1
1
  class Setting::ForemanTasks < Setting
2
2
  def self.default_settings
3
3
  [
4
- set('foreman_tasks_sync_task_timeout', N_('Number of seconds to wait for synchronous task to finish.'), 120),
5
- set('dynflow_enable_console', N_('Enable the dynflow console (/foreman_tasks/dynflow) for debugging'), true),
6
- set('dynflow_console_require_auth', N_('Require user to be authenticated as user with admin rights when accessing dynflow console'), true),
7
- set('foreman_tasks_proxy_action_retry_count', N_('Number of attempts to start a task on the smart proxy before failing'), 4),
8
- set('foreman_tasks_proxy_action_retry_interval', N_('Time in seconds between retries'), 15),
9
- set('foreman_tasks_proxy_batch_trigger', N_('Allow triggering tasks on the smart proxy in batches'), true),
10
- set('foreman_tasks_proxy_batch_size', N_('Number of tasks which should be sent to the smart proxy in one request, if foreman_tasks_proxy_batch_trigger is enabled'), 100),
4
+ set('foreman_tasks_sync_task_timeout', N_('Number of seconds to wait for synchronous task to finish.'), 120, N_('Sync task timeout')),
5
+ set('dynflow_enable_console', N_('Enable the dynflow console (/foreman_tasks/dynflow) for debugging'), true, N_('Enable dynflow console')),
6
+ set('dynflow_console_require_auth', N_('Require user to be authenticated as user with admin rights when accessing dynflow console'), true, N_('Require auth for dynflow console')),
7
+ set('foreman_tasks_proxy_action_retry_count', N_('Number of attempts to start a task on the smart proxy before failing'), 4, N_('Proxy action retry count')),
8
+ set('foreman_tasks_proxy_action_retry_interval', N_('Time in seconds between retries'), 15, N_('Proxy action retry interval')),
9
+ set('foreman_tasks_proxy_batch_trigger', N_('Allow triggering tasks on the smart proxy in batches'), true, N_('Allow proxy batch tasks')),
10
+ set('foreman_tasks_proxy_batch_size', N_('Number of tasks which should be sent to the smart proxy in one request, if foreman_tasks_proxy_batch_trigger is enabled'), 100, N_('Proxy tasks batch size')),
11
11
  set('foreman_tasks_troubleshooting_url',
12
12
  N_('Url pointing to the task troubleshooting documentation. '\
13
13
  'It should contain %{label} placeholder, that will be replaced with normalized task label '\
14
14
  '(restricted to only alphanumeric characters)). %{version} placeholder is also available.'),
15
- nil),
15
+ nil, N_('Tasks troubleshooting URL')),
16
16
  set('foreman_tasks_polling_multiplier',
17
17
  N_('Polling multiplier which is used to multiply the default polling intervals. '\
18
18
  'This can be used to prevent polling too frequently for long running tasks.'),
@@ -24,7 +24,11 @@ module ForemanTasks
24
24
  private
25
25
 
26
26
  def scope_by(field)
27
- @new_scope = @new_scope.where(field => @params[field]) if @params[field].present?
27
+ if (field == :result) && (@params[field] == 'other')
28
+ @new_scope = @new_scope.where(:result => ['cancelled', 'pending'])
29
+ elsif @params[field].present?
30
+ @new_scope = @new_scope.where(field => @params[field])
31
+ end
28
32
  end
29
33
 
30
34
  def scope_by_time
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '3.0.0'.freeze
2
+ VERSION = '3.0.1'.freeze
3
3
  end
@@ -45,6 +45,16 @@ module ForemanTasks
45
45
  end
46
46
  end
47
47
 
48
+ describe 'POST /api/tasks/bulk_search' do
49
+ it 'searching for a task' do
50
+ task = FactoryBot.create(:dynflow_task, :user_create_task)
51
+ post :bulk_search, params: { :searches => [{ :type => "task", :task_id => task.id, :search_id => "1" }] }
52
+ assert_response :success
53
+ data = JSON.parse(response.body)
54
+ _(data[0]['results'][0]['id']).must_equal task.id
55
+ end
56
+ end
57
+
48
58
  describe 'GET /api/tasks/show' do
49
59
  it 'searches for task' do
50
60
  task = FactoryBot.create(:dynflow_task, :user_create_task)
@@ -1,15 +1,19 @@
1
1
  .scheduled-tasks-card {
2
2
  text-align: center;
3
+
3
4
  .scheduled-data {
5
+ margin-top: 30px;
4
6
  padding-right: 15px;
5
7
  cursor: pointer;
6
8
  font-size: 40px;
7
9
  font-weight: 300;
8
10
  transition: font-weight 50ms ease-in;
11
+
9
12
  p {
10
13
  font-size: 20px;
11
14
  margin: 0;
12
15
  }
16
+
13
17
  * {
14
18
  margin: 10px;
15
19
  }
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import classNames from 'classnames';
4
+
5
+ import { Icon, Button, OverlayTrigger, Tooltip } from 'patternfly-react';
6
+ import { translate as __ } from 'foremanReact/common/I18n';
7
+ import {
8
+ TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
9
+ TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS,
10
+ } from '../../../../TasksDashboardConstants';
11
+ import { queryPropType } from '../../../../TasksDashboardPropTypes';
12
+
13
+ const tooltip = (
14
+ <Tooltip id="stopped-tooltip">
15
+ {__('Other includes all stopped tasks that are cancelled or pending')}
16
+ </Tooltip>
17
+ );
18
+
19
+ export const OtherInfo = ({ updateQuery, otherCount, query }) => {
20
+ const { OTHER } = TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS;
21
+ const { STOPPED } = TASKS_DASHBOARD_AVAILABLE_QUERY_STATES;
22
+ const active = query.state === STOPPED && query.result === OTHER;
23
+ return (
24
+ <span className={classNames(active && 'other-active')}>
25
+ <OverlayTrigger
26
+ overlay={tooltip}
27
+ trigger={['hover', 'focus']}
28
+ placement="bottom"
29
+ >
30
+ <span>
31
+ <Icon type="pf" name="info" />
32
+ <span>{__('Other:')} </span>
33
+ </span>
34
+ </OverlayTrigger>
35
+ <Button
36
+ bsStyle="link"
37
+ onClick={() =>
38
+ updateQuery({
39
+ state: STOPPED,
40
+ result: OTHER,
41
+ })
42
+ }
43
+ >
44
+ {otherCount}
45
+ </Button>
46
+ </span>
47
+ );
48
+ };
49
+ OtherInfo.propTypes = {
50
+ updateQuery: PropTypes.func.isRequired,
51
+ otherCount: PropTypes.number.isRequired,
52
+ query: queryPropType.isRequired,
53
+ };
@@ -0,0 +1,14 @@
1
+ import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
+
3
+ import { OtherInfo } from './OtherInfo';
4
+
5
+ const fixtures = {
6
+ render: {
7
+ updateQuery: jest.fn,
8
+ otherCount: 7,
9
+ query: { state: 'STOPPED', result: 'OTHER' },
10
+ },
11
+ };
12
+
13
+ describe('OtherInfo', () =>
14
+ testComponentSnapshotsWithFixtures(OtherInfo, fixtures));
@@ -4,8 +4,8 @@ import { Card } from 'patternfly-react';
4
4
  import classNames from 'classnames';
5
5
  import { noop } from 'foremanReact/common/helpers';
6
6
  import { translate as __ } from 'foremanReact/common/I18n';
7
-
8
- import { StoppedTable } from './StoppedTasksCardHelper';
7
+ import { OtherInfo } from './OtherInfo';
8
+ import { StoppedTable } from './StoppedTasksCardTable';
9
9
  import {
10
10
  timePropType,
11
11
  queryPropType,
@@ -14,7 +14,6 @@ import {
14
14
  TASKS_DASHBOARD_AVAILABLE_TIMES,
15
15
  TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
16
16
  } from '../../../../TasksDashboardConstants';
17
- import { getQueryValueText } from '../../../../TasksDashboardHelper';
18
17
  import './StoppedTasksCard.scss';
19
18
 
20
19
  const StoppedTasksCard = ({
@@ -44,16 +43,19 @@ const StoppedTasksCard = ({
44
43
  {__('Stopped')}
45
44
  </Card.Title>
46
45
  <Card.Body>
47
- <table className="table table-bordered table-striped stopped-table">
48
- <thead>
49
- <tr>
50
- <th />
51
- <th>{__('Total')}</th>
52
- <th>{getQueryValueText(time)}</th>
53
- </tr>
54
- </thead>
55
- <tbody>{StoppedTable(data, query, time, updateQuery)}</tbody>
56
- </table>
46
+ <React.Fragment>
47
+ <StoppedTable
48
+ data={data.results}
49
+ query={query}
50
+ time={time}
51
+ updateQuery={updateQuery}
52
+ />
53
+ <OtherInfo
54
+ updateQuery={updateQuery}
55
+ otherCount={data.other}
56
+ query={query}
57
+ />
58
+ </React.Fragment>
57
59
  </Card.Body>
58
60
  </Card>
59
61
  );
@@ -66,9 +68,12 @@ const resultPropType = PropTypes.shape({
66
68
 
67
69
  StoppedTasksCard.propTypes = {
68
70
  data: PropTypes.shape({
69
- error: resultPropType.isRequired,
70
- warning: resultPropType.isRequired,
71
- success: resultPropType.isRequired,
71
+ results: PropTypes.shape({
72
+ error: resultPropType.isRequired,
73
+ warning: resultPropType.isRequired,
74
+ success: resultPropType.isRequired,
75
+ }),
76
+ other: PropTypes.number,
72
77
  }),
73
78
  time: timePropType,
74
79
  query: queryPropType,
@@ -78,9 +83,12 @@ StoppedTasksCard.propTypes = {
78
83
 
79
84
  StoppedTasksCard.defaultProps = {
80
85
  data: {
81
- error: { total: 0, last: 0 },
82
- warning: { total: 0, last: 0 },
83
- success: { total: 0, last: 0 },
86
+ results: {
87
+ error: { total: 0, last: 0 },
88
+ warning: { total: 0, last: 0 },
89
+ success: { total: 0, last: 0 },
90
+ },
91
+ other: 0,
84
92
  },
85
93
  time: TASKS_DASHBOARD_AVAILABLE_TIMES.H24,
86
94
  query: {},
@@ -39,4 +39,18 @@
39
39
  }
40
40
  }
41
41
  }
42
+
43
+ .other-active {
44
+ text-decoration: underline;
45
+ }
46
+
47
+ .pficon {
48
+ margin-right: 5px;
49
+ }
50
+
51
+ .btn-link {
52
+ font-size: 14px;
53
+ padding-top: 0;
54
+ padding-bottom: 0;
55
+ }
42
56
  }
@@ -1,48 +1,15 @@
1
1
  import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
- import {
3
- TASKS_DASHBOARD_AVAILABLE_TIMES,
4
- TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
5
- TASKS_DASHBOARD_AVAILABLE_QUERY_MODES,
6
- TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS,
7
- } from '../../../../TasksDashboardConstants';
2
+ import { TASKS_DASHBOARD_AVAILABLE_QUERY_STATES } from '../../../../TasksDashboardConstants';
8
3
  import StoppedTasksCard from './StoppedTasksCard';
9
4
 
10
5
  const { STOPPED } = TASKS_DASHBOARD_AVAILABLE_QUERY_STATES;
11
- const { LAST } = TASKS_DASHBOARD_AVAILABLE_QUERY_MODES;
12
- const { WEEK } = TASKS_DASHBOARD_AVAILABLE_TIMES;
13
6
 
14
7
  const fixtures = {
15
8
  'render with minimal props': {},
16
- 'render with props': {
17
- data: {
18
- error: { total: 9, last: 1 },
19
- warning: { total: 8, last: 2 },
20
- success: { total: 7, last: 3 },
21
- },
22
- time: WEEK,
23
- },
24
9
  'render selected': {
25
10
  query: { state: STOPPED },
26
11
  },
27
12
  };
28
13
 
29
- Object.values(TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS).forEach(result => {
30
- fixtures[`render ${result}-total selected`] = {
31
- query: {
32
- state: STOPPED,
33
- result,
34
- },
35
- };
36
- fixtures[`render ${result}-last selected`] = {
37
- time: WEEK,
38
- query: {
39
- state: STOPPED,
40
- result,
41
- mode: LAST,
42
- time: WEEK,
43
- },
44
- };
45
- });
46
-
47
14
  describe('StoppedTasksCard', () =>
48
15
  testComponentSnapshotsWithFixtures(StoppedTasksCard, fixtures));
@@ -1,11 +1,18 @@
1
1
  import React from 'react';
2
+ import PropTypes from 'prop-types';
2
3
  import { capitalize } from 'lodash';
3
4
  import classNames from 'classnames';
4
5
  import { Icon, Button } from 'patternfly-react';
6
+ import { translate as __ } from 'foremanReact/common/I18n';
5
7
  import {
6
8
  TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
7
9
  TASKS_DASHBOARD_AVAILABLE_QUERY_MODES,
8
10
  } from '../../../../TasksDashboardConstants';
11
+ import { getQueryValueText } from '../../../../TasksDashboardHelper';
12
+ import {
13
+ timePropType,
14
+ queryPropType,
15
+ } from '../../../../TasksDashboardPropTypes';
9
16
 
10
17
  const resultIcons = {
11
18
  error: <Icon type="pf" name="error-circle-o" />,
@@ -13,7 +20,7 @@ const resultIcons = {
13
20
  success: <Icon type="pf" name="ok" />,
14
21
  };
15
22
 
16
- export const StoppedTable = (data, query, time, updateQuery) =>
23
+ const StoppedTableCells = (data, query, time, updateQuery) =>
17
24
  Object.entries(data).map(([result, { total, last }]) => {
18
25
  const { STOPPED } = TASKS_DASHBOARD_AVAILABLE_QUERY_STATES;
19
26
  const { LAST } = TASKS_DASHBOARD_AVAILABLE_QUERY_MODES;
@@ -61,3 +68,23 @@ export const StoppedTable = (data, query, time, updateQuery) =>
61
68
  </tr>
62
69
  );
63
70
  });
71
+
72
+ export const StoppedTable = ({ data, query, time, updateQuery }) => (
73
+ <table className="table table-bordered table-striped stopped-table">
74
+ <thead>
75
+ <tr>
76
+ <th />
77
+ <th>{__('Total')}</th>
78
+ <th>{getQueryValueText(time)}</th>
79
+ </tr>
80
+ </thead>
81
+ <tbody>{StoppedTableCells(data, query, time, updateQuery)}</tbody>
82
+ </table>
83
+ );
84
+
85
+ StoppedTable.propTypes = {
86
+ data: PropTypes.object.isRequired,
87
+ query: queryPropType.isRequired,
88
+ time: timePropType.isRequired,
89
+ updateQuery: PropTypes.func.isRequired,
90
+ };
@@ -0,0 +1,54 @@
1
+ import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
+
3
+ import { StoppedTable } from './StoppedTasksCardTable';
4
+ import {
5
+ TASKS_DASHBOARD_AVAILABLE_TIMES,
6
+ TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
7
+ TASKS_DASHBOARD_AVAILABLE_QUERY_MODES,
8
+ TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS,
9
+ } from '../../../../TasksDashboardConstants';
10
+
11
+ const { STOPPED } = TASKS_DASHBOARD_AVAILABLE_QUERY_STATES;
12
+ const { LAST } = TASKS_DASHBOARD_AVAILABLE_QUERY_MODES;
13
+ const { WEEK } = TASKS_DASHBOARD_AVAILABLE_TIMES;
14
+ const data = {
15
+ error: { total: 9, last: 1 },
16
+ warning: { total: 8, last: 2 },
17
+ success: { total: 7, last: 3 },
18
+ };
19
+ const fixtures = {
20
+ 'render with props': {
21
+ data,
22
+ time: WEEK,
23
+ query: {},
24
+ updateQuery: jest.fn(),
25
+ },
26
+ };
27
+
28
+ Object.values(TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS)
29
+ .filter(result => result !== TASKS_DASHBOARD_AVAILABLE_QUERY_RESULTS.OTHER)
30
+ .forEach(result => {
31
+ fixtures[`render ${result}-total selected`] = {
32
+ query: {
33
+ state: STOPPED,
34
+ result,
35
+ },
36
+ updateQuery: jest.fn(),
37
+ data,
38
+ time: WEEK,
39
+ };
40
+ fixtures[`render ${result}-last selected`] = {
41
+ time: WEEK,
42
+ query: {
43
+ state: STOPPED,
44
+ result,
45
+ mode: LAST,
46
+ time: WEEK,
47
+ },
48
+ updateQuery: jest.fn(),
49
+ data,
50
+ };
51
+ });
52
+
53
+ describe('StoppedTable', () =>
54
+ testComponentSnapshotsWithFixtures(StoppedTable, fixtures));