foreman_remote_execution 1.5.0 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.babelrc +9 -0
- data/.eslintignore +3 -0
- data/.eslintrc +49 -0
- data/.gitignore +1 -0
- data/.hound.yml +5 -0
- data/.rubocop.yml +4 -1
- data/.rubocop_todo.yml +63 -35
- data/.travis.yml +6 -0
- data/app/assets/javascripts/foreman_remote_execution/template_invocation.js +1 -1
- data/app/assets/stylesheets/foreman_remote_execution/job_invocations.css.scss +0 -14
- data/app/controllers/job_invocations_controller.rb +18 -0
- data/app/helpers/job_invocations_chart_helper.rb +77 -0
- data/app/helpers/job_invocations_helper.rb +79 -0
- data/app/helpers/remote_execution_helper.rb +10 -50
- data/app/models/job_invocation.rb +4 -0
- data/app/models/remote_execution_provider.rb +4 -0
- data/app/views/job_invocations/_card_results.html.erb +11 -0
- data/app/views/job_invocations/_card_schedule.html.erb +32 -0
- data/app/views/job_invocations/_card_target_hosts.html.erb +33 -0
- data/app/views/job_invocations/_card_user_input.html.erb +16 -0
- data/app/views/job_invocations/_tab_hosts.html.erb +1 -1
- data/app/views/job_invocations/_tab_overview.html.erb +25 -55
- data/app/views/job_invocations/_tab_preview_templates.html.erb +20 -0
- data/app/views/job_invocations/_user_input.html.erb +21 -0
- data/app/views/job_invocations/show.html.erb +14 -8
- data/app/views/job_invocations/show.js.erb +3 -6
- data/config/routes.rb +1 -0
- data/lib/foreman_remote_execution/engine.rb +2 -2
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/package.json +62 -0
- data/test/unit/job_invocation_test.rb +15 -0
- data/webpack/index.js +29 -0
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.js +34 -0
- data/webpack/react_app/components/jobInvocations/AggregateStatus/index.test.js +36 -0
- data/webpack/react_app/components/jobInvocations/index.js +58 -0
- data/webpack/react_app/redux/actions/jobInvocations/index.js +74 -0
- data/webpack/react_app/redux/consts.js +6 -0
- data/webpack/react_app/redux/reducers/index.js +6 -0
- data/webpack/react_app/redux/reducers/jobInvocations/index.fixtures.js +78 -0
- data/webpack/react_app/redux/reducers/jobInvocations/index.js +32 -0
- data/webpack/react_app/redux/reducers/jobInvocations/index.test.js +37 -0
- data/webpack/test_setup.js +11 -0
- metadata +26 -2
@@ -1,24 +1,30 @@
|
|
1
1
|
<% title @job_invocation.description, trunc_with_tooltip(@job_invocation.description, 120) %>
|
2
2
|
<% stylesheet 'foreman_remote_execution/job_invocations' %>
|
3
3
|
<% javascript 'charts', 'foreman_remote_execution/template_invocation' %>
|
4
|
+
<%= javascript_include_tag *webpack_asset_paths('remoteexecution', :extension => 'js'), "data-turbolinks-track" => true, 'defer' => 'defer' %>
|
4
5
|
|
5
6
|
<% if @job_invocation.task %>
|
6
7
|
<% title_actions(button_group(job_invocation_task_buttons(@job_invocation.task))) %>
|
7
8
|
<% end %>
|
8
9
|
|
9
10
|
<ul class="nav nav-tabs" data-tabs="tabs">
|
10
|
-
<li class="
|
11
|
-
|
12
|
-
|
11
|
+
<li class="active">
|
12
|
+
<a href="#primary" data-toggle="tab"><%= _('Overview') %></a>
|
13
|
+
</li>
|
14
|
+
<li>
|
15
|
+
<a href="#preview_templates" data-toggle="tab"><%= _('Preview templates') %></a>
|
16
|
+
</li>
|
17
|
+
<% if @job_invocation.recurring_logic.present? %>
|
18
|
+
<li><a href="#recurring_logic" data-toggle="tab"><%= _('Recurring logic') %></a></li>
|
19
|
+
<% end %>
|
13
20
|
</ul>
|
14
21
|
|
15
22
|
<div class="tab-content">
|
16
|
-
<div class="tab-pane
|
17
|
-
<%= render 'tab_overview', :job_invocation => @job_invocation %>
|
23
|
+
<div class="tab-pane active" id="primary">
|
24
|
+
<%= render 'tab_overview', :job_invocation => @job_invocation, :hosts => @hosts %>
|
18
25
|
</div>
|
19
|
-
|
20
|
-
|
21
|
-
<%= render 'tab_hosts', :job_invocation => @job_invocation, :hosts => @hosts %>
|
26
|
+
<div class="tab-pane" id="preview_templates">
|
27
|
+
<%= render 'tab_preview_templates', :job_invocation => @job_invocation %>
|
22
28
|
</div>
|
23
29
|
|
24
30
|
<% unless @job_invocation.recurring_logic.nil? %>
|
@@ -1,11 +1,8 @@
|
|
1
1
|
$('div#title_action div.btn-group').html('<%= button_group(job_invocation_task_buttons(@job_invocation.task)).html_safe %>');
|
2
|
-
$('div#status_chart').html('<%=j job_invocation_chart(@job_invocation) %>');
|
3
|
-
$('div#status').flot_pie();
|
4
|
-
|
5
2
|
<% if params[:hosts_needs_refresh] == 'true' && @job_invocation.resolved? %>
|
6
|
-
var
|
7
|
-
|
8
|
-
|
3
|
+
var hosts_table = $('div#hosts');
|
4
|
+
hosts_table.html('<%=j render('tab_hosts', :job_invocation => @job_invocation, :hosts => @hosts) %>');
|
5
|
+
hosts_table.data('refresh_required', '');
|
9
6
|
<% end %>
|
10
7
|
|
11
8
|
<% ['name', 'status', 'actions', 'provider'].each do |attribute| %>
|
data/config/routes.rb
CHANGED
@@ -31,7 +31,7 @@ module ForemanRemoteExecution
|
|
31
31
|
|
32
32
|
initializer 'foreman_remote_execution.register_plugin', before: :finisher_hook do |_app|
|
33
33
|
Foreman::Plugin.register :foreman_remote_execution do
|
34
|
-
requires_foreman '>= 1.
|
34
|
+
requires_foreman '>= 1.18'
|
35
35
|
|
36
36
|
apipie_documented_controllers ["#{ForemanRemoteExecution::Engine.root}/app/controllers/api/v2/*.rb"]
|
37
37
|
|
@@ -54,7 +54,7 @@ module ForemanRemoteExecution
|
|
54
54
|
permission :lock_job_templates, { :job_templates => [:lock, :unlock] }, :resource_type => 'JobTemplate'
|
55
55
|
permission :create_job_invocations, { :job_invocations => [:new, :create, :refresh, :rerun, :preview_hosts],
|
56
56
|
'api/v2/job_invocations' => [:create, :rerun] }, :resource_type => 'JobInvocation'
|
57
|
-
permission :view_job_invocations, { :job_invocations => [:index, :show, :auto_complete_search], :template_invocations => [:show],
|
57
|
+
permission :view_job_invocations, { :job_invocations => [:index, :chart, :show, :auto_complete_search], :template_invocations => [:show],
|
58
58
|
'api/v2/job_invocations' => [:index, :show, :output] }, :resource_type => 'JobInvocation'
|
59
59
|
permission :create_template_invocations, {}, :resource_type => 'TemplateInvocation'
|
60
60
|
permission :cancel_job_invocations, { :job_invocations => [:cancel], 'api/v2/job_invocations' => [:cancel] }, :resource_type => 'JobInvocation'
|
data/package.json
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
{
|
2
|
+
"name": "foreman_remote_execution",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"license": "GPL-3.0",
|
5
|
+
"scripts": {
|
6
|
+
"lint": "./node_modules/.bin/eslint -c .eslintrc webpack/ script/ || exit 0",
|
7
|
+
"test": "node node_modules/.bin/jest webpack",
|
8
|
+
"test:watch": "node node_modules/.bin/jest webpack --watchAll",
|
9
|
+
"test:current": "node node_modules/.bin/jest webpack --watch"
|
10
|
+
},
|
11
|
+
"jest": {
|
12
|
+
"verbose": true,
|
13
|
+
"moduleDirectories": [
|
14
|
+
"node_modules",
|
15
|
+
"webpack"
|
16
|
+
],
|
17
|
+
"setupFiles": [
|
18
|
+
"raf/polyfill",
|
19
|
+
"./webpack/test_setup.js"
|
20
|
+
],
|
21
|
+
"testPathIgnorePatterns": [
|
22
|
+
"/node_modules/",
|
23
|
+
"<rootDir>/foreman/"
|
24
|
+
]
|
25
|
+
},
|
26
|
+
"repository": {
|
27
|
+
"type": "git",
|
28
|
+
"url": "git+https://github.com/foreman_remote_execution/foreman_remote_execution.git"
|
29
|
+
},
|
30
|
+
"bugs": {
|
31
|
+
"url": "http://projects.theforeman.org/projects/foreman_remote_execution/issues"
|
32
|
+
},
|
33
|
+
"devDependencies": {
|
34
|
+
"babel-eslint": "^8.2.1",
|
35
|
+
"babel-preset-env": "^1.6.0",
|
36
|
+
"babel-preset-react": "^6.24.1",
|
37
|
+
"babel-plugin-lodash": "^3.3.2",
|
38
|
+
"babel-plugin-transform-object-assign": "^6.22.0",
|
39
|
+
"babel-plugin-transform-class-properties": "^6.24.1",
|
40
|
+
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
41
|
+
"enzyme": "^3.2.0",
|
42
|
+
"enzyme-adapter-react-16": "^1.1.0",
|
43
|
+
"enzyme-to-json": "^3.1.2",
|
44
|
+
"eslint": "^4.10.0",
|
45
|
+
"eslint-config-airbnb": "^16.0.0",
|
46
|
+
"eslint-plugin-import": "^2.8.0",
|
47
|
+
"eslint-plugin-jest": "^21.2.0",
|
48
|
+
"eslint-plugin-jsx-a11y": "^6.0.2",
|
49
|
+
"eslint-plugin-react": "^7.4.0",
|
50
|
+
"jest": "^21.2.1"
|
51
|
+
},
|
52
|
+
"dependencies": {
|
53
|
+
"babel-polyfill": "^6.26.0",
|
54
|
+
"prop-types": "^15.6.0",
|
55
|
+
"react": "^16.2.0",
|
56
|
+
"react-dom": "^16.2.0",
|
57
|
+
"react-redux": "^5.0.6",
|
58
|
+
"redux": "^3.7.2",
|
59
|
+
"seamless-immutable": "^7.1.3",
|
60
|
+
"urijs": "^1.19.0"
|
61
|
+
}
|
62
|
+
}
|
@@ -173,4 +173,19 @@ class JobInvocationTest < ActiveSupport::TestCase
|
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
+
describe '#finished?' do
|
177
|
+
let(:task) { ForemanTasks::Task.new }
|
178
|
+
before { job_invocation.task = task }
|
179
|
+
|
180
|
+
it 'returns false if task state is pending' do
|
181
|
+
job_invocation.task.expects(:pending?).returns(true)
|
182
|
+
refute job_invocation.finished?
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'returns true if task is not pending' do
|
186
|
+
job_invocation.task.expects(:pending?).returns(false)
|
187
|
+
assert job_invocation.finished?
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
176
191
|
end
|
data/webpack/index.js
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
import URI from 'urijs';
|
2
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
3
|
+
import { mount, registerReducer } from 'foremanReact/common/MountingService';
|
4
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
5
|
+
import componentRegistry from 'foremanReact/components/componentRegistry';
|
6
|
+
import JobInvocationContainer from './react_app/components/jobInvocations';
|
7
|
+
import rootReducer from './react_app/redux/reducers';
|
8
|
+
|
9
|
+
componentRegistry.register({
|
10
|
+
name: 'JobInvocationContainer',
|
11
|
+
type: JobInvocationContainer,
|
12
|
+
});
|
13
|
+
|
14
|
+
registerReducer('foremanRemoteExecutionReducers', rootReducer);
|
15
|
+
|
16
|
+
if (window.location.href.match(/job_invocations/)) {
|
17
|
+
const jobInvocationId = parseInt(
|
18
|
+
new URI(window.location.href).filename(),
|
19
|
+
10,
|
20
|
+
);
|
21
|
+
|
22
|
+
const mountJobInvocationContainer = () => {
|
23
|
+
mount('JobInvocationContainer', '#status_chart', {
|
24
|
+
url: `/job_invocations/chart?id=${jobInvocationId}`,
|
25
|
+
});
|
26
|
+
};
|
27
|
+
|
28
|
+
document.addEventListener('page:change', mountJobInvocationContainer);
|
29
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
const AggregateStatus = ({ statuses }) => (
|
4
|
+
<div id="aggregate_statuses">
|
5
|
+
<p className="card-pf-aggregate-status-notifications">
|
6
|
+
<span className="card-pf-aggregate-status-notification">
|
7
|
+
<span id="success_count">
|
8
|
+
<span className="pficon pficon-ok" />
|
9
|
+
{statuses.success}
|
10
|
+
</span>
|
11
|
+
</span>
|
12
|
+
<span className="card-pf-aggregate-status-notification">
|
13
|
+
<span id="failed_count">
|
14
|
+
<span className="pficon pficon-error-circle-o" />
|
15
|
+
{statuses.failed}
|
16
|
+
</span>
|
17
|
+
</span>
|
18
|
+
<span className="card-pf-aggregate-status-notification">
|
19
|
+
<span id="pending_count">
|
20
|
+
<span className="pficon pficon-running" />
|
21
|
+
{statuses.pending}
|
22
|
+
</span>
|
23
|
+
</span>
|
24
|
+
<span className="card-pf-aggregate-status-notification">
|
25
|
+
<span id="cancelled_count">
|
26
|
+
<span className="pficon pficon-close" />
|
27
|
+
{statuses.cancelled}
|
28
|
+
</span>
|
29
|
+
</span>
|
30
|
+
</p>
|
31
|
+
</div>
|
32
|
+
);
|
33
|
+
|
34
|
+
export default AggregateStatus;
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { shallow } from 'enzyme';
|
3
|
+
import AggregateStatus from './index.js';
|
4
|
+
|
5
|
+
jest.unmock('./index.js');
|
6
|
+
|
7
|
+
describe('AggregateStatus', () => {
|
8
|
+
describe('has no data', () => {
|
9
|
+
it('renders cards with no data', () => {
|
10
|
+
const chartNumbers = shallow(<AggregateStatus statuses={{}} />);
|
11
|
+
const success = chartNumbers.find('#success_count').text();
|
12
|
+
const failed = chartNumbers.find('#failed_count').text();
|
13
|
+
const pending = chartNumbers.find('#pending_count').text();
|
14
|
+
const cancelled = chartNumbers.find('#cancelled_count').text();
|
15
|
+
expect(success).toBe('');
|
16
|
+
expect(failed).toBe('');
|
17
|
+
expect(cancelled).toBe('');
|
18
|
+
expect(pending).toBe('');
|
19
|
+
});
|
20
|
+
|
21
|
+
it('renders cards with props passed', () => {
|
22
|
+
const statuses = {
|
23
|
+
success: 19, failed: 20, cancelled: 31, pending: 3,
|
24
|
+
};
|
25
|
+
const chartNumbers = shallow(<AggregateStatus statuses={statuses} />);
|
26
|
+
const success = chartNumbers.find('#success_count').text();
|
27
|
+
const failed = chartNumbers.find('#failed_count').text();
|
28
|
+
const pending = chartNumbers.find('#pending_count').text();
|
29
|
+
const cancelled = chartNumbers.find('#cancelled_count').text();
|
30
|
+
expect(success).toBe(statuses.success.toString());
|
31
|
+
expect(failed).toBe(statuses.failed.toString());
|
32
|
+
expect(cancelled).toBe(statuses.cancelled.toString());
|
33
|
+
expect(pending).toBe(statuses.pending.toString());
|
34
|
+
});
|
35
|
+
});
|
36
|
+
});
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import { connect } from 'react-redux';
|
2
|
+
import React from 'react';
|
3
|
+
import Immutable from 'seamless-immutable';
|
4
|
+
import PropTypes from 'prop-types';
|
5
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
6
|
+
import DonutChart from 'foremanReact/components/common/charts/DonutChart';
|
7
|
+
import AggregateStatus from './AggregateStatus/index.js';
|
8
|
+
import * as JobInvocationActions from '../../redux/actions/jobInvocations';
|
9
|
+
|
10
|
+
class JobInvocationContainer extends React.Component {
|
11
|
+
componentDidMount() {
|
12
|
+
const { startJobInvocationsPolling, data: { url } } = this.props;
|
13
|
+
|
14
|
+
startJobInvocationsPolling(url);
|
15
|
+
}
|
16
|
+
|
17
|
+
render() {
|
18
|
+
const { jobInvocations, statuses } = this.props;
|
19
|
+
|
20
|
+
return (
|
21
|
+
<div id="job_invocations_chart_container">
|
22
|
+
<DonutChart data={Immutable.asMutable(jobInvocations)} />
|
23
|
+
<AggregateStatus statuses={statuses} />
|
24
|
+
</div>
|
25
|
+
);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
const mapStateToProps = (state) => {
|
30
|
+
const {
|
31
|
+
jobInvocations,
|
32
|
+
statuses,
|
33
|
+
} = state.foremanRemoteExecutionReducers.jobInvocations;
|
34
|
+
|
35
|
+
return {
|
36
|
+
jobInvocations,
|
37
|
+
statuses,
|
38
|
+
};
|
39
|
+
};
|
40
|
+
|
41
|
+
JobInvocationContainer.propTypes = {
|
42
|
+
startJobInvocationsPolling: PropTypes.func,
|
43
|
+
data: PropTypes.string,
|
44
|
+
jobInvocations: PropTypes.arrayOf(PropTypes.arrayOf(
|
45
|
+
PropTypes.string,
|
46
|
+
PropTypes.number,
|
47
|
+
PropTypes.string,
|
48
|
+
)),
|
49
|
+
statuses: PropTypes.shape({}),
|
50
|
+
};
|
51
|
+
|
52
|
+
JobInvocationContainer.defaultProps = {
|
53
|
+
startJobInvocationsPolling: JobInvocationActions.startJobInvocationsPolling,
|
54
|
+
data: '',
|
55
|
+
jobInvocations: [['property', 3, 'color']],
|
56
|
+
statuses: {},
|
57
|
+
};
|
58
|
+
export default connect(mapStateToProps, JobInvocationActions)(JobInvocationContainer);
|
@@ -0,0 +1,74 @@
|
|
1
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
2
|
+
import API from 'foremanReact/API';
|
3
|
+
|
4
|
+
import {
|
5
|
+
JOB_INVOCATIONS_GET_JOB_INVOCATIONS,
|
6
|
+
JOB_INVOCATIONS_POLLING_STARTED,
|
7
|
+
JOB_INVOCATIONS_JOB_FINISHED,
|
8
|
+
} from '../../consts';
|
9
|
+
|
10
|
+
const defaultJobInvocationsPollingInterval = 1000;
|
11
|
+
const jobInvocationsInterval = process.env.JOB_INVOCATIONS_POLLING ||
|
12
|
+
defaultJobInvocationsPollingInterval;
|
13
|
+
|
14
|
+
const getJobInvocations = url => (dispatch, getState) => {
|
15
|
+
function onGetJobInvocationsSuccess({ data }) {
|
16
|
+
// If the job has finished, stop polling
|
17
|
+
if (data.finished) {
|
18
|
+
dispatch({
|
19
|
+
type: JOB_INVOCATIONS_JOB_FINISHED,
|
20
|
+
payload: {
|
21
|
+
jobInvocations: data,
|
22
|
+
},
|
23
|
+
});
|
24
|
+
} else {
|
25
|
+
dispatch({
|
26
|
+
type: JOB_INVOCATIONS_GET_JOB_INVOCATIONS,
|
27
|
+
payload: {
|
28
|
+
jobInvocations: data,
|
29
|
+
},
|
30
|
+
});
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
function onGetJobInvocationsFailed(error) {
|
35
|
+
if (error.response.status === 401) {
|
36
|
+
window.location.replace('/users/login');
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
function triggerPolling() {
|
41
|
+
if (jobInvocationsInterval) {
|
42
|
+
setTimeout(
|
43
|
+
() => dispatch(getJobInvocations(url)),
|
44
|
+
jobInvocationsInterval,
|
45
|
+
);
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
const isDocumentVisible =
|
50
|
+
document.visibilityState === 'visible' ||
|
51
|
+
document.visibilityState === 'prerender';
|
52
|
+
|
53
|
+
if (getState().foremanRemoteExecutionReducers.jobInvocations.isPolling) {
|
54
|
+
if (isDocumentVisible) {
|
55
|
+
API.get(url)
|
56
|
+
.then(onGetJobInvocationsSuccess)
|
57
|
+
.catch(onGetJobInvocationsFailed)
|
58
|
+
.then(triggerPolling);
|
59
|
+
} else {
|
60
|
+
// document is not visible, keep polling without api call
|
61
|
+
triggerPolling();
|
62
|
+
}
|
63
|
+
}
|
64
|
+
};
|
65
|
+
|
66
|
+
export const startJobInvocationsPolling = url => (dispatch, getState) => {
|
67
|
+
if (getState().foremanRemoteExecutionReducers.jobInvocations.isPolling) {
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
dispatch({
|
71
|
+
type: JOB_INVOCATIONS_POLLING_STARTED,
|
72
|
+
});
|
73
|
+
dispatch(getJobInvocations(url));
|
74
|
+
};
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import Immutable from 'seamless-immutable';
|
2
|
+
|
3
|
+
export const initialState = Immutable({
|
4
|
+
isPolling: false,
|
5
|
+
jobInvocations: [],
|
6
|
+
statuses: [],
|
7
|
+
});
|
8
|
+
|
9
|
+
export const pollingStarted = Immutable({
|
10
|
+
isPolling: true,
|
11
|
+
jobInvocations: [],
|
12
|
+
statuses: [],
|
13
|
+
});
|
14
|
+
|
15
|
+
export const jobInvocationsPayload = Immutable({
|
16
|
+
jobInvocations: {
|
17
|
+
job_invocations: [
|
18
|
+
[
|
19
|
+
'Success',
|
20
|
+
100,
|
21
|
+
'#B7312D',
|
22
|
+
],
|
23
|
+
[
|
24
|
+
'Failed',
|
25
|
+
20,
|
26
|
+
'#B7312D',
|
27
|
+
],
|
28
|
+
[
|
29
|
+
'Pending',
|
30
|
+
40,
|
31
|
+
'#B7312D',
|
32
|
+
],
|
33
|
+
[
|
34
|
+
'Cancelled',
|
35
|
+
0,
|
36
|
+
'#B7312D',
|
37
|
+
],
|
38
|
+
],
|
39
|
+
statuses: {
|
40
|
+
cancelled: 0,
|
41
|
+
failed: 0,
|
42
|
+
pending: 0,
|
43
|
+
success: 1,
|
44
|
+
},
|
45
|
+
},
|
46
|
+
});
|
47
|
+
|
48
|
+
export const jobInvocationsReceived = Immutable({
|
49
|
+
isPolling: true,
|
50
|
+
jobInvocations: [
|
51
|
+
[
|
52
|
+
'Success',
|
53
|
+
100,
|
54
|
+
'#B7312D',
|
55
|
+
],
|
56
|
+
[
|
57
|
+
'Failed',
|
58
|
+
20,
|
59
|
+
'#B7312D',
|
60
|
+
],
|
61
|
+
[
|
62
|
+
'Pending',
|
63
|
+
40,
|
64
|
+
'#B7312D',
|
65
|
+
],
|
66
|
+
[
|
67
|
+
'Cancelled',
|
68
|
+
0,
|
69
|
+
'#B7312D',
|
70
|
+
],
|
71
|
+
],
|
72
|
+
statuses: {
|
73
|
+
cancelled: 0,
|
74
|
+
failed: 0,
|
75
|
+
pending: 0,
|
76
|
+
success: 1,
|
77
|
+
},
|
78
|
+
});
|