foreman_patch 1.1.6.alpha4 → 1.2.0.alpha1
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.
- checksums.yaml +4 -4
- data/app/controllers/foreman_patch/api/v2/invocations_controller.rb +1 -23
- data/app/controllers/foreman_patch/concerns/hosts_controller_extensions.rb +41 -35
- data/app/lib/actions/foreman_patch/cycle/complete.rb +41 -0
- data/app/lib/actions/foreman_patch/cycle/create.rb +1 -5
- data/app/lib/actions/foreman_patch/cycle/initiate.rb +1 -5
- data/app/lib/actions/foreman_patch/cycle/plan.rb +66 -0
- data/app/lib/actions/foreman_patch/invocation/action.rb +29 -23
- data/app/lib/actions/foreman_patch/invocation/patch.rb +8 -16
- data/app/lib/actions/foreman_patch/invocation/wait_for_host.rb +29 -4
- data/app/lib/actions/foreman_patch/round/patch.rb +1 -5
- data/app/lib/actions/foreman_patch/round/plan.rb +33 -0
- data/app/lib/actions/foreman_patch/window/plan.rb +43 -0
- data/app/lib/actions/foreman_patch/window/publish.rb +1 -5
- data/app/lib/actions/foreman_patch/window/resolve_hosts.rb +1 -5
- data/app/models/foreman_patch/invocation.rb +4 -4
- data/app/models/foreman_patch/round.rb +23 -4
- data/app/models/setting/patching.rb +57 -0
- data/app/services/foreman_patch/ticket/api.rb +1 -2
- data/app/views/foreman_patch/api/v2/invocations/base.json.rabl +1 -1
- data/app/views/foreman_patch/api/v2/invocations/phase.json.rabl +7 -0
- data/app/views/foreman_patch/api/v2/invocations/show.json.rabl +2 -2
- data/app/views/foreman_patch/api/v2/rounds/base.json.rabl +1 -1
- data/app/views/foreman_patch/api/v2/rounds/status.json.rabl +8 -2
- data/app/views/foreman_patch/groups/index.html.erb +1 -1
- data/app/views/foreman_patch/layouts/react.html.erb +1 -1
- data/app/views/templates/ensure_services.erb +4 -7
- data/config/api_routes.rb +24 -28
- data/config/routes/mount_engine.rb +3 -0
- data/config/routes/overrides.rb +10 -0
- data/config/routes.rb +29 -40
- data/db/seeds.d/100-assign_features_with_templates.rb +12 -6
- data/lib/foreman_patch/engine.rb +46 -11
- data/lib/foreman_patch/plugin.rb +47 -0
- data/lib/foreman_patch/version.rb +1 -1
- data/lib/foreman_patch.rb +2 -3
- data/locale/en/foreman_patch.po +1 -1
- data/locale/foreman_patch.pot +1 -1
- data/locale/gemspec.rb +1 -1
- data/package.json +9 -20
- data/public/assets/foreman_patch/cycle_plans-e5667e178ba389908f5c815b24ec0ea77c340849d56bc39c5ce72bb626bd446a.scss.gz +0 -0
- data/public/assets/foreman_patch/cycle_plans-ff3d252119622a68828ff70f4a97328303963002237dbf850e92d6a706e93667.scss.gz +0 -0
- data/public/assets/foreman_patch/foreman_patch-be2e2ba89548f4a490612e8a6cd1cdebc0473be89f8023a3df7612f05a75d301.css +1 -0
- data/public/assets/foreman_patch/foreman_patch-be2e2ba89548f4a490612e8a6cd1cdebc0473be89f8023a3df7612f05a75d301.css.gz +0 -0
- data/public/assets/foreman_patch/foreman_patch-ce5805a60c0d5f896f557ff5246e5a09172043004c850b39bea54e618df1c485.css +1 -0
- data/public/assets/foreman_patch/foreman_patch-ce5805a60c0d5f896f557ff5246e5a09172043004c850b39bea54e618df1c485.css.gz +0 -0
- data/public/assets/foreman_patch/foreman_patch.json +1 -1
- data/public/assets/foreman_patch/plan_edit_windows-9ba20f84f3ecf2c4eb903acd57d30ee3e16f023a79db30bc614aa22f26442ce3.js +1 -0
- data/public/assets/foreman_patch/plan_edit_windows-9ba20f84f3ecf2c4eb903acd57d30ee3e16f023a79db30bc614aa22f26442ce3.js.gz +0 -0
- data/public/assets/foreman_patch/plan_edit_windows-e656ba411642a7f983b51958ab30ac49c056322d19295a603cff4d5e6c71c8ed.js +1 -0
- data/public/assets/foreman_patch/plan_edit_windows-e656ba411642a7f983b51958ab30ac49c056322d19295a603cff4d5e6c71c8ed.js.gz +0 -0
- data/public/webpack/foreman_patch/bundle-e45c4bb530e40506f2da.css.gz +0 -0
- data/public/webpack/foreman_patch/bundle-e45c4bb530e40506f2da.js +6 -0
- data/public/webpack/foreman_patch/bundle-e45c4bb530e40506f2da.js.gz +0 -0
- data/public/webpack/foreman_patch/bundle-e45c4bb530e40506f2da.js.map +1 -0
- data/public/webpack/foreman_patch/bundle-e45c4bb530e40506f2da.js.map.gz +0 -0
- data/public/webpack/foreman_patch/{foreman_patch.css → foreman_patch-4a4e1a59d74af09c4b8b.css} +1 -1
- data/public/webpack/foreman_patch/foreman_patch-4a4e1a59d74af09c4b8b.css.gz +0 -0
- data/public/webpack/foreman_patch/foreman_patch-4a4e1a59d74af09c4b8b.js +6 -0
- data/public/webpack/foreman_patch/foreman_patch-4a4e1a59d74af09c4b8b.js.gz +0 -0
- data/public/webpack/foreman_patch/foreman_patch-4a4e1a59d74af09c4b8b.js.map +1 -0
- data/public/webpack/foreman_patch/foreman_patch-4a4e1a59d74af09c4b8b.js.map.gz +0 -0
- data/public/webpack/foreman_patch/manifest.json +14 -13
- data/public/webpack/foreman_patch/manifest.json.gz +0 -0
- data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js +2 -0
- data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.gz +0 -0
- data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.map +1 -0
- data/public/webpack/foreman_patch/vendor-4b77c91f1e9103179596.js.map.gz +0 -0
- data/webpack/components/Invocation/Invocation.js +47 -0
- data/webpack/{src/Components → components}/Invocation/InvocationSelectors.js +3 -0
- data/webpack/components/Invocation/index.js +36 -0
- data/webpack/components/Invocations/Invocations.js +16 -48
- data/webpack/components/Invocations/InvocationsPage.js +1 -24
- data/webpack/components/Invocations/InvocationsSelectors.js +1 -1
- data/webpack/components/Invocations/components/{InvocationActions.js → InvocationItem.js} +16 -4
- data/webpack/components/Invocations/index.js +12 -95
- data/webpack/components/RoundProgress/AggregateStatus.js +5 -6
- data/webpack/components/RoundProgress/RoundProgress.js +6 -7
- data/webpack/components/RoundProgress/RoundProgressSelectors.js +2 -3
- data/webpack/components/common/Calendar/Calendar.js +4 -5
- data/webpack/components/common/Terminal/OutputLine.js +26 -0
- data/webpack/components/common/Terminal/Terminal.js +115 -0
- data/webpack/components/common/Terminal/Terminal.scss +47 -0
- data/webpack/index.js +0 -3
- metadata +92 -49
- data/app/controllers/foreman_patch/react_controller.rb +0 -12
- data/app/lib/actions/foreman_patch/invocation/process_logging.rb +0 -44
- data/app/lib/actions/foreman_patch/invocation/proxy_action.rb +0 -52
- data/app/models/foreman_patch/event.rb +0 -13
- data/app/views/foreman_patch/api/v2/invocations/event.json.rabl +0 -3
- data/db/migrate/20230706092400_nullify_group_on_delete.rb +0 -11
- data/db/migrate/20230707102800_create_invocation_events.rb +0 -16
- data/lib/foreman_patch/register.rb +0 -119
- data/public/assets/foreman_patch/calendar-b5391efda77239c4a4894e9f03f34610f6c8e2e748b2a147febfea814b857cdc.scss.gz +0 -0
- data/public/assets/foreman_patch/foreman_patch-410cf04bf9b09e65fee034cc3f2dd74acf2524abf881c6d6e559d5c62a615faf.css +0 -11
- data/public/assets/foreman_patch/foreman_patch-410cf04bf9b09e65fee034cc3f2dd74acf2524abf881c6d6e559d5c62a615faf.css.gz +0 -0
- data/public/assets/foreman_patch/foreman_patch-84845e54f06d3a11189828e656432d587c7312358cdf694753da7b78b7dabcee.css +0 -11
- data/public/assets/foreman_patch/foreman_patch-84845e54f06d3a11189828e656432d587c7312358cdf694753da7b78b7dabcee.css.gz +0 -0
- data/public/assets/foreman_patch/foreman_patch-a76c5fd10a5795e97c5ae4c222bfdf4ab88da49d6a7659175dba79f8fc62ab47.css +0 -82
- data/public/assets/foreman_patch/foreman_patch-a76c5fd10a5795e97c5ae4c222bfdf4ab88da49d6a7659175dba79f8fc62ab47.css.gz +0 -0
- data/public/assets/foreman_patch/plan_edit_windows-2eb04c7e83fa62797b0a14364d3ff5b3c4336983603fdc5a276b5464eeba7e60.js +0 -9
- data/public/assets/foreman_patch/plan_edit_windows-2eb04c7e83fa62797b0a14364d3ff5b3c4336983603fdc5a276b5464eeba7e60.js.gz +0 -0
- data/public/assets/foreman_patch/plan_edit_windows-ddedd3e70fb6ef761f636be2b7b35286e86d68e126bfc37294f9365a5171a928.js +0 -9
- data/public/assets/foreman_patch/plan_edit_windows-ddedd3e70fb6ef761f636be2b7b35286e86d68e126bfc37294f9365a5171a928.js.gz +0 -0
- data/public/webpack/foreman_patch/bundle.js +0 -34173
- data/public/webpack/foreman_patch/foreman_patch.js +0 -34366
- data/public/webpack/foreman_patch/foreman_patch:global.css +0 -1
- data/public/webpack/foreman_patch/foreman_patch:global.js +0 -32098
- data/public/webpack/foreman_patch/vendor.js +0 -5201
- data/webpack/components/common/Calendar/Calendar.css +0 -76
- data/webpack/components/common/Table/index.js +0 -28
- data/webpack/global_index.js +0 -16
- data/webpack/src/Components/Invocation/Invocation.js +0 -67
- data/webpack/src/Components/Invocation/InvocationLogFooter.js +0 -30
- data/webpack/src/Components/Invocation/InvocationLogToolbar.js +0 -80
- data/webpack/src/Components/Invocation/index.js +0 -62
- data/webpack/src/Components/InvocationStatus.js +0 -50
- data/webpack/src/Components/Loading.js +0 -51
- data/webpack/src/Extends/index.js +0 -15
- data/webpack/src/Router/routes.js +0 -5
- data/webpack/src/reducers.js +0 -7
- /data/public/webpack/foreman_patch/{bundle.css → bundle-e45c4bb530e40506f2da.css} +0 -0
- /data/webpack/{src/Components → components}/Invocation/InvocationActions.js +0 -0
- /data/webpack/{src/Components → components}/Invocation/InvocationConsts.js +0 -0
- /data/webpack/components/Invocations/{Invocations.css → InvocationsPage.scss} +0 -0
- /data/{public/assets/foreman_patch/calendar-b5391efda77239c4a4894e9f03f34610f6c8e2e748b2a147febfea814b857cdc.scss → webpack/components/common/Calendar/Calendar.scss} +0 -0
|
Binary file
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
|
4
|
+
import { Tabs, Tab, TabTitleText, LoadingState } from 'patternfly-react';
|
|
5
|
+
import { STATUS } from 'foremanReact/constants';
|
|
6
|
+
|
|
7
|
+
import Terminal from '../common/Terminal/Terminal';
|
|
8
|
+
|
|
9
|
+
const Invocation = ({ invocation, status }) => {
|
|
10
|
+
if (status === STATUS.ERROR) {
|
|
11
|
+
return (
|
|
12
|
+
<Alert type="error">
|
|
13
|
+
{__(
|
|
14
|
+
'There was an error loading the invocation, try refreshing the page.'
|
|
15
|
+
)}
|
|
16
|
+
</Alert>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const [activeTabKey, setActiveTabKey] = useState(0);
|
|
21
|
+
|
|
22
|
+
const handleTabClick = (event, tabIndex) => {
|
|
23
|
+
setActiveTabKey(tabIndex);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<LoadingState loading={status == STATUS.PENDING}>
|
|
28
|
+
<Tabs activeKey={activeTabKey} onSelect={handleTabClick}>
|
|
29
|
+
<Tab eventKey={0} title={<TabTitleText>Overview</TabTitleText>}>
|
|
30
|
+
TODO: status
|
|
31
|
+
</Tab>
|
|
32
|
+
{invocation.phases.map((phase, index) => (
|
|
33
|
+
<Tab event={index + 1} title={<TabTitleText>{phase.humanized_name}</TabTitleText>}>
|
|
34
|
+
<Terminal key={phase.label} linesets={phase.live_output}/>
|
|
35
|
+
</Tab>
|
|
36
|
+
))}
|
|
37
|
+
</Tabs>
|
|
38
|
+
</LoadingState>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
Invocation.propTypes = {
|
|
43
|
+
status: PropTypes.string.isRequired,
|
|
44
|
+
invocation: PropTypes.object.isRequired,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default Invocation;
|
|
@@ -7,5 +7,8 @@ import { INVOCATION } from './InvocationConsts';
|
|
|
7
7
|
export const selectInvocation = state =>
|
|
8
8
|
selectAPIResponse(state, INVOCATION) || {};
|
|
9
9
|
|
|
10
|
+
export const selectState = state =>
|
|
11
|
+
selectAPIResponse(state, INVOCATION).state;
|
|
12
|
+
|
|
10
13
|
export const selectStatus = state =>
|
|
11
14
|
selectAPIStatus(state, INVOCATION);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React { useEffect, useState } from 'react';
|
|
2
|
+
import { useSelector, useDispatch } from 'react-redux';
|
|
3
|
+
import { stopInterval } from 'foremanReact/redux/middlewares/IntervalMiddleware';
|
|
4
|
+
import Invocation from './Invocation';
|
|
5
|
+
import {
|
|
6
|
+
selectInvocation,
|
|
7
|
+
selectState,
|
|
8
|
+
selectStatus,
|
|
9
|
+
} from './InvocationSelectors';
|
|
10
|
+
import { getData } from './InvocationActions';
|
|
11
|
+
import { INVOCATION } from './InvocationsConsts';
|
|
12
|
+
|
|
13
|
+
const WrappedInvocation = () => {
|
|
14
|
+
const dispatch = useDispatch();
|
|
15
|
+
const state = useSelector(selectState);
|
|
16
|
+
const invocation = useSelector(selectInvocation);
|
|
17
|
+
const status = useSelector(selectStatus);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
dispatch(getData());
|
|
21
|
+
|
|
22
|
+
return () => {
|
|
23
|
+
dispatch(stopInterval(INVOCATION));
|
|
24
|
+
};
|
|
25
|
+
}, [dispatch]);
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (state === 'stopped') {
|
|
29
|
+
dispatch(stopInterval(INVOCATION));
|
|
30
|
+
}
|
|
31
|
+
}, [state, dispatch]);
|
|
32
|
+
|
|
33
|
+
return <Invocation invocation={invocation} status={status}/>
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default WrappedInvocation;
|
|
@@ -2,13 +2,11 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
4
4
|
import { LoadingState, Alert } from 'patternfly-react';
|
|
5
|
-
import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
6
5
|
import { STATUS } from 'foremanReact/constants';
|
|
7
6
|
|
|
8
|
-
import
|
|
9
|
-
import InvocationActions from './components/InvocationActions';
|
|
7
|
+
import InvocationItem from './components/InvocationItem';
|
|
10
8
|
|
|
11
|
-
const Invocations = ({ status, items
|
|
9
|
+
const Invocations = ({ status, items }) => {
|
|
12
10
|
if (status === STATUS.ERROR) {
|
|
13
11
|
return (
|
|
14
12
|
<Alert type="error">
|
|
@@ -20,51 +18,26 @@ const Invocations = ({ status, items, selectAll, areAllSelected, onSelect, isSel
|
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
const rows = items.length ? (
|
|
23
|
-
items.map(
|
|
24
|
-
<Tr key={`invocation-${item.id}`}>
|
|
25
|
-
<Td
|
|
26
|
-
select={{
|
|
27
|
-
rowIndex,
|
|
28
|
-
onSelect: (_event, isSelecting) => onSelect(item, rowIndex, isSelecting),
|
|
29
|
-
isSelected: isSelected(item)
|
|
30
|
-
}}
|
|
31
|
-
/>
|
|
32
|
-
<Td className="invocation_name">
|
|
33
|
-
<a href={`/foreman_patch/invocations/${item.id}`}>{item.name}</a>
|
|
34
|
-
</Td>
|
|
35
|
-
<Td>
|
|
36
|
-
<InvocationStatus status={item.status}/>
|
|
37
|
-
</Td>
|
|
38
|
-
<Td>
|
|
39
|
-
<InvocationActions {...item}/>
|
|
40
|
-
</Td>
|
|
41
|
-
</Tr>
|
|
42
|
-
))
|
|
21
|
+
items.map(item => (<InvocationItem {...item} />))
|
|
43
22
|
) : (
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
</
|
|
23
|
+
<tr>
|
|
24
|
+
<td colSpan="3">{__('No hosts found.')}</td>
|
|
25
|
+
</tr>
|
|
47
26
|
);
|
|
48
27
|
|
|
49
28
|
return (
|
|
50
29
|
<LoadingState loading={!items.length && status === STATUS.PENDING}>
|
|
51
30
|
<div>
|
|
52
|
-
<
|
|
53
|
-
<
|
|
54
|
-
<
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
<Th className="col-md-2">{__('Status')}</Th>
|
|
63
|
-
<Th className="col-md-1">{__('Actions')}</Th>
|
|
64
|
-
</Tr>
|
|
65
|
-
</Thead>
|
|
66
|
-
<Tbody>{rows}</Tbody>
|
|
67
|
-
</TableComposable>
|
|
31
|
+
<table className="table table-bordered table-striped table-hover">
|
|
32
|
+
<thead>
|
|
33
|
+
<tr>
|
|
34
|
+
<th>{__('Host')}</th>
|
|
35
|
+
<th className="col-md-2">{__('Status')}</th>
|
|
36
|
+
<th className="col-md-1">{__('Actions')}</th>
|
|
37
|
+
</tr>
|
|
38
|
+
</thead>
|
|
39
|
+
<tbody>{rows}</tbody>
|
|
40
|
+
</table>
|
|
68
41
|
</div>
|
|
69
42
|
</LoadingState>
|
|
70
43
|
);
|
|
@@ -73,15 +46,10 @@ const Invocations = ({ status, items, selectAll, areAllSelected, onSelect, isSel
|
|
|
73
46
|
Invocations.propTypes = {
|
|
74
47
|
status: PropTypes.string,
|
|
75
48
|
items: PropTypes.array.isRequired,
|
|
76
|
-
selectAll: PropTypes.func.isRequired,
|
|
77
|
-
areAllSelected: PropTypes.bool,
|
|
78
|
-
onSelect: PropTypes.func.isRequired,
|
|
79
|
-
isSelected: PropTypes.func.isRequired,
|
|
80
49
|
};
|
|
81
50
|
|
|
82
51
|
Invocations.defaultProps = {
|
|
83
52
|
status: null,
|
|
84
|
-
areAllSelected: false,
|
|
85
53
|
};
|
|
86
54
|
|
|
87
55
|
export default Invocations;
|
|
@@ -4,7 +4,6 @@ import { Grid } from 'patternfly-react';
|
|
|
4
4
|
|
|
5
5
|
import SearchBar from 'foremanReact/components/SearchBar';
|
|
6
6
|
import Pagination from 'foremanReact/components/Pagination/PaginationWrapper';
|
|
7
|
-
import { ActionButtons } from 'foremanReact/components/common/ActionButtons/ActionButtons';
|
|
8
7
|
import { getControllerSearchProps } from 'foremanReact/constants';
|
|
9
8
|
|
|
10
9
|
import Invocations from './Invocations';
|
|
@@ -18,11 +17,6 @@ const InvocationsPage = ({
|
|
|
18
17
|
pagination,
|
|
19
18
|
handleSearch,
|
|
20
19
|
handlePagination,
|
|
21
|
-
selectAll,
|
|
22
|
-
areAllSelected,
|
|
23
|
-
onSelect,
|
|
24
|
-
isSelected,
|
|
25
|
-
actions
|
|
26
20
|
}) => (
|
|
27
21
|
<div id="patch_invocations">
|
|
28
22
|
<Grid.Row>
|
|
@@ -41,19 +35,9 @@ const InvocationsPage = ({
|
|
|
41
35
|
}}
|
|
42
36
|
/>
|
|
43
37
|
</Grid.Col>
|
|
44
|
-
<Grid.Col md={6} className="title_action">
|
|
45
|
-
<ActionButtons buttons={[]} />
|
|
46
|
-
</Grid.Col>
|
|
47
38
|
</Grid.Row>
|
|
48
39
|
<br />
|
|
49
|
-
<Invocations
|
|
50
|
-
status={status}
|
|
51
|
-
items={items}
|
|
52
|
-
selectAll={selectAll}
|
|
53
|
-
areAllSelected={areAllSelected}
|
|
54
|
-
onSelect={onSelect}
|
|
55
|
-
isSelected={isSelected}
|
|
56
|
-
/>
|
|
40
|
+
<Invocations status={status} items={items} />
|
|
57
41
|
<Pagination
|
|
58
42
|
viewType="table"
|
|
59
43
|
itemCount={total}
|
|
@@ -73,17 +57,10 @@ InvocationsPage.propTypes = {
|
|
|
73
57
|
pagination: PropTypes.object.isRequired,
|
|
74
58
|
handleSearch: PropTypes.func.isRequired,
|
|
75
59
|
handlePagination: PropTypes.func.isRequired,
|
|
76
|
-
selectAll: PropTypes.func.isRequired,
|
|
77
|
-
areAllSelected: PropTypes.bool,
|
|
78
|
-
onSelect: PropTypes.func.isRequired,
|
|
79
|
-
isSelected: PropTypes.func.isRequired,
|
|
80
|
-
actions: PropTypes.array,
|
|
81
60
|
};
|
|
82
61
|
|
|
83
62
|
InvocationsPage.defaultProps = {
|
|
84
63
|
status: null,
|
|
85
|
-
areAllSelected: false,
|
|
86
|
-
actions: []
|
|
87
64
|
};
|
|
88
65
|
|
|
89
66
|
export default InvocationsPage;
|
|
@@ -12,7 +12,7 @@ export const selectTotal = state =>
|
|
|
12
12
|
selectAPIResponse(state, INVOCATIONS).total || 0;
|
|
13
13
|
|
|
14
14
|
export const selectAutoRefresh = state =>
|
|
15
|
-
selectItems(state).some(item => (item.
|
|
15
|
+
selectItems(state).some(item => (item.result === 'pending'));
|
|
16
16
|
|
|
17
17
|
export const selectStatus = state => selectAPIStatus(state, INVOCATIONS);
|
|
18
18
|
|
|
@@ -3,7 +3,9 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { ActionButtons } from 'foremanReact/components/common/ActionButtons/ActionButtons';
|
|
4
4
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import InvocationStatus from './InvocationStatus';
|
|
7
|
+
|
|
8
|
+
const InvocationItem = ({ id, name, status, task_id, host_id }) => {
|
|
7
9
|
|
|
8
10
|
const actions = [
|
|
9
11
|
{
|
|
@@ -39,11 +41,21 @@ const InvocationActions = ({ id, name, status, task_id, host_id }) => {
|
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
return (
|
|
42
|
-
<
|
|
44
|
+
<tr id={`invocation-${id}`}>
|
|
45
|
+
<td className="invocation_name">
|
|
46
|
+
<a href={`/foreman_patch/invocations/${id}`}>{name}</a>
|
|
47
|
+
</td>
|
|
48
|
+
<td className="invocation_status">
|
|
49
|
+
<InvocationStatus status={status} />
|
|
50
|
+
</td>
|
|
51
|
+
<td className="invocation_actions">
|
|
52
|
+
<ActionButtons buttons={[...actions]} />
|
|
53
|
+
</td>
|
|
54
|
+
</tr>
|
|
43
55
|
);
|
|
44
56
|
};
|
|
45
57
|
|
|
46
|
-
|
|
58
|
+
InvocationItem.propTypes = {
|
|
47
59
|
id: PropTypes.number.isRequired,
|
|
48
60
|
name: PropTypes.string.isRequired,
|
|
49
61
|
status: PropTypes.string.isRequired,
|
|
@@ -51,4 +63,4 @@ InvocationActions.propTypes = {
|
|
|
51
63
|
task_id: PropTypes.number.isRequired,
|
|
52
64
|
};
|
|
53
65
|
|
|
54
|
-
export default
|
|
66
|
+
export default InvocationItem;
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import { useSelector, useDispatch } from 'react-redux';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
|
-
import { Grid } from 'patternfly-react';
|
|
5
4
|
|
|
6
|
-
import {
|
|
5
|
+
import {
|
|
7
6
|
withInterval,
|
|
8
7
|
stopInterval
|
|
9
8
|
} from 'foremanReact/redux/middlewares/IntervalMiddleware';
|
|
10
9
|
import { get } from 'foremanReact/redux/API';
|
|
11
10
|
import { useForemanSettings } from 'foremanReact/Root/Context/ForemanContext';
|
|
12
|
-
import { getControllerSearchProps } from 'foremanReact/constants';
|
|
13
|
-
import { translate as __ } from 'foremanReact/common/I18n';
|
|
14
|
-
import SearchBar from 'foremanReact/components/SearchBar';
|
|
15
|
-
import Pagination from 'foremanReact/components/Pagination/PaginationWrapper';
|
|
16
|
-
import { ActionButtons } from 'foremanReact/components/common/ActionButtons/ActionButtons';
|
|
17
11
|
|
|
18
|
-
import Invocations from './Invocations';
|
|
19
12
|
import {
|
|
20
13
|
selectItems,
|
|
21
14
|
selectTotal,
|
|
@@ -25,8 +18,7 @@ import {
|
|
|
25
18
|
} from './InvocationsSelectors';
|
|
26
19
|
import { getUrl } from './InvocationsHelpers';
|
|
27
20
|
import { INVOCATIONS } from './InvocationsConstants';
|
|
28
|
-
|
|
29
|
-
import './Invocations.css';
|
|
21
|
+
import InvocationsPage from './InvocationsPage';
|
|
30
22
|
|
|
31
23
|
const WrappedInvocations = ({ round }) => {
|
|
32
24
|
const dispatch = useDispatch();
|
|
@@ -44,9 +36,6 @@ const WrappedInvocations = ({ round }) => {
|
|
|
44
36
|
});
|
|
45
37
|
const [url, setUrl] = useState(getUrl(round, searchQuery, pagination));
|
|
46
38
|
const intervalExists = useSelector(selectIntervalExists);
|
|
47
|
-
const [selectedItems, setSelectedItems] = useState([]);
|
|
48
|
-
const [recentSelectedItemIndex, setRecentSelectedRowIndex] = useState(null);
|
|
49
|
-
const [shifting, setShifting] = useState(false);
|
|
50
39
|
|
|
51
40
|
const handleSearch = query => {
|
|
52
41
|
const defaultPagination = { page: 1, perPage: pagination.perPage };
|
|
@@ -63,39 +52,13 @@ const WrappedInvocations = ({ round }) => {
|
|
|
63
52
|
setUrl(getUrl(round, searchQuery, args));
|
|
64
53
|
};
|
|
65
54
|
|
|
66
|
-
const selectAll = (isSelecting) => setSelectedItems(isSelecting ? items.map(item => item.id) : []);
|
|
67
|
-
|
|
68
|
-
const areAllSelected = selectedItems.length == items.length;
|
|
69
|
-
|
|
70
|
-
const setItemSelected = (item, isSelecting) =>
|
|
71
|
-
setSelectedItems(prevSelected => {
|
|
72
|
-
const otherSelectedItems = prevSelected.filter(i => i !== item.id);
|
|
73
|
-
return isSelecting ? [...otherSelectedItems, item.id] : otherSelectedItems;
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const onSelect = (item, rowIndex, isSelecting) => {
|
|
77
|
-
if (shifting && recentSelectedRowIndex !== null) {
|
|
78
|
-
const numberSelected = rowIndex - recentSelectedRowIndex;
|
|
79
|
-
const intermediateIndexes =
|
|
80
|
-
numberSelected > 0
|
|
81
|
-
? Array.from(new Array(numberSelected + 1), (_x, i) => i + recentSelectedRowIndex)
|
|
82
|
-
: Array.from(new Array(Math.abs(numberSelected) + 1), (_x, i) => i + rowIndex);
|
|
83
|
-
intermediateIndexes.forEach(index, setItemSelected(items[index], isSelecting));
|
|
84
|
-
} else {
|
|
85
|
-
setItemSelected(item, isSelecting);
|
|
86
|
-
}
|
|
87
|
-
setRecentSelectedRowIndex(rowIndex);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const isSelected = item => selectedItems.includes(item.id);
|
|
91
|
-
|
|
92
55
|
const stopApiInterval = () => {
|
|
93
56
|
if (intervalExists) {
|
|
94
57
|
dispatch(stopInterval(INVOCATIONS));
|
|
95
58
|
}
|
|
96
59
|
};
|
|
97
60
|
|
|
98
|
-
const getData = url =>
|
|
61
|
+
const getData = url => withInterval(get({
|
|
99
62
|
key: INVOCATIONS,
|
|
100
63
|
url,
|
|
101
64
|
handleError: () => {
|
|
@@ -104,73 +67,27 @@ const WrappedInvocations = ({ round }) => {
|
|
|
104
67
|
}), 5000);
|
|
105
68
|
|
|
106
69
|
useEffect(() => {
|
|
107
|
-
const onKeyDown = (e) => {
|
|
108
|
-
if (e.key === 'Shift') {
|
|
109
|
-
setShifting(true);
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
const onKeyUp = (e) => {
|
|
113
|
-
if (e.key === 'Shift') {
|
|
114
|
-
setShifting(false);
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
|
|
118
70
|
dispatch(getData(url));
|
|
119
71
|
|
|
120
72
|
if (!autoRefresh) {
|
|
121
73
|
dispatch(stopInterval(INVOCATIONS));
|
|
122
74
|
}
|
|
123
75
|
|
|
124
|
-
document.addEventListener('keydown', onKeyDown);
|
|
125
|
-
document.addEventListener('keyup', onKeyUp);
|
|
126
|
-
|
|
127
76
|
return () => {
|
|
128
77
|
dispatch(stopInterval(INVOCATIONS));
|
|
129
|
-
document.removeEventListener('keydown', onKeyDown);
|
|
130
|
-
document.removeEventListener('keyup', onKeyUp);
|
|
131
78
|
};
|
|
132
79
|
}, [dispatch, url, autoRefresh]);
|
|
133
80
|
|
|
134
81
|
return (
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
searchQuery,
|
|
145
|
-
url: '/foreman_patch/invocations/auto_complete_search',
|
|
146
|
-
useKeyShortcuts: true,
|
|
147
|
-
},
|
|
148
|
-
bookmarks: {},
|
|
149
|
-
}}
|
|
150
|
-
/>
|
|
151
|
-
</Grid.Col>
|
|
152
|
-
<Grid.Col md={6}>
|
|
153
|
-
<ActionButtons buttons={actions} />
|
|
154
|
-
</Grid.Col>
|
|
155
|
-
</Grid.Row>
|
|
156
|
-
<br />
|
|
157
|
-
<Invocations
|
|
158
|
-
status={status}
|
|
159
|
-
items={items}
|
|
160
|
-
selectAll={selectAll}
|
|
161
|
-
areAllSelected={areAllSelected}
|
|
162
|
-
isSelected={isSelected}
|
|
163
|
-
onSelect={onSelect}
|
|
164
|
-
/>
|
|
165
|
-
<Pagination
|
|
166
|
-
viewType="table"
|
|
167
|
-
itemCount={total}
|
|
168
|
-
pagination={pagination}
|
|
169
|
-
onChange={handlePagination}
|
|
170
|
-
dropdownButtonId="invocations-pagination-dropdown"
|
|
171
|
-
className="invocations-pagination"
|
|
172
|
-
/>
|
|
173
|
-
</React.Fragment>
|
|
82
|
+
<InvocationsPage
|
|
83
|
+
status={status}
|
|
84
|
+
items={items}
|
|
85
|
+
total={total}
|
|
86
|
+
searchQuery={searchQuery}
|
|
87
|
+
handleSearch={handleSearch}
|
|
88
|
+
pagination={pagination}
|
|
89
|
+
handlePagination={handlePagination}
|
|
90
|
+
/>
|
|
174
91
|
);
|
|
175
92
|
};
|
|
176
93
|
|
|
@@ -19,7 +19,7 @@ const AggregateStatus = ({ progress }) => (
|
|
|
19
19
|
<span className="card-pf-aggregate-status-notification">
|
|
20
20
|
<span id="failed_count">
|
|
21
21
|
<span className="pficon pficon-error-circle-o" />
|
|
22
|
-
{progress.
|
|
22
|
+
{progress.failed}
|
|
23
23
|
</span>
|
|
24
24
|
</span>
|
|
25
25
|
<span className="card-pf-aggregate-status-notification">
|
|
@@ -31,7 +31,7 @@ const AggregateStatus = ({ progress }) => (
|
|
|
31
31
|
<span className="card-pf-aggregate-status-notification">
|
|
32
32
|
<span id="pending_count">
|
|
33
33
|
<span className="pficon pficon-pending" />
|
|
34
|
-
{progress.pending
|
|
34
|
+
{progress.pending}
|
|
35
35
|
</span>
|
|
36
36
|
</span>
|
|
37
37
|
<span className="card-pf-aggregate-status-notification">
|
|
@@ -46,12 +46,11 @@ const AggregateStatus = ({ progress }) => (
|
|
|
46
46
|
|
|
47
47
|
AggregateStatus.propTypes = {
|
|
48
48
|
progress: PropTypes.shape({
|
|
49
|
-
planned: PropTypes.number,
|
|
50
|
-
pending: PropTypes.number,
|
|
51
|
-
running: PropTypes.number,
|
|
52
49
|
success: PropTypes.number,
|
|
53
50
|
warning: PropTypes.number,
|
|
54
|
-
|
|
51
|
+
failed: PropTypes.number,
|
|
52
|
+
running: PropTypes.number,
|
|
53
|
+
pending: PropTypes.number,
|
|
55
54
|
cancelled: PropTypes.number,
|
|
56
55
|
}).isRequired,
|
|
57
56
|
};
|
|
@@ -11,14 +11,14 @@ const RoundProgress = ({ progress }) => {
|
|
|
11
11
|
const data = [
|
|
12
12
|
[__('Success'), progress.success, '#5CB85C'],
|
|
13
13
|
[__('Warning'), progress.warning, '#DB843D'],
|
|
14
|
-
[__('Failed'), progress.
|
|
14
|
+
[__('Failed'), progress.failed, '#D9534F'],
|
|
15
15
|
[__('Running'), progress.running, '#3D96AE'],
|
|
16
|
-
[__('Pending'), progress.pending
|
|
16
|
+
[__('Pending'), progress.pending, '#DEDEDE'],
|
|
17
17
|
[__('Cancelled'), progress.cancelled, '#B7312D'],
|
|
18
18
|
];
|
|
19
19
|
|
|
20
20
|
const iMax = data.reduce((im, e, i, arr) =>
|
|
21
|
-
(e[1] > arr[im][
|
|
21
|
+
(e[1] > arr[im][i] ? i : im), 0);
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<div id="round_progress">
|
|
@@ -36,12 +36,11 @@ const RoundProgress = ({ progress }) => {
|
|
|
36
36
|
|
|
37
37
|
RoundProgress.propTypes = {
|
|
38
38
|
progress: PropTypes.shape({
|
|
39
|
-
pending: PropTypes.number,
|
|
40
|
-
planned: PropTypes.number,
|
|
41
|
-
running: PropTypes.number,
|
|
42
39
|
success: PropTypes.number,
|
|
43
40
|
warning: PropTypes.number,
|
|
44
|
-
|
|
41
|
+
failed: PropTypes.number,
|
|
42
|
+
running: PropTypes.number,
|
|
43
|
+
pending: PropTypes.number,
|
|
45
44
|
cancelled: PropTypes.number,
|
|
46
45
|
}).isRequired,
|
|
47
46
|
};
|
|
@@ -8,10 +8,9 @@ import { ROUND_PROGRESS } from './RoundProgressConstants';
|
|
|
8
8
|
const defaultProgress = {
|
|
9
9
|
success: 0,
|
|
10
10
|
warning: 0,
|
|
11
|
-
|
|
11
|
+
failed: 0,
|
|
12
12
|
running: 0,
|
|
13
13
|
pending: 0,
|
|
14
|
-
planned: 0,
|
|
15
14
|
cancelled: 0,
|
|
16
15
|
};
|
|
17
16
|
|
|
@@ -19,7 +18,7 @@ export const selectProgress = state =>
|
|
|
19
18
|
selectAPIResponse(state, ROUND_PROGRESS).progress || defaultProgress;
|
|
20
19
|
|
|
21
20
|
export const selectAutoRefresh = state =>
|
|
22
|
-
selectAPIResponse(state, ROUND_PROGRESS).
|
|
21
|
+
!selectAPIResponse(state, ROUND_PROGRESS).complete;
|
|
23
22
|
|
|
24
23
|
export const selectStatus = state =>
|
|
25
24
|
selectAPIStatus(state, ROUND_PROGRESS);
|
|
@@ -2,13 +2,12 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { DndProvider } from 'react-dnd';
|
|
4
4
|
import HTML5Backend from 'react-dnd-html5-backend';
|
|
5
|
-
|
|
6
|
-
import './Calendar.css';
|
|
5
|
+
import './Calendar.scss';
|
|
7
6
|
|
|
8
7
|
import { views, getView } from './View';
|
|
9
8
|
|
|
10
9
|
const Calendar = (props) => {
|
|
11
|
-
const {
|
|
10
|
+
const {start, end, weekStartsOn, locale, onEventMoved} = props;
|
|
12
11
|
|
|
13
12
|
const initialDate = () => {
|
|
14
13
|
const { date } = props;
|
|
@@ -28,7 +27,7 @@ const Calendar = (props) => {
|
|
|
28
27
|
|
|
29
28
|
const result = events.map(event => {
|
|
30
29
|
if (event.id === updatedEvent.id) {
|
|
31
|
-
return {
|
|
30
|
+
return {...event, ...updatedEvent};
|
|
32
31
|
}
|
|
33
32
|
return event;
|
|
34
33
|
});
|
|
@@ -79,7 +78,7 @@ Calendar.defaultProps = {
|
|
|
79
78
|
date: new Date(),
|
|
80
79
|
view: views.MONTH,
|
|
81
80
|
events: [],
|
|
82
|
-
onEventMoved: (event) => {
|
|
81
|
+
onEventMoved: (event) => {},
|
|
83
82
|
locale: 'en-US',
|
|
84
83
|
weekStartsOn: 1,
|
|
85
84
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { classnames } from 'classname';
|
|
4
|
+
|
|
5
|
+
const OutputLine = ({index, type, children}) => {
|
|
6
|
+
return (
|
|
7
|
+
<div className={classnames('line', type)} >
|
|
8
|
+
<span className="counter">{index}</span>
|
|
9
|
+
<div className="content">
|
|
10
|
+
{children}
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
OutputLine.propTypes = {
|
|
17
|
+
index: PropTypes.number.isRequired,
|
|
18
|
+
type: PropTypes.string,
|
|
19
|
+
timestamp: PropTypes.number,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
OutputLine.defaultProps = {
|
|
23
|
+
type: 'stdout',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default OutputLine;
|