From 9f12a9ac6ff1c9ab4d394bf2c53f6be5f1d050ca Mon Sep 17 00:00:00 2001 From: MariaAga Date: Thu, 9 Jan 2025 12:29:32 +0000 Subject: [PATCH] Fixes #38130 - add info to job details --- .../api/v2/job_invocations_controller.rb | 2 + .../api/v2/job_invocations/base.json.rabl | 2 +- .../api/v2/job_invocations/show.json.rabl | 38 ++ .../job_invocations/_tab_overview.html.erb | 1 + .../JobInvocationDetail/JobAdditionInfo.js | 399 ++++++++++++++++++ .../JobInvocationConstants.js | 12 + webpack/JobInvocationDetail/index.js | 4 + 7 files changed, 457 insertions(+), 1 deletion(-) create mode 100644 webpack/JobInvocationDetail/JobAdditionInfo.js diff --git a/app/controllers/api/v2/job_invocations_controller.rb b/app/controllers/api/v2/job_invocations_controller.rb index ea8404b8c..a9487fc6e 100644 --- a/app/controllers/api/v2/job_invocations_controller.rb +++ b/app/controllers/api/v2/job_invocations_controller.rb @@ -22,6 +22,8 @@ def index param :host_status, :bool, required: false, desc: N_('Show Job status for the hosts') def show set_hosts_and_template_invocations + @job_organization = Taxonomy.find_by(id: @job_invocation.task.input[:current_organization_id]) + @job_location = Taxonomy.find_by(id: @job_invocation.task.input[:current_location_id]) if params[:host_status] == 'true' set_statuses_and_smart_proxies end diff --git a/app/views/api/v2/job_invocations/base.json.rabl b/app/views/api/v2/job_invocations/base.json.rabl index b01c5f059..be2929f2e 100644 --- a/app/views/api/v2/job_invocations/base.json.rabl +++ b/app/views/api/v2/job_invocations/base.json.rabl @@ -1,6 +1,6 @@ object @job_invocation -attributes :id, :description, :job_category, :targeting_id, :status, :start_at, :status_label, :ssh_user, :time_to_pickup +attributes :id, :description, :job_category, :targeting_id, :status, :start_at, :status_label, :ssh_user, :time_to_pickup, :concurrency_level, :execution_timeout_interval node do |invocation| pattern_template = invocation.pattern_template_invocations.first diff --git a/app/views/api/v2/job_invocations/show.json.rabl b/app/views/api/v2/job_invocations/show.json.rabl index b37e795ac..d126536bc 100644 --- a/app/views/api/v2/job_invocations/show.json.rabl +++ b/app/views/api/v2/job_invocations/show.json.rabl @@ -1,3 +1,41 @@ object @job_invocation +attribute :pattern_template_invocations + extends 'api/v2/job_invocations/main' + +node :job_organization do + @job_organization +end + +node :job_location do + @job_location +end + +# node :inputs do +# # @job_invocation.pattern_template_invocations[0][:input_values] +# @job_invocation.pattern_template_invocations[0].input_values +# # @job_invocation.pattern_template_invocations.map(&:input_values) +# # @job_invocation.pattern_template_invocations.map{ |invocation| invocation.input_values +# # } +# end + +# child @job_invocation.pattern_template_invocations => :pattern_template_invocations do |template| +# puts template.inspect +# # @job_invocation.pattern_template_invocations +# child template.input_values => :input_values do +# attributes :template_input_name, :template_input_id +# node :value do |iv| +# iv.template_input.respond_to?(:hidden_value) && iv.template_input.hidden_value? ? '*' * 5 : iv.value +# end +# end +# end + +# child @inputs do +# child :input_values do +# attributes :template_input_name, :template_input_id +# node :value do |iv| +# iv.template_input.respond_to?(:hidden_value) && iv.template_input.hidden_value? ? '*' * 5 : iv.value +# end +# end +# end diff --git a/app/views/job_invocations/_tab_overview.html.erb b/app/views/job_invocations/_tab_overview.html.erb index be0553c32..879500793 100644 --- a/app/views/job_invocations/_tab_overview.html.erb +++ b/app/views/job_invocations/_tab_overview.html.erb @@ -1,4 +1,5 @@ <% template_invocations = job_invocation.pattern_template_invocations %> +<%= job_invocation.pattern_template_invocations[0].input_values.inspect %>
<%= render :partial => 'card_results', :locals => { :job_invocation => job_invocation } %> diff --git a/webpack/JobInvocationDetail/JobAdditionInfo.js b/webpack/JobInvocationDetail/JobAdditionInfo.js new file mode 100644 index 000000000..df907fe49 --- /dev/null +++ b/webpack/JobInvocationDetail/JobAdditionInfo.js @@ -0,0 +1,399 @@ +/* eslint-disable camelcase */ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { + ExpandableSection, + DataList, + DataListCell, + DataListItemCells, + DataListItem, + DataListItemRow, +} from '@patternfly/react-core'; +import { translate as __ } from 'foremanReact/common/I18n'; +import { TARGETING_TYPES } from './JobInvocationConstants'; + +const Schedule = ({ data }) => { + const [isExpanded, setIsExpanded] = useState(false); + const { + concurrency_level, + scheduling, + time_to_pickup, + execution_timeout_interval, + } = data; + return ( + + + <> + + + + {__('Concurrency level limited to')} + , + + {concurrency_level} + , + ]} + /> + + + + + + {__('Scheduled to start before')} + , + + {scheduling?.start_before} + , + ]} + /> + + + + + + {__('Scheduled to start at')} + , + + {scheduling?.start_at} + , + ]} + /> + + + + + + {__('Timeout to kill after')} + , + + {`${execution_timeout_interval} ${__('seconds')}`} + , + ]} + /> + + + + + + {__('Time to pickup')} + , + + {`${time_to_pickup} ${__('seconds')}`} + , + ]} + /> + + + + + + ); +}; +const Recurring = ({ data }) => { + const [isExpanded, setIsExpanded] = useState(false); + const { recurrence } = data; + + if (!recurrence) return null; + return ( + + + <> + + + {__('ID')}, + + + {recurrence.id} + + , + ]} + /> + + + + + + {__('Cron line')} + , + + {recurrence.cron_line} + , + ]} + /> + + + {/* TODO {__('Action')} + + {format_task_input(recurring_logic.tasks.last)} + */} + + + + {__('Last occurrence')} + , + + {recurrence.last_occurrence} + , + ]} + /> + + + + + + {__('Next occurrence')} + , + + {recurrence.next_occurrence} + , + ]} + /> + + + + + + {__('Current iteration')} + , + + {recurrence.iteration} + , + ]} + /> + + + + + + {__('Iteration limit')} + , + + {recurrence.max_iteration} + , + ]} + /> + + + + + + {__('Repeat until')} + , + + {recurrence.end_time} + , + ]} + /> + + + {/* TODO {__('State')} + + {recurring_logic_state(recurring_logic)} + */} + + + + {__('Purpose')} + , + + {recurrence.purpose} + , + ]} + /> + + + + + + {__('Task count')} + , + + {recurrence.task_count} + , + ]} + /> + + + + + + ); +}; +const TargetHosts = ({ data }) => { + const [isExpanded, setIsExpanded] = useState(false); + const { + targeting, + job_location: location, + job_organization: organization, + } = data; + + // manual selection using static query + // execution order + // + // TODO is needed? bookmark_id is always null in the wizard, also why is knowing the bookmark relevent? + // const targetingSelectioning = targeting.bookmark_id ? `{__('Bookmark') ${targeting.bookmark_name}` : __('Manual selection'); + const type = `${__('Manual selection')} ${__('using ')} \ + ${TARGETING_TYPES[targeting.targeting_type].toLowerCase()}`; + return ( + + {type} +
{targeting.search_query}
+ + + + + + {__('Organization')} + , + + {organization} + , + ]} + /> + + + + + + {__('Location')} + , + + {location} + , + ]} + /> + + + + + + {__('Execution order')} + , + + {targeting.randomized_ordering + ? __('Randomized') + : __('Alphabetical')} + , + ]} + /> + + + +
+ ); +}; +const Inputs = ({ data }) => { + const [isExpanded, setIsExpanded] = useState(false); + const inputs = + data?.template_invocations?.[0]?.template_invocation_input_values; + + // const inputs = TODO get inputs + // data?.pattern_template_invocations?.[0]?.template_invocation_input_values; + if (!inputs) return null; + return ( + + + {inputs.map(({ template_input_name: name, value }) => ( + + + + {name} + , + + {value} + , + ]} + /> + + + ))} + + + ); +}; +export const JobAdditionInfo = ({ data }) => { + const [isExpanded, setIsExpanded] = useState(false); + + return ( + // + <> + + + + + + // + ); +}; + +JobAdditionInfo.propTypes = { + data: PropTypes.shape({ + recurrence: PropTypes.object, + targeting: PropTypes.object, + }).isRequired, +}; + +Recurring.propTypes = JobAdditionInfo.propTypes; +TargetHosts.propTypes = JobAdditionInfo.propTypes; +Inputs.propTypes = JobAdditionInfo.propTypes; +Schedule.propTypes = JobAdditionInfo.propTypes; diff --git a/webpack/JobInvocationDetail/JobInvocationConstants.js b/webpack/JobInvocationDetail/JobInvocationConstants.js index 16d1f2b4d..4e857d0f1 100644 --- a/webpack/JobInvocationDetail/JobInvocationConstants.js +++ b/webpack/JobInvocationDetail/JobInvocationConstants.js @@ -113,3 +113,15 @@ const Columns = () => { }; export default Columns; + +const STATIC_TYPE = 'static_query'; +const DYNAMIC_TYPE = 'dynamic_query'; +export const TARGETING_TYPES = { + [STATIC_TYPE]: __('Static Query'), + [DYNAMIC_TYPE]: __('Dynamic Query'), +}; + +export const ORDERINGS = { + ORDERED: __('Alphabetical'), + RANDOMIZED: __('Randomized'), +}; diff --git a/webpack/JobInvocationDetail/index.js b/webpack/JobInvocationDetail/index.js index 2f57ed75e..3e3b9fd7d 100644 --- a/webpack/JobInvocationDetail/index.js +++ b/webpack/JobInvocationDetail/index.js @@ -25,6 +25,7 @@ import { selectItems } from './JobInvocationSelectors'; import JobInvocationSystemStatusChart from './JobInvocationSystemStatusChart'; import JobInvocationToolbarButtons from './JobInvocationToolbarButtons'; import JobInvocationHostTable from './JobInvocationHostTable'; +import { JobAdditionInfo } from './JobAdditionInfo'; const JobInvocationDetailPage = ({ match: { @@ -129,6 +130,9 @@ const JobInvocationDetailPage = ({ + + {items.id !== undefined && } +