From 77e71aced46cfa62ae493f16260b03481faaa53f Mon Sep 17 00:00:00 2001 From: kmalyjur <78563507+kmalyjur@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:12:35 -0400 Subject: [PATCH] Fixes #39352 - Job inv page ignores remote_execution_job_invocation_report_template setting --- .../JobInvocationConstants.js | 1 + .../JobInvocationToolbarButtons.js | 40 +++++++---- .../__tests__/MainInformation.test.js | 68 ++++++++++++++++++- 3 files changed, 96 insertions(+), 13 deletions(-) diff --git a/webpack/JobInvocationDetail/JobInvocationConstants.js b/webpack/JobInvocationDetail/JobInvocationConstants.js index 12453eca2..f08ff1e0c 100644 --- a/webpack/JobInvocationDetail/JobInvocationConstants.js +++ b/webpack/JobInvocationDetail/JobInvocationConstants.js @@ -13,6 +13,7 @@ export const GET_TEMPLATE_INVOCATIONS = 'GET_TEMPLATE_INVOCATIONS'; export const CHANGE_ENABLED_RECURRING_LOGIC = 'CHANGE_ENABLED_RECURRING_LOGIC'; export const CANCEL_RECURRING_LOGIC = 'CANCEL_RECURRING_LOGIC'; export const GET_REPORT_TEMPLATES = 'GET_REPORT_TEMPLATES'; +export const GET_REPORT_TEMPLATE_SETTING = 'GET_REPORT_TEMPLATE_SETTING'; export const GET_REPORT_TEMPLATE_INPUTS = 'GET_REPORT_TEMPLATE_INPUTS'; export const JOB_INVOCATION_HOSTS = 'JOB_INVOCATION_HOSTS'; export const GET_TEMPLATE_INVOCATION = 'GET_TEMPLATE_INVOCATION'; diff --git a/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js b/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js index 7869d331c..ae30ccd79 100644 --- a/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js +++ b/webpack/JobInvocationDetail/JobInvocationToolbarButtons.js @@ -23,6 +23,7 @@ import { import { STATUS, GET_REPORT_TEMPLATES, + GET_REPORT_TEMPLATE_SETTING, GET_REPORT_TEMPLATE_INPUTS, } from './JobInvocationConstants'; import { selectTaskCancelable } from './JobInvocationSelectors'; @@ -80,22 +81,37 @@ const JobInvocationToolbarButtons = ({ jobId, data }) => { useEffect(() => { let isMounted = true; + const fetchReportTemplate = templateName => { + dispatch( + get({ + key: GET_REPORT_TEMPLATES, + url: '/api/report_templates', + params: { + search: `name="${templateName}"`, + per_page: 1, + }, + handleSuccess: ({ data: { results } }) => { + if (isMounted) { + setReportTemplateJobId(results[0]?.id); + } + }, + handleError: () => { + if (isMounted) { + setReportTemplateJobId(undefined); + } + }, + }) + ); + }; dispatch( get({ - key: GET_REPORT_TEMPLATES, - url: '/api/report_templates', - handleSuccess: ({ data: { results } }) => { - if (isMounted) { - setReportTemplateJobId( - results.find(result => result.name === 'Job - Invocation Report') - ?.id - ); - } + key: GET_REPORT_TEMPLATE_SETTING, + url: '/api/settings/remote_execution_job_invocation_report_template', + handleSuccess: ({ data: { value } }) => { + fetchReportTemplate(value); }, handleError: () => { - if (isMounted) { - setReportTemplateJobId(undefined); - } + fetchReportTemplate('Job - Invocation Report'); }, }) ); diff --git a/webpack/JobInvocationDetail/__tests__/MainInformation.test.js b/webpack/JobInvocationDetail/__tests__/MainInformation.test.js index 76ce24b39..1d7df7966 100644 --- a/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +++ b/webpack/JobInvocationDetail/__tests__/MainInformation.test.js @@ -29,6 +29,7 @@ import { CANCEL_RECURRING_LOGIC, CHANGE_ENABLED_RECURRING_LOGIC, GET_REPORT_TEMPLATES, + GET_REPORT_TEMPLATE_SETTING, GET_REPORT_TEMPLATE_INPUTS, GET_TASK, JOB_INVOCATION_KEY, @@ -85,7 +86,13 @@ jest.mock('foremanReact/routes/common/PageLayout/PageLayout', () => const setupApiMocks = () => { api.get.mockImplementation(({ handleSuccess, key, ...action }) => { - if (key === GET_REPORT_TEMPLATES) { + if (key === GET_REPORT_TEMPLATE_SETTING) { + if (handleSuccess) { + handleSuccess({ + data: { value: 'Job - Invocation Report' }, + }); + } + } else if (key === GET_REPORT_TEMPLATES) { if (handleSuccess) { handleSuccess({ data: mockReportTemplatesResponse, @@ -323,6 +330,59 @@ describe('JobInvocationDetailPage', () => { expect(createReportButton).toHaveClass('pf-m-disabled'); }); + it('falls back to default template name when settings API fails', async () => { + api.get.mockImplementation( + ({ handleSuccess, handleError, key, ...action }) => { + if (key === GET_REPORT_TEMPLATE_SETTING) { + if (handleError) { + handleError({ message: 'Not found' }); + } + } else if (key === GET_REPORT_TEMPLATES) { + if (handleSuccess) { + handleSuccess({ + data: mockReportTemplatesResponse, + }); + } + } else if (key === GET_REPORT_TEMPLATE_INPUTS) { + if (handleSuccess) { + handleSuccess({ + data: mockReportTemplateInputsResponse, + }); + } + } + + return { type: 'get', key, ...action }; + } + ); + + const jobId = jobInvocationData.id; + + renderJobInvocationDetailPage(createJobInvocationDetailState(), { + jobId, + }); + + expect(api.get).toHaveBeenCalledWith( + expect.objectContaining({ + key: GET_REPORT_TEMPLATE_SETTING, + url: '/api/settings/remote_execution_job_invocation_report_template', + }) + ); + expect(api.get).toHaveBeenCalledWith( + expect.objectContaining({ + key: GET_REPORT_TEMPLATES, + url: '/api/report_templates', + params: expect.objectContaining({ + search: 'name="Job - Invocation Report"', + }), + }) + ); + expect(screen.getByText('Create report').getAttribute('href')).toEqual( + foremanUrl( + `/templates/report_templates/${mockReportTemplatesResponse.results[0].id}/generate?report_template_report%5Binput_values%5D%5B${mockReportTemplateInputsResponse.results[0].id}%5D%5Bvalue%5D=${jobId}` + ) + ); + }); + it('should dispatch global actions', async () => { const actualActions = jest.requireActual('../JobInvocationActions'); const { getTask } = jest.requireMock('../JobInvocationActions'); @@ -342,6 +402,12 @@ describe('JobInvocationDetailPage', () => { { jobId } ); + expect(api.get).toHaveBeenCalledWith( + expect.objectContaining({ + key: GET_REPORT_TEMPLATE_SETTING, + url: '/api/settings/remote_execution_job_invocation_report_template', + }) + ); expect(api.get).toHaveBeenCalledWith( expect.objectContaining({ key: GET_REPORT_TEMPLATES,