diff --git a/changelogs/fragments/6948.yml b/changelogs/fragments/6948.yml new file mode 100644 index 000000000000..8b76f5e39105 --- /dev/null +++ b/changelogs/fragments/6948.yml @@ -0,0 +1,2 @@ +fix: +- Fix web log sample visualization & vis-builder not rendering with data source issue ([#6948](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6948)) \ No newline at end of file diff --git a/src/plugins/data_explorer/public/components/app.tsx b/src/plugins/data_explorer/public/components/app.tsx index ff6b5931a404..6b19413d17e3 100644 --- a/src/plugins/data_explorer/public/components/app.tsx +++ b/src/plugins/data_explorer/public/components/app.tsx @@ -3,34 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; +import React from 'react'; import { AppMountParameters } from '../../../../core/public'; import { useView } from '../utils/use'; import { AppContainer } from './app_container'; -import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; -import { DataExplorerServices } from '../types'; -import { syncQueryStateWithUrl } from '../../../data/public'; export const DataExplorerApp = ({ params }: { params: AppMountParameters }) => { const { view } = useView(); - const { - services: { - data: { query }, - osdUrlStateStorage, - }, - } = useOpenSearchDashboards(); - const { pathname } = useLocation(); - - useEffect(() => { - // syncs `_g` portion of url with query services - const { stop } = syncQueryStateWithUrl(query, osdUrlStateStorage); - - return () => stop(); - - // this effect should re-run when pathname is changed to preserve querystring part, - // so the global state is always preserved - }, [query, osdUrlStateStorage, pathname]); - return ; }; diff --git a/src/plugins/data_explorer/public/components/app_container.tsx b/src/plugins/data_explorer/public/components/app_container.tsx index 529829140057..bf4a02bd223b 100644 --- a/src/plugins/data_explorer/public/components/app_container.tsx +++ b/src/plugins/data_explorer/public/components/app_container.tsx @@ -10,51 +10,60 @@ import { AppMountParameters } from '../../../../core/public'; import { Sidebar } from './sidebar'; import { NoView } from './no_view'; import { View } from '../services/view_service/view'; +import { shallowEqual } from '../utils/use/shallow_equal'; import './app_container.scss'; -export const AppContainer = ({ view, params }: { view?: View; params: AppMountParameters }) => { - const isMobile = useIsWithinBreakpoints(['xs', 's', 'm']); - // TODO: Make this more robust. - if (!view) { - return ; - } +export const AppContainer = React.memo( + ({ view, params }: { view?: View; params: AppMountParameters }) => { + const isMobile = useIsWithinBreakpoints(['xs', 's', 'm']); + // TODO: Make this more robust. + if (!view) { + return ; + } - const { Canvas, Panel, Context } = view; + const { Canvas, Panel, Context } = view; - const MemoizedPanel = memo(Panel); - const MemoizedCanvas = memo(Canvas); + const MemoizedPanel = memo(Panel); + const MemoizedCanvas = memo(Canvas); - // Render the application DOM. - return ( - - {/* TODO: improve fallback state */} - Loading...}> - - - {(EuiResizablePanel, EuiResizableButton) => ( - <> - - - - - - + // Render the application DOM. + return ( + + {/* TODO: improve fallback state */} + Loading...}> + + + {(EuiResizablePanel, EuiResizableButton) => ( + <> + + + + + + - - - - - - - )} - - - - - ); -}; + + + + + + + )} + + + + + ); + }, + (prevProps, nextProps) => { + return ( + prevProps.view === nextProps.view && + shallowEqual(prevProps.params, nextProps.params, ['history']) + ); + } +); diff --git a/src/plugins/data_explorer/public/utils/use/shallow_equal.test.ts b/src/plugins/data_explorer/public/utils/use/shallow_equal.test.ts new file mode 100644 index 000000000000..d30bb2ffd3db --- /dev/null +++ b/src/plugins/data_explorer/public/utils/use/shallow_equal.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { shallowEqual } from './shallow_equal'; + +describe('shallowEqual', () => { + it('should return true for equal objects without ignored keys', () => { + const obj1 = { a: 1, b: 2, c: 3 }; + const obj2 = { a: 1, b: 2, c: 3 }; + const ignoreKeys = []; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(true); + }); + + it('should return false for objects with different values', () => { + const obj1 = { a: 1, b: 2, c: 3 }; + const obj2 = { a: 1, b: 2, c: 4 }; + const ignoreKeys = []; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(false); + }); + + it('should return false for objects with different keys', () => { + const obj1 = { a: 1, b: 2 }; + const obj2 = { a: 1, b: 2, c: 3 }; + const ignoreKeys = []; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(false); + }); + + it('should return true for objects with different values but ignored', () => { + const obj1 = { a: 1, b: 2, c: 3 }; + const obj2 = { a: 1, b: 2, c: 4 }; + const ignoreKeys = ['c']; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(true); + }); + + it('should return true for objects with different keys but ignored', () => { + const obj1 = { a: 1, b: 2 }; + const obj2 = { a: 1, b: 2, c: 4 }; + const ignoreKeys = ['c']; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(true); + }); +}); diff --git a/src/plugins/data_explorer/public/utils/use/shallow_equal.ts b/src/plugins/data_explorer/public/utils/use/shallow_equal.ts new file mode 100644 index 000000000000..734d5b5cf64c --- /dev/null +++ b/src/plugins/data_explorer/public/utils/use/shallow_equal.ts @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// A simple shallow equal function that can ignore specified keys +export function shallowEqual(object1: any, object2: any, ignoreKeys: any) { + const keys1 = Object.keys(object1).filter((key) => !ignoreKeys.includes(key)); + const keys2 = Object.keys(object2).filter((key) => !ignoreKeys.includes(key)); + + if (keys1.length !== keys2.length) { + return false; + } + + for (const key of keys1) { + if (object1[key] !== object2[key]) { + return false; + } + } + + return true; +} diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index 9da9704f32a7..e3a84ae84638 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -9,6 +9,7 @@ import { debounceTime } from 'rxjs/operators'; import { i18n } from '@osd/i18n'; import { useEffect } from 'react'; import { cloneDeep } from 'lodash'; +import { useLocation } from 'react-router-dom'; import { RequestAdapter } from '../../../../../inspector/public'; import { DiscoverViewServices } from '../../../build_services'; import { search } from '../../../../../data/public'; @@ -31,6 +32,7 @@ import { getResponseInspectorStats, } from '../../../opensearch_dashboards_services'; import { SEARCH_ON_PAGE_LOAD_SETTING } from '../../../../common'; +import { syncQueryStateWithUrl } from '../../../../../data/public'; export enum ResultStatus { UNINITIALIZED = 'uninitialized', @@ -68,11 +70,19 @@ export type RefetchSubject = Subject; * }, [data$]); */ export const useSearch = (services: DiscoverViewServices) => { + const { pathname } = useLocation(); const initalSearchComplete = useRef(false); const [savedSearch, setSavedSearch] = useState(undefined); const { savedSearch: savedSearchId, sort, interval } = useSelector((state) => state.discover); - const { data, filterManager, getSavedSearchById, core, toastNotifications, chrome } = services; const indexPattern = useIndexPattern(services); + const { + data, + filterManager, + getSavedSearchById, + core, + toastNotifications, + osdUrlStateStorage, + } = services; const timefilter = data.query.timefilter.timefilter; const fetchStateRef = useRef<{ abortController: AbortController | undefined; @@ -309,6 +319,16 @@ export const useSearch = (services: DiscoverViewServices) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [getSavedSearchById, savedSearchId]); + useEffect(() => { + // syncs `_g` portion of url with query services + const { stop } = syncQueryStateWithUrl(data.query, osdUrlStateStorage); + + return () => stop(); + + // this effect should re-run when pathname is changed to preserve querystring part, + // so the global state is always preserved + }, [data.query, osdUrlStateStorage, pathname]); + return { data$, refetch$, diff --git a/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts index d2699128abd5..21167a761aea 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts @@ -398,7 +398,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Line) Avg bytes over time', uiStateJSON: '{}', @@ -408,13 +408,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '39b5bd70-eb7b-11ed-8e00-17d7d50cd7b2', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzE2LDFd', @@ -525,7 +519,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Area) Stacked extensions over time', uiStateJSON: '{}', @@ -535,13 +529,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'c0ba29f0-eb8f-11ed-8e00-17d7d50cd7b2', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzIyLDFd', @@ -652,7 +640,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Vertical Bar) Stacked responses over time', uiStateJSON: '{}', @@ -662,13 +650,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '23a5de70-eb99-11ed-8e00-17d7d50cd7b2', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzI4LDFd', @@ -780,7 +762,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Horizontal Bar) Top destination count', uiStateJSON: '{}', @@ -790,13 +772,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '08741f50-2275-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzM0LDFd', @@ -889,7 +865,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Heatmap) Source vs OS', uiStateJSON: '{}', @@ -899,13 +875,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '3d034700-227f-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzM5LDFd', @@ -953,7 +923,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Table) Bytes by request stats summary', uiStateJSON: '{"vis":{"sortColumn":{"colIndex":0,"direction":"asc"}}}', @@ -963,13 +933,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'f8df8de0-22a6-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzQyLDFd', @@ -1061,7 +1025,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Metric) Unique visitors', uiStateJSON: '{}', @@ -1071,13 +1035,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '104396f0-22a4-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzQ3LDFd', @@ -1170,7 +1128,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Pie) Visitors by OS', uiStateJSON: '{}', @@ -1180,13 +1138,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '7fd12620-2a44-11ee-92de-ad1b6a4928e5', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzUyLDFd', @@ -1234,7 +1186,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Gauge) Average bytes by extension', uiStateJSON: '{}', @@ -1244,13 +1196,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'f772de50-2281-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzU1LDFd', @@ -1298,7 +1244,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Goal) Average machine RAM', uiStateJSON: '{}', @@ -1308,13 +1254,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '9b0ae760-2282-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzU4LDFd', @@ -1362,7 +1302,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Coordinate Map) Geohash coordinates', uiStateJSON: '{"mapZoom":3,"mapCenter":[35.0659731379842,-107.80640422373408]}', @@ -1372,13 +1312,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'fe07f770-227f-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzYxLDFd', @@ -1388,7 +1322,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Region Map) Destination count', uiStateJSON: '{}', @@ -1398,13 +1332,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'eb268650-2a43-11ee-92de-ad1b6a4928e5', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzYyLDFd', @@ -1490,7 +1418,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Tag Cloud) Requests', uiStateJSON: '{}', @@ -1500,13 +1428,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '81017350-2a45-11ee-92de-ad1b6a4928e5', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzY3LDFd', diff --git a/src/plugins/home/server/services/sample_data/data_sets/util.ts b/src/plugins/home/server/services/sample_data/data_sets/util.ts index 871a9574b591..4b2cc8b56fa3 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/util.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/util.ts @@ -25,7 +25,7 @@ export const appendDataSourceId = (id: string) => { const overrideSavedObjectId = (savedObject: SavedObject, idGenerator: (id: string) => string) => { savedObject.id = idGenerator(savedObject.id); // update reference - if (savedObject.type === 'dashboard') { + if (savedObject.type === 'dashboard' || savedObject.type === 'visualization-visbuilder') { savedObject.references.map((reference) => { if (reference.id) { reference.id = idGenerator(reference.id); @@ -88,7 +88,8 @@ export const getSavedObjectsWithDataSource = ( if ( saveObject.type === 'dashboard' || saveObject.type === 'visualization' || - saveObject.type === 'search' + saveObject.type === 'search' || + saveObject.type === 'visualization-visbuilder' ) { saveObject.attributes.title = saveObject.attributes.title + `_${dataSourceTitle}`; }