diff --git a/dashboards-reports/opensearch_dashboards.json b/dashboards-reports/opensearch_dashboards.json index f71795fd..648800fa 100644 --- a/dashboards-reports/opensearch_dashboards.json +++ b/dashboards-reports/opensearch_dashboards.json @@ -2,7 +2,7 @@ "id": "reportsDashboards", "version": "1.0.0.0-beta1", "opensearchDashboardsVersion": "1.0.0-beta1", - "requiredPlugins": ["navigation", "data"], + "requiredPlugins": ["navigation", "data", "opensearchDashboardsUtils"], "optionalPlugins": ["share"], "server": true, "ui": true diff --git a/dashboards-reports/public/components/context_menu/context_menu.js b/dashboards-reports/public/components/context_menu/context_menu.js index c3c4e0d2..1db0734e 100644 --- a/dashboards-reports/public/components/context_menu/context_menu.js +++ b/dashboards-reports/public/components/context_menu/context_menu.js @@ -34,6 +34,7 @@ import { displayLoadingModal, addSuccessOrFailureToast, contextMenuViewReports, + replaceQueryURL, } from './context_menu_helpers'; import { popoverMenu, @@ -42,25 +43,7 @@ import { } from './context_menu_ui'; import { timeRangeMatcher } from '../utils/utils'; import { parse } from 'url'; - -const replaceQueryURL = () => { - let url = location.pathname + location.hash; - let [, fromDateString, toDateString] = url.match(timeRangeMatcher); - fromDateString = fromDateString.replace(/[']+/g, ''); - - // convert time range to from date format in case time range is relative - const fromDateFormat = dateMath.parse(fromDateString); - toDateString = toDateString.replace(/[']+/g, ''); - const toDateFormat = dateMath.parse(toDateString); - - // replace to and from dates with absolute date - url = url.replace(fromDateString, "'" + fromDateFormat.toISOString() + "'"); - url = url.replace( - toDateString + '))', - "'" + toDateFormat.toISOString() + "'))" - ); - return url; -}; +import { unhashUrl } from '../../../../../src/plugins/opensearch_dashboards_utils/public'; const generateInContextReport = async ( timeRanges, @@ -190,21 +173,21 @@ $(function () { // generate PDF onclick $(document).on('click', '#generatePDF', function () { const timeRanges = getTimeFieldsFromUrl(); - const queryUrl = replaceQueryURL(); + const queryUrl = replaceQueryURL(location.href); generateInContextReport(timeRanges, queryUrl, 'pdf'); }); // generate PNG onclick $(document).on('click', '#generatePNG', function () { const timeRanges = getTimeFieldsFromUrl(); - const queryUrl = replaceQueryURL(); + const queryUrl = replaceQueryURL(location.href); generateInContextReport(timeRanges, queryUrl, 'png'); }); // generate CSV onclick $(document).on('click', '#generateCSV', function () { const timeRanges = getTimeFieldsFromUrl(); - const queryUrl = replaceQueryURL(); + const queryUrl = replaceQueryURL(location.href); const saved_search_id = getUuidFromUrl()[1]; generateInContextReport(timeRanges, queryUrl, 'csv', { saved_search_id }); }); diff --git a/dashboards-reports/public/components/context_menu/context_menu_helpers.js b/dashboards-reports/public/components/context_menu/context_menu_helpers.js index 6b0ba2d7..61b27fcf 100644 --- a/dashboards-reports/public/components/context_menu/context_menu_helpers.js +++ b/dashboards-reports/public/components/context_menu/context_menu_helpers.js @@ -33,6 +33,7 @@ import { permissionsMissingOnGeneration, } from './context_menu_ui'; import { timeRangeMatcher } from '../utils/utils'; +import { unhashUrl } from '../../../../../src/plugins/opensearch_dashboards_utils/public'; const getReportSourceURL = (baseURI) => { const url = baseURI.substr(0, baseURI.indexOf('?')); @@ -44,7 +45,7 @@ export const contextMenuViewReports = () => window.location.assign('reports-dashboards#/'); export const getTimeFieldsFromUrl = () => { - const url = window.location.href; + const url = unhashUrl(window.location.href); let [, fromDateString, toDateString] = url.match(timeRangeMatcher); fromDateString = fromDateString.replace(/[']+/g, ''); @@ -84,7 +85,9 @@ export const contextMenuCreateReportDefinition = (baseURI) => { }; export const displayLoadingModal = () => { - const opensearchDashboardsBody = document.getElementById('opensearch-dashboards-body'); + const opensearchDashboardsBody = document.getElementById( + 'opensearch-dashboards-body' + ); if (opensearchDashboardsBody) { try { const loadingModal = document.createElement('div'); @@ -133,3 +136,28 @@ export const addSuccessOrFailureToast = (status, reportSource) => { } } }; + +export const replaceQueryURL = (pageUrl) => { + // we unhash the url in case Kibana advanced UI setting 'state:storeInSessionStorage' is turned on + const unhashedUrl = new URL(unhashUrl(pageUrl)); + let queryUrl = unhashedUrl.pathname + unhashedUrl.hash; + let [, fromDateString, toDateString] = queryUrl.match(timeRangeMatcher); + fromDateString = fromDateString.replace(/[']+/g, ''); + + // convert time range to from date format in case time range is relative + const fromDateFormat = dateMath.parse(fromDateString); + toDateString = toDateString.replace(/[']+/g, ''); + const toDateFormat = dateMath.parse(toDateString); + + // replace to and from dates with absolute date + queryUrl = queryUrl.replace( + fromDateString, + "'" + fromDateFormat.toISOString() + "'" + ); + queryUrl = queryUrl.replace( + toDateString + '))', + "'" + toDateFormat.toISOString() + "'))" + ); + console.log(`log output queryUrl\n` + queryUrl); + return queryUrl; +}; diff --git a/dashboards-reports/public/plugin.ts b/dashboards-reports/public/plugin.ts index 707e9dd4..5fff5bda 100644 --- a/dashboards-reports/public/plugin.ts +++ b/dashboards-reports/public/plugin.ts @@ -40,10 +40,7 @@ import { PLUGIN_NAME } from '../common'; export class ReportsDashboardsPlugin implements - Plugin< - ReportsDashboardsPluginSetup, - ReportsDashboardsPluginStart - > { + Plugin { public setup(core: CoreSetup): ReportsDashboardsPluginSetup { // Register an application into the side navigation menu core.application.register({ diff --git a/dashboards-reports/server/routes/utils/__tests__/savedSearchReportHelper.test.ts b/dashboards-reports/server/routes/utils/__tests__/savedSearchReportHelper.test.ts index 332c6f53..3655a006 100644 --- a/dashboards-reports/server/routes/utils/__tests__/savedSearchReportHelper.test.ts +++ b/dashboards-reports/server/routes/utils/__tests__/savedSearchReportHelper.test.ts @@ -84,11 +84,17 @@ describe('test create saved search report', () => { }, 20000); test('create report with expected file name extension', async () => { - const csvReport = await createSavedSearchReport(input, mockOpenSearchClient([])); + const csvReport = await createSavedSearchReport( + input, + mockOpenSearchClient([]) + ); expect(csvReport.fileName).toContain('.csv'); input.report_definition.report_params.core_params.report_format = 'xlsx'; - const xlsxReport = await createSavedSearchReport(input, mockOpenSearchClient([])); + const xlsxReport = await createSavedSearchReport( + input, + mockOpenSearchClient([]) + ); expect(xlsxReport.fileName).toContain('.xlsx'); }, 20000); @@ -295,7 +301,7 @@ test('create report for data set contains null field value', async () => { hit({ category: 'c2', customer_gender: 'le' }), hit({ category: 'c3', customer_gender: null }), ]; - const client = mockEsClient(hits); + const client = mockOpenSearchClient(hits); const { dataUrl } = await createSavedSearchReport(input, client); expect(dataUrl).toEqual( diff --git a/dashboards-reports/server/routes/utils/__tests__/visualReportHelper.test.ts b/dashboards-reports/server/routes/utils/__tests__/visualReportHelper.test.ts index 2f74b68f..6bf6dc6e 100644 --- a/dashboards-reports/server/routes/utils/__tests__/visualReportHelper.test.ts +++ b/dashboards-reports/server/routes/utils/__tests__/visualReportHelper.test.ts @@ -90,7 +90,7 @@ describe('test create visual report', () => { expect(fileName).toContain(`${reportParams.report_name}`); expect(fileName).toContain('.png'); expect(dataUrl).toBeDefined(); - }, 30000); + }, 60000); test('create pdf report', async () => { expect.assertions(3); @@ -105,5 +105,5 @@ describe('test create visual report', () => { expect(fileName).toContain(`${reportParams.report_name}`); expect(fileName).toContain('.pdf'); expect(dataUrl).toBeDefined(); - }, 30000); + }, 60000); }); diff --git a/dashboards-reports/server/routes/utils/visual_report/visualReportHelper.ts b/dashboards-reports/server/routes/utils/visual_report/visualReportHelper.ts index 4177b807..22690e47 100644 --- a/dashboards-reports/server/routes/utils/visual_report/visualReportHelper.ts +++ b/dashboards-reports/server/routes/utils/visual_report/visualReportHelper.ts @@ -71,24 +71,34 @@ export const createVisualReport = async ( ? DOMPurify.sanitize(header) : DEFAULT_REPORT_HEADER; const reportFooter = footer ? DOMPurify.sanitize(footer) : ''; - + // add waitForDynamicContent function - const waitForDynamicContent = async(page, timeout = 30000, interval = 1000, checks = 5) => { - const maxChecks = timeout / interval; - let passedChecks = 0; + const waitForDynamicContent = async ( + page, + timeout = 30000, + interval = 1000, + checks = 5 + ) => { + const maxChecks = timeout / interval; + let passedChecks = 0; let previousLength = 0; - - let i=0; while(i++ <= maxChecks){ - let pageContent = await page.content(); + + let i = 0; + while (i++ <= maxChecks) { + let pageContent = await page.content(); let currentLength = pageContent.length; - - (previousLength === 0 || previousLength != currentLength) ? passedChecks = 0 : passedChecks++; - if (passedChecks >= checks) { break; } - + + previousLength === 0 || previousLength != currentLength + ? (passedChecks = 0) + : passedChecks++; + if (passedChecks >= checks) { + break; + } + previousLength = currentLength; await page.waitFor(interval); } - } + }; // set up puppeteer const browser = await puppeteer.launch({ @@ -188,7 +198,7 @@ export const createVisualReport = async ( `report source can only be one of [Dashboard, Visualization]` ); } - + // wait for dynamic page content to render await waitForDynamicContent(page);