foreman-tasks 12.1.1 → 12.2.2

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -1
  4. data/foreman-tasks.gemspec +1 -3
  5. data/lib/foreman_tasks/version.rb +1 -1
  6. data/test/controllers/api/tasks_controller_test.rb +2 -2
  7. data/webpack/ForemanTasks/Components/TaskDetails/Components/Dependencies.js +69 -58
  8. data/webpack/ForemanTasks/Components/TaskDetails/Components/Errors.js +25 -5
  9. data/webpack/ForemanTasks/Components/TaskDetails/Components/Locks.js +170 -43
  10. data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +12 -4
  11. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +217 -201
  12. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskSkeleton.js +30 -34
  13. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Dependencies.test.js +90 -29
  14. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Errors.test.js +50 -27
  15. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Locks.test.js +256 -23
  16. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Raw.test.js +44 -22
  17. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +56 -24
  18. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +42 -22
  19. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +45 -54
  20. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +65 -25
  21. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +37 -13
  22. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +53 -8
  23. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/PausedTasksCard.test.js +53 -7
  24. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/RunningTasksCard.test.js +53 -7
  25. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.js +5 -4
  26. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.test.js +44 -14
  27. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +6 -5
  28. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.js +5 -4
  29. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.scss +3 -8
  30. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/TasksDonutCard.test.js +75 -34
  31. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChart.test.js +57 -34
  32. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/TasksDonutChartHelper.test.js +23 -9
  33. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.fixtures.js +14 -11
  34. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.js +19 -21
  35. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/TasksCardsGrid.test.js +63 -14
  36. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.js +9 -17
  37. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/TimeDropDown.test.js +49 -13
  38. metadata +2 -46
  39. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Errors.test.js.snap +0 -77
  40. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Locks.test.js.snap +0 -116
  41. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Raw.test.js.snap +0 -174
  42. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +0 -62
  43. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +0 -127
  44. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +0 -580
  45. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +0 -172
  46. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +0 -52
  47. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/PausedTasksCard/__snapshots__/PausedTasksCard.test.js.snap +0 -38
  48. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/RunningTasksCard/__snapshots__/RunningTasksCard.test.js.snap +0 -38
  49. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/__snapshots__/ScheduledTasksCard.test.js.snap +0 -97
  50. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutCard/__snapshots__/TasksDonutCard.test.js.snap +0 -183
  51. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChart.test.js.snap +0 -302
  52. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/TasksDonutChart/__snapshots__/TasksDonutChartHelper.test.js.snap +0 -21
  53. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +0 -210
  54. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksTimeRow/Components/TimeDropDown/__snapshots__/TimeDropDown.test.js.snap +0 -85
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51404155da98c410758c31a9dcb5648d4fc6144823baf0f1e9917df7ecf72777
4
- data.tar.gz: 37a731595c5e39dd3492fc51f8405bf96806f127f8c7606efe6c327c9e7a0321
3
+ metadata.gz: 79e3003ee203359edba19b75adac7c38435b94081969faba3ad211601c559345
4
+ data.tar.gz: b3da633082735d6adf5a5d569744d3d5a6fa1d18d05568e7bc048b922205c674
5
5
  SHA512:
6
- metadata.gz: 2b5563312efffad6871f30a4adb94c5579d5208205e6733ed35fe52b409e1fdcb0b8d1526a71ffe3ac57d852742eabe015a21e5d4a5b1fe2f359b3f5a3915950
7
- data.tar.gz: 60e82330e3f9eedac8729b2c5060c1597d142081287616f4ff3d284c71b5d5d39644de6072f2c825069b9d6d972d564723700dce10baa43cdaf20504208c3910
6
+ metadata.gz: 6614edd5d7578167024f5df26bc5f950862dd9a2411a75cfd3f591b19755acbc40a1ca4321eff752800023923bb574d0095aa8c81ab4fa953e030999cf3d4547
7
+ data.tar.gz: fcdd9f699f2a55d3e27bf014f8dbee0dd0e92e3d4f6b6b6921f0a4ba9841cf2cd8aa2392d0376667fa34a85ec41b53ad6e6ff25dae9443fcee9bd625350e82f2
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
+
5
+ gem 'theforeman-rubocop', '~> 0.1.2', require: false, groups: %i[development rubocop]
@@ -6,6 +6,6 @@ attributes :id, :label, :pending, :action
6
6
  attributes :username, :started_at, :ended_at, :state, :result, :progress
7
7
 
8
8
  # A workaround for https://github.com/ruby/json/issues/957
9
- node(:duration) { |t| t.duration&.in_seconds&.to_s if t.respond_to?(:duration) }
9
+ node(:duration) { |t| t.duration&.to_f&.to_s if t.respond_to?(:duration) }
10
10
  attributes :input, :output, :humanized, :cli_example, :start_at
11
11
  node(:available_actions) { |t| { cancellable: t.execution_plan&.cancellable?, resumable: t.resumable? } }
@@ -33,7 +33,5 @@ same resource. It also optionally provides Dynflow infrastructure for using it f
33
33
  s.add_dependency "get_process_mem" # for memory polling
34
34
  s.add_dependency "sinatra" # for Dynflow web console
35
35
 
36
- s.add_development_dependency 'factory_bot_rails', '~> 4.8.0'
37
- s.add_development_dependency 'sqlite3'
38
- s.add_development_dependency 'theforeman-rubocop', '~> 0.1.0'
36
+ s.add_development_dependency "sqlite3"
39
37
  end
@@ -1,3 +1,3 @@
1
1
  module ForemanTasks
2
- VERSION = '12.1.1'.freeze
2
+ VERSION = '12.2.2'.freeze
3
3
  end
@@ -108,7 +108,7 @@ module ForemanTasks
108
108
  get :show, params: { id: task.id }, session: set_session_user
109
109
  assert_response :success
110
110
  data = JSON.parse(response.body)
111
- assert_equal task.duration.in_seconds.to_s, data['duration']
111
+ assert_equal task.duration.to_f.to_s, data['duration']
112
112
  end
113
113
  end
114
114
 
@@ -118,7 +118,7 @@ module ForemanTasks
118
118
  get :index, session: set_session_user
119
119
  assert_response :success
120
120
  data = JSON.parse(response.body)
121
- assert_equal task.duration.in_seconds.to_s, data['results'][0]['duration']
121
+ assert_equal task.duration.to_f.to_s, data['results'][0]['duration']
122
122
  end
123
123
  end
124
124
 
@@ -1,55 +1,75 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
+ import { capitalize } from 'lodash';
3
4
  import {
4
- Alert,
5
- AlertVariant,
6
5
  Grid,
7
6
  GridItem,
7
+ Text,
8
+ TextVariants,
8
9
  Title,
9
10
  } from '@patternfly/react-core';
10
11
  import { Table, Thead, Tbody, Tr, Th, Td } from '@patternfly/react-table';
11
12
  import { translate as __ } from 'foremanReact/common/I18n';
12
13
 
13
- const DependencyTable = ({ title, tasks }) => {
14
- const tableId = title.toLowerCase().replace(/\s+/g, '-');
15
- return (
16
- <div>
17
- <Title headingLevel="h4" size="md" ouiaId={`${tableId}-title`}>
18
- {title}
19
- </Title>
20
- {tasks.length === 0 ? (
21
- <p className="text-muted">{__('None')}</p>
22
- ) : (
23
- <Table aria-label={title} variant="compact" ouiaId={`${tableId}-table`}>
24
- <Thead>
25
- <Tr ouiaId={`${tableId}-table-header`}>
26
- <Th width={50}>{__('Action')}</Th>
27
- <Th width={25}>{__('State')}</Th>
28
- <Th width={25}>{__('Result')}</Th>
29
- </Tr>
30
- </Thead>
31
- <Tbody>
32
- {tasks.map(task => (
33
- <Tr key={task.id} ouiaId={`${tableId}-table-row-${task.id}`}>
34
- <Td>
35
- <a href={`/foreman_tasks/tasks/${task.id}`}>
36
- {task.humanized || task.action}
37
- </a>
38
- </Td>
39
- <Td>{task.state}</Td>
40
- <Td>{task.result}</Td>
14
+ const DependencyTable = ({ title, tasks, ouiaSectionId }) => (
15
+ <React.Fragment>
16
+ <Title headingLevel="h3" size="lg" ouiaId={`${ouiaSectionId}-title`}>
17
+ {title}
18
+ </Title>
19
+ <Grid hasGutter>
20
+ <GridItem span={12} xl={8}>
21
+ {tasks.length === 0 ? (
22
+ <Text component={TextVariants.small} ouiaId={`${ouiaSectionId}-none`}>
23
+ {__('None')}
24
+ </Text>
25
+ ) : (
26
+ <Table
27
+ aria-label={title}
28
+ variant="compact"
29
+ ouiaId={`${ouiaSectionId}-table`}
30
+ >
31
+ <Thead>
32
+ <Tr ouiaId={`${ouiaSectionId}-table-header`}>
33
+ <Th>{__('Name')}</Th>
34
+ <Th>{__('State')}</Th>
35
+ <Th>{__('Result')}</Th>
41
36
  </Tr>
42
- ))}
43
- </Tbody>
44
- </Table>
45
- )}
46
- </div>
47
- );
48
- };
37
+ </Thead>
38
+ <Tbody>
39
+ {tasks.map(task => (
40
+ <Tr
41
+ key={task.id}
42
+ ouiaId={`${ouiaSectionId}-table-row-${task.id}`}
43
+ >
44
+ <Td dataLabel={__('Name')}>
45
+ <Text
46
+ component={TextVariants.a}
47
+ href={`/foreman_tasks/tasks/${task.id}`}
48
+ ouiaId={`${ouiaSectionId}-task-link-${task.id}`}
49
+ >
50
+ {task.humanized || task.action}
51
+ </Text>
52
+ </Td>
53
+ <Td dataLabel={__('State')}>
54
+ {capitalize(String(task.state || ''))}
55
+ </Td>
56
+ <Td dataLabel={__('Result')}>
57
+ {capitalize(String(task.result || ''))}
58
+ </Td>
59
+ </Tr>
60
+ ))}
61
+ </Tbody>
62
+ </Table>
63
+ )}
64
+ </GridItem>
65
+ </Grid>
66
+ </React.Fragment>
67
+ );
49
68
 
50
69
  DependencyTable.propTypes = {
51
70
  title: PropTypes.string.isRequired,
52
71
  tasks: PropTypes.array,
72
+ ouiaSectionId: PropTypes.string.isRequired,
53
73
  };
54
74
 
55
75
  DependencyTable.defaultProps = {
@@ -57,27 +77,18 @@ DependencyTable.defaultProps = {
57
77
  };
58
78
 
59
79
  const Dependencies = ({ dependsOn, blocks }) => (
60
- <div>
61
- <Alert
62
- variant={AlertVariant.info}
63
- isInline
64
- title={__('Task dependencies')}
65
- ouiaId="task-dependencies-info-alert"
66
- >
67
- {__(
68
- 'This task may have dependencies on other tasks or may be blocking other tasks from executing. Dependencies are established through task chaining relationships.'
69
- )}
70
- </Alert>
71
- <br />
72
- <Grid hasGutter>
73
- <GridItem span={6}>
74
- <DependencyTable title={__('Depends on')} tasks={dependsOn} />
75
- </GridItem>
76
- <GridItem span={6}>
77
- <DependencyTable title={__('Blocks')} tasks={blocks} />
78
- </GridItem>
79
- </Grid>
80
- </div>
80
+ <React.Fragment>
81
+ <DependencyTable
82
+ title={__('Task depends on')}
83
+ tasks={dependsOn}
84
+ ouiaSectionId="task-dependencies-depends-on"
85
+ />
86
+ <DependencyTable
87
+ title={__('Task blocks')}
88
+ tasks={blocks}
89
+ ouiaSectionId="task-dependencies-blocks"
90
+ />
91
+ </React.Fragment>
81
92
  );
82
93
 
83
94
  Dependencies.propTypes = {
@@ -1,20 +1,40 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Alert } from 'patternfly-react';
3
+ import { Alert } from '@patternfly/react-core';
4
4
  import { translate as __ } from 'foremanReact/common/I18n';
5
5
 
6
6
  const Errors = ({ ...props }) => {
7
7
  const { failedSteps, executionPlan } = props;
8
8
  if (!executionPlan)
9
9
  return (
10
- <Alert type="error">{__('Execution plan data not available ')}</Alert>
10
+ <Alert
11
+ variant="danger"
12
+ isInline
13
+ ouiaId="task-errors-plan-missing"
14
+ title={__('Execution plan unavailable')}
15
+ >
16
+ {__('Execution plan data not available ')}
17
+ </Alert>
11
18
  );
12
19
  if (!failedSteps.length)
13
- return <Alert type="success">{__('No errors')}</Alert>;
20
+ return (
21
+ <Alert
22
+ variant="success"
23
+ isInline
24
+ ouiaId="task-errors-none"
25
+ title={__('No errors')}
26
+ />
27
+ );
14
28
  return (
15
29
  <div>
16
30
  {failedSteps.map((step, i) => (
17
- <Alert type="error" key={i}>
31
+ <Alert
32
+ variant="danger"
33
+ isInline
34
+ key={i}
35
+ ouiaId={`task-error-${i}`}
36
+ title={__('Step error')}
37
+ >
18
38
  <span>{__('Action')}:</span>
19
39
  <span>
20
40
  <pre>{step.action_class}</pre>
@@ -37,7 +57,7 @@ const Errors = ({ ...props }) => {
37
57
  </span>
38
58
  <span>{__('Backtrace')}:</span>
39
59
  <span>
40
- <pre>{step.error.backtrace.join('\n')}</pre>
60
+ <pre>{(step.error.backtrace || []).join('\n')}</pre>
41
61
  </span>
42
62
  </React.Fragment>
43
63
  )}
@@ -1,56 +1,183 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Alert, Card, Row, Col } from 'patternfly-react';
4
- import { translate as __ } from 'foremanReact/common/I18n';
3
+ import {
4
+ EmptyState,
5
+ EmptyStateBody,
6
+ EmptyStateHeader,
7
+ EmptyStateIcon,
8
+ EmptyStateVariant,
9
+ Flex,
10
+ FlexItem,
11
+ Grid,
12
+ GridItem,
13
+ Icon,
14
+ Text,
15
+ TextContent,
16
+ TextVariants,
17
+ Title,
18
+ } from '@patternfly/react-core';
19
+ import { Table, Tbody, Tr, Td } from '@patternfly/react-table';
20
+ import { LockIcon, LockOpenIcon } from '@patternfly/react-icons';
21
+ import { translate as __, sprintf } from 'foremanReact/common/I18n';
5
22
 
6
- const ConditionalLink = ({ children, link }) =>
7
- link ? <a href={link}>{children}</a> : children;
23
+ const LocksSection = ({
24
+ title,
25
+ description,
26
+ items,
27
+ RowIcon,
28
+ ouiaSectionId,
29
+ }) => (
30
+ <Flex direction={{ default: 'column' }}>
31
+ <FlexItem spacer={{ default: 'spacerSm' }}>
32
+ <Flex
33
+ alignItems={{ default: 'alignItemsCenter' }}
34
+ spaceItems={{ default: 'spaceItemsSm' }}
35
+ >
36
+ <FlexItem>
37
+ <Title
38
+ headingLevel="h3"
39
+ size="lg"
40
+ style={{ margin: '0' }}
41
+ ouiaId={`${ouiaSectionId}-title`}
42
+ >
43
+ {title}
44
+ </Title>
45
+ </FlexItem>
46
+ <FlexItem>
47
+ <RowIcon aria-hidden />
48
+ </FlexItem>
49
+ </Flex>
50
+ </FlexItem>
51
+ <FlexItem>
52
+ <TextContent>
53
+ <Text
54
+ component={TextVariants.p}
55
+ ouiaId={`${ouiaSectionId}-description`}
56
+ >
57
+ {description}
58
+ </Text>
59
+ </TextContent>
60
+ </FlexItem>
61
+ <FlexItem>
62
+ <Grid>
63
+ <GridItem span={5}>
64
+ <Table
65
+ aria-label={title}
66
+ variant="compact"
67
+ ouiaId={`${ouiaSectionId}-table`}
68
+ >
69
+ <Tbody>
70
+ {items.map((lock, index) => (
71
+ <Tr
72
+ key={`${lock.resource_type}-${lock.resource_id}-${index}`}
73
+ ouiaId={`${ouiaSectionId}-row-${index}`}
74
+ >
75
+ <Td>
76
+ <Flex
77
+ alignItems={{ default: 'alignItemsCenter' }}
78
+ spaceItems={{ default: 'spaceItemsSm' }}
79
+ flexWrap={{ default: 'nowrap' }}
80
+ >
81
+ <FlexItem>
82
+ <Icon size="sm">
83
+ <RowIcon />
84
+ </Icon>
85
+ </FlexItem>
86
+ <FlexItem>
87
+ {lock.link ? (
88
+ <a
89
+ href={lock.link}
90
+ data-ouia-component-id={`${ouiaSectionId}-resource-type-link-${index}`}
91
+ >
92
+ {lock.resource_type}
93
+ </a>
94
+ ) : (
95
+ lock.resource_type
96
+ )}
97
+ </FlexItem>
98
+ </Flex>
99
+ </Td>
100
+ <Td>{sprintf(__('id: %s'), String(lock.resource_id))}</Td>
101
+ </Tr>
102
+ ))}
103
+ </Tbody>
104
+ </Table>
105
+ </GridItem>
106
+ </Grid>
107
+ </FlexItem>
108
+ </Flex>
109
+ );
8
110
 
9
- ConditionalLink.propTypes = {
10
- children: PropTypes.node.isRequired,
11
- link: PropTypes.string,
111
+ LocksSection.propTypes = {
112
+ title: PropTypes.string.isRequired,
113
+ description: PropTypes.string.isRequired,
114
+ items: PropTypes.array.isRequired,
115
+ RowIcon: PropTypes.elementType.isRequired,
116
+ ouiaSectionId: PropTypes.string.isRequired,
12
117
  };
13
118
 
14
- ConditionalLink.defaultProps = {
15
- link: null,
16
- };
119
+ const Locks = ({ locks }) => {
120
+ const nonExclusive = locks.filter(l => !l.exclusive);
121
+ const exclusive = locks.filter(l => l.exclusive);
17
122
 
18
- const Locks = ({ locks }) => (
19
- <div>
20
- <Alert type="info">
21
- {__(
22
- 'You can find resource locks on this page. Exclusive lock marked with locked icon means that no other task can use locked resource while this task is running. Non-exclusive lock marked with unlocked icon means other tasks can access the resource freely, it is only used to indicate the relation of this task with the resource'
123
+ if (locks.length === 0) {
124
+ return (
125
+ <EmptyState variant={EmptyStateVariant.lg}>
126
+ <EmptyStateHeader
127
+ headingLevel="h3"
128
+ titleText={__('No resources')}
129
+ icon={<EmptyStateIcon icon={LockOpenIcon} />}
130
+ />
131
+ <EmptyStateBody>
132
+ {__(
133
+ 'No resources currently associated with this task. Locking resources prevents conflicting tasks from running simultaneously. Other tasks must wait until this process completes.'
134
+ )}
135
+ </EmptyStateBody>
136
+ </EmptyState>
137
+ );
138
+ }
139
+
140
+ return (
141
+ <Flex
142
+ direction={{ default: 'column' }}
143
+ gap={{ default: 'gap2xl' }}
144
+ data-ouia-component-id="task-locks-populated"
145
+ >
146
+ {nonExclusive.length > 0 && (
147
+ <LocksSection
148
+ title={__('Non-exclusive resources')}
149
+ description={__(
150
+ "Other tasks can access the resource simultaneously. This lock tracks the task's relationship to the resource without blocking others."
151
+ )}
152
+ items={nonExclusive}
153
+ RowIcon={LockOpenIcon}
154
+ ouiaSectionId="task-locks-non-exclusive"
155
+ />
23
156
  )}
24
- </Alert>
25
- <Card.Grid>
26
- <Row>
27
- {locks.map((lock, key) => (
28
- <Col xs={6} sm={4} md={4} key={key}>
29
- <ConditionalLink link={lock.link}>
30
- <Card className="card-pf-aggregate-status" accented>
31
- <Card.Title>
32
- <span
33
- className={`fa ${
34
- lock.exclusive ? 'fa-lock' : 'fa-unlock-alt'
35
- }`}
36
- />
37
- {lock.resource_type}
38
- </Card.Title>
39
- <Card.Body>
40
- {`id:${lock.resource_id}`}
41
- <br />
42
- </Card.Body>
43
- </Card>
44
- </ConditionalLink>
45
- </Col>
46
- ))}
47
- </Row>
48
- </Card.Grid>
49
- </div>
50
- );
157
+ {exclusive.length > 0 && (
158
+ <LocksSection
159
+ title={__('Exclusive resources')}
160
+ description={__(
161
+ 'Only this task can access the resource. Other tasks must wait until this process completes.'
162
+ )}
163
+ items={exclusive}
164
+ RowIcon={LockIcon}
165
+ ouiaSectionId="task-locks-exclusive"
166
+ />
167
+ )}
168
+ </Flex>
169
+ );
170
+ };
171
+
172
+ const lockShape = PropTypes.shape({
173
+ exclusive: PropTypes.bool,
174
+ resource_type: PropTypes.string,
175
+ resource_id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
176
+ link: PropTypes.string,
177
+ });
51
178
 
52
179
  Locks.propTypes = {
53
- locks: PropTypes.array,
180
+ locks: PropTypes.arrayOf(lockShape),
54
181
  };
55
182
 
56
183
  Locks.defaultProps = {
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Alert, Button } from 'patternfly-react';
4
- import { translate as __ } from 'foremanReact/common/I18n';
3
+ import { Alert, AlertVariant, Button } from '@patternfly/react-core';
4
+ import { translate as __, sprintf } from 'foremanReact/common/I18n';
5
5
 
6
6
  const RunningSteps = ({
7
7
  runningSteps,
@@ -14,11 +14,19 @@ const RunningSteps = ({
14
14
  return (
15
15
  <div>
16
16
  {runningSteps.map((step, i) => (
17
- <Alert type="warning" key={i}>
17
+ <Alert
18
+ variant={AlertVariant.warning}
19
+ isInline
20
+ key={step.id || i}
21
+ ouiaId={`running-step-${i}`}
22
+ title={sprintf(__('Running step %s'), i + 1)}
23
+ >
18
24
  {step.cancellable && (
19
25
  <p>
20
26
  <Button
21
- bsSize="small"
27
+ variant="danger"
28
+ size="sm"
29
+ ouiaId={`running-step-cancel-button-${i}`}
22
30
  onClick={() => {
23
31
  if (!taskReload) {
24
32
  taskReloadStart(id);