Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Log Explorer] Remove top level tabs #970

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .cypress/integration/1_event_analytics.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ describe('Open flyout for a data row to see details', () => {
});
});

describe('Add/delete/switch explorer top level tabs', () => {
// skip for now due to tab removals
describe.skip('Add/delete/switch explorer top level tabs', () => {
beforeEach(() => {
landOnEventExplorer();
});
Expand Down Expand Up @@ -406,15 +407,15 @@ describe('Live tail stop automatically', () => {
landOnEventExplorer();
});

it('Moving to other tab should stop live tail automatically', () => {
it.skip('Moving to other tab should stop live tail automatically', () => {
clearQuerySearchBoxText('searchAutocompleteTextArea');
cy.get('[data-test-subj="searchAutocompleteTextArea"]').type(TEST_QUERIES[1].query);
cy.get('[data-test-subj=eventLiveTail]').click();
cy.get('[data-test-subj=eventLiveTail__delay10s]').click();
cy.get('.euiToastHeader__title').contains('On').should('exist');
});

it('Add a new tab', () => {
it.skip('Add a new tab', () => {
cy.get('[data-test-subj="eventExplorer__topLevelTabbing"]')
.find('button.euiTab')
.then((lists) => {
Expand All @@ -426,7 +427,7 @@ describe('Live tail stop automatically', () => {
});
});

it('Click to switch to another tab', () => {
it.skip('Click to switch to another tab', () => {
cy.get('[data-test-subj="eventExplorer__addNewTab"]', {
timeout: COMMAND_TIMEOUT_LONG,
}).click();
Expand All @@ -441,7 +442,7 @@ describe('Live tail stop automatically', () => {
.should('have.class', 'euiTab-isSelected');
});

it('Close current selected tab', () => {
it.skip('Close current selected tab', () => {
cy.get('[data-test-subj="eventExplorer__addNewTab"]', {
timeout: COMMAND_TIMEOUT_LONG,
}).click();
Expand Down
3 changes: 3 additions & 0 deletions common/constants/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import { htmlIdGenerator } from '@elastic/eui';
import { ThresholdUnitType } from '../../public/components/event_analytics/explorer/visualizations/config_panel/config_panes/config_controls/config_thresholds';
import { VIS_CHART_TYPES } from './shared';

// URLs
export const EVENT_ANALYTICS_DOCUMENTATION_URL =
'https://opensearch.org/docs/latest/observability-plugin/event-analytics/';
export const OPEN_TELEMETRY_LOG_CORRELATION_LINK =
'https://opentelemetry.io/docs/reference/specification/logs/overview/#log-correlation';
export const LOG_EXPLORER_BASE_PATH = 'observability-logs#/explorer/';
Copy link
Member

@joshuali925 joshuali925 Sep 7, 2023

Choose a reason for hiding this comment

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

use ${observabilityLogsID} instead of observability-logs?


export const RAW_QUERY = 'rawQuery';
export const FINAL_QUERY = 'finalQuery';
export const SELECTED_DATE_RANGE = 'selectedDateRange';
Expand Down
4 changes: 1 addition & 3 deletions common/types/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ export interface IExplorerFields {
}

export interface EmptyTabParams {
tabIds: string[] | undefined;
queries: any | undefined;
explorerData: any | undefined;
tabIds: string[];
}

export interface ILogExplorerProps {
Expand Down
1 change: 0 additions & 1 deletion public/components/common/search/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
EuiBadge,
EuiContextMenuPanel,
EuiToolTip,
EuiCallOut,
} from '@elastic/eui';
import { DatePicker } from './date_picker';
import '@algolia/autocomplete-theme-classic';
Expand Down
21 changes: 3 additions & 18 deletions public/components/event_analytics/explorer/explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import {
DATE_PICKER_FORMAT,
DEFAULT_AVAILABILITY_QUERY,
EVENT_ANALYTICS_DOCUMENTATION_URL,
NEW_TAB,
PATTERNS_EXTRACTOR_REGEX,
PATTERNS_REGEX,
RAW_QUERY,
Expand All @@ -52,7 +51,6 @@ import {
SELECTED_TIMESTAMP,
TAB_CHART_ID,
TAB_CHART_TITLE,
TAB_CREATED_TYPE,
TAB_EVENT_ID,
TAB_EVENT_TITLE,
TIME_INTERVAL_OPTIONS,
Expand Down Expand Up @@ -347,17 +345,6 @@ export const Explorer = ({
}, [appBasedRef.current]);

useEffect(() => {
let objectId;
if (queryRef.current![TAB_CREATED_TYPE] === NEW_TAB || appLogEvents) {
objectId = queryRef.current!.savedObjectId || '';
} else {
objectId = queryRef.current!.savedObjectId || savedObjectId;
}
if (objectId) {
updateTabData(objectId);
} else {
fetchData(startTime, endTime);
}
if (
routerContext &&
routerContext.searchParams.get(CREATE_TAB_PARAM_KEY) === CREATE_TAB_PARAM[TAB_CHART_ID]
Expand All @@ -367,10 +354,8 @@ export const Explorer = ({
}, []);

useEffect(() => {
if (appLogEvents) {
if (savedObjectId) {
updateTabData(savedObjectId);
}
if (savedObjectId) {
updateTabData(savedObjectId);
}
}, [savedObjectId]);

Expand Down Expand Up @@ -642,7 +627,7 @@ export const Explorer = ({
isOverridingTimestamp,
query,
isLiveTailOnRef.current,
isOverridingPattern
isOverridingPattern,
]);

const visualizations: IVisualizationContainerProps = useMemo(() => {
Expand Down
170 changes: 21 additions & 149 deletions public/components/event_analytics/explorer/log_explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,21 @@
* SPDX-License-Identifier: Apache-2.0
*/
/* eslint-disable react-hooks/exhaustive-deps */

import {
EuiIcon,
EuiTabbedContent,
EuiTabbedContentTab,
EuiText,
htmlIdGenerator,
} from '@elastic/eui';
import $ from 'jquery';
import { isEmpty, map } from 'lodash';
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { isEmpty } from 'lodash';
import React, { useContext, useEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { LogExplorerRouterContext } from '..';
import {
APP_ANALYTICS_TAB_ID_REGEX,
CREATE_TAB_PARAM_KEY,
NEW_TAB,
REDIRECT_TAB,
SAVED_OBJECT_ID,
TAB_CHART_ID,
TAB_EVENT_ID,
TAB_ID_TXT_PFX,
TAB_TITLE,
} from '../../../../common/constants/explorer';
import { ILogExplorerProps } from '../../../../common/types/explorer';
import { initializeTabData, removeTabData } from '../../application_analytics/helpers/utils';
import { selectQueryResult } from '../redux/slices/query_result_slice';
import { selectQueries } from '../redux/slices/query_slice';
import { selectQueryTabs, setSelectedQueryTab } from '../redux/slices/query_tab_slice';
import { selectQueryTabs } from '../redux/slices/query_tab_slice';
import { Explorer } from './explorer';

const searchBarConfigs = {
Expand Down Expand Up @@ -60,11 +45,9 @@ export const LogExplorer = ({
}: ILogExplorerProps) => {
const history = useHistory();
const routerContext = useContext(LogExplorerRouterContext);
const dispatch = useDispatch();
const tabIds = useSelector(selectQueryTabs).queryTabIds.filter(
(tabid: string) => !tabid.match(APP_ANALYTICS_TAB_ID_REGEX)
);
const tabNames = useSelector(selectQueryTabs).tabNames;
const queries = useSelector(selectQueries);
const curSelectedTabId = useSelector(selectQueryTabs).selectedQueryTab;
const explorerData = useSelector(selectQueryResult);
Expand All @@ -79,68 +62,12 @@ export const LogExplorer = ({

const [tabCreatedTypes, setTabCreatedTypes] = useState({});

// Append add-new-tab link to the end of the tab list, and remove it once tabs state changes
useEffect(() => {
const newLink = $(
'<a class="linkNewTag" data-test-subj="eventExplorer__addNewTab">+ Add new</a>'
).on('click', () => {
addNewTab(NEW_TAB);
});
$('.queryTabs > .euiTabs').append(newLink);
return () => {
$('.queryTabs > .euiTabs .linkNewTag').remove();
};
}, [tabIds]);

const handleTabClick = (selectedTab: EuiTabbedContentTab) => {
history.replace(`/explorer/${queryRef.current![selectedTab.id][SAVED_OBJECT_ID] || ''}`);
dispatch(setSelectedQueryTab({ tabId: selectedTab.id }));
};

const handleTabClose = (TabIdToBeClosed: string) => {
if (tabIds.length === 1) {
setToast('Cannot close last tab.', 'danger');
return;
}

const index: number = tabIds.indexOf(TabIdToBeClosed);
const curSelectedTab = curSelectedTabIdRef.current;
let newIdToFocus = '';
if (TabIdToBeClosed === curSelectedTab) {
if (index === 0) {
newIdToFocus = tabIds[index + 1];
} else if (index > 0) {
newIdToFocus = tabIds[index - 1];
}
}
removeTabData(dispatch, TabIdToBeClosed, newIdToFocus);
};

const addNewTab = async (where: string) => {
// get a new tabId
const tabId = htmlIdGenerator(TAB_ID_TXT_PFX)();

// create a new tab
await initializeTabData(dispatch, tabId, where);

setTabCreatedTypes((staleState) => {
return {
...staleState,
[tabId]: where,
};
});

return tabId;
};

const dispatchSavedObjectId = async () => {
const emptyTabId = getExistingEmptyTab({
return getExistingEmptyTab({
tabIds: tabIdsRef.current,
queries: queryRef.current,
explorerData: explorerDataRef.current,
});
const newTabId = emptyTabId ? emptyTabId : await addNewTab(REDIRECT_TAB);
return newTabId;
};

useEffect(() => {
Expand All @@ -150,7 +77,6 @@ export const LogExplorer = ({
if (routerContext && routerContext.searchParams.has(CREATE_TAB_PARAM_KEY)) {
// need to wait for current redux event loop to finish
setImmediate(() => {
addNewTab(NEW_TAB);
routerContext.searchParams.delete(CREATE_TAB_PARAM_KEY);
routerContext.routerProps.history.replace({
search: routerContext.searchParams.toString(),
Expand All @@ -159,78 +85,24 @@ export const LogExplorer = ({
}
}, []);

function getQueryTab({
tabTitle,
tabId,
handlesTabClose,
}: {
tabTitle: string;
tabId: string;
handlesTabClose: (TabIdToBeClosed: string) => void;
}) {
return {
id: tabId,
name: (
<>
<EuiText size="s" textAlign="left" color="default">
<span className="tab-title">{tabTitle}</span>
<EuiIcon
type="cross"
onClick={(e) => {
e.stopPropagation();
handlesTabClose(tabId);
}}
data-test-subj="eventExplorer__tabClose"
/>
</EuiText>
</>
),
content: (
<>
<Explorer
key={`explorer_${tabId}`}
pplService={pplService}
dslService={dslService}
tabId={tabId}
savedObjects={savedObjects}
timestampUtils={timestampUtils}
setToast={setToast}
history={history}
notifications={notifications}
savedObjectId={savedObjectId}
tabCreatedTypes={tabCreatedTypes}
curSelectedTabId={curSelectedTabIdRef}
http={http}
searchBarConfigs={searchBarConfigs}
queryManager={queryManager}
/>
</>
),
};
}

const memorizedTabs = useMemo(() => {
const res = map(tabIds, (tabId) => {
return getQueryTab({
tabTitle: tabNames[tabId] || TAB_TITLE,
tabId,
handlesTabClose: handleTabClose,
});
});

return res;
}, [tabIds, tabNames, tabCreatedTypes]);

return (
<>
<EuiTabbedContent
id="queryTabs"
className="queryTabs"
tabs={memorizedTabs}
selectedTab={memorizedTabs.find((tab) => tab.id === curSelectedTabId)}
onTabClick={(selectedTab: EuiTabbedContentTab) => handleTabClick(selectedTab)}
data-test-subj="eventExplorer__topLevelTabbing"
size="s"
<Explorer
key={`explorer_${tabIds[0]}`}
pplService={pplService}
dslService={dslService}
tabId={tabIds[0]}
savedObjects={savedObjects}
timestampUtils={timestampUtils}
setToast={setToast}
history={history}
notifications={notifications}
savedObjectId={savedObjectId}
tabCreatedTypes={tabCreatedTypes}
curSelectedTabId={curSelectedTabIdRef}
http={http}
Copy link
Member

Choose a reason for hiding this comment

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

Do we need http to be passed here can we use import CoreRefs?

Copy link
Collaborator Author

@mengweieric mengweieric Sep 7, 2023

Choose a reason for hiding this comment

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

I just copied the entire component over for tab changes. But to your point, I've created the issue for tracking this as I saw there are around 7 - 8 references in explorer where changes required for this are kinda out of the scope of this PR. Later we can have campaign for this as I feel we need to also refactor some of the components to not
depend on http

searchBarConfigs={searchBarConfigs}
queryManager={queryManager}
/>
</>
);
Expand Down
Loading