From 71d1b6298552b3af56c42972ae4995e7227995a8 Mon Sep 17 00:00:00 2001 From: Rupal Mahajan Date: Tue, 10 Jan 2023 19:43:46 +0000 Subject: [PATCH] Backport 2.x to main (#630) * Remove odfe bwc test (#408) (#409) * removed odfe bwc test Signed-off-by: Shenoy Pratik * removed bwc test from workflows Signed-off-by: Shenoy Pratik (cherry picked from commit 556b5fb0a774534ec167dfb9e96f68855296ef75) Co-authored-by: Shenoy Pratik * Remove odfe bwc test (#408) * removed odfe bwc test Signed-off-by: Shenoy Pratik * removed bwc test from workflows Signed-off-by: Shenoy Pratik (cherry picked from commit 556b5fb0a774534ec167dfb9e96f68855296ef75) * Bump version 2.2.0 Signed-off-by: vamsi-amazon * Bump version 2.2.0 (#413) Signed-off-by: vamsi-amazon (cherry picked from commit c91534a67503e6c61ef6e1f53e852bb937f9fc14) Co-authored-by: vamsi-amazon * Release notes for 2.2.0 Signed-off-by: vamsi-amazon (cherry picked from commit f43f7de6eea93f8749eb08ce6cb248275ef78c85) * Release notes for 2.2.0 Signed-off-by: vamsi-amazon (cherry picked from commit f43f7de6eea93f8749eb08ce6cb248275ef78c85) * [2.x] Restrict chromium requests (#435) * Fix regex validation, detect iframe, embed, object tags Signed-off-by: Joshua Li * Disallow redirection to non-localhost urls Signed-off-by: Joshua Li * Disallow connection to non-allowlisted urls Signed-off-by: Joshua Li * Disable JIT Signed-off-by: Joshua Li * Fix workflow Signed-off-by: Joshua Li * Try to fix CI Signed-off-by: Joshua Li * Fix localstorage logic Signed-off-by: Joshua Li Signed-off-by: Joshua Li * [2.2] Restrict chromium requests (#431) * Fix regex validation, detect iframe, embed, object tags Signed-off-by: Joshua Li * Disallow redirection to non-localhost urls Signed-off-by: Joshua Li * Disallow connection to non-allowlisted urls Signed-off-by: Joshua Li * Disable JIT Signed-off-by: Joshua Li * Fix workflow Signed-off-by: Joshua Li * Try to fix CI Signed-off-by: Joshua Li * Fix localstorage logic Signed-off-by: Joshua Li Signed-off-by: Joshua Li * Increment version to 2.2.1-SNAPSHOT Signed-off-by: opensearch-ci-bot * Increment version to 2.3.0-SNAPSHOT Signed-off-by: opensearch-ci-bot * Added release notes for 2.2.1 release Signed-off-by: vamsi-amazon * Merge pull request #459 from mengweieric/release-notes-2.3.0 Release notes for 2.3.0 (cherry picked from commit b0c564338323056d33fddf30e70a5b0e59b69c6a) * [2.x] Upgrade puppeteer (#489) * upgrade puppeteer & change report timeout Signed-off-by: Rupal Mahajan * Change timeout Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan * Bump verison 2.4.0 (#499) Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan * add group = org.opensearch.plugin (#506) (#507) Signed-off-by: prudhvigodithi Signed-off-by: prudhvigodithi (cherry picked from commit b25984bbd9dad06e331a9b33330d6b31894f8651) Co-authored-by: Prudhvi Godithi * feat: enable windows and macos build (#504) (#511) Signed-off-by: Derek Ho * Update version for jsdom, terser and jsoup (#515) Signed-off-by: Rupal Mahajan * Fix snakeyaml vulnerability issue by disabling detekt (#517) Signed-off-by: Rupal Mahajan * Update ktlint version (#519) Signed-off-by: Rupal Mahajan * Upgrade minimatch, moment (#513) Signed-off-by: Rupal Mahajan * Revert detekt changes with upgraded version 1.21.0 (#527) Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan * Add loader-utils to resolutions (#525) Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan * Nit: add resolutions at once place (#529) (#530) Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan (cherry picked from commit 0dada242c5ab0fcc22e6d330eeaaa71bb6796b23) Co-authored-by: Rupal Mahajan * add release notes for 2.4.0.0 (#532) (#533) Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan (cherry picked from commit a1c4839c10f5737dd73b6ce3e1781d4356d1de2e) Co-authored-by: Rupal Mahajan * Bump loader-utils from 2.0.3 to 2.0.4 in /dashboards-reports (#539) (#541) Bumps [loader-utils](https://github.com/webpack/loader-utils) from 2.0.3 to 2.0.4. - [Release notes](https://github.com/webpack/loader-utils/releases) - [Changelog](https://github.com/webpack/loader-utils/blob/v2.0.4/CHANGELOG.md) - [Commits](https://github.com/webpack/loader-utils/compare/v2.0.3...v2.0.4) --- updated-dependencies: - dependency-name: loader-utils dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> (cherry picked from commit f250deb48333bb49a2cc202896eec74c2ee9ea36) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * update qs 6.5.3 (#545) Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan * Fix metrics tests and ClassNotFoundException when calling stats API (#546) Signed-off-by: Joshua Li * Use advanced settings for leading wildcards in query for csv reports (#549) * Fetch allowLeadingWildcards from config Signed-off-by: Rupal Mahajan * Fix tests Signed-off-by: Rupal Mahajan * nit Signed-off-by: Rupal Mahajan * add default value for allowLeadingWildCards Co-authored-by: Joshua Li Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan Co-authored-by: Joshua Li * Increment version to 2.5.0-SNAPSHOT (#528) Signed-off-by: opensearch-ci-bot Signed-off-by: opensearch-ci-bot Co-authored-by: opensearch-ci-bot * [1.x] Upgrade decode-uri-component (#558) (#560) * upgrade loader-utils for CVE-2022-37601 Signed-off-by: Rupal Mahajan * Update async for CVE-2021-43138 Signed-off-by: Rupal Mahajan * Fix cross-fetch for CVE-2022-1365 Signed-off-by: Rupal Mahajan * Fix for CVE-2022-37599, CVE-2022-37603 Signed-off-by: Rupal Mahajan * Update terser for CVE-2022-25858 Signed-off-by: Rupal Mahajan * Update minimatch for CVE-2022-3517 Signed-off-by: Rupal Mahajan * Update moment for CVE-2022-24785 Signed-off-by: Rupal Mahajan * Update jsdom for CVE-2021-20066 Signed-off-by: Rupal Mahajan * Update execa for GMS-2020-2 Signed-off-by: Rupal Mahajan * Update qs for CVE-2022-24999 Signed-off-by: Rupal Mahajan * Update moment for CVE-2022-31129 Signed-off-by: Rupal Mahajan * Update decode-uri-component for CVE-2022-38900 Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan (cherry picked from commit d3f36b512fe2982a2bab4d4086ad4ba6a597631a) Co-authored-by: Rupal Mahajan * Fix windows and macos CI (#569) (#571) * Update windows & mac CI for reo name change Signed-off-by: Rupal Mahajan * Fix linux build Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan (cherry picked from commit 9ce868480beff4cf21746609a5415efa225e18b8) Co-authored-by: Rupal Mahajan * Add ERR_ADDRESS_INVALID in Troubleshooting (#574) * Add workaround for ERR_ADDRESS_INVALID in doc Signed-off-by: Rupal Mahajan * nit Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan * Add release notes for 2.4.1 (#580) Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan * Remove jackson-databind and jackson-annotations (#587) * Remove jackson-databind and jackson-annotations dependencies Signed-off-by: Rupal Mahajan * resolve dompurify conflicting dependencies Signed-off-by: Rupal Mahajan * fix build Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan * Use front-end report generation instead of chromium (#586) * Increment version to 2.4.1-SNAPSHOT (#540) Signed-off-by: opensearch-ci-bot Signed-off-by: opensearch-ci-bot Co-authored-by: opensearch-ci-bot * --wip-- Signed-off-by: Joshua Li * Add initial implementation of client reporting generation Signed-off-by: Joshua Li * Fix url with basepath Signed-off-by: Joshua Li * Update header footer height Signed-off-by: Joshua Li * Update dialog text to not close dialog Signed-off-by: Joshua Li * Remove console.log Signed-off-by: Joshua Li * Remove unused components Signed-off-by: Joshua Li * Remove chromium references Signed-off-by: Joshua Li * Add report generation error handling Signed-off-by: Joshua Li * Minor refactors Signed-off-by: Joshua Li * Add postinstall patch to support safari for html2canvas Signed-off-by: Joshua Li * Add dompurify Signed-off-by: Joshua Li * Fix build error Signed-off-by: Joshua Li * Remove chromium from CI Signed-off-by: Joshua Li * Update CI artifact name Signed-off-by: Joshua Li Signed-off-by: opensearch-ci-bot Signed-off-by: Joshua Li Co-authored-by: opensearch-trigger-bot[bot] <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Co-authored-by: opensearch-ci-bot * Remove front end code (#620) * Remove frontend code Signed-off-by: Rupal Mahajan * Move one level up Signed-off-by: Rupal Mahajan * Update workflow file Signed-off-by: Rupal Mahajan * nit: remove dashboard setup from readme Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan * Remove unnecessary scripts after repo split (#622) Signed-off-by: Joshua Li * Include integration tests in windows workflow (#624) Signed-off-by: Rupal Mahajan Signed-off-by: Rupal Mahajan Signed-off-by: vamsi-amazon Signed-off-by: Joshua Li Signed-off-by: opensearch-ci-bot Signed-off-by: Eric Wei Signed-off-by: Rupal Mahajan Signed-off-by: Derek Ho Co-authored-by: opensearch-trigger-bot[bot] <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Co-authored-by: Shenoy Pratik Co-authored-by: vamsi-amazon Co-authored-by: Joshua Li Co-authored-by: opensearch-ci-bot Co-authored-by: Prudhvi Godithi Co-authored-by: Eric Wei Co-authored-by: Derek Ho Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- reports-scheduler/.classpath => .classpath | 0 .../.codecov.yml => .codecov.yml | 0 .../.editorconfig => .editorconfig | 0 .../dashboards-reports-release-workflow.yml | 115 - ...boards-reports-test-and-build-workflow.yml | 256 - ...orts-scheduler-test-and-build-workflow.yml | 30 +- .gitignore | 312 +- {reports-scheduler/.idea => .idea}/.name | 0 .../.idea => .idea}/codeStyles/Project.xml | 0 .../codeStyles/codeStyleConfig.xml | 0 .../.idea => .idea}/kotlinc.xml | 0 {reports-scheduler/.idea => .idea}/misc.xml | 0 {reports-scheduler/.idea => .idea}/vcs.xml | 0 reports-scheduler/.project => .project | 0 README.md | 52 - .../esplugin-coverage.gradle | 10 +- .../pkgbuild.gradle | 0 .../build.gradle => build.gradle | 23 +- .../checkstyle/checkstyle.xml | 0 .../checkstyle/google_checks.xml | 0 .../checkstyle/suppressions.xml | 0 .../.cypress/integration/01-create.spec.ts | 248 - .../.cypress/integration/02-edit.spec.ts | 97 - .../.cypress/integration/03-details.spec.ts | 111 - .../.cypress/integration/04-download.spec.ts | 94 - dashboards-reports/.cypress/plugins/index.js | 26 - .../.cypress/support/commands.js | 72 - .../.cypress/support/constants.js | 9 - dashboards-reports/.cypress/support/index.js | 30 - dashboards-reports/.cypress/support/utils.js | 12 - dashboards-reports/.cypress/tsconfig.json | 8 - dashboards-reports/.eslintrc | 9 - dashboards-reports/.gitignore | 13 - dashboards-reports/.i18nrc.json | 7 - dashboards-reports/.lintstagedrc | 3 - ....opensearch_dashboards-plugin-helpers.json | 12 - dashboards-reports/.prettierignore | 8 - dashboards-reports/.prettierrc | 6 - dashboards-reports/DEVELOPER_GUIDE.md | 67 - dashboards-reports/README.md | 23 - dashboards-reports/THIRD-PARTY | 203 - dashboards-reports/babel.config.js | 20 - dashboards-reports/common/index.ts | 33 - dashboards-reports/cypress.json | 17 - dashboards-reports/opensearch_dashboards.json | 10 - dashboards-reports/package.json | 79 - dashboards-reports/public/app.scss | 0 dashboards-reports/public/application.tsx | 29 - dashboards-reports/public/components/app.tsx | 150 - .../components/context_menu/context_menu.js | 361 - .../context_menu/context_menu_helpers.js | 140 - .../context_menu/context_menu_ui.js | 399 - .../__snapshots__/main.test.tsx.snap | 3908 ------- .../report_definitions_table.test.tsx.snap | 954 -- .../__snapshots__/reports_table.test.tsx.snap | 1025 -- .../__utils__/main_utils_test_utils.tsx | 122 - .../components/main/__tests__/main.test.tsx | 214 - .../main/__tests__/main_utils.test.tsx | 146 - .../report_definitions_table.test.tsx | 99 - .../main/__tests__/reports_table.test.tsx | 85 - .../public/components/main/index.ts | 7 - .../components/main/loading_modal/index.ts | 6 - .../main/loading_modal/loading_modal.tsx | 89 - .../public/components/main/main.tsx | 367 - .../public/components/main/main_utils.tsx | 226 - .../report_definition_details.test.tsx.snap | 1233 --- .../report_definition_details.test.tsx | 420 - .../report_definition_details.tsx | 837 -- .../main/report_definitions_table.tsx | 214 - .../report_details.test.tsx.snap | 760 -- .../__tests__/report_details.test.tsx | 124 - .../main/report_details/report_details.tsx | 490 - .../public/components/main/reports_table.tsx | 272 - .../create/create_report_definition.tsx | 365 - .../report_definitions/create/index.ts | 6 - .../__snapshots__/delivery.test.tsx.snap | 83 - .../delivery/__tests__/delivery.test.tsx | 106 - .../report_definitions/delivery/delivery.tsx | 358 - .../delivery/delivery_constants.tsx | 34 - .../report_definitions/delivery/index.ts | 6 - .../edit/edit_report_definition.tsx | 352 - .../report_definitions/edit/index.ts | 6 - .../report_settings.test.tsx.snap | 8471 -------------- .../__tests__/report_settings.test.tsx | 837 -- .../report_settings_helpers.test.tsx | 177 - .../report_settings/index.ts | 6 - .../report_settings/report_settings.tsx | 926 -- .../report_settings_constants.tsx | 114 - .../report_settings_helpers.tsx | 182 - .../report_settings/time_range.tsx | 229 - .../report_trigger.test.tsx.snap | 421 - .../__tests__/report_trigger.test.tsx | 380 - .../report_trigger/index.ts | 6 - .../report_trigger/report_trigger.tsx | 720 -- .../report_trigger_constants.tsx | 157 - .../report_trigger/timezone.tsx | 70 - .../report_definitions/utils/index.ts | 14 - .../report_definitions/utils/utils.tsx | 81 - .../components/utils/settings_service.ts | 31 - .../public/components/utils/utils.tsx | 31 - dashboards-reports/public/hack.js | 4 - dashboards-reports/public/index.scss | 32 - dashboards-reports/public/index.ts | 17 - dashboards-reports/public/plugin.ts | 64 - dashboards-reports/public/types.ts | 15 - .../headless-chrome/README.md | 56 - .../headless-chrome/build_headless_chrome.sh | 176 - .../backend/opensearch-reports-plugin.ts | 146 - .../server/clusters/notificationsPlugin.ts | 46 - dashboards-reports/server/config/config.ts | 63 - .../server/config/createConfig.ts | 47 - dashboards-reports/server/config/index.ts | 13 - dashboards-reports/server/config/schema.ts | 35 - dashboards-reports/server/index.ts | 25 - .../server/model/backendModel.ts | 149 - dashboards-reports/server/model/index.ts | 246 - dashboards-reports/server/plugin.ts | 118 - dashboards-reports/server/routes/index.ts | 20 - .../server/routes/lib/createReport.ts | 120 - .../routes/lib/createReportDefinition.ts | 36 - .../server/routes/lib/saveReport.ts | 52 - .../routes/lib/updateReportDefinition.ts | 40 - .../server/routes/lib/updateReportState.ts | 35 - dashboards-reports/server/routes/metric.ts | 39 - .../server/routes/notifications.ts | 142 - dashboards-reports/server/routes/report.ts | 331 - .../server/routes/reportDefinition.ts | 291 - .../server/routes/reportSource.ts | 78 - .../utils/__tests__/demo_dashboard.html | 9699 ----------------- .../utils/__tests__/metricHelper.test.ts | 28 - .../__tests__/savedSearchReportHelper.test.ts | 649 -- .../__tests__/visualReportHelper.test.ts | 80 - .../server/routes/utils/constants.ts | 308 - .../converters/__tests__/backendToUi.test.ts | 117 - .../converters/__tests__/uiToBackend.test.ts | 86 - .../routes/utils/converters/backendToUi.ts | 391 - .../routes/utils/converters/uiToBackend.ts | 155 - .../server/routes/utils/dataReportHelpers.ts | 238 - .../server/routes/utils/helpers.ts | 94 - .../server/routes/utils/metricHelper.ts | 154 - .../routes/utils/savedSearchReportHelper.ts | 264 - .../server/routes/utils/types.ts | 49 - .../utils/visual_report/footer_template.html | 5 - .../utils/visual_report/header_template.html | 5 - .../routes/utils/visual_report/style.css | 211 - .../utils/visual_report/visualReportHelper.ts | 275 - dashboards-reports/server/types.ts | 9 - .../utils/__tests__/validationHelper.test.ts | 172 - .../server/utils/validationHelper.ts | 130 - dashboards-reports/test/__mocks__/fileMock.js | 1 - .../test/__mocks__/loggerMock.ts | 17 - .../test/__mocks__/styleMock.js | 1 - dashboards-reports/test/httpMockClient.js | 39 - dashboards-reports/test/jest.config.js | 25 - dashboards-reports/test/propsMock.js | 13 - dashboards-reports/test/setup.jest.ts | 19 - dashboards-reports/test/setupTests.ts | 7 - dashboards-reports/translations/pl.json | 299 - dashboards-reports/translations/zh-CN.json | 80 - dashboards-reports/tsconfig.json | 32 - dashboards-reports/yarn.lock | 5014 --------- reports-scheduler/detekt.yml => detekt.yml | 0 .../wrapper/gradle-wrapper.jar | Bin .../wrapper/gradle-wrapper.properties | 0 reports-scheduler/gradlew => gradlew | 0 reports-scheduler/gradlew.bat => gradlew.bat | 0 .../create_release_notes.py | 0 ...ashboards-reports.release-notes-2.4.1.0.md | 9 + reports-scheduler/.gitignore | 301 - reports-scheduler/scripts/build.sh | 82 - .../settings.gradle => settings.gradle | 0 .../main/config/reports-scheduler.yml | 0 .../metrics/BasicCounter.java | 0 .../reportsscheduler/metrics/Counter.java | 0 .../reportsscheduler/metrics/Metrics.java | 0 .../metrics/RollingCounter.java | 0 .../ReportsSchedulerPlugin.kt | 0 .../action/CreateReportDefinitionAction.kt | 0 .../action/DeleteReportDefinitionAction.kt | 0 .../action/GetAllReportDefinitionsAction.kt | 0 .../action/GetAllReportInstancesAction.kt | 0 .../action/GetReportDefinitionAction.kt | 0 .../action/GetReportInstanceAction.kt | 0 .../action/InContextReportCreateAction.kt | 0 .../action/OnDemandReportCreateAction.kt | 0 .../action/PluginBaseAction.kt | 0 .../action/ReportDefinitionActions.kt | 0 .../action/ReportInstanceActions.kt | 0 .../action/UpdateReportDefinitionAction.kt | 0 .../UpdateReportInstanceStatusAction.kt | 0 .../index/ReportDefinitionsIndex.kt | 0 .../index/ReportInstancesIndex.kt | 0 .../reportsscheduler/model/BaseResponse.kt | 0 .../model/CreateReportDefinitionRequest.kt | 0 .../model/CreateReportDefinitionResponse.kt | 0 .../model/DeleteReportDefinitionRequest.kt | 0 .../model/DeleteReportDefinitionResponse.kt | 0 .../model/GetAllReportDefinitionsRequest.kt | 0 .../model/GetAllReportDefinitionsResponse.kt | 0 .../model/GetAllReportInstancesRequest.kt | 0 .../model/GetAllReportInstancesResponse.kt | 0 .../model/GetReportDefinitionRequest.kt | 0 .../model/GetReportDefinitionResponse.kt | 0 .../model/GetReportInstanceRequest.kt | 0 .../model/GetReportInstanceResponse.kt | 0 .../model/InContextReportCreateRequest.kt | 0 .../model/InContextReportCreateResponse.kt | 0 .../model/OnDemandReportCreateRequest.kt | 0 .../model/OnDemandReportCreateResponse.kt | 0 .../model/ReportDefinition.kt | 0 .../model/ReportDefinitionDetails.kt | 0 .../model/ReportDefinitionDetailsDoc.kt | 0 .../ReportDefinitionDetailsSearchResults.kt | 0 .../reportsscheduler/model/ReportInstance.kt | 0 .../model/ReportInstanceDoc.kt | 0 .../model/ReportInstanceSearchResults.kt | 0 .../reportsscheduler/model/RestTag.kt | 0 .../reportsscheduler/model/SearchResults.kt | 0 .../model/UpdateReportDefinitionRequest.kt | 0 .../model/UpdateReportDefinitionResponse.kt | 0 .../UpdateReportInstanceStatusRequest.kt | 0 .../UpdateReportInstanceStatusResponse.kt | 0 .../resthandler/OnDemandReportRestHandler.kt | 4 +- .../resthandler/PluginBaseHandler.kt | 0 .../ReportDefinitionListRestHandler.kt | 0 .../ReportDefinitionRestHandler.kt | 0 .../ReportInstanceListRestHandler.kt | 0 .../resthandler/ReportInstanceRestHandler.kt | 0 .../resthandler/ReportStatsRestHandler.kt | 0 .../RestResponseToXContentListener.kt | 0 .../scheduler/ReportDefinitionJobParser.kt | 0 .../scheduler/ReportDefinitionJobRunner.kt | 0 .../security/SecurityAccess.kt | 0 .../security/UserAccessManager.kt | 0 .../settings/PluginSettings.kt | 0 .../reportsscheduler/util/Helpers.kt | 0 .../reportsscheduler/util/OpenForTesting.kt | 0 .../util/SecureIndexClient.kt | 0 .../plugin-metadata/plugin-security.policy | 0 ...rch.jobscheduler.spi.JobSchedulerExtension | 0 .../template/email_content_template.html | 0 .../resources/notifications/template/logo.png | Bin .../resources/report-definitions-mapping.yml | 0 .../resources/report-definitions-settings.yml | 0 .../resources/report-instances-mapping.yml | 0 .../resources/report-instances-settings.yml | 0 .../metrics/BasicCounterTests.java | 6 +- .../metrics/RollingCounterTests.java | 15 +- .../opensearch/integTest/IntegTestHelpers.kt | 0 .../integTest/PluginRestTestCase.kt | 0 .../integTest/ReportsSchedulerPluginIT.kt | 0 ...eportsSchedulerBackwardsCompatibilityIT.kt | 0 .../rest/InContextMenuReportGenerationIT.kt | 0 .../rest/OnDemandReportGenerationIT.kt | 0 .../integTest/rest/ReportDefinitionIT.kt | 0 .../integTest/rest/ReportInstanceIT.kt | 0 .../reportsscheduler/TestHelpers.kt | 0 .../CreateReportDefinitionRequestTests.kt | 0 .../CreateReportDefinitionResponseTests.kt | 0 .../DeleteReportDefinitionRequestTests.kt | 0 .../DeleteReportDefinitionResponseTests.kt | 0 .../GetAllReportDefinitionsRequestTests.kt | 0 .../GetAllReportDefinitionsResponseTests.kt | 0 .../GetAllReportInstancesRequestTests.kt | 0 .../GetAllReportInstancesResponseTests.kt | 0 .../model/GetReportDefinitionRequestTests.kt | 0 .../model/GetReportDefinitionResponseTests.kt | 0 .../model/GetReportInstanceRequestTests.kt | 0 .../model/GetReportInstanceResponseTests.kt | 0 .../InContextReportCreateRequestTests.kt | 0 .../InContextReportCreateResponseTests.kt | 0 .../model/OnDemandReportCreateRequestTests.kt | 0 .../OnDemandReportCreateResponseTests.kt | 0 .../UpdateReportDefinitionRequestTests.kt | 0 .../UpdateReportDefinitionResponseTests.kt | 0 .../UpdateReportInstanceStatusRequestTests.kt | 0 ...UpdateReportInstanceStatusResponseTests.kt | 0 .../reportsscheduler/util/HelpersTests.kt | 0 .../resources/bwc/job-scheduler/.gitignore | 0 .../bwc/reports-scheduler/.gitignore | 0 .../test/resources/job-scheduler/.gitignore | 0 .../test/resources/security/sample.pem | 0 .../test/resources/security/test-kirk.jks | Bin 283 files changed, 350 insertions(+), 50030 deletions(-) rename reports-scheduler/.classpath => .classpath (100%) rename reports-scheduler/.codecov.yml => .codecov.yml (100%) rename reports-scheduler/.editorconfig => .editorconfig (100%) delete mode 100644 .github/workflows/dashboards-reports-release-workflow.yml delete mode 100644 .github/workflows/dashboards-reports-test-and-build-workflow.yml rename {reports-scheduler/.idea => .idea}/.name (100%) rename {reports-scheduler/.idea => .idea}/codeStyles/Project.xml (100%) rename {reports-scheduler/.idea => .idea}/codeStyles/codeStyleConfig.xml (100%) rename {reports-scheduler/.idea => .idea}/kotlinc.xml (100%) rename {reports-scheduler/.idea => .idea}/misc.xml (100%) rename {reports-scheduler/.idea => .idea}/vcs.xml (100%) rename reports-scheduler/.project => .project (100%) rename {reports-scheduler/build-tools => build-tools}/esplugin-coverage.gradle (83%) rename {reports-scheduler/build-tools => build-tools}/pkgbuild.gradle (100%) rename reports-scheduler/build.gradle => build.gradle (93%) rename {reports-scheduler/config => config}/checkstyle/checkstyle.xml (100%) rename {reports-scheduler/config => config}/checkstyle/google_checks.xml (100%) rename {reports-scheduler/config => config}/checkstyle/suppressions.xml (100%) delete mode 100644 dashboards-reports/.cypress/integration/01-create.spec.ts delete mode 100644 dashboards-reports/.cypress/integration/02-edit.spec.ts delete mode 100644 dashboards-reports/.cypress/integration/03-details.spec.ts delete mode 100644 dashboards-reports/.cypress/integration/04-download.spec.ts delete mode 100644 dashboards-reports/.cypress/plugins/index.js delete mode 100644 dashboards-reports/.cypress/support/commands.js delete mode 100644 dashboards-reports/.cypress/support/constants.js delete mode 100644 dashboards-reports/.cypress/support/index.js delete mode 100644 dashboards-reports/.cypress/support/utils.js delete mode 100644 dashboards-reports/.cypress/tsconfig.json delete mode 100644 dashboards-reports/.eslintrc delete mode 100644 dashboards-reports/.gitignore delete mode 100644 dashboards-reports/.i18nrc.json delete mode 100644 dashboards-reports/.lintstagedrc delete mode 100644 dashboards-reports/.opensearch_dashboards-plugin-helpers.json delete mode 100644 dashboards-reports/.prettierignore delete mode 100644 dashboards-reports/.prettierrc delete mode 100644 dashboards-reports/DEVELOPER_GUIDE.md delete mode 100644 dashboards-reports/README.md delete mode 100644 dashboards-reports/THIRD-PARTY delete mode 100644 dashboards-reports/babel.config.js delete mode 100644 dashboards-reports/common/index.ts delete mode 100644 dashboards-reports/cypress.json delete mode 100644 dashboards-reports/opensearch_dashboards.json delete mode 100644 dashboards-reports/package.json delete mode 100644 dashboards-reports/public/app.scss delete mode 100644 dashboards-reports/public/application.tsx delete mode 100644 dashboards-reports/public/components/app.tsx delete mode 100644 dashboards-reports/public/components/context_menu/context_menu.js delete mode 100644 dashboards-reports/public/components/context_menu/context_menu_helpers.js delete mode 100644 dashboards-reports/public/components/context_menu/context_menu_ui.js delete mode 100644 dashboards-reports/public/components/main/__tests__/__snapshots__/main.test.tsx.snap delete mode 100644 dashboards-reports/public/components/main/__tests__/__snapshots__/report_definitions_table.test.tsx.snap delete mode 100644 dashboards-reports/public/components/main/__tests__/__snapshots__/reports_table.test.tsx.snap delete mode 100644 dashboards-reports/public/components/main/__tests__/__utils__/main_utils_test_utils.tsx delete mode 100644 dashboards-reports/public/components/main/__tests__/main.test.tsx delete mode 100644 dashboards-reports/public/components/main/__tests__/main_utils.test.tsx delete mode 100644 dashboards-reports/public/components/main/__tests__/report_definitions_table.test.tsx delete mode 100644 dashboards-reports/public/components/main/__tests__/reports_table.test.tsx delete mode 100644 dashboards-reports/public/components/main/index.ts delete mode 100644 dashboards-reports/public/components/main/loading_modal/index.ts delete mode 100644 dashboards-reports/public/components/main/loading_modal/loading_modal.tsx delete mode 100644 dashboards-reports/public/components/main/main.tsx delete mode 100644 dashboards-reports/public/components/main/main_utils.tsx delete mode 100644 dashboards-reports/public/components/main/report_definition_details/__tests__/__snapshots__/report_definition_details.test.tsx.snap delete mode 100644 dashboards-reports/public/components/main/report_definition_details/__tests__/report_definition_details.test.tsx delete mode 100644 dashboards-reports/public/components/main/report_definition_details/report_definition_details.tsx delete mode 100644 dashboards-reports/public/components/main/report_definitions_table.tsx delete mode 100644 dashboards-reports/public/components/main/report_details/__tests__/__snapshots__/report_details.test.tsx.snap delete mode 100644 dashboards-reports/public/components/main/report_details/__tests__/report_details.test.tsx delete mode 100644 dashboards-reports/public/components/main/report_details/report_details.tsx delete mode 100644 dashboards-reports/public/components/main/reports_table.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/create/create_report_definition.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/create/index.ts delete mode 100644 dashboards-reports/public/components/report_definitions/delivery/__tests__/__snapshots__/delivery.test.tsx.snap delete mode 100644 dashboards-reports/public/components/report_definitions/delivery/__tests__/delivery.test.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/delivery/delivery.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/delivery/delivery_constants.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/delivery/index.ts delete mode 100644 dashboards-reports/public/components/report_definitions/edit/edit_report_definition.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/edit/index.ts delete mode 100644 dashboards-reports/public/components/report_definitions/report_settings/__tests__/__snapshots__/report_settings.test.tsx.snap delete mode 100644 dashboards-reports/public/components/report_definitions/report_settings/__tests__/report_settings.test.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/report_settings/__tests__/report_settings_helpers.test.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/report_settings/index.ts delete mode 100644 dashboards-reports/public/components/report_definitions/report_settings/report_settings.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/report_settings/report_settings_constants.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/report_settings/report_settings_helpers.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/report_settings/time_range.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/report_trigger/__tests__/__snapshots__/report_trigger.test.tsx.snap delete mode 100644 dashboards-reports/public/components/report_definitions/report_trigger/__tests__/report_trigger.test.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/report_trigger/index.ts delete mode 100644 dashboards-reports/public/components/report_definitions/report_trigger/report_trigger.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/report_trigger/report_trigger_constants.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/report_trigger/timezone.tsx delete mode 100644 dashboards-reports/public/components/report_definitions/utils/index.ts delete mode 100644 dashboards-reports/public/components/report_definitions/utils/utils.tsx delete mode 100644 dashboards-reports/public/components/utils/settings_service.ts delete mode 100644 dashboards-reports/public/components/utils/utils.tsx delete mode 100644 dashboards-reports/public/hack.js delete mode 100644 dashboards-reports/public/index.scss delete mode 100644 dashboards-reports/public/index.ts delete mode 100644 dashboards-reports/public/plugin.ts delete mode 100644 dashboards-reports/public/types.ts delete mode 100644 dashboards-reports/rendering-engine/headless-chrome/README.md delete mode 100644 dashboards-reports/rendering-engine/headless-chrome/build_headless_chrome.sh delete mode 100644 dashboards-reports/server/backend/opensearch-reports-plugin.ts delete mode 100644 dashboards-reports/server/clusters/notificationsPlugin.ts delete mode 100644 dashboards-reports/server/config/config.ts delete mode 100644 dashboards-reports/server/config/createConfig.ts delete mode 100644 dashboards-reports/server/config/index.ts delete mode 100644 dashboards-reports/server/config/schema.ts delete mode 100644 dashboards-reports/server/index.ts delete mode 100644 dashboards-reports/server/model/backendModel.ts delete mode 100644 dashboards-reports/server/model/index.ts delete mode 100644 dashboards-reports/server/plugin.ts delete mode 100644 dashboards-reports/server/routes/index.ts delete mode 100644 dashboards-reports/server/routes/lib/createReport.ts delete mode 100644 dashboards-reports/server/routes/lib/createReportDefinition.ts delete mode 100644 dashboards-reports/server/routes/lib/saveReport.ts delete mode 100644 dashboards-reports/server/routes/lib/updateReportDefinition.ts delete mode 100644 dashboards-reports/server/routes/lib/updateReportState.ts delete mode 100644 dashboards-reports/server/routes/metric.ts delete mode 100644 dashboards-reports/server/routes/notifications.ts delete mode 100644 dashboards-reports/server/routes/report.ts delete mode 100644 dashboards-reports/server/routes/reportDefinition.ts delete mode 100644 dashboards-reports/server/routes/reportSource.ts delete mode 100644 dashboards-reports/server/routes/utils/__tests__/demo_dashboard.html delete mode 100644 dashboards-reports/server/routes/utils/__tests__/metricHelper.test.ts delete mode 100644 dashboards-reports/server/routes/utils/__tests__/savedSearchReportHelper.test.ts delete mode 100644 dashboards-reports/server/routes/utils/__tests__/visualReportHelper.test.ts delete mode 100644 dashboards-reports/server/routes/utils/constants.ts delete mode 100644 dashboards-reports/server/routes/utils/converters/__tests__/backendToUi.test.ts delete mode 100644 dashboards-reports/server/routes/utils/converters/__tests__/uiToBackend.test.ts delete mode 100644 dashboards-reports/server/routes/utils/converters/backendToUi.ts delete mode 100644 dashboards-reports/server/routes/utils/converters/uiToBackend.ts delete mode 100644 dashboards-reports/server/routes/utils/dataReportHelpers.ts delete mode 100644 dashboards-reports/server/routes/utils/helpers.ts delete mode 100644 dashboards-reports/server/routes/utils/metricHelper.ts delete mode 100644 dashboards-reports/server/routes/utils/savedSearchReportHelper.ts delete mode 100644 dashboards-reports/server/routes/utils/types.ts delete mode 100644 dashboards-reports/server/routes/utils/visual_report/footer_template.html delete mode 100644 dashboards-reports/server/routes/utils/visual_report/header_template.html delete mode 100644 dashboards-reports/server/routes/utils/visual_report/style.css delete mode 100644 dashboards-reports/server/routes/utils/visual_report/visualReportHelper.ts delete mode 100644 dashboards-reports/server/types.ts delete mode 100644 dashboards-reports/server/utils/__tests__/validationHelper.test.ts delete mode 100644 dashboards-reports/server/utils/validationHelper.ts delete mode 100644 dashboards-reports/test/__mocks__/fileMock.js delete mode 100644 dashboards-reports/test/__mocks__/loggerMock.ts delete mode 100644 dashboards-reports/test/__mocks__/styleMock.js delete mode 100644 dashboards-reports/test/httpMockClient.js delete mode 100644 dashboards-reports/test/jest.config.js delete mode 100644 dashboards-reports/test/propsMock.js delete mode 100644 dashboards-reports/test/setup.jest.ts delete mode 100644 dashboards-reports/test/setupTests.ts delete mode 100644 dashboards-reports/translations/pl.json delete mode 100644 dashboards-reports/translations/zh-CN.json delete mode 100644 dashboards-reports/tsconfig.json delete mode 100644 dashboards-reports/yarn.lock rename reports-scheduler/detekt.yml => detekt.yml (100%) rename {reports-scheduler/gradle => gradle}/wrapper/gradle-wrapper.jar (100%) rename {reports-scheduler/gradle => gradle}/wrapper/gradle-wrapper.properties (100%) rename reports-scheduler/gradlew => gradlew (100%) rename reports-scheduler/gradlew.bat => gradlew.bat (100%) rename {reports-scheduler/release-notes => release-notes}/create_release_notes.py (100%) create mode 100644 release-notes/opensearch-dashboards-reports.release-notes-2.4.1.0.md delete mode 100644 reports-scheduler/.gitignore delete mode 100755 reports-scheduler/scripts/build.sh rename reports-scheduler/settings.gradle => settings.gradle (100%) rename {reports-scheduler/src => src}/main/config/reports-scheduler.yml (100%) rename {reports-scheduler/src => src}/main/java/org/opensearch/reportsscheduler/metrics/BasicCounter.java (100%) rename {reports-scheduler/src => src}/main/java/org/opensearch/reportsscheduler/metrics/Counter.java (100%) rename {reports-scheduler/src => src}/main/java/org/opensearch/reportsscheduler/metrics/Metrics.java (100%) rename {reports-scheduler/src => src}/main/java/org/opensearch/reportsscheduler/metrics/RollingCounter.java (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/ReportsSchedulerPlugin.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/CreateReportDefinitionAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/DeleteReportDefinitionAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/GetAllReportDefinitionsAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/GetAllReportInstancesAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/GetReportDefinitionAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/GetReportInstanceAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/InContextReportCreateAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/OnDemandReportCreateAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/PluginBaseAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/ReportDefinitionActions.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/ReportInstanceActions.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/UpdateReportDefinitionAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/action/UpdateReportInstanceStatusAction.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/index/ReportDefinitionsIndex.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/index/ReportInstancesIndex.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/BaseResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/CreateReportDefinitionRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/CreateReportDefinitionResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/DeleteReportDefinitionRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/DeleteReportDefinitionResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/GetAllReportDefinitionsRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/GetAllReportDefinitionsResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/GetAllReportInstancesRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/GetAllReportInstancesResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/GetReportDefinitionRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/GetReportDefinitionResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/GetReportInstanceRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/GetReportInstanceResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/InContextReportCreateRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/InContextReportCreateResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/OnDemandReportCreateRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/OnDemandReportCreateResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/ReportDefinition.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/ReportDefinitionDetails.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/ReportDefinitionDetailsDoc.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/ReportDefinitionDetailsSearchResults.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/ReportInstance.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/ReportInstanceDoc.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/ReportInstanceSearchResults.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/RestTag.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/SearchResults.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/UpdateReportDefinitionRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/UpdateReportDefinitionResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/UpdateReportInstanceStatusRequest.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/model/UpdateReportInstanceStatusResponse.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/resthandler/OnDemandReportRestHandler.kt (96%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/resthandler/PluginBaseHandler.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/resthandler/ReportDefinitionListRestHandler.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/resthandler/ReportDefinitionRestHandler.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/resthandler/ReportInstanceListRestHandler.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/resthandler/ReportInstanceRestHandler.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/resthandler/ReportStatsRestHandler.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/resthandler/RestResponseToXContentListener.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/scheduler/ReportDefinitionJobParser.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/scheduler/ReportDefinitionJobRunner.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/security/SecurityAccess.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/security/UserAccessManager.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/settings/PluginSettings.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/util/Helpers.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/util/OpenForTesting.kt (100%) rename {reports-scheduler/src => src}/main/kotlin/org/opensearch/reportsscheduler/util/SecureIndexClient.kt (100%) rename {reports-scheduler/src => src}/main/plugin-metadata/plugin-security.policy (100%) rename {reports-scheduler/src => src}/main/resources/META-INF/services/org.opensearch.jobscheduler.spi.JobSchedulerExtension (100%) rename {reports-scheduler/src => src}/main/resources/notifications/template/email_content_template.html (100%) rename {reports-scheduler/src => src}/main/resources/notifications/template/logo.png (100%) rename {reports-scheduler/src => src}/main/resources/report-definitions-mapping.yml (100%) rename {reports-scheduler/src => src}/main/resources/report-definitions-settings.yml (100%) rename {reports-scheduler/src => src}/main/resources/report-instances-mapping.yml (100%) rename {reports-scheduler/src => src}/main/resources/report-instances-settings.yml (100%) rename reports-scheduler/src/test/java/org/opensearch/reportsscheduler/metrics/BasicCounterTest.java => src/test/java/org/opensearch/reportsscheduler/metrics/BasicCounterTests.java (85%) rename reports-scheduler/src/test/java/org/opensearch/reportsscheduler/metrics/RollingCounterTest.java => src/test/java/org/opensearch/reportsscheduler/metrics/RollingCounterTests.java (87%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/integTest/IntegTestHelpers.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/integTest/PluginRestTestCase.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/integTest/ReportsSchedulerPluginIT.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/integTest/bwc/ReportsSchedulerBackwardsCompatibilityIT.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/integTest/rest/InContextMenuReportGenerationIT.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/integTest/rest/OnDemandReportGenerationIT.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/integTest/rest/ReportDefinitionIT.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/integTest/rest/ReportInstanceIT.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/TestHelpers.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/CreateReportDefinitionRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/CreateReportDefinitionResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/DeleteReportDefinitionRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/DeleteReportDefinitionResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/GetAllReportDefinitionsRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/GetAllReportDefinitionsResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/GetAllReportInstancesRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/GetAllReportInstancesResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/GetReportDefinitionRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/GetReportDefinitionResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/GetReportInstanceRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/GetReportInstanceResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/InContextReportCreateRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/InContextReportCreateResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/OnDemandReportCreateRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/OnDemandReportCreateResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/UpdateReportDefinitionRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/UpdateReportDefinitionResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/UpdateReportInstanceStatusRequestTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/model/UpdateReportInstanceStatusResponseTests.kt (100%) rename {reports-scheduler/src => src}/test/kotlin/org/opensearch/reportsscheduler/util/HelpersTests.kt (100%) rename {reports-scheduler/src => src}/test/resources/bwc/job-scheduler/.gitignore (100%) rename {reports-scheduler/src => src}/test/resources/bwc/reports-scheduler/.gitignore (100%) rename {reports-scheduler/src => src}/test/resources/job-scheduler/.gitignore (100%) rename {reports-scheduler/src => src}/test/resources/security/sample.pem (100%) rename {reports-scheduler/src => src}/test/resources/security/test-kirk.jks (100%) diff --git a/reports-scheduler/.classpath b/.classpath similarity index 100% rename from reports-scheduler/.classpath rename to .classpath diff --git a/reports-scheduler/.codecov.yml b/.codecov.yml similarity index 100% rename from reports-scheduler/.codecov.yml rename to .codecov.yml diff --git a/reports-scheduler/.editorconfig b/.editorconfig similarity index 100% rename from reports-scheduler/.editorconfig rename to .editorconfig diff --git a/.github/workflows/dashboards-reports-release-workflow.yml b/.github/workflows/dashboards-reports-release-workflow.yml deleted file mode 100644 index bceefb9d..00000000 --- a/.github/workflows/dashboards-reports-release-workflow.yml +++ /dev/null @@ -1,115 +0,0 @@ -name: Release OpenSearch Dashboards Reports Artifacts - -on: - push: - tags: - - "v*" - -env: - PLUGIN_NAME: reportsDashboards - ARTIFACT_NAME: reports-dashboards - OPENSEARCH_VERSION: '1.0' - OPENSEARCH_PLUGIN_VERSION: 1.0.0.0 - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_STAGING_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_STAGING_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - - name: Checkout Plugin - uses: actions/checkout@v1 - - - name: Checkout OpenSearch Dashboards - uses: actions/checkout@v1 - with: - repository: opensearch-project/Opensearch-Dashboards - ref: ${{ env.OPENSEARCH_VERSION }} - path: dashboards-reports/OpenSearch-Dashboards - - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: "10.24.1" - - - name: Move Dashboards Reports to Plugins Dir - run: mv dashboards-reports OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - - - name: Add Chromium Binary to Reporting for Testing - run: | - sudo apt install -y libnss3-dev fonts-liberation libfontconfig1 - cd OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-linux-x64.zip - unzip chromium-linux-x64.zip - rm chromium-linux-x64.zip - - - name: OpenSearch Dashboards Plugin Bootstrap - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}; yarn osd bootstrap - - - name: Test - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}; yarn test - - - name: Build Artifact and upload to S3 - run: | - cd OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - yarn build - - cd build - mkdir -p ./{linux-x64,linux-arm64,windows-x64}/OpenSearch-Dashboards/${{ env.PLUGIN_NAME }} - cp ./${{ env.PLUGIN_NAME }}-*.zip ./linux-x64/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-linux-x64.zip - cp ./${{ env.PLUGIN_NAME }}-*.zip ./linux-arm64/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-linux-arm64.zip - mv ./${{ env.PLUGIN_NAME }}-*.zip ./windows-x64/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-windows-x64.zip - - s3_prefix="s3://staging.artifacts.opendistroforelasticsearch.amazon.com/snapshots/kibana-plugins/reports/" - - cd linux-x64 - wget https://github.com/opensearch-project/dashboards-reports/releases/download/chromium-1.12.0.0/chromium-linux-x64.zip - unzip chromium-linux-x64.zip -d ./OpenSearch-Dashboards/${{ env.PLUGIN_NAME }} - rm chromium-linux-x64.zip - zip -ur ./${{ env.ARTIFACT_NAME }}-*.zip ./OpenSearch-Dashboards - linux_x64_artifact=`ls ./${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-linux-x64.zip` - - #Inject build number before the suffix and upload to S3 - linux_x64_artifact_outfile=`basename ${linux_x64_artifact%.zip}-build-${GITHUB_RUN_NUMBER}.zip` - echo "Copying $linux_x64_artifact to ${s3_prefix}${linux_x64_artifact_outfile}" - aws s3 cp --quiet $linux_x64_artifact ${s3_prefix}${linux_x64_artifact_outfile} - cd .. - - cd linux-arm64 - wget https://github.com/opensearch-project/dashboards-reports/releases/download/chromium-1.12.0.0/chromium-linux-arm64.zip - unzip chromium-linux-arm64.zip -d ./OpenSearch-Dashboards/${{ env.PLUGIN_NAME }} - rm chromium-linux-arm64.zip - zip -ur ./${{ env.ARTIFACT_NAME }}-*.zip ./OpenSearch-Dashboards - linux_arm64_artifact=`ls ./${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-linux-arm64.zip` - - #Inject build number before the suffix and upload to S3 - linux_arm64_artifact_outfile=`basename ${linux_arm64_artifact%.zip}-build-${GITHUB_RUN_NUMBER}.zip` - echo "Copying $linux_arm64_artifact to ${s3_prefix}${linux_arm64_artifact_outfile}" - aws s3 cp --quiet $linux_arm64_artifact ${s3_prefix}${linux_arm64_artifact_outfile} - cd .. - - cd windows-x64 - wget https://github.com/opensearch-project/dashboards-reports/releases/download/chromium-1.12.0.0/chromium-windows-x64.zip - unzip chromium-windows-x64.zip -d ./OpenSearch-Dashboards/${{ env.PLUGIN_NAME }} - rm chromium-windows-x64.zip - zip -ur ./${{ env.ARTIFACT_NAME }}-*.zip ./OpenSearch-Dashboards - windows_x64_artifact=`ls ./${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-windows-x64.zip` - - #Inject build number before the suffix and upload to S3 - windows_x64_artifact_outfile=`basename ${windows_x64_artifact%.zip}-build-${GITHUB_RUN_NUMBER}.zip` - echo "Copying $windows_x64_artifact to ${s3_prefix}${windows_x64_artifact_outfile}" - aws s3 cp --quiet $windows_x64_artifact ${s3_prefix}${windows_x64_artifact_outfile} diff --git a/.github/workflows/dashboards-reports-test-and-build-workflow.yml b/.github/workflows/dashboards-reports-test-and-build-workflow.yml deleted file mode 100644 index e12b2e71..00000000 --- a/.github/workflows/dashboards-reports-test-and-build-workflow.yml +++ /dev/null @@ -1,256 +0,0 @@ -name: Test and Build OpenSearch Dashboards Reports - -on: [pull_request, push] - -env: - PLUGIN_NAME: reportsDashboards - ARTIFACT_NAME: reports-dashboards - OPENSEARCH_VERSION: 'main' - OPENSEARCH_PLUGIN_VERSION: 3.0.0.0 - - -jobs: - linux-build: - runs-on: ubuntu-latest - steps: - - name: Checkout Plugin - uses: actions/checkout@v1 - - - name: Checkout OpenSearch Dashboards - uses: actions/checkout@v1 - with: - repository: opensearch-project/Opensearch-Dashboards - ref: ${{ env.OPENSEARCH_VERSION }} - path: OpenSearch-Dashboards - - - name: Get node version - id: versions_step - run: - echo "::set-output name=node_version::$(node -p "(require('../OpenSearch-Dashboards/package.json').engines.node).match(/[.0-9]+/)[0]")" - - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: ${{ steps.versions_step.outputs.node_version }} - registry-url: 'https://registry.npmjs.org' - - - - name: Move Dashboards Reports to Plugins Dir - run: mv dashboards-reports ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - - - name: Add Chromium Binary to Reporting for Testing - run: | - sudo apt update - sudo apt install -y libnss3-dev fonts-liberation libfontconfig1 - cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-linux-x64.zip - unzip chromium-linux-x64.zip - rm chromium-linux-x64.zip - - - name: OpenSearch Dashboards Plugin Bootstrap - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}; yarn osd bootstrap - - - name: Test - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}; yarn test --coverage - - - name: Upload coverage - uses: codecov/codecov-action@v1 - with: - flags: dashboards-reports - directory: ../OpenSearch-Dashboards/plugins/ - token: ${{ secrets.CODECOV_TOKEN }} - - - name: Build Artifact - run: | - cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - yarn build - - cd build - mkdir -p ./{linux-x64,linux-arm64}/opensearch-dashboards/${{ env.PLUGIN_NAME }} - cp ./${{ env.PLUGIN_NAME }}-*.zip ./linux-x64/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-linux-x64.zip - cp ./${{ env.PLUGIN_NAME }}-*.zip ./linux-arm64/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-linux-arm64.zip - - cd linux-x64 - wget https://github.com/opensearch-project/dashboards-reports/releases/download/chromium-1.12.0.0/chromium-linux-x64.zip - unzip chromium-linux-x64.zip -d ./opensearch-dashboards/${{ env.PLUGIN_NAME }} - zip -ur ./${{ env.ARTIFACT_NAME }}-*.zip ./opensearch-dashboards - mv ./${{ env.ARTIFACT_NAME }}-*.zip .. - cd .. - - cd linux-arm64 - wget https://github.com/opensearch-project/dashboards-reports/releases/download/chromium-1.12.0.0/chromium-linux-arm64.zip - unzip chromium-linux-arm64.zip -d ./opensearch-dashboards/${{ env.PLUGIN_NAME }} - zip -ur ./${{ env.ARTIFACT_NAME }}-*.zip ./opensearch-dashboards - mv ./${{ env.ARTIFACT_NAME }}-*.zip .. - cd .. - - - name: Upload Artifact For Linux x64 - uses: actions/upload-artifact@v1 - with: - name: dashboards-reports-linux-x64 - path: ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}/build/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-linux-x64.zip - - - name: Upload Artifact For Linux arm64 - uses: actions/upload-artifact@v1 - with: - name: dashboards-reports-linux-arm64 - path: ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}/build/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-linux-arm64.zip - - windows-build: - runs-on: windows-latest - steps: - - name: Checkout Plugin - uses: actions/checkout@v1 - - # Enable longer filenames for windows - - name: Enable longer filenames - run: git config --system core.longpaths true - - - name: Checkout OpenSearch Dashboards - uses: actions/checkout@v1 - with: - repository: opensearch-project/Opensearch-Dashboards - ref: ${{ env.OPENSEARCH_VERSION }} - path: OpenSearch-Dashboards - - - name: Get node version - id: versions_step - run: - echo "::set-output name=node_version::$(node -p "(require('../OpenSearch-Dashboards/package.json').engines.node).match(/[.0-9]+/)[0]")" - - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: ${{ steps.versions_step.outputs.node_version }} - registry-url: 'https://registry.npmjs.org' - - - - name: Move Dashboards Reports to Plugins Dir - run: mv dashboards-reports ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - - - name: Add Chromium Binary to Reporting for Testing - run: | - cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - curl.exe -LO https://github.com/opensearch-project/dashboards-reports/releases/download/chromium-1.12.0.0/chromium-windows-x64.zip - Expand-Archive -Path 'chromium-windows-x64.zip' - Move-Item -Path "./chromium-windows-x64/.chromium" -Destination "./.chromium" - rd chromium-windows-x64.zip - rd chromium-windows-x64 - - - name: OpenSearch Dashboards Plugin Bootstrap - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} && yarn osd bootstrap - - - name: Test - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} && yarn test - - - name: Build Artifact - run: | - cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - yarn build - - cd build - mkdir -p ./windows-x64/opensearch-dashboards/${{ env.PLUGIN_NAME }} - mv ./${{ env.PLUGIN_NAME }}-*.zip ./windows-x64/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-windows-x64.zip - - cd windows-x64 - curl.exe -LO https://github.com/opensearch-project/dashboards-reports/releases/download/chromium-1.12.0.0/chromium-windows-x64.zip - Expand-Archive -Path 'chromium-windows-x64.zip' - Move-Item -Path "./chromium-windows-x64/.chromium" -Destination "./opensearch-dashboards/${{ env.PLUGIN_NAME }}" - rd chromium-windows-x64.zip - rd chromium-windows-x64 - Compress-Archive -Path "./${{ env.ARTIFACT_NAME }}-*.zip" -Destination "./opensearch-dashboards" - mv ./${{ env.ARTIFACT_NAME }}-*.zip .. - cd .. - - - name: Upload Artifact For Windows - uses: actions/upload-artifact@v1 - with: - name: dashboards-reports-windows-x64 - path: ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}/build/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-windows-x64.zip - - macos-build: - runs-on: macos-latest - steps: - - name: Checkout Plugin - uses: actions/checkout@v1 - - - name: Checkout OpenSearch Dashboards - uses: actions/checkout@v1 - with: - repository: opensearch-project/Opensearch-Dashboards - ref: ${{ env.OPENSEARCH_VERSION }} - path: OpenSearch-Dashboards - - - name: Get node version - id: versions_step - run: - echo "::set-output name=node_version::$(node -p "(require('../OpenSearch-Dashboards/package.json').engines.node).match(/[.0-9]+/)[0]")" - - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: ${{ steps.versions_step.outputs.node_version }} - registry-url: 'https://registry.npmjs.org' - - - - name: Move Dashboards Reports to Plugins Dir - run: mv dashboards-reports ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - - - name: Add Chromium Binary to Reporting for Testing - run: | - cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-macos-x64.zip - unzip chromium-macos-x64.zip - rm chromium-macos-x64.zip - - - name: OpenSearch Dashboards Plugin Bootstrap - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}; yarn osd bootstrap - - - name: Test - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}; yarn test - - - name: Build Artifact - run: | - cd ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }} - yarn build - - cd build - mkdir -p ./macos-x64/opensearch-dashboards/${{ env.PLUGIN_NAME }} - mv ./${{ env.PLUGIN_NAME }}-*.zip ./macos-x64/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-macos-x64.zip - - cd macos-x64 - wget https://github.com/opensearch-project/dashboards-reports/releases/download/chromium-1.12.0.0/chromium-macos-x64.zip - unzip chromium-macos-x64.zip -d ./opensearch-dashboards/${{ env.PLUGIN_NAME }} - zip -ur ./${{ env.ARTIFACT_NAME }}-*.zip ./opensearch-dashboards - mv ./${{ env.ARTIFACT_NAME }}-*.zip .. - cd .. - - - name: Upload Artifact For MacOS x64 - uses: actions/upload-artifact@v1 - with: - name: dashboards-reports-macosx-x64 - path: ../OpenSearch-Dashboards/plugins/${{ env.PLUGIN_NAME }}/build/${{ env.ARTIFACT_NAME }}-${{ env.OPENSEARCH_PLUGIN_VERSION }}-macos-x64.zip diff --git a/.github/workflows/reports-scheduler-test-and-build-workflow.yml b/.github/workflows/reports-scheduler-test-and-build-workflow.yml index 01576aa1..acf27f15 100644 --- a/.github/workflows/reports-scheduler-test-and-build-workflow.yml +++ b/.github/workflows/reports-scheduler-test-and-build-workflow.yml @@ -17,19 +17,16 @@ jobs: with: java-version: ${{ matrix.java }} - # reports-scheduler - name: Checkout Reports Scheduler uses: actions/checkout@v2 - name: RunBackwards Compatibility Tests run: | - cd reports-scheduler echo "Running backwards compatibility tests ..." ./gradlew bwcTestSuite - name: Build with Gradle run: | - cd reports-scheduler ./gradlew build - name: Upload coverage @@ -42,7 +39,7 @@ jobs: - name: Create Artifact Path run: | mkdir -p reports-scheduler-builds - cp -r ./reports-scheduler/build/distributions/*.zip reports-scheduler-builds/ + cp -r ./build/distributions/*.zip reports-scheduler-builds/ - name: Upload Artifacts uses: actions/upload-artifact@v1 @@ -64,26 +61,17 @@ jobs: with: java-version: ${{ matrix.java }} - # reports-scheduler - name: Checkout Reports Scheduler uses: actions/checkout@v2 - # Disable bwc tests since first release - # - name: RunBackwards Compatibility Tests - # run: | - # cd reports-scheduler - # echo "Running backwards compatibility tests ..." - # ./gradlew.bat bwcTestSuite - - name: Build with Gradle run: | - cd reports-scheduler - ./gradlew.bat build -x integTest -x jacocoTestReport + ./gradlew.bat build - name: Create Artifact Path run: | mkdir -p reports-scheduler-builds - cp -r ./reports-scheduler/build/distributions/*.zip reports-scheduler-builds/ + cp -r ./build/distributions/*.zip reports-scheduler-builds/ - name: Upload Artifacts uses: actions/upload-artifact@v1 @@ -109,22 +97,14 @@ jobs: - name: Checkout Reports Scheduler uses: actions/checkout@v2 - # Disable bwc tests since first release - # - name: RunBackwards Compatibility Tests - # run: | - # cd reports-scheduler - # echo "Running backwards compatibility tests ..." - # ./gradlew bwcTestSuite - - name: Build with Gradle run: | - cd reports-scheduler - ./gradlew build -x integTest -x jacocoTestReport + ./gradlew build - name: Create Artifact Path run: | mkdir -p reports-scheduler-builds - cp -r ./reports-scheduler/build/distributions/*.zip reports-scheduler-builds/ + cp -r ./build/distributions/*.zip reports-scheduler-builds/ - name: Upload Artifacts uses: actions/upload-artifact@v1 diff --git a/.gitignore b/.gitignore index 77852916..8c03270c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,19 +3,313 @@ *.iml .gradle out -local-test -.local-* - -npm-debug.log* -node_modules /build/ /public/app.css -.idea/ -.vscode/ -yarn-error.log /coverage/ .history/ .eslintcache # Kibana -.empty \ No newline at end of file +.empty + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Kotlin ### +# Compiled class file + +# Log file + +# BlueJ files + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml + +### Gradle ### +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### Gradle Patch ### +**/build/ + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +.idea/artifacts +.idea/compiler.xml +.idea/jarRepositories.xml +.idea/modules.xml +.idea/*.iml +.idea/modules +*.iml +*.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# AWS plugin +.idea/aws.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + + +### Eclipse ### +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project + +### Eclipse Patch ### +# Spring Boot Tooling +.sts4-cache/ + +local-test +.local-* + +/artifacts/ diff --git a/reports-scheduler/.idea/.name b/.idea/.name similarity index 100% rename from reports-scheduler/.idea/.name rename to .idea/.name diff --git a/reports-scheduler/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml similarity index 100% rename from reports-scheduler/.idea/codeStyles/Project.xml rename to .idea/codeStyles/Project.xml diff --git a/reports-scheduler/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml similarity index 100% rename from reports-scheduler/.idea/codeStyles/codeStyleConfig.xml rename to .idea/codeStyles/codeStyleConfig.xml diff --git a/reports-scheduler/.idea/kotlinc.xml b/.idea/kotlinc.xml similarity index 100% rename from reports-scheduler/.idea/kotlinc.xml rename to .idea/kotlinc.xml diff --git a/reports-scheduler/.idea/misc.xml b/.idea/misc.xml similarity index 100% rename from reports-scheduler/.idea/misc.xml rename to .idea/misc.xml diff --git a/reports-scheduler/.idea/vcs.xml b/.idea/vcs.xml similarity index 100% rename from reports-scheduler/.idea/vcs.xml rename to .idea/vcs.xml diff --git a/reports-scheduler/.project b/.project similarity index 100% rename from reports-scheduler/.project rename to .project diff --git a/README.md b/README.md index d9d4d8fa..684716a7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ - [Contributing](#contributing) - [Setup](#setup-&-build) - [Notifications Integration](#notifications-integration) -- [Troubleshooting](#troubleshooting) - [Code of Conduct](#code-of-conduct) - [Security](#security) - [License](#license) @@ -27,13 +26,6 @@ OpenSearch Dashboards Reports allows ‘Report Owner’ (engineers, including bu | Distribution build tests | [![OpenSearch IT tests][reports-scheduler-it-badge]][reports-scheduler-it-link] [![OpenSearch IT code][reports-scheduler-it-code-badge]][reports-scheduler-it-code-link] | | Backward compatibility tests | [![BWC tests][bwc-tests-badge]][bwc-tests-link] | -### Dashboard-Reports - -| | | -| ------------------------ | ------------------------------------------------------------------------------------------------------------------ | -| Test and build | [![Observability Dashboards CI][dashboard-reports-build-badge]][dashboard-reports-build-link] | -| Code coverage | [![codecov][dashboard-reports-codecov-badge]][codecov-link] | -| Distribution build tests | [![cypress tests][cypress-test-badge]][cypress-test-link] [![cypress code][cypress-code-badge]][cypress-code-link] | ### Repository Checks @@ -57,11 +49,8 @@ OpenSearch Dashboards Reports allows ‘Report Owner’ (engineers, including bu [dco-badge-link]: https://github.com/opensearch-project/dashboards-reports/actions/workflows/dco.yml [link-check-badge]: https://github.com/opensearch-project/dashboards-reports/actions/workflows/link-checker.yml/badge.svg [link-check-link]: https://github.com/opensearch-project/dashboards-reports/actions/workflows/link-checker.yml -[dashboard-reports-build-badge]: https://github.com/opensearch-project/dashboards-reports/actions/workflows/dashboards-reports-test-and-build-workflow.yml/badge.svg -[dashboard-reports-build-link]: https://github.com/opensearch-project/dashboards-reports/actions/workflows/dashboards-reports-test-and-build-workflow.yml [reports-scheduler-build-badge]: https://github.com/opensearch-project/dashboards-reports/actions/workflows/reports-scheduler-test-and-build-workflow.yml/badge.svg [reports-scheduler-build-link]: https://github.com/opensearch-project/dashboards-reports/actions/workflows/reports-scheduler-test-and-build-workflow.yml -[dashboard-reports-codecov-badge]: https://codecov.io/gh/opensearch-project/dashboards-reports/branch/main/graphs/badge.svg?flag=dashboards-reports [reports-scheduler-codecov-badge]: https://codecov.io/gh/opensearch-project/dashboards-reports/branch/main/graphs/badge.svg?flag=reports-scheduler [codecov-link]: https://codecov.io/gh/opensearch-project/dashboards-reports [cypress-test-badge]: https://img.shields.io/badge/Cypress%20tests-in%20progress-yellow @@ -95,50 +84,10 @@ Please see our technical [documentation](https://opensearch.org/docs/dashboards/ We welcome you to get involved in development, documentation, testing the OpenSearch Dashboards reports plugin. See our [CONTRIBUTING.md](./CONTRIBUTING.md) and join in. -## Setup & Build - -Complete OpenSearch Dashboards Report feature is composed of 2 plugins. - -- [OpenSearch Dashboards reports plugin](./dashboards-reports/README.md) -- OpenSearch Reports scheduler plugin - ## Notifications Integration OpenSearch Dashboards Reports integration with [Notifications](https://github.com/opensearch-project/notifications) is currently in progress. Tracking [here](https://github.com/opensearch-project/dashboards-reports/issues/72) -## Troubleshooting - -### Fail to launch Chromium - -There could be two reasons for this problem - -1. You are not having the correct version of headless-chrome matching to the OS that your OpenSearch Dashboards is running. Different versions of headless-chrome can be found [here](https://github.com/opensearch-project/dashboards-reports/releases/tag/chromium-1.12.0.0) - -2. Missing additional dependencies. Please refer to [additional dependencies section](./dashboards-reports/rendering-engine/headless-chrome/README.md#additional-libaries) to install required dependencies according to your operating system. - -### Missing Font Dependencies - -Chromium may not have all of the dependencies you may require to be able to view all of the content of your reports. - -If you are using a CentOS/RHEL system, install the following packages: - -- [`ipa-gothic-fonts`](https://centos.pkgs.org/7/centos-x86_64/ipa-gothic-fonts-003.03-5.el7.noarch.rpm.html) -- [`xorg-x11-fonts-100dpi`](https://centos.pkgs.org/7/centos-x86_64/xorg-x11-fonts-100dpi-7.5-9.el7.noarch.rpm.html) -- [`xorg-x11-fonts-75dpi`](https://centos.pkgs.org/7/centos-x86_64/xorg-x11-fonts-75dpi-7.5-9.el7.noarch.rpm.html) -- [`xorg-x11-utils`](https://centos.pkgs.org/7/centos-x86_64/xorg-x11-utils-7.5-23.el7.x86_64.rpm.html) -- [`xorg-x11-fonts-cyrillic`](https://centos.pkgs.org/7/centos-x86_64/xorg-x11-fonts-cyrillic-7.5-9.el7.noarch.rpm.html) -- [`xorg-x11-fonts-Type1`](https://centos.pkgs.org/7/centos-x86_64/xorg-x11-fonts-Type1-7.5-9.el7.noarch.rpm.html) -- [`xorg-x11-fonts-misc`](https://centos.pkgs.org/7/centos-x86_64/xorg-x11-fonts-misc-7.5-9.el7.noarch.rpm.html) -- [`fontconfig`](https://www.freedesktop.org/wiki/Software/fontconfig/) -- [`freetype`](https://freetype.org/) - -If you are using a Ubuntu/Debian system, install the following packages: - -- [`fonts-liberation`](https://packages.debian.org/search?keywords=fonts-liberation) -- [`libfontconfig1`](https://packages.debian.org/sid/libfontconfig1) - -The installation command for both systems can be found [here](./dashboards-reports/rendering-engine/headless-chrome/README.md). - ## Code of Conduct This project has adopted the [Amazon Open Source Code of Conduct](CODE_OF_CONDUCT.md). For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq), or contact [opensource-codeofconduct@amazon.com](mailto:opensource-codeofconduct@amazon.com) with any additional questions or comments. @@ -153,4 +102,3 @@ See the [LICENSE](./LICENSE) file for our project's licensing. We will ask you t ## Copyright -Copyright OpenSearch Contributors. See [NOTICE](NOTICE.txt) for details. diff --git a/reports-scheduler/build-tools/esplugin-coverage.gradle b/build-tools/esplugin-coverage.gradle similarity index 83% rename from reports-scheduler/build-tools/esplugin-coverage.gradle rename to build-tools/esplugin-coverage.gradle index 31be46fd..3e8815fe 100644 --- a/reports-scheduler/build-tools/esplugin-coverage.gradle +++ b/build-tools/esplugin-coverage.gradle @@ -17,6 +17,9 @@ * break if there are multiple nodes in the integTestCluster. But for now... it sorta works. */ +import org.apache.tools.ant.taskdefs.condition.Os +apply plugin: 'jacoco' + // Get gradle to generate the required jvm agent arg for us using a dummy tasks of type Test. Unfortunately Elastic's // testing tasks don't derive from Test so the jacoco plugin can't do this automatically. def jacocoDir = "${buildDir}/jacoco" @@ -61,7 +64,12 @@ allprojects{ jacocoTestReport.dependsOn integTest testClusters.integTest { - jvmArgs " ${dummyIntegTest.jacoco.getAsJvmArg()}".replace('javaagent:','javaagent:/') + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + // Replacing build with absolute path to fix the error "error opening zip file or JAR manifest missing : /build/tmp/expandedArchives/..../jacocoagent.jar" + jvmArgs " ${dummyIntegTest.jacoco.getAsJvmArg()}".replace('build',"${buildDir}") + } else { + jvmArgs " ${dummyIntegTest.jacoco.getAsJvmArg()}".replace('javaagent:','javaagent:/') + } systemProperty 'com.sun.management.jmxremote', "true" systemProperty 'com.sun.management.jmxremote.authenticate', "false" systemProperty 'com.sun.management.jmxremote.port', "7777" diff --git a/reports-scheduler/build-tools/pkgbuild.gradle b/build-tools/pkgbuild.gradle similarity index 100% rename from reports-scheduler/build-tools/pkgbuild.gradle rename to build-tools/pkgbuild.gradle diff --git a/reports-scheduler/build.gradle b/build.gradle similarity index 93% rename from reports-scheduler/build.gradle rename to build.gradle index 95d35840..9d5fe36c 100644 --- a/reports-scheduler/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ buildscript { } common_utils_version = System.getProperty("common_utils.version", opensearch_build) - job_scheduler_version = System.getProperty("job_scheduler.version", opensearch_build) + job_scheduler_version = System.getProperty("job_scheduler.version", opensearch_build) kotlin_version = System.getProperty("kotlin.version", "1.6.0") } @@ -164,7 +164,9 @@ dependencies { compileOnly "${group}:opensearch-job-scheduler-spi:${job_scheduler_version}" implementation group: 'com.google.guava', name: 'guava', version: '31.0.1-jre' implementation "org.json:json:20180813" - implementation group: 'com.github.wnameless', name: 'json-flattener', version: '0.1.0' + implementation group: 'com.github.wnameless.json', name: 'json-flattener', version: '0.15.1' + // json-base is transitive dependencies by json-flattener + implementation group: 'com.github.wnameless.json', name: 'json-base', version: '2.2.1' implementation 'org.jsoup:jsoup:1.15.3' implementation 'com.google.code.gson:gson:2.8.9' implementation "org.jetbrains.kotlin:kotlin-test:${kotlin_version}" @@ -174,11 +176,12 @@ dependencies { 'org.junit.jupiter:junit-jupiter-api:5.6.2' ) testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.6.2') - testCompile "org.opensearch.test:framework:${opensearch_version}" - testCompile "org.jetbrains.kotlin:kotlin-test:${kotlin_version}" + testImplementation "org.opensearch.test:framework:${opensearch_version}" + testImplementation "org.jetbrains.kotlin:kotlin-test:${kotlin_version}" testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" - testCompile "org.mockito:mockito-core:3.12.4" - testCompile 'com.google.code.gson:gson:2.8.9' + testImplementation "org.mockito:mockito-core:4.7.0" + testImplementation "org.mockito:mockito-junit-jupiter:4.7.0" + testImplementation 'com.google.code.gson:gson:2.8.9' ktlint "com.pinterest:ktlint:0.45.1" } @@ -570,12 +573,6 @@ task updateVersion { println "Setting version to ${newVersion}." // String tokenization to support -SNAPSHOT ant.replaceregexp(file:'build.gradle', match: '"opensearch.version", "\\d.*"', replace: '"opensearch.version", "' + newVersion.tokenize('-')[0] + '-SNAPSHOT"', flags:'g', byline:true) - ant.replaceregexp(file:'../.github/workflows/dashboards-reports-test-and-build-workflow.yml', match:'OPENSEARCH_PLUGIN_VERSION: \\d+.\\d+.\\d+.\\d+', replace:'OPENSEARCH_PLUGIN_VERSION: ' + newVersion.tokenize('-')[0] + '.0', flags:'g', byline:true) - ant.replaceregexp(file:'../.github/workflows/draft-release-notes-workflow.yml', match:'version: \\d+.\\d+.\\d+.\\d+', replace:'version: ' + newVersion.tokenize('-')[0] + '.0', flags:'g', byline:true) - // Match key version in JSON files. - ant.replaceregexp(file:'../dashboards-reports/opensearch_dashboards.json', match:'"version": "\\d+.\\d+.\\d+.\\d+', replace:'"version": ' + '"' + newVersion.tokenize('-')[0] + '.0', flags:'g', byline:true) - ant.replaceregexp(file:'../dashboards-reports/package.json', match:'"version": "\\d+.\\d+.\\d+.\\d+', replace:'"version": ' + '"' + newVersion.tokenize('-')[0] + '.0', flags:'g', byline:true) - // Match key opensearchDashboardsVersion in JSON files. - ant.replaceregexp(file:'../dashboards-reports/opensearch_dashboards.json', match:'"opensearchDashboardsVersion": "\\d+.\\d+.\\d+', replace:'"opensearchDashboardsVersion": ' + '"' + newVersion.tokenize('-')[0], flags:'g', byline:true) + ant.replaceregexp(file:'./.github/workflows/draft-release-notes-workflow.yml', match:'version: \\d+.\\d+.\\d+.\\d+', replace:'version: ' + newVersion.tokenize('-')[0] + '.0', flags:'g', byline:true) } } diff --git a/reports-scheduler/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml similarity index 100% rename from reports-scheduler/config/checkstyle/checkstyle.xml rename to config/checkstyle/checkstyle.xml diff --git a/reports-scheduler/config/checkstyle/google_checks.xml b/config/checkstyle/google_checks.xml similarity index 100% rename from reports-scheduler/config/checkstyle/google_checks.xml rename to config/checkstyle/google_checks.xml diff --git a/reports-scheduler/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml similarity index 100% rename from reports-scheduler/config/checkstyle/suppressions.xml rename to config/checkstyle/suppressions.xml diff --git a/dashboards-reports/.cypress/integration/01-create.spec.ts b/dashboards-reports/.cypress/integration/01-create.spec.ts deleted file mode 100644 index d047aeff..00000000 --- a/dashboards-reports/.cypress/integration/01-create.spec.ts +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { visitReportingLandingPage } from "../support/utils"; - -describe('Adding sample data', () => { - it('Adds sample data', () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/home#/tutorial_directory/sampleData`); - cy.get('div[data-test-subj="sampleDataSetCardflights"]').contains(/(Add|View) data/).click(); - cy.wait(3000); - cy.visit(`${Cypress.env('opensearchDashboards')}/app/home#/tutorial_directory/sampleData`); - cy.get('div[data-test-subj="sampleDataSetCardecommerce"]').contains(/(Add|View) data/).click(); - cy.wait(3000); - cy.visit(`${Cypress.env('opensearchDashboards')}/app/home#/tutorial_directory/sampleData`); - cy.get('div[data-test-subj="sampleDataSetCardlogs"]').contains(/(Add|View) data/).click(); - cy.wait(3000); - }); -}); - -describe('Cypress', () => { - it('Visits Reporting homepage', () => { - visitReportingLandingPage(); - }); - - it('Visit Create page', () => { - visitCreateReportDefinitionPage(); - }); - - it('Create a new on-demand dashboard report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress dashboard on-demand report'); - setReportDefinitionDescription('Description for cypress test'); - selectReportSourceComboBox(); - - // // select drop-down option in report source list - cy.contains('[Logs] Web Traffic').click(); - - cy.wait(500); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a new on-demand visualization report definition', ()=> { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress vis on-demand report'); - setReportDefinitionDescription('Description for cypress test'); - selectReportSource('#visualizationReportSource'); - selectReportSourceComboBox(); - cy.wait(500); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a new on-demand saved search report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress saved search on-demand report'); - setReportDefinitionDescription('Description for cypress test'); - selectReportSource('#savedSearchReportSource'); - selectReportSourceComboBox(); - cy.wait(500); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a new dashboard daily recurring report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress dashboard daily scheduled report'); - setReportDefinitionDescription('Description for cypress test'); - selectReportSourceComboBox(); - - // select drop-down option in report source list - cy.contains('[Logs] Web Traffic').click(); - - cy.wait(500); - setReportTriggerToSchedule(); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a new visualization daily recurring report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress vis daily scheduled report'); - setReportDefinitionDescription('Description for cypress test'); - selectReportSource('#visualizationReportSource'); - selectReportSourceComboBox(); - cy.wait(500); - setReportTriggerToSchedule(); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a new saved search daily recurring report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress search daily scheduled report'); - setReportDefinitionDescription('Description for cypress test'); - selectReportSource('#savedSearchReportSource'); - selectReportSourceComboBox(); - setReportTriggerToSchedule(); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a new dashboard interval recurring report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress dashboard recurring report'); - setReportDefinitionDescription('Description for cypress test'); - selectReportSourceComboBox(); - - // select drop-down option in report source list - cy.contains('[Logs] Web Traffic').click(); - - cy.wait(500); - setReportTriggerToSchedule(); - selectIntervalScheduleFrequency(); - inputTextIntoField('#recurringByIntervalNumber', '5'); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a new visualization interval recurring report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress vis interval recurring report'); - selectReportSource('#visualizationReportSource'); - selectReportSourceComboBox(); - setReportTriggerToSchedule(); - selectIntervalScheduleFrequency(); - inputTextIntoField('#recurringByIntervalNumber', '5'); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a new saved search interval recurring report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress saved search interval recurring report'); - selectReportSource('#savedSearchReportSource'); - selectReportSourceComboBox(); - setReportTriggerToSchedule(); - selectIntervalScheduleFrequency(); - inputTextIntoField('#recurringByIntervalNumber', '5'); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a dashboard cron-based report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress dashboard cron definition'); - selectReportSourceComboBox(); - - // select drop-down option in report source list - cy.contains('[Logs] Web Traffic').click(); - cy.wait(500); - setReportTriggerToSchedule(); - selectCronBasedRequestTime(); - inputTextIntoField('#cronExpressionFieldText', '0 12 * * *'); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a visualization cron-based report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress vis cron definition'); - selectReportSource('#visualizationReportSource'); - selectReportSourceComboBox(); - setReportTriggerToSchedule(); - selectCronBasedRequestTime(); - inputTextIntoField('#cronExpressionFieldText', '0 12 * * *'); - cy.wait(500); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); - - it('Create a saved search cron-based report definition', () => { - visitCreateReportDefinitionPage(); - setReportDefinitionName('Cypress search cron definition'); - selectReportSource('#savedSearchReportSource'); - selectReportSourceComboBox(); - setReportTriggerToSchedule(); - selectCronBasedRequestTime(); - inputTextIntoField('#cronExpressionFieldText', '0 12 * * *'); - cy.wait(500); - clickCreateReportDefinitionButton(); - cy.wait(3000); - verifyOnReportingLandingPage(); - }); -}); - -function visitCreateReportDefinitionPage() { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/reports-dashboards#/`); - cy.location('pathname', { timeout: 60000 }).should( - 'include', - '/reports-dashboards' - ); - cy.wait(3000); - cy.get('#createReportHomepageButton').click(); -} - -function setReportDefinitionName(name: string) { - cy.get('#reportSettingsName').type(name); -} - -function setReportDefinitionDescription(description: string) { - cy.get('#reportSettingsDescription').type(description); -} - -function selectReportSource(name: string) { - cy.get(name).click({force: true}); -} - -function selectReportSourceComboBox() { - cy.get('[data-test-subj="comboBoxInput"]').eq(0).click({ force: true }); -} - -function setReportTriggerToSchedule() { - cy.get('#Schedule').check({ force: true }); -} - -function selectIntervalScheduleFrequency() { - cy.get('#recurringFrequencySelect').select('By interval'); -} - -function selectCronBasedRequestTime() { - cy.contains('Cron based').click({ force: true }); -} - -function inputTextIntoField(selector: string, text: string) { - cy.get(selector).type(text); -} - -function clickCreateReportDefinitionButton() { - cy.get('#createNewReportDefinition').click({ force: true }); -} - -function verifyOnReportingLandingPage() { - cy.get('#reportDefinitionDetailsLink').should('exist'); -} \ No newline at end of file diff --git a/dashboards-reports/.cypress/integration/02-edit.spec.ts b/dashboards-reports/.cypress/integration/02-edit.spec.ts deleted file mode 100644 index a87e77d4..00000000 --- a/dashboards-reports/.cypress/integration/02-edit.spec.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -describe('Cypress', () => { - it('Visit edit page, update name and description', () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/reports-dashboards#/`); - cy.location('pathname', { timeout: 60000 }).should( - 'include', - '/reports-dashboards' - ); - - cy.wait(12500); - - cy.get('#reportDefinitionDetailsLink').first().click(); - - cy.get('#editReportDefinitionButton').should('exist'); - - cy.get('#editReportDefinitionButton').click(); - - cy.url().should('include', 'edit'); - - cy.wait(1000); - - // update the report name - cy.get('#reportSettingsName').type(' update name'); - - // update report description - cy.get('#reportSettingsDescription').type(' update description'); - - cy.get('#editReportDefinitionButton').click({ force: true }); - - cy.wait(12500); - - // check that re-direct to home page - cy.get('#reportDefinitionDetailsLink').should('exist'); - }); - - it('Visit edit page, change report trigger', () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/reports-dashboards#/`); - cy.location('pathname', { timeout: 60000 }).should( - 'include', - '/reports-dashboards' - ); - - cy.wait(12500); - - cy.get('#reportDefinitionDetailsLink').first().click(); - - cy.get('#editReportDefinitionButton').should('exist'); - - cy.get('#editReportDefinitionButton').click(); - - cy.url().should('include', 'edit'); - - cy.wait(1000); - cy.get('#reportDefinitionTriggerTypes > div:nth-child(2)').click({ force: true }); - - cy.get('#Schedule').check({ force: true }); - cy.get('#editReportDefinitionButton').click({ force: true }); - - cy.wait(12500); - - // check that re-direct to home page - cy.get('#reportDefinitionDetailsLink').should('exist'); - }); - - it('Visit edit page, change report trigger back', () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/reports-dashboards#/`); - cy.location('pathname', { timeout: 60000 }).should( - 'include', - '/reports-dashboards' - ); - - cy.wait(12500); - - cy.get('#reportDefinitionDetailsLink').first().click(); - - cy.get('#editReportDefinitionButton').should('exist'); - - cy.get('#editReportDefinitionButton').click(); - - cy.url().should('include', 'edit'); - - cy.wait(1000); - - cy.get('#reportDefinitionTriggerTypes > div:nth-child(1)').click({ force: true }); - - cy.get('#editReportDefinitionButton').click({ force: true }); - - cy.wait(12500); - - // check that re-direct to home page - cy.get('#reportDefinitionDetailsLink').should('exist'); - }); -}); diff --git a/dashboards-reports/.cypress/integration/03-details.spec.ts b/dashboards-reports/.cypress/integration/03-details.spec.ts deleted file mode 100644 index 166da435..00000000 --- a/dashboards-reports/.cypress/integration/03-details.spec.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { visitReportingLandingPage } from "../support/utils"; - -describe('Cypress', () => { - it('Visit report definition details page', () => { - visitReportingLandingPage(); - cy.wait(5000); - visitReportDefinitionDetailsPage(); - verifyReportDefinitionDetailsURL(); - verifyDeleteDefinitionButtonExists(); - verifyGenerateReportFromFileFormatExists(); - }); - - it('Go to edit report definition from report definition details', () => { - visitReportingLandingPage(); - cy.wait(5000); - visitReportDefinitionDetailsPage(); - verifyEditDefinitionButtonExists(); - clickEditReportDefinitionButton(); - verifyEditReportDefinitionURL(); - }); - - it('Verify report source URL on report definition details', () => { - visitReportingLandingPage(); - cy.wait(5000); - visitReportDefinitionDetailsPage(); - verifyReportDefinitionSourceURLExists(); - - }); - - it('Delete report definition from details page', () => { - visitReportingLandingPage(); - cy.wait(5000); - visitReportDefinitionDetailsPage(); - verifyDeleteDefinitionButtonExists(); - deleteReportDefinition(); - verifyDeleteSuccess(); - }); - - it('Visit report details page', () => { - visitReportingLandingPage(); - cy.wait(5000); - visitReportDetailsPage(); - verifyReportDetailsURL(); - }); - - it('Verify report source URL on report details', () => { - visitReportingLandingPage(); - cy.wait(5000); - visitReportDetailsPage(); - verifyReportDetailsSourceURLExists(); - }); -}); - -function visitReportDefinitionDetailsPage() { - cy.get('#reportDefinitionDetailsLink').first().click(); -} - -function verifyReportDefinitionDetailsURL() { - cy.url().should('include', 'report_definition_details'); -} - -function verifyDeleteDefinitionButtonExists() { - cy.get('#deleteReportDefinitionButton').should('exist'); -} - -function verifyEditDefinitionButtonExists() { - cy.get('#editReportDefinitionButton').should('exist'); -} - -function clickEditReportDefinitionButton() { - cy.get('#editReportDefinitionButton').click({ force: true }); -} - -function verifyEditReportDefinitionURL() { - cy.url().should('include', 'edit'); -} - -function verifyReportDefinitionSourceURLExists() { - cy.get('#reportDefinitionSourceURL').should('exist'); -} - -function verifyReportDetailsSourceURLExists() { - cy.get('#reportDetailsSourceURL').should('exist'); -} - -function verifyGenerateReportFromFileFormatExists() { - cy.get('#generateReportFromDetailsFileFormat').should('exist'); -} - -function deleteReportDefinition() { - cy.get('#deleteReportDefinitionButton').click(); - cy.wait(500); - cy.get('button.euiButton:nth-child(2)').click({ force: true }); -} - -function verifyDeleteSuccess() { - cy.get('#deleteReportDefinitionSuccessToast').should('exist'); -} - -function visitReportDetailsPage() { - cy.get('#reportDetailsLink').first().click(); -} - -function verifyReportDetailsURL() { - cy.url().should('include', 'report_details'); -} diff --git a/dashboards-reports/.cypress/integration/04-download.spec.ts b/dashboards-reports/.cypress/integration/04-download.spec.ts deleted file mode 100644 index af7e6409..00000000 --- a/dashboards-reports/.cypress/integration/04-download.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -describe('Cypress', () => { - it('Download from reporting homepage', () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/reports-dashboards#/`); - cy.location('pathname', { timeout: 60000 }).should( - 'include', - '/reports-dashboards' - ); - - cy.wait(12500); - cy.get('#landingPageOnDemandDownload').click({ force: true }); - cy.get('body').then($body => { - if ($body.find('#downloadInProgressLoadingModal').length > 0) { - return; - } - else { - assert(false); - } - }) - }); - - it('Download pdf from in-context menu', () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/dashboards#`); - cy.wait(5000); - - // click first entry in dashboards page - cy.get('tr.euiTableRow:nth-child(1) > td:nth-child(2) > div:nth-child(2) > a:nth-child(1)').click({ force: true }); - - // click Reporting in-context menu - cy.get('#downloadReport > span:nth-child(1) > span:nth-child(1)').click({ force: true }); - - // download PDF - cy.get('#generatePDF > span:nth-child(1) > span:nth-child(2)').click({ force: true }); - - cy.get('#reportGenerationProgressModal'); - }); - - it('Download png from in-context menu', () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/dashboards#`); - cy.wait(5000); - - // click first entry in dashboards page - cy.get('tr.euiTableRow:nth-child(1) > td:nth-child(2) > div:nth-child(2) > a:nth-child(1)').click({ force: true }); - - // click Reporting in-context menu - cy.get('#downloadReport > span:nth-child(1) > span:nth-child(1)').click({ force: true }); - - cy.get('#generatePNG').click({ force: true }); - - cy.get('#reportGenerationProgressModal'); - }); - - it('Download csv from saved search in-context menu', () => { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/discover#`); - cy.wait(5000); - - // open saved search list - cy.get('button.euiButtonEmpty:nth-child(3) > span:nth-child(1) > span:nth-child(1)').click({ force: true }); - cy.wait(5000); - - // click first entry - cy.get('li.euiListGroupItem:nth-child(1) > button:nth-child(1)').click({ force: true }); - - // open reporting menu - cy.get('#downloadReport').click({ force: true }); - - cy.get('#generateCSV').click({ force: true }); - }); - - it('Download from Report definition details page', () => { - // create an on-demand report definition - - cy.visit(`${Cypress.env('opensearchDashboards')}/app/reports-dashboards#/`); - cy.location('pathname', { timeout: 60000 }).should( - 'include', - '/reports-dashboards' - ); - cy.wait(10000); - - cy.get('tr.euiTableRow-isSelectable:nth-child(1) > td:nth-child(1) > div:nth-child(2) > button:nth-child(1)').first().click(); - - cy.url().should('include', 'report_definition_details'); - - cy.get('#generateReportFromDetailsButton').should('exist'); - - cy.get('#generateReportFromDetailsButton').click({ force: true }); - - cy.get('#downloadInProgressLoadingModal'); - }); -}); diff --git a/dashboards-reports/.cypress/plugins/index.js b/dashboards-reports/.cypress/plugins/index.js deleted file mode 100644 index 8ac1f106..00000000 --- a/dashboards-reports/.cypress/plugins/index.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -/// -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) - -/** - * @type {Cypress.PluginConfig} - */ -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config -} diff --git a/dashboards-reports/.cypress/support/commands.js b/dashboards-reports/.cypress/support/commands.js deleted file mode 100644 index dab9071d..00000000 --- a/dashboards-reports/.cypress/support/commands.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -const { ADMIN_AUTH } = require('./constants'); - -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add("login", (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) - -Cypress.Commands.overwrite('visit', (originalFn, url, options) => { - // Add the basic auth header when security enabled in the OpenSearch cluster - // https://github.com/cypress-io/cypress/issues/1288 - if (Cypress.env('security_enabled')) { - if (options) { - options.auth = ADMIN_AUTH; - } else { - options = { auth: ADMIN_AUTH }; - } - // Add query parameters - select the default OpenSearch Dashboards tenant - options.qs = { security_tenant: 'private' }; - return originalFn(url, options); - } else { - return originalFn(url, options); - } -}); - -// Be able to add default options to cy.request(), https://github.com/cypress-io/cypress/issues/726 -Cypress.Commands.overwrite('request', (originalFn, ...args) => { - let defaults = {}; - // Add the basic authentication header when security enabled in the OpenSearch cluster - if (Cypress.env('security_enabled')) { - defaults.auth = ADMIN_AUTH; - } - - let options = {}; - if (typeof args[0] === 'object' && args[0] !== null) { - options = Object.assign({}, args[0]); - } else if (args.length === 1) { - [options.url] = args; - } else if (args.length === 2) { - [options.method, options.url] = args; - } else if (args.length === 3) { - [options.method, options.url, options.body] = args; - } - - return originalFn(Object.assign({}, defaults, options)); -}); - diff --git a/dashboards-reports/.cypress/support/constants.js b/dashboards-reports/.cypress/support/constants.js deleted file mode 100644 index 1001fd49..00000000 --- a/dashboards-reports/.cypress/support/constants.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export const ADMIN_AUTH = { - username: 'admin', - password: 'admin', -}; diff --git a/dashboards-reports/.cypress/support/index.js b/dashboards-reports/.cypress/support/index.js deleted file mode 100644 index c70c2dd5..00000000 --- a/dashboards-reports/.cypress/support/index.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands' - -// Alternatively you can use CommonJS syntax: -// require('./commands') - -// Switch the base URL of OpenSearch when security enabled in the cluster -if (Cypress.env('security_enabled')) { - Cypress.env('opensearch', 'https://localhost:9200'); -} diff --git a/dashboards-reports/.cypress/support/utils.js b/dashboards-reports/.cypress/support/utils.js deleted file mode 100644 index a534be13..00000000 --- a/dashboards-reports/.cypress/support/utils.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export function visitReportingLandingPage() { - cy.visit(`${Cypress.env('opensearchDashboards')}/app/reports-dashboards#/`); - cy.location('pathname', { timeout: 60000 }).should( - 'include', - '/reports-dashboards' - ); - } \ No newline at end of file diff --git a/dashboards-reports/.cypress/tsconfig.json b/dashboards-reports/.cypress/tsconfig.json deleted file mode 100644 index 2d48dc0e..00000000 --- a/dashboards-reports/.cypress/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "allowJs": true, - "baseUrl": "../node_modules", - "types": ["cypress"] - }, - "include": ["**/*.*"] -} \ No newline at end of file diff --git a/dashboards-reports/.eslintrc b/dashboards-reports/.eslintrc deleted file mode 100644 index 52a1c6be..00000000 --- a/dashboards-reports/.eslintrc +++ /dev/null @@ -1,9 +0,0 @@ ---- -extends: '@elastic/kibana' - -settings: - import/resolver: - '@osd/eslint-import-resolver-kibana': - rootPackageName: 'reports-dashboards' - pluginPaths: - - . diff --git a/dashboards-reports/.gitignore b/dashboards-reports/.gitignore deleted file mode 100644 index 9e1fedcc..00000000 --- a/dashboards-reports/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -npm-debug.log* -node_modules -/build/ -/public/app.css -.idea/ -yarn-error.log -/coverage/ -.DS_Store -.history/ -.eslintcache -package-lock.json -/target/ -.chromium/ \ No newline at end of file diff --git a/dashboards-reports/.i18nrc.json b/dashboards-reports/.i18nrc.json deleted file mode 100644 index f60aeca5..00000000 --- a/dashboards-reports/.i18nrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "paths": { - "opensearch.reports": "public" - }, - "exclude": [], - "translations": ["translations/zh-CN.json", "translations/pl.json"] -} diff --git a/dashboards-reports/.lintstagedrc b/dashboards-reports/.lintstagedrc deleted file mode 100644 index e7e7db11..00000000 --- a/dashboards-reports/.lintstagedrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "*.{ts,tsx,js,jsx,json,css,md}": ["prettier --write", "git add"] -} diff --git a/dashboards-reports/.opensearch_dashboards-plugin-helpers.json b/dashboards-reports/.opensearch_dashboards-plugin-helpers.json deleted file mode 100644 index 05b7d7e4..00000000 --- a/dashboards-reports/.opensearch_dashboards-plugin-helpers.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "serverSourcePatterns": [ - "package.json", - "tsconfig.json", - "yarn.lock", - ".i18nrc.json", - "common/**/*", - "public/**/*", - "server/**/*", - "translations/**/*" - ] -} diff --git a/dashboards-reports/.prettierignore b/dashboards-reports/.prettierignore deleted file mode 100644 index 7dc413d2..00000000 --- a/dashboards-reports/.prettierignore +++ /dev/null @@ -1,8 +0,0 @@ -.vscode -build -coverage -node_modules -npm-debug.log -yarn.lock -*.md -*.lock \ No newline at end of file diff --git a/dashboards-reports/.prettierrc b/dashboards-reports/.prettierrc deleted file mode 100644 index f443e3cf..00000000 --- a/dashboards-reports/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "trailingComma": "es5", - "singleQuote": true, - "printWidth": 80, - "bracketSpacing": true -} diff --git a/dashboards-reports/DEVELOPER_GUIDE.md b/dashboards-reports/DEVELOPER_GUIDE.md deleted file mode 100644 index 39e2ffbc..00000000 --- a/dashboards-reports/DEVELOPER_GUIDE.md +++ /dev/null @@ -1,67 +0,0 @@ -## Developer Guide - -So you want to contribute code to this project? Excellent! We're glad you're here. Here's what you need to do. - -## Install Prerequisites - -### JDK 11 - -OpenSearch builds using Java 11 at a minimum. This means you must have a JDK 11 -installed with the environment variable `JAVA_HOME` referencing the path to Java home -for your JDK 11 installation, e.g. `JAVA_HOME=/usr/lib/jvm/jdk-11`. - -By default, tests use the same runtime as `JAVA_HOME`. However, since OpenSearch -supports JDK 8, the build supports compiling with JDK 11 and testing on a different -version of JDK runtime. To do this, set `RUNTIME_JAVA_HOME` pointing to the Java home of -another JDK installation, e.g. `RUNTIME_JAVA_HOME=/usr/lib/jvm/jdk-8`. - -## Setup - -1. Download OpenSearch for the version that matches the [OpenSearch Dashboards version specified in package.json](./package.json#L7). -1. Download the OpenSearch Dashboards source code for the [version specified in package.json](./package.json#L7) you want to set up. - -1. Change your node version to the version specified in `.node-version` inside the OpenSearch Dashboards root directory. -1. Create a `plugins` directory inside the OpenSearch Dashboards source code directory, if `plugins` directory doesn't exist. -1. Check out this package from version control into the `plugins` directory. - ``` - git clone git@github.com:opensearch-project/dashboards-reports.git plugins --no-checkout - cd plugins - echo 'dashboards-reports/*' >> .git/info/sparse-checkout - git config core.sparseCheckout true - git checkout dev - ``` -1. Run `yarn osd bootstrap` inside `OpenSearch-Dashboards/plugins/dashboards-reports`. - -Ultimately, your directory structure should look like this: - - -```md -. -├── OpenSearch-Dashboards -│ └──plugins -│ └── dashboards-reports -``` - -## Build - -To build the plugin's distributable zip simply run `yarn build`. - -Example output: `./build/reports-dashboards-0.0.1.zip` - -## Run - -- `yarn start` - - Starts OpenSearch Dashboards and includes this plugin. OpenSearch Dashboards will be available on `localhost:5601`. - -- `yarn test:jest` - - Runs the plugin tests. - -### Backports - -The Github workflow in [`backport.yml`](../.github/workflows/backport.yml) creates backport PRs automatically when the original PR -with an appropriate label `backport ` is merged to main with the backport workflow run successfully on the -PR. For example, if a PR on main needs to be backported to `1.x` branch, add a label `backport 1.x` to the PR and make sure the -backport workflow runs on the PR along with other checks. Once this PR is merged to main, the workflow will create a backport PR -to the `1.x` branch. \ No newline at end of file diff --git a/dashboards-reports/README.md b/dashboards-reports/README.md deleted file mode 100644 index 85204bf8..00000000 --- a/dashboards-reports/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# OpenSearch Dashboards Reports - -OpenSearch Dashboards Reports allows ‘Report Owner’ (engineers, including but not limited to developers, DevOps, IT Engineer, and IT admin) export and share reports from OpenSearch Dashboards dashboards, saved search, alerts and visualizations. It helps automate the process of scheduling reports on an on-demand or a periodical basis (on cron schedules as well). Further, it also automates the process of exporting and sharing reports triggered for various alerts. The feature is present in the Dashboard, Discover, and Visualization tabs. We are currently working on integrating Dashboards Reports with Notifications to enable sharing functionality. After the support is introduced, scheduled reports can be sent to (shared with) self or various stakeholders within the organization. These stakeholders include but are not limited to, executives, managers, engineers (developers, DevOps, IT Engineer) in the form of pdf, hyperlinks, csv, excel via various channels such as email, Slack, and Amazon Chime. However, in order to export, schedule and share reports, report owners should have the necessary permissions as defined under Roles and Privileges. - -## Contributing - -See [developer guide](DEVELOPER_GUIDE.md) and [how to contribute to this project](../CONTRIBUTING.md). - -## Code of Conduct - -This project has adopted the [Amazon Open Source Code of Conduct](../CODE_OF_CONDUCT.md). For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq), or contact [opensource-codeofconduct@amazon.com](mailto:opensource-codeofconduct@amazon.com) with any additional questions or comments. - -## Security - -If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public GitHub issue. - -## License - -See the [LICENSE](../LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. - -## Copyright - -Copyright 2020-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/dashboards-reports/THIRD-PARTY b/dashboards-reports/THIRD-PARTY deleted file mode 100644 index 4de447de..00000000 --- a/dashboards-reports/THIRD-PARTY +++ /dev/null @@ -1,203 +0,0 @@ -** @elastic/eui; version 5.1.0 -- https://elastic.github.io/eui/#/ - -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND -DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, and - distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by the - copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all other - entities that control, are controlled by, or are under common control - with that entity. For the purposes of this definition, "control" means - (i) the power, direct or indirect, to cause the direction or management - of such entity, whether by contract or otherwise, or (ii) ownership of - fifty percent (50%) or more of the outstanding shares, or (iii) - beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity exercising - permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation source, - and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but not limited - to compiled object code, generated documentation, and conversions to - other media types. - - "Work" shall mean the work of authorship, whether in Source or Object - form, made available under the License, as indicated by a copyright - notice that is included in or attached to the work (an example is - provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object form, - that is based on (or derived from) the Work and for which the editorial - revisions, annotations, elaborations, or other modifications represent, - as a whole, an original work of authorship. For the purposes of this - License, Derivative Works shall not include works that remain separable - from, or merely link (or bind by name) to the interfaces of, the Work and - Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including the original - version of the Work and any modifications or additions to that Work or - Derivative Works thereof, that is intentionally submitted to Licensor for - inclusion in the Work by the copyright owner or by an individual or Legal - Entity authorized to submit on behalf of the copyright owner. For the - purposes of this definition, "submitted" means any form of electronic, - verbal, or written communication sent to the Licensor or its - representatives, including but not limited to communication on electronic - mailing lists, source code control systems, and issue tracking systems - that are managed by, or on behalf of, the Licensor for the purpose of - discussing and improving the Work, but excluding communication that is - conspicuously marked or otherwise designated in writing by the copyright - owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity on - behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of this - License, each Contributor hereby grants to You a perpetual, worldwide, - non-exclusive, no-charge, royalty-free, irrevocable copyright license to - reproduce, prepare Derivative Works of, publicly display, publicly perform, - sublicense, and distribute the Work and such Derivative Works in Source or - Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of this - License, each Contributor hereby grants to You a perpetual, worldwide, - non-exclusive, no-charge, royalty-free, irrevocable (except as stated in - this section) patent license to make, have made, use, offer to sell, sell, - import, and otherwise transfer the Work, where such license applies only to - those patent claims licensable by such Contributor that are necessarily - infringed by their Contribution(s) alone or by combination of their - Contribution(s) with the Work to which such Contribution(s) was submitted. - If You institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work or a - Contribution incorporated within the Work constitutes direct or contributory - patent infringement, then any patent licenses granted to You under this - License for that Work shall terminate as of the date such litigation is - filed. - - 4. Redistribution. You may reproduce and distribute copies of the Work or - Derivative Works thereof in any medium, with or without modifications, and - in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a - copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating - that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You - distribute, all copyright, patent, trademark, and attribution notices - from the Source form of the Work, excluding those notices that do not - pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must include - a readable copy of the attribution notices contained within such NOTICE - file, excluding those notices that do not pertain to any part of the - Derivative Works, in at least one of the following places: within a - NOTICE text file distributed as part of the Derivative Works; within the - Source form or documentation, if provided along with the Derivative - Works; or, within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents of the - NOTICE file are for informational purposes only and do not modify the - License. You may add Your own attribution notices within Derivative Works - that You distribute, alongside or as an addendum to the NOTICE text from - the Work, provided that such additional attribution notices cannot be - construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may - provide additional or different license terms and conditions for use, - reproduction, or distribution of Your modifications, or for any such - Derivative Works as a whole, provided Your use, reproduction, and - distribution of the Work otherwise complies with the conditions stated in - this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, any - Contribution intentionally submitted for inclusion in the Work by You to the - Licensor shall be under the terms and conditions of this License, without - any additional terms or conditions. Notwithstanding the above, nothing - herein shall supersede or modify the terms of any separate license agreement - you may have executed with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, except - as required for reasonable and customary use in describing the origin of the - Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in - writing, Licensor provides the Work (and each Contributor provides its - Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied, including, without limitation, any - warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or - FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining - the appropriateness of using or redistributing the Work and assume any risks - associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, whether - in tort (including negligence), contract, or otherwise, unless required by - applicable law (such as deliberate and grossly negligent acts) or agreed to - in writing, shall any Contributor be liable to You for damages, including - any direct, indirect, special, incidental, or consequential damages of any - character arising as a result of this License or out of the use or inability - to use the Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all other - commercial damages or losses), even if such Contributor has been advised of - the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing the Work - or Derivative Works thereof, You may choose to offer, and charge a fee for, - acceptance of support, warranty, indemnity, or other liability obligations - and/or rights consistent with this License. However, in accepting such - obligations, You may act only on Your own behalf and on Your sole - responsibility, not on behalf of any other Contributor, and only if You - agree to indemnify, defend, and hold each Contributor harmless for any - liability incurred by, or claims asserted against, such Contributor by - reason of your accepting any such warranty or additional liability. END OF - TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification -within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); - -you may not use this file except in compliance with the License. - -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software - -distributed under the License is distributed on an "AS IS" BASIS, - -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - -See the License for the specific language governing permissions and - -limitations under the License. - -* For dashboards-reports see also this required NOTICE: - dashboards-reports - Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/dashboards-reports/babel.config.js b/dashboards-reports/babel.config.js deleted file mode 100644 index aab76c8a..00000000 --- a/dashboards-reports/babel.config.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -module.exports = { - presets: [ - require('@babel/preset-env', { - targets: { node: '10' }, - }), - require('@babel/preset-react'), - require('@babel/preset-typescript'), - ], - plugins: [ - require('@babel/plugin-proposal-class-properties'), - require('@babel/plugin-proposal-object-rest-spread'), - ['@babel/plugin-transform-modules-commonjs', { allowTopLevelThis: true }], - [require('@babel/plugin-transform-runtime'), { regenerator: true }], - ], -}; diff --git a/dashboards-reports/common/index.ts b/dashboards-reports/common/index.ts deleted file mode 100644 index ce180a09..00000000 --- a/dashboards-reports/common/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export const PLUGIN_NAME = 'Reporting'; -export const PLUGIN_ID = 'reports-dashboards'; - -export const API_PREFIX = '/api/reporting'; - -const BASE_REPORTS_URI = '/_plugins/_reports'; - -export const OPENSEARCH_REPORTS_API = { - ON_DEMAND_REPORT: `${BASE_REPORTS_URI}/on_demand`, - REPORT_INSTANCE: `${BASE_REPORTS_URI}/instance`, - LIST_REPORT_INSTANCES: `${BASE_REPORTS_URI}/instances`, - REPORT_DEFINITION: `${BASE_REPORTS_URI}/definition`, - LIST_REPORT_DEFINITIONS: `${BASE_REPORTS_URI}/definitions`, -}; - -const REPORTING_NOTIFICATIONS_API_PREFIX = '/api/reporting_notifications'; -export const REPORTING_NOTIFICATIONS_DASHBOARDS_API = Object.freeze({ - GET_CONFIGS: `${REPORTING_NOTIFICATIONS_API_PREFIX}/get_configs`, - GET_EVENT: `${REPORTING_NOTIFICATIONS_API_PREFIX}/get_event`, - SEND_TEST_MESSAGE: `${REPORTING_NOTIFICATIONS_API_PREFIX}/test_message`, -}); - -const NOTIFICATIONS_API_BASE_PATH = '/_plugins/_notifications'; -export const NOTIFICATIONS_API = Object.freeze({ - CONFIGS: `${NOTIFICATIONS_API_BASE_PATH}/configs`, - EVENTS: `${NOTIFICATIONS_API_BASE_PATH}/events`, - TEST_MESSAGE: `${NOTIFICATIONS_API_BASE_PATH}/feature/test`, -}); diff --git a/dashboards-reports/cypress.json b/dashboards-reports/cypress.json deleted file mode 100644 index e72b2afa..00000000 --- a/dashboards-reports/cypress.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "video": true, - "fixturesFolder": ".cypress/fixtures", - "integrationFolder": ".cypress/integration", - "pluginsFile": ".cypress/plugins/index.js", - "screenshotsFolder": ".cypress/screenshots", - "supportFile": ".cypress/support/index.js", - "videosFolder": ".cypress/videos", - "requestTimeout": 60000, - "responseTimeout": 60000, - "defaultCommandTimeout": 60000, - "env": { - "opensearch": "localhost:9200", - "opensearchDashboards": "localhost:5601", - "security_enabled": true - } -} diff --git a/dashboards-reports/opensearch_dashboards.json b/dashboards-reports/opensearch_dashboards.json deleted file mode 100644 index 70d4a2ce..00000000 --- a/dashboards-reports/opensearch_dashboards.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "reportsDashboards", - "version": "3.0.0.0", - "opensearchDashboardsVersion": "3.0.0", - "requiredPlugins": ["navigation", "data", "opensearchDashboardsUtils"], - "optionalPlugins": ["share"], - "server": true, - "ui": true, - "configPath": ["opensearch_reporting"] -} diff --git a/dashboards-reports/package.json b/dashboards-reports/package.json deleted file mode 100644 index cebe1f37..00000000 --- a/dashboards-reports/package.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "name": "reports-dashboards", - "version": "2.1.0.0", - "description": "OpenSearch Dashboards Reports Plugin", - "license": "Apache-2.0", - "main": "index.ts", - "scripts": { - "osd": "node ../../scripts/osd", - "opensearch": "node ../../scripts/opensearch", - "lint": "eslint .", - "start": "yarn plugin_helpers start", - "build": "yarn plugin_helpers build", - "test": "../../node_modules/.bin/jest --config ./test/jest.config.js", - "cypress:run": "cypress run", - "cypress:open": "cypress open", - "plugin_helpers": "node ../../scripts/plugin_helpers" - }, - "dependencies": { - "async-mutex": "^0.2.6", - "babel-polyfill": "^6.26.0", - "cron-validator": "^1.1.1", - "dompurify": "^2.4.1", - "elastic-builder": "^2.7.1", - "enzyme-adapter-react-16": "^1.15.5", - "jest-fetch-mock": "^3.0.3", - "jquery": "^3.5.0", - "jsdom": "16.5.0", - "json-2-csv": "^3.7.6", - "puppeteer-core": "^13.7.0", - "react-addons-test-utils": "^15.6.2", - "react-id-generator": "^3.0.1", - "react-markdown": "^4.3.1", - "react-mde": "^10.2.1", - "react-native-base64": "^0.0.2", - "react-native-i18n": "^2.0.15", - "react-navigation": "^4.3.9", - "react-router-dom": "^5.3.0", - "react-toast-notifications": "^2.4.0", - "set-interval-async": "1.0.33", - "showdown": "^1.9.1" - }, - "devDependencies": { - "@elastic/eslint-import-resolver-kibana": "link:../../packages/osd-eslint-import-resolver-opensearch-dashboards", - "@types/dompurify": "^2.3.3", - "@types/enzyme-adapter-react-16": "^1.0.6", - "@types/jsdom": "^16.2.3", - "@types/puppeteer-core": "^5.4.0", - "@types/react": "^16.14.23", - "@types/react-addons-test-utils": "^0.14.25", - "@types/react-dom": "^16.9.8", - "@types/react-test-renderer": "^16.9.1", - "@types/set-interval-async": "^1.0.0", - "@types/showdown": "^1.9.3", - "babel-jest": "^27.5.1", - "cypress": "^5.0.0", - "elastic-builder": "^2.7.1", - "eslint-plugin-babel": "^5.3.1", - "eslint-plugin-no-unsanitized": "^3.0.2", - "eslint-plugin-prefer-object-spread": "^1.2.1", - "identity-obj-proxy": "^3.0.0", - "jest-dom": "^4.0.0", - "react-test-renderer": "^16.12.0", - "ts-jest": "^26.1.0" - }, - "resolutions": { - "trim": "^1.0.0", - "doc-path": "2.1.2", - "y18n": "^5.0.5", - "lodash": "^4.17.21", - "path-parse": "^1.0.7", - "glob-parent": "^5.1.2", - "css-what": "^5.0.1", - "ansi-regex": "5.0.1", - "json-schema": "0.4.0", - "ws": "^7.4.6", - "minimatch": "^3.0.5", - "loader-utils": "^2.0.3" - } -} diff --git a/dashboards-reports/public/app.scss b/dashboards-reports/public/app.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/dashboards-reports/public/application.tsx b/dashboards-reports/public/application.tsx deleted file mode 100644 index 5fc2379d..00000000 --- a/dashboards-reports/public/application.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; -import { AppMountParameters, CoreStart } from '../../../src/core/public'; -import { AppPluginStartDependencies } from './types'; -import { ReportsDashboardsApp } from './components/app'; - -export const renderApp = ( - { notifications, http, chrome }: CoreStart, - { navigation }: AppPluginStartDependencies, - { appBasePath, element }: AppMountParameters -) => { - ReactDOM.render( - , - element - ); - - return () => ReactDOM.unmountComponentAtNode(element); -}; diff --git a/dashboards-reports/public/components/app.tsx b/dashboards-reports/public/components/app.tsx deleted file mode 100644 index 4091c0d7..00000000 --- a/dashboards-reports/public/components/app.tsx +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; -import { HashRouter as Router, Route, Switch } from 'react-router-dom'; - -import { - EuiPage, - EuiPageBody, - EuiPageContentBody, - EuiPageContentHeader, - EuiPageContentHeaderSection, -} from '@elastic/eui'; -import CSS from 'csstype'; -import { - CoreStart, - CoreSystem, - ChromeBreadcrumb, - IUiSettingsClient, -} from '../../../../src/core/public'; -import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public'; - -import { CreateReport } from './report_definitions/create/create_report_definition'; -import { Main } from './main/main'; -import { ReportDetails } from './main/report_details/report_details'; -import { ReportDefinitionDetails } from './main/report_definition_details/report_definition_details'; -import { EditReportDefinition } from './report_definitions/edit/edit_report_definition'; -import { i18n } from '@osd/i18n'; - -export interface CoreInterface { - http: CoreStart['http']; - uiSettings: IUiSettingsClient; - setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; -} - -interface ReportsDashboardsAppDeps { - basename: string; - notifications: CoreStart['notifications']; - http: CoreStart['http']; - navigation: NavigationPublicPluginStart; - chrome: CoreStart['chrome']; -} - -const styles: CSS.Properties = { - float: 'left', - width: '100%', - maxWidth: '1600px', -}; - -export const ReportsDashboardsApp = ({ - basename, - notifications, - http, - navigation, - chrome, -}: ReportsDashboardsAppDeps) => { - // Render the application DOM. - return ( - - -
- - - - - - - - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - ( -
- )} - /> - - - - -
-
-
- ); -}; diff --git a/dashboards-reports/public/components/context_menu/context_menu.js b/dashboards-reports/public/components/context_menu/context_menu.js deleted file mode 100644 index f30e336d..00000000 --- a/dashboards-reports/public/components/context_menu/context_menu.js +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -/* eslint-disable no-restricted-globals */ -import $ from 'jquery'; -import { i18n } from '@osd/i18n'; -import { readStreamToFile } from '../main/main_utils'; -import { - contextMenuCreateReportDefinition, - getTimeFieldsFromUrl, - displayLoadingModal, - addSuccessOrFailureToast, - contextMenuViewReports, - replaceQueryURL, -} from './context_menu_helpers'; -import { - popoverMenu, - popoverMenuDiscover, - getMenuItem, -} from './context_menu_ui'; -import { parse } from 'url'; -import { uiSettingsService } from '../utils/settings_service'; - -const generateInContextReport = async ( - timeRanges, - queryUrl, - fileFormat, - rest = {} -) => { - displayLoadingModal(); - const baseUrl = queryUrl.substr(0, queryUrl.indexOf('?')); - // Add selected tenant info to url - try { - const tenant = await getTenantInfoIfExists(); - if (tenant) { - queryUrl = addTenantToURL(queryUrl, tenant); - } - } catch (error) { - addSuccessOrFailureToast('failure'); - console.log(`failed to get user tenant: ${error}`); - } - - let reportSource = ''; - if (/\/app\/dashboards/.test(baseUrl)) { - reportSource = 'Dashboard'; - } else if (/\/app\/visualize/.test(baseUrl)) { - reportSource = 'Visualization'; - } else if (/\/app\/discover/.test(baseUrl)) { - reportSource = 'Saved search'; - } - - // create query body - const contextMenuOnDemandReport = { - query_url: queryUrl, - time_from: timeRanges.time_from.valueOf(), - time_to: timeRanges.time_to.valueOf(), - report_definition: { - report_params: { - report_name: 'On_demand_report', - report_source: reportSource, - description: 'In-context report download', - core_params: { - base_url: baseUrl, - report_format: fileFormat, - time_duration: timeRanges.time_duration, - ...rest, - }, - }, - delivery: { - configIds: [''], - title: '', - textDescription: '', - htmlDescription: '', - }, - trigger: { - trigger_type: 'On demand', - }, - }, - }; - - fetch( - `../api/reporting/generateReport?${new URLSearchParams( - uiSettingsService.getSearchParams() - )}`, - { - headers: { - 'Content-Type': 'application/json', - 'osd-xsrf': 'reporting', - accept: '*/*', - 'accept-language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6', - pragma: 'no-cache', - 'sec-fetch-dest': 'empty', - 'sec-fetch-mode': 'cors', - 'sec-fetch-site': 'same-origin', - }, - method: 'POST', - body: JSON.stringify(contextMenuOnDemandReport), - referrerPolicy: 'strict-origin-when-cross-origin', - mode: 'cors', - credentials: 'include', - } - ) - .then((response) => { - if (response.status === 200) { - $('#reportGenerationProgressModal').remove(); - addSuccessOrFailureToast('success'); - } else { - if (response.status === 403) { - addSuccessOrFailureToast('permissionsFailure'); - } else if (response.status === 503) { - addSuccessOrFailureToast('timeoutFailure', reportSource); - } else { - addSuccessOrFailureToast('failure'); - } - } - return response.json(); - }) - .then(async (data) => { - await readStreamToFile(data.data, fileFormat, data.filename); - }); -}; - -// try to match uuid and user entered custom-id followed by '?' in URL, which would be the saved search id for discover URL -// custom id example: v1s-f00-b4r1-01, Filebeat-Apache-Dashboard-ecs, -const getUuidFromUrl = () => window.location.href.match(/([0-9a-zA-Z-]+)\?/); -const isDiscover = () => window.location.href.includes('discover'); - -// open Download drop-down -$(function () { - $(document).on('click', '#downloadReport', function () { - const popoverScreen = document.querySelectorAll('body'); - if (popoverScreen) { - try { - const reportPopover = document.createElement('div'); - // eslint-disable-next-line no-unsanitized/property - reportPopover.innerHTML = isDiscover() - ? popoverMenuDiscover(getUuidFromUrl()) - : popoverMenu(getUuidFromUrl()); - popoverScreen[0].appendChild(reportPopover.children[0]); - $('#reportPopover').show(); - } catch (e) { - console.log('error displaying menu:', e); - } - } - }); - - // generate PDF onclick - $(document).on('click', '#generatePDF', function () { - const timeRanges = getTimeFieldsFromUrl(); - const queryUrl = replaceQueryURL(location.href); - generateInContextReport(timeRanges, queryUrl, 'pdf'); - }); - - // generate PNG onclick - $(document).on('click', '#generatePNG', function () { - const timeRanges = getTimeFieldsFromUrl(); - const queryUrl = replaceQueryURL(location.href); - generateInContextReport(timeRanges, queryUrl, 'png'); - }); - - // generate CSV onclick - $(document).on('click', '#generateCSV', function () { - const timeRanges = getTimeFieldsFromUrl(); - const queryUrl = replaceQueryURL(location.href); - const saved_search_id = getUuidFromUrl()[1]; - generateInContextReport(timeRanges, queryUrl, 'csv', { saved_search_id }); - }); - - // navigate to Create report definition page with report source and pre-set time range - $(document).on('click', '#createReportDefinition', function () { - contextMenuCreateReportDefinition(this.baseURI); - }); - - // redirect to Reporting home page - $(document).on('click', '#viewReports', function () { - contextMenuViewReports(); - }); - - // close popover menu on click outside - $('body').on('click', function (e) { - if ($(e.target).data('toggle') !== '#downloadReport') { - $('#reportPopover').remove(); - } - }); - - // close modal/toast - $(function () { - // close modal with 'x' in upper-right modal - $(document).on('click', '#closeReportGenerationModal', function () { - $('#reportGenerationProgressModal').remove(); - }); - - // close modal with the close EuiButton - $(document).on('click', '#closeReportGenerationModalButton', function () { - $('#reportGenerationProgressModal').remove(); - }); - - // close the toast that appears upon successful report generation - $(document).on('click', '#closeReportSuccessToast', function () { - $('#reportSuccessToast').remove(); - }); - - // close the toast that apepars upon failure of report generation - $(document).on('click', '#closeReportFailureToast', function () { - $('#reportFailureToast').remove(); - }); - - // close permissions failure toast - $(document).on('click', '#permissionsMissingErrorToast', function () { - $('#permissionsMissingErrorToast').remove(); - }); - }); - - locationHashChanged(); -}); - -const isDiscoverNavMenu = (navMenu) => { - return ( - navMenu[0].children.length === 5 && - ($('[data-test-subj="breadcrumb first"]').prop('title') === 'Discover' || - $('[data-test-subj="breadcrumb first last"]').prop('title') === - 'Discover') - ); -}; - -const isDashboardNavMenu = (navMenu) => { - return ( - (navMenu[0].children.length === 4 || navMenu[0].children.length === 6) && - $('[data-test-subj="breadcrumb first"]').prop('title') === 'Dashboard' - ); -}; - -const isVisualizationNavMenu = (navMenu) => { - return ( - navMenu[0].children.length === 3 && - $('[data-test-subj="breadcrumb first"]').prop('title') === 'Visualize' - ); -}; - -function locationHashChanged() { - const observer = new MutationObserver(function (mutations) { - const navMenu = document.querySelectorAll( - 'span.osdTopNavMenu__wrapper > nav.euiHeaderLinks > div.euiHeaderLinks__list' - ); - if ( - navMenu && - navMenu.length && - (isDiscoverNavMenu(navMenu) || - isDashboardNavMenu(navMenu) || - isVisualizationNavMenu(navMenu)) - ) { - try { - if ($('#downloadReport').length) { - return; - } - const menuItem = document.createElement('div'); - menuItem.innerHTML = getMenuItem( - i18n.translate('opensearch.reports.menu.name', { - defaultMessage: 'Reporting', - }) - ); - navMenu[0].insertBefore(menuItem.children[0], navMenu[0].lastChild); - } catch (e) { - console.log(e); - } finally { - observer.disconnect(); - } - } - }); - - // Start observing - observer.observe(document.body, { - //document.body is node target to observe - childList: true, //This is a must have for the observer with subtree - subtree: true, //Set to true if changes must also be observed in descendants. - }); -} - -$(window).one('hashchange', function (e) { - locationHashChanged(); -}); -/** - * for navigating to tabs from OpenSearch Dashboards sidebar, it uses history.pushState, which doesn't trigger onHashchange. - * https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate/4585031 - */ -(function (history) { - const pushState = history.pushState; - history.pushState = function (state) { - if (typeof history.onpushstate === 'function') { - history.onpushstate({ state: state }); - } - return pushState.apply(history, arguments); - }; -})(window.history); - -window.onpopstate = history.onpushstate = () => { - locationHashChanged(); -}; - -async function getTenantInfoIfExists() { - const res = await fetch(`../api/v1/multitenancy/tenant`, { - headers: { - 'Content-Type': 'application/json', - 'osd-xsrf': 'reporting', - accept: '*/*', - 'accept-language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6', - pragma: 'no-cache', - 'sec-fetch-dest': 'empty', - 'sec-fetch-mode': 'cors', - 'sec-fetch-site': 'same-origin', - }, - method: 'GET', - referrerPolicy: 'strict-origin-when-cross-origin', - mode: 'cors', - credentials: 'include', - }) - .then((response) => { - if (response.status === 404) { - // endpoint doesn't exist, security plugin is not enabled. - return undefined; - } else { - return response.text(); - } - }) - .then((tenant) => { - if (tenant === '') { - tenant = 'global'; - } else if (tenant === '__user__') { - tenant = 'private'; - } - return tenant; - }); - - return res; -} - -// helper function to add tenant info to url(if tenant is available) -function addTenantToURL(url, userRequestedTenant) { - // build fake url from relative url - const fakeUrl = `http://opensearch.com${url}`; - const tenantKey = 'security_tenant'; - const tenantKeyAndValue = - tenantKey + '=' + encodeURIComponent(userRequestedTenant); - - const { pathname, search } = parse(fakeUrl); - const queryDelimiter = !search ? '?' : '&'; - // The url parser returns null if the search is empty. Change that to an empty - // string so that we can use it to build the values later - if (search && search.toLowerCase().indexOf(tenantKey) > -1) { - // If we for some reason already have a tenant in the URL we skip any updates - return url; - } - - // A helper for finding the part in the string that we want to extend/replace - const valueToReplace = pathname + (search || ''); - const replaceWith = valueToReplace + queryDelimiter + tenantKeyAndValue; - - return url.replace(valueToReplace, replaceWith); -} diff --git a/dashboards-reports/public/components/context_menu/context_menu_helpers.js b/dashboards-reports/public/components/context_menu/context_menu_helpers.js deleted file mode 100644 index 3ebe5d76..00000000 --- a/dashboards-reports/public/components/context_menu/context_menu_helpers.js +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import dateMath from '@elastic/datemath'; -import moment from 'moment'; -import { - reportGenerationInProgressModal, - reportGenerationSuccess, - reportGenerationFailure, - 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('?')); - const reportSourceId = url.substr(url.lastIndexOf('/') + 1, url.length); - return reportSourceId; -}; - -export const contextMenuViewReports = () => - window.location.assign('reports-dashboards#/'); - -export const getTimeFieldsFromUrl = () => { - const url = unhashUrl(window.location.href); - - let [, fromDateString, toDateString] = url.match(timeRangeMatcher); - fromDateString = decodeURIComponent(fromDateString.replace(/[']+/g, '')); - // convert time range to from date format in case time range is relative - const fromDateFormat = dateMath.parse(fromDateString); - toDateString = decodeURIComponent(toDateString.replace(/[']+/g, '')); - const toDateFormat = dateMath.parse(toDateString, { roundUp: true }); - - const timeDuration = moment.duration(toDateFormat.diff(fromDateFormat)); - - return { - time_from: fromDateFormat, - time_to: toDateFormat, - time_duration: timeDuration.toISOString(), - }; -}; - -export const contextMenuCreateReportDefinition = (baseURI) => { - const reportSourceId = getReportSourceURL(baseURI); - let reportSource = ''; - const timeRanges = getTimeFieldsFromUrl(); - - // check report source - if (/\/app\/dashboards/.test(baseURI)) { - reportSource = 'dashboard:'; - } else if (/\/app\/visualize/.test(baseURI)) { - reportSource = 'visualize:'; - } else if (/\/app\/discover/.test(baseURI)) { - reportSource = 'discover:'; - } - reportSource += reportSourceId.toString(); - window.location.assign( - `reports-dashboards#/create?previous=${reportSource}?timeFrom=${timeRanges.time_from.toISOString()}?timeTo=${timeRanges.time_to.toISOString()}` - ); -}; - -export const displayLoadingModal = () => { - const opensearchDashboardsBody = document.getElementById( - 'opensearch-dashboards-body' - ); - if (opensearchDashboardsBody) { - try { - const loadingModal = document.createElement('div'); - loadingModal.innerHTML = reportGenerationInProgressModal(); - opensearchDashboardsBody.appendChild(loadingModal.children[0]); - } catch (e) { - console.log('error displaying loading modal:', e); - } - } -}; - -export const addSuccessOrFailureToast = (status, reportSource) => { - const generateToast = document.querySelectorAll('.euiGlobalToastList'); - if (generateToast) { - try { - const generateInProgressToast = document.createElement('div'); - if (status === 'success') { - generateInProgressToast.innerHTML = reportGenerationSuccess(); - setTimeout(function () { - document.getElementById('reportSuccessToast').style.display = 'none'; - }, 6000); // closes toast automatically after 6s - } else if (status === 'failure') { - generateInProgressToast.innerHTML = reportGenerationFailure(); - setTimeout(function () { - document.getElementById('reportFailureToast').style.display = 'none'; - }, 6000); - } else if (status === 'timeoutFailure') { - generateInProgressToast.innerHTML = reportGenerationFailure( - 'Error generating report.', - `Timed out generating on-demand report from ${reportSource}. Try again later.` - ); - setTimeout(function () { - document.getElementById('reportFailureToast').style.display = 'none'; - }, 6000); - } else if (status === 'permissionsFailure') { - generateInProgressToast.innerHTML = permissionsMissingOnGeneration(); - setTimeout(function () { - document.getElementById( - 'permissionsMissingErrorToast' - ).style.display = 'none'; - }, 6000); - } - generateToast[0].appendChild(generateInProgressToast.children[0]); - } catch (e) { - console.log('error displaying toast', e); - } - } -}; - -export const replaceQueryURL = (pageUrl) => { - // we unhash the url in case OpenSearch Dashboards advanced UI setting 'state:storeInSessionStorage' is turned on - const unhashedUrl = new URL(unhashUrl(pageUrl)); - let queryUrl = unhashedUrl.pathname + unhashedUrl.hash; - let [, fromDateStringMatch, toDateStringMatch] = - queryUrl.match(timeRangeMatcher); - const fromDateString = decodeURIComponent(fromDateStringMatch.replace(/[']+/g, '')); - - // convert time range to from date format in case time range is relative - const fromDateFormat = dateMath.parse(fromDateString); - const toDateString = decodeURIComponent(toDateStringMatch.replace(/[']+/g, '')); - const toDateFormat = dateMath.parse(toDateString, { roundUp: true }); - - // replace to and from dates with absolute date - queryUrl = queryUrl.replace( - fromDateStringMatch, - "'" + fromDateFormat.toISOString() + "'" - ); - queryUrl = queryUrl.replace( - toDateStringMatch, - "'" + toDateFormat.toISOString() + "'" - ); - return queryUrl; -}; diff --git a/dashboards-reports/public/components/context_menu/context_menu_ui.js b/dashboards-reports/public/components/context_menu/context_menu_ui.js deleted file mode 100644 index 0c99641f..00000000 --- a/dashboards-reports/public/components/context_menu/context_menu_ui.js +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { i18n } from '@osd/i18n'; - -export const getMenuItem = (name) => { - return ` - - `; -}; - -export const popoverMenu = (savedObjectAvailable) => { - const buttonClass = savedObjectAvailable - ? 'euiContextMenuItem' - : 'euiContextMenuItem euiContextMenuItem-isDisabled'; - const button = savedObjectAvailable ? 'button' : 'button disabled'; - const popoverHeight = savedObjectAvailable ? '395px' : '380px'; - const message = savedObjectAvailable - ? i18n.translate('opensearch.reports.menu.visual.waitPrompt', { - defaultMessage: - 'Files can take a minute or two to generate depending on the size of your source data.', - }) - : i18n.translate('opensearch.reports.menu.visual.savePrompt', { - defaultMessage: - 'Save this Visualization/Dashboard to enable PDF/PNG reports.', - }); - - const arrowRight = '100px'; - const popoverRight = '77px'; - - return ` -
-
-
-
-
-
- -
-
- `; -}; - -// TODO: merge this function and popoverMenu() into one -export const popoverMenuDiscover = (savedObjectAvailable) => { - const buttonClass = savedObjectAvailable - ? 'euiContextMenuItem' - : 'euiContextMenuItem euiContextMenuItem-isDisabled'; - const button = savedObjectAvailable ? 'button' : 'button disabled'; - const popoverHeight = savedObjectAvailable ? '354px' : '322px'; - const message = savedObjectAvailable - ? i18n.translate('opensearch.reports.menu.csv.waitPrompt', { - defaultMessage: - 'Files can take a minute or two to generate depending on the size of your source data.', - }) - : i18n.translate('opensearch.reports.menu.csv.savePrompt', { - defaultMessage: 'Save this search to enable CSV reports.', - }); - const arrowRight = '60px'; - const popoverRight = '77px'; - - return ` -
-
-
-
-
-
- -
-
- `; -}; - -export const permissionsMissingOnGeneration = () => { - return ` -
-

${i18n.translate( - 'opensearch.reports.menu.newNotificationAppears', - { defaultMessage: 'A new notification appears' } - )}

-
- - ${i18n.translate( - 'opensearch.reports.menu.errorGeneratingReport', - { defaultMessage: 'Error generating report.' } - )} -
- -
-

${i18n.translate('opensearch.reports.menu.insufficientPermissions', { - defaultMessage: - 'Insufficient permissions. Reach out to your OpenSearch Dashboards administrator.', - })}

-
-
- `; -}; - -export const reportGenerationSuccess = () => { - return ` -
-

A new notification appears

-
- - ${i18n.translate( - 'opensearch.reports.menu.successfullyGenerated', - { defaultMessage: 'Successfully generated report.' } - )} -
- - -
- `; -}; - -export const reportGenerationFailure = ( - title = i18n.translate('opensearch.reports.menu.downloadError', { - defaultMessage: 'Download error', - }), - text = i18n.translate('opensearch.reports.menu.errorGeneratingThisReport', { - defaultMessage: 'There was an error generating this report.', - }) -) => { - return ` -
-

A new notification appears

-
- - ${title} -
- -
-

${text}

-
-
- `; -}; - -export const reportGenerationInProgressModal = () => { - return ` -
-
-
-
-
- -
-
-
-
-

${i18n.translate( - 'opensearch.reports.menu.progress.generatingReport', - { defaultMessage: 'Generating report' } - )}

-
-
-
-
-
-
${i18n.translate( - 'opensearch.reports.menu.progress.preparingYourFile', - { defaultMessage: 'Preparing your file for download.' } - )}
-
${i18n.translate( - 'opensearch.reports.menu.progress.youCanClose', - { - defaultMessage: - 'You can close this dialog while we continue in the background.', - } - )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `; -}; diff --git a/dashboards-reports/public/components/main/__tests__/__snapshots__/main.test.tsx.snap b/dashboards-reports/public/components/main/__tests__/__snapshots__/main.test.tsx.snap deleted file mode 100644 index 7f552895..00000000 --- a/dashboards-reports/public/components/main/__tests__/__snapshots__/main.test.tsx.snap +++ /dev/null @@ -1,3908 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`
panel render component 1`] = ` -
-
-
-
-

- Reports - -

- ( - 0 - ) -

-

-
- - - -
-
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Creation time - - - - - - - - Generate - - -
-
- -
-

- No reports to display -

- -
-
-
-
- Create a report definition, or share/download a report from a dashboard, saved search or visualization. -
- -
-
- -
-
-
-
-
-
-
-
-
-
-
-
-

- Report definitions -

- - ( - 0 - ) -

-

-
-
- -
- - - -
-
-
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Schedule details - - - - - - Last Updated - - - - -
-
- -
-

- No report definitions to display -

- -
-
-
-
- Create a new report definition to get started -
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-
-
-
-`; - -exports[`
panel render component after create success 1`] = ` -
-
-
-
-

- Reports - -

- ( - 0 - ) -

-

-
- - - -
-
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Creation time - - - - - - - - Generate - - -
-
- -
-

- No reports to display -

- -
-
-
-
- Create a report definition, or share/download a report from a dashboard, saved search or visualization. -
- -
-
- -
-
-
-
-
-
-
-
-
-
-
-
-

- Report definitions -

- - ( - 0 - ) -

-

-
-
- -
- - - -
-
-
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Schedule details - - - - - - Last Updated - - - - -
-
- -
-

- No report definitions to display -

- -
-
-
-
- Create a new report definition to get started -
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-
-
-
-

- A new notification appears -

-
- - - Successfully created report definition. - -
- -
-
-
-`; - -exports[`
panel render component after delete success 1`] = ` -
-
-
-
-

- Reports - -

- ( - 0 - ) -

-

-
- - - -
-
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Creation time - - - - - - - - Generate - - -
-
- -
-

- No reports to display -

- -
-
-
-
- Create a report definition, or share/download a report from a dashboard, saved search or visualization. -
- -
-
- -
-
-
-
-
-
-
-
-
-
-
-
-

- Report definitions -

- - ( - 0 - ) -

-

-
-
- -
- - - -
-
-
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Schedule details - - - - - - Last Updated - - - - -
-
- -
-

- No report definitions to display -

- -
-
-
-
- Create a new report definition to get started -
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-
-
-
-

- A new notification appears -

-
- - - Successfully deleted report definition. - -
- -
-
-
-`; - -exports[`
panel render component after edit success 1`] = ` -
-
-
-
-

- Reports - -

- ( - 0 - ) -

-

-
- - - -
-
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Creation time - - - - - - - - Generate - - -
-
- -
-

- No reports to display -

- -
-
-
-
- Create a report definition, or share/download a report from a dashboard, saved search or visualization. -
- -
-
- -
-
-
-
-
-
-
-
-
-
-
-
-

- Report definitions -

- - ( - 0 - ) -

-

-
-
- -
- - - -
-
-
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Schedule details - - - - - - Last Updated - - - - -
-
- -
-

- No report definitions to display -

- -
-
-
-
- Create a new report definition to get started -
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-
-
-
-

- A new notification appears -

-
- - - Successfully updated report definition. - -
- -
-
-
-`; diff --git a/dashboards-reports/public/components/main/__tests__/__snapshots__/report_definitions_table.test.tsx.snap b/dashboards-reports/public/components/main/__tests__/__snapshots__/report_definitions_table.test.tsx.snap deleted file mode 100644 index a2a56bfd..00000000 --- a/dashboards-reports/public/components/main/__tests__/__snapshots__/report_definitions_table.test.tsx.snap +++ /dev/null @@ -1,954 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` panel render component 1`] = ` -
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Schedule details - - - - - - Last Updated - - - - -
-
- Name -
-
- -
-
-
- Source -
-
- -
-
-
- Type -
-
- - Download - -
-
-
- Schedule details -
-
- -
-
-
- Last Updated -
-
-
- Invalid Date @ Invalid Date -
-
-
-
- Status -
-
- - Created - -
-
-
- Name -
-
- -
-
-
- Source -
-
- -
-
-
- Type -
-
- - Download - -
-
-
- Schedule details -
-
- -
-
-
- Last Updated -
-
-
- Invalid Date @ Invalid Date -
-
-
-
- Status -
-
- - Created - -
-
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-`; - -exports[` panel render empty table 1`] = ` -
-
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Schedule details - - - - - - Last Updated - - - - -
-
- -
-

- No report definitions to display -

- -
-
-
-
- Create a new report definition to get started -
- -
-
- -
-
- -
-
- -
-
-
-
-
-
-`; diff --git a/dashboards-reports/public/components/main/__tests__/__snapshots__/reports_table.test.tsx.snap b/dashboards-reports/public/components/main/__tests__/__snapshots__/reports_table.test.tsx.snap deleted file mode 100644 index d2593c6e..00000000 --- a/dashboards-reports/public/components/main/__tests__/__snapshots__/reports_table.test.tsx.snap +++ /dev/null @@ -1,1025 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` panel render component 1`] = ` -
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Creation time - - - - - - - - Generate - - -
-
- Name -
-
- -
-
-
- Source -
- -
-
- Type -
-
- - Test type - -
-
-
- Creation time -
-
-
- Invalid Date @ Invalid Date -
-
-
-
- State -
-
- - Created - -
-
-
- Generate -
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-`; - -exports[` panel render empty component 1`] = ` -
-
-
-
-
- -
- - - -
-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- - - - - - - - - - - - - - - - -
-
- - - Name - - - - - - Source - - - - - - - - Creation time - - - - - - - - Generate - - -
-
- -
-

- No reports to display -

- -
-
-
-
- Create a report definition, or share/download a report from a dashboard, saved search or visualization. -
- -
-
- -
-
-
-
-
-
-
-`; diff --git a/dashboards-reports/public/components/main/__tests__/__utils__/main_utils_test_utils.tsx b/dashboards-reports/public/components/main/__tests__/__utils__/main_utils_test_utils.tsx deleted file mode 100644 index 28e8e36b..00000000 --- a/dashboards-reports/public/components/main/__tests__/__utils__/main_utils_test_utils.tsx +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export const reportTableMockResponse = [ - { - _id: '123456', - _index: 'test', - _score: 1, - _source: { - last_updated: 123456789, - query_url: 'test_query_url_value.com', - report_definition: { - delivery: { - delivery_type: 'OpenSearch Dashboards user', - delivery_params: { - opensearch_dashboards_recipients: [], - }, - }, - report_params: { - report_name: 'Test report table response', - description: 'description', - report_source: 'Dashboard', - core_params: { - base_url: 'test_base_url.com', - header: '', - footer: '', - report_format: 'pdf', - time_duration: 'PT30M', - window_height: 800, - window_width: 1200, - }, - }, - trigger: { - trigger_type: 'On demand', - }, - state: 'Created', - time_created: 123456780, - time_from: 123456780, - time_to: 123456799, - }, - }, - _type: 'doc', - }, -]; - -export const mockReportsTableItems = [ - { - id: '123456', - reportName: 'Test report table response', - type: 'On demand', - sender: '—', - opensearchDashboardsRecipients: '—', - emailRecipients: '—', - reportSource: 'Dashboard', - timeCreated: undefined, - state: undefined, - url: 'test_query_url_value.com', - format: 'pdf', - }, -]; - -export const reportDefinitionsTableMockResponse = [ - { - _index: 'report_definition', - _type: '_doc', - _id: '42MmKXUBDW-VXnk7pa6d', - _score: 1, - _source: { - report_definition: { - report_params: { - report_name: 'schedule definition', - report_source: 'Dashboard', - description: 'description', - core_params: { - base_url: 'test_base_url.com', - report_format: 'pdf', - header: '', - footer: '', - time_duration: 'PT30M', - window_width: 1200, - window_height: 800, - }, - }, - delivery: { - delivery_type: 'OpenSearch Dashboards user', - delivery_params: { opensearch_dashboards_recipients: [] }, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - enabled_time: 1602713178321, - schedule: { - period: 1, - interval: 'DAYS', - }, - schedule_type: 'Recurring', - enabled: false, - }, - }, - time_created: 1602713199604, - last_updated: 1602713211007, - status: 'Disabled', - }, - }, - }, -]; - -export const reportDefinitionsTableMockContent = [ - { - id: '42MmKXUBDW-VXnk7pa6d', - reportName: 'schedule definition', - type: 'Schedule', - owner: '—', - source: 'Dashboard', - baseUrl: 'test_base_url.com', - lastUpdated: 1602713211007, - details: 'Recurring', - status: 'Disabled', - }, -]; diff --git a/dashboards-reports/public/components/main/__tests__/main.test.tsx b/dashboards-reports/public/components/main/__tests__/main.test.tsx deleted file mode 100644 index 3142326e..00000000 --- a/dashboards-reports/public/components/main/__tests__/main.test.tsx +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { render } from '@testing-library/react'; -import { Main } from '../main'; -import httpClientMock from '../../../../test/httpMockClient'; -import { configure, mount } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import { act } from 'react-dom/test-utils'; - -function setBreadcrumbs(array: []) { - jest.fn(); -} - -describe('
panel', () => { - configure({ adapter: new Adapter() }); - test('render component', (done) => { - window = Object.create(window); - Object.defineProperty(window, 'location', { - configurable: true, - value: { - assign: jest.fn(), - href: 'reports-dashboards#/', - }, - }); - - const { container } = render( -
- ); - - expect(container.firstChild).toMatchSnapshot(); - done(); - }); - - test('render component after create success', async () => { - delete window.location; - - Object.defineProperty(window, 'location', { - configurable: true, - value: { - assign: jest.fn(), - href: 'reports-dashboards#/create=success', - }, - }); - - const { container } = render( -
- ); - - expect(container.firstChild).toMatchSnapshot(); - }); - - test('render component after edit success', async () => { - delete window.location; - - Object.defineProperty(window, 'location', { - configurable: true, - value: { - assign: jest.fn(), - href: 'reports-dashboards#/edit=success', - }, - }); - - const { container } = render( -
- ); - - expect(container.firstChild).toMatchSnapshot(); - }); - - test('render component after delete success', async () => { - delete window.location; - - Object.defineProperty(window, 'location', { - configurable: true, - value: { - assign: jest.fn(), - href: 'reports-dashboards#/delete=success', - }, - }); - - const { container } = render( -
- ); - - expect(container.firstChild).toMatchSnapshot(); - }) - - test('test refresh reports definitions button', async () => { - const promise = Promise.resolve(); - const data = [ - { - _id: 'abcdefg', - _source: { - query_url: '/app/visualize/edit/1234567890', - state: 'Created', - time_created: 123456789, - time_from: 123456789, - time_to: 1234567890, - report_definition: { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: 'http://localhost:5601', - report_format: 'png', - header: '', - footer: '', - time_duration: 'PT30M', - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: {}, - }, - }, - }, - }, - ]; - - httpClientMock.get = jest.fn().mockResolvedValue({ - data, - }); - - const component = mount( -
- ); - await act(() => promise); - - const generate = component.find('button').at(7); - generate.simulate('click'); - await act(() => promise); - }); - - test('test refresh reports table button', async () => { - const promise = Promise.resolve(); - const data = [ - { - _id: 'abcdefg', - _source: { - query_url: '/app/visualize/edit/1234567890', - state: 'Created', - time_created: 123456789, - time_from: 123456789, - time_to: 1234567890, - report_definition: { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: 'http://localhost:5601', - report_format: 'png', - header: '', - footer: '', - time_duration: 'PT30M', - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: {}, - }, - }, - }, - }, - ]; - - httpClientMock.get = jest.fn().mockResolvedValue({ - data, - }); - - const component = mount( -
- ); - await act(() => promise); - - const generate = component.find('button').at(0); - generate.simulate('click'); - await act(() => promise); - }); - - // TODO: mock catch() error response to contain status code - test.skip('test error toasts posted', async () => { - jest.spyOn(console, 'log').mockImplementation(() => {}); // silence console log error from main - const promise = Promise.resolve(); - - httpClientMock.get = jest.fn().mockResolvedValue({ - response: null, - }); - - const component = mount( -
- ); - const generate = component.find('button').at(7); - try { - generate.simulate('click'); - await act(() => promise); - } catch (e) { - await act(() => promise); - } - }); -}); diff --git a/dashboards-reports/public/components/main/__tests__/main_utils.test.tsx b/dashboards-reports/public/components/main/__tests__/main_utils.test.tsx deleted file mode 100644 index 8f852a45..00000000 --- a/dashboards-reports/public/components/main/__tests__/main_utils.test.tsx +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - humanReadableDate, - extractFilename, - extractFileFormat, - getFileFormatPrefix, - addReportsTableContent, - addReportDefinitionsTableContent, - removeDuplicatePdfFileFormat, - readStreamToFile, - generateReportFromDefinitionId, - generateReportById, -} from '../main_utils'; -import { - reportDefinitionsTableMockResponse, - mockReportsTableItems, - reportTableMockResponse, - reportDefinitionsTableMockContent, -} from './__utils__/main_utils_test_utils'; -import sinon from 'sinon'; -import httpClientMock from '../../../../test/httpMockClient'; - -describe('main_utils tests', () => { - global.URL.createObjectURL = jest.fn(); - let mockElement = document.createElement('a'); - mockElement.download = 'string'; - mockElement.click = function name() {}; - sinon.stub(document, 'createElement').returns(mockElement); - - test('test humanReadableDate', () => { - const readableDate = new Date(2018, 11, 24, 10, 33, 30); - const humanReadable = humanReadableDate(readableDate); - - expect(humanReadable).toBe('Mon Dec 24 2018 @ 10:33:30 AM'); - }); - - test('test extractFileName', () => { - const fullFile = 'test_file_name_extracted_correctly.pdf'; - const fileName = extractFilename(fullFile); - - expect(fileName).toBe('test_file_name_extracted_correctly'); - }); - - test('test extractFileFormat', () => { - const fullFile = 'test_file_format_extracted_correctly.png'; - const fileFormat = extractFileFormat(fullFile); - - expect(fileFormat).toBe('png'); - }); - - test('test getFileFormatPrefix', () => { - const fileFormat = 'pdf'; - const fileFormatPrefix = getFileFormatPrefix(fileFormat); - - expect(fileFormatPrefix).toBe('data:pdf;base64,'); - }); - - test('test addReportsTableContent', () => { - const reportsTableItems = addReportsTableContent(reportTableMockResponse); - - expect(reportsTableItems).toStrictEqual(mockReportsTableItems); - }); - - test('test addReportDefinitionsTableContent', () => { - const reportDefinitionsTableItems = addReportDefinitionsTableContent( - reportDefinitionsTableMockResponse - ); - - expect(reportDefinitionsTableItems).toStrictEqual( - reportDefinitionsTableMockContent - ); - }); - - test('test removeDuplicatePdfFileFormat', () => { - const duplicateFormat = 'test_duplicate_remove.pdf.pdf'; - const duplicateRemoved = removeDuplicatePdfFileFormat(duplicateFormat); - - expect(duplicateRemoved).toBe('test_duplicate_remove.pdf'); - }); - - test('test readStreamToFile csv compile', () => { - const stream = - 'category,customer_gender\n' + - 'c1,Male\n' + - 'c2,Male\n' + - 'c3,Male\n' + - 'c4,Male\n' + - 'c5,Male'; - - const fileFormat = 'csv'; - const fileName = 'test_data_report.csv'; - readStreamToFile(stream, fileFormat, fileName); - }); - - test('test readStreamToFile pdf compile', () => { - const stream = 'data:pdf;base64,zxvniaorbguw40absdoanlsdf'; - const fileFormat = 'pdf'; - const fileName = 'test_pdf_report.pdf'; - readStreamToFile(stream, fileFormat, fileName); - }); - - test('test generateReport compile', () => { - const reportDefinitionId = '1'; - generateReportFromDefinitionId(reportDefinitionId, httpClientMock); - }); - - test('test generateReportById compile', () => { - const reportId = '1'; - const handleSuccessToast = jest.fn(); - const handleErrorToast = jest.fn(); - generateReportById( - reportId, - httpClientMock, - handleSuccessToast, - handleErrorToast - ); - }); - - test('test generateReportById timeout error handling', async () => { - expect.assertions(1); - const reportId = '1'; - const handleSuccessToast = jest.fn(); - const handleErrorToast = jest.fn(); - const handlePermissionsMissingToast = jest.fn(); - - httpClientMock.get.mockReturnValue( - Promise.reject({ body: { statusCode: 503 } }) - ); - - await generateReportById( - reportId, - httpClientMock, - handleSuccessToast, - handleErrorToast, - handlePermissionsMissingToast - ); - expect(handleErrorToast).toHaveBeenCalledWith( - 'Error generating report.', - 'Timed out generating report ID 1. Try again later.' - ); - }); -}); diff --git a/dashboards-reports/public/components/main/__tests__/report_definitions_table.test.tsx b/dashboards-reports/public/components/main/__tests__/report_definitions_table.test.tsx deleted file mode 100644 index c6ff2d63..00000000 --- a/dashboards-reports/public/components/main/__tests__/report_definitions_table.test.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { render } from '@testing-library/react'; -import { ReportDefinitions } from '../report_definitions_table'; -import { configure, mount } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; - -const pagination = { - initialPageSize: 10, - pageSizeOptions: [8, 10, 13], -}; - -describe(' panel', () => { - configure({ adapter: new Adapter() }); - test('render component', () => { - let reportDefinitionsTableContent = [ - { - reportName: 'test report name', - type: 'Download', - owner: 'davidcui', - source: 'Dashboard', - lastUpdated: 'test updated time', - details: '', - status: 'Created', - }, - { - reportName: 'test report name 2', - type: 'Download', - owner: 'davidcui', - source: 'Dashboard', - lastUpdated: 'test updated time', - details: '', - status: 'Created', - }, - ]; - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); - }); - - test('render empty table', () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); - }); - - test('test click on report definition row', async () => { - window = Object.create(window); - Object.defineProperty(window, 'location', { - configurable: true, - value: { - assign: jest.fn(), - }, - }); - let promise = Promise.resolve(); - let reportDefinitionsTableContent = [ - { - reportName: 'test report name', - type: 'Download', - owner: 'davidcui', - source: 'Dashboard', - lastUpdated: 'test updated time', - details: '', - status: 'Created', - }, - { - reportName: 'test report name 2', - type: 'Download', - owner: 'davidcui', - source: 'Dashboard', - lastUpdated: 'test updated time', - details: '', - status: 'Created', - }, - ]; - - const component = mount( - - ); - - const nameLink = component.find('button').at(3); - nameLink.simulate('click'); - }); -}); diff --git a/dashboards-reports/public/components/main/__tests__/reports_table.test.tsx b/dashboards-reports/public/components/main/__tests__/reports_table.test.tsx deleted file mode 100644 index 0ec69731..00000000 --- a/dashboards-reports/public/components/main/__tests__/reports_table.test.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { render } from '@testing-library/react'; -import { ReportsTable } from '../reports_table'; -import httpClientMock from '../../../../test/httpMockClient'; -import { configure, mount } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import { act } from 'react-dom/test-utils'; - -const pagination = { - initialPageSize: 10, - pageSizeOptions: [8, 10, 13], -}; - -describe(' panel', () => { - configure({ adapter: new Adapter() }); - test('render component', () => { - let reportsTableItems = [ - { - id: '1', - reportName: 'test report table item', - type: 'Test type', - sender: 'N/A', - recipients: 'N/A', - reportSource: 'Test report source', - lastUpdated: 'test updated time', - state: 'Created', - url: 'Test url', - }, - ]; - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); - }); - - test('render empty component', async () => { - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); - }); - - test('click on generate button', async () => { - const promise = Promise.resolve(); - let reportsTableItems = [ - { - id: '1', - reportName: 'test report table item', - type: 'Test type', - sender: 'N/A', - recipients: 'N/A', - reportSource: 'Test report source', - lastUpdated: 'test updated time', - state: 'Created', - url: 'Test url', - }, - ]; - - const component = mount( - - ); - - const generateClick = component.find('button').at(6); - // console.log(generateClick.debug()); - generateClick.simulate('click'); - await act(() => promise); - }); -}); diff --git a/dashboards-reports/public/components/main/index.ts b/dashboards-reports/public/components/main/index.ts deleted file mode 100644 index 7dd7bc03..00000000 --- a/dashboards-reports/public/components/main/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { Main } from './main'; -export { ReportDetails } from './report_details/report_details'; diff --git a/dashboards-reports/public/components/main/loading_modal/index.ts b/dashboards-reports/public/components/main/loading_modal/index.ts deleted file mode 100644 index 2f6c609b..00000000 --- a/dashboards-reports/public/components/main/loading_modal/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - - export { GenerateReportLoadingModal } from './loading_modal'; \ No newline at end of file diff --git a/dashboards-reports/public/components/main/loading_modal/loading_modal.tsx b/dashboards-reports/public/components/main/loading_modal/loading_modal.tsx deleted file mode 100644 index ff3f70c2..00000000 --- a/dashboards-reports/public/components/main/loading_modal/loading_modal.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiOverlayMask, - EuiModal, - EuiModalHeader, - EuiTitle, - EuiText, - EuiModalBody, - EuiSpacer, - EuiFlexGroup, - EuiFlexItem, - EuiLoadingSpinner, - EuiButton, -} from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import React, { useState } from 'react'; - -export function GenerateReportLoadingModal(props: { setShowLoading: any }) { - const { setShowLoading } = props; - - const [isModalVisible, setIsModalVisible] = useState(true); - - const closeModal = () => { - setIsModalVisible(false); - setShowLoading(false); - }; - const showModal = () => setIsModalVisible(true); - - return ( -
- - - - - -

- {i18n.translate( - 'opensearch.reports.loading.generatingReport', - { defaultMessage: 'Generating report' } - )} -

-
-
-
- - - {i18n.translate('opensearch.reports.loading.preparingYourFile', { - defaultMessage: 'Preparing your file for download.', - })} - - - {i18n.translate('opensearch.reports.loading.youCanClose', { - defaultMessage: - 'You can close this dialog while we continue in the background.', - })} - - - - - - - - - - - - {i18n.translate('opensearch.reports.loading.close', { - defaultMessage: 'Close', - })} - - - - -
-
-
- ); -} diff --git a/dashboards-reports/public/components/main/main.tsx b/dashboards-reports/public/components/main/main.tsx deleted file mode 100644 index bfbb8cb9..00000000 --- a/dashboards-reports/public/components/main/main.tsx +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { Fragment, useState, useEffect } from 'react'; -import { i18n } from '@osd/i18n'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiButton, - EuiTitle, - // @ts-ignore - EuiHorizontalRule, - EuiSpacer, - EuiPanel, - EuiGlobalToastList, -} from '@elastic/eui'; -import { ReportsTable } from './reports_table'; -import { ReportDefinitions } from './report_definitions_table'; -import { - addReportsTableContent, - addReportDefinitionsTableContent, -} from './main_utils'; -import CSS from 'csstype'; -import { - permissionsMissingToast, - permissionsMissingActions, -} from '../utils/utils'; - -const reportCountStyles: CSS.Properties = { - color: 'gray', - display: 'inline', -}; - -export function Main(props) { - const [reportsTableContent, setReportsTableContent] = useState([]); - const [ - reportDefinitionsTableContent, - setReportDefinitionsTableContent, - ] = useState([]); - const [toasts, setToasts] = useState([]); - - const addPermissionsMissingDownloadToastHandler = () => { - const toast = permissionsMissingToast( - permissionsMissingActions.GENERATING_REPORT - ); - setToasts(toasts.concat(toast)); - }; - - const handlePermissionsMissingDownloadToast = () => { - addPermissionsMissingDownloadToastHandler(); - }; - - const addReportsTableContentErrorToastHandler = (errorType: string) => { - let toast = {}; - if (errorType === 'permissions') { - toast = permissionsMissingToast( - permissionsMissingActions.LOADING_REPORTS_TABLE - ); - } else if (errorType === 'API') { - toast = { - title: i18n.translate( - 'opensearch.reports.main.errorGeneratingReportsTable.', - { defaultMessage: 'Error generating reports table.' } - ), - color: 'danger', - iconType: 'alert', - id: 'reportsTableErrorToast', - }; - } - setToasts(toasts.concat(toast)); - }; - - const handleReportsTableErrorToast = (errorType: string) => { - addReportsTableContentErrorToastHandler(errorType); - }; - - const addReportDefinitionsTableErrorToastHandler = (errorType: string) => { - let toast = {}; - if (errorType === 'permissions') { - toast = permissionsMissingToast( - permissionsMissingActions.LOADING_DEFINITIONS_TABLE - ); - } else if (errorType === 'API') { - toast = { - title: i18n.translate( - 'opensearch.reports.main.errorGeneratingReportDefinitionsTable.', - { defaultMessage: 'Error generating report definitions table.' } - ), - color: 'danger', - iconType: 'alert', - id: 'reportDefinitionsTableErrorToast', - }; - } - setToasts(toasts.concat(toast)); - }; - - const handleReportDefinitionsTableErrorToast = (errorType: string) => { - addReportDefinitionsTableErrorToastHandler(errorType); - }; - - const addErrorOnDemandDownloadToastHandler = ( - title = i18n.translate('opensearch.reports.main.errorDownloadingReport', { - defaultMessage: 'Error downloading report.', - }), - text = '' - ) => { - const errorToast = { - title, - text, - color: 'danger', - iconType: 'alert', - id: 'onDemandDownloadErrorToast', - }; - setToasts(toasts.concat(errorToast)); - }; - - const handleOnDemandDownloadErrorToast = (title?: string, text?: string) => { - addErrorOnDemandDownloadToastHandler(title, text); - }; - - const addSuccessOnDemandDownloadToastHandler = () => { - const successToast = { - title: i18n.translate( - 'opensearch.reports.main.successfullyDownloadedReport', - { defaultMessage: 'Successfully downloaded report.' } - ), - color: 'success', - iconType: 'check', - id: 'onDemandDownloadSuccessToast', - }; - setToasts(toasts.concat(successToast)); - }; - - const handleOnDemandDownloadSuccessToast = () => { - addSuccessOnDemandDownloadToastHandler(); - }; - - const addCreateReportDefinitionSuccessToastHandler = () => { - const successToast = { - title: i18n.translate( - 'opensearch.reports.main.successfullyCreatedReportDefinition', - { defaultMessage: 'Successfully created report definition.' } - ), - color: 'success', - iconType: 'check', - id: 'createReportDefinitionSuccessToast', - }; - setToasts(toasts.concat(successToast)); - }; - - const handleCreateReportDefinitionSuccessToast = () => { - addCreateReportDefinitionSuccessToastHandler(); - }; - - const addEditReportDefinitionSuccessToastHandler = () => { - const successToast = { - title: i18n.translate( - 'opensearch.reports.main.successfullyUpdatedReportDefinition', - { defaultMessage: 'Successfully updated report definition.' } - ), - color: 'success', - iconType: 'check', - id: 'editReportDefinitionSuccessToast', - }; - setToasts(toasts.concat(successToast)); - }; - - const handleEditReportDefinitionSuccessToast = () => { - addEditReportDefinitionSuccessToastHandler(); - }; - - const addDeleteReportDefinitionSuccessToastHandler = () => { - const successToast = { - title: i18n.translate( - 'opensearch.reports.main.successfullyDeletedReportDefinition', - { defaultMessage: 'Successfully deleted report definition.' } - ), - color: 'success', - iconType: 'check', - id: 'deleteReportDefinitionSuccessToast', - }; - setToasts(toasts.concat(successToast)); - }; - - const handleDeleteReportDefinitionSuccessToast = () => { - addDeleteReportDefinitionSuccessToastHandler(); - }; - - const removeToast = (removedToast) => { - setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); - }; - - const pagination = { - initialPageSize: 10, - pageSizeOptions: [5, 10, 20], - }; - - useEffect(() => { - props.setBreadcrumbs([ - { - text: i18n.translate('opensearch.reports.main.title.reporting', { - defaultMessage: 'Reporting', - }), - href: '#', - }, - ]); - refreshReportsTable(); - refreshReportsDefinitionsTable(); - - if (window.location.href.includes('create=success')) { - handleCreateReportDefinitionSuccessToast(); - // refresh might not fetch the latest changes when coming from create or edit page - // workaround to wait 1 second and refresh again - setTimeout(() => { - refreshReportsTable(); - refreshReportsDefinitionsTable(); - }, 1000); - } else if (window.location.href.includes('edit=success')) { - handleEditReportDefinitionSuccessToast(); - setTimeout(() => { - refreshReportsTable(); - refreshReportsDefinitionsTable(); - }, 1000); - } else if (window.location.href.includes('delete=success')) { - handleDeleteReportDefinitionSuccessToast(); - setTimeout(() => { - refreshReportsTable(); - refreshReportsDefinitionsTable(); - }, 1000); - } - window.location.href = 'reports-dashboards#/'; - }, []); - - const refreshReportsTable = async () => { - const { httpClient } = props; - await httpClient - .get('../api/reporting/reports') - .then((response) => { - setReportsTableContent(addReportsTableContent(response.data)); - }) - .catch((error) => { - console.log('error when fetching all reports: ', error); - // permission denied error - if (error.body.statusCode === 403) { - handleReportsTableErrorToast('permissions'); - } else { - handleReportsTableErrorToast('API'); - } - }); - }; - - const refreshReportsDefinitionsTable = async () => { - const { httpClient } = props; - await httpClient - .get('../api/reporting/reportDefinitions') - .then((response) => { - setReportDefinitionsTableContent( - addReportDefinitionsTableContent(response.data) - ); - }) - .catch((error) => { - console.log('error when fetching all report definitions: ', error); - if (error.body.statusCode === 403) { - handleReportDefinitionsTableErrorToast('permissions'); - } else { - handleReportDefinitionsTableErrorToast('API'); - } - }); - }; - - return ( -
- - - - -

- {i18n.translate('opensearch.reports.main.title.reports', { - defaultMessage: 'Reports', - })}{' '} -

({reportsTableContent.length})

-

-
-
- - - {i18n.translate( - 'opensearch.reports.main.reports.button.refresh', - { defaultMessage: 'Refresh' } - )} - - -
- - -
- - - - - -

- {i18n.translate( - 'opensearch.reports.main.title.reportDefinitions', - { defaultMessage: 'Report definitions' } - )} -

- {' '} - ({reportDefinitionsTableContent.length}) -

-

-
-
- - - {i18n.translate( - 'opensearch.reports.main.reportDefinitions.button.refresh', - { defaultMessage: 'Refresh' } - )} - - - - { - window.location.assign('reports-dashboards#/create'); - }} - id={'createReportHomepageButton'} - > - {i18n.translate( - 'opensearch.reports.main.reportDefinitions.button.create', - { defaultMessage: 'Create' } - )} - - -
- - -
- -
- ); -} diff --git a/dashboards-reports/public/components/main/main_utils.tsx b/dashboards-reports/public/components/main/main_utils.tsx deleted file mode 100644 index 44066c02..00000000 --- a/dashboards-reports/public/components/main/main_utils.tsx +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import 'babel-polyfill'; -import { i18n } from '@osd/i18n'; -import { HttpFetchOptions, HttpSetup } from '../../../../../src/core/public'; -import { uiSettingsService } from '../utils/settings_service'; - -export const getAvailableNotificationsChannels = (configList: any) => { - let availableChannels = []; - for (let i = 0; i < configList.length; ++i) { - let channelEntry = {}; - channelEntry = { - label: configList[i].config.name, - id: configList[i].config_id - } - availableChannels.push(channelEntry); - } - return availableChannels; -} - -type fileFormatsOptions = { - [key: string]: string -} - -export const fileFormatsUpper: fileFormatsOptions = { - csv: 'CSV', - pdf: 'PDF', - png: 'PNG', -}; - -export const humanReadableDate = (date: string | number | Date) => { - let readableDate = new Date(date); - return ( - readableDate.toDateString() + ' @ ' + readableDate.toLocaleTimeString() - ); -}; - -export const extractFilename = (filename: string) => { - return filename.substring(0, filename.length - 4); -}; - -export const extractFileFormat = (filename: string) => { - const fileFormat = filename; - return fileFormat.substring(filename.length - 3, filename.length); -}; - -export const getFileFormatPrefix = (fileFormat: string) => { - var fileFormatPrefix = 'data:' + fileFormat + ';base64,'; - return fileFormatPrefix; -}; - -export const addReportsTableContent = (data: string | any[]) => { - let reportsTableItems = []; - for (let index = 0; index < data.length; ++index) { - let item = data[index]; - let report = item._source; - let reportDefinition = report.report_definition; - let reportParams = reportDefinition.report_params; - let trigger = reportDefinition.trigger; - - let reportsTableEntry = { - id: item._id, - reportName: reportParams.report_name, - type: trigger.trigger_type, - sender: `\u2014`, - opensearchDashboardsRecipients: `\u2014`, - emailRecipients: `\u2014`, - reportSource: reportParams.report_source, - //TODO: wrong name - timeCreated: report.time_created, - state: report.state, - url: report.query_url, - format: reportParams.core_params.report_format, - }; - reportsTableItems.push(reportsTableEntry); - } - return reportsTableItems; -}; - -export const addReportDefinitionsTableContent = (data: any) => { - let reportDefinitionsTableItems = []; - for (let index = 0; index < data.length; ++index) { - let item = data[index]; - let reportDefinition = item._source.report_definition; - let reportParams = reportDefinition.report_params; - let trigger = reportDefinition.trigger; - let triggerParams = trigger.trigger_params; - let reportDefinitionsTableEntry = { - id: item._id, - reportName: reportParams.report_name, - type: trigger.trigger_type, - owner: `\u2014`, // Todo: replace - source: reportParams.report_source, - baseUrl: reportParams.core_params.base_url, - lastUpdated: reportDefinition.last_updated, - details: - trigger.trigger_type === 'On demand' - ? `\u2014` - : triggerParams.schedule_type, // e.g. recurring, cron based - status: reportDefinition.status, - }; - reportDefinitionsTableItems.push(reportDefinitionsTableEntry); - } - return reportDefinitionsTableItems; -}; - -export const removeDuplicatePdfFileFormat = (filename: string) => { - return filename.substring(0, filename.length - 4); -}; - -export const readDataReportToFile = async ( - stream: string, - fileFormat: string, - fileName: string -) => { - const blob = new Blob([stream]); - const url = URL.createObjectURL(blob); - let link = document.createElement('a'); - link.setAttribute('href', url); - link.setAttribute('download', fileName); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); -}; - -export const readStreamToFile = async ( - stream: string, - fileFormat: string, - fileName: string -) => { - let link = document.createElement('a'); - if (fileName.includes('csv')) { - readDataReportToFile(stream, fileFormat, fileName); - return; - } - let fileFormatPrefix = getFileFormatPrefix(fileFormat); - let url = fileFormatPrefix + stream; - if (typeof link.download !== 'string') { - window.open(url, '_blank'); - return; - } - link.download = fileName; - link.href = url; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); -}; - -export const generateReportFromDefinitionId = async ( - reportDefinitionId: string, - httpClient: HttpSetup -) => { - let status = false; - let permissionsError = false; - await httpClient - .post(`../api/reporting/generateReport/${reportDefinitionId}`, { - headers: { - 'Content-Type': 'application/json', - }, - query: uiSettingsService.getSearchParams(), - }) - .then(async (response: any) => { - // for emailing a report, this API response doesn't have response body - if (response) { - const fileFormat = extractFileFormat(response['filename']); - const fileName = response['filename']; - await readStreamToFile(await response['data'], fileFormat, fileName); - } - status = true; - }) - .catch((error) => { - console.log('error on generating report:', error); - if (error.body.statusCode === 403) { - permissionsError = true; - } - status = false; - }); - return { - status: status, - permissionsError: permissionsError, - }; -}; - -export const generateReportById = async ( - reportId: string, - httpClient: HttpSetup, - handleSuccessToast, - handleErrorToast, - handlePermissionsMissingToast -) => { - await httpClient - .get(`../api/reporting/generateReport/${reportId}`, { - query: uiSettingsService.getSearchParams(), - }) - .then(async (response) => { - //TODO: duplicate code, extract to be a function that can reuse. e.g. handleResponse(response) - const fileFormat = extractFileFormat(response['filename']); - const fileName = response['filename']; - await readStreamToFile(await response['data'], fileFormat, fileName); - handleSuccessToast(); - return response; - }) - .catch((error) => { - console.log('error on generating report by id:', error); - if (error.body.statusCode === 403) { - handlePermissionsMissingToast(); - } else if (error.body.statusCode === 503) { - handleErrorToast( - i18n.translate('opensearch.reports.utils.errorTitle', { - defaultMessage: 'Error generating report.', - }), - i18n.translate('opensearch.reports.utils.errorText', { - defaultMessage: - 'Timed out generating report ID {reportId}. Try again later.', - values: { reportId: reportId }, - description: 'Error number toast', - }) - ); - } else { - handleErrorToast(); - } - }); -}; diff --git a/dashboards-reports/public/components/main/report_definition_details/__tests__/__snapshots__/report_definition_details.test.tsx.snap b/dashboards-reports/public/components/main/report_definition_details/__tests__/__snapshots__/report_definition_details.test.tsx.snap deleted file mode 100644 index e1b1f857..00000000 --- a/dashboards-reports/public/components/main/report_definition_details/__tests__/__snapshots__/report_definition_details.test.tsx.snap +++ /dev/null @@ -1,1233 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` panel render 5 hours recurring definition details 1`] = ` -
-
-

- Report definition details -

-
-
-
-
-
-
-

-

-
-
-
-
- -
-
- -
-
- -
-
-
-
-

- Report settings -

-
-
-
-
-
- Name -
-
-
-
-
-
-
- Description -
-
-
-
-
-
-
- Created -
-
-
-
-
-
-
- Last updated -
-
-
-
-
-
-
- -
-
-
- Time period -
-
- Last -
-
-
-
-
-
- File format -
-
- -
-
-
-
-
-
-
-
-
-
- Report header -
-
-
-
-
-
-
- Report footer -
-
-
-
-
-
-
-
-
-
-
-
- Report trigger -
-
-
-
-
-
-
- Schedule details -
-
-
-
-
-
-
- Status -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[` panel render disabled daily definition, click 1`] = ` -
-
-

- Report definition details -

-
-
-
-
-
-
-

-

-
-
-
-
- -
-
- -
-
- -
-
-
-
-

- Report settings -

-
-
-
-
-
- Name -
-
-
-
-
-
-
- Description -
-
-
-
-
-
-
- Created -
-
-
-
-
-
-
- Last updated -
-
-
-
-
-
-
- -
-
-
- Time period -
-
- Last -
-
-
-
-
-
- File format -
-
- -
-
-
-
-
-
-
-
-
-
- Report header -
-
-
-
-
-
-
- Report footer -
-
-
-
-
-
-
-
-
-
-
-
- Report trigger -
-
-
-
-
-
-
- Schedule details -
-
-
-
-
-
-
- Status -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[` panel render on demand definition details 1`] = ` -
-
-

- Report definition details -

-
-
-
-
-
-
-

-

-
-
-
-
- -
-
- -
-
- -
-
-
-
-

- Report settings -

-
-
-
-
-
- Name -
-
-
-
-
-
-
- Description -
-
-
-
-
-
-
- Created -
-
-
-
-
-
-
- Last updated -
-
-
-
-
-
-
- -
-
-
- Time period -
-
- Last -
-
-
-
-
-
- File format -
-
- -
-
-
-
-
-
-
-
-
-
- Report header -
-
-
-
-
-
-
- Report footer -
-
-
-
-
-
-
-
-
-
-
-
- Report trigger -
-
-
-
-
-
-
- Schedule details -
-
-
-
-
-
-
- Status -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; diff --git a/dashboards-reports/public/components/main/report_definition_details/__tests__/report_definition_details.test.tsx b/dashboards-reports/public/components/main/report_definition_details/__tests__/report_definition_details.test.tsx deleted file mode 100644 index 7e26cd63..00000000 --- a/dashboards-reports/public/components/main/report_definition_details/__tests__/report_definition_details.test.tsx +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { act, render } from '@testing-library/react'; -import { ReportDefinitionDetails } from '../report_definition_details'; -import httpClientMock from '../../../../../test/httpMockClient'; -import 'babel-polyfill'; -import { configure, mount } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; - -function setBreadcrumbs(array: []) { - jest.fn(); -} - -describe(' panel', () => { - let propsMock = { - match: { - params: { - reportDefinitionId: jest.fn(), - }, - }, - }; - - const match = { - params: { - reportDefinitionId: '1', - }, - }; - beforeEach(() => { - jest.clearAllMocks(); - }); - - configure({ adapter: new Adapter() }); - test('render on demand definition details', async () => { - const promise = Promise.resolve(); - const report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'On demand', - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - config_list: [] - }); - - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('render 5 hours recurring definition details', async () => { - const promise = Promise.resolve(); - const report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - schedule: { - interval: { - period: 5, - unit: 'HOURS', - timezone: 'PST8PDT', - }, - }, - enabled_time: 1114939203, - enabled: true, - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - config_list: [] - }); - - const { container } = render( - - ); - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('render disabled daily definition, click', async () => { - let promise = Promise.resolve(); - const report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - schedule: { - interval: { - period: 1, - unit: 'DAYS', - timezone: 'PST8PDT', - }, - }, - enabled_time: 1114939203, - enabled: false, - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - config_list: [] - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('simulate click on generateReport', async () => { - let promise = Promise.resolve(); - const report_definition = { - report_params: { - report_name: null, - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'On demand', - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - config_list: [] - }); - - const component = mount( - - ); - await act(() => promise); - component.update(); - const statusButton = component.find('button').at(1); - - statusButton.simulate('click'); - await act(() => promise); - }); - - test('simulate click on delete', async () => { - let promise = Promise.resolve(); - const report_definition = { - report_params: { - report_name: null, - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - schedule: { - interval: { - period: 1, - unit: 'DAYS', - timezone: 'PST8PDT', - }, - }, - enabled_time: 1114939203, - enabled: false, - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - config_list: [] - }); - - const component = mount( - - ); - - const statusButton = component.find('button').at(0); - statusButton.update(); - statusButton.simulate('click'); - - await act(() => promise); - }); - - test('simulate click to enable', async () => { - let promise = Promise.resolve(); - const report_definition = { - status: 'Disabled', - report_params: { - report_name: 'test click on enable disable', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - schedule: { - interval: { - period: 1, - unit: 'DAYS', - timezone: 'PST8PDT', - }, - }, - enabled_time: 1114939203, - enabled: false, - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - config_list: [] - }); - - httpClientMock.put = jest.fn().mockResolvedValue({}); - - const component = mount( - - ); - await act(() => promise); - component.update(); - const statusButton = component.find('button').at(1); - - statusButton.simulate('click'); - await act(() => promise); - }); - - test('simulate click to disable', async () => { - let promise = Promise.resolve(); - const report_definition = { - status: 'Active', - report_params: { - report_name: 'test click on enable disable', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - schedule: { - interval: { - period: 1, - unit: 'DAYS', - timezone: 'PST8PDT', - }, - }, - enabled_time: 1114939203, - enabled: true, - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - config_list: [] - }); - - httpClientMock.put = jest.fn().mockResolvedValue({}); - - const component = mount( - - ); - await act(() => promise); - component.update(); - const statusButton = component.find('button').at(1); - - statusButton.simulate('click'); - await act(() => promise); - }); -}); diff --git a/dashboards-reports/public/components/main/report_definition_details/report_definition_details.tsx b/dashboards-reports/public/components/main/report_definition_details/report_definition_details.tsx deleted file mode 100644 index 2d44dfd2..00000000 --- a/dashboards-reports/public/components/main/report_definition_details/report_definition_details.tsx +++ /dev/null @@ -1,837 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useState } from 'react'; -import { i18n } from '@osd/i18n'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiPage, - EuiPageHeader, - EuiTitle, - EuiPageBody, - EuiPageContent, - EuiHorizontalRule, - EuiSpacer, - EuiPageHeaderSection, - EuiButton, - EuiIcon, - EuiLink, - EuiGlobalToastList, - EuiOverlayMask, - EuiConfirmModal, -} from '@elastic/eui'; -import { - ReportDetailsComponent, - formatEmails, - trimAndRenderAsText, -} from '../report_details/report_details'; -import { - fileFormatsUpper, - generateReportFromDefinitionId, -} from '../main_utils'; -import { ReportDefinitionSchemaType } from '../../../../server/model'; -import moment from 'moment'; -import { - permissionsMissingToast, - permissionsMissingActions, -} from '../../utils/utils'; -import { GenerateReportLoadingModal } from '../loading_modal'; - -const ON_DEMAND = 'On demand'; - -interface ReportDefinitionDetails { - name: string; - description: string; - created: string; - lastUpdated: string; - source: string; - timePeriod: string; - fileFormat: string; - status: string | undefined; - reportHeader: string; - reportFooter: string; - triggerType: string; - scheduleDetails: string; - baseUrl: string; -} - -export function ReportDefinitionDetails(props: { match?: any; setBreadcrumbs?: any; httpClient?: any; }) { - const [reportDefinitionDetails, setReportDefinitionDetails] = useState({ - name: '', - description: '', - created: '', - lastUpdated: '', - source: '', - timePeriod: '', - fileFormat: '', - status: '', - reportHeader: '', - reportFooter: '', - triggerType: '', - scheduleDetails: '', - baseUrl: '' - }); - const [ - reportDefinitionRawResponse, - setReportDefinitionRawResponse, - ] = useState({}); - const [toasts, setToasts] = useState([]); - const [showDeleteModal, setShowDeleteModal] = useState(false); - const [showLoading, setShowLoading] = useState(false); - const reportDefinitionId = props.match['params']['reportDefinitionId']; - - const handleLoading = (e: boolean | ((prevState: boolean) => boolean)) => { - setShowLoading(e); - }; - - const handleShowDeleteModal = (e: boolean | ((prevState: boolean) => boolean)) => { - setShowDeleteModal(e); - }; - - const addPermissionsMissingStatusChangeToastHandler = () => { - const toast = permissionsMissingToast( - permissionsMissingActions.CHANGE_SCHEDULE_STATUS - ); - // @ts-ignore - setToasts(toasts.concat(toast)); - }; - - const addPermissionsMissingDeleteToastHandler = () => { - const toast = permissionsMissingToast( - permissionsMissingActions.DELETE_REPORT_DEFINITION - ); - // @ts-ignore - setToasts(toasts.concat(toast)); - }; - - const handlePermissionsMissingDeleteToast = () => { - addPermissionsMissingDeleteToastHandler(); - }; - - const addPermissionsMissingGenerateReportToastHandler = () => { - const toast = permissionsMissingToast( - permissionsMissingActions.GENERATING_REPORT - ); - // @ts-ignore - setToasts(toasts.concat(toast)); - }; - - const addErrorLoadingDetailsToastHandler = () => { - const errorToast = { - title: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.toast.errorLoadingReportDefinitionDetails. ', - { defaultMessage: 'Error loading report definition details.' } - ), - color: 'danger', - iconType: 'alert', - id: 'reportDefinitionDetailsErrorToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const handleDetailsErrorToast = () => { - addErrorLoadingDetailsToastHandler(); - }; - - const addSuccessGeneratingReportToastHandler = () => { - const successToast = { - title: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.toast.successfullyGeneratedReport. ', - { defaultMessage: 'Successfully generated report.' } - ), - color: 'success', - iconType: 'check', - id: 'generateReportSuccessToast', - }; - // @ts-ignore - setToasts(toasts.concat(successToast)); - }; - - const handleSuccessGeneratingReportToast = () => { - addSuccessGeneratingReportToastHandler(); - }; - - const addErrorGeneratingReportToastHandler = () => { - const errorToast = { - title: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.toast.errorGeneratingReport. ', - { defaultMessage: 'Error generating report.' } - ), - color: 'danger', - iconType: 'alert', - id: 'generateReportErrorToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const handleErrorGeneratingReportToast = (errorType: string) => { - if (errorType === 'permissions') { - addPermissionsMissingGenerateReportToastHandler(); - } else if (errorType === 'API') { - addErrorGeneratingReportToastHandler(); - } - }; - - const addSuccessEnablingScheduleToastHandler = () => { - const successToast = { - title: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.toast.successfullyEnabledSchedule. ', - { defaultMessage: 'Successfully enabled schedule.' } - ), - color: 'success', - iconType: 'check', - id: 'successEnableToast', - }; - // @ts-ignore - setToasts(toasts.concat(successToast)); - }; - - const addErrorEnablingScheduleToastHandler = () => { - const errorToast = { - title: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.toast.errorEnablingSchedule. ', - { defaultMessage: 'Error enabling schedule.' } - ), - color: 'danger', - iconType: 'alert', - id: 'errorToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const addSuccessDisablingScheduleToastHandler = () => { - const successToast = { - title: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.toast.successfullyDisabledSchedule. ', - { defaultMessage: 'Successfully disabled schedule.' } - ), - color: 'success', - iconType: 'check', - id: 'successDisableToast', - }; - // @ts-ignore - setToasts(toasts.concat(successToast)); - }; - - const handleSuccessChangingScheduleStatusToast = (statusChange: string) => { - if (statusChange === 'enable') { - addSuccessEnablingScheduleToastHandler(); - } else if (statusChange === 'disable') { - addSuccessDisablingScheduleToastHandler(); - } - }; - - const addErrorDisablingScheduleToastHandler = () => { - const errorToast = { - title: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.toast.errorDisablingSchedule. ', - { defaultMessage: 'Error disabling schedule.' } - ), - color: 'danger', - iconType: 'alert', - id: 'errorDisableToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const handleErrorChangingScheduleStatusToast = (statusChange: string) => { - if (statusChange === 'enable') { - addErrorEnablingScheduleToastHandler(); - } else if (statusChange === 'disable') { - addErrorDisablingScheduleToastHandler(); - } else if (statusChange === 'permissions') { - addPermissionsMissingStatusChangeToastHandler(); - } - }; - - const addErrorDeletingReportDefinitionToastHandler = () => { - const errorToast = { - title: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.toast.errorDeletingReport definition. ', - { defaultMessage: 'Error deleting report definition.' } - ), - color: 'danger', - iconType: 'alert', - id: 'errorDeleteToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const handleErrorDeletingReportDefinitionToast = () => { - addErrorDeletingReportDefinitionToastHandler(); - }; - - const removeToast = (removedToast: { id: string; }) => { - setToasts(toasts.filter((toast: any) => toast.id !== removedToast.id)); - }; - - const handleReportDefinitionDetails = (e: ReportDefinitionDetails) => { - setReportDefinitionDetails(e); - }; - - const handleReportDefinitionRawResponse = (e: {} ) => { - setReportDefinitionRawResponse(e); - }; - - const DeleteConfirmationModal = () => { - const closeModal = () => { - setShowDeleteModal(false); - }; - - return ( -
- - -

- {i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.button.delete.query', - { - defaultMessage: 'Are you sure you want to delete "{name}"?', - values: { name: reportDefinitionDetails.name }, - } - )} -

-
-
-
- ); - }; - - const humanReadableScheduleDetails = (trigger) => { - let scheduleDetails = ''; - if (trigger.trigger_type === 'Schedule') { - if (trigger.trigger_params.schedule_type === 'Recurring') { - // Daily - if ( - trigger.trigger_params.schedule.interval.unit === 'DAYS' && - trigger.trigger_params.schedule.interval.period === 1 - ) { - const date = new Date( - trigger.trigger_params.schedule.interval.start_time - ); - scheduleDetails = i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.schedule.dailyAt', - { - defaultMessage: 'Daily @ {time}', - values: { time: date.toTimeString() }, - } - ); - } - // By interval - else { - const date = new Date( - trigger.trigger_params.schedule.interval.start_time - ); - scheduleDetails = i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.schedule.byInterval', - { - defaultMessage: - 'By interval, every {period} {unit}, starting @ {time}', - values: { - period: trigger.trigger_params.schedule.interval.period, - unit: trigger.trigger_params.schedule.interval.unit.toLowerCase(), - time: date.toTimeString(), - }, - } - ); - } - } - // Cron - else if (trigger.trigger_params.schedule_type === 'Cron based') { - scheduleDetails = i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.schedule.cronBased', - { - defaultMessage: 'Cron based: {expression} ({timezone})', - values: { - expression: trigger.trigger_params.schedule.cron.expression, - timezone: trigger.trigger_params.schedule.cron.timezone, - }, - } - ); - } - } - return scheduleDetails; - }; - - const getReportDefinitionDetailsMetadata = ( - data: ReportDefinitionSchemaType - ) : ReportDefinitionDetails => { - const reportDefinition: ReportDefinitionSchemaType = data; - const { - report_params: reportParams, - trigger, - delivery, - time_created: timeCreated, - last_updated: lastUpdated, - } = reportDefinition; - const { - trigger_type: triggerType, - trigger_params: triggerParams, - } = trigger; - const { - core_params: { - base_url: baseUrl, - report_format: reportFormat, - time_duration: timeDuration, - }, - } = reportParams; - - let readableDate = new Date(timeCreated); - let displayCreatedDate = - readableDate.toDateString() + ' ' + readableDate.toLocaleTimeString(); - - let readableUpdatedDate = new Date(lastUpdated); - let displayUpdatedDate = - readableUpdatedDate.toDateString() + - ' ' + - readableUpdatedDate.toLocaleTimeString(); - - let reportDefinitionDetails = { - name: reportParams.report_name, - description: - reportParams.description === '' ? `\u2014` : reportParams.description, - created: displayCreatedDate, - lastUpdated: displayUpdatedDate, - source: reportParams.report_source, - baseUrl: baseUrl, - // TODO: need better display - timePeriod: moment.duration(timeDuration).humanize(), - fileFormat: reportFormat, - reportHeader: - reportParams.core_params.hasOwnProperty('header') && - reportParams.core_params.header != '' - ? reportParams.core_params.header - : `\u2014`, - reportFooter: - reportParams.core_params.hasOwnProperty('footer') && - reportParams.core_params.footer != '' - ? reportParams.core_params.footer - : `\u2014`, - triggerType: triggerType, - scheduleDetails: triggerParams - ? humanReadableScheduleDetails(data.trigger) - : `\u2014`, - status: reportDefinition.status, - }; - return reportDefinitionDetails; - }; - - useEffect(() => { - const { httpClient } = props; - httpClient - .get(`../api/reporting/reportDefinitions/${reportDefinitionId}`) - .then((response: {report_definition: ReportDefinitionSchemaType}) => { - handleReportDefinitionRawResponse(response); - handleReportDefinitionDetails(getReportDefinitionDetailsMetadata(response.report_definition)); - props.setBreadcrumbs([ - { - text: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.schedule.breadcrumb.reporting', - { defaultMessage: 'Reporting' } - ), - href: '#', - }, - { - text: i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.schedule.breadcrumb.reportDefinitionDetails', - { - defaultMessage: 'Report definition details: {name}', - values: { - name: response.report_definition.report_params.report_name, - }, - } - ), - }, - ]); - }) - .catch((error: any) => { - console.error( - i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.schedule.breadcrumb.error', - { - defaultMessage: - 'error when getting report definition details: {error}', - values: { error: error }, - } - ) - ); - handleDetailsErrorToast(); - }); - }, []); - - const downloadIconDownload = async () => { - handleLoading(true); - await generateReportFromDetails(); - handleLoading(false); - }; - - const fileFormatDownload = (data: { [x: string]: any; }) => { - let formatUpper = data['fileFormat']; - formatUpper = fileFormatsUpper[formatUpper]; - return ( - - {formatUpper + ' '} - - - ); - }; - - const sourceURL = (data: ReportDefinitionDetails) => { - return ( - - {data['source']} - - ); - }; - - const changeScheduledReportDefinitionStatus = (statusChange: string) => { - let updatedReportDefinition = reportDefinitionRawResponse.report_definition; - if (statusChange === 'Disable') { - updatedReportDefinition.trigger.trigger_params.enabled = false; - updatedReportDefinition.status = 'Disabled'; - } else if (statusChange === 'Enable') { - updatedReportDefinition.trigger.trigger_params.enabled = true; - updatedReportDefinition.status = 'Active'; - } - const { httpClient } = props; - httpClient - .put(`../api/reporting/reportDefinitions/${reportDefinitionId}`, { - body: JSON.stringify(updatedReportDefinition), - params: reportDefinitionId.toString(), - }) - .then(() => { - const updatedRawResponse = { report_definition: {} }; - updatedRawResponse.report_definition = updatedReportDefinition; - handleReportDefinitionRawResponse(updatedRawResponse); - setReportDefinitionDetails( - getReportDefinitionDetailsMetadata(updatedReportDefinition) - ); - if (statusChange === 'Enable') { - handleSuccessChangingScheduleStatusToast('enable'); - } else if (statusChange === 'Disable') { - handleSuccessChangingScheduleStatusToast('disable'); - } - }) - .catch((error: { body: { statusCode: number; }; }) => { - console.error('error in updating report definition status:', error); - if (error.body.statusCode === 403) { - handleErrorChangingScheduleStatusToast('permissions'); - } else { - if (statusChange === 'Enable') { - handleErrorChangingScheduleStatusToast('enable'); - } else if (statusChange === 'Disable') { - handleErrorChangingScheduleStatusToast('disable'); - } - } - }); - }; - - const ScheduledDefinitionStatus = () => { - const status = - reportDefinitionDetails.status === 'Active' ? 'Disable' : 'Enable'; - - return ( - changeScheduledReportDefinitionStatus(status)} - id={'changeStatusFromDetailsButton'} - > - {status} - - ); - }; - - const generateReportFromDetails = async () => { - const { httpClient } = props; - handleLoading(true); - let generateReportSuccess = await generateReportFromDefinitionId( - reportDefinitionId, - httpClient - ); - handleLoading(false); - if (generateReportSuccess.status) { - handleSuccessGeneratingReportToast(); - } else { - if (generateReportSuccess.permissionsError) { - handleErrorGeneratingReportToast('permissions'); - } else { - handleErrorGeneratingReportToast('API'); - } - } - }; - - const deleteReportDefinition = () => { - const { httpClient } = props; - httpClient - .delete(`../api/reporting/reportDefinitions/${reportDefinitionId}`) - .then(() => { - window.location.assign(`reports-dashboards#/delete=success`); - }) - .catch((error: { body: { statusCode: number; }; }) => { - console.log('error when deleting report definition:', error); - if (error.body.statusCode === 403) { - handlePermissionsMissingDeleteToast(); - } else { - handleErrorDeletingReportDefinitionToast(); - } - }); - }; - - const showActionButton = - reportDefinitionDetails.triggerType === ON_DEMAND ? ( - generateReportFromDetails()} - id={'generateReportFromDetailsButton'} - > - Generate report - - ) : ( - - ); - - const triggerSection = - reportDefinitionDetails.triggerType === ON_DEMAND ? ( - - ) : ( - - - - - - - ); - - const showDeleteConfirmationModal = showDeleteModal ? ( - - ) : null; - - const showLoadingModal = showLoading ? ( - - ) : null; - - return ( - - - -

- {i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.title', - { defaultMessage: 'Report definition details' } - )} -

-
- - - - - - - -

{reportDefinitionDetails.name}

-
-
-
-
- - - handleShowDeleteModal(show)} - id={'deleteReportDefinitionButton'} - > - {i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.deleteReportDefinitionButton', - { defaultMessage: 'Delete' } - )} - - - {showActionButton} - - { - window.location.assign( - `reports-dashboards#/edit/${reportDefinitionId}` - ); - }} - id={'editReportDefinitionButton'} - > - {i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.editReportDefinitionButton', - { defaultMessage: 'Edit' } - )} - - - -
- - -

- {i18n.translate( - 'opensearch.reports.reportDefinitionsDetails.reportSettings', - { defaultMessage: 'Report settings' } - )} -

-
- - - - - - - - - - - - - - - - - - - - - - - {triggerSection} -
- - {showDeleteConfirmationModal} - {showLoadingModal} -
-
- ); -} diff --git a/dashboards-reports/public/components/main/report_definitions_table.tsx b/dashboards-reports/public/components/main/report_definitions_table.tsx deleted file mode 100644 index b0d255b3..00000000 --- a/dashboards-reports/public/components/main/report_definitions_table.tsx +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState } from 'react'; -import { - EuiLink, - EuiInMemoryTable, - EuiButton, - EuiEmptyPrompt, - EuiText, - EuiIcon, -} from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import { humanReadableDate } from './main_utils'; - -const emptyMessageReportDefinitions = ( - - {i18n.translate( - 'opensearch.reports.reportDefinitionsTable.emptyMessageReports.noReportDefinitions', - { defaultMessage: 'No report definitions to display' } - )} - - } - titleSize="xs" - body={ -
- - {i18n.translate( - 'opensearch.reports.reportDefinitionsTable.emptyMessageReports.createANewDefinition', - { defaultMessage: 'Create a new report definition to get started' } - )} - - - {i18n.translate( - 'opensearch.reports.reportDefinitionsTable.emptyMessageReports.toLearnMore', - { defaultMessage: 'To learn more, see' } - )}{' '} - - {i18n.translate( - 'opensearch.reports.reportDefinitionsTable.emptyMessageReports.getStarted', - { - defaultMessage: - 'Get started with OpenSearch Dashboards reporting', - } - )} - - - -
- } - actions={ -
- { - window.location.assign('reports-dashboards#/create'); - }} - > - {i18n.translate( - 'opensearch.reports.reportDefinitionsTable.emptyMessageReports.createReportDefinition', - { defaultMessage: 'Create report definition' } - )} - -
- } - /> -); - -const reportDefinitionsSearch = { - box: { - incremental: true, - }, - filters: [], -}; - -export function ReportDefinitions(props) { - const { pagination, reportDefinitionsTableContent } = props; - - const [sortField, setSortField] = useState('lastUpdated'); - const [sortDirection, setSortDirection] = useState('des'); - - const sorting = { - sort: { - field: sortField, - direction: sortDirection, - }, - }; - - const getDefinitionTableItemId = (name) => { - let index; - for ( - index = 0; - index < props.reportDefinitionsTableContent.length; - ++index - ) { - if (name === reportDefinitionsTableContent[index].reportName) { - return reportDefinitionsTableContent[index].id; - } - } - }; - - const navigateToDefinitionDetails = (name: any) => { - let id = getDefinitionTableItemId(name); - window.location.assign( - `reports-dashboards#/report_definition_details/${id}` - ); - }; - - const reportDefinitionsColumns = [ - { - field: 'reportName', - name: i18n.translate( - 'opensearch.reports.reportDefinitionsTable.columns.name', - { - defaultMessage: 'Name', - } - ), - render: (name) => ( - navigateToDefinitionDetails(name)} - id={'reportDefinitionDetailsLink'} - > - {name} - - ), - }, - { - field: 'source', - name: i18n.translate( - 'opensearch.reports.reportDefinitionsTable.columns.source', - { defaultMessage: 'Source' } - ), - render: (value, item) => ( - - {value} - - ), - }, - { - field: 'type', - name: i18n.translate( - 'opensearch.reports.reportDefinitionsTable.columns.type', - { - defaultMessage: 'Type', - } - ), - sortable: true, - truncateText: false, - }, - { - field: 'details', - name: i18n.translate( - 'opensearch.reports.reportDefinitionsTable.columns.scheduleDetails', - { defaultMessage: 'Schedule details' } - ), - sortable: false, - truncateText: true, - }, - { - field: 'lastUpdated', - name: i18n.translate( - 'opensearch.reports.reportDefinitionsTable.columns.lastUpdated', - { defaultMessage: 'Last Updated' } - ), - render: (date) => { - let readable = humanReadableDate(date); - return {readable}; - }, - }, - { - field: 'status', - name: i18n.translate( - 'opensearch.reports.reportDefinitionsTable.columns.status', - { defaultMessage: 'Status' } - ), - sortable: true, - truncateText: false, - }, - ]; - - const displayMessage = - reportDefinitionsTableContent.length === 0 - ? emptyMessageReportDefinitions - : i18n.translate( - 'opensearch.reports.reportDefinitionsTable.emptyMessageReports.noDefinitionsFound', - { - defaultMessage: - '0 report definitions match the search criteria. Search again.', - } - ); - - return ( -
- -
- ); -} diff --git a/dashboards-reports/public/components/main/report_details/__tests__/__snapshots__/report_details.test.tsx.snap b/dashboards-reports/public/components/main/report_details/__tests__/__snapshots__/report_details.test.tsx.snap deleted file mode 100644 index 7d0b79f6..00000000 --- a/dashboards-reports/public/components/main/report_details/__tests__/__snapshots__/report_details.test.tsx.snap +++ /dev/null @@ -1,760 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` panel render 5 hours recurring component 1`] = ` -
-
-

- Report details -

-
-
-
-
-
-
-

- test create report definition trigger -

-
-
-
-
-
-

- Report Settings -

-
-
-
-
-
- Name -
-
- test create report definition trigger -
-
-
-
-
-
- Description -
-
- — -
-
-
-
-
-
- Created -
-
- — -
-
-
-
-
-
- Last updated -
-
- — -
-
-
-
-
-
- -
-
-
- Time period -
-
- Invalid Date -> 10/23/2020, 8:53:35 PM -
-
-
-
-
-
- File format -
-
- -
-
-
-
-
-
- State -
-
-
-
-
-
-
-
-
-
- Report header -
-
-

- — -

-
-
-
-
-
-
- Report footer -
-
-

- — -

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Report trigger -
-
- Schedule -
-
-
-
-
-
- Schedule type -
-
- Recurring -
-
-
-
-
-
- Schedule details -
-
- — -
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; - -exports[` panel render on-demand component 1`] = ` -
-
-

- Report details -

-
-
-
-
-
-
-

- test create report definition trigger -

-
-
-
-
-
-

- Report Settings -

-
-
-
-
-
- Name -
-
- test create report definition trigger -
-
-
-
-
-
- Description -
-
- — -
-
-
-
-
-
- Created -
-
- — -
-
-
-
-
-
- Last updated -
-
- — -
-
-
-
-
-
- -
-
-
- Time period -
-
- Invalid Date -> 10/23/2020, 8:53:35 PM -
-
-
-
-
-
- File format -
-
- -
-
-
-
-
-
- State -
-
-
-
-
-
-
-
-
-
- Report header -
-
-

- — -

-
-
-
-
-
-
- Report footer -
-
-

- — -

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Report trigger -
-
- On demand -
-
-
-
-
-
-
-`; diff --git a/dashboards-reports/public/components/main/report_details/__tests__/report_details.test.tsx b/dashboards-reports/public/components/main/report_details/__tests__/report_details.test.tsx deleted file mode 100644 index 4bad6fa7..00000000 --- a/dashboards-reports/public/components/main/report_details/__tests__/report_details.test.tsx +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { render } from '@testing-library/react'; -import { ReportDetails } from '../report_details'; -import propsMock from '../../../../../test/propsMock'; -import httpClientMock from '../../../../../test/httpMockClient'; -import 'babel-polyfill'; -import { act } from 'react-dom/test-utils'; - -function setBreadcrumbs(array: []) { - jest.fn(); -} - -describe(' panel', () => { - const match = { - params: { - reportId: '1', - }, - }; - - test('render on-demand component', async () => { - const promise = Promise.resolve(); - const report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: 'PT30M', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'On demand', - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - query_url: `http://localhost:5601/app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?_g=(time:(from:'2020-10-23T20:53:35.315Z',to:'2020-10-23T21:23:35.316Z'))`, - config_list: [] - }); - - const { container } = render( - - ); - await act(() => promise); - await expect(container.firstChild).toMatchSnapshot(); - }); - - test('render 5 hours recurring component', async () => { - const promise = Promise.resolve(); - const report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: 'PT30M', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - schedule: { - interval: { - period: 5, - unit: 'HOURS', - timezone: 'PST8PDT', - }, - }, - enabled_time: 1114939203, - enabled: true, - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - query_url: `http://localhost:5601/app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?_g=(time:(from:'2020-10-23T20:53:35.315Z',to:'2020-10-23T21:23:35.316Z'))`, - config_list: [] - }); - - const { container } = render( - - ); - await act(() => promise); - await expect(container.firstChild).toMatchSnapshot(); - }); -}); diff --git a/dashboards-reports/public/components/main/report_details/report_details.tsx b/dashboards-reports/public/components/main/report_details/report_details.tsx deleted file mode 100644 index 65fa02aa..00000000 --- a/dashboards-reports/public/components/main/report_details/report_details.tsx +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useState } from 'react'; -import { i18n } from '@osd/i18n'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiPage, - EuiPageHeader, - EuiTitle, - EuiPageBody, - EuiPageContent, - EuiHorizontalRule, - EuiSpacer, - EuiDescriptionList, - EuiDescriptionListTitle, - EuiDescriptionListDescription, - EuiPageHeaderSection, - EuiLink, - EuiIcon, - EuiGlobalToastList, -} from '@elastic/eui'; -import { fileFormatsUpper, generateReportById } from '../main_utils'; -import { GenerateReportLoadingModal } from '../loading_modal'; -import { ReportSchemaType } from '../../../../server/model'; -import dateMath from '@elastic/datemath'; -import { - permissionsMissingActions, - permissionsMissingToast, - timeRangeMatcher, -} from '../../utils/utils'; -import { TRIGGER_TYPE } from '../../../../server/routes/utils/constants'; - -interface ReportDetails { - reportName: string; - description: string; - created: string; - lastUpdated: string; - source: string; - time_period: string; - defaultFileFormat: string; - state: string | undefined; - reportHeader: string; - reportFooter: string; - triggerType: string; - scheduleType: string; - scheduleDetails: string; - queryUrl: string; -} - -export const ReportDetailsComponent = (props: { reportDetailsComponentTitle: any; reportDetailsComponentContent: any; }) => { - const { reportDetailsComponentTitle, reportDetailsComponentContent } = props; - - return ( - - - - {reportDetailsComponentTitle} - - - {reportDetailsComponentContent} - - - - ); -}; - -// convert markdown to plain text, trim it if it's longer than 3 lines -export const trimAndRenderAsText = (markdown: string) => { - if (!markdown) return markdown; - const lines = markdown.split('\n').filter((line) => line); - const elements = lines.slice(0, 3).map((line, i) =>

{line}

); - return lines.length <= 3 ? elements : elements.concat(

...

); -}; - -export const formatEmails = (emails: string[]) => { - return Array.isArray(emails) ? emails.join(', ') : emails; -}; - -export function ReportDetails(props: { match?: any; setBreadcrumbs?: any; httpClient: any; }) { - const [reportDetails, setReportDetails] = useState({ - reportName: '', - description: '', - created: '', - lastUpdated: '', - source: '', - time_period: '', - defaultFileFormat: '', - state: '', - reportHeader: '', - reportFooter: '', - triggerType: '', - scheduleType: '', - scheduleDetails: '', - queryUrl: '' - }); - const [toasts, setToasts] = useState([]); - const [showLoading, setShowLoading] = useState(false); - - const reportId = props.match['params']['reportId']; - - const handleLoading = (e: boolean | ((prevState: boolean) => boolean)) => { - setShowLoading(e); - }; - - const addPermissionsMissingDownloadToastHandler = () => { - const toast = permissionsMissingToast( - permissionsMissingActions.GENERATING_REPORT - ); - // @ts-ignore - setToasts(toasts.concat(toast)); - }; - - const handlePermissionsMissingDownloadToast = () => { - addPermissionsMissingDownloadToastHandler(); - }; - - const addErrorToastHandler = ( - title = i18n.translate( - 'opensearch.reports.details.errorLoadingReportDetails', - { defaultMessage: 'Error loading report details.' } - ), - text = '' - ) => { - const errorToast = { - title, - text, - color: 'danger', - iconType: 'alert', - id: 'reportDetailsErrorToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const handleErrorToast = (title?: string, text?: string) => { - addErrorToastHandler(title, text); - }; - - const addSuccessToastHandler = () => { - const successToast = { - title: 'Success', - color: 'success', - text: ( -

- {i18n.translate( - 'opensearch.reports.details.reportSuccessfullyDownloaded', - { defaultMessage: 'Report successfully downloaded!' } - )} -

- ), - id: 'onDemandDownloadSuccessToast', - }; - // @ts-ignore - setToasts(toasts.concat(successToast)); - }; - - const handleSuccessToast = () => { - addSuccessToastHandler(); - }; - - const removeToast = (removedToast: { id: any; }) => { - setToasts(toasts.filter((toast : any) => toast.id !== removedToast.id)); - }; - - const handleReportDetails = (e: React.SetStateAction) => { - setReportDetails(e); - }; - - const convertTimestamp = (timestamp: number | undefined) => { - let displayDate = `\u2014`; - if (timestamp) { - let readableDate = new Date(timestamp); - displayDate = readableDate.toLocaleString(); - } - return displayDate; - }; - - const parseTimePeriod = (queryUrl: string) => { - let [fromDateString, toDateString] : RegExpMatchArray | null = queryUrl.match( - timeRangeMatcher - ); - - fromDateString = decodeURIComponent(fromDateString.replace(/[']+/g, '')); - toDateString = decodeURIComponent(toDateString.replace(/[']+/g, '')); - - let fromDateParsed = dateMath.parse(fromDateString); - let toDateParsed = dateMath.parse(toDateString, { roundUp: true }); - - const fromTimePeriod = fromDateParsed?.toDate(); - const toTimePeriod = toDateParsed?.toDate(); - return ( - fromTimePeriod?.toLocaleString() + ' -> ' + toTimePeriod?.toLocaleString() - ); - }; - - const getReportDetailsData = ( - report: ReportSchemaType - ) : ReportDetails => { - const { - report_definition: reportDefinition, - last_updated: lastUpdated, - state, - query_url: queryUrl, - } = report; - const { report_params: reportParams, trigger } = reportDefinition; - const { - trigger_type: triggerType, - trigger_params: triggerParams, - } = trigger; - const coreParams = reportParams.core_params; - // covert timestamp to local date-time string - let reportDetails = { - reportName: reportParams.report_name, - description: - reportParams.description === '' ? `\u2014` : reportParams.description, - created: convertTimestamp(report.time_created), - lastUpdated: convertTimestamp(report.last_updated), - source: reportParams.report_source, - // TODO: we have all data needed, time_from, time_to, time_duration, - // think of a way to better display - time_period: (reportParams.report_source !== 'Notebook') ? parseTimePeriod(queryUrl) : `\u2014`, - defaultFileFormat: coreParams.report_format, - state: state, - reportHeader: - reportParams.core_params.hasOwnProperty('header') && - reportParams.core_params.header != '' - ? reportParams.core_params.header - : `\u2014`, - reportFooter: - reportParams.core_params.hasOwnProperty('footer') && - reportParams.core_params.footer != '' - ? reportParams.core_params.footer - : `\u2014`, - triggerType: triggerType, - scheduleType: triggerParams ? triggerParams.schedule_type : `\u2014`, - scheduleDetails: `\u2014`, - queryUrl: queryUrl, - }; - return reportDetails; - }; - - useEffect(() => { - const { httpClient } = props; - httpClient - .get('../api/reporting/reports/' + reportId) - .then((response: ReportSchemaType) => { - handleReportDetails(getReportDetailsData(response)); - props.setBreadcrumbs([ - { - text: i18n.translate( - 'opensearch.reports.details.breadcrumb.reporting', - { defaultMessage: 'Reporting' } - ), - href: '#', - }, - { - text: i18n.translate( - 'opensearch.reports.details.breadcrumb.reportDetails', - { - defaultMessage: 'Report details: {name}', - values: { - name: response.report_definition.report_params.report_name, - }, - } - ), - }, - ]); - }) - .catch((error: any) => { - console.log('Error when fetching report details: ', error); - handleErrorToast(); - }); - }, []); - - const downloadIconDownload = async () => { - handleLoading(true); - await generateReportById( - reportId, - props.httpClient, - handleSuccessToast, - handleErrorToast, - handlePermissionsMissingDownloadToast - ); - handleLoading(false); - }; - - const fileFormatDownload = (data: ReportDetails) => { - let formatUpper = data['defaultFileFormat']; - formatUpper = fileFormatsUpper[formatUpper]; - return ( - - {formatUpper + ' '} - - - ); - }; - - const sourceURL = (data: ReportDetails) => { - return ( - - {data['source']} - - ); - }; - - const triggerSection = - reportDetails.triggerType === TRIGGER_TYPE.onDemand ? ( - - ) : ( - - - - - - - ) - - const showLoadingModal = showLoading ? ( - - ) : null; - - return ( - - - -

- {i18n.translate('opensearch.reports.details.title', { - defaultMessage: 'Report details', - })} -

-
- - - - - - - -

{reportDetails.reportName}

-
-
-
-
-
- - -

- {i18n.translate('opensearch.reports.details.reportSettings', { - defaultMessage: 'Report Settings', - })} -

-
- - - - - - - - - - - - - - - - - - - - - - - {triggerSection} -
- - {showLoadingModal} -
-
- ); -} diff --git a/dashboards-reports/public/components/main/reports_table.tsx b/dashboards-reports/public/components/main/reports_table.tsx deleted file mode 100644 index 90b85563..00000000 --- a/dashboards-reports/public/components/main/reports_table.tsx +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { Fragment, useState } from 'react'; -import { i18n } from '@osd/i18n'; -import { - EuiButton, - // @ts-ignore - EuiLink, - EuiText, - EuiIcon, - EuiEmptyPrompt, - EuiInMemoryTable, -} from '@elastic/eui'; -import { - fileFormatsUpper, - humanReadableDate, - generateReportById, -} from './main_utils'; -import { GenerateReportLoadingModal } from './loading_modal'; - -const reportStatusOptions = [ - 'Created', - 'Error', - 'Pending', - 'Shared', - 'Archived', -]; -const reportTypeOptions = ['Schedule', 'On demand']; - -const emptyMessageReports = ( - - {i18n.translate( - 'opensearch.reports.reportsTable.emptyMessageReports.noReportsToDisplay', - { defaultMessage: 'No reports to display' } - )} - - } - titleSize="xs" - body={ -
- - {i18n.translate( - 'opensearch.reports.reportsTable.emptyMessageReports.createAReportDefinition', - { - defaultMessage: - 'Create a report definition, or share/download a report from a dashboard, saved search or visualization.', - } - )} - - - {i18n.translate( - 'opensearch.reports.reportsTable.emptyMessageReports.toLearnMore', - { defaultMessage: 'To learn more, see' } - )}{' '} - - {i18n.translate( - 'opensearch.reports.reportsTable.emptyMessageReports.getStarted', - { - defaultMessage: - 'Get started with OpenSearch Dashboards reporting', - } - )} - - - -
- } - /> -); - -export function ReportsTable(props) { - const { - pagination, - reportsTableItems, - httpClient, - handleSuccessToast, - handleErrorToast, - handlePermissionsMissingToast, - } = props; - - const [sortField, setSortField] = useState('timeCreated'); - const [sortDirection, setSortDirection] = useState('des'); - const [showLoading, setShowLoading] = useState(false); - const [message, setMessage] = useState(''); - - const handleLoading = (e) => { - setShowLoading(e); - }; - - const onDemandDownload = async (id: any) => { - handleLoading(true); - await generateReportById( - id, - httpClient, - handleSuccessToast, - handleErrorToast, - handlePermissionsMissingToast - ); - handleLoading(false); - }; - - const reportsTableColumns = [ - { - field: 'reportName', - name: i18n.translate( - 'opensearch.reports.reportsTable.reportsTableColumns.Name', - { defaultMessage: 'Name' } - ), - render: (reportName, item) => ( - { - window.location.assign( - `reports-dashboards#/report_details/${item.id}` - ); - }} - id={'reportDetailsLink'} - > - {reportName} - - ), - }, - { - // TODO: link to dashboard/visualization snapshot, use "queryUrl" field. Display dashboard name? - field: 'reportSource', - name: i18n.translate( - 'opensearch.reports.reportsTable.reportsTableColumns.Source', - { defaultMessage: 'Source' } - ), - render: (source, item) => - item.state === 'Pending' ? ( - {source} - ) : ( - - {source} - - ), - }, - { - field: 'type', - name: i18n.translate( - 'opensearch.reports.reportsTable.reportsTableColumns.Type', - { defaultMessage: 'Type' } - ), - sortable: true, - truncateText: false, - }, - { - field: 'timeCreated', - name: i18n.translate( - 'opensearch.reports.reportsTable.reportsTableColumns.creationTime', - { defaultMessage: 'Creation time' } - ), - render: (date) => { - let readable = humanReadableDate(date); - return {readable}; - }, - }, - { - field: 'state', - name: i18n.translate( - 'opensearch.reports.reportsTable.reportsTableColumns.State', - { defaultMessage: 'State' } - ), - sortable: true, - truncateText: false, - }, - { - field: 'id', - name: i18n.translate( - 'opensearch.reports.reportsTable.reportsTableColumns.Generate', - { defaultMessage: 'Generate' } - ), - render: (id, item) => - item.state === 'Pending' ? ( - - {fileFormatsUpper[item.format]} - - ) : ( - onDemandDownload(id)} - id="landingPageOnDemandDownload" - > - {fileFormatsUpper[item.format]} - - ), - }, - ]; - - const sorting = { - sort: { - field: sortField, - direction: sortDirection, - }, - }; - - const reportsListSearch = { - box: { - incremental: true, - }, - filters: [ - { - type: 'field_value_selection', - field: 'type', - name: i18n.translate( - 'opensearch.reports.reportsTable.reportsListSearch.Type', - { defaultMessage: 'Type' } - ), - multiSelect: 'or', - options: reportTypeOptions.map((type) => ({ - value: type, - name: type, - view: type, - })), - }, - { - type: 'field_value_selection', - field: 'state', - name: i18n.translate( - 'opensearch.reports.reportsTable.reportsListSearch.State', - { defaultMessage: 'State' } - ), - multiSelect: 'or', - options: reportStatusOptions.map((state) => ({ - value: state, - name: state, - view: state, - })), - }, - ], - }; - - const displayMessage = - reportsTableItems.length === 0 - ? emptyMessageReports - : i18n.translate( - 'opensearch.reports.reportsTable.reportsListSearch.noRreportsMatch', - { - defaultMessage: '0 reports match the search criteria. Search again', - } - ); - - const showLoadingModal = showLoading ? ( - - ) : null; - - return ( - - - {showLoadingModal} - - ); -} diff --git a/dashboards-reports/public/components/report_definitions/create/create_report_definition.tsx b/dashboards-reports/public/components/report_definitions/create/create_report_definition.tsx deleted file mode 100644 index eed7015a..00000000 --- a/dashboards-reports/public/components/report_definitions/create/create_report_definition.tsx +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useState } from 'react'; -import { i18n } from '@osd/i18n'; -import { - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiGlobalToastList, - EuiButton, - EuiTitle, - EuiPageBody, - EuiSpacer, -} from '@elastic/eui'; -import { ReportSettings } from '../report_settings'; -import { generateReportFromDefinitionId } from '../../main/main_utils'; -import { converter } from '../utils'; -import { - permissionsMissingToast, - permissionsMissingActions, -} from '../../utils/utils'; -import { definitionInputValidation } from '../utils/utils'; - -interface reportParamsType { - report_name: string; - report_source: string; - description: string; - core_params: visualReportParams | dataReportParams; -} -interface visualReportParams { - base_url: string; - report_format: string; - header: string; - footer: string; - time_duration: string; -} - -interface dataReportParams { - saved_search_id: number; - base_url: string; - report_format: string; - time_duration: string; -} -interface triggerType { - trigger_type: string; - trigger_params?: any; -} - -interface deliveryType { - configIds: Array; - title: string; - textDescription: string; - htmlDescription: string; -} - -export interface TriggerParamsType { - schedule_type: string; - schedule: Recurring | Cron; - enabled_time: number; - enabled: boolean; -} - -interface Recurring { - interval: { - period: number; - unit: string; - start_time: number; - }; -} - -interface Cron { - cron: { - cron_expression: string; - time_zone: string; - }; -} - -export interface reportDefinitionParams { - report_params: reportParamsType; - delivery: deliveryType; - trigger: triggerType; -} - -export interface timeRangeParams { - timeFrom: Date; - timeTo: Date; -} - -export function CreateReport(props: { [x: string]: any; setBreadcrumbs?: any; httpClient?: any; }) { - let createReportDefinitionRequest: reportDefinitionParams = { - report_params: { - report_name: '', - report_source: '', - description: '', - core_params: { - base_url: '', - report_format: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: '', - }, - }; - - const [toasts, setToasts] = useState([]); - const [comingFromError, setComingFromError] = useState(false); - const [preErrorData, setPreErrorData] = useState({}); - - const [ - showSettingsReportNameError, - setShowSettingsReportNameError, - ] = useState(false); - const [ - settingsReportNameErrorMessage, - setSettingsReportNameErrorMessage, - ] = useState(''); - const [ - showSettingsReportSourceError, - setShowSettingsReportSourceError, - ] = useState(false); - const [ - settingsReportSourceErrorMessage, - setSettingsReportSourceErrorMessage, - ] = useState(''); - const [ - showTriggerIntervalNaNError, - setShowTriggerIntervalNaNError, - ] = useState(false); - const [showCronError, setShowCronError] = useState(false); - const [showTimeRangeError, setShowTimeRangeError] = useState(false); - - // preserve the state of the request after an invalid create report definition request - if (comingFromError) { - createReportDefinitionRequest = preErrorData; - } - - const addInputValidationErrorToastHandler = () => { - const errorToast = { - title: i18n.translate( - 'opensearch.reports.createReportDefinition.error.fieldsHaveAnError', - { - defaultMessage: - 'One or more fields have an error. Please check and try again.', - } - ), - color: 'danger', - iconType: 'alert', - id: 'errorToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const handleInputValidationErrorToast = () => { - addInputValidationErrorToastHandler(); - }; - - const addErrorOnCreateToastHandler = (errorType: string) => { - let toast = {}; - if (errorType === 'permissions') { - toast = permissionsMissingToast( - permissionsMissingActions.CREATING_REPORT_DEFINITION - ); - } else if (errorType === 'API') { - toast = { - title: i18n.translate( - 'opensearch.reports.createReportDefinition.error.errorCreating', - { defaultMessage: 'Error creating report definition.' } - ), - color: 'danger', - iconType: 'alert', - id: 'errorToast', - }; - } - // @ts-ignore - setToasts(toasts.concat(toast)); - }; - - const handleErrorOnCreateToast = (errorType: string) => { - addErrorOnCreateToastHandler(errorType); - }; - - const addInvalidTimeRangeToastHandler = () => { - const errorToast = { - title: i18n.translate( - 'opensearch.reports.createReportDefinition.error.invalidTimeRange', - { defaultMessage: 'Invalid time range selected.' } - ), - color: 'danger', - iconType: 'alert', - id: 'timeRangeErrorToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const handleInvalidTimeRangeToast = () => { - addInvalidTimeRangeToastHandler(); - }; - - const removeToast = (removedToast: { id: string; }) => { - setToasts(toasts.filter((toast: any) => toast.id !== removedToast.id)); - }; - - let timeRange = { - timeFrom: new Date(), - timeTo: new Date(), - }; - - const createNewReportDefinition = async ( - metadata: reportDefinitionParams, - timeRange: timeRangeParams - ) => { - const { httpClient } = props; - //TODO: need better handle - if ( - metadata.trigger.trigger_type === 'On demand' && - metadata.trigger.trigger_params !== undefined - ) { - delete metadata.trigger.trigger_params; - } - - let error = false; - await definitionInputValidation( - metadata, - error, - setShowSettingsReportNameError, - setSettingsReportNameErrorMessage, - setShowSettingsReportSourceError, - setSettingsReportSourceErrorMessage, - setShowTriggerIntervalNaNError, - timeRange, - setShowTimeRangeError, - setShowCronError, - ).then((response) => { - error = response; - }); - if (error) { - handleInputValidationErrorToast(); - setPreErrorData(metadata); - setComingFromError(true); - } else { - httpClient - .post('../api/reporting/reportDefinition', { - body: JSON.stringify(metadata), - headers: { - 'Content-Type': 'application/json', - }, - }) - .then(async (resp: { scheduler_response: { reportDefinitionId: string; }; }) => { - //TODO: consider handle the on demand report generation from server side instead - if (metadata.trigger.trigger_type === 'On demand') { - const reportDefinitionId = - resp.scheduler_response.reportDefinitionId; - generateReportFromDefinitionId(reportDefinitionId, httpClient); - } - window.location.assign(`reports-dashboards#/create=success`); - }) - .catch((error: {body: { statusCode: number; }; }) => { - console.log('error in creating report definition: ' + error); - if (error.body.statusCode === 403) { - handleErrorOnCreateToast('permissions'); - } else { - handleErrorOnCreateToast('API'); - } - }); - } - }; - - useEffect(() => { - window.scrollTo(0, 0); - props.setBreadcrumbs([ - { - text: i18n.translate( - 'opensearch.reports.createReportDefinition.breadcrumb.reporting', - { defaultMessage: 'Reporting' } - ), - href: '#', - }, - { - text: i18n.translate( - 'opensearch.reports.createReportDefinition.breadcrumb.createReportDefinition', - { defaultMessage: 'Create report definition' } - ), - href: '#/create', - }, - ]); - }, []); - - return ( -
- - -

- {i18n.translate('opensearch.reports.createReportDefinition.title', { - defaultMessage: 'Create report definition', - })} -

-
- - - - - - { - window.location.assign(`reports-dashboards#/`); - }} - > - {i18n.translate( - 'opensearch.reports.createReportDefinition.cancel', - { defaultMessage: 'Cancel' } - )} - - - - - createNewReportDefinition( - createReportDefinitionRequest, - timeRange - ) - } - id={'createNewReportDefinition'} - > - {i18n.translate( - 'opensearch.reports.createReportDefinition.create', - { defaultMessage: 'Create' } - )} - - - - -
-
- ); -} diff --git a/dashboards-reports/public/components/report_definitions/create/index.ts b/dashboards-reports/public/components/report_definitions/create/index.ts deleted file mode 100644 index 4f247918..00000000 --- a/dashboards-reports/public/components/report_definitions/create/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { CreateReport } from './create_report_definition'; diff --git a/dashboards-reports/public/components/report_definitions/delivery/__tests__/__snapshots__/delivery.test.tsx.snap b/dashboards-reports/public/components/report_definitions/delivery/__tests__/__snapshots__/delivery.test.tsx.snap deleted file mode 100644 index 3df27334..00000000 --- a/dashboards-reports/public/components/report_definitions/delivery/__tests__/__snapshots__/delivery.test.tsx.snap +++ /dev/null @@ -1,83 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` panel render create component 1`] = ` -
-
-

- Notification settings -

-
-
-
-
- -
- -
-
-
-`; - -exports[` panel render edit component 1`] = ` -
-
-

- Notification settings -

-
-
-
-
- -
- -
-
-
-`; diff --git a/dashboards-reports/public/components/report_definitions/delivery/__tests__/delivery.test.tsx b/dashboards-reports/public/components/report_definitions/delivery/__tests__/delivery.test.tsx deleted file mode 100644 index fed5f8a8..00000000 --- a/dashboards-reports/public/components/report_definitions/delivery/__tests__/delivery.test.tsx +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { render } from '@testing-library/react'; -import { ReportDelivery } from '../delivery'; -import httpClientMock from '../../../../../test/httpMockClient'; -import { act } from 'react-dom/test-utils'; - -const emptyRequest = { - report_params: { - report_name: '', - report_source: '', - description: '', - core_params: { - base_url: '', - report_format: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: '', - trigger_params: {}, - }, - time_created: 0, - last_updated: 0, - status: '', -}; - -const timeRange = { - timeFrom: new Date(1234567800), - timeTo: new Date(1234567890), -}; - -global.fetch = jest.fn(() => ({ - then: jest.fn(() => ({ - then: jest.fn() - })) -})); - -describe(' panel', () => { - test('render create component', () => { - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - }); - - test('render edit component', async () => { - const promise = Promise.resolve(); - let editReportDefinitionRequest = { - report_params: { - report_name: 'edit cron schedule component', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'On demand', - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition: editReportDefinitionRequest, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); -}); diff --git a/dashboards-reports/public/components/report_definitions/delivery/delivery.tsx b/dashboards-reports/public/components/report_definitions/delivery/delivery.tsx deleted file mode 100644 index b3ab50f3..00000000 --- a/dashboards-reports/public/components/report_definitions/delivery/delivery.tsx +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useState } from 'react'; -import { - EuiFormRow, - EuiPageHeader, - EuiTitle, - EuiPageContent, - EuiPageContentBody, - EuiHorizontalRule, - EuiSpacer, - EuiCheckbox, - EuiComboBox, - EuiFieldText, - EuiButton, -} from '@elastic/eui'; -import CSS from 'csstype'; -import { - getChannelsQueryObject, - noDeliveryChannelsSelectedMessage, - testMessageConfirmationMessage, - testMessageFailureMessage, -} from './delivery_constants'; -import 'react-mde/lib/styles/css/react-mde-all.css'; -import { reportDefinitionParams } from '../create/create_report_definition'; -import ReactMDE from 'react-mde'; -import { converter } from '../utils'; -import { getAvailableNotificationsChannels } from '../../main/main_utils'; -import { REPORTING_NOTIFICATIONS_DASHBOARDS_API } from '../../../../common'; - -const styles: CSS.Properties = { - maxWidth: '800px', -}; - -// TODO: add to schema to avoid need for export -export let includeDelivery = false; - -export type ReportDeliveryProps = { - edit: boolean; - editDefinitionId: string; - reportDefinitionRequest: reportDefinitionParams; - httpClientProps: any; - showDeliveryChannelError: boolean; - deliveryChannelError: string; - showDeliverySubjectError: boolean; - deliverySubjectError: string; - showDeliveryTextError: boolean; - deliveryTextError: string; -}; - -export function ReportDelivery(props: ReportDeliveryProps) { - const { - edit, - editDefinitionId, - reportDefinitionRequest, - httpClientProps, - showDeliveryChannelError, - deliveryChannelError, - showDeliverySubjectError, - deliverySubjectError, - showDeliveryTextError, - deliveryTextError, - } = props; - - const [isDeliveryHidden, setIsHidden] = useState(false); - const [sendNotification, setSendNotification] = useState(false); - const [channels, setChannels] = useState([]); - const [selectedChannels, setSelectedChannels] = useState([]); - const [notificationSubject, setNotificationSubject] = useState('New report'); - const [notificationMessage, setNotificationMessage] = useState( - 'New report available to view' - ); - const [selectedTab, setSelectedTab] = React.useState<'write' | 'preview'>( - 'write' - ); - const [testMessageConfirmation, setTestMessageConfirmation] = useState(''); - - const handleSendNotification = (e: { target: { checked: boolean } }) => { - setSendNotification(e.target.checked); - includeDelivery = e.target.checked; - if (includeDelivery) { - reportDefinitionRequest.delivery.title = 'New report'; - reportDefinitionRequest.delivery.textDescription = - 'New report available to view'; - reportDefinitionRequest.delivery.htmlDescription = converter.makeHtml( - 'New report available to view' - ); - } else { - reportDefinitionRequest.delivery.title = `\u2014`; - reportDefinitionRequest.delivery.textDescription = `\u2014`; - } - }; - - const handleSelectedChannels = (e: Array<{ label: string; id: string }>) => { - setSelectedChannels(e); - reportDefinitionRequest.delivery.configIds = []; - for (let i = 0; i < e.length; ++i) { - reportDefinitionRequest.delivery.configIds.push(e[i].id); - } - }; - - const handleNotificationSubject = (e: { target: { value: string } }) => { - setNotificationSubject(e.target.value); - reportDefinitionRequest.delivery.title = e.target.value; - }; - - const handleNotificationMessage = (e: string) => { - setNotificationMessage(e); - reportDefinitionRequest.delivery.textDescription = e.toString(); - reportDefinitionRequest.delivery.htmlDescription = converter.makeHtml( - e.toString() - ); - }; - - const handleTestMessageConfirmation = (e: JSX.Element) => { - setTestMessageConfirmation(e); - }; - - const defaultCreateDeliveryParams = () => { - includeDelivery = false; - reportDefinitionRequest.delivery = { - configIds: [], - title: `\u2014`, // default values before any Notifications settings are configured - textDescription: `\u2014`, - htmlDescription: '', - }; - }; - - const isStatusCodeSuccess = (statusCode: string) => { - if (!statusCode) return true; - return /^2\d\d/.test(statusCode); - }; - - const eventToNotification = (event: any) => { - const success = event.event.status_list.every((status: any) => - isStatusCodeSuccess(status.delivery_status.status_code) - ); - return { - event_source: event.event.event_source, - status_list: event.event.status_list, - event_id: event.event_id, - created_time_ms: event.created_time_ms, - last_updated_time_ms: event.last_updated_time_ms, - success, - }; - }; - - const getNotification = async (id: string) => { - const response = await httpClientProps.get( - `${REPORTING_NOTIFICATIONS_DASHBOARDS_API.GET_EVENT}/${id}` - ); - return eventToNotification(response.event_list[0]); - }; - - const sendTestNotificationsMessage = async () => { - if (selectedChannels.length === 0) { - handleTestMessageConfirmation(noDeliveryChannelsSelectedMessage); - } - let testMessageFailures = false; - let failedChannels: string[] = []; - // for each config ID in the current channels list - for (let i = 0; i < selectedChannels.length; ++i) { - try { - const eventId = await httpClientProps - .get( - `${REPORTING_NOTIFICATIONS_DASHBOARDS_API.SEND_TEST_MESSAGE}/${selectedChannels[i].id}`, - { - query: { - feature: 'reports', - }, - } - ) - .then((response) => response.event_id); - - await getNotification(eventId).then((response) => { - if (!response.success) { - const error = new Error('Failed to send the test message.'); - failedChannels.push(response.status_list[0].config_name); - error.stack = JSON.stringify(response.status_list, null, 2); - throw error; - } - }); - } catch (error) { - testMessageFailures = true; - } - } - if (testMessageFailures) { - handleTestMessageConfirmation(testMessageFailureMessage(failedChannels)); - } else { - handleTestMessageConfirmation(testMessageConfirmationMessage); - } - }; - - const checkIfNotificationsPluginIsInstalled = () => { - fetch( - '../api/console/proxy?path=%2F_cat%2Fplugins%3Fv%3Dtrue%26s%3Dcomponent%26h%3Dcomponent&method=GET', - { - credentials: 'include', - headers: { - Accept: 'text/plain, */*; q=0.01', - 'Accept-Language': 'en-US,en;q=0.5', - 'osd-xsrf': 'true', - }, - method: 'POST', - mode: 'cors', - } - ) - .then((response) => { - return response.text(); - }) - .then(function (data) { - if (data.includes('opensearch-notifications')) { - setIsHidden(false); - return; - } - setIsHidden(true); - }); - }; - - useEffect(() => { - checkIfNotificationsPluginIsInstalled(); - httpClientProps - .get(`${REPORTING_NOTIFICATIONS_DASHBOARDS_API.GET_CONFIGS}`, { - query: getChannelsQueryObject, - }) - .then(async (response: any) => { - let availableChannels = getAvailableNotificationsChannels( - response.config_list - ); - setChannels(availableChannels); - return availableChannels; - }) - .then((availableChannels: any) => { - if (edit) { - httpClientProps - .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) - .then(async (response: any) => { - if (response.report_definition.delivery.configIds.length > 0) { - // add config IDs - handleSendNotification({ target: { checked: true } }); - let delivery = response.report_definition.delivery; - let editChannelOptions = []; - for (let i = 0; i < delivery.configIds.length; ++i) { - for (let j = 0; j < availableChannels.length; ++j) { - if (delivery.configIds[i] === availableChannels[j].id) { - let editChannelOption = { - label: availableChannels[j].label, - id: availableChannels[j].id, - }; - editChannelOptions.push(editChannelOption); - break; - } - } - } - setSelectedChannels(editChannelOptions); - setNotificationSubject(delivery.title); - setNotificationMessage(delivery.textDescription); - reportDefinitionRequest.delivery = delivery; - } - }); - } else { - defaultCreateDeliveryParams(); - } - }) - .catch((error: string) => { - console.log( - 'error: cannot get available channels from Notifications plugin:', - error - ); - }); - }, []); - - const showNotificationsBody = sendNotification ? ( -
- - - - - - - - - - - - Promise.resolve(converter.makeHtml(markdown)) - } - /> - - - - - Send test message - - -
- ) : null; - - return ( - - ); -} diff --git a/dashboards-reports/public/components/report_definitions/delivery/delivery_constants.tsx b/dashboards-reports/public/components/report_definitions/delivery/delivery_constants.tsx deleted file mode 100644 index 3e049470..00000000 --- a/dashboards-reports/public/components/report_definitions/delivery/delivery_constants.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react"; -import { EuiIcon, EuiText } from '@elastic/eui' - -export const noDeliveryChannelsSelectedMessage = ( - - Please select a channel. - -) - -export const testMessageConfirmationMessage = ( - - Test message sent to selected channels. If no test message is received, try again or check your channel settings in Notifications. - -); - -export const testMessageFailureMessage = (failedChannels: Array) => ( - - Failed to send test message for some channels. Please adjust channel settings for {failedChannels.toString()} - -) - -export const getChannelsQueryObject = { - config_type: ['slack', 'email', 'chime', 'webhook', 'sns', 'ses'], - from_index: 0, - max_items: 1000, - sort_field: 'name', - sort_order: 'asc', - feature_list: ['reports'] -} diff --git a/dashboards-reports/public/components/report_definitions/delivery/index.ts b/dashboards-reports/public/components/report_definitions/delivery/index.ts deleted file mode 100644 index 91d85f4a..00000000 --- a/dashboards-reports/public/components/report_definitions/delivery/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ReportDelivery } from './delivery'; diff --git a/dashboards-reports/public/components/report_definitions/edit/edit_report_definition.tsx b/dashboards-reports/public/components/report_definitions/edit/edit_report_definition.tsx deleted file mode 100644 index 3e876931..00000000 --- a/dashboards-reports/public/components/report_definitions/edit/edit_report_definition.tsx +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useState } from 'react'; -import { i18n } from '@osd/i18n'; -import { - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiButton, - EuiPage, - EuiTitle, - EuiPageBody, - EuiSpacer, - EuiGlobalToastList, -} from '@elastic/eui'; -import { ReportSettings } from '../report_settings'; -import { ReportTrigger } from '../report_trigger'; -import { ReportDefinitionSchemaType } from 'server/model'; -import { converter } from '../utils'; -import { - permissionsMissingToast, - permissionsMissingActions, -} from '../../utils/utils'; -import { definitionInputValidation } from '../utils/utils'; - -export function EditReportDefinition(props: { [x: string]: any; setBreadcrumbs?: any; httpClient?: any; }) { - const [toasts, setToasts] = useState([]); - const [comingFromError, setComingFromError] = useState(false); - const [preErrorData, setPreErrorData] = useState({}); - - const [ - showSettingsReportNameError, - setShowSettingsReportNameError, - ] = useState(false); - const [ - settingsReportNameErrorMessage, - setSettingsReportNameErrorMessage, - ] = useState(''); - const [ - showSettingsReportSourceError, - setShowSettingsReportSourceError, - ] = useState(false); - const [ - settingsReportSourceErrorMessage, - setSettingsReportSourceErrorMessage, - ] = useState(''); - const [ - showTriggerIntervalNaNError, - setShowTriggerIntervalNaNError, - ] = useState(false); - const [showCronError, setShowCronError] = useState(false); - const [showTimeRangeError, setShowTimeRangeError] = useState(false); - - const addPermissionsMissingViewEditPageToastHandler = (errorType: string) => { - let toast = {}; - if (errorType === 'permissions') { - toast = permissionsMissingToast( - permissionsMissingActions.VIEWING_EDIT_PAGE - ); - } else if (errorType === 'API') { - toast = { - title: i18n.translate( - 'opensearch.reports.editReportDefinition.errorLoading', - { defaultMessage: 'Error loading report definition values.' } - ), - color: 'danger', - iconType: 'alert', - id: 'errorToast', - }; - } - // @ts-ignore - setToasts(toasts.concat(toast)); - }; - - const handleViewEditPageErrorToast = (errorType: string) => { - addPermissionsMissingViewEditPageToastHandler(errorType); - }; - - const addInputValidationErrorToastHandler = () => { - const errorToast = { - title: i18n.translate( - 'opensearch.reports.editReportDefinition.fieldsHaveAnError', - { - defaultMessage: - 'One or more fields have an error. Please check and try again.', - } - ), - color: 'danger', - iconType: 'alert', - id: 'errorToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const handleInputValidationErrorToast = () => { - addInputValidationErrorToastHandler(); - }; - - const addErrorUpdatingReportDefinitionToastHandler = (errorType: string) => { - let toast = {}; - if (errorType === 'permissions') { - toast = permissionsMissingToast( - permissionsMissingActions.UPDATING_DEFINITION - ); - } else if (errorType === 'API') { - toast = { - title: i18n.translate( - 'opensearch.reports.editReportDefinition.errorUpdating', - { defaultMessage: 'Error updating report definition.' } - ), - color: 'danger', - iconType: 'alert', - id: 'errorToast', - }; - } - // @ts-ignore - setToasts(toasts.concat(toast)); - }; - - const handleErrorUpdatingReportDefinitionToast = (errorType: string) => { - addErrorUpdatingReportDefinitionToastHandler(errorType); - }; - - const addErrorDeletingReportDefinitionToastHandler = () => { - const errorToast = { - title: i18n.translate( - 'opensearch.reports.editReportDefinition.errorDeleting', - { defaultMessage: 'Error deleting old scheduled report definition.' } - ), - color: 'danger', - iconType: 'alert', - id: 'errorDeleteToast', - }; - // @ts-ignore - setToasts(toasts.concat(errorToast)); - }; - - const handleErrorDeletingReportDefinitionToast = () => { - addErrorDeletingReportDefinitionToastHandler(); - }; - - const removeToast = (removedToast: { id: any; }) => { - setToasts(toasts.filter((toast: any) => toast.id !== removedToast.id)); - }; - - const reportDefinitionId = props['match']['params']['reportDefinitionId']; - let reportDefinition: ReportDefinitionSchemaType; - let editReportDefinitionRequest = { - report_params: { - report_name: '', - report_source: '', - description: '', - core_params: { - base_url: '', - report_format: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: '', - }, - time_created: 0, - last_updated: 0, - status: '', - }; - reportDefinition = editReportDefinitionRequest; // initialize reportDefinition object - - let timeRange = { - timeFrom: new Date(), - timeTo: new Date(), - }; - - if (comingFromError) { - editReportDefinitionRequest = preErrorData; - } - - const callUpdateAPI = async (metadata) => { - const { httpClient } = props; - httpClient - .put(`../api/reporting/reportDefinitions/${reportDefinitionId}`, { - body: JSON.stringify(metadata), - params: reportDefinitionId.toString(), - }) - .then(async () => { - window.location.assign(`reports-dashboards#/edit=success`); - }) - .catch((error: { body: { statusCode: number; }; }) => { - console.log('error in updating report definition:', error); - if (error.body.statusCode === 400) { - handleInputValidationErrorToast(); - } else if (error.body.statusCode === 403) { - handleErrorUpdatingReportDefinitionToast('permissions'); - } else { - handleErrorUpdatingReportDefinitionToast('API'); - } - setPreErrorData(metadata); - setComingFromError(true); - }); - }; - - const editReportDefinition = async (metadata: { report_params: {core_params: {header: string, footer: string}}}) => { - if ('header' in metadata.report_params.core_params) { - metadata.report_params.core_params.header = converter.makeHtml( - metadata.report_params.core_params.header - ); - } - if ('footer' in metadata.report_params.core_params) { - metadata.report_params.core_params.footer = converter.makeHtml( - metadata.report_params.core_params.footer - ); - } - - // client-side input validation - let error = false; - await definitionInputValidation( - metadata, - error, - setShowSettingsReportNameError, - setSettingsReportNameErrorMessage, - setShowSettingsReportSourceError, - setSettingsReportSourceErrorMessage, - setShowTriggerIntervalNaNError, - timeRange, - setShowTimeRangeError, - setShowCronError, - ).then((response) => { - error = response; - }); - if (error) { - handleInputValidationErrorToast(); - setPreErrorData(metadata); - setComingFromError(true); - } else { - await callUpdateAPI(metadata); - } - }; - - useEffect(() => { - window.scrollTo(0, 0); - const { httpClient } = props; - httpClient - .get(`../api/reporting/reportDefinitions/${reportDefinitionId}`) - .then((response) => { - reportDefinition = response.report_definition; - const { - time_created: timeCreated, - status, - last_updated: lastUpdated, - report_params: { report_name: reportName }, - } = reportDefinition; - // configure non-editable fields - editReportDefinitionRequest.time_created = timeCreated; - editReportDefinitionRequest.last_updated = lastUpdated; - editReportDefinitionRequest.status = status; - - props.setBreadcrumbs([ - { - text: 'Reporting', - href: '#', - }, - { - text: `Report definition details: ${reportName}`, - href: `#/report_definition_details/${reportDefinitionId}`, - }, - { - text: `Edit report definition: ${reportName}`, - }, - ]); - }) - .catch((error: { body: { statusCode: number; }; }) => { - console.error( - 'error when loading edit report definition page: ', - error - ); - if (error.body.statusCode === 403) { - handleViewEditPageErrorToast('permissions'); - } else { - handleViewEditPageErrorToast('API'); - } - }); - }, []); - - return ( - - - -

- {i18n.translate('opensearch.reports.editReportDefinition.title', { - defaultMessage: 'Edit report definition', - })} -

-
- - - - - - { - window.location.assign('reports-dashboards#/'); - }} - > - {i18n.translate( - 'opensearch.reports.editReportDefinition.cancel', - { defaultMessage: 'Cancel' } - )} - - - - editReportDefinition(editReportDefinitionRequest)} - id={'editReportDefinitionButton'} - > - {i18n.translate('opensearch.reports.editReportDefinition.save', { - defaultMessage: 'Save Changes', - })} - - - - -
-
- ); -} diff --git a/dashboards-reports/public/components/report_definitions/edit/index.ts b/dashboards-reports/public/components/report_definitions/edit/index.ts deleted file mode 100644 index bcba3740..00000000 --- a/dashboards-reports/public/components/report_definitions/edit/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { EditReportDefinition } from './edit_report'; diff --git a/dashboards-reports/public/components/report_definitions/report_settings/__tests__/__snapshots__/report_settings.test.tsx.snap b/dashboards-reports/public/components/report_definitions/report_settings/__tests__/__snapshots__/report_settings.test.tsx.snap deleted file mode 100644 index d348db59..00000000 --- a/dashboards-reports/public/components/report_definitions/report_settings/__tests__/__snapshots__/report_settings.test.tsx.snap +++ /dev/null @@ -1,8471 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` panel dashboard create from in-context 1`] = ` -
-
-

- Report settings -

-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
- Valid characters are a-z, A-Z, 0-9, (), [], _ (underscore), - (hyphen) and (space). -
-
-
-
-
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
-
-
-
- - -
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-
-
-`; - -exports[` panel display errors on create 1`] = ` -
-
-

- Report settings -

-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
- Valid characters are a-z, A-Z, 0-9, (), [], _ (underscore), - (hyphen) and (space). -
-
-
-
-
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
-
-
-
- - -
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-
-
-`; - -exports[` panel render component 1`] = ` -
-
-

- Report settings -

-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
- Valid characters are a-z, A-Z, 0-9, (), [], _ (underscore), - (hyphen) and (space). -
-
-
-
-
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
-
-
-
- - -
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-
-
-`; - -exports[` panel visualization create from in-context 1`] = ` -
-
-

- Report settings -

-
-
-
-
-
-
-
- -
-
-
-
- -
-
-
- Valid characters are a-z, A-Z, 0-9, (), [], _ (underscore), - (hyphen) and (space). -
-
-
-
-
-
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
-
- -
-
-
-
-
- - -
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
-
-
-
- -
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-
-
-`; diff --git a/dashboards-reports/public/components/report_definitions/report_settings/__tests__/report_settings.test.tsx b/dashboards-reports/public/components/report_definitions/report_settings/__tests__/report_settings.test.tsx deleted file mode 100644 index 0f7ead8f..00000000 --- a/dashboards-reports/public/components/report_definitions/report_settings/__tests__/report_settings.test.tsx +++ /dev/null @@ -1,837 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { render } from '@testing-library/react'; -import { ReportSettings } from '../report_settings'; -import 'babel-polyfill'; -import 'regenerator-runtime'; -import httpClientMock from '../../../../../test/httpMockClient'; -import { configure, mount, shallow } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import { act } from 'react-dom/test-utils'; - -const emptyRequest = { - report_params: { - report_name: '', - report_source: '', - description: '', - core_params: { - base_url: '', - report_format: '', - time_duration: '', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: '', - trigger_params: {}, - }, - time_created: 0, - last_updated: 0, - status: '', -}; - -let timeRange = { - timeFrom: new Date(123456789), - timeTo: new Date(1234567890), -}; - -const dashboardHits = { - hits: [ - { - _id: 'dashboard:abcdefghijklmnop12345', - _source: { - dashboard: { - description: 'mock dashboard value', - hits: 0, - timeFrom: 'now-24h', - timeTo: 'now', - title: 'Mock Dashboard', - }, - notebook: { - name: 'mock notebook name' - } - }, - }, - ], -}; - -const visualizationHits = { - hits: [ - { - _id: 'visualization:abcdefghijklmnop12345', - _source: { - visualization: { - description: 'mock visualization value', - title: 'Mock Visualization', - }, - notebook: { - name: 'mock notebook name' - }, - }, - }, - ], -}; - -const savedSearchHits = { - hits: [ - { - _id: 'search:abcdefghijklmnop12345', - _source: { - search: { - title: 'Mock saved search value', - }, - notebook: { - name: 'mock notebook name' - }, - }, - }, - ], -}; - -describe(' panel', () => { - jest.spyOn(console, 'log').mockImplementation(() => {}); - configure({ adapter: new Adapter() }); - test('render component', () => { - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - }); - - test('render edit, dashboard source', async () => { - const promise = Promise.resolve(); - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: 'test description', - core_params: { - base_url: 'http://localhost:5601/dashboard/abcdefghijklmnop12345', - report_format: 'pdf', - header: 'header content', - footer: 'footer content', - time_duration: 'PT30M', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: dashboardHits, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('render edit, visualization source', async () => { - const promise = Promise.resolve(); - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Visualization', - description: 'test description', - core_params: { - base_url: 'http://localhost:5601/edit/abcdefghijklmnop12345', - report_format: 'png', - header: 'header content', - footer: 'footer content', - time_duration: 'PT30M', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: visualizationHits, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('render edit, saved search source', async () => { - const promise = Promise.resolve(); - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Saved search', - description: 'test description', - core_params: { - base_url: 'http://localhost:5601/discover/abcdefghijklmnop12345', - report_format: 'csv', - header: 'test header content', - footer: 'test footer content', - time_duration: 'PT30M', - saved_search_id: 'abcdefghijk', - limit: 10000, - excel: true, - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: savedSearchHits, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('render edit, dashboard source', async () => { - const promise = Promise.resolve(); - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Saved search', - description: 'test description', - core_params: { - base_url: 'http://localhost:5601', - report_format: 'csv', - header: 'test header content', - footer: 'test footer content', - time_duration: 'PT30M', - saved_search_id: 'abcdefghijk', - limit: 10000, - excel: true, - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: dashboardHits, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('render edit, visualization source', async () => { - const promise = Promise.resolve(); - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Saved search', - description: 'test description', - core_params: { - base_url: 'http://localhost:5601', - report_format: 'csv', - header: 'test header content', - footer: 'test footer content', - time_duration: 'PT30M', - saved_search_id: 'abcdefghijk', - limit: 10000, - excel: true, - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: visualizationHits, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - - test('dashboard create from in-context', async () => { - window = Object.create(window); - Object.defineProperty(window, 'location', { - configurable: true, - value: { - href: - 'http://localhost:5601/app/reports-dashboards#/create?previous=dashboard:abcdefghijklmnop12345?timeFrom=2020-10-26T20:52:56.382Z?timeTo=2020-10-27T20:52:56.384Z', - }, - }); - - const promise = Promise.resolve(); - - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: 'http://localhost:5601/dashboard/abcdefghijklmnop12345', - report_format: 'png', - header: '', - footer: '', - time_duration: 'PT30M', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: dashboardHits, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('visualization create from in-context', async () => { - // @ts-ignore - delete window.location; // reset window.location.href for in-context testing - - window = Object.create(window); - Object.defineProperty(window, 'location', { - configurable: true, - value: { - href: - 'http://localhost:5601/app/reports-dashboards#/create?previous=visualize:abcdefghijklmnop12345?timeFrom=2020-10-26T20:52:56.382Z?timeTo=2020-10-27T20:52:56.384Z', - }, - }); - - const promise = Promise.resolve(); - - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Visualization', - description: '', - core_params: { - base_url: 'http://localhost:5601/edit/abcdefghijklmnop12345', - report_format: 'pdf', - header: '', - footer: '', - time_duration: 'PT30M', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: visualizationHits, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('saved search create from in-context', async () => { - // @ts-ignore - delete window.location; // reset window.location.href for in-context testing - - window = Object.create(window); - Object.defineProperty(window, 'location', { - value: { - href: - 'http://localhost:5601/app/reports-dashboards#/create?previous=discover:abcdefghijklmnop12345?timeFrom=2020-10-26T20:52:56.382Z?timeTo=2020-10-27T20:52:56.384Z', - }, - }); - - const promise = Promise.resolve(); - - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Saved search', - description: '', - core_params: { - base_url: 'http://localhost:5601/discover/abcdefghijklmnop12345', - report_format: 'csv', - header: '', - footer: '', - time_duration: 'PT30M', - saved_search_id: 'abcdefghijk', - limit: 10000, - excel: true, - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: {}, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: savedSearchHits, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('simulate click on dashboard combo box', async () => { - const promise = Promise.resolve(); - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Saved search', - description: 'test description', - core_params: { - base_url: 'http://localhost:5601', - report_format: 'csv', - header: 'test header content', - footer: 'test footer content', - time_duration: 'PT30M', - saved_search_id: 'abcdefghijk', - limit: 10000, - excel: true, - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: dashboardHits, - }); - - const component = shallow( - - , {disableLifecycleMethods: true}); - await act(() => promise); - - const comboBox = component.find('EuiComboBox').at(0); - comboBox.simulate('change', [{value: 'test', label: 'test'}]); - - await act(() => promise); - }); - - test('simulate click on visualization combo box', async () => { - const promise = Promise.resolve(); - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Visualization', - description: 'test description', - core_params: { - base_url: 'http://localhost:5601', - report_format: 'pdf', - header: 'test header content', - footer: 'test footer content', - time_duration: 'PT30M', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: visualizationHits, - }); - - const component = mount( - - ); - await act(() => promise); - - const reportSourceRadio = component.find('EuiRadioGroup').at(0); - const visualizationRadio = reportSourceRadio.find('EuiRadio').at(1); - - visualizationRadio.find('input').simulate('change', 'visualizationReportSource'); - await act(() => promise); - const comboBox = component.find('EuiComboBox').at(0); - - act(() => { - comboBox.props().onChange([{ value: 'test', label: 'test' }]); - }); - component.update(); - - await act(() => promise); - }); - - test('simulate click on saved search combo box', async () => { - const promise = Promise.resolve(); - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Saved search', - description: 'test description', - core_params: { - base_url: 'http://localhost:5601', - report_format: 'pdf', - header: 'test header content', - footer: 'test footer content', - time_duration: 'PT30M', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - enabled: false, - enabled_time: 1234567890, - schedule: { - interval: { - period: 1, - start_time: 123456789, - unit: 'Days' - } - } - }, - }, - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - hits: savedSearchHits, - }); - - const component = mount( - - ); - await act(() => promise); - - const reportSourceRadio = component.find('EuiRadioGroup').at(0); - const visualizationRadio = reportSourceRadio.find('EuiRadio').at(2); - - visualizationRadio.find('input').simulate('change', 'savedSearchReportSource'); - await act(() => promise); - const comboBox = component.find('EuiComboBox').at(0); - - act(() => { - comboBox.props().onChange([{ value: 'test', label: 'test' }]); - }) - component.update(); - - await act(() => promise); - }); - - test('display errors on create', async () => { - const promise = Promise.resolve(); - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); -}); diff --git a/dashboards-reports/public/components/report_definitions/report_settings/__tests__/report_settings_helpers.test.tsx b/dashboards-reports/public/components/report_definitions/report_settings/__tests__/report_settings_helpers.test.tsx deleted file mode 100644 index 9a5b3367..00000000 --- a/dashboards-reports/public/components/report_definitions/report_settings/__tests__/report_settings_helpers.test.tsx +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - getDashboardBaseUrlCreate, - getDashboardOptions, - getSavedSearchBaseUrlCreate, - getSavedSearchOptions, - getVisualizationBaseUrlCreate, - getVisualizationOptions, - handleDataToVisualReportSourceChange, - parseInContextUrl, -} from '../report_settings_helpers'; - -const TEST_DEFINITION_ID = '12345'; - -describe('report_settings_helpers tests', () => { - test('parseInContextUrl', () => { - const urlString = - 'http://localhost:5601/app/reports-dashboards#/create?previous=dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d?timeFrom=2020-10-26T20:52:56.382Z?timeTo=2020-10-27T20:52:56.384Z'; - - const id = parseInContextUrl(urlString, 'id'); - expect(id).toBe('7adfa750-4c81-11e8-b3d7-01146121b73d'); - - const timeFrom = parseInContextUrl(urlString, 'timeFrom'); - expect(timeFrom).toBe('2020-10-26T20:52:56.382Z'); - - const timeTo = parseInContextUrl(urlString, 'timeTo'); - expect(timeTo).toBe('2020-10-27T20:52:56.384Z'); - - const error = parseInContextUrl(urlString, 'invalid'); - expect(error).toBe('error: invalid parameter'); - }); - - test('getDashboardBaseUrlCreate', () => { - const baseUrl = getDashboardBaseUrlCreate(true, TEST_DEFINITION_ID, true); - expect(baseUrl).toBe('/app/dashboards#/view/'); - - const baseUrlNotFromEdit = getDashboardBaseUrlCreate( - false, - TEST_DEFINITION_ID, - true - ); - expect(baseUrlNotFromEdit).toBe('/app/dashboards#/view/'); - }); - - test('getDashboardBaseUrlCreate not from in-context', () => { - const baseUrl = getDashboardBaseUrlCreate(false, TEST_DEFINITION_ID, false); - expect(baseUrl).toBe('/'); - }) - - test('getVisualizationBaseUrlCreate', () => { - const baseUrl = getVisualizationBaseUrlCreate( - true, - TEST_DEFINITION_ID, - true - ); - expect(baseUrl).toBe('/app/visualize#/edit/'); - - const baseUrlNotFromEdit = getVisualizationBaseUrlCreate( - false, - TEST_DEFINITION_ID, - true - ); - expect(baseUrlNotFromEdit).toBe('/app/visualize#/edit/'); - }); - - test('getVisualizationBaseUrlCreate not from in-context', () => { - const baseUrl = getVisualizationBaseUrlCreate( - false, - TEST_DEFINITION_ID, - false - ); - expect(baseUrl).toBe('/'); - }) - - test('getSavedSearchBaseUrlCreate', () => { - const baseUrl = getSavedSearchBaseUrlCreate(true, TEST_DEFINITION_ID, true); - expect(baseUrl).toBe('/app/discover#/view/'); - - const baseUrlNotFromEdit = getSavedSearchBaseUrlCreate( - false, - TEST_DEFINITION_ID, - true - ); - expect(baseUrlNotFromEdit).toBe('/app/discover#/view/'); - }); - - test('getSavedSearchBaseUrlCreate not from in-context', () => { - const baseUrl = getSavedSearchBaseUrlCreate(false, TEST_DEFINITION_ID, false); - expect(baseUrl).toBe('/'); - }) - - test('getDashboardOptions', () => { - const mockData = [ - { - _id: 'dashboard:1234567890abcdefghijk', - _source: { - dashboard: { - title: 'Mock dashboard title', - }, - }, - }, - ]; - - const options = getDashboardOptions(mockData); - expect(options[0].value).toBe('1234567890abcdefghijk'); - expect(options[0].label).toBe('Mock dashboard title'); - }); - - test('getVisualizationOptions', () => { - const mockData = [ - { - _id: 'visualization:1234567890abcdefghijk', - _source: { - visualization: { - title: 'Mock visualization title', - }, - }, - }, - ]; - - const options = getVisualizationOptions(mockData); - expect(options[0].value).toBe('1234567890abcdefghijk'); - expect(options[0].label).toBe('Mock visualization title'); - }); - - test('getSavedSearchOptions', () => { - const mockData = [ - { - _id: 'search:1234567890abcdefghijk', - _source: { - search: { - title: 'Mock saved search title', - }, - }, - }, - ]; - const options = getSavedSearchOptions(mockData); - expect(options[0].value).toBe('1234567890abcdefghijk'); - expect(options[0].label).toBe('Mock saved search title'); - }); - - test('handleDataToVisualReportSourceChange', () => { - let reportDefinitionRequest = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - report_format: '', - saved_search_id: '', - limit: 10, - excel: true, - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: {}, - }, - }; - - handleDataToVisualReportSourceChange(reportDefinitionRequest); - expect( - reportDefinitionRequest.report_params.core_params.report_format - ).toBe('pdf'); - expect(reportDefinitionRequest.report_params.core_params).toMatchObject({ - report_format: 'pdf', - }); - }); -}); diff --git a/dashboards-reports/public/components/report_definitions/report_settings/index.ts b/dashboards-reports/public/components/report_definitions/report_settings/index.ts deleted file mode 100644 index 2b410f03..00000000 --- a/dashboards-reports/public/components/report_definitions/report_settings/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ReportSettings } from './report_settings'; diff --git a/dashboards-reports/public/components/report_definitions/report_settings/report_settings.tsx b/dashboards-reports/public/components/report_definitions/report_settings/report_settings.tsx deleted file mode 100644 index 0db86cfd..00000000 --- a/dashboards-reports/public/components/report_definitions/report_settings/report_settings.tsx +++ /dev/null @@ -1,926 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useState } from 'react'; -import { i18n } from '@osd/i18n'; -import { - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiPageHeader, - EuiTitle, - EuiPageContent, - EuiPageContentBody, - EuiHorizontalRule, - EuiText, - EuiSpacer, - EuiRadioGroup, - EuiSelect, - EuiTextArea, - EuiCheckboxGroup, - EuiComboBox, -} from '@elastic/eui'; -import { - REPORT_SOURCE_RADIOS, - PDF_PNG_FILE_FORMAT_OPTIONS, - HEADER_FOOTER_CHECKBOX, - REPORT_SOURCE_TYPES, -} from './report_settings_constants'; -import Showdown from 'showdown'; -import ReactMde from 'react-mde'; -import 'react-mde/lib/styles/css/react-mde-all.css'; -import { - reportDefinitionParams, - timeRangeParams, -} from '../create/create_report_definition'; -import { - parseInContextUrl, - getSavedSearchBaseUrlCreate, - getVisualizationBaseUrlCreate, - getSavedSearchOptions, - getVisualizationOptions, - getDashboardBaseUrlCreate, - getDashboardOptions, - handleDataToVisualReportSourceChange, - getNotebooksOptions, - getNotebooksBaseUrlCreate, - getReportSourceFromURL, -} from './report_settings_helpers'; -import { TimeRangeSelect } from './time_range'; -import { converter } from '../utils'; -import { ReportDefinitionSchemaType } from 'server/model'; -import { ReportTrigger } from '../report_trigger'; - -type ReportSettingProps = { - edit: boolean; - editDefinitionId: string; - reportDefinitionRequest: reportDefinitionParams; - httpClientProps: any; - timeRange: timeRangeParams; - showSettingsReportNameError: boolean; - settingsReportNameErrorMessage: string; - showSettingsReportSourceError: boolean; - settingsReportSourceErrorMessage: string; - showTimeRangeError: boolean; - showTriggerIntervalNaNError: boolean; - showCronError: boolean; -}; - -export function ReportSettings(props: ReportSettingProps) { - const { - edit, - editDefinitionId, - reportDefinitionRequest, - httpClientProps, - timeRange, - showSettingsReportNameError, - settingsReportNameErrorMessage, - showSettingsReportSourceError, - settingsReportSourceErrorMessage, - showTimeRangeError, - showTriggerIntervalNaNError, - showCronError - } = props; - - const [reportName, setReportName] = useState(''); - const [reportDescription, setReportDescription] = useState(''); - const [reportSourceId, setReportSourceId] = useState('dashboardReportSource'); - - const [dashboardSourceSelect, setDashboardSourceSelect] = useState([] as any); - const [dashboards, setDashboards] = useState([] as any); - - const [visualizationSourceSelect, setVisualizationSourceSelect] = useState( - [] as any - ); - const [visualizations, setVisualizations] = useState([] as any); - - const [savedSearchSourceSelect, setSavedSearchSourceSelect] = useState( - [] as any - ); - const [savedSearches, setSavedSearches] = useState([] as any); - - const [notebooksSourceSelect, setNotebooksSourceSelect] = useState([] as any); - const [notebooks, setNotebooks] = useState([] as any); - - const [fileFormat, setFileFormat] = useState('pdf'); - - const handleDashboards = (e) => { - setDashboards(e); - }; - - const handleVisualizations = (e) => { - setVisualizations(e); - }; - - const handleSavedSearches = (e) => { - setSavedSearches(e); - }; - - const handleNotebooks = (e) => { - setNotebooks(e); - }; - - const handleReportName = (e: { - target: { value: React.SetStateAction }; - }) => { - setReportName(e.target.value); - reportDefinitionRequest.report_params.report_name = e.target.value.toString(); - }; - - const handleReportDescription = (e: { - target: { value: React.SetStateAction }; - }) => { - setReportDescription(e.target.value); - reportDefinitionRequest.report_params.description = e.target.value.toString(); - }; - - const handleReportSource = (e: React.SetStateAction) => { - setReportSourceId(e); - let fromInContext = false; - if (window.location.href.includes('?')) { - fromInContext = true; - } - if (e === 'dashboardReportSource') { - reportDefinitionRequest.report_params.report_source = 'Dashboard'; - reportDefinitionRequest.report_params.core_params.base_url = - getDashboardBaseUrlCreate(edit, editDefinitionId, fromInContext) + - dashboards[0]?.value; - - // set params to visual report params after switch from saved search - handleDataToVisualReportSourceChange(reportDefinitionRequest); - setFileFormat('pdf'); - } else if (e === 'visualizationReportSource') { - reportDefinitionRequest.report_params.report_source = 'Visualization'; - reportDefinitionRequest.report_params.core_params.base_url = - getVisualizationBaseUrlCreate(edit, editDefinitionId, fromInContext) + - visualizations[0]?.value; - - // set params to visual report params after switch from saved search - handleDataToVisualReportSourceChange(reportDefinitionRequest); - setFileFormat('pdf'); - } else if (e === 'savedSearchReportSource') { - reportDefinitionRequest.report_params.report_source = 'Saved search'; - reportDefinitionRequest.report_params.core_params.base_url = - getSavedSearchBaseUrlCreate(edit, editDefinitionId, fromInContext) + - savedSearches[0]?.value; - reportDefinitionRequest.report_params.core_params.saved_search_id = - savedSearches[0]?.value; - reportDefinitionRequest.report_params.core_params.report_format = 'csv'; - reportDefinitionRequest.report_params.core_params.limit = 10000; - reportDefinitionRequest.report_params.core_params.excel = true; - } else if (e === 'notebooksReportSource') { - reportDefinitionRequest.report_params.report_source = 'Notebook'; - reportDefinitionRequest.report_params.core_params.base_url = - getNotebooksBaseUrlCreate(edit, editDefinitionId, fromInContext) + - notebooks[0]?.value; - - // set params to visual report params after switch from saved search - handleDataToVisualReportSourceChange(reportDefinitionRequest); - setFileFormat('pdf'); - } - }; - - const handleDashboardSelect = (e: string | any[]) => { - setDashboardSourceSelect(e); - - let fromInContext = false; - if (window.location.href.includes('?')) { - fromInContext = true; - } - - if (e.length > 0) { - reportDefinitionRequest.report_params.core_params.base_url = - getDashboardBaseUrlCreate(edit, editDefinitionId, fromInContext) + - e[0].value; - } else { - reportDefinitionRequest.report_params.core_params.base_url = ''; - } - }; - - const handleVisualizationSelect = (e) => { - setVisualizationSourceSelect(e); - let fromInContext = false; - if (window.location.href.includes('?')) { - fromInContext = true; - } - - if (e.length > 0) { - reportDefinitionRequest.report_params.core_params.base_url = - getVisualizationBaseUrlCreate(edit, editDefinitionId, fromInContext) + - e[0].value; - } else { - reportDefinitionRequest.report_params.core_params.base_url = ''; - } - }; - - const handleSavedSearchSelect = (e) => { - setSavedSearchSourceSelect(e); - let fromInContext = false; - if (window.location.href.includes('?')) { - fromInContext = true; - } - if (e.length > 0) { - reportDefinitionRequest.report_params.core_params.saved_search_id = - e[0].value; - - reportDefinitionRequest.report_params.core_params.base_url = - getSavedSearchBaseUrlCreate(edit, editDefinitionId, fromInContext) + - e[0].value; - } else { - reportDefinitionRequest.report_params.core_params.base_url = ''; - } - }; - - const handleNotebooksSelect = (e) => { - setNotebooksSourceSelect(e); - let fromInContext = false; - if (window.location.href.includes('?')) { - fromInContext = true; - } - if (e.length > 0) { - reportDefinitionRequest.report_params.core_params.base_url = - getNotebooksBaseUrlCreate(edit, editDefinitionId, fromInContext) + - e[0].value; - } else { - reportDefinitionRequest.report_params.core_params.base_url = ''; - } - }; - - const handleFileFormat = (e: React.SetStateAction) => { - setFileFormat(e); - reportDefinitionRequest.report_params.core_params.report_format = e.toString(); - }; - - const PDFandPNGFileFormats = () => { - return ( -
- - - -
- ); - }; - - const SettingsMarkdown = () => { - const [ - checkboxIdSelectHeaderFooter, - setCheckboxIdSelectHeaderFooter, - ] = useState({ ['header']: false, ['footer']: false }); - - const [footer, setFooter] = useState(''); - const [selectedTabFooter, setSelectedTabFooter] = React.useState< - 'write' | 'preview' - >('write'); - - const [header, setHeader] = useState(''); - const [selectedTabHeader, setSelectedTabHeader] = React.useState< - 'write' | 'preview' - >('write'); - - const handleHeader = (e) => { - setHeader(e); - reportDefinitionRequest.report_params.core_params.header = e; - }; - - const handleFooter = (e) => { - setFooter(e); - reportDefinitionRequest.report_params.core_params.footer = e; - }; - - const handleCheckboxHeaderFooter = (optionId) => { - const newCheckboxIdToSelectedMap = { - ...checkboxIdSelectHeaderFooter, - ...{ - [optionId]: !checkboxIdSelectHeaderFooter[optionId], - }, - }; - setCheckboxIdSelectHeaderFooter(newCheckboxIdToSelectedMap); - }; - - const showFooter = checkboxIdSelectHeaderFooter.footer ? ( - - - Promise.resolve(converter.makeHtml(markdown)) - } - /> - - ) : null; - - const showHeader = checkboxIdSelectHeaderFooter.header ? ( - - - Promise.resolve(converter.makeHtml(markdown)) - } - /> - - ) : null; - - useEffect(() => { - let unmounted = false; - if (edit) { - httpClientProps - .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) - .then(async (response: {}) => { - const reportDefinition: ReportDefinitionSchemaType = - response.report_definition; - const { - report_params: { - core_params: { header, footer }, - }, - } = reportDefinition; - // set header/footer default - if (header) { - checkboxIdSelectHeaderFooter.header = true; - if (!unmounted) { - setHeader(header); - } - } - if (footer) { - checkboxIdSelectHeaderFooter.footer = true; - if (!unmounted) { - setFooter(footer); - } - } - }) - .catch((error: any) => { - console.error( - 'error in fetching report definition details:', - error - ); - }); - } else { - // keeps header/footer from re-rendering empty when other fields in Report Settings are changed - checkboxIdSelectHeaderFooter.header = - 'header' in reportDefinitionRequest.report_params.core_params; - checkboxIdSelectHeaderFooter.footer = - 'footer' in reportDefinitionRequest.report_params.core_params; - if (checkboxIdSelectHeaderFooter.header) { - setHeader(reportDefinitionRequest.report_params.core_params.header); - } - if (checkboxIdSelectHeaderFooter.footer) { - setFooter(reportDefinitionRequest.report_params.core_params.footer); - } - } - return () => { - unmounted = true; - }; - }, []); - - return ( -
- - - {showHeader} - {showFooter} -
- ); - }; - - const VisualReportFormatAndMarkdown = () => { - return ( -
- - -
- ); - }; - - const setReportSourceDropdownOption = (options, reportSource, url) => { - let index = 0; - if (reportSource === REPORT_SOURCE_TYPES.dashboard) { - for (index = 0; index < options.dashboard.length; ++index) { - if (url.includes(options.dashboard[index].value)) { - setDashboardSourceSelect([options.dashboard[index]]); - } - } - } else if (reportSource === REPORT_SOURCE_TYPES.visualization) { - for (index = 0; index < options.visualizations.length; ++index) { - if (url.includes(options.visualizations[index].value)) { - setVisualizationSourceSelect([options.visualizations[index]]); - } - } - } else if (reportSource === REPORT_SOURCE_TYPES.savedSearch) { - for (index = 0; index < options.savedSearch.length; ++index) { - if (url.includes(options.savedSearch[index].value)) { - setSavedSearchSourceSelect([options.savedSearch[index]]); - } - } - } - }; - - const setDefaultFileFormat = (fileFormat) => { - let index = 0; - for (index = 0; index < PDF_PNG_FILE_FORMAT_OPTIONS.length; ++index) { - if ( - fileFormat.toUpperCase() === PDF_PNG_FILE_FORMAT_OPTIONS[index].label - ) { - setFileFormat(PDF_PNG_FILE_FORMAT_OPTIONS[index].id); - } - } - }; - - const setDashboardFromInContextMenu = (response, id) => { - let index; - for (index = 0; index < response.dashboard.length; ++index) { - if (id === response.dashboard[index].value) { - setDashboardSourceSelect([response.dashboard[index]]); - } - } - }; - - const setVisualizationFromInContextMenu = (response, id) => { - let index; - for (index = 0; index < response.visualizations.length; ++index) { - if (id === response.visualizations[index].value) { - setVisualizationSourceSelect([response.visualizations[index]]); - } - } - }; - - const setSavedSearchFromInContextMenu = (response, id) => { - let index; - for (index = 0; index < response.savedSearch.length; ++index) { - if (id === response.savedSearch[index].value) { - setSavedSearchSourceSelect([response.savedSearch[index]]); - } - } - }; - - const setNotebookFromInContextMenu = (response, id) => { - for (let index = 0; index < response.notebooks.length; ++index) { - if (id === response.notebooks[index].value) { - setNotebooksSourceSelect([response.notebooks[index]]); - } - } - }; - - const setInContextDefaultConfiguration = (response) => { - const url = window.location.href; - const source = getReportSourceFromURL(url); - const id = parseInContextUrl(url, 'id'); - if (source === 'dashboard') { - setReportSourceId('dashboardReportSource'); - reportDefinitionRequest.report_params.report_source = - REPORT_SOURCE_RADIOS[0].label; - - setDashboardFromInContextMenu(response, id); - reportDefinitionRequest.report_params.core_params.base_url = - getDashboardBaseUrlCreate(edit, id, true) + id; - } else if (source === 'visualize') { - setReportSourceId('visualizationReportSource'); - reportDefinitionRequest.report_params.report_source = - REPORT_SOURCE_RADIOS[1].label; - - setVisualizationFromInContextMenu(response, id); - reportDefinitionRequest.report_params.core_params.base_url = - getVisualizationBaseUrlCreate(edit, editDefinitionId, true) + id; - } else if (source === 'discover') { - setReportSourceId('savedSearchReportSource'); - reportDefinitionRequest.report_params.core_params.report_format = 'csv'; - reportDefinitionRequest.report_params.core_params.saved_search_id = id; - reportDefinitionRequest.report_params.report_source = - REPORT_SOURCE_RADIOS[2].label; - - setSavedSearchFromInContextMenu(response, id); - reportDefinitionRequest.report_params.core_params.base_url = - getSavedSearchBaseUrlCreate(edit, editDefinitionId, true) + id; - } else if (source === 'notebook') { - setReportSourceId('notebooksReportSource'); - reportDefinitionRequest.report_params.report_source = - REPORT_SOURCE_RADIOS[3].label; - - setNotebookFromInContextMenu(response, id); - reportDefinitionRequest.report_params.core_params.base_url = - getNotebooksBaseUrlCreate(edit, id, true) + id; - // set placeholder time range since notebooks doesn't use it - reportDefinitionRequest.report_params.core_params.time_duration = 'PT30M'; - } - }; - - const setDefaultEditValues = async (response, reportSourceOptions) => { - setReportName(response.report_definition.report_params.report_name); - setReportDescription(response.report_definition.report_params.description); - reportDefinitionRequest.report_params.report_name = - response.report_definition.report_params.report_name; - reportDefinitionRequest.report_params.description = - response.report_definition.report_params.description; - reportDefinitionRequest.report_params = - response.report_definition.report_params; - const reportSource = response.report_definition.report_params.report_source; - REPORT_SOURCE_RADIOS.map((radio) => { - if (radio.label === reportSource) { - setReportSourceId(radio.id); - reportDefinitionRequest.report_params.report_source = reportSource; - } - }); - setDefaultFileFormat( - response.report_definition.report_params.core_params.report_format - ); - setReportSourceDropdownOption( - reportSourceOptions, - reportSource, - response.report_definition.report_params.core_params.base_url - ); - }; - - const defaultConfigurationEdit = async (httpClientProps) => { - let editData = {}; - await httpClientProps - .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) - .then(async (response: {}) => { - editData = response; - }) - .catch((error: any) => { - console.error('error in fetching report definition details:', error); - }); - return editData; - }; - - const defaultConfigurationCreate = async (httpClientProps) => { - let reportSourceOptions = { - dashboard: [], - visualizations: [], - savedSearch: [], - notebooks: [], - }; - reportDefinitionRequest.report_params.core_params.report_format = fileFormat; - await httpClientProps - .get('../api/reporting/getReportSource/dashboard') - .then(async (response) => { - let dashboardOptions = getDashboardOptions(response['hits']['hits']); - reportSourceOptions.dashboard = dashboardOptions; - handleDashboards(dashboardOptions); - if (!edit) { - reportDefinitionRequest.report_params.report_source = 'Dashboard'; - } - }) - .catch((error) => { - console.log('error when fetching dashboards:', error); - }); - - await httpClientProps - .get('../api/reporting/getReportSource/visualization') - .then(async (response) => { - let visualizationOptions = getVisualizationOptions( - response['hits']['hits'] - ); - reportSourceOptions.visualizations = visualizationOptions; - await handleVisualizations(visualizationOptions); - }) - .catch((error) => { - console.log('error when fetching visualizations:', error); - }); - - await httpClientProps - .get('../api/reporting/getReportSource/search') - .then(async (response) => { - let savedSearchOptions = getSavedSearchOptions( - response['hits']['hits'] - ); - reportSourceOptions.savedSearch = savedSearchOptions; - await handleSavedSearches(savedSearchOptions); - }) - .catch((error) => { - console.log('error when fetching saved searches:', error); - }); - - await httpClientProps - .get('../api/observability/notebooks/') - .catch((error: any) => { - console.error('error fetching notebooks, retrying with legacy api', error) - return httpClientProps.get('../api/notebooks/') - }) - .then(async (response: any) => { - let notebooksOptions = getNotebooksOptions(response.data); - reportSourceOptions.notebooks = notebooksOptions; - await handleNotebooks(notebooksOptions); - }) - .catch((error) => { - console.log('error when fetching notebooks:', error); - }); - return reportSourceOptions; - }; - - useEffect(() => { - let reportSourceOptions = {}; - let editData = {}; - if (edit) { - defaultConfigurationEdit(httpClientProps).then(async (response) => { - editData = response; - }); - } - defaultConfigurationCreate(httpClientProps).then(async (response) => { - reportSourceOptions = response; - // if coming from in-context menu - if (window.location.href.indexOf('?') > -1) { - setInContextDefaultConfiguration(response); - } - if (edit) { - setDefaultEditValues(editData, reportSourceOptions); - } - }); - }, []); - - const displayDashboardSelect = - reportSourceId === 'dashboardReportSource' ? ( -
- - - - -
- ) : null; - - const displayVisualizationSelect = - reportSourceId === 'visualizationReportSource' ? ( -
- - - - -
- ) : null; - - const displaySavedSearchSelect = - reportSourceId === 'savedSearchReportSource' ? ( -
- - - - -
- ) : null; - - const displayVisualReportsFormatAndMarkdown = - reportSourceId != 'savedSearchReportSource' ? ( -
- - -
- ) : ( -
- - -

CSV

-
-
-
- ); - - const displayNotebooksSelect = - reportSourceId === 'notebooksReportSource' ? ( -
- - - - -
- ) : null; - - const displayTimeRangeSelect = - reportSourceId != 'notebooksReportSource' ? ( -
- - -
- ) : null; - - return ( - - - -

- {i18n.translate( - 'opensearch.reports.reportSettingProps.form.reportSettings', - { defaultMessage: 'Report settings' } - )} -

-
-
- - - - - - - - - - - - - - - - - - - - - - {displayDashboardSelect} - {displayVisualizationSelect} - {displaySavedSearchSelect} - {/* - */} - {displayNotebooksSelect} - {displayTimeRangeSelect} - {displayVisualReportsFormatAndMarkdown} - - - -
- ); -} diff --git a/dashboards-reports/public/components/report_definitions/report_settings/report_settings_constants.tsx b/dashboards-reports/public/components/report_definitions/report_settings/report_settings_constants.tsx deleted file mode 100644 index 824892f1..00000000 --- a/dashboards-reports/public/components/report_definitions/report_settings/report_settings_constants.tsx +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { i18n } from '@osd/i18n'; - -export const REPORT_SOURCE_RADIOS = [ - { - id: 'dashboardReportSource', - label: i18n.translate( - 'opensearch.reports.settings.constants.reportSourceRadios.dashboard', - { defaultMessage: 'Dashboard' } - ), - }, - { - id: 'visualizationReportSource', - label: i18n.translate( - 'opensearch.reports.settings.constants.reportSourceRadios.visualization', - { defaultMessage: 'Visualization' } - ), - }, - { - id: 'savedSearchReportSource', - label: i18n.translate( - 'opensearch.reports.settings.constants.reportSourceRadios.savedSearch', - { defaultMessage: 'Saved search' } - ), - }, - { - id: 'notebooksReportSource', - label: 'Notebook', - }, -]; - -export const PDF_PNG_FILE_FORMAT_OPTIONS = [ - { - id: 'pdf', - label: 'PDF', - }, - { - id: 'png', - label: 'PNG', - }, -]; - -export const SAVED_SEARCH_FORMAT_OPTIONS = [ - { - id: 'csvFormat', - label: 'CSV', - }, - { - id: 'xlsFormat', - label: 'XLS', - }, -]; - -export const HEADER_FOOTER_CHECKBOX = [ - { - id: 'header', - label: i18n.translate( - 'opensearch.reports.settings.constants.headerFooterCheckbox.addHeader', - { defaultMessage: 'Add header' } - ), - }, - { - id: 'footer', - label: i18n.translate( - 'opensearch.reports.settings.constants.headerFooterCheckbox.addFooter', - { defaultMessage: 'Add footer' } - ), - }, -]; -export const REPORT_SOURCE_TYPES = { - dashboard: 'Dashboard', - visualization: 'Visualization', - savedSearch: 'Saved search', - notebook: 'Notebook', -}; - -export const commonTimeRanges = [ - { - start: 'now/d', - end: 'now', - label: i18n.translate( - 'opensearch.reports.settings.constants.commonTimeRanges.todaySoFar', - { defaultMessage: 'Today so far' } - ), - }, - { - start: 'now/w', - end: 'now', - label: i18n.translate( - 'opensearch.reports.settings.constants.commonTimeRanges.weekToDate', - { defaultMessage: 'Week to date' } - ), - }, - { - start: 'now/M', - end: 'now', - label: i18n.translate( - 'opensearch.reports.settings.constants.commonTimeRanges.monthToDate', - { defaultMessage: 'Month to date' } - ), - }, - { - start: 'now/y', - end: 'now', - label: i18n.translate( - 'opensearch.reports.settings.constants.commonTimeRanges.yearToDate', - { defaultMessage: 'Year to date' } - ), - }, -]; diff --git a/dashboards-reports/public/components/report_definitions/report_settings/report_settings_helpers.tsx b/dashboards-reports/public/components/report_definitions/report_settings/report_settings_helpers.tsx deleted file mode 100644 index cc4ef232..00000000 --- a/dashboards-reports/public/components/report_definitions/report_settings/report_settings_helpers.tsx +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export const parseInContextUrl = (url: string, parameter: string) => { - const info = url.split('?'); - if (parameter === 'id') { - return info[1].substring(info[1].indexOf(':') + 1, info[1].length); - } else if (parameter === 'timeFrom') { - return info[2].substring(info[2].indexOf('=') + 1, info[2].length); - } else if (parameter === 'timeTo') { - return info[3].substring(info[3].indexOf('=') + 1, info[3].length); - } - return 'error: invalid parameter'; -}; - -export const getDashboardBaseUrlCreate = ( - edit: boolean, - editDefinitionId: string, - fromInContext: boolean -) => { - let baseUrl; - if (!fromInContext) { - baseUrl = location.pathname + location.hash; - } else { - baseUrl = '/app/dashboards#/view/'; - } - if (edit) { - return baseUrl.replace( - `reports-dashboards#/edit/${editDefinitionId}`, - 'dashboards#/view/' - ); - } else if (fromInContext) { - return baseUrl; - } - return baseUrl.replace( - 'reports-dashboards#/create', - 'dashboards#/view/' - ); -}; - -export const getVisualizationBaseUrlCreate = ( - edit: boolean, - editDefinitionId: string, - fromInContext: boolean -) => { - let baseUrl; - if (!fromInContext) { - baseUrl = location.pathname + location.hash; - } else { - baseUrl = '/app/visualize#/edit/'; - } - if (edit) { - return baseUrl.replace( - `reports-dashboards#/edit/${editDefinitionId}`, - 'visualize#/edit/' - ); - } else if (fromInContext) { - return baseUrl; - } - return baseUrl.replace( - 'reports-dashboards#/create', - 'visualize#/edit/' - ); -}; - -export const getSavedSearchBaseUrlCreate = ( - edit: boolean, - editDefinitionId: string, - fromInContext: boolean -) => { - let baseUrl; - if (!fromInContext) { - baseUrl = location.pathname + location.hash; - } else { - baseUrl = '/app/discover#/view/'; - } - if (edit) { - return baseUrl.replace( - `reports-dashboards#/edit/${editDefinitionId}`, - 'discover#/view/' - ); - } else if (fromInContext) { - return baseUrl; - } - return baseUrl.replace( - 'reports-dashboards#/create', - 'discover#/view/' - ); -}; - -export const getNotebooksBaseUrlCreate = ( - edit: boolean, - editDefinitionId: string, - fromInContext: boolean -) => { - let baseUrl; - if (!fromInContext) { - baseUrl = location.pathname + location.hash; - } else { - baseUrl = '/app/notebooks-dashboards?view=output_only#/'; - } - if (edit) { - return baseUrl.replace( - `reports-dashboards#/edit/${editDefinitionId}`, - 'notebooks-dashboards?view=output_only#/' - ); - } else if (fromInContext) { - return baseUrl; - } - return baseUrl.replace( - 'reports-dashboards#/create', - 'notebooks-dashboards?view=output_only#/' - ); -} - -export const getDashboardOptions = (data: string | any[]) => { - let index; - let dashboard_options = []; - for (index = 0; index < data.length; ++index) { - let entry = { - value: data[index]['_id'].substring(10), - label: data[index]['_source']['dashboard']['title'], - }; - dashboard_options.push(entry); - } - return dashboard_options; -}; - -export const getVisualizationOptions = (data: string | any[]) => { - let index; - let options = []; - for (index = 0; index < data.length; ++index) { - let entry = { - value: data[index]['_id'].substring(14), - label: data[index]['_source']['visualization']['title'], - }; - options.push(entry); - } - return options; -}; - -export const getSavedSearchOptions = (data: string | any[]) => { - let index; - let options = []; - for (index = 0; index < data.length; ++index) { - let entry = { - value: data[index]['_id'].substring(7), - label: data[index]['_source']['search']['title'], - }; - options.push(entry); - } - return options; -}; - -export const getNotebooksOptions = (data: any) => { - let index; - let options = []; - for (index = 0; index < data.length; ++index) { - let entry = { - value: data[index]['id'], - label: data[index]['path'] - } - options.push(entry); - } - return options; -} - -export const handleDataToVisualReportSourceChange = ( - reportDefinitionRequest -) => { - delete reportDefinitionRequest.report_params.core_params.saved_search_id; - delete reportDefinitionRequest.report_params.core_params.limit; - delete reportDefinitionRequest.report_params.core_params.excel; - reportDefinitionRequest.report_params.core_params.report_format = 'pdf'; -}; - -export const getReportSourceFromURL = (url: string) => { - const source = url.split('?')[1].match(/previous=(.*):/); - return source![1]; -} \ No newline at end of file diff --git a/dashboards-reports/public/components/report_definitions/report_settings/time_range.tsx b/dashboards-reports/public/components/report_definitions/report_settings/time_range.tsx deleted file mode 100644 index f27630c6..00000000 --- a/dashboards-reports/public/components/report_definitions/report_settings/time_range.tsx +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import moment from 'moment'; -import React, { useState, useEffect } from 'react'; -import { i18n } from '@osd/i18n'; -import { parseInContextUrl } from './report_settings_helpers'; -import dateMath from '@elastic/datemath'; -import { - EuiFormRow, - EuiGlobalToastList, - EuiSuperDatePicker, -} from '@elastic/eui'; -import { commonTimeRanges } from './report_settings_constants'; - -export function TimeRangeSelect(props) { - const { - reportDefinitionRequest, - timeRange, - edit, - id, - httpClientProps, - showTimeRangeError, - } = props; - - const [recentlyUsedRanges, setRecentlyUsedRanges] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [start, setStart] = useState('now-30m'); - const [end, setEnd] = useState('now'); - - const [toasts, setToasts] = useState([]); - - const addInvalidTimeRangeToastHandler = () => { - const errorToast = { - title: i18n.translate('opensearch.reports.timeRange.invalidTimeRange', { - defaultMessage: 'Invalid time range selected.', - }), - color: 'danger', - iconType: 'alert', - id: 'timeRangeErrorToast', - }; - setToasts(toasts.concat(errorToast)); - }; - - const handleInvalidTimeRangeToast = () => { - addInvalidTimeRangeToastHandler(); - }; - - const removeToast = (removedToast) => { - setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); - }; - - const isValidTimeRange = ( - timeRangeMoment: number | moment.Moment, - limit: string, - handleInvalidTimeRangeToast: any - ) => { - if (limit === 'start') { - if (!timeRangeMoment || !timeRangeMoment.isValid()) { - handleInvalidTimeRangeToast(); - } - } else if (limit === 'end') { - if ( - !timeRangeMoment || - !timeRangeMoment.isValid() || - timeRangeMoment > moment.now() - ) { - handleInvalidTimeRangeToast(); - } - } - }; - - const setDefaultEditTimeRange = (duration, unmounted) => { - let time_difference = moment.now() - duration; - const fromDate = new Date(time_difference); - parseTimeRange(fromDate, end, reportDefinitionRequest); - if (!unmounted) { - setStart(fromDate.toISOString()); - setEnd(end); - } - }; - - // valid time range check for absolute time end date - const checkValidAbsoluteEndDate = (end) => { - let endDate = new Date(end); - let nowDate = new Date(moment.now()); - let valid = true; - if (endDate.getTime() > nowDate.getTime()) { - end = 'now'; - valid = false; - } - return valid; - }; - - useEffect(() => { - let unmounted = false; - // if we are coming from the in-context menu - if (window.location.href.indexOf('?') > -1) { - const url = window.location.href; - const timeFrom = parseInContextUrl(url, 'timeFrom'); - const timeTo = parseInContextUrl(url, 'timeTo'); - parseTimeRange(timeFrom, timeTo, reportDefinitionRequest); - if (!unmounted) { - setStart(timeFrom); - setEnd(timeTo); - } - } else { - if (edit) { - httpClientProps - .get(`../api/reporting/reportDefinitions/${id}`) - .then(async (response: {}) => { - let duration = - response.report_definition.report_params.core_params - .time_duration; - duration = moment.duration(duration); - setDefaultEditTimeRange(duration, unmounted); - }) - .catch((error) => { - console.error( - 'error in fetching report definition details:', - error - ); - }); - } else { - parseTimeRange(start, end, reportDefinitionRequest); - } - } - return () => { - unmounted = true; - }; - }, []); - - const onTimeChange = ({ start, end }) => { - isValidTimeRange( - dateMath.parse(start), - 'start', - handleInvalidTimeRangeToast - ); - isValidTimeRange( - dateMath.parse(end, { roundUp: true }), - 'end', - handleInvalidTimeRangeToast - ); - - const recentlyUsedRange = recentlyUsedRanges.filter((recentlyUsedRange) => { - const isDuplicate = - recentlyUsedRange.start === start && recentlyUsedRange.end === end; - return !isDuplicate; - }); - const validEndDate = checkValidAbsoluteEndDate(end); - if (!validEndDate) { - handleInvalidTimeRangeToast(); - return; - } - - recentlyUsedRange.unshift({ start, end }); - setStart(start); - setEnd(end); - setRecentlyUsedRanges( - recentlyUsedRange.length > 10 - ? recentlyUsedRange.slice(0, 9) - : recentlyUsedRange - ); - setIsLoading(true); - startLoading(); - parseTimeRange(start, end, reportDefinitionRequest); - }; - - const parseTimeRange = (start, end, reportDefinitionRequest) => { - timeRange.timeFrom = dateMath.parse(start); - timeRange.timeTo = dateMath.parse(end); - const timeDuration = moment.duration( - dateMath.parse(end).diff(dateMath.parse(start)) - ); - reportDefinitionRequest.report_params.core_params.time_duration = timeDuration.toISOString(); - }; - - const startLoading = () => { - setTimeout(stopLoading, 1000); - }; - - const stopLoading = () => { - setIsLoading(false); - }; - - return ( -
-
- - - -
-
- -
-
- ); -} diff --git a/dashboards-reports/public/components/report_definitions/report_trigger/__tests__/__snapshots__/report_trigger.test.tsx.snap b/dashboards-reports/public/components/report_definitions/report_trigger/__tests__/__snapshots__/report_trigger.test.tsx.snap deleted file mode 100644 index c0973df4..00000000 --- a/dashboards-reports/public/components/report_definitions/report_trigger/__tests__/__snapshots__/report_trigger.test.tsx.snap +++ /dev/null @@ -1,421 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` panel Render edit on-demand component 1`] = ` -
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-`; - -exports[` panel render create component 1`] = ` -
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-`; - -exports[` panel render edit Cron schedule component 1`] = ` -
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-`; - -exports[` panel render edit recurring 5 hours schedule component 1`] = ` -
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-`; - -exports[` panel render edit recurring 10 minutes schedule component 1`] = ` -
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-`; - -exports[` panel render edit recurring daily schedule component 1`] = ` -
-
-
- -
-
-
-
- -
- -
-
- -
- -
-
-
-
-
-
-`; diff --git a/dashboards-reports/public/components/report_definitions/report_trigger/__tests__/report_trigger.test.tsx b/dashboards-reports/public/components/report_definitions/report_trigger/__tests__/report_trigger.test.tsx deleted file mode 100644 index b8c2f5d3..00000000 --- a/dashboards-reports/public/components/report_definitions/report_trigger/__tests__/report_trigger.test.tsx +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { - render, - waitFor, - waitForElement, - waitForElementToBeRemoved, -} from '@testing-library/react'; -import { ReportTrigger } from '../report_trigger'; -import 'babel-polyfill'; -import 'regenerator-runtime'; -import httpClientMock from '../../../../../test/httpMockClient'; -import { act } from 'react-dom/test-utils'; -import moment from 'moment-timezone'; - -const names = jest.fn(); - -const emptyRequest = { - report_params: { - report_name: '', - report_source: '', - description: '', - core_params: { - base_url: '', - report_format: '', - time_duration: '', - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: '', - trigger_params: {}, - }, - time_created: 0, - last_updated: 0, - status: '', -}; - -describe(' panel', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - test('render create component', () => { - let createReportDefinitionRequest = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: {}, - }, - }; - - let timeRange = { - timeFrom: new Date(), - timeTo: new Date(), - }; - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - }); - - // edit test - test('render edit recurring 5 hours schedule component', async () => { - const promise = Promise.resolve(); - let report_definition = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - schedule: { - interval: { - period: 5, - unit: 'HOURS', - timezone: 'PST8PDT', - }, - }, - enabled_time: 1114939203, - enabled: true, - }, - }, - }; - - let timeRange = { - timeFrom: new Date(), - timeTo: new Date(), - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('render edit recurring daily schedule component', async () => { - const promise = Promise.resolve(); - let editReportDefinitionRequest = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - schedule: { - interval: { - period: 1, - unit: 'DAYS', - start_time: 1114939203, - }, - }, - enabled_time: 1114939203, - enabled: true, - }, - }, - }; - - let timeRange = { - timeFrom: new Date(), - timeTo: new Date(), - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition: editReportDefinitionRequest, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('render edit Cron schedule component', async () => { - const promise = Promise.resolve(); - let cronReportDefinitionRequest = { - report_params: { - report_name: 'edit cron schedule component', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Cron based', - schedule: { - cron: { - expression: '30 1 * * *', - timezone: 'PDT', - }, - }, - enabled_time: 1234567890, - enabled: true, - }, - }, - }; - - let timeRange = { - timeFrom: new Date(), - timeTo: new Date(), - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition: cronReportDefinitionRequest, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('render edit recurring 10 minutes schedule component', async () => { - const promise = Promise.resolve(); - let editReportDefinitionRequest = { - report_params: { - report_name: 'test create report definition trigger', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - schedule_type: 'Recurring', - schedule: { - interval: { - period: 10, - unit: 'MINUTES', - start_time: 1114939203, - }, - }, - enabled_time: 1114939203, - enabled: true, - }, - }, - }; - - let timeRange = { - timeFrom: new Date(), - timeTo: new Date(), - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition: editReportDefinitionRequest, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); - - test('Render edit on-demand component', async () => { - const promise = Promise.resolve(); - let editReportDefinitionRequest = { - report_params: { - report_name: 'edit cron schedule component', - report_source: 'Dashboard', - description: '', - core_params: { - base_url: '', - report_format: '', - header: '', - footer: '', - time_duration: '', - }, - }, - delivery: { - delivery_type: '', - delivery_params: {}, - }, - trigger: { - trigger_type: 'On demand', - }, - }; - - let timeRange = { - timeFrom: new Date(), - timeTo: new Date(), - }; - - httpClientMock.get = jest.fn().mockResolvedValue({ - report_definition: editReportDefinitionRequest, - }); - - const { container } = render( - - ); - - expect(container.firstChild).toMatchSnapshot(); - await act(() => promise); - }); -}); diff --git a/dashboards-reports/public/components/report_definitions/report_trigger/index.ts b/dashboards-reports/public/components/report_definitions/report_trigger/index.ts deleted file mode 100644 index 99c31037..00000000 --- a/dashboards-reports/public/components/report_definitions/report_trigger/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export { ReportTrigger } from './report_trigger'; diff --git a/dashboards-reports/public/components/report_definitions/report_trigger/report_trigger.tsx b/dashboards-reports/public/components/report_definitions/report_trigger/report_trigger.tsx deleted file mode 100644 index 1ab67ebc..00000000 --- a/dashboards-reports/public/components/report_definitions/report_trigger/report_trigger.tsx +++ /dev/null @@ -1,720 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect, useState } from 'react'; -import { i18n } from '@osd/i18n'; -import { - EuiFormRow, - EuiRadioGroup, - EuiDatePicker, - EuiSelect, - EuiSpacer, - EuiFlexGroup, - EuiFlexItem, - EuiText, - EuiFieldText, - EuiCheckboxGroup, - EuiTextArea, - EuiLink, - EuiFieldNumber, -} from '@elastic/eui'; -import moment, { Moment } from 'moment'; -import { reportDefinitionParams } from '../create/create_report_definition'; -import { - SCHEDULE_RECURRING_OPTIONS, - INTERVAL_TIME_PERIODS, - WEEKLY_CHECKBOX_OPTIONS, - MONTHLY_ON_THE_OPTIONS, - TRIGGER_TYPE_OPTIONS, - SCHEDULE_TYPE_OPTIONS, - TIMEZONE_OPTIONS, -} from './report_trigger_constants'; -import { TimezoneSelect } from './timezone'; - -type ReportTriggerProps = { - edit: boolean; - editDefinitionId: string; - reportDefinitionRequest: reportDefinitionParams; - httpClientProps: any; - showTriggerIntervalNaNError: boolean; - showCronError: boolean; -}; - -export function ReportTrigger(props: ReportTriggerProps) { - const { - edit, - editDefinitionId, - reportDefinitionRequest, - httpClientProps, - showTriggerIntervalNaNError, - showCronError, - } = props; - - const [reportTriggerType, setReportTriggerType] = useState( - TRIGGER_TYPE_OPTIONS[0].id - ); - - const [scheduleType, setScheduleType] = useState( - SCHEDULE_TYPE_OPTIONS[0].label - ); - //TODO: should read local timezone and display - const [scheduleRecurringFrequency, setScheduleRecurringFrequency] = useState( - 'daily' - ); - const [recurring, setRecurringTime] = useState(moment()); - - const [weeklyCheckbox, setWeeklyCheckbox] = useState({ - ['monCheckbox']: true, - }); - const [monthlySelect, setMonthlySelect] = useState( - MONTHLY_ON_THE_OPTIONS[0].value - ); - - const handleReportTriggerType = (e: string) => { - setReportTriggerType(e); - reportDefinitionRequest.trigger.trigger_type = e; - if (e === 'On demand') { - delete reportDefinitionRequest.trigger.trigger_params; - } - }; - - const handleScheduleType = (e: React.SetStateAction) => { - setScheduleType(e); - if (e === SCHEDULE_TYPE_OPTIONS[1].label) { - delete reportDefinitionRequest.trigger.trigger_params.schedule.interval; - } else if (e === SCHEDULE_TYPE_OPTIONS[0].label) { - delete reportDefinitionRequest.trigger.trigger_params.schedule.cron; - } - }; - - const handleScheduleRecurringFrequency = (e: { - target: { value: React.SetStateAction }; - }) => { - setScheduleRecurringFrequency(e.target.value); - reportDefinitionRequest.trigger.trigger_params.schedule_type = - e.target.value; - }; - - const handleRecurringTime = (e: React.SetStateAction) => { - setRecurringTime(e); - }; - - const handleWeeklyCheckbox = (e) => { - const newCheckboxIdToSelectedMap = { - ...weeklyCheckbox, - ...{ - [e]: !weeklyCheckbox[e], - }, - }; - setWeeklyCheckbox(newCheckboxIdToSelectedMap); - }; - - const handleMonthlySelect = (e: { - target: { value: React.SetStateAction }; - }) => { - setMonthlySelect(e.target.value); - }; - - const RequestTime = () => { - useEffect(() => { - let recurringDaily = { - interval: { - period: 1, - unit: 'DAYS', - start_time: recurring.valueOf(), - }, - }; - reportDefinitionRequest.trigger.trigger_params = { - ...reportDefinitionRequest.trigger.trigger_params, - enabled_time: recurring.valueOf(), - schedule: recurringDaily, - }; - }, []); - - return ( -
- - - - -
- ); - }; - - const RecurringDaily = () => { - const [recurringDailyTime, setRecurringDailyTime] = useState(moment()); - - const handleRecurringDailyTime = (e) => { - setRecurringDailyTime(e); - reportDefinitionRequest.trigger.trigger_params.schedule.interval.start_time = e.valueOf(); - }; - - const setDailyParams = () => { - let recurringDaily = { - interval: { - period: 1, - unit: 'DAYS', - start_time: recurringDailyTime.valueOf(), - }, - }; - reportDefinitionRequest.trigger.trigger_params = { - ...reportDefinitionRequest.trigger.trigger_params, - enabled_time: recurringDailyTime.valueOf(), - schedule: recurringDaily, - }; - }; - - const isDailySchedule = (response) => { - return ( - response.report_definition.trigger.trigger_params.schedule_type === - SCHEDULE_TYPE_OPTIONS[0].id && - response.report_definition.trigger.trigger_params.schedule.interval - .period === 1 && - response.report_definition.trigger.trigger_params.schedule.interval === - 'DAYS' - ); - }; - - useEffect(() => { - let unmounted = false; - if (edit) { - httpClientProps - .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) - .then(async (response) => { - // if switching from on demand to schedule - if ( - response.report_definition.trigger.trigger_type === 'On demand' - ) { - setDailyParams(); - } else if (isDailySchedule(response)) { - const date = moment( - response.report_definition.trigger.trigger_params.schedule - .interval.start_time - ); - if (!unmounted) { - setRecurringDailyTime(date); - } - } - // if switching from on-demand to schedule - else if ( - reportDefinitionRequest.trigger.trigger_params.schedule_type === - SCHEDULE_TYPE_OPTIONS[0].id - ) { - setDailyParams(); - } - }); - } else { - setDailyParams(); - } - return () => { - unmounted = true; - }; - }, []); - - return ( -
- - - - -
- ); - }; - - const RecurringInterval = () => { - const [intervalText, setIntervalText] = useState(''); - const [intervalTimePeriod, setIntervalTimePeriod] = useState( - INTERVAL_TIME_PERIODS[0].value - ); - const [recurringIntervalTime, setRecurringIntervalTime] = useState( - moment() - ); - - const handleRecurringIntervalTime = (e) => { - setRecurringIntervalTime(e); - reportDefinitionRequest.trigger.trigger_params.schedule.interval.start_time = e.valueOf(); - }; - - const handleIntervalText = (e: { - target: { value: React.SetStateAction }; - }) => { - setIntervalText(e.target.value); - }; - - const handleIntervalTimePeriod = (e: { - target: { value: React.SetStateAction }; - }) => { - setIntervalTimePeriod(e.target.value); - }; - - useEffect(() => { - let interval = { - interval: { - period: parseInt(intervalText, 10), - unit: intervalTimePeriod, - start_time: recurringIntervalTime.valueOf(), - }, - }; - reportDefinitionRequest.trigger.trigger_params = { - ...reportDefinitionRequest.trigger.trigger_params, - enabled_time: recurringIntervalTime.valueOf(), - schedule: interval, - }; - }, [intervalTimePeriod, intervalText]); - - // second useEffect() only to be triggered before render when on Edit - useEffect(() => { - let unmounted = false; - if (edit) { - httpClientProps - .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) - .then(async (response) => { - if ( - response.report_definition.trigger.trigger_params - .schedule_type === SCHEDULE_TYPE_OPTIONS[0].id - ) { - const date = moment( - response.report_definition.trigger.trigger_params.schedule - .interval.start_time - ); - if (!unmounted) { - setRecurringIntervalTime(date); - setIntervalText( - response.report_definition.trigger.trigger_params.schedule.interval.period.toString() - ); - setIntervalTimePeriod( - response.report_definition.trigger.trigger_params.schedule - .interval.unit - ); - } - } - }); - } - return () => { - unmounted = true; - }; - }, []); - - return ( -
- - - - - - - - - - - - - - - -
- ); - }; - - const RecurringWeekly = () => { - return ( -
- - - - - -
- ); - }; - - const RecurringMonthly = () => { - const [monthlyDayNumber, setMonthlyDayNumber] = useState(''); - - const handleMonthlyDayNumber = (e: { - target: { value: React.SetStateAction }; - }) => { - setMonthlyDayNumber(e.target.value); - }; - - return ( -
- - - - - - - - - - - - -
- ); - }; - - const CronExpression = () => { - const [cronExpression, setCronExpression] = useState(''); - - const handleCronExpression = (e: { - target: { value: React.SetStateAction }; - }) => { - setCronExpression(e.target.value); - reportDefinitionRequest.trigger.trigger_params.schedule.cron.expression = - e.target.value; - }; - - const setCronParams = () => { - let cron = { - cron: { - expression: '', - timezone: TIMEZONE_OPTIONS[0].value, - }, - }; - reportDefinitionRequest.trigger.trigger_params = { - ...reportDefinitionRequest.trigger.trigger_params, - enabled_time: Date.now().valueOf(), - schedule: cron, - }; - }; - - useEffect(() => { - if (edit) { - httpClientProps - .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) - .then(async (response) => { - // if switching from on demand to schedule - if ( - response.report_definition.trigger.trigger_type === 'On demand' - ) { - setCronParams(); - } else if ( - response.report_definition.trigger.trigger_params - .schedule_type === SCHEDULE_TYPE_OPTIONS[1].id - ) { - setCronExpression( - response.report_definition.trigger.trigger_params.schedule.cron - .expression - ); - } else { - setCronParams(); - } - }); - } else { - setCronParams(); - } - }, []); - - return ( -
- - - Cron help - - - } - > - - - -
- ); - }; - - const ScheduleTriggerRecurring = () => { - const display_daily = - scheduleRecurringFrequency === 'daily' ? : null; - - const display_interval = - scheduleRecurringFrequency === 'byInterval' ? ( - - ) : null; - - const display_weekly = - scheduleRecurringFrequency === 'weekly' ? : null; - - const display_monthly = - scheduleRecurringFrequency === 'monthly' ? : null; - - return ( -
- - - - - {display_daily} - {display_interval} - {display_weekly} - {display_monthly} -
- ); - }; - - const ScheduleTrigger = () => { - const display_recurring = - scheduleType === SCHEDULE_TYPE_OPTIONS[0].id ? ( - - ) : null; - - const display_cron = - scheduleType === SCHEDULE_TYPE_OPTIONS[1].id ? ( -
- - -
- ) : null; - - useEffect(() => { - // Set default trigger_type - SCHEDULE_TYPE_OPTIONS.map((item) => { - if (item.id === scheduleType) { - reportDefinitionRequest.trigger.trigger_params = { - ...reportDefinitionRequest.trigger.trigger_params, - schedule_type: item.id, - //TODO: need better handle - }; - if (!edit) { - reportDefinitionRequest.trigger.trigger_params.enabled = true; - } - if (!('enabled' in reportDefinitionRequest.trigger.trigger_params)) { - reportDefinitionRequest.trigger.trigger_params.enabled = true; - } - } - }); - }, [scheduleType]); - - return ( -
- - - - - {display_recurring} - {display_cron} -
- ); - }; - - const schedule = - reportTriggerType === 'Schedule' ? : null; - - const defaultEditTriggerType = (trigger_type) => { - let index = 0; - for (index; index < TRIGGER_TYPE_OPTIONS.length; ++index) { - if (TRIGGER_TYPE_OPTIONS[index].id === trigger_type) { - setReportTriggerType(TRIGGER_TYPE_OPTIONS[index].id); - } - } - }; - - const defaultEditRequestType = (trigger) => { - let index = 0; - for (index; index < SCHEDULE_TYPE_OPTIONS.length; ++index) { - if ( - SCHEDULE_TYPE_OPTIONS[index].id === trigger.trigger_params.schedule_type - ) { - setScheduleType(SCHEDULE_TYPE_OPTIONS[index].id); - } - } - }; - - const defaultEditScheduleFrequency = (trigger_params) => { - if (trigger_params.schedule_type === SCHEDULE_TYPE_OPTIONS[0].id) { - if ( - trigger_params.schedule.interval.unit === 'Days' && - trigger_params.schedule.interval.period === 1 - ) { - setScheduleRecurringFrequency('daily'); - } else { - setScheduleRecurringFrequency('byInterval'); - } - } - }; - - const defaultConfigurationEdit = (trigger) => { - defaultEditTriggerType(trigger.trigger_type); - if (trigger.trigger_type === 'Schedule') { - defaultEditScheduleFrequency(trigger.trigger_params); - defaultEditRequestType(trigger); - } else if (trigger.trigger_type == 'On demand') { - setReportTriggerType('On demand'); - reportDefinitionRequest.trigger.trigger_type = 'On demand'; - } - }; - - useEffect(() => { - if (edit) { - httpClientProps - .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) - .then(async (response) => { - defaultConfigurationEdit(response.report_definition.trigger); - reportDefinitionRequest.trigger = response.report_definition.trigger; - }); - } - // Set default trigger_type for create new report definition - else { - TRIGGER_TYPE_OPTIONS.map((item) => { - if (item.id === reportTriggerType) { - reportDefinitionRequest.trigger.trigger_type = item.id; - } - }); - } - }, []); - - return ( -
- - - - - {schedule} -
- ); -} diff --git a/dashboards-reports/public/components/report_definitions/report_trigger/report_trigger_constants.tsx b/dashboards-reports/public/components/report_definitions/report_trigger/report_trigger_constants.tsx deleted file mode 100644 index 71905384..00000000 --- a/dashboards-reports/public/components/report_definitions/report_trigger/report_trigger_constants.tsx +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import moment from 'moment-timezone'; -import { i18n } from '@osd/i18n'; - -export const TRIGGER_TYPE_OPTIONS = [ - { - id: 'On demand', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.triggerTypeOptions.onDemand', - { defaultMessage: 'On demand' } - ), - }, - { - id: 'Schedule', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.triggerTypeOptions.schedule', - { defaultMessage: 'Schedule' } - ), - }, -]; - -export const SCHEDULE_TYPE_OPTIONS = [ - { - id: 'Recurring', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.scheduleTypeOptions.recurring', - { defaultMessage: 'Recurring' } - ), - }, - { - id: 'Cron based', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.scheduleTypeOptions.cronBased', - { defaultMessage: 'Cron based' } - ), - }, -]; - -export const SCHEDULE_RECURRING_OPTIONS = [ - { - value: 'daily', - text: i18n.translate( - 'opensearch.reports.reportTriggerConstants.scheduleRecurringOptions.daily', - { defaultMessage: 'Daily' } - ), - }, - { - value: 'byInterval', - text: i18n.translate( - 'opensearch.reports.reportTriggerConstants.scheduleRecurringOptions.byInterval', - { defaultMessage: 'By interval' } - ), - }, - // TODO: disable on UI. Add them back once we support - // { - // value: 'weekly', - // text: 'Weekly', - // }, - // { - // value: 'monthly', - // text: 'Monthly', - // }, -]; - -export const INTERVAL_TIME_PERIODS = [ - { - value: 'MINUTES', - text: i18n.translate( - 'opensearch.reports.reportTriggerConstants.intervalTimePeriods.minutes', - { defaultMessage: 'Minutes' } - ), - }, - { - value: 'HOURS', - text: i18n.translate( - 'opensearch.reports.reportTriggerConstants.intervalTimePeriods.hours', - { defaultMessage: 'Hours' } - ), - }, - { - value: 'DAYS', - text: i18n.translate( - 'opensearch.reports.reportTriggerConstants.intervalTimePeriods.days', - { defaultMessage: 'Days' } - ), - }, -]; - -export const WEEKLY_CHECKBOX_OPTIONS = [ - { - id: 'monCheckbox', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.weeklyCheckboxOptions.mon', - { defaultMessage: 'Mon' } - ), - }, - { - id: 'tueCheckbox', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.weeklyCheckboxOptions.tue', - { defaultMessage: 'Tue' } - ), - }, - { - id: 'wedCheckbox', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.weeklyCheckboxOptions.wed', - { defaultMessage: 'Wed' } - ), - }, - { - id: 'thuCheckbox', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.weeklyCheckboxOptions.thu', - { defaultMessage: 'Thu' } - ), - }, - { - id: 'friCheckbox', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.weeklyCheckboxOptions.fri', - { defaultMessage: 'Fri' } - ), - }, - { - id: 'satCheckbox', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.weeklyCheckboxOptions.sat', - { defaultMessage: 'Sat' } - ), - }, - { - id: 'sunCheckbox', - label: i18n.translate( - 'opensearch.reports.reportTriggerConstants.weeklyCheckboxOptions.sun', - { defaultMessage: 'Sun' } - ), - }, -]; - -export const MONTHLY_ON_THE_OPTIONS = [ - { - value: 'day', - text: i18n.translate( - 'opensearch.reports.reportTriggerConstants.monthlyOnTheOptions.day', - { defaultMessage: 'Day' } - ), - }, -]; - -export const TIMEZONE_OPTIONS = moment.tz - .names() - .map((tz) => ({ value: tz, text: tz })); diff --git a/dashboards-reports/public/components/report_definitions/report_trigger/timezone.tsx b/dashboards-reports/public/components/report_definitions/report_trigger/timezone.tsx deleted file mode 100644 index aee4ceca..00000000 --- a/dashboards-reports/public/components/report_definitions/report_trigger/timezone.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiFormRow, EuiSelect } from '@elastic/eui'; -import React, { useState, useEffect } from 'react'; -import { i18n } from '@osd/i18n'; -import { TIMEZONE_OPTIONS } from './report_trigger_constants'; - -export function TimezoneSelect(props: { reportDefinitionRequest: any; httpClientProps: any; edit: any; editDefinitionId: any; }) { - const { - reportDefinitionRequest, - httpClientProps, - edit, - editDefinitionId, - } = props; - const [timezone, setTimezone] = useState(TIMEZONE_OPTIONS[0].value); - - const handleTimezone = (e: { target: { value: React.SetStateAction; }; }) => { - setTimezone(e.target.value); - if ( - reportDefinitionRequest.trigger.trigger_params.schedule_type === - 'Cron based' - ) { - reportDefinitionRequest.trigger.trigger_params.schedule.cron.timezone = - e.target.value; - } - }; - - useEffect(() => { - let unmounted = false; - if (edit) { - httpClientProps - .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) - .then(async (response) => { - if ( - !unmounted && - reportDefinitionRequest.trigger.trigger_params.schedule_type === - 'Cron based' - ) { - setTimezone( - response.report_definition.trigger.trigger_params.schedule.cron - .timezone - ); - } - }); - } - return () => { - unmounted = true; - }; - }, []); - - return ( -
- - - -
- ); -} diff --git a/dashboards-reports/public/components/report_definitions/utils/index.ts b/dashboards-reports/public/components/report_definitions/utils/index.ts deleted file mode 100644 index f5e69b95..00000000 --- a/dashboards-reports/public/components/report_definitions/utils/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import Showdown from 'showdown'; - -export const converter = new Showdown.Converter({ - tables: true, - simplifiedAutoLink: true, - strikethrough: true, - tasklists: true, - noHeaderId: true, -}); diff --git a/dashboards-reports/public/components/report_definitions/utils/utils.tsx b/dashboards-reports/public/components/report_definitions/utils/utils.tsx deleted file mode 100644 index cf10f061..00000000 --- a/dashboards-reports/public/components/report_definitions/utils/utils.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { isValidCron } from 'cron-validator'; -import { i18n } from '@osd/i18n'; -import moment from 'moment'; -import { includeDelivery } from '../delivery/delivery'; - -export const definitionInputValidation = async ( - metadata, - error, - setShowSettingsReportNameError, - setSettingsReportNameErrorMessage, - setShowSettingsReportSourceError, - setSettingsReportSourceErrorMessage, - setShowTriggerIntervalNaNError, - timeRange, - setShowTimeRangeError, - setShowCronError -) => { - // check report name - // allow a-z, A-Z, 0-9, (), [], ',' - and _ and spaces - let regexp = /^[\w\-\s\(\)\[\]\,\_\-+]+$/; - if (metadata.report_params.report_name.search(regexp) === -1) { - setShowSettingsReportNameError(true); - if (metadata.report_params.report_name === '') { - setSettingsReportNameErrorMessage('Name must not be empty.'); - } else { - setSettingsReportNameErrorMessage('Invalid characters in report name.'); - } - error = true; - } - - // if recurring by interval and input is not a number - if ( - metadata.trigger.trigger_type === 'Schedule' && - metadata.trigger.trigger_params.schedule_type === 'Recurring' - ) { - let interval = parseInt( - metadata.trigger.trigger_params.schedule.interval.period - ); - if (isNaN(interval)) { - setShowTriggerIntervalNaNError(true); - error = true; - } - } - - // if report source is blank - if (metadata.report_params.core_params.base_url === '') { - setShowSettingsReportSourceError(true); - setSettingsReportSourceErrorMessage( - i18n.translate('opensearch.reports.error.reportSourceMustNotBeEmpty', { - defaultMessage: 'Report source must not be empty.', - }) - ); - error = true; - } - - // if time range is invalid - const nowDate = new Date(moment.now()); - if (timeRange.timeFrom > timeRange.timeTo || timeRange.timeTo > nowDate) { - setShowTimeRangeError(true); - error = true; - } - - // if cron based and cron input is invalid - if ( - metadata.trigger.trigger_type === 'Schedule' && - metadata.trigger.trigger_params.schedule_type === 'Cron based' - ) { - if ( - !isValidCron(metadata.trigger.trigger_params.schedule.cron.expression) - ) { - setShowCronError(true); - error = true; - } - } - return error; -}; diff --git a/dashboards-reports/public/components/utils/settings_service.ts b/dashboards-reports/public/components/utils/settings_service.ts deleted file mode 100644 index 197e5e4e..00000000 --- a/dashboards-reports/public/components/utils/settings_service.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { IUiSettingsClient } from '../../../../../src/core/public'; - -let uiSettings: IUiSettingsClient; - -export const uiSettingsService = { - init: (client: IUiSettingsClient) => { - uiSettings = client; - }, - get: (key: string, defaultOverride?: any) => { - return uiSettings?.get(key, defaultOverride) || ''; - }, - getSearchParams: function () { - const rawTimeZone = this.get('dateFormat:tz'); - const timezone = - !rawTimeZone || rawTimeZone === 'Browser' - ? Intl.DateTimeFormat().resolvedOptions().timeZone - : rawTimeZone; - const dateFormat = this.get('dateFormat'); - const csvSeparator = this.get('csv:separator'); - return { - timezone, - dateFormat, - csvSeparator, - }; - }, -}; diff --git a/dashboards-reports/public/components/utils/utils.tsx b/dashboards-reports/public/components/utils/utils.tsx deleted file mode 100644 index 2638c993..00000000 --- a/dashboards-reports/public/components/utils/utils.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; - -export const permissionsMissingToast = (action: string) => { - return { - title: 'Error ' + action, - color: 'danger', - iconType: 'alert', - id: 'permissionsMissingErrorToast' + action.replace(' ', ''), - text: ( -

Insufficient permissions. Reach out to your OpenSearch Dashboards administrator.

- ), - }; -}; - -export const permissionsMissingActions = { - CHANGE_SCHEDULE_STATUS: 'changing schedule status.', - DELETE_REPORT_DEFINITION: 'deleting report definition.', - GENERATING_REPORT: 'generating report.', - LOADING_REPORTS_TABLE: 'loading reports table.', - LOADING_DEFINITIONS_TABLE: 'loading report definitions table.', - VIEWING_EDIT_PAGE: 'viewing edit page.', - UPDATING_DEFINITION: 'updating report definition', - CREATING_REPORT_DEFINITION: 'creating new report definition.', -}; - -export const timeRangeMatcher = /time:\(from:(.+?),to:(.+?)\)/; diff --git a/dashboards-reports/public/hack.js b/dashboards-reports/public/hack.js deleted file mode 100644 index a850c169..00000000 --- a/dashboards-reports/public/hack.js +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ diff --git a/dashboards-reports/public/index.scss b/dashboards-reports/public/index.scss deleted file mode 100644 index c9c7fb66..00000000 --- a/dashboards-reports/public/index.scss +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -.react-mde .mde-header .mde-tabs button { - border-radius: 2px; - margin: 12px 4px 0px; - background-color: transparent; - border-bottom: 3px solid transparent; - cursor: pointer; - padding: 0 16px; - min-height: 30px; - &.selected { - border-top: none; - border-left: none; - border-right: none; - border-bottom: 3px solid #006bb4; - } - &:first-child { - margin-left: 0px; - } -} - -.mde-preview-content { - ul { - list-style: disc; - } - ol { - list-style: decimal; - } -} diff --git a/dashboards-reports/public/index.ts b/dashboards-reports/public/index.ts deleted file mode 100644 index 81ec549e..00000000 --- a/dashboards-reports/public/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import './index.scss'; -import { ReportsDashboardsPlugin } from './plugin'; - -// This exports static code and TypeScript types, -// as well as, OpenSearch Dashboards Platform `plugin()` initializer. -export function plugin() { - return new ReportsDashboardsPlugin(); -} -export { - ReportsDashboardsPluginSetup, - ReportsDashboardsPluginStart, -} from './types'; diff --git a/dashboards-reports/public/plugin.ts b/dashboards-reports/public/plugin.ts deleted file mode 100644 index 2c26eb6c..00000000 --- a/dashboards-reports/public/plugin.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - AppMountParameters, - CoreSetup, - CoreStart, - Plugin, -} from '../../../src/core/public'; -import { - ReportsDashboardsPluginSetup, - ReportsDashboardsPluginStart, - AppPluginStartDependencies, -} from './types'; -import { i18n } from '@osd/i18n'; -import './components/context_menu/context_menu'; -import { PLUGIN_ID, PLUGIN_NAME } from '../common'; -import { uiSettingsService } from './components/utils/settings_service'; - -export class ReportsDashboardsPlugin - implements Plugin -{ - public setup(core: CoreSetup): ReportsDashboardsPluginSetup { - uiSettingsService.init(core.uiSettings); - // Register an application into the side navigation menu - core.application.register({ - id: PLUGIN_ID, - title: i18n.translate('opensearch.reports.pluginName', { - defaultMessage: PLUGIN_NAME, - }), - category: { - id: 'opensearch', - label: i18n.translate('opensearch.reports.categoryName', { - defaultMessage: 'OpenSearch Plugins', - }), - order: 2000, - }, - order: 2000, - async mount(params: AppMountParameters) { - // Load application bundle - const { renderApp } = await import('./application'); - // Get start services as specified in opensearch_dashboards.json - const [coreStart, depsStart] = await core.getStartServices(); - // Render the application - return renderApp( - coreStart, - depsStart as AppPluginStartDependencies, - params - ); - }, - }); - - // Return methods that should be available to other plugins - return {}; - } - - public start(core: CoreStart): ReportsDashboardsPluginStart { - return {}; - } - - public stop() {} -} diff --git a/dashboards-reports/public/types.ts b/dashboards-reports/public/types.ts deleted file mode 100644 index 0f99e9bb..00000000 --- a/dashboards-reports/public/types.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { NavigationPublicPluginStart } from '../../../src/plugins/navigation/public'; - -export interface ReportsDashboardsPluginSetup {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ReportsDashboardsPluginStart {} - -export interface AppPluginStartDependencies { - navigation: NavigationPublicPluginStart; -} diff --git a/dashboards-reports/rendering-engine/headless-chrome/README.md b/dashboards-reports/rendering-engine/headless-chrome/README.md deleted file mode 100644 index 21cf34a5..00000000 --- a/dashboards-reports/rendering-engine/headless-chrome/README.md +++ /dev/null @@ -1,56 +0,0 @@ -## Chrome Binaries for OpenSearch Dashboards Reports used by Puppeteer -Headless Chrome for Linux and Mac are chrome binaries which are significantly smaller than the standard binaries shipped by Google and Puppeteer. -Chrome binary can be built from shell script build_headless_chrome.sh for Mac, Linux x64 and Linux arm64, -output of script is called headless_shell. - -## Puppeteer's Chrome version - -Find the puppeteer version used in OpenSearch Dashboards node_modules.json and get the associated chrome SHA to build from crrev.com and puppeteer repositories. Puppeteer 1.9 uses rev 674921 with commit sha as 312d84c8ce62810976feda0d3457108a6dfff9e6) - -## headless Chrome folder structure --chromium - |-chromium - |-chromium - |-src - |-out - |-headless - |-headless_shell # output of scripts - -## How to generate the headless_chrome -This is a shell script to set environment variable, download the source code and build the executable. - -## Commands to create headless_chrome -Run below command to create headless_shell for each platform - -headless-chrome.sh chrome-version-SHA (arch_name (arm64)) -. Mac x64: ./build_headless_chrome.sh -. Linux x64: ./build_headless_chrome.sh -. Linux arm64: ./build_headless_chrome.sh arm64 - -# How to call in Command line: -. PNG report: ./headless_shell --headless --disable-gpu --screenshot=test.png https://opensearch.org/docs/ -. PDF report: ./headless_shell --headless --disable-gpu --print-to-pdf=test.pdf https://opensearch.org/docs/ - -## Headless Chromium for MAC -# Files: - headless_shell - libswiftshader_libGLESv2.dylib - -## Headless Chromium for Linux (arm64 and x64) -# Files: - headless_shell - swiftshader - |-libEGL.so - |-libEGL.so.TOC - |-libGLESv2.so - |-libGLESv2.so.TOC -# Additional libaries: -- Ubuntu needs additional dependencies to run chromium -``` -sudo apt install -y libnss3-dev fonts-liberation libfontconfig1 -``` -- RedHat/CentOS/Amazon Linux 2 needs additional dependencies to run chromium -``` -sudo yum install -y libnss3.so xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc fontconfig freetype ipa-gothic-fonts -``` - diff --git a/dashboards-reports/rendering-engine/headless-chrome/build_headless_chrome.sh b/dashboards-reports/rendering-engine/headless-chrome/build_headless_chrome.sh deleted file mode 100644 index 219ba8e8..00000000 --- a/dashboards-reports/rendering-engine/headless-chrome/build_headless_chrome.sh +++ /dev/null @@ -1,176 +0,0 @@ -#!/bin/bash - -# Initializes a Linux environment. This need only be done once per -# machine. The OS needs to be a flavor that supports apt get, such as Ubuntu. - -function generateArgs { -if [ $1 == 'linux' ]; then - echo 'import("//build/args/headless.gn") -is_component_build = false -remove_webcore_debug_symbols = true -enable_nacl = false -is_debug = false -symbol_level = 0 -use_kerberos = false' > args.gn -elif [ $1 == 'darwin' ]; then - echo '#args configuration - -icu_use_data_file = false -v8_use_external_startup_data = false -remove_webcore_debug_symbols = true -use_kerberos = false -use_libpci = false -use_pulseaudio = false -use_udev = false -is_debug = false -symbol_level = 0 -is_component_build = false -enable_nacl = false -enable_print_preview = false -enable_basic_printing = false -enable_remoting = false -use_alsa = false -use_cups = false -use_dbus = false -use_gio = false -' > args.gn -fi -} - -ARGC=("$#") - -if [ $ARGC -lt 1 ]; -then - echo "format: build_headless_chrome.sh {chrome_source_version} (arch_name)" - echo "Mac x64: ./build_headless_chrome.sh 312d84c8ce62810976feda0d3457108a6dfff9e6" - echo "Linux x64: ./build_headless_chrome.sh 312d84c8ce62810976feda0d3457108a6dfff9e6" - echo "Linux arm64: ./build_headless_chrome.sh 312d84c8ce62810976feda0d3457108a6dfff9e6 arm64" - exit -fi - -source_version=$1 - -if [ $ARGC -lt 2 ]; -then - arch_name="x64" -else - arch_name=$2 -fi - -if ! [ -x "$(command -v python)" ]; then - echo "Python is not found, please install python or setup python environment properly" - exit -fi - -# Launch the cross-platform init script using a relative path -# from this script's location. -mkdir -p ~/chromium - -if [ "$#" -eq 2 ]; then - arch_name=$2 -fi - -current_folder=$(pwd) - -# find the current platform -platform_name='unknown' -if [[ "$OSTYPE" == "linux-gnu"* ]]; then - platform_name='linux' -elif [[ "$OSTYPE" == "darwin"* ]]; then - platform_name='darwin' -elif [[ "$OSTYPE" == "win32" ]]; then - platform_name='windows' -fi - -if [[ "$platform_name" == "unknown" ]]; then - echo "platform is" $platform_name - exit -fi - -echo "source_version = " $source_version -echo "platform_name = " $platform_name -echo "arch_name = " $arch_name -generateArgs $platform_name - -# Configure git -git config --global core.autocrlf false -git config --global core.filemode false -git config --global branch.autosetuprebase always -cd chromium - -# Grab Chromium's custom build tools, if they aren't already installed -# (On Windows, they are installed before this Python script is run) -if ! [ -d "depot_tools" ] -then - git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git -fi - -# Put depot_tools on the path so we can properly run the fetch command -export PATH="$PATH:${HOME}/chromium/depot_tools" -echo ${HOME}/chromium/depot_tools - -# Fetch the Chromium source code - -if [ -d 'chromium' ]; then - echo "chromium src aready exists, please delete it and retry..." - exit -fi - -mkdir -p chromium -cd chromium -pwd - -# Build Linux deps -echo "fetching chromium..." -fetch chromium - - -# Build Linux deps - -cd src -if [[ arch_name -eq "arm64" ]]; then - ./build/linux/sysroot_scripts/install-sysroot.py --arch=$arch_name -fi - -if [[ platform_name -eq "linux" ]]; then - ./build/install-build-deps.sh -fi - - -# Set to "arm" to build for ARM on Linux -echo 'Building Chromium ' $source_version ' for ' $arch_name - -# Sync the codebase to the correct version, syncing master first -# to ensure that we actually have all the versions we may refer to -echo 'Syncing source code' - - -git checkout -f master -git fetch -f origin -gclient sync --with_branch_heads --with_tags --jobs 16 -git checkout $source_version -gclient sync --with_branch_heads --with_tags --jobs 16 -gclient runhooks -echo "current_folder :" $current_folder - -platform_build_args=$current_folder'/args.gn' -#platform_build_args=$current_folder/chromium/build_chromium/$platform_name/args.gn - -outputDir='headless' -mkdir -p 'out/headless' - -echo "platform_build_args :" $platform_build_args - -cp $platform_build_args 'out/headless/args.gn' -echo "platform_build_args :" $platform_build_args -echo 'target_cpu = '\"$arch_name\" >> 'out/headless/args.gn' - -gn gen out/headless - -autoninja -C out/headless headless_shell - -if [[ ($platform_name != "Windows" && $arch_name != 'arm64') ]]; then - echo 'Optimizing headless_shell' - mv out/headless/headless_shell out/headless/headless_shell_raw - strip -o out/headless/headless_shell out/headless/headless_shell_raw -fi diff --git a/dashboards-reports/server/backend/opensearch-reports-plugin.ts b/dashboards-reports/server/backend/opensearch-reports-plugin.ts deleted file mode 100644 index 5c0c943e..00000000 --- a/dashboards-reports/server/backend/opensearch-reports-plugin.ts +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { OPENSEARCH_REPORTS_API } from '../../common'; - -export default function (Client: any, config: any, components: any) { - const clientAction = components.clientAction.factory; - - Client.prototype.opensearch_reports = components.clientAction.namespaceFactory(); - const opensearchReports = Client.prototype.opensearch_reports.prototype; - - /** - * report related APIs - */ - opensearchReports.createReport = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.ON_DEMAND_REPORT}`, - }, - method: 'PUT', - needBody: true, - }); - - opensearchReports.createReportFromDefinition = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.ON_DEMAND_REPORT}/<%=reportDefinitionId%>`, - req: { - reportDefinitionId: { - type: 'string', - required: true, - }, - }, - }, - method: 'POST', - needBody: true, - }); - - opensearchReports.updateReportInstanceStatus = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.REPORT_INSTANCE}/<%=reportInstanceId%>`, - req: { - reportInstanceId: { - type: 'string', - required: true, - }, - }, - }, - method: 'POST', - needBody: true, - }); - - opensearchReports.getReportById = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.REPORT_INSTANCE}/<%=reportInstanceId%>`, - req: { - reportInstanceId: { - type: 'string', - required: true, - }, - }, - }, - method: 'GET', - }); - - opensearchReports.getReports = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.LIST_REPORT_INSTANCES}`, - params: { - fromIndex: { - type: 'number', - }, - maxItems: { - type: 'number', - }, - }, - }, - method: 'GET', - }); - - /** - * report definition related APIs - */ - opensearchReports.createReportDefinition = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.REPORT_DEFINITION}`, - }, - method: 'POST', - needBody: true, - }); - - opensearchReports.updateReportDefinitionById = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.REPORT_DEFINITION}/<%=reportDefinitionId%>`, - req: { - reportDefinitionId: { - type: 'string', - required: true, - }, - }, - }, - method: 'PUT', - needBody: true, - }); - - opensearchReports.getReportDefinitionById = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.REPORT_DEFINITION}/<%=reportDefinitionId%>`, - req: { - reportDefinitionId: { - type: 'string', - required: true, - }, - }, - }, - method: 'GET', - }); - - opensearchReports.getReportDefinitions = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.LIST_REPORT_DEFINITIONS}`, - params: { - fromIndex: { - type: 'number', - }, - maxItems: { - type: 'number', - }, - }, - }, - method: 'GET', - }); - - opensearchReports.deleteReportDefinitionById = clientAction({ - url: { - fmt: `${OPENSEARCH_REPORTS_API.REPORT_DEFINITION}/<%=reportDefinitionId%>`, - req: { - reportDefinitionId: { - type: 'string', - required: true, - }, - }, - }, - method: 'DELETE', - }); -} diff --git a/dashboards-reports/server/clusters/notificationsPlugin.ts b/dashboards-reports/server/clusters/notificationsPlugin.ts deleted file mode 100644 index 4f48cb7d..00000000 --- a/dashboards-reports/server/clusters/notificationsPlugin.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { NOTIFICATIONS_API } from '../../common'; - -export function NotificationsPlugin(Client: any, config: any, components: any) { - const clientAction = components.clientAction.factory; - - Client.prototype.notifications = components.clientAction.namespaceFactory(); - const notifications = Client.prototype.notifications.prototype; - - notifications.getConfigs = clientAction({ - url: { - fmt: NOTIFICATIONS_API.CONFIGS, - }, - method: 'GET', - }); - - notifications.getEventById = clientAction({ - url: { - fmt: `${NOTIFICATIONS_API.EVENTS}/<%=eventId%>`, - req: { - eventId: { - type: 'string', - required: true, - }, - }, - }, - method: 'GET', - }); - - notifications.sendTestMessage = clientAction({ - url: { - fmt: `${NOTIFICATIONS_API.TEST_MESSAGE}/<%=configId%>`, - req: { - configId: { - type: 'string', - required: true, - }, - }, - }, - method: 'GET', - }); -} diff --git a/dashboards-reports/server/config/config.ts b/dashboards-reports/server/config/config.ts deleted file mode 100644 index e77433d0..00000000 --- a/dashboards-reports/server/config/config.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - CoreSetup, - Logger, - PluginInitializerContext, -} from '../../../../src/core/server'; -import { ReportingConfigType } from './schema'; -import { get } from 'lodash'; -import { first, map } from 'rxjs/operators'; -import { createConfig$ } from './createConfig'; - -interface Config { - get(key1: Key1): BaseType[Key1]; - get( - key1: Key1, - key2: Key2 - ): BaseType[Key1][Key2]; -} - -interface OsdServerConfigType { - server: { - basePath: string; - host: string; - name: string; - port: number; - protocol: string; - }; -} - -export interface ReportingConfig extends Config { - osdConfig: Config; -} - -export const buildConfig = async ( - initContext: PluginInitializerContext, - core: CoreSetup, - logger: Logger -): Promise => { - const config$ = initContext.config.create(); - const serverInfo = core.http.getServerInfo(); - const osdConfig = { - server: { - basePath: core.http.basePath.serverBasePath, - host: serverInfo.hostname, - name: serverInfo.name, - port: serverInfo.port, - protocol: serverInfo.protocol, - }, - }; - - const reportingConfig$ = createConfig$(core, config$, logger); - const reportingConfig = await reportingConfig$.pipe(first()).toPromise(); - return { - get: (...keys: string[]) => get(reportingConfig, keys.join('.'), null), - osdConfig: { - get: (...keys: string[]) => get(osdConfig, keys.join('.'), null), - }, - }; -}; diff --git a/dashboards-reports/server/config/createConfig.ts b/dashboards-reports/server/config/createConfig.ts deleted file mode 100644 index db9efbe5..00000000 --- a/dashboards-reports/server/config/createConfig.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { CoreSetup, Logger } from '../../../../src/core/server'; - -import { ReportingConfigType } from './schema'; - -/* - * Set up dynamic config defaults - */ -export function createConfig$( - core: CoreSetup, - config$: Observable, - logger: Logger -) { - return config$.pipe( - map((config) => { - const { osd_server: reportingServer } = config; - const serverInfo = core.http.getServerInfo(); - // osd_server.hostname, default to server.host - const osdServerHostname = reportingServer.hostname - ? reportingServer.hostname - : serverInfo.hostname; - - // osd_server.port, default to server.port - const osdServerPort = reportingServer.port - ? reportingServer.port - : serverInfo.port; - // osd_server.protocol, default to server.protocol - const osdServerProtocol = reportingServer.protocol - ? reportingServer.protocol - : serverInfo.protocol; - return { - ...config, - osd_server: { - hostname: osdServerHostname, - port: osdServerPort, - protocol: osdServerProtocol, - }, - }; - }) - ); -} diff --git a/dashboards-reports/server/config/index.ts b/dashboards-reports/server/config/index.ts deleted file mode 100644 index 639a496c..00000000 --- a/dashboards-reports/server/config/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { PluginConfigDescriptor } from '../../../../src/core/server'; -import { ConfigSchema, ReportingConfigType } from './schema'; -export { buildConfig } from './config'; -export { ConfigSchema, ReportingConfigType }; - -export const config: PluginConfigDescriptor = { - schema: ConfigSchema, -}; diff --git a/dashboards-reports/server/config/schema.ts b/dashboards-reports/server/config/schema.ts deleted file mode 100644 index ac7abb38..00000000 --- a/dashboards-reports/server/config/schema.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { schema, TypeOf } from '@osd/config-schema'; - -const OsdServerSchema = schema.object({ - hostname: schema.maybe( - schema.string({ - validate(value) { - if (value === '0') { - return 'must not be "0" for the headless browser to correctly resolve the host'; - } - }, - hostname: true, - }) - ), - port: schema.maybe(schema.number()), - protocol: schema.maybe( - schema.string({ - validate(value) { - if (!/^https?$/.test(value)) { - return 'must be "http" or "https"'; - } - }, - }) - ), -}); // default values are all dynamic in createConfig$ - -export const ConfigSchema = schema.object({ - osd_server: OsdServerSchema, -}); - -export type ReportingConfigType = TypeOf; diff --git a/dashboards-reports/server/index.ts b/dashboards-reports/server/index.ts deleted file mode 100644 index 1e64b68f..00000000 --- a/dashboards-reports/server/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { PluginInitializerContext } from '../../../src/core/server'; -import { ReportingConfigType } from './config'; -import { ReportsDashboardsPlugin } from './plugin'; - -export { config } from './config'; -export { ReportingConfig } from './config/config'; -export { ReportsDashboardsPlugin as Plugin }; - -// This exports static code and TypeScript types, -// as well as, OpenSearch Dashboards Platform `plugin()` initializer. -export function plugin( - initializerContext: PluginInitializerContext -) { - return new ReportsDashboardsPlugin(initializerContext); -} - -export { - ReportsDashboardsPluginSetup, - ReportsDashboardsPluginStart, -} from './types'; diff --git a/dashboards-reports/server/model/backendModel.ts b/dashboards-reports/server/model/backendModel.ts deleted file mode 100644 index 2967f546..00000000 --- a/dashboards-reports/server/model/backendModel.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - FORMAT, - REPORT_STATE, - REPORT_TYPE, - TRIGGER_TYPE, -} from '../routes/utils/constants'; - -export type BackendReportInstanceType = { - id: string; - lastUpdatedTimeMs?: number; - createdTimeMs?: number; - beginTimeMs: number; - endTimeMs: number; - access?: string[]; - tenant?: string; - status: BACKEND_REPORT_STATE; - statusText?: string; - inContextDownloadUrlPath?: string; - reportDefinitionDetails: BackendReportDefinitionDetailsType; -}; - -export type BackendReportDefinitionType = { - name: string; - isEnabled: boolean; - source: { - description: string; - type: BACKEND_REPORT_SOURCE; - id: string; - origin: string; - }; - format: { - duration: string; - fileFormat: BACKEND_REPORT_FORMAT; - limit?: number; - header?: string; - footer?: string; - }; - trigger: { - triggerType: BACKEND_TRIGGER_TYPE; - schedule?: CronType | IntervalType; - }; - delivery?: DeliveryType; -}; - -export type BackendReportDefinitionDetailsType = { - id?: string; - lastUpdatedTimeMs: number; - createdTimeMs: number; - access?: string[]; - reportDefinition: BackendReportDefinitionType; -}; - -export type CronType = { - cron: { - expression: string; - timezone: string; - }; -}; - -export type IntervalType = { - interval: { - start_time: number; - period: number; - unit: string; - }; -}; - -export type DeliveryType = { - configIds: string[]; - title: string; - textDescription: string; - htmlDescription?: string; -}; - -export enum BACKEND_DELIVERY_FORMAT { - linkOnly = 'LinkOnly', - attachment = 'Attachment', - embedded = 'Embedded', -} - -export enum BACKEND_REPORT_SOURCE { - dashboard = 'Dashboard', - visualization = 'Visualization', - savedSearch = 'SavedSearch', - notebook = 'Notebook' -} - -export enum BACKEND_REPORT_STATE { - scheduled = 'Scheduled', - executing = 'Executing', - success = 'Success', - failed = 'Failed', -} - -export enum BACKEND_REPORT_FORMAT { - pdf = 'Pdf', - png = 'Png', - csv = 'Csv', -} - -export enum BACKEND_TRIGGER_TYPE { - download = 'Download', - onDemand = 'OnDemand', - cronSchedule = 'CronSchedule', - intervalSchedule = 'IntervalSchedule', -} - -export const REPORT_STATE_DICT = { - [REPORT_STATE.pending]: BACKEND_REPORT_STATE.executing, - [REPORT_STATE.error]: BACKEND_REPORT_STATE.failed, - [REPORT_STATE.shared]: BACKEND_REPORT_STATE.success, - [REPORT_STATE.created]: BACKEND_REPORT_STATE.success, -}; - -export const REPORT_SOURCE_DICT = { - [REPORT_TYPE.dashboard]: BACKEND_REPORT_SOURCE.dashboard, - [REPORT_TYPE.visualization]: BACKEND_REPORT_SOURCE.visualization, - [REPORT_TYPE.savedSearch]: BACKEND_REPORT_SOURCE.savedSearch, - [REPORT_TYPE.notebook]: BACKEND_REPORT_SOURCE.notebook -}; - -export const REPORT_FORMAT_DICT = { - [FORMAT.csv]: BACKEND_REPORT_FORMAT.csv, - [FORMAT.pdf]: BACKEND_REPORT_FORMAT.pdf, - [FORMAT.png]: BACKEND_REPORT_FORMAT.png, -}; - -export const TRIGGER_TYPE_DICT = { - [TRIGGER_TYPE.schedule]: [ - BACKEND_TRIGGER_TYPE.cronSchedule, - BACKEND_TRIGGER_TYPE.intervalSchedule, - ], - [TRIGGER_TYPE.onDemand]: [ - BACKEND_TRIGGER_TYPE.onDemand, - BACKEND_TRIGGER_TYPE.download, - ], -}; - -export const URL_PREFIX_DICT = { - [BACKEND_REPORT_SOURCE.dashboard]: '/app/dashboards#/view/', - [BACKEND_REPORT_SOURCE.savedSearch]: '/app/discover#/view/', - [BACKEND_REPORT_SOURCE.visualization]: '/app/visualize#/edit/', - [BACKEND_REPORT_SOURCE.notebook]: '/app/notebooks-dashboards?view=output_only#/' -}; diff --git a/dashboards-reports/server/model/index.ts b/dashboards-reports/server/model/index.ts deleted file mode 100644 index 73ffae07..00000000 --- a/dashboards-reports/server/model/index.ts +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { schema, TypeOf } from '@osd/config-schema'; -import { - isValidRelativeUrl, - regexDuration, - regexEmailAddress, - regexReportName, -} from '../utils/validationHelper'; -import { isValidCron } from 'cron-validator'; -import { - REPORT_TYPE, - TRIGGER_TYPE, - FORMAT, - SCHEDULE_TYPE, - REPORT_STATE, - REPORT_DEFINITION_STATUS, - DELIVERY_TYPE, - DEFAULT_MAX_SIZE, -} from '../routes/utils/constants'; - -export const dataReportSchema = schema.object({ - // Need this to build the links in email - origin: schema.uri(), //e.g. https://xxxxx.com - base_url: schema.string({ - validate(value) { - if (!isValidRelativeUrl(value)) { - return `invalid relative url: ${value}`; - } - }, - minLength: 1, - }), - saved_search_id: schema.string(), - //ISO duration format. 'PT10M' means 10 min - time_duration: schema.string({ - validate(value) { - if (!regexDuration.test(value)) { - return `invalid time duration: ${value}`; - } - }, - }), - //TODO: future support schema.literal('xlsx') - report_format: schema.oneOf([schema.literal(FORMAT.csv)]), - limit: schema.number({ defaultValue: DEFAULT_MAX_SIZE, min: 0 }), - excel: schema.boolean({ defaultValue: true }), -}); - -export const visualReportSchema = schema.object({ - // Need this to build the links in email - origin: schema.uri(), //e.g. https://xxxxx.com - base_url: schema.string({ - validate(value) { - if (!isValidRelativeUrl(value)) { - return `invalid relative url: ${value}`; - } - }, - minLength: 1, - }), - window_width: schema.number({ defaultValue: 1600, min: 0 }), - window_height: schema.number({ defaultValue: 800, min: 0 }), - report_format: schema.oneOf([ - schema.literal(FORMAT.pdf), - schema.literal(FORMAT.png), - ]), - header: schema.maybe(schema.string()), - footer: schema.maybe(schema.string()), - time_duration: schema.string({ - validate(value) { - if (!regexDuration.test(value)) { - return `invalid time duration: ${value}`; - } - }, - }), -}); - -export const intervalSchema = schema.object({ - interval: schema.object({ - period: schema.number({ min: 0 }), - // Refer to job scheduler SPI https://github.com/opensearch-project/job-scheduler/blob/main/spi/src/main/java/org/opensearch/jobscheduler/spi/schedule/IntervalSchedule.java - unit: schema.oneOf([ - schema.literal('MINUTES'), - schema.literal('HOURS'), - schema.literal('DAYS'), - // Job scheduler in reporting OpenSearch plugin always saves as following format - schema.literal('Minutes'), - schema.literal('Hours'), - schema.literal('Days'), - ]), - // timestamp - start_time: schema.number(), - }), -}); - -export const cronSchema = schema.object({ - cron: schema.object({ - expression: schema.string({ - validate(value) { - if (!isValidCron(value)) { - return `invalid cron expression: ${value}`; - } - }, - }), - //TODO: add more validation once we add full support of timezone - timezone: schema.string(), - }), -}); - -export const scheduleSchema = schema.object({ - schedule_type: schema.oneOf([ - /* - TODO: Future Date option will be added in the future. - Currently @osd/config-schema has no support for more than 2 conditions, keep an eye on library update - */ - schema.literal(SCHEDULE_TYPE.recurring), - schema.literal(SCHEDULE_TYPE.cron), - ]), - schedule: schema.conditional( - schema.siblingRef('schedule_type'), - SCHEDULE_TYPE.recurring, - intervalSchema, - cronSchema - ), - enabled_time: schema.number(), - enabled: schema.boolean(), -}); - -export const opensearchDashboardsUserSchema = schema.object({ - opensearch_dashboards_recipients: schema.arrayOf(schema.string()), -}); - -export const channelSchema = schema.object({ - recipients: schema.arrayOf( - schema.string({ - validate(value) { - if (!regexEmailAddress.test(value)) { - return `invalid email address ${value}`; - } - }, - }), - { minSize: 1 } - ), - title: schema.string(), - textDescription: schema.string(), - htmlDescription: schema.maybe(schema.string()), - configIds: schema.maybe(schema.arrayOf(schema.string())), -}); - -export const triggerSchema = schema.object({ - trigger_type: schema.oneOf([ - /* - TODO: Alerting will be added in the future. - Currently @osd/config-schema has no support for more than 2 conditions, keep an eye on library update - */ - schema.literal(TRIGGER_TYPE.schedule), - schema.literal(TRIGGER_TYPE.onDemand), - ]), - trigger_params: schema.conditional( - schema.siblingRef('trigger_type'), - TRIGGER_TYPE.onDemand, - schema.never(), - scheduleSchema - ), -}); - -export const deliverySchema = schema.object({ - configIds: schema.arrayOf(schema.string()), - title: schema.string(), - textDescription: schema.string(), - htmlDescription: schema.string() -}); - -export const reportParamsSchema = schema.object({ - report_name: schema.string({ - validate(value) { - if (!regexReportName.test(value)) { - return `invald report name ${value}.\nMust be non-empty, allow a-z, A-Z, 0-9, (), [], ',' - and _ and spaces`; - } - }, - }), - report_source: schema.oneOf([ - schema.literal(REPORT_TYPE.dashboard), - schema.literal(REPORT_TYPE.visualization), - schema.literal(REPORT_TYPE.savedSearch), - schema.literal(REPORT_TYPE.notebook) - ]), - description: schema.string(), - core_params: schema.conditional( - schema.siblingRef('report_source'), - REPORT_TYPE.savedSearch, - dataReportSchema, - visualReportSchema - ), -}); - -export const reportDefinitionSchema = schema.object({ - report_params: reportParamsSchema, - delivery: deliverySchema, - trigger: triggerSchema, - time_created: schema.maybe(schema.number()), - last_updated: schema.maybe(schema.number()), - status: schema.maybe( - schema.oneOf([ - schema.literal(REPORT_DEFINITION_STATUS.active), - schema.literal(REPORT_DEFINITION_STATUS.disabled), - ]) - ), -}); - -export const reportSchema = schema.object({ - query_url: schema.string({ - validate(value) { - if (!isValidRelativeUrl(value)) { - return `invalid relative url: ${value}`; - } - }, - minLength: 1, - }), - time_from: schema.number(), - time_to: schema.number(), - report_definition: reportDefinitionSchema, - - time_created: schema.maybe(schema.number()), - last_updated: schema.maybe(schema.number()), - state: schema.maybe( - schema.oneOf([ - schema.literal(REPORT_STATE.created), - schema.literal(REPORT_STATE.error), - schema.literal(REPORT_STATE.pending), - schema.literal(REPORT_STATE.shared), - ]) - ), -}); - -export type ReportDefinitionSchemaType = TypeOf; -export type ReportSchemaType = TypeOf; -export type DataReportSchemaType = TypeOf; -export type VisualReportSchemaType = TypeOf; -export type ChannelSchemaType = TypeOf; -export type OpenSearchDashboardsUserSchemaType = TypeOf; -export type DeliverySchemaType = TypeOf; -export type TriggerSchemaType = TypeOf; -export type ScheduleSchemaType = TypeOf; -export type ReportParamsSchemaType = TypeOf; diff --git a/dashboards-reports/server/plugin.ts b/dashboards-reports/server/plugin.ts deleted file mode 100644 index dd461296..00000000 --- a/dashboards-reports/server/plugin.ts +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - PluginInitializerContext, - CoreSetup, - CoreStart, - Plugin, - Logger, - ILegacyClusterClient, -} from '../../../src/core/server'; -import { Semaphore, SemaphoreInterface, withTimeout } from 'async-mutex'; -import opensearchReportsPlugin from './backend/opensearch-reports-plugin'; -import { - ReportsDashboardsPluginSetup, - ReportsDashboardsPluginStart, -} from './types'; -import registerRoutes from './routes'; -import { NotificationsPlugin } from './clusters/notificationsPlugin'; -import { buildConfig, ReportingConfigType } from './config'; -import { ReportingConfig } from './config/config'; - -export interface ReportsPluginRequestContext { - logger: Logger; - opensearchClient: ILegacyClusterClient; -} -//@ts-ignore -declare module 'kibana/server' { - interface RequestHandlerContext { - reports_plugin: ReportsPluginRequestContext; - } -} - -export class ReportsDashboardsPlugin - implements - Plugin { - private readonly logger: Logger; - private readonly semaphore: SemaphoreInterface; - private readonly initializerContext: PluginInitializerContext< - ReportingConfigType - >; - private reportingConfig?: ReportingConfig; - - constructor(context: PluginInitializerContext) { - this.logger = context.logger.get(); - this.initializerContext = context; - const timeoutError = new Error('Server busy'); - timeoutError.statusCode = 503; - this.semaphore = withTimeout(new Semaphore(1), 300000, timeoutError); - } - - public async setup(core: CoreSetup) { - this.logger.debug('reports-dashboards: Setup'); - - try { - const config = await buildConfig( - this.initializerContext, - core, - this.logger - ); - this.reportingConfig = config; - this.logger.debug('Setup complete'); - } catch (error) { - this.logger.error( - `Error in Reporting setup, reporting may not function properly` - ); - this.logger.error(error); - } - - if (!this.reportingConfig) { - throw new Error('Reporting Config is not initialized'); - } - - const router = core.http.createRouter(); - // Deprecated API. Switch to the new opensearch client as soon as https://github.com/elastic/kibana/issues/35508 done. - const opensearchReportsClient: ILegacyClusterClient = core.opensearch.legacy.createClient( - 'opensearch_reports', - { - plugins: [opensearchReportsPlugin, NotificationsPlugin], - } - ); - - const notificationsClient: ILegacyClusterClient = core.opensearch.legacy.createClient( - 'opensearch_notifications', - { - plugins: [NotificationsPlugin], - } - ); - - // Register server side APIs - registerRoutes(router, this.reportingConfig); - - // put logger into route handler context, so that we don't need to pass through parameters - core.http.registerRouteHandlerContext( - //@ts-ignore - 'reporting_plugin', - (context, request) => { - return { - logger: this.logger, - semaphore: this.semaphore, - opensearchReportsClient, - notificationsClient, - }; - } - ); - - return {}; - } - - public start(core: CoreStart) { - this.logger.debug('reports-dashboards: Started'); - return {}; - } - - public stop() {} -} diff --git a/dashboards-reports/server/routes/index.ts b/dashboards-reports/server/routes/index.ts deleted file mode 100644 index 51b93476..00000000 --- a/dashboards-reports/server/routes/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import registerReportRoute from './report'; -import registerReportDefinitionRoute from './reportDefinition'; -import registerReportSourceRoute from './reportSource'; -import registerMetricRoute from './metric'; -import registerNotificationRoute from './notifications'; -import { IRouter } from '../../../../src/core/server'; -import { ReportingConfig } from 'server/config/config'; - -export default function (router: IRouter, config: ReportingConfig) { - registerReportRoute(router, config); - registerReportDefinitionRoute(router, config); - registerReportSourceRoute(router); - registerMetricRoute(router); - registerNotificationRoute(router); -} diff --git a/dashboards-reports/server/routes/lib/createReport.ts b/dashboards-reports/server/routes/lib/createReport.ts deleted file mode 100644 index 57f2c5cd..00000000 --- a/dashboards-reports/server/routes/lib/createReport.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - REPORT_TYPE, - DATA_REPORT_CONFIG, - EXTRA_HEADERS, -} from '../utils/constants'; - -import { - ILegacyScopedClusterClient, - OpenSearchDashboardsRequest, - Logger, - RequestHandlerContext, -} from '../../../../../src/core/server'; -import { createSavedSearchReport } from '../utils/savedSearchReportHelper'; -import { ReportSchemaType } from '../../model'; -import { CreateReportResultType } from '../utils/types'; -import { createVisualReport } from '../utils/visual_report/visualReportHelper'; -import { saveReport } from './saveReport'; -import { SemaphoreInterface } from 'async-mutex'; -import { ReportingConfig } from 'server'; -import _ from 'lodash'; - -export const createReport = async ( - request: OpenSearchDashboardsRequest, - context: RequestHandlerContext, - report: ReportSchemaType, - config: ReportingConfig, - savedReportId?: string -): Promise => { - const isScheduledTask = false; - //@ts-ignore - const logger: Logger = context.reporting_plugin.logger; - //@ts-ignore - const semaphore: SemaphoreInterface = context.reporting_plugin.semaphore; - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - const opensearchClient = context.core.opensearch.legacy.client; - // @ts-ignore - const timezone = request.query.timezone; - // @ts-ignore - const dateFormat = - request.query.dateFormat || DATA_REPORT_CONFIG.excelDateFormat; - // @ts-ignore - const csvSeparator = request.query.csvSeparator || ','; - const protocol = config.get('osd_server', 'protocol'); - const hostname = config.get('osd_server', 'hostname'); - const port = config.get('osd_server', 'port'); - const basePath = config.osdConfig.get('server', 'basePath'); - - let createReportResult: CreateReportResultType; - let reportId; - - const { - report_definition: { report_params: reportParams }, - } = report; - const { report_source: reportSource } = reportParams; - - try { - // create new report instance and set report state to "pending" - if (savedReportId) { - reportId = savedReportId; - } else { - const opensearchResp = await saveReport(report, opensearchReportsClient); - reportId = opensearchResp.reportInstance.id; - } - // generate report - if (reportSource === REPORT_TYPE.savedSearch) { - createReportResult = await createSavedSearchReport( - report, - opensearchClient, - dateFormat, - csvSeparator, - isScheduledTask, - logger - ); - } else { - // report source can only be one of [saved search, visualization, dashboard, notebook] - // compose url - const relativeUrl = report.query_url.startsWith(basePath) - ? report.query_url - : `${basePath}${report.query_url}`; - const completeQueryUrl = `${protocol}://${hostname}:${port}${relativeUrl}`; - const extraHeaders = _.pick(request.headers, EXTRA_HEADERS); - - const [value, release] = await semaphore.acquire(); - try { - createReportResult = await createVisualReport( - reportParams, - completeQueryUrl, - logger, - extraHeaders, - timezone - ); - } finally { - release(); - } - } - // update report state to "created" - // TODO: temporarily remove the following - // if (!savedReportId) { - // await updateReportState(reportId, opensearchReportsClient, REPORT_STATE.created); - // } - } catch (error) { - // update report instance with "error" state - // TODO: save error detail and display on UI - // TODO: temporarily disable the following, will add back - // if (!savedReportId) { - // await updateReportState(reportId, opensearchReportsClient, REPORT_STATE.error); - // } - throw error; - } - - return createReportResult; -}; diff --git a/dashboards-reports/server/routes/lib/createReportDefinition.ts b/dashboards-reports/server/routes/lib/createReportDefinition.ts deleted file mode 100644 index 7e3a3301..00000000 --- a/dashboards-reports/server/routes/lib/createReportDefinition.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { ReportDefinitionSchemaType } from '../../model'; -import { - OpenSearchDashboardsRequest, - RequestHandlerContext, - ILegacyScopedClusterClient, -} from '../../../../../src/core/server'; -import { uiToBackendReportDefinition } from '../utils/converters/uiToBackend'; - -export const createReportDefinition = async ( - request: OpenSearchDashboardsRequest, - context: RequestHandlerContext, - reportDefinition: ReportDefinitionSchemaType -) => { - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - // create report definition - const reqBody = { - reportDefinition: uiToBackendReportDefinition(reportDefinition), - }; - - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.createReportDefinition', - { - body: reqBody, - } - ); - - return opensearchResp; -}; diff --git a/dashboards-reports/server/routes/lib/saveReport.ts b/dashboards-reports/server/routes/lib/saveReport.ts deleted file mode 100644 index 6a66c84c..00000000 --- a/dashboards-reports/server/routes/lib/saveReport.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { v1 as uuidv1 } from 'uuid'; -import { ReportSchemaType } from '../../model'; -import { BACKEND_REPORT_STATE } from '../../model/backendModel'; -import { ILegacyScopedClusterClient } from '../../../../../src/core/server'; -import { uiToBackendReportDefinition } from '../utils/converters/uiToBackend'; - -export const saveReport = async ( - report: ReportSchemaType, - opensearchReportsClient: ILegacyScopedClusterClient -) => { - const timePending = Date.now(); - const { - time_from: timeFrom, - time_to: timeTo, - query_url: queryUrl, - report_definition: reportDefinition, - } = report; - - const reqBody = { - beginTimeMs: timeFrom, - endTimeMs: timeTo, - reportDefinitionDetails: { - id: uuidv1(), - lastUpdatedTimeMs: timePending, - createdTimeMs: timePending, - reportDefinition: { - ...uiToBackendReportDefinition(reportDefinition), - trigger: { - triggerType: 'Download', // TODO: this is a corner case for in-context menu button download only - }, - }, - }, - // download from in-context menu should always pass executing state to backend - // TODO: set to success, since update report status API in temporarily unavailable, need change back to pending later - status: BACKEND_REPORT_STATE.success, - inContextDownloadUrlPath: queryUrl, - }; - - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.createReport', - { - body: reqBody, - } - ); - - return opensearchResp; -}; diff --git a/dashboards-reports/server/routes/lib/updateReportDefinition.ts b/dashboards-reports/server/routes/lib/updateReportDefinition.ts deleted file mode 100644 index 375909f1..00000000 --- a/dashboards-reports/server/routes/lib/updateReportDefinition.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { ReportDefinitionSchemaType } from '../../model'; -import { - ILegacyScopedClusterClient, - OpenSearchDashboardsRequest, - RequestHandlerContext, -} from '../../../../../src/core/server'; -import { uiToBackendReportDefinition } from '../utils/converters/uiToBackend'; - -export const updateReportDefinition = async ( - request: OpenSearchDashboardsRequest, - context: RequestHandlerContext, - reportDefinition: ReportDefinitionSchemaType -) => { - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - // @ts-ignore - const reportDefinitionId = request.params.reportDefinitionId; - // create report definition - const reqBody = { - reportDefinitionId: reportDefinitionId, - reportDefinition: uiToBackendReportDefinition(reportDefinition), - }; - - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.updateReportDefinitionById', - { - reportDefinitionId: reportDefinitionId, - body: reqBody, - } - ); - - return opensearchResp; -}; diff --git a/dashboards-reports/server/routes/lib/updateReportState.ts b/dashboards-reports/server/routes/lib/updateReportState.ts deleted file mode 100644 index 02366992..00000000 --- a/dashboards-reports/server/routes/lib/updateReportState.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - ILegacyClusterClient, - ILegacyScopedClusterClient, -} from '../../../../../src/core/server'; -import { REPORT_STATE } from '../utils/constants'; -import { getBackendReportState } from '../utils/converters/uiToBackend'; - -// The only thing can be updated of a report instance is its "state" -export const updateReportState = async ( - reportId: string, - opensearchReportsClient: ILegacyClusterClient | ILegacyScopedClusterClient, - state: REPORT_STATE -) => { - //Build request body - const reqBody = { - reportInstanceId: reportId, - status: getBackendReportState(state), - }; - - const opensearchResp = await opensearchReportsClient.callAsInternalUser( - // @ts-ignore - 'opensearch_reports.updateReportInstanceStatus', - { - reportInstanceId: reportId, - body: reqBody, - } - ); - - return opensearchResp; -}; diff --git a/dashboards-reports/server/routes/metric.ts b/dashboards-reports/server/routes/metric.ts deleted file mode 100644 index a3bbe80a..00000000 --- a/dashboards-reports/server/routes/metric.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - IOpenSearchDashboardsResponse, - IRouter, - ResponseError, -} from '../../../../src/core/server'; -import { API_PREFIX } from '../../common'; -import { errorResponse } from './utils/helpers'; -import { getMetrics } from './utils/metricHelper'; - -export default function (router: IRouter) { - router.get( - { - path: `${API_PREFIX}/stats`, - validate: false, - }, - async ( - context, - request, - response - ): Promise> => { - //@ts-ignore - const logger: Logger = context.reporting_plugin.logger; - try { - const metrics = getMetrics(); - return response.ok({ - body: metrics, - }); - } catch (error) { - logger.error(`failed during query reporting stats: ${error}`); - return errorResponse(response, error); - } - } - ); -} diff --git a/dashboards-reports/server/routes/notifications.ts b/dashboards-reports/server/routes/notifications.ts deleted file mode 100644 index 4dcdb47f..00000000 --- a/dashboards-reports/server/routes/notifications.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { schema } from '@osd/config-schema'; -import { REPORTING_NOTIFICATIONS_DASHBOARDS_API } from '../../common'; -import { - IRouter, - IOpenSearchDashboardsResponse, - ResponseError, - Logger, - ILegacyScopedClusterClient, -} from '../../../../src/core/server'; -import { joinRequestParams } from './utils/helpers'; - -export default function(router: IRouter) { - // Get all configs from Notifications - router.get( - { - path: REPORTING_NOTIFICATIONS_DASHBOARDS_API.GET_CONFIGS, - validate: { - query: schema.object({ - from_index: schema.number(), - max_items: schema.number(), - query: schema.maybe(schema.string()), - config_type: schema.oneOf([ - schema.arrayOf(schema.string()), - schema.string() - ]), - feature_list: schema.maybe( - schema.oneOf([schema.arrayOf(schema.string()), schema.string()]) - ), - is_enabled: schema.maybe(schema.boolean()), - sort_field: schema.string(), - sort_order: schema.string(), - config_id_list: schema.maybe( - schema.oneOf([schema.arrayOf(schema.string()), schema.string()]) - ), - }) - } - }, - async (context, request, response) => { - const config_type = joinRequestParams(request.query.config_type); - const feature_list = joinRequestParams(request.query.feature_list); - const config_id_list = joinRequestParams(request.query.config_id_list); - const query = request.query.query; - // @ts-ignore - const client: ILegacyScopedClusterClient = context.reporting_plugin.notificationsClient.asScoped( - request - ); - try { - const resp = await client.callAsCurrentUser( - 'notifications.getConfigs', - { - from_index: request.query.from_index, - max_items: request.query.max_items, - is_enabled: request.query.is_enabled, - sort_field: request.query.sort_field, - sort_order: request.query.sort_order, - config_type, - ...(feature_list && { feature_list }), - ...(query && { query }), - ...(config_id_list && { config_id_list }), - } - ); - return response.ok({ body: resp }); - } catch (error) { - return response.custom({ - statusCode: error.statusCode || 500, - body: error.message, - }); - } - } - ); - - // get event by id - router.get( - { - path: `${REPORTING_NOTIFICATIONS_DASHBOARDS_API.GET_EVENT}/{eventId}`, - validate: { - params: schema.object({ - eventId: schema.string(), - }), - }, - }, - async (context, request, response) => { - // @ts-ignore - const client: ILegacyScopedClusterClient = context.reporting_plugin.notificationsClient.asScoped( - request - ); - try { - const resp = await client.callAsCurrentUser( - 'notifications.getEventById', - { eventId: request.params.eventId } - ); - return response.ok({ body: resp }); - } catch (error) { - return response.custom({ - statusCode: error.statusCode || 500, - body: error.message, - }); - } - } - ) - - // Send test message - router.get( - { - path: `${REPORTING_NOTIFICATIONS_DASHBOARDS_API.SEND_TEST_MESSAGE}/{configId}`, - validate: { - params: schema.object({ - configId: schema.string(), - }), - query: schema.object({ - feature: schema.string(), - }), - }, - }, - async (context, request, response) => { - // @ts-ignore - const client: ILegacyScopedClusterClient = context.reporting_plugin.notificationsClient.asScoped( - request - ); - try { - const resp = await client.callAsCurrentUser( - 'notifications.sendTestMessage', - { - configId: request.params.configId, - feature: request.query.feature, - } - ); - return response.ok({ body: resp }); - } catch (error) { - return response.custom({ - statusCode: error.statusCode || 500, - body: error.message, - }); - } - } - ); -} \ No newline at end of file diff --git a/dashboards-reports/server/routes/report.ts b/dashboards-reports/server/routes/report.ts deleted file mode 100644 index 4c443a57..00000000 --- a/dashboards-reports/server/routes/report.ts +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { schema } from '@osd/config-schema'; -import { - IRouter, - IOpenSearchDashboardsResponse, - ResponseError, - Logger, - ILegacyScopedClusterClient, -} from '../../../../src/core/server'; -import { API_PREFIX } from '../../common'; -import { createReport } from './lib/createReport'; -import { checkErrorType, errorResponse } from './utils/helpers'; -import { DEFAULT_MAX_SIZE, DELIVERY_TYPE } from './utils/constants'; -import { - backendToUiReport, - backendToUiReportsList, -} from './utils/converters/backendToUi'; -import { addToMetric } from './utils/metricHelper'; -import { validateReport } from '../../server/utils/validationHelper'; -import { ReportingConfig } from 'server'; - -export default function (router: IRouter, config: ReportingConfig) { - const protocol = config.get('osd_server', 'protocol'); - const hostname = config.get('osd_server', 'hostname'); - const port = config.get('osd_server', 'port'); - const basePath = config.osdConfig.get('server', 'basePath'); - // generate report (with provided metadata) - router.post( - { - path: `${API_PREFIX}/generateReport`, - validate: { - body: schema.any(), - query: schema.object({ - timezone: schema.maybe(schema.string()), - dateFormat: schema.maybe(schema.string()), - csvSeparator: schema.maybe(schema.string()), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report', 'create', 'count'); - //@ts-ignore - const logger: Logger = context.reporting_plugin.logger; - let report = request.body; - // input validation - try { - report.report_definition.report_params.core_params.origin = `${protocol}://${hostname}:${port}${basePath}`; - report = await validateReport( - context.core.opensearch.legacy.client, - report, - basePath - ); - } catch (error) { - logger.error(`Failed input validation for create report ${error}`); - addToMetric('report', 'create', 'user_error'); - return response.badRequest({ body: error }); - } - - try { - const reportData = await createReport(request, context, report, config); - - // if not deliver to user himself , no need to send actual file data to client - const delivery = report.report_definition.delivery; - addToMetric('report', 'create', 'count', report); - return response.ok({ - body: { - data: reportData.dataUrl, - filename: reportData.fileName, - }, - }); - } catch (error) { - // TODO: better error handling for delivery and stages in generating report, pass logger to deeper level - logger.error(`Failed to generate report: ${error}`); - logger.error(error); - addToMetric('report', 'create', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); - - // generate report from report id - router.get( - { - path: `${API_PREFIX}/generateReport/{reportId}`, - validate: { - params: schema.object({ - reportId: schema.string(), - }), - query: schema.object({ - timezone: schema.string(), - dateFormat: schema.string(), - csvSeparator: schema.string(), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report', 'download', 'count'); - //@ts-ignore - const logger: Logger = context.reporting_plugin.logger; - try { - const savedReportId = request.params.reportId; - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - // get report - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.getReportById', - { - reportInstanceId: savedReportId, - } - ); - // convert report to use UI model - const report = backendToUiReport( - opensearchResp.reportInstance, - basePath - ); - // generate report - const reportData = await createReport( - request, - context, - report, - config, - savedReportId - ); - addToMetric('report', 'download', 'count', report); - - return response.ok({ - body: { - data: reportData.dataUrl, - filename: reportData.fileName, - }, - }); - } catch (error) { - logger.error(`Failed to generate report by id: ${error}`); - logger.error(error); - addToMetric('report', 'download', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); - - // create report from existing report definition - router.post( - { - path: `${API_PREFIX}/generateReport/{reportDefinitionId}`, - validate: { - params: schema.object({ - reportDefinitionId: schema.string(), - }), - query: schema.object({ - timezone: schema.string(), - dateFormat: schema.string(), - csvSeparator: schema.string(), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report', 'create_from_definition', 'count'); - //@ts-ignore - const logger: Logger = context.reporting_plugin.logger; - const reportDefinitionId = request.params.reportDefinitionId; - let report: any; - try { - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - // call OpenSearch API to create report from definition - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.createReportFromDefinition', - { - reportDefinitionId: reportDefinitionId, - body: { - reportDefinitionId: reportDefinitionId, - }, - } - ); - const reportId = opensearchResp.reportInstance.id; - // convert report to use UI model - const report = backendToUiReport( - opensearchResp.reportInstance, - basePath - ); - // generate report - const reportData = await createReport( - request, - context, - report, - config, - reportId - ); - addToMetric('report', 'create_from_definition', 'count', report); - - return response.ok({ - body: { - data: reportData.dataUrl, - filename: reportData.fileName, - }, - }); - } catch (error) { - logger.error( - `Failed to generate report from reportDefinition id ${reportDefinitionId} : ${error}` - ); - logger.error(error); - addToMetric('report', 'create_from_definition', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); - - // get all reports details - router.get( - { - path: `${API_PREFIX}/reports`, - validate: { - query: schema.object({ - fromIndex: schema.maybe(schema.number()), - maxItems: schema.maybe(schema.number()), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report', 'list', 'count'); - const { fromIndex, maxItems } = request.query as { - fromIndex: number; - maxItems: number; - }; - - try { - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.getReports', - { - fromIndex: fromIndex, - maxItems: maxItems || DEFAULT_MAX_SIZE, - } - ); - - const reportsList = backendToUiReportsList( - opensearchResp.reportInstanceList, - basePath - ); - - return response.ok({ - body: { - data: reportsList, - }, - }); - } catch (error) { - //@ts-ignore - context.reporting_plugin.logger.error( - `Failed to get reports details: ${error}` - ); - addToMetric('report', 'list', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); - - // get single report details by id - router.get( - { - path: `${API_PREFIX}/reports/{reportId}`, - validate: { - params: schema.object({ - reportId: schema.string(), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report', 'info', 'count'); - try { - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.getReportById', - { - reportInstanceId: request.params.reportId, - } - ); - - const report = backendToUiReport( - opensearchResp.reportInstance, - basePath - ); - - return response.ok({ - body: report, - }); - } catch (error) { - //@ts-ignore - context.reporting_plugin.logger.error( - `Failed to get single report details: ${error}` - ); - addToMetric('report', 'info', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); -} diff --git a/dashboards-reports/server/routes/reportDefinition.ts b/dashboards-reports/server/routes/reportDefinition.ts deleted file mode 100644 index 2db35019..00000000 --- a/dashboards-reports/server/routes/reportDefinition.ts +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { schema } from '@osd/config-schema'; -import { - IRouter, - IOpenSearchDashboardsResponse, - ResponseError, - ILegacyScopedClusterClient, -} from '../../../../src/core/server'; -import { API_PREFIX } from '../../common'; -import { checkErrorType, errorResponse } from './utils/helpers'; -import { createReportDefinition } from './lib/createReportDefinition'; -import { - backendToUiReportDefinition, - backendToUiReportDefinitionsList, -} from './utils/converters/backendToUi'; -import { updateReportDefinition } from './lib/updateReportDefinition'; -import { DEFAULT_MAX_SIZE } from './utils/constants'; -import { addToMetric } from './utils/metricHelper'; -import { validateReportDefinition } from '../../server/utils/validationHelper'; -import { ReportingConfig } from 'server'; - -export default function (router: IRouter, config: ReportingConfig) { - const protocol = config.get('osd_server', 'protocol'); - const hostname = config.get('osd_server', 'hostname'); - const port = config.get('osd_server', 'port'); - const basePath = config.osdConfig.get('server', 'basePath'); - - // Create report Definition - router.post( - { - path: `${API_PREFIX}/reportDefinition`, - validate: { - body: schema.any(), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report_definition', 'create', 'count'); - let reportDefinition = request.body; - //@ts-ignore - const logger = context.reporting_plugin.logger; - // input validation - try { - reportDefinition.report_params.core_params.origin = `${protocol}://${hostname}:${port}${basePath}`; - reportDefinition = await validateReportDefinition( - context.core.opensearch.legacy.client, - reportDefinition, - basePath - ); - } catch (error) { - logger.error( - `Failed input validation for create report definition ${error}` - ); - addToMetric('report_definition', 'create', 'user_error'); - return response.badRequest({ body: error }); - } - - // save metadata - try { - const res = await createReportDefinition( - request, - context, - reportDefinition - ); - - return response.ok({ - body: { - state: 'Report definition created', - scheduler_response: res, - }, - }); - } catch (error) { - logger.error(`Failed to create report definition: ${error}`); - addToMetric('report_definition', 'create', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); - - // Update report definition by id - router.put( - { - path: `${API_PREFIX}/reportDefinitions/{reportDefinitionId}`, - validate: { - body: schema.any(), - params: schema.object({ - reportDefinitionId: schema.string(), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report_definition', 'update', 'count'); - let reportDefinition = request.body; - //@ts-ignore - const logger = context.reporting_plugin.logger; - // input validation - try { - reportDefinition.report_params.core_params.origin = - request.headers.origin; - reportDefinition = await validateReportDefinition( - context.core.opensearch.legacy.client, - reportDefinition, - basePath - ); - } catch (error) { - logger.error( - `Failed input validation for update report definition ${error}` - ); - addToMetric('report_definition', 'update', 'user_error'); - return response.badRequest({ body: error }); - } - // Update report definition metadata - try { - const opensearchResp = await updateReportDefinition( - request, - context, - reportDefinition - ); - - return response.ok({ - body: { - state: 'Report definition updated', - scheduler_response: opensearchResp, - }, - }); - } catch (error) { - logger.error(`Failed to update report definition: ${error}`); - addToMetric('report_definition', 'update', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); - - // get all report definitions details - router.get( - { - path: `${API_PREFIX}/reportDefinitions`, - validate: { - query: schema.object({ - fromIndex: schema.maybe(schema.number()), - maxItems: schema.maybe(schema.number()), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report_definition', 'list', 'count'); - const { fromIndex, maxItems } = request.query as { - fromIndex: number; - maxItems: number; - }; - try { - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.getReportDefinitions', - { - fromIndex: fromIndex, - maxItems: maxItems || DEFAULT_MAX_SIZE, - } - ); - const reportDefinitionsList = backendToUiReportDefinitionsList( - opensearchResp.reportDefinitionDetailsList, - basePath - ); - return response.ok({ - body: { - data: reportDefinitionsList, - }, - }); - } catch (error) { - //@ts-ignore - context.reporting_plugin.logger.error( - `Failed to get report definition details: ${error}` - ); - addToMetric('report_definition', 'list', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); - - // get report definition detail by id - router.get( - { - path: `${API_PREFIX}/reportDefinitions/{reportDefinitionId}`, - validate: { - params: schema.object({ - reportDefinitionId: schema.string(), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report_definition', 'info', 'count'); - try { - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.getReportDefinitionById', - { - reportDefinitionId: request.params.reportDefinitionId, - } - ); - - const reportDefinition = backendToUiReportDefinition( - opensearchResp.reportDefinitionDetails, - basePath - ); - - return response.ok({ - body: { report_definition: reportDefinition }, - }); - } catch (error) { - //@ts-ignore - context.reporting_plugin.logger.error( - `Failed to get single report details: ${error}` - ); - addToMetric('report_definition', 'info', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); - - // Delete report definition by id - router.delete( - { - path: `${API_PREFIX}/reportDefinitions/{reportDefinitionId}`, - validate: { - params: schema.object({ - reportDefinitionId: schema.string(), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - addToMetric('report_definition', 'delete', 'count'); - try { - // @ts-ignore - const opensearchReportsClient: ILegacyScopedClusterClient = context.reporting_plugin.opensearchReportsClient.asScoped( - request - ); - - const opensearchResp = await opensearchReportsClient.callAsCurrentUser( - 'opensearch_reports.deleteReportDefinitionById', - { - reportDefinitionId: request.params.reportDefinitionId, - } - ); - - return response.ok({ - body: { - state: 'Report definition deleted', - opensearch_response: opensearchResp, - }, - }); - } catch (error) { - //@ts-ignore - context.reporting_plugin.logger.error( - `Failed to delete report definition: ${error}` - ); - addToMetric('report_definition', 'delete', checkErrorType(error)); - return errorResponse(response, error); - } - } - ); -} diff --git a/dashboards-reports/server/routes/reportSource.ts b/dashboards-reports/server/routes/reportSource.ts deleted file mode 100644 index 43cbbb32..00000000 --- a/dashboards-reports/server/routes/reportSource.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - IRouter, - IOpenSearchDashboardsResponse, - ResponseError, -} from '../../../../src/core/server'; -import { API_PREFIX } from '../../common'; -import { checkErrorType, parseOpenSearchErrorResponse } from './utils/helpers'; -import { RequestParams } from '@elastic/elasticsearch'; -import { schema } from '@osd/config-schema'; -import { DEFAULT_MAX_SIZE } from './utils/constants'; -import { addToMetric } from './utils/metricHelper'; - -export default function (router: IRouter) { - router.get( - { - path: `${API_PREFIX}/getReportSource/{reportSourceType}`, - validate: { - params: schema.object({ - reportSourceType: schema.string(), - }), - }, - }, - async ( - context, - request, - response - ): Promise> => { - let responseParams; - if (request.params.reportSourceType === 'dashboard') { - const params: RequestParams.Search = { - index: '.kibana', - q: 'type:dashboard', - size: DEFAULT_MAX_SIZE, - }; - responseParams = params; - } else if (request.params.reportSourceType === 'visualization') { - const params: RequestParams.Search = { - index: '.kibana', - q: 'type:visualization', - size: DEFAULT_MAX_SIZE, - }; - responseParams = params; - } else if (request.params.reportSourceType === 'search') { - const params: RequestParams.Search = { - index: '.kibana', - q: 'type:search', - size: DEFAULT_MAX_SIZE, - }; - responseParams = params; - } try { - const opensearchResp = await context.core.opensearch.legacy.client.callAsCurrentUser( - 'search', - responseParams - ); - addToMetric('report_source', 'list', 'count'); - - return response.ok({ - body: opensearchResp, - }); - } catch (error) { - //@ts-ignore - context.reporting_plugin.logger.error( - `Failed to get reports source for ${request.params.reportSourceType}: ${error}` - ); - addToMetric('report_source', 'list', checkErrorType(error)); - return response.custom({ - statusCode: error.statusCode, - body: parseOpenSearchErrorResponse(error), - }); - } - } - ); -} diff --git a/dashboards-reports/server/routes/utils/__tests__/demo_dashboard.html b/dashboards-reports/server/routes/utils/__tests__/demo_dashboard.html deleted file mode 100644 index 71caafea..00000000 --- a/dashboards-reports/server/routes/utils/__tests__/demo_dashboard.html +++ /dev/null @@ -1,9699 +0,0 @@ - - -[eCommerce] Revenue Dashboard - OpenSearch
-
-

-

Dashboard panel: [eCommerce] Markdown[eCommerce] Markdown

Sample eCommerce Data

-

This dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about OpenSearch Dashboards, check our docs.

-

Dashboard panel: [eCommerce] Controls[eCommerce] Controls

Dashboard panel: [eCommerce] Sold Products per Day[eCommerce] Sold Products per Day

Trxns / day
149

Dashboard panel: [eCommerce] Sales by Gender[eCommerce] Sales by Gender

FEMALE (52.89%)MALE (47.11%)

Dashboard panel: [eCommerce] Average Sales Price[eCommerce] Average Sales Price

$74.62per order
average spend

Dashboard panel: [eCommerce] Average Sold Quantity[eCommerce] Average Sold Quantity

2.124per order
average items

Dashboard panel: [eCommerce] Total Revenue[eCommerce] Total Revenue

$78,725.49

Dashboard panel: [eCommerce] Sales by Category[eCommerce] Sales by Category

Sum of total_quantity020406080100
2021-06-17 12:002021-06-18 12:002021-06-19 12:002021-06-20 12:002021-06-21 12:002021-06-22 12:002021-06-23 12:00order_date per 3 hours

Dashboard panel: [eCommerce] Promotion Tracking[eCommerce] Promotion Tracking

  • Revenue Trousers
    $71
  • Revenue Watches
    $239
  • Revenue Bags
    $1,055.781
  • Revenue Cocktail Dresses
    $483.969

Dashboard panel: [eCommerce] Sales Count Map[eCommerce] Sales Count Map

Dashboard panel: [eCommerce] Top Selling Products[eCommerce] Top Selling Products

Lace-up boots - blackAnkle boots - blackBoots - blackPrint T-shirt - blackJumper - blackLace-up boots - resin coffeeDress with Defined Waist

Dashboard panel: [eCommerce] Orders[eCommerce] Orders

-
-
-
- - -
1–50 of 1055
-
-
-
-
- - - - - -
Timecategoryskutaxful_total_pricetotal_quantity
- -Jun 23, 2021 @ 23:56:10.000
Women's Accessories, Women's Clothing
ZO0301903019, ZO0049800498
$43.98
2
- -Jun 23, 2021 @ 23:41:46.000
Men's Clothing
ZO0128701287, ZO0577005770
$49.98
2
- -Jun 23, 2021 @ 23:37:26.000
Men's Clothing
ZO0558005580, ZO0276502765
$18.98
2
- -Jun 23, 2021 @ 23:33:07.000
Women's Accessories, Women's Clothing
ZO0358803588, ZO0179601796
$91.98
2
- -Jun 23, 2021 @ 23:21:36.000
Men's Clothing
ZO0543605436, ZO0425604256
$89.98
2
- -Jun 23, 2021 @ 23:21:36.000
Men's Clothing
ZO0629306293, ZO0578405784
$37.98
2
- -Jun 23, 2021 @ 22:51:22.000
Men's Clothing
ZO0291602916, ZO0292302923
$221.98
2
- -Jun 23, 2021 @ 22:48:29.000
Women's Clothing, Women's Accessories
ZO0262902629, ZO0358703587
$83.98
2
- -Jun 23, 2021 @ 22:29:46.000
Men's Clothing
ZO0474604746, ZO0111701117
$36.98
2
- -Jun 23, 2021 @ 22:12:29.000
Men's Accessories, Men's Shoes
ZO0598005980, ZO0681706817
$75.98
2
- -Jun 23, 2021 @ 22:11:02.000
Women's Clothing, Women's Shoes
ZO0221402214, ZO0677006770
$103.98
2
- -Jun 23, 2021 @ 21:59:31.000
Men's Clothing, Men's Shoes
ZO0579905799, ZO0386403864
$55.98
2
- -Jun 23, 2021 @ 21:55:12.000
Men's Clothing
ZO0474204742, ZO0574005740
$31.98
2
- -Jun 23, 2021 @ 21:48:00.000
Men's Clothing, Men's Shoes
ZO0580905809, ZO0507105071
$41.98
2
- -Jun 23, 2021 @ 21:23:31.000
Women's Clothing
ZO0217002170, ZO0164201642
$27.98
2
- -Jun 23, 2021 @ 21:17:46.000
Women's Shoes, Women's Clothing
ZO0368003680, ZO0173001730
$63.98
2
- -Jun 23, 2021 @ 21:12:00.000
Men's Clothing
ZO0437404374, ZO0293102931
$24.98
2
- -Jun 23, 2021 @ 21:09:07.000
Women's Accessories, Women's Shoes
ZO0085300853, ZO0678506785
$95.98
2
- -Jun 23, 2021 @ 20:56:10.000
Women's Clothing, Women's Shoes
ZO0638706387, ZO0677206772
$92.98
2
- -Jun 23, 2021 @ 20:41:46.000
Women's Shoes, Women's Clothing
ZO0678406784, ZO0712707127
$99.98
2
- -Jun 23, 2021 @ 20:37:26.000
Women's Clothing
ZO0708107081, ZO0500905009
$42.98
2
- -Jun 23, 2021 @ 20:33:07.000
Women's Shoes
ZO0250002500, ZO0675406754
$159.98
2
- -Jun 23, 2021 @ 20:24:29.000
Women's Accessories
ZO0205602056, ZO0356903569
$46.98
2
- -Jun 23, 2021 @ 20:00:00.000
Men's Clothing
ZO0441304413, ZO0561205612
$22.98
2
- -Jun 23, 2021 @ 19:55:41.000
Men's Shoes, Men's Clothing
ZO0691306913, ZO0275502755
$139.98
2
- -Jun 23, 2021 @ 19:32:38.000
Men's Clothing
ZO0295102951, ZO0453304533, ZO0588305883, ZO0411304113
$82.96
4
- -Jun 23, 2021 @ 19:19:41.000
Men's Clothing, Men's Accessories
ZO0296402964, ZO0316203162
$42.98
2
- -Jun 23, 2021 @ 19:18:14.000
Men's Clothing, Men's Shoes
ZO0588005880, ZO0571805718, ZO0403504035, ZO0457504575
$108.96
4
- -Jun 23, 2021 @ 19:15:22.000
Women's Clothing
ZO0051800518, ZO0333303333
$92.98
2
- -Jun 23, 2021 @ 19:06:43.000
Men's Clothing, Men's Shoes
ZO0431904319, ZO0683606836
$149.98
2
- -Jun 23, 2021 @ 19:05:17.000
Women's Clothing, Women's Accessories
ZO0181701817, ZO0095300953
$45.98
2
- -Jun 23, 2021 @ 18:58:05.000
Men's Clothing
ZO0620606206, ZO0454204542
$70.98
2
- -Jun 23, 2021 @ 18:40:48.000
Women's Shoes, Women's Accessories
ZO0670906709, ZO0211302113
$128.98
2
- -Jun 23, 2021 @ 18:30:43.000
Women's Clothing
ZO0263002630, ZO0497904979
$93.98
2
- -Jun 23, 2021 @ 18:27:50.000
Men's Clothing, Men's Shoes
ZO0300603006, ZO0123501235, ZO0399803998, ZO0624206242
$160.96
4
- -Jun 23, 2021 @ 18:13:26.000
Women's Accessories, Women's Shoes
ZO0696806968, ZO0020700207
$66.98
2
- -Jun 23, 2021 @ 18:03:22.000
Women's Clothing, Women's Accessories
ZO0271302713, ZO0703207032
$74.98
2
- -Jun 23, 2021 @ 18:00:29.000
Men's Shoes, Men's Accessories
ZO0403504035, ZO0608606086
$91.98
2
- -Jun 23, 2021 @ 17:46:05.000
Men's Shoes, Men's Clothing
ZO0521405214, ZO0585905859
$64.98
2
- -Jun 23, 2021 @ 17:31:41.000
Women's Clothing
ZO0171101711, ZO0048400484
$74.98
2
- -Jun 23, 2021 @ 17:28:48.000
Women's Accessories
ZO0209302093, ZO0087400874
$47.98
2
- -Jun 23, 2021 @ 17:27:22.000
Women's Accessories
ZO0096100961, ZO0091000910
$53.98
2
- -Jun 23, 2021 @ 17:04:19.000
Men's Clothing
ZO0284802848, ZO0581605816
$49.98
2
- -Jun 23, 2021 @ 17:02:53.000
Men's Shoes
ZO0401004010, ZO0257802578
$119.98
2
- -Jun 23, 2021 @ 16:51:22.000
Men's Shoes, Men's Accessories
ZO0520705207, ZO0397603976, ZO0395003950, ZO0702307023
$207.96
4
- -Jun 23, 2021 @ 16:49:55.000
Women's Shoes, Women's Clothing
ZO0364403644, ZO0150401504
$116.98
2
- -Jun 23, 2021 @ 16:31:12.000
Men's Clothing, Women's Accessories
ZO0554505545, ZO0703407034
$96.98
2
- -Jun 23, 2021 @ 16:25:26.000
Women's Clothing
ZO0263002630
$51.99
1
- -Jun 23, 2021 @ 16:02:24.000
Women's Shoes
ZO0365203652, ZO0383303833
$126.98
2
- -Jun 23, 2021 @ 16:00:58.000
Women's Clothing
ZO0179701797, ZO0496004960
$42.98
2
-
- - -
- - - -
- -
- -
-
\ No newline at end of file diff --git a/dashboards-reports/server/routes/utils/__tests__/metricHelper.test.ts b/dashboards-reports/server/routes/utils/__tests__/metricHelper.test.ts deleted file mode 100644 index 3953a724..00000000 --- a/dashboards-reports/server/routes/utils/__tests__/metricHelper.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { checkErrorType } from '../helpers'; - -describe('Test collecting metrics', () => { - // TODO: need more tests - - test('check error type', () => { - const badRequestError = { - statusCode: 400, - }; - const serverError = { - statusCode: 500, - }; - const unknownError = { - statusCode: undefined, - }; - const userErrorType = checkErrorType(badRequestError); - const sysErrorType = checkErrorType(serverError); - const unknownErrorType = checkErrorType(unknownError); - expect(userErrorType).toEqual('user_error'); - expect(sysErrorType).toEqual('system_error'); - expect(unknownErrorType).toEqual('system_error'); - }); -}); diff --git a/dashboards-reports/server/routes/utils/__tests__/savedSearchReportHelper.test.ts b/dashboards-reports/server/routes/utils/__tests__/savedSearchReportHelper.test.ts deleted file mode 100644 index 7009dda3..00000000 --- a/dashboards-reports/server/routes/utils/__tests__/savedSearchReportHelper.test.ts +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import 'regenerator-runtime/runtime'; -import { createSavedSearchReport } from '../savedSearchReportHelper'; -import { reportSchema } from '../../../model'; -import { mockLogger } from '../../../../test/__mocks__/loggerMock'; -import _ from 'lodash'; - -/** - * The mock and sample input for saved search export function. - */ -const input = { - query_url: '/app/discover#/view/7adfa750-4c81-11e8-b3d7-01146121b73d', - time_from: 1343576635300, - time_to: 1596037435301, - report_definition: { - report_params: { - report_name: 'test report table order', - report_source: 'Saved search', - description: 'Hi this is your saved search on demand', - core_params: { - base_url: '/app/discover#/view/7adfa750-4c81-11e8-b3d7-01146121b73d', - saved_search_id: 'ddd8f430-f2ef-11ea-8c86-81a0b21b4b67', - report_format: 'csv', - time_duration: 'PT5M', - limit: 10000, - excel: true, - origin: 'http://localhost:5601', - }, - }, - delivery: { - configIds: [], - title: 'title', - textDescription: 'text description', - htmlDescription: 'html description', - }, - trigger: { - trigger_type: 'On demand', - }, - }, -}; - -const mockDateFormat = 'MM/DD/YYYY h:mm:ss.SSS a'; - -/** - * Max result window size in OpenSearch index settings. - */ -const maxResultSize = 5; - -describe('test create saved search report', () => { - test('create report with valid input', async () => { - // Check if the assumption of input is up-to-date - reportSchema.validate(input); - }, 20000); - - test('create report with expected file name', async () => { - const hits: Array<{ _source: any }> = []; - const client = mockOpenSearchClient(hits); - const { timeCreated, fileName } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - expect(fileName).toContain(`test report table order_`); - }, 20000); - - test('create report with expected file name extension', async () => { - const csvReport = await createSavedSearchReport( - input, - mockOpenSearchClient([]), - mockDateFormat, - ',', - undefined, - mockLogger - ); - expect(csvReport.fileName).toContain('.csv'); - - input.report_definition.report_params.core_params.report_format = 'xlsx'; - const xlsxReport = await createSavedSearchReport( - input, - mockOpenSearchClient([]), - mockDateFormat, - ',', - undefined, - mockLogger - ); - expect(xlsxReport.fileName).toContain('.xlsx'); - }, 20000); - - test('create report for empty data set', async () => { - const hits: Array<{ _source: any }> = []; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - expect(dataUrl).toEqual(''); - }, 20000); - - test('create report for small data set by single search', async () => { - const hits = [ - hit({ category: 'c1', customer_gender: 'Male' }), - hit({ category: 'c2', customer_gender: 'Male' }), - hit({ category: 'c3', customer_gender: 'Male' }), - hit({ category: 'c4', customer_gender: 'Male' }), - hit({ category: 'c5', customer_gender: 'Male' }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender\n' + - 'c1,Male\n' + - 'c2,Male\n' + - 'c3,Male\n' + - 'c4,Male\n' + - 'c5,Male' - ); - }, 20000); - - test('create report for large data set by scroll', async () => { - const hits = [ - hit({ category: 'c1', customer_gender: 'Male' }), - hit({ category: 'c2', customer_gender: 'Male' }), - hit({ category: 'c3', customer_gender: 'Male' }), - hit({ category: 'c4', customer_gender: 'Male' }), - hit({ category: 'c5', customer_gender: 'Male' }), - hit({ category: 'c6', customer_gender: 'Female' }), - hit({ category: 'c7', customer_gender: 'Female' }), - hit({ category: 'c8', customer_gender: 'Female' }), - hit({ category: 'c9', customer_gender: 'Female' }), - hit({ category: 'c10', customer_gender: 'Female' }), - hit({ category: 'c11', customer_gender: 'Male' }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender\n' + - 'c1,Male\n' + - 'c2,Male\n' + - 'c3,Male\n' + - 'c4,Male\n' + - 'c5,Male\n' + - 'c6,Female\n' + - 'c7,Female\n' + - 'c8,Female\n' + - 'c9,Female\n' + - 'c10,Female\n' + - 'c11,Male' - ); - }, 20000); - - test('create report with limit smaller than max result size', async () => { - // Assign a smaller limit than default to test - input.report_definition.report_params.core_params.limit = 1; - - const hits = [ - hit({ category: 'c1', customer_gender: 'Male' }), - hit({ category: 'c2', customer_gender: 'Male' }), - hit({ category: 'c3', customer_gender: 'Male' }), - hit({ category: 'c4', customer_gender: 'Male' }), - hit({ category: 'c5', customer_gender: 'Male' }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual('category,customer_gender\n' + 'c1,Male'); - }, 20000); - - test('create report with limit greater than max result size', async () => { - // Assign a limit just a little greater than max result size (5) - input.report_definition.report_params.core_params.limit = 6; - - const hits = [ - hit({ category: 'c1', customer_gender: 'Male' }), - hit({ category: 'c2', customer_gender: 'Male' }), - hit({ category: 'c3', customer_gender: 'Male' }), - hit({ category: 'c4', customer_gender: 'Male' }), - hit({ category: 'c5', customer_gender: 'Male' }), - hit({ category: 'c6', customer_gender: 'Female' }), - hit({ category: 'c7', customer_gender: 'Female' }), - hit({ category: 'c8', customer_gender: 'Female' }), - hit({ category: 'c9', customer_gender: 'Female' }), - hit({ category: 'c10', customer_gender: 'Female' }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender\n' + - 'c1,Male\n' + - 'c2,Male\n' + - 'c3,Male\n' + - 'c4,Male\n' + - 'c5,Male\n' + - 'c6,Female' - ); - }, 20000); - - test('create report with limit greater than total result size', async () => { - // Assign a limit even greater than the result size - input.report_definition.report_params.core_params.limit = 10; - - const hits = [ - hit({ category: 'c1', customer_gender: 'Male' }), - hit({ category: 'c2', customer_gender: 'Male' }), - hit({ category: 'c3', customer_gender: 'Male' }), - hit({ category: 'c4', customer_gender: 'Male' }), - hit({ category: 'c5', customer_gender: 'Male' }), - hit({ category: 'c6', customer_gender: 'Female' }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender\n' + - 'c1,Male\n' + - 'c2,Male\n' + - 'c3,Male\n' + - 'c4,Male\n' + - 'c5,Male\n' + - 'c6,Female' - ); - }, 20000); - - test('create report for data set with comma', async () => { - const hits = [ - hit({ category: ',c1', customer_gender: 'Ma,le' }), - hit({ category: 'c2,', customer_gender: 'M,ale' }), - hit({ category: ',,c3', customer_gender: 'Male,,,' }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender\n' + - '",c1","Ma,le"\n' + - '"c2,","M,ale"\n' + - '",,c3","Male,,,"' - ); - }, 20000); - - test('create report for data set with comma and custom separator', async () => { - const hits = [ - hit({ category: ',c1', customer_gender: 'Ma,le' }), - hit({ category: 'c2,', customer_gender: 'M,ale' }), - hit({ category: ',,c3', customer_gender: 'Male,,,' }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - '|', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category|customer_gender\n' + - ',c1|Ma,le\n' + - 'c2,|M,ale\n' + - ',,c3|Male,,,' - ); - }, 20000); - - test('create report for data set with nested fields', async () => { - const hits = [ - hit({ - 'geoip.country_iso_code': 'GB', - 'geoip.location': { lon: -0.1, lat: 51.5 }, - }), - hit({ - 'geoip.country_iso_code': 'US', - 'geoip.city_name': 'New York', - 'geoip.location': { lon: -74, lat: 40.8 }, - }), - ]; - const client = mockOpenSearchClient( - hits, - '"geoip.country_iso_code", "geoip.city_name", "geoip.location"' - ); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'geoip.country_iso_code,geoip.location.lon,geoip.location.lat,geoip.city_name\n' + - 'GB,-0.1,51.5, \n' + - 'US,-74,40.8,New York' - ); - }, 20000); - - test('create report by sanitizing data set for Excel', async () => { - const hits = [ - hit({ category: 'c1', customer_gender: '=Male' }), - hit({ category: 'c2', customer_gender: 'Male=' }), - hit({ category: 'c3', customer_gender: '+Ma,le' }), - hit({ category: ',-c4', customer_gender: 'Male' }), - hit({ category: ',,,@c5', customer_gender: 'Male' }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender\n' + - `c1,'=Male\n` + - `c2,Male=\n` + - `c3,"'+Ma,le"\n` + - `",-c4",Male\n` + - `",,,@c5",Male` - ); - }, 20000); - - test('create report by not sanitizing data set for Excel', async () => { - // Enable Excel escape option - input.report_definition.report_params.core_params.excel = false; - - const hits = [ - hit({ category: 'c1', customer_gender: '=Male' }), - hit({ category: 'c2', customer_gender: 'Male=' }), - hit({ category: 'c3', customer_gender: '+Ma,le' }), - hit({ category: ',-c4', customer_gender: 'Male' }), - hit({ category: ',,,@c5', customer_gender: 'Male' }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender\n' + - 'c1,=Male\n' + - 'c2,Male=\n' + - 'c3,"+Ma,le"\n' + - '",-c4",Male\n' + - '",,,@c5",Male' - ); - }, 20000); -}); - -test('create report for data set contains null field value', async () => { - const hits = [ - hit({ category: 'c1', customer_gender: 'Ma' }), - hit({ category: 'c2', customer_gender: 'le' }), - hit({ category: 'c3', customer_gender: null }), - ]; - const client = mockOpenSearchClient(hits); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender\n' + 'c1,Ma\n' + 'c2,le\n' + 'c3, ' - ); -}, 20000); - -test('create report for data set with metadata fields', async () => { - const metadataFields = { _index: 'nameofindex', _id: 'someid' }; - let hits = [ - hit({ category: 'c1', customer_gender: 'Male' }), - hit({ category: 'c2', customer_gender: 'Male' }), - hit({ category: 'c3', customer_gender: 'Male' }), - hit({ category: 'c4', customer_gender: 'Male' }), - hit({ category: 'c5', customer_gender: 'Male' }), - ]; - hits.forEach((i) => { - _.merge(i, metadataFields); - }); - - const client = mockOpenSearchClient( - hits, - '"category", "customer_gender","_index","_id"' - ); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender,_index,_id\n' + - 'c1,Male,nameofindex,someid\n' + - 'c2,Male,nameofindex,someid\n' + - 'c3,Male,nameofindex,someid\n' + - 'c4,Male,nameofindex,someid\n' + - 'c5,Male,nameofindex,someid' - ); -}, 20000); - -test('create report with empty/one/multiple(list) date values', async () => { - const hits = [ - hit( - { category: 'c1', customer_gender: 'Ma', order_date: [] }, - { order_date: [] } - ), - hit( - { - category: 'c2', - customer_gender: 'le', - order_date: ['2021-12-16T14:04:55'], - }, - { order_date: ['2021-12-16T14:04:55'] } - ), - hit( - { - category: 'c3', - customer_gender: 'he', - order_date: ['2021-12-17T14:04:55', '2021-12-18T14:04:55'], - }, - { order_date: ['2021-12-17T14:04:55', '2021-12-18T14:04:55'] } - ), - hit( - { - category: 'c4', - customer_gender: 'te', - order_date: '2021-12-19T14:04:55', - }, - { order_date: ['2021-12-19T14:04:55'] } - ), - ]; - const client = mockOpenSearchClient( - hits, - '"category", "customer_gender", "order_date"' - ); - const { dataUrl } = await createSavedSearchReport( - input, - client, - mockDateFormat, - ',', - undefined, - mockLogger - ); - - expect(dataUrl).toEqual( - 'category,customer_gender,order_date\n' + - 'c1,Ma,[]\n' + - 'c2,le,"[""12/16/2021 2:04:55.000 pm""]"\n' + - 'c3,he,"[""12/17/2021 2:04:55.000 pm"",""12/18/2021 2:04:55.000 pm""]"\n' + - 'c4,te,12/19/2021 2:04:55.000 pm' - ); -}, 20000); - -/** - * Mock Elasticsearch client and return different mock objects based on endpoint and parameters. - */ -function mockOpenSearchClient( - mockHits: Array<{ _source: any }>, - columns = '"category", "customer_gender"' -) { - let call = 0; - const client = jest.fn(); - client.callAsInternalUser = jest - .fn() - .mockImplementation((endpoint: string, params: any) => { - switch (endpoint) { - case 'get': - return { - _source: params.id.startsWith('index-pattern:') - ? mockIndexPattern() - : mockSavedSearch(columns), - }; - case 'indices.getSettings': - return mockIndexSettings(); - case 'count': - return { - count: mockHits.length, - }; - case 'search': - return { - hits: { - hits: mockHits.slice(0, params.size), - }, - }; - case 'scroll': - call++; - return { - hits: { - hits: mockHits.slice( - maxResultSize * call, - maxResultSize * (call + 1) - ), - }, - }; - case 'clearScroll': - return null; - default: - fail('Fail due to unexpected function call on client', endpoint); - } - }); - return client; -} - -/** - * Mock a saved search for opensearch_dashboards_sample_data_ecommerce with 2 default selected fields: category and customer_gender. - */ -function mockSavedSearch(columns = '"category", "customer_gender"') { - return JSON.parse(` - { - "type": "search", - "id": "ddd8f430-f2ef-11ea-8c86-81a0b21b4b67", - "search": { - "title": "Show category and gender", - "description": "", - "hits": 0, - "columns": [ ${columns} ], - "sort": [], - "version": 1, - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\\"highlightAll\\":true,\\"version\\":true,\\"query\\":{\\"query\\":\\"\\",\\"language\\":\\"kuery\\"},\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.index\\",\\"filter\\":[]}" - } - }, - "references": [ - { - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern", - "id": "ff959d40-b880-11e8-a6d9-e546fe2bba5f" - } - ] - } - `); -} - -/** - * Mock index pattern for opensearch_dashboards_sample_data_ecommerce. - */ -function mockIndexPattern() { - return JSON.parse(` - { - "index-pattern": { - "title": "opensearch_dashboards_sample_data_ecommerce", - "timeFieldName": "order_date", - "fields": "[{\\"name\\":\\"_id\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"_id\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":false},{\\"name\\":\\"_index\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"_index\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":false},{\\"name\\":\\"_score\\",\\"type\\":\\"number\\",\\"count\\":0,\\"scripted\\":false,\\"searchable\\":false,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"_source\\",\\"type\\":\\"_source\\",\\"opensearchTypes\\":[\\"_source\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":false,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"_type\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"_type\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":false},{\\"name\\":\\"category\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"text\\"],\\"count\\":2,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"category.keyword\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true,\\"subType\\":{\\"multi\\":{\\"parent\\":\\"category\\"}}},{\\"name\\":\\"currency\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"customer_birth_date\\",\\"type\\":\\"date\\",\\"opensearchTypes\\":[\\"date\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"customer_first_name\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"text\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"customer_first_name.keyword\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true,\\"subType\\":{\\"multi\\":{\\"parent\\":\\"customer_first_name\\"}}},{\\"name\\":\\"customer_full_name\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"text\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"customer_full_name.keyword\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true,\\"subType\\":{\\"multi\\":{\\"parent\\":\\"customer_full_name\\"}}},{\\"name\\":\\"customer_gender\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":2,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"customer_id\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"customer_last_name\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"text\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"customer_last_name.keyword\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true,\\"subType\\":{\\"multi\\":{\\"parent\\":\\"customer_last_name\\"}}},{\\"name\\":\\"customer_phone\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"day_of_week\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"day_of_week_i\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"integer\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"email\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"geoip.city_name\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"geoip.continent_name\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"geoip.country_iso_code\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"geoip.location\\",\\"type\\":\\"geo_point\\",\\"opensearchTypes\\":[\\"geo_point\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"geoip.region_name\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"manufacturer\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"text\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"manufacturer.keyword\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true,\\"subType\\":{\\"multi\\":{\\"parent\\":\\"manufacturer\\"}}},{\\"name\\":\\"order_date\\",\\"type\\":\\"date\\",\\"opensearchTypes\\":[\\"date\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"order_id\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products._id\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"text\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"products._id.keyword\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true,\\"subType\\":{\\"multi\\":{\\"parent\\":\\"products._id\\"}}},{\\"name\\":\\"products.base_price\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.base_unit_price\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.category\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"text\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"products.category.keyword\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true,\\"subType\\":{\\"multi\\":{\\"parent\\":\\"products.category\\"}}},{\\"name\\":\\"products.created_on\\",\\"type\\":\\"date\\",\\"opensearchTypes\\":[\\"date\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.discount_amount\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.discount_percentage\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.manufacturer\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"text\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"products.manufacturer.keyword\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true,\\"subType\\":{\\"multi\\":{\\"parent\\":\\"products.manufacturer\\"}}},{\\"name\\":\\"products.min_price\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.price\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.product_id\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"long\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.product_name\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"text\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":false,\\"readFromDocValues\\":false},{\\"name\\":\\"products.product_name.keyword\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true,\\"subType\\":{\\"multi\\":{\\"parent\\":\\"products.product_name\\"}}},{\\"name\\":\\"products.quantity\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"integer\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.sku\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.tax_amount\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.taxful_price\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.taxless_price\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"products.unit_discount_amount\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"sku\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"taxful_total_price\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"taxless_total_price\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"half_float\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"total_quantity\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"integer\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"total_unique_products\\",\\"type\\":\\"number\\",\\"opensearchTypes\\":[\\"integer\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"type\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true},{\\"name\\":\\"user\\",\\"type\\":\\"string\\",\\"opensearchTypes\\":[\\"keyword\\"],\\"count\\":0,\\"scripted\\":false,\\"searchable\\":true,\\"aggregatable\\":true,\\"readFromDocValues\\":true}]", - "fieldFormatMap": "{\\"taxful_total_price\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5601\\",\\"pathname\\":\\"/app/opensearch_dashboards\\",\\"basePath\\":\\"\\"},\\"pattern\\":\\"$0,0.[00]\\"}}}" - } - } - `); -} - -/** - * Mock index settings for opensearch_dashboards_sample_data_ecommerce. - */ -function mockIndexSettings() { - return JSON.parse(` - { - "opensearch_dashboards_sample_data_ecommerce": { - "settings": { - "index": { - "number_of_shards": "1", - "auto_expand_replicas": "0-1", - "provided_name": "opensearch_dashboards_sample_data_ecommerce", - "max_result_window": "${maxResultSize}", - "creation_date": "1594417718898", - "number_of_replicas": "0", - "uuid": "0KnfmEsaTYKg39ONcrA5Eg", - "version": { - "created": "7080099" - } - } - } - } - } - `); -} - -function hit(source_kv: any, fields_kv = {}) { - return { - _source: source_kv, - fields: fields_kv, - }; -} diff --git a/dashboards-reports/server/routes/utils/__tests__/visualReportHelper.test.ts b/dashboards-reports/server/routes/utils/__tests__/visualReportHelper.test.ts deleted file mode 100644 index 81595979..00000000 --- a/dashboards-reports/server/routes/utils/__tests__/visualReportHelper.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import 'regenerator-runtime/runtime'; -import { createVisualReport } from '../visual_report/visualReportHelper'; -import { Logger } from '../../../../../../src/core/server'; -import { ReportParamsSchemaType, reportSchema } from '../../../model'; -import { mockLogger } from '../../../../test/__mocks__/loggerMock'; - -const mockHeader = { mockKey: 'mockValue' }; -const input = { - query_url: '/app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d', - time_from: 1343576635300, - time_to: 1596037435301, - report_definition: { - report_params: { - report_name: 'test visual report', - report_source: 'Dashboard', - description: 'Hi this is your Dashboard on demand', - core_params: { - base_url: '/app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d', - window_width: 1300, - window_height: 900, - report_format: 'png', - time_duration: 'PT5M', - origin: 'http://localhost:5601', - }, - }, - delivery: { - configIds: [], - title: 'title', - textDescription: 'text description', - htmlDescription: 'html description', - }, - trigger: { - trigger_type: 'On demand', - }, - }, -}; - -const mockHtmlPath = `file://${__dirname}/demo_dashboard.html`; - -describe('test create visual report', () => { - test('create report with valid input', async () => { - // Check if the assumption of input is up-to-date - reportSchema.validate(input); - }, 20000); - - test('create png report', async () => { - expect.assertions(3); - const reportParams = input.report_definition.report_params; - const { dataUrl, fileName } = await createVisualReport( - reportParams as ReportParamsSchemaType, - mockHtmlPath, - mockLogger, - mockHeader - ); - expect(fileName).toContain(`${reportParams.report_name}`); - expect(fileName).toContain('.png'); - expect(dataUrl).toBeDefined(); - }, 60000); - - test('create pdf report', async () => { - expect.assertions(3); - const reportParams = input.report_definition.report_params; - reportParams.core_params.report_format = 'pdf'; - - const { dataUrl, fileName } = await createVisualReport( - reportParams as ReportParamsSchemaType, - mockHtmlPath, - mockLogger, - mockHeader - ); - expect(fileName).toContain(`${reportParams.report_name}`); - expect(fileName).toContain('.pdf'); - expect(dataUrl).toBeDefined(); - }, 60000); -}); diff --git a/dashboards-reports/server/routes/utils/constants.ts b/dashboards-reports/server/routes/utils/constants.ts deleted file mode 100644 index dffb0cd1..00000000 --- a/dashboards-reports/server/routes/utils/constants.ts +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { CountersType } from './types'; -import Showdown from 'showdown'; - -export enum FORMAT { - pdf = 'pdf', - png = 'png', - csv = 'csv', -} - -export enum REPORT_STATE { - created = 'Created', - error = 'Error', - pending = 'Pending', - shared = 'Shared', -} - -export enum REPORT_DEFINITION_STATUS { - active = 'Active', - disabled = 'Disabled', -} - -export enum DELIVERY_CHANNEL { - email = 'Email', - slack = 'Slack', - chime = 'Chime', - opensearchDashboards = 'OpenSearch Dashboards user', -} - -export enum SCHEDULE_TYPE { - recurring = 'Recurring', - cron = 'Cron based', -} - -export enum REPORT_TYPE { - savedSearch = 'Saved search', - dashboard = 'Dashboard', - visualization = 'Visualization', - notebook = 'Notebook', -} - -export enum DATA_REPORT_CONFIG { - excelDateFormat = 'MM/DD/YYYY h:mm:ss.SSS a', -} - -export enum TRIGGER_TYPE { - schedule = 'Schedule', - onDemand = 'On demand', -} - -export enum DELIVERY_TYPE { - opensearchDashboardsUser = 'OpenSearch Dashboards user', - channel = 'Channel', -} - -export enum SELECTOR { - dashboard = '#dashboardViewport', - visualization = '.visEditor__content', - notebook = '.euiPageBody', -} - -// https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-from-size.html -export const DEFAULT_MAX_SIZE = 10000; - -export const DEFAULT_REPORT_HEADER = '

OpenSearch Dashboards Reports

'; - -export const SECURITY_CONSTANTS = { - TENANT_LOCAL_STORAGE_KEY: 'opendistro::security::tenant::show_popup', -}; - -export const EXTRA_HEADERS = [ - 'cookie', - 'x-proxy-user', - 'x-proxy-roles', - 'x-forwarded-for', -]; - -export const converter = new Showdown.Converter({ - tables: true, - simplifiedAutoLink: true, - strikethrough: true, - tasklists: true, - noHeaderId: true, -}); - -const BLOCKED_KEYWORD = 'BLOCKED_KEYWORD'; -const ipv4Regex = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])/g -const ipv6Regex = /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/g; -const localhostRegex = /localhost:([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])/g; -const iframeRegex = /iframe/g; - -export const replaceBlockedKeywords = (htmlString: string) => { - // replace : - htmlString = htmlString.replace(ipv4Regex, BLOCKED_KEYWORD); - // replace ipv6 addresses - htmlString = htmlString.replace(ipv6Regex, BLOCKED_KEYWORD); - // replace iframe keyword - htmlString = htmlString.replace(iframeRegex, BLOCKED_KEYWORD); - // replace localhost: - htmlString = htmlString.replace(localhostRegex, BLOCKED_KEYWORD); - return htmlString; -} - -export const CHROMIUM_PATH = `${__dirname}/../../../.chromium/headless_shell`; - - -/** - * Metric constants - */ -export const WINDOW = 3600; -export const INTERVAL = 60; -export const CAPACITY = (WINDOW / INTERVAL) * 2; - -export const GLOBAL_BASIC_COUNTER: CountersType = { - report: { - create: { - total: 0, - }, - create_from_definition: { - total: 0, - }, - download: { - total: 0, - }, - list: { - total: 0, - }, - info: { - total: 0, - }, - }, - report_definition: { - create: { - total: 0, - }, - list: { - total: 0, - }, - info: { - total: 0, - }, - update: { - total: 0, - }, - delete: { - total: 0, - }, - }, - report_source: { - list: { - total: 0, - }, - }, - dashboard: { - pdf: { - download: { - total: 0, - }, - }, - png: { - download: { - total: 0, - }, - }, - }, - visualization: { - pdf: { - download: { - total: 0, - }, - }, - png: { - download: { - total: 0, - }, - }, - }, - notebook: { - pdf: { - download: { - count: 0, - }, - }, - png: { - download: { - count: 0, - }, - }, - }, - saved_search: { - csv: { - download: { - total: 0, - }, - }, - }, -}; - -export const DEFAULT_ROLLING_COUNTER: CountersType = { - report: { - create: { - count: 0, - system_error: 0, - user_error: 0, - }, - create_from_definition: { - count: 0, - system_error: 0, - user_error: 0, - }, - download: { - count: 0, - system_error: 0, - user_error: 0, - }, - list: { - count: 0, - system_error: 0, - user_error: 0, - }, - info: { - count: 0, - system_error: 0, - user_error: 0, - }, - }, - report_definition: { - create: { - count: 0, - system_error: 0, - user_error: 0, - }, - list: { - count: 0, - system_error: 0, - user_error: 0, - }, - info: { - count: 0, - system_error: 0, - user_error: 0, - }, - update: { - count: 0, - system_error: 0, - user_error: 0, - }, - delete: { - count: 0, - system_error: 0, - user_error: 0, - }, - }, - report_source: { - list: { - count: 0, - system_error: 0, - user_error: 0, - }, - }, - dashboard: { - pdf: { - download: { - count: 0, - }, - }, - png: { - download: { - count: 0, - }, - }, - }, - visualization: { - pdf: { - download: { - count: 0, - }, - }, - png: { - download: { - count: 0, - }, - }, - }, - notebook: { - pdf: { - download: { - count: 0, - }, - }, - png: { - download: { - count: 0, - }, - }, - }, - saved_search: { - csv: { - download: { - count: 0, - }, - }, - }, -}; diff --git a/dashboards-reports/server/routes/utils/converters/__tests__/backendToUi.test.ts b/dashboards-reports/server/routes/utils/converters/__tests__/backendToUi.test.ts deleted file mode 100644 index 4877f807..00000000 --- a/dashboards-reports/server/routes/utils/converters/__tests__/backendToUi.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { ReportingConfig } from 'server/config/config'; -import { - BackendReportInstanceType, - BACKEND_DELIVERY_FORMAT, - BACKEND_REPORT_FORMAT, - BACKEND_REPORT_SOURCE, - BACKEND_REPORT_STATE, - BACKEND_TRIGGER_TYPE, -} from '../../../../model/backendModel'; -import { backendToUiReport } from '../backendToUi'; - -const input: BackendReportInstanceType = { - id: 'ScvStHUBQ1Iwo-aR31dV', - lastUpdatedTimeMs: 1605056644321, - createdTimeMs: 1605056520018, - beginTimeMs: 1605054720000, - endTimeMs: 1605056520000, - access: ['roleId'], - reportDefinitionDetails: { - id: 'OMvRtHUBQ1Iwo-aRcFdO', - lastUpdatedTimeMs: 1605056426053, - createdTimeMs: 1605056426053, - access: ['roleId'], - reportDefinition: { - name: 'cron-email', - isEnabled: true, - source: { - description: 'some random', - type: BACKEND_REPORT_SOURCE.dashboard, - origin: 'http://localhost:5601', - id: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', - }, - format: { - duration: 'PT30M', - fileFormat: BACKEND_REPORT_FORMAT.pdf, - header: '

test header

', - footer: '

fake footer

', - }, - trigger: { - triggerType: BACKEND_TRIGGER_TYPE.cronSchedule, - schedule: { - cron: { - expression: '2 17 * * *', - timezone: 'PST8PDT', - }, - }, - }, - delivery: { - title: 'test email subject', - textDescription: '- test\n- optional\n- message', - htmlDescription: - '
    \n
  • test
  • \n
  • optional
  • \n
  • message
  • \n
', - configIds: [], - }, - }, - }, - status: BACKEND_REPORT_STATE.success, -}; - -const sampleServerBasePath = '/test'; - -const output = { - query_url: `${sampleServerBasePath}/app/dashboards#/view/722b74f0-b882-11e8-a6d9-e546fe2bba5f?_g=(time:(from:'2020-11-11T00:32:00.000Z',to:'2020-11-11T01:02:00.000Z'))`, - time_from: 1605054720000, - time_to: 1605056520000, - last_updated: 1605056644321, - time_created: 1605056520018, - state: 'Shared', - report_definition: { - report_params: { - report_name: 'cron-email', - report_source: 'Dashboard', - description: 'some random', - core_params: { - base_url: `${sampleServerBasePath}/app/dashboards#/view/722b74f0-b882-11e8-a6d9-e546fe2bba5f`, - report_format: 'pdf', - header: '

test header

', - footer: '

fake footer

', - time_duration: 'PT30M', - origin: 'http://localhost:5601', - window_width: 1600, - window_height: 800, - }, - }, - trigger: { - trigger_type: 'Schedule', - trigger_params: { - enabled_time: 1605056426053, - enabled: true, - schedule_type: 'Cron based', - schedule: { cron: { expression: '2 17 * * *', timezone: 'PST8PDT' } }, - }, - }, - delivery: { - title: 'test email subject', - textDescription: '- test\n- optional\n- message', - htmlDescription: - '
    \n
  • test
  • \n
  • optional
  • \n
  • message
  • \n
', - configIds: [], - }, - time_created: 1605056426053, - last_updated: 1605056426053, - status: 'Active', - }, -}; - -describe('test backend to ui model conversion', () => { - test('convert backend to ui report', async () => { - const res = backendToUiReport(input, sampleServerBasePath); - expect(res).toEqual(output); - }, 20000); -}); diff --git a/dashboards-reports/server/routes/utils/converters/__tests__/uiToBackend.test.ts b/dashboards-reports/server/routes/utils/converters/__tests__/uiToBackend.test.ts deleted file mode 100644 index a1fbe6d6..00000000 --- a/dashboards-reports/server/routes/utils/converters/__tests__/uiToBackend.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { ReportDefinitionSchemaType } from 'server/model'; -import { - DELIVERY_TYPE, - FORMAT, - REPORT_TYPE, - SCHEDULE_TYPE, - TRIGGER_TYPE, -} from '../../constants'; -import { uiToBackendReportDefinition } from '../uiToBackend'; - -/** - * The mock and sample input. - */ -const input: ReportDefinitionSchemaType = { - report_params: { - report_name: 'test report table order', - report_source: REPORT_TYPE.savedSearch, - description: 'Hi this is your saved search on demand', - core_params: { - base_url: '/app/discover#/view/7adfa750-4c81-11e8-b3d7-01146121b73d', - saved_search_id: 'ddd8f430-f2ef-11ea-8c86-81a0b21b4b67', - report_format: FORMAT.csv, - time_duration: 'PT5M', - limit: 10000, - excel: true, - origin: 'http://localhost:5601', - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, - trigger: { - trigger_type: TRIGGER_TYPE.schedule, - trigger_params: { - schedule_type: SCHEDULE_TYPE.recurring, - schedule: { - interval: { - period: 2, - unit: 'Minutes', - start_time: 1599609062156, - }, - }, - enabled_time: 1599609062156, - enabled: true, - }, - }, -}; - -const output = { - name: 'test report table order', - isEnabled: true, - source: { - description: 'Hi this is your saved search on demand', - type: 'SavedSearch', - id: '7adfa750-4c81-11e8-b3d7-01146121b73d', - origin: 'http://localhost:5601', - }, - format: { duration: 'PT5M', fileFormat: 'Csv', limit: 10000 }, - trigger: { - triggerType: 'IntervalSchedule', - schedule: { - interval: { period: 2, unit: 'Minutes', start_time: 1599609062156 }, - }, - }, - delivery: { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }, -}; - -describe('test ui to backend model conversion', () => { - test('convert ui to backend report instance', async () => { - const res = uiToBackendReportDefinition(input); - expect(res).toEqual(output); - }, 20000); -}); diff --git a/dashboards-reports/server/routes/utils/converters/backendToUi.ts b/dashboards-reports/server/routes/utils/converters/backendToUi.ts deleted file mode 100644 index 0d9b9816..00000000 --- a/dashboards-reports/server/routes/utils/converters/backendToUi.ts +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - DataReportSchemaType, - DeliverySchemaType, - reportDefinitionSchema, - ReportDefinitionSchemaType, - ReportSchemaType, - TriggerSchemaType, - VisualReportSchemaType, -} from '../../../model'; -import { - BackendReportDefinitionDetailsType, - BackendReportInstanceType, - BACKEND_REPORT_FORMAT, - BACKEND_REPORT_SOURCE, - BACKEND_REPORT_STATE, - CronType, - DeliveryType, - IntervalType, - REPORT_FORMAT_DICT, - REPORT_SOURCE_DICT, - REPORT_STATE_DICT, - TRIGGER_TYPE_DICT, - URL_PREFIX_DICT, -} from '../../../model/backendModel'; -import { - DEFAULT_MAX_SIZE, - DELIVERY_TYPE, - FORMAT, - REPORT_DEFINITION_STATUS, - REPORT_STATE, - REPORT_TYPE, - SCHEDULE_TYPE, - TRIGGER_TYPE, -} from '../constants'; -import moment from 'moment'; -import { parse } from 'url'; - -export const backendToUiReport = ( - backendReportInstance: BackendReportInstanceType, - serverBasePath: string -): ReportSchemaType => { - const { - inContextDownloadUrlPath, - beginTimeMs, - endTimeMs, - tenant, - status, - lastUpdatedTimeMs: reportLastUpdatedTimeMs, - createdTimeMs: reportCreatedTimeMs, - reportDefinitionDetails: backendReportDefinitionDetails, - } = backendReportInstance; - - const { - reportDefinition: { - source: { type: sourceType, id: sourceId }, - delivery, - }, - } = backendReportDefinitionDetails; - - const baseUrl = getBaseUrl(sourceType, sourceId); - - let report: ReportSchemaType = { - // inContextDownloadUrlPath may not exist for report instance created from scheduled job - query_url: - inContextDownloadUrlPath || - getUiQueryUrl(baseUrl, beginTimeMs, endTimeMs, tenant), - time_from: beginTimeMs, - time_to: endTimeMs, - last_updated: reportLastUpdatedTimeMs, - time_created: reportCreatedTimeMs, - state: getUiReportState(status, delivery), - report_definition: backendToUiReportDefinition( - backendReportDefinitionDetails, - serverBasePath - ), - }; - - // Add severbasePath back to query_url - report.query_url = serverBasePath + report.query_url; - - return report; -}; - -export const backendToUiReportsList = ( - backendReportsList: BackendReportInstanceType[], - serverBasePath: string -) => { - const res = backendReportsList.map((backendReport) => { - return { - _id: backendReport.id, - _source: backendToUiReport(backendReport, serverBasePath), - }; - }); - return res; -}; - -export const backendToUiReportDefinition = ( - backendReportDefinitionDetails: BackendReportDefinitionDetailsType, - serverBasePath: string -): ReportDefinitionSchemaType => { - const { - lastUpdatedTimeMs, - createdTimeMs, - reportDefinition: { - name, - isEnabled, - source: { type: sourceType, description, id: sourceId, origin }, - format: { fileFormat, duration, header, footer, limit }, - trigger: { triggerType, schedule }, - delivery, - }, - } = backendReportDefinitionDetails; - - const baseUrl = getBaseUrl(sourceType, sourceId); - const reportSource = getUiReportSource(sourceType); - let uiReportDefinition: ReportDefinitionSchemaType = { - report_params: { - report_name: name, - report_source: reportSource, - description: description, - core_params: - reportSource === REPORT_TYPE.savedSearch - ? getDataReportCoreParams( - limit, - sourceId, - fileFormat, - duration, - baseUrl, - origin - ) - : getVisualReportCoreParams( - fileFormat, - header, - footer, - duration, - baseUrl, - origin - ), - }, - trigger: getUiTriggerParams( - triggerType, - schedule, - createdTimeMs, - isEnabled - ), - delivery: getUiDeliveryParams(delivery), //TODO: - time_created: createdTimeMs, - last_updated: lastUpdatedTimeMs, - status: getUiReportDefinitionStatus(isEnabled), - }; - // validate to assign default values to some fields for UI model - uiReportDefinition = reportDefinitionSchema.validate(uiReportDefinition); - uiReportDefinition.report_params.core_params.base_url = - serverBasePath + uiReportDefinition.report_params.core_params.base_url; - return uiReportDefinition; -}; - -export const backendToUiReportDefinitionsList = ( - backendReportDefinitionDetailsList: BackendReportDefinitionDetailsType[], - serverBasePath: string -) => { - const res = backendReportDefinitionDetailsList.map( - (backendReportDefinitionDetails) => { - return { - _id: backendReportDefinitionDetails.id, - _source: { - // TODO: this property can be removed, but need UI changes as well - report_definition: backendToUiReportDefinition( - backendReportDefinitionDetails, - serverBasePath - ), - }, - }; - } - ); - return res; -}; - -const getVisualReportCoreParams = ( - fileFormat: BACKEND_REPORT_FORMAT, - header: string = '', - footer: string = '', - duration: string, - baseUrl: string, - origin: string -): VisualReportSchemaType => { - let res: VisualReportSchemaType = { - base_url: baseUrl, - report_format: getUiReportFormat(fileFormat), - header: header, - footer: footer, - time_duration: duration, - origin: origin, - }; - return res; -}; - -// queryUrl = baseUrl + time range -const getUiQueryUrl = ( - baseUrl: string, - beginTimeMs: number, - endTimeMs: number, - tenant?: string -) => { - const timeFrom = moment(beginTimeMs).toISOString(); - const timeTo = moment(endTimeMs).toISOString(); - let queryUrl = `${baseUrl}?_g=(time:(from:'${timeFrom}',to:'${timeTo}'))`; - if (tenant !== undefined) { - if (tenant === '') { - tenant = 'global'; - } else if (tenant === '__user__') { - tenant = 'private'; - } - queryUrl = addTenantToURL(queryUrl, tenant); - } - - return queryUrl; -}; - -const getBaseUrl = (sourceType: BACKEND_REPORT_SOURCE, sourceId: string) => { - //TODO: AES domain has different prefix, need figure out a general solution - const baseUrl = `${URL_PREFIX_DICT[sourceType]}${sourceId}`; - return baseUrl; -}; - -const getDataReportCoreParams = ( - limit: number = DEFAULT_MAX_SIZE, - sourceId: string, - fileFormat: BACKEND_REPORT_FORMAT, - duration: string, - baseUrl: string, - origin: string -): DataReportSchemaType => { - let res: DataReportSchemaType = { - base_url: baseUrl, - report_format: getUiReportFormat(fileFormat), - limit: limit, - time_duration: duration, - saved_search_id: sourceId, - origin: origin, - }; - return res; -}; - -const getUiScheduleParams = ( - schedule: CronType | IntervalType | undefined, - createdTimeMs: number, - isEnabled: boolean -) => { - let res = { - trigger_params: { - enabled_time: createdTimeMs, - enabled: isEnabled, - schedule_type: - schedule && 'cron' in schedule - ? SCHEDULE_TYPE.cron - : SCHEDULE_TYPE.recurring, - schedule: schedule, - }, - }; - return res; -}; - -const getUiTriggerType = (backendField: string): TRIGGER_TYPE => { - let res: any; - for (let [ui, backendFieldList] of Object.entries(TRIGGER_TYPE_DICT)) { - for (let item of backendFieldList) { - if (item === backendField) { - res = ui; - } - } - } - return res; -}; - -const getUiReportFormat = (backendField: string): FORMAT => { - let res: any; - for (let [ui, backend] of Object.entries(REPORT_FORMAT_DICT)) { - if (backend === backendField) { - res = ui; - } - } - return res; -}; - -const getUiReportState = ( - status: BACKEND_REPORT_STATE, - delivery: any -): REPORT_STATE => { - let res: any; - for (let [ui, backend] of Object.entries(REPORT_STATE_DICT)) { - if (backend === status) { - // distinguish "shared" and "created" - if (status === BACKEND_REPORT_STATE.success && delivery) { - res = REPORT_STATE.shared; - } else { - res = ui; - } - } else if (status === BACKEND_REPORT_STATE.scheduled) { - // corner case - res = REPORT_STATE.pending; - } - } - return res; -}; - -const getUiReportSource = (type: BACKEND_REPORT_SOURCE): REPORT_TYPE => { - let res: any; - for (let [ui, backend] of Object.entries(REPORT_SOURCE_DICT)) { - if (backend === type) { - res = ui; - } - } - return res; -}; - -const getUiReportDefinitionStatus = ( - isEnabled: any -): REPORT_DEFINITION_STATUS => { - return isEnabled - ? REPORT_DEFINITION_STATUS.active - : REPORT_DEFINITION_STATUS.disabled; -}; - -const getUiTriggerParams = ( - triggerType: any, - schedule: CronType | IntervalType | undefined, - createdTimeMs: number, - isEnabled: boolean -): TriggerSchemaType => { - let res: TriggerSchemaType = { - trigger_type: getUiTriggerType(triggerType), - ...(getUiTriggerType(triggerType) === TRIGGER_TYPE.schedule && - getUiScheduleParams(schedule, createdTimeMs, isEnabled)), - }; - - return res; -}; - -// Delivery -const getUiDeliveryParams = ( - delivery: DeliveryType | undefined -): DeliverySchemaType => { - const opensearchDashboardsUserDeliveryParams = { - configIds: [], - title: '', - textDescription: '', - htmlDescription: '' - }; - - let params: any; - if (delivery) { - const { ...rest } = delivery; - params = { - ...rest - }; - } else { - params = opensearchDashboardsUserDeliveryParams; - } - return params; -}; - -// helper function to add tenant info to url(if tenant is available) -const addTenantToURL = (url: string, userRequestedTenant: string) => { - // build fake url from relative url - const fakeUrl = `http://opensearch.com${url}`; - const tenantKey = 'security_tenant'; - const tenantKeyAndValue = - tenantKey + '=' + encodeURIComponent(userRequestedTenant); - - const { pathname, search } = parse(fakeUrl); - const queryDelimiter = !search ? '?' : '&'; - - // The url parser returns null if the search is empty. Change that to an empty - // string so that we can use it to build the values later - if (search && search.toLowerCase().indexOf(tenantKey) > -1) { - // If we for some reason already have a tenant in the URL we skip any updates - return url; - } - - // A helper for finding the part in the string that we want to extend/replace - const valueToReplace = pathname! + (search || ''); - const replaceWith = valueToReplace + queryDelimiter + tenantKeyAndValue; - - return url.replace(valueToReplace, replaceWith); -}; diff --git a/dashboards-reports/server/routes/utils/converters/uiToBackend.ts b/dashboards-reports/server/routes/utils/converters/uiToBackend.ts deleted file mode 100644 index 4a2064cd..00000000 --- a/dashboards-reports/server/routes/utils/converters/uiToBackend.ts +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - ChannelSchemaType, - DeliverySchemaType, - ReportDefinitionSchemaType, - ScheduleSchemaType, - TriggerSchemaType, -} from '../../../model'; -import { - BackendReportDefinitionType, - BACKEND_DELIVERY_FORMAT, - BACKEND_REPORT_FORMAT, - BACKEND_REPORT_SOURCE, - BACKEND_REPORT_STATE, - BACKEND_TRIGGER_TYPE, - DeliveryType, - REPORT_FORMAT_DICT, - REPORT_SOURCE_DICT, - REPORT_STATE_DICT, -} from '../../../model/backendModel'; -import { - DELIVERY_TYPE, - FORMAT, - REPORT_STATE, - REPORT_TYPE, - SCHEDULE_TYPE, -} from '../constants'; - -export const uiToBackendReportDefinition = ( - reportDefinition: ReportDefinitionSchemaType -): BackendReportDefinitionType => { - const { - report_params: { - report_name: reportName, - description, - report_source: reportSource, - core_params: { - base_url: baseUrl, - time_duration: timeDuration, - report_format: reportFormat, - header, - footer, - limit, - origin, - }, - }, - trigger, - delivery, - } = reportDefinition; - - let backendReportDefinition: BackendReportDefinitionType = { - name: reportName, - isEnabled: getBackendIsEnabled(trigger), - source: { - description: description, - type: getBackendReportSource(reportSource), - id: getBackendReportSourceId(baseUrl), - origin: origin, - }, - format: { - duration: timeDuration, - fileFormat: getBackendReportFormat(reportFormat), - ...(limit && { limit: limit }), - ...(header && { header: header }), - ...(footer && { footer: footer }), - }, - trigger: getBackendTrigger(trigger), - ...(getBackendDelivery(delivery) && { - delivery: getBackendDelivery(delivery), - }), - }; - return backendReportDefinition; -}; - -const getBackendIsEnabled = (trigger: TriggerSchemaType) => { - let enabled = true; - if (trigger.trigger_params) { - enabled = trigger.trigger_params.enabled; - } - return enabled; -}; - -const getBackendDelivery = ( - delivery: DeliverySchemaType -): DeliveryType | undefined => { - const { - configIds: configIds, - title: title, - textDescription: textDescription, - htmlDescription: htmlDescription - } = delivery; - let res = { - configIds: configIds, - title: title, - textDescription: textDescription, - htmlDescription: htmlDescription - } - return res; -}; - -const getBackendTrigger = (trigger: TriggerSchemaType) => { - const { trigger_params: scheduleParams } = trigger; - const { schedule } = { ...scheduleParams }; - let res = { - triggerType: scheduleParams - ? getBackendTriggerType(scheduleParams) - : BACKEND_TRIGGER_TYPE.onDemand, - schedule: schedule, - }; - return res; -}; - -const getBackendTriggerType = ( - scheduleParams: ScheduleSchemaType -): BACKEND_TRIGGER_TYPE => { - const { schedule_type: scheduleType } = scheduleParams; - let res; - switch (scheduleType) { - case SCHEDULE_TYPE.cron: - res = BACKEND_TRIGGER_TYPE.cronSchedule; - break; - case SCHEDULE_TYPE.recurring: - res = BACKEND_TRIGGER_TYPE.intervalSchedule; - break; - } - return res; -}; - -const getBackendReportFormat = ( - reportFormat: FORMAT -): BACKEND_REPORT_FORMAT => { - return REPORT_FORMAT_DICT[reportFormat]; -}; - -export const getBackendReportState = ( - reportState: REPORT_STATE -): BACKEND_REPORT_STATE => { - return REPORT_STATE_DICT[reportState]; -}; - -export const getBackendReportSource = ( - reportSource: REPORT_TYPE -): BACKEND_REPORT_SOURCE => { - return REPORT_SOURCE_DICT[reportSource]; -}; -//TODO: tmp solution, we are extracting the id from the baseUrl, e.g. /app/dashboards#/view/ -// since currently dashboard/visualization id are not required in the UI model, will add in the future -const getBackendReportSourceId = (baseUrl: string): string => { - const id = baseUrl.split('/').pop() || ''; - return id; -}; diff --git a/dashboards-reports/server/routes/utils/dataReportHelpers.ts b/dashboards-reports/server/routes/utils/dataReportHelpers.ts deleted file mode 100644 index bc108832..00000000 --- a/dashboards-reports/server/routes/utils/dataReportHelpers.ts +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import esb, { Sort } from 'elastic-builder'; -import converter from 'json-2-csv'; -import _ from 'lodash'; -import moment from 'moment'; -import { DATA_REPORT_CONFIG } from './constants'; -import { - buildOpenSearchQuery, - Filter, - Query, -} from '../../../../../src/plugins/data/common'; - -export var metaData = { - saved_search_id: null, - report_format: null, - start: null, - end: null, - fields: null, - type: null, - timeFieldName: null, - sorting: null, - fields_exist: false, - selectedFields: [], - paternName: null, - searchSourceJSON: [], - dateFields: [], -}; - -// Get the selected columns by the user. -export const getSelectedFields = async (columns) => { - const selectedFields = []; - let fields_exist = false; - for (let column of columns) { - if (column !== '_source') { - fields_exist = true; - selectedFields.push(column); - } else { - fields_exist = false; - selectedFields.push('_source'); - } - } - metaData.fields_exist = fields_exist; - metaData.selectedFields = selectedFields; -}; - -// Build the OpenSearch query from the meta data -// is_count is set to 1 if we building the count query but 0 if we building the fetch data query -export const buildRequestBody = (report: any, is_count: number) => { - let esbBoolQuery = esb.boolQuery(); - const searchSourceJSON = report._source.searchSourceJSON; - - const savedObjectQuery: Query = JSON.parse(searchSourceJSON).query; - const savedObjectFilter: Filter = JSON.parse(searchSourceJSON).filter; - const QueryFromSavedObject = buildOpenSearchQuery( - undefined, - savedObjectQuery, - savedObjectFilter - ); - // Add time range - if (report._source.timeFieldName && report._source.timeFieldName.length > 0) { - esbBoolQuery.must( - esb - .rangeQuery(report._source.timeFieldName) - .format('epoch_millis') - .gte(report._source.start - 1) - .lte(report._source.end + 1) - ); - } - if (is_count) { - return esb.requestBodySearch().query(esbBoolQuery); - } - - // Add sorting to the query - let esbSearchQuery = esb - .requestBodySearch() - .query(esbBoolQuery) - .version(true); - - if (report._source.sorting.length > 0) { - const sortings: Sort[] = report._source.sorting.map((element: string[]) => { - return esb.sort(element[0], element[1]); - }); - esbSearchQuery.sorts(sortings); - } - - // add selected fields to query - if (report._source.fields_exist) { - esbSearchQuery.source({ includes: report._source.selectedFields }); - } - // Add a customizer to merge queries to generate request body - let requestBody = _.mergeWith( - { query: QueryFromSavedObject }, - esbSearchQuery.toJSON(), - (objValue, srcValue) => { - if (_.isArray(objValue)) { - return objValue.concat(srcValue); - } - } - ); - - requestBody = addDocValueFields(report, requestBody); - return requestBody; -}; - -// Fetch the data from OpenSearch -export const getOpenSearchData = ( - arrayHits, - report, - params, - dateFormat: string -) => { - let hits: any = []; - for (let valueRes of arrayHits) { - for (let data of valueRes.hits) { - const fields = data.fields; - // get all the fields of type date and format them to excel format - for (let dateField of report._source.dateFields) { - const dateValue = data._source[dateField]; - if (dateValue && dateValue.length !== 0) { - if (dateValue instanceof Array) { - // loop through array - dateValue.forEach((element, index) => { - data._source[dateField][index] = moment( - fields[dateField][index] - ).format(dateFormat); - }); - } else { - // The fields response always returns an array of values for each field - // https://www.elastic.co/guide/en/elasticsearch/reference/master/search-fields.html#search-fields-response - data._source[dateField] = moment(fields[dateField][0]).format( - dateFormat - ); - } - } - } - delete data['fields']; - if (report._source.fields_exist === true) { - let result = traverse(data, report._source.selectedFields); - hits.push(params.excel ? sanitize(result) : result); - } else { - hits.push(params.excel ? sanitize(data) : data); - } - // Truncate to expected limit size - if (hits.length >= params.limit) { - return hits; - } - } - } - return hits; -}; - -//Convert the data to Csv format -export const convertToCSV = async (dataset, csvSeparator) => { - let convertedData: any = []; - const options = { - delimiter: { field: csvSeparator, eol: '\n' }, - emptyFieldValue: ' ', - }; - await converter.json2csvAsync(dataset[0], options).then((csv) => { - convertedData = csv; - }); - return convertedData; -}; - -function flattenHits(hits, result = {}, prefix = '') { - for (const [key, value] of Object.entries(hits)) { - if (!hits.hasOwnProperty(key)) continue; - if ( - value != null && - typeof value === 'object' && - !Array.isArray(value) && - Object.keys(value).length > 0 - ) { - flattenHits(value, result, prefix + key + '.'); - } else { - result[prefix.replace(/^_source\./, '') + key] = value; - } - } - return result; -} - -//Return only the selected fields -function traverse(data, keys, result = {}) { - data = flattenHits(data); - const sourceKeys = Object.keys(data); - keys.forEach((key) => { - const value = _.get(data, key, undefined); - if (value !== undefined) result[key] = value; - else { - Object.keys(data) - .filter((sourceKey) => sourceKey.startsWith(key + '.')) - .forEach((sourceKey) => (result[sourceKey] = data[sourceKey])); - } - }); - return result; -} - -/** - * Escape special characters if field value prefixed with. - * This is intend to avoid CSV injection in Microsoft Excel. - * @param doc document - */ -function sanitize(doc: any) { - for (const field in doc) { - if (doc[field] == null) continue; - if ( - doc[field].toString().startsWith('+') || - (doc[field].toString().startsWith('-') && - typeof doc[field] !== 'number') || - doc[field].toString().startsWith('=') || - doc[field].toString().startsWith('@') - ) { - doc[field] = "'" + doc[field]; - } - } - return doc; -} - -const addDocValueFields = (report: any, requestBody: any) => { - const docValues = []; - for (const dateType of report._source.dateFields) { - docValues.push({ - field: dateType, - format: 'date_hour_minute_second_fraction', - }); - } - // elastic-builder doesn't provide function to build docvalue_fields with format, - // this is a workaround which appends docvalues field to the request body. - requestBody = { - ...requestBody, - docvalue_fields: docValues, - }; - return requestBody; -}; diff --git a/dashboards-reports/server/routes/utils/helpers.ts b/dashboards-reports/server/routes/utils/helpers.ts deleted file mode 100644 index 5bada6d0..00000000 --- a/dashboards-reports/server/routes/utils/helpers.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { OpenSearchDashboardsResponseFactory } from '../../../../../src/core/server'; -import { v1 as uuidv1 } from 'uuid'; -import { - ILegacyClusterClient, - ILegacyScopedClusterClient, -} from '../../../../../src/core/server'; - -/** - * OpenSearch error response body: - * { - * error: { - * root_cause: [{ type: 'status_exception', reason: 'test exception' }], - * type: 'status_exception', - * reason: 'test exception', - * }, - * status: 404, - * }; - * - */ -export function parseOpenSearchErrorResponse(error: any) { - if (error.response) { - try { - const opensearchErrorResponse = JSON.parse(error.response); - return opensearchErrorResponse.error.reason || error.response; - } catch (parsingError) { - return error.response; - } - } - return error.message; -} - -export function errorResponse(response: OpenSearchDashboardsResponseFactory, error: any) { - return response.custom({ - statusCode: error.statusCode || 500, - body: parseOpenSearchErrorResponse(error), - }); -} - -/** - * Generate report file name based on name and timestamp. - * @param itemName report item name - * @param timeCreated timestamp when this is being created - */ -export function getFileName(itemName: string, timeCreated: Date): string { - return `${itemName}_${timeCreated.toISOString()}_${uuidv1()}`; -} - -/** - * Call OpenSearch cluster function. - * @param client OpenSearch client - * @param endpoint OpenSearch API method - * @param params OpenSearch API parameters - */ -export const callCluster = async ( - client: ILegacyClusterClient | ILegacyScopedClusterClient, - endpoint: string, - params: any, - isScheduledTask: boolean -) => { - let opensearchResp; - if (isScheduledTask) { - opensearchResp = await (client as ILegacyClusterClient).callAsInternalUser( - endpoint, - params - ); - } else { - opensearchResp = await (client as ILegacyScopedClusterClient).callAsCurrentUser( - endpoint, - params - ); - } - return opensearchResp; -}; - -export const checkErrorType = (error: any) => { - if (error.statusCode && Math.floor(error.statusCode / 100) === 4) { - return 'user_error'; - } else { - return 'system_error'; - } -}; - -export const joinRequestParams = ( - queryParams: string | string[] | undefined -) => { - if (Array.isArray(queryParams)) return queryParams.join(','); - if (typeof queryParams === 'string') return queryParams; - return ''; -}; \ No newline at end of file diff --git a/dashboards-reports/server/routes/utils/metricHelper.ts b/dashboards-reports/server/routes/utils/metricHelper.ts deleted file mode 100644 index d58876dc..00000000 --- a/dashboards-reports/server/routes/utils/metricHelper.ts +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { ReportSchemaType } from 'server/model'; -import { - EntityType, - CountersNameType, - CountersType, - ActionType, -} from './types'; -import _ from 'lodash'; -import { - CAPACITY, - DEFAULT_ROLLING_COUNTER, - GLOBAL_BASIC_COUNTER, - INTERVAL, - WINDOW, -} from './constants'; - -export const time2CountWin: Map = new Map(); - -export const addToMetric = ( - entity: EntityType, - action: ActionType, - counter: CountersNameType, - reportMetadata?: ReportSchemaType -) => { - const count = 1; - // remove outdated key-value pairs - trim(); - - const timeKey = getKey(Date.now()); - const rollingCounters = time2CountWin.get(timeKey); - - time2CountWin.set( - timeKey, - updateCounters( - entity, - action, - counter, - rollingCounters || _.cloneDeep(DEFAULT_ROLLING_COUNTER), - count, - reportMetadata - ) - ); -}; - -export const getMetrics = () => { - const preTimeKey = getPreKey(Date.now()); - const rollingCounters = time2CountWin.get(preTimeKey); - const metrics = buildMetrics(rollingCounters); - return metrics; -}; - -const trim = () => { - if (time2CountWin.size > CAPACITY) { - const currentKey = getKey(Date.now() - WINDOW * 1000); - time2CountWin.forEach((_value, key, map) => { - if (key < currentKey) { - map.delete(key); - } - }); - } -}; - -const getKey = (milliseconds: number) => { - return Math.floor(milliseconds / 1000 / INTERVAL); -}; - -const getPreKey = (milliseconds: number) => { - return getKey(milliseconds) - 1; -}; - -const isEntity = (arg: string): arg is EntityType => { - return ( - arg === 'report' || arg === 'report_definition' || arg === 'report_source' - ); -}; - -const buildMetrics = (rollingCounters: CountersType | undefined) => { - if (!rollingCounters) { - rollingCounters = DEFAULT_ROLLING_COUNTER; - } - const basicMetrics = _.merge(rollingCounters, GLOBAL_BASIC_COUNTER); - const overallActionMetrics = { - request_total: 0, - request_count: 0, - success_count: 0, - failed_request_count_system_error: 0, - failed_request_count_user_error: 0, - }; - Object.keys(basicMetrics).forEach((keys) => { - if (isEntity(keys)) { - for (const [action, counters] of Object.entries(basicMetrics[keys])) { - overallActionMetrics.request_count += counters?.count || 0; - overallActionMetrics.request_total += counters?.total || 0; - overallActionMetrics.failed_request_count_system_error += - counters?.system_error || 0; - overallActionMetrics.failed_request_count_user_error += - counters?.user_error || 0; - } - } - }); - overallActionMetrics.success_count = - overallActionMetrics.request_count - - (overallActionMetrics.failed_request_count_system_error + - overallActionMetrics.failed_request_count_user_error); - - return { ...basicMetrics, ...overallActionMetrics }; -}; - -const updateCounters = ( - entity: EntityType, - action: ActionType, - counter: CountersNameType, - rollingCounter: CountersType, - count: number, - reportMetadata?: ReportSchemaType -) => { - // update usage metrics - if (reportMetadata) { - const { - report_definition: { - report_params: { - report_source: source, - core_params: { report_format: format }, - }, - }, - } = reportMetadata; - - // @ts-ignore - rollingCounter[source.toLowerCase().replace(' ', '_')][format]['download'][ - counter - ] += count; - // update basic counter for total request count - if (counter === 'count') { - //@ts-ignore - GLOBAL_BASIC_COUNTER[source.toLowerCase().replace(' ', '_')][format][ - 'download' - ]['total']++; - } - } else { - // update action metric, per API - // @ts-ignore - rollingCounter[entity][action][counter] += count; - if (counter === 'count') { - // @ts-ignore - GLOBAL_BASIC_COUNTER[entity][action]['total']++; - } - } - return rollingCounter; -}; diff --git a/dashboards-reports/server/routes/utils/savedSearchReportHelper.ts b/dashboards-reports/server/routes/utils/savedSearchReportHelper.ts deleted file mode 100644 index ce05b412..00000000 --- a/dashboards-reports/server/routes/utils/savedSearchReportHelper.ts +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - buildRequestBody, - convertToCSV, - getOpenSearchData, - getSelectedFields, - metaData, -} from './dataReportHelpers'; -import { - ILegacyClusterClient, - ILegacyScopedClusterClient, - Logger, -} from '../../../../../src/core/server'; -import { getFileName, callCluster } from './helpers'; -import { CreateReportResultType } from './types'; -import { RequestParams } from '@elastic/elasticsearch'; -import esb from 'elastic-builder'; - -/** - * Specify how long scroll context should be maintained for scrolled search - */ -const scrollTimeout = '1m'; - -export async function createSavedSearchReport( - report: any, - client: ILegacyClusterClient | ILegacyScopedClusterClient, - dateFormat: string, - csvSeparator: string, - isScheduledTask: boolean = true, - logger: Logger -): Promise { - const params = report.report_definition.report_params; - const reportFormat = params.core_params.report_format; - const reportName = params.report_name; - - await populateMetaData(client, report, isScheduledTask, logger); - const data = await generateReportData( - client, - params.core_params, - dateFormat, - csvSeparator, - isScheduledTask, - logger - ); - - const curTime = new Date(); - const timeCreated = curTime.valueOf(); - const fileName = getFileName(reportName, curTime) + '.' + reportFormat; - return { - timeCreated, - dataUrl: data, - fileName, - }; -} - -/** - * Populate parameters and saved search info related to meta data object. - * @param client OpenSearch client - * @param report Report input - */ -async function populateMetaData( - client: ILegacyClusterClient | ILegacyScopedClusterClient, - report: any, - isScheduledTask: boolean, - logger: Logger -) { - metaData.saved_search_id = - report.report_definition.report_params.core_params.saved_search_id; - metaData.report_format = - report.report_definition.report_params.core_params.report_format; - metaData.start = report.time_from; - metaData.end = report.time_to; - - // Get saved search info - let resIndexPattern: any = {}; - const ssParams = { - index: '.kibana', - id: 'search:' + metaData.saved_search_id, - }; - const ssInfos = await callCluster(client, 'get', ssParams, isScheduledTask); - - metaData.sorting = ssInfos._source.search.sort; - metaData.type = ssInfos._source.type; - metaData.searchSourceJSON = - ssInfos._source.search.kibanaSavedObjectMeta.searchSourceJSON; - - // Get the list of selected columns in the saved search.Otherwise select all the fields under the _source - await getSelectedFields(ssInfos._source.search.columns); - - // Get index name - for (const item of ssInfos._source.references) { - if (item.name === JSON.parse(metaData.searchSourceJSON).indexRefName) { - // Get index-pattern information - const indexPattern = await callCluster( - client, - 'get', - { - index: '.kibana', - id: 'index-pattern:' + item.id, - }, - isScheduledTask - ); - resIndexPattern = indexPattern._source['index-pattern']; - metaData.paternName = resIndexPattern.title; - (metaData.timeFieldName = resIndexPattern.timeFieldName), - (metaData.fields = resIndexPattern.fields); // Get all fields - // Getting fields of type Date - const dateFields = []; - for (const item of JSON.parse(metaData.fields)) { - if (item.type === 'date') { - dateFields.push(item.name); - } - } - metaData.dateFields = dateFields; - } - } -} - -/** - * Generate CSV data by query and convert OpenSearch data set. - * @param client OpenSearch client - * @param limit limit size of result data set - */ -async function generateReportData( - client: ILegacyClusterClient | ILegacyScopedClusterClient, - params: any, - dateFormat: string, - csvSeparator: string, - isScheduledTask: boolean, - logger: Logger -) { - let opensearchData: any = {}; - const arrayHits: any = []; - const report = { _source: metaData }; - const indexPattern: string = report._source.paternName; - const maxResultSize: number = await getMaxResultSize(); - const opensearchCount = await getOpenSearchDataSize(); - - const total = Math.min(opensearchCount.count, params.limit); - if (total === 0) { - return ''; - } - - const reqBody = buildRequestBody(report, 0); - logger.info( - `[Reporting csv module] DSL request body: ${JSON.stringify(reqBody)}` - ); - if (total > maxResultSize) { - await getOpenSearchDataByScroll(); - } else { - await getOpenSearchDataBySearch(); - } - return convertOpenSearchDataToCsv(); - - // Fetch OpenSearch query max size windows to decide search or scroll - async function getMaxResultSize() { - const settings = await callCluster( - client, - 'indices.getSettings', - { - index: indexPattern, - includeDefaults: true, - }, - isScheduledTask - ); - - let maxResultSize = Number.MAX_SAFE_INTEGER; - for (let indexName in settings) { - // The location of max result window differs if default overridden. - maxResultSize = Math.min( - maxResultSize, - settings[indexName].settings.index.max_result_window || - settings[indexName].defaults.index.max_result_window - ); - } - return maxResultSize; - } - - // Build the OpenSearch Count query to count the size of result - async function getOpenSearchDataSize() { - const countReq = buildRequestBody(report, 1); - return await callCluster( - client, - 'count', - { - index: indexPattern, - body: countReq, - }, - isScheduledTask - ); - } - - async function getOpenSearchDataByScroll() { - const searchParams: RequestParams.Search = { - index: report._source.paternName, - scroll: scrollTimeout, - body: reqBody, - size: maxResultSize, - }; - // Open scroll context by fetching first batch - opensearchData = await callCluster( - client, - 'search', - searchParams, - isScheduledTask - ); - arrayHits.push(opensearchData.hits); - - // Start scrolling till the end - const nbScroll = Math.floor(total / maxResultSize); - for (let i = 0; i < nbScroll; i++) { - const resScroll = await callCluster( - client, - 'scroll', - { - scrollId: opensearchData._scroll_id, - scroll: scrollTimeout, - }, - isScheduledTask - ); - if (Object.keys(resScroll.hits.hits).length > 0) { - arrayHits.push(resScroll.hits); - } - } - - // Clear scroll context - await callCluster( - client, - 'clearScroll', - { - scrollId: opensearchData._scroll_id, - }, - isScheduledTask - ); - } - - async function getOpenSearchDataBySearch() { - const searchParams: RequestParams.Search = { - index: report._source.paternName, - body: reqBody, - size: total, - }; - - opensearchData = await callCluster( - client, - 'search', - searchParams, - isScheduledTask - ); - - arrayHits.push(opensearchData.hits); - } - - // Parse OpenSearch data and convert to CSV - async function convertOpenSearchDataToCsv() { - const dataset: any = []; - dataset.push(getOpenSearchData(arrayHits, report, params, dateFormat)); - return await convertToCSV(dataset, csvSeparator); - } -} diff --git a/dashboards-reports/server/routes/utils/types.ts b/dashboards-reports/server/routes/utils/types.ts deleted file mode 100644 index 3c589466..00000000 --- a/dashboards-reports/server/routes/utils/types.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export interface CreateReportResultType { - timeCreated: number; - dataUrl: string; - fileName: string; -} - -type ReportSourceType = 'dashboard' | 'visualization' | 'saved_search' | 'notebook'; -type ReportFormatType = 'pdf' | 'png' | 'csv'; -type UsageActionType = 'download'; -export type EntityType = 'report' | 'report_definition' | 'report_source'; - -export type CountersNameType = - | 'count' - | 'system_error' - | 'user_error' - | 'total'; -export type ActionType = - | 'info' - | 'list' - | 'delete' - | 'create' - | 'download' - | 'update' - | 'create_from_definition'; - -export type CountersType = ActionCountersType & UsageCountersType; - -type ActionCountersType = { - [entity in EntityType]: { - [action in ActionType]?: { - [counter in CountersNameType]?: number; - }; - }; -}; - -type UsageCountersType = { - [source in ReportSourceType]: { - [format in ReportFormatType]?: { - [action in UsageActionType]: { - [counter in CountersNameType]?: number; - }; - }; - }; -}; diff --git a/dashboards-reports/server/routes/utils/visual_report/footer_template.html b/dashboards-reports/server/routes/utils/visual_report/footer_template.html deleted file mode 100644 index 6fc56f8c..00000000 --- a/dashboards-reports/server/routes/utils/visual_report/footer_template.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
-
-
-
diff --git a/dashboards-reports/server/routes/utils/visual_report/header_template.html b/dashboards-reports/server/routes/utils/visual_report/header_template.html deleted file mode 100644 index 9796c499..00000000 --- a/dashboards-reports/server/routes/utils/visual_report/header_template.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
-
-
-
diff --git a/dashboards-reports/server/routes/utils/visual_report/style.css b/dashboards-reports/server/routes/utils/visual_report/style.css deleted file mode 100644 index 58628427..00000000 --- a/dashboards-reports/server/routes/utils/visual_report/style.css +++ /dev/null @@ -1,211 +0,0 @@ -html, -body { - margin: 0; - padding: 0; -} - -/* nice padding + matches Kibana default UI colors you could also set this to inherit if - the wrapper gets inserted inside a kibana section. I might also remove the manual text color here as well, potentially */ -.reportWrapper { - padding: 8px; - background-color: #fafbfd; -} - -/* Notice that I'm using an ID of #reportingHeader, and #reportingFooter, instead of a classname (.reportingHeader, .reportingFooter). This is - in order to force specificity here higher in case any other styles would conflict */ -#reportingHeader, -#reportingFooter { - font-family: 'Inter UI', -apple-system, BlinkMacSystemFont, 'Segoe UI', - Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol'; - background-color: #fff; - border: 1px solid #d3dae6; - box-shadow: 0 2px 2px -1px rgba(152, 162, 179, 0.3), - 0 1px 5px -2px rgba(152, 162, 179, 0.3); - border-radius: 4px; - padding: 1em; - margin-bottom: 1em; -} - -#reportingFooter { - margin-top: 1em; -} - -#reportingHeader p, -#reportingFooter p { - max-width: 960px; -} - -/* Adjust the margin when the header is the first item */ -#reportingHeader h1:first-child, -#reportingFooter h1:first-child, -#reportingHeader h2:first-child, -#reportingFooter h2:first-child, -#reportingHeader h3:first-child, -#reportingFooter h3:first-child, -#reportingHeader h4:first-child, -#reportingFooter h4:first-child, -#reportingHeader h5:first-child, -#reportingFooter h5:first-child, -#reportingHeader h6:first-child, -#reportingFooter h6:first-child { - margin-top: 0.25em; -} - -/* nicer list styles */ -#reportingHeader ul, -#reportingFooter ul, -#reportingHeader ol, -#reportingFooter ol { - max-width: 70rem; - margin-bottom: 1em; -} - -#reportingHeader ul li, -#reportingFooter ul li, -#reportingHeader ol li, -#reportingFooter ol li { - margin-bottom: 0.25em; - margin-left: -0.5em; - padding-left: 0.25em; -} - -#reportingHeader ul, -#reportingFooter ul { - list-style-type: disc; -} - -/* here we explicitly set nested paragraphs inside lists to inherit their styles from the list, in case markdown does funky things */ -#reportingHeader ul p, -#reportingFooter ul p, -#reportingHeader ol p, -#reportingFooter ol p { - font-family: inherit; - font-size: inherit; - font-weight: inherit; - /* We only inherit vertical spacing, not horizontal */ - margin-top: inherit; - margin-bottom: inherit; -} - -