Skip to content

Conversation

@jackiehanyang
Copy link
Collaborator

@jackiehanyang jackiehanyang commented Apr 1, 2025

Description

This PR implements the contextual launch feature. It first checks whether an index pattern with a title matching the indices used to create the detector already exists. If it does, the index pattern id is retrieved and included in the Discover page URL. If not, a new index pattern is created using all the indices that were used to create the detector, and its id is then included in the Discover page URL.

Screenshot 2025-04-02 at 16 30 36
Screenshot 2025-04-02 at 16 30 55

Issues Resolved

[List any issues this PR will resolve]

Check List

  • New functionality includes testing.
    • All tests pass
  • New functionality has been documented.
  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Copy link
Collaborator

@kaituo kaituo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write some ITs or UTs to cover your functionality?

Signed-off-by: Jackie Han <[email protected]>
@jackiehanyang
Copy link
Collaborator Author

Can you write some ITs or UTs to cover your functionality?

Added a UT file. There was no existing UT setup for the file I touched, so I originally planned to cover it with an IT. However, after reviewing it, I felt it would be better to have UTs for this feature. So I set up a new file to add unit tests for the AnomalyResultsTable page.

Signed-off-by: Jackie Han <[email protected]>
const startISO = new Date(startTime - TEN_MINUTES_IN_MS).toISOString();
const endISO = new Date(endTime + TEN_MINUTES_IN_MS).toISOString();

const basePath = `${window.location.origin}${window.location.pathname.split('/app/')[0]}`;
Copy link
Member

@kavilla kavilla Apr 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead you could use the core service that is accessible by every plugin getUrlForApp
https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/src/core/public/application/types.ts#L826

so like

window.open(getUrlForApp(def.appId), '_blank', 'noopener, noreferrer')

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion, I didn't know we have such method :)
I would leave it as the current implementation because these two methods work exactly the same, but the one that uses the core service adds extra burden when writing unit tests, as it needs to be mocked.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you plan on mock the services to be super basic, you should be able to use the helper methods which should instantiate all the mocks for those services

https://github.com/opensearch-project/OpenSearch-Dashboards/blob/main/src/core/public/mocks.ts#L200

for example,

import { coreMock } from '../../../../../core/public/mocks';

const startMock = coreMock.createStart();

@kaituo
Copy link
Collaborator

kaituo commented Apr 4, 2025

Test failed:

Test Suites: 1 failed, 1 skipped, 85 passed, 86 of 87 total
Tests: 1 failed, 2 skipped, 441 passed, 444 total
Snapshots: 80 passed, 80 total
Time: 163.372 s
Ran all test suites.

Signed-off-by: Jackie Han <[email protected]>
@jackiehanyang
Copy link
Collaborator Author

Test failed:

Test Suites: 1 failed, 1 skipped, 85 passed, 86 of 87 total Tests: 1 failed, 2 skipped, 441 passed, 444 total Snapshots: 80 passed, 80 total Time: 163.372 s Ran all test suites.

The failed test case is flaky, so I deleted it in the latest revision. I tried to capture the error message in the inner try catch block but sometimes the error message from the outer try catch block is being captured, so it's flaky.

@kaituo
Copy link
Collaborator

kaituo commented Apr 4, 2025

I started a detector with two categorical fields with one local index and one remote index. When clicking the contextual link, I got
Screenshot 2025-04-04 at 1 33 57 PM

please fix the error and add the scenario to your test.

Error getting aggregated anomaly results for detector Yxt_ApYBFppsB-v16WKP:  [1:155] [bool] failed to parse field [filter] 2 [AnomalyDetailsChart.tsx:115](http://localhost:5601/plugin:anomalyDetectionDashboards/plugins/anomaly-detection-dashboards-plugin/public/pages/AnomalyCharts/containers/AnomalyDetailsChart.tsx)
    AnomalyDetailsChart AnomalyDetailsChart.tsx:115
Warning: Each child in a list should have a unique "key" prop. See https://fb.me/react-warning-keys for more information.
    in SpecsParserComponent (created by Connect(SpecsParserComponent))
    in Connect(SpecsParserComponent) (created by Chart)
    in ErrorBoundary (created by Chart)
    in div (created by Chart)
    in Provider (created by Chart)
    in Chart (created by FeatureChart)
    in div (created by FeatureChart)
    in div (created by ContentPanel)
    in div (created by ContentPanel)
    in div (created by EuiPanel)
    in EuiPanel (created by ContentPanel)
    in ContentPanel (created by FeatureChart)
    in FeatureChart
    in Unknown (created by AnomalyHistory)
    in div (created by EuiPanel)
    in EuiPanel (created by AnomalyHistory)
    in div (created by AnomalyHistory)
    in div (created by AnomalyHistory)
    in div
    in div (created by ContentPanel)
    in div (created by ContentPanel)
    in div (created by EuiPanel)
    in EuiPanel (created by ContentPanel)
    in ContentPanel
    in Unknown (created by AnomalyHistory)
    in AnomalyHistory (created by HistoricalDetectorResults)
    in div (created by EuiFlexItem)
    in EuiFlexItem (created by HistoricalDetectorResults)
    in div (created by EuiFlexGroup)
    in EuiFlexGroup (created by HistoricalDetectorResults)
    in div (created by EuiPageBody)
    in EuiPageBody (created by HistoricalDetectorResults)
    in div (created by EuiPage)
    in EuiPage (created by HistoricalDetectorResults)
    in HistoricalDetectorResults (created by Context.Consumer)
    in Route (created by DetectorDetail)
    in Switch (created by DetectorDetail)
    in DetectorDetail (created by Context.Consumer)
    in Route (created by Context.Consumer)
    in Switch (created by Context.Consumer)
    in div (created by EuiPageBody)
    in EuiPageBody (created by Context.Consumer)
    in div (created by EuiPage)
    in EuiPage (created by Context.Consumer)
    in Main (created by Context.Consumer)
    in Route
    in Router (created by HashRouter)
    in HashRouter
    in Provider [react-dom.development.js:88](http://localhost:5601/9007199254740991/bundles/osd-ui-shared-deps/osd-ui-shared-deps/node_modules/react-dom/cjs/react-dom.development.js)

Dashboard log:

Anomaly detector - Unable to search anomaly result StatusCodeError: [x_content_parse_exception] [1:155] [bool] failed to parse field [filter]
    at respond (/Users/kaituo/code/github/OpenSearch-Dashboards/node_modules/elasticsearch/src/lib/transport.js:349:15)
    at checkRespForFailure (/Users/kaituo/code/github/OpenSearch-Dashboards/node_modules/elasticsearch/src/lib/transport.js:306:7)
    at HttpConnector.<anonymous> (/Users/kaituo/code/github/OpenSearch-Dashboards/node_modules/elasticsearch/src/lib/connectors/http.js:173:7)
    at IncomingMessage.wrapper (/Users/kaituo/code/github/OpenSearch-Dashboards/node_modules/lodash/lodash.js:4991:19)
    at IncomingMessage.emit (node:events:529:35)
    at IncomingMessage.emit (node:domain:489:12)
    at endReadableNT (node:internal/streams/readable:1400:12)
    at processTicksAndRejections (node:internal/process/task_queues:82:21) {
  status: 400,
  displayName: 'BadRequest',
  path: '/_plugins/_anomaly_detection/detectors/results/_search',
  query: {},
  body: {
    error: {
      root_cause: [Array],
      type: 'x_content_parse_exception',
      reason: '[1:155] [bool] failed to parse field [filter]',
      caused_by: [Object]
    },
    status: 400
  },
  statusCode: 400,
  response: '{"error":{"root_cause":[{"type":"x_content_parse_exception","reason":"[1:155] [bool] failed to parse field [filter]"}],"type":"x_content_parse_exception","reason":"[1:155] [bool] failed to parse field [filter]","caused_by":{"type":"illegal_argument_exception","reason":"field name is null or empty"}},"status":400}',
  toString: [Function (anonymous)],
  toJSON: [Function (anonymous)]
}
​```

@jackiehanyang
Copy link
Collaborator Author

AnomalyDetailsChart

the error looks like related to AnomalyDetailsChart when rendering the chart as some field value is off instead of contextual launch. But let me look into it.

Signed-off-by: Jackie Han <[email protected]>
@jackiehanyang
Copy link
Collaborator Author

AnomalyDetailsChart

the error looks like related to AnomalyDetailsChart when rendering the chart as some field value is off instead of contextual launch. But let me look into it.

fixed in the new revision, the current implementation works with remote index use case, just needed also update the props name in the parent file when changing the props name. Fixed in the latest revision and added a test case for it

@jackiehanyang jackiehanyang merged commit b853bdf into opensearch-project:main Apr 8, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants