mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Remove links to Logs Explorer (#203685)
Resolves https://github.com/elastic/kibana/issues/182229 ## Release Note Remove Logs Explorer ## Summary - Removes the Discover/Logs Explorer tabs in the top nav - Changes all links to Logs Explorer in other applications to Discover - Removes all APIs exposed by Logs Explorer Note: This does not remove Logs Explorer from the codebase. There will be a follow up for that work. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
e8ef186be8
commit
8902f7026c
146 changed files with 535 additions and 6718 deletions
|
@ -38,7 +38,6 @@ enabled:
|
|||
- x-pack/test/apm_api_integration/rules/config.ts
|
||||
- x-pack/test/apm_api_integration/trial/config.ts
|
||||
- x-pack/test/dataset_quality_api_integration/basic/config.ts
|
||||
- x-pack/test/functional/apps/observability_logs_explorer/config.ts
|
||||
- x-pack/test/functional/apps/dataset_quality/config.ts
|
||||
- x-pack/test/functional/apps/slo/embeddables/config.ts
|
||||
- x-pack/test/functional/apps/uptime/config.ts
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
export * from './apm';
|
||||
export * from './dataset_quality';
|
||||
export * from './dataset_quality_details';
|
||||
export * from './logs_explorer';
|
||||
export * from './observability_logs_explorer';
|
||||
export * from './observability_onboarding';
|
||||
export * from './uptime';
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
import type { Filter, TimeRange, Query, AggregateQuery } from '@kbn/es-query';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
export type RefreshInterval = {
|
||||
pause: boolean;
|
||||
value: number;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
export type FilterControls = {
|
||||
namespace?: ListFilterControl;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
export type ListFilterControl = {
|
||||
mode: 'include';
|
||||
values: string[];
|
||||
};
|
||||
|
||||
export const LOGS_EXPLORER_LOCATOR_ID = 'LOGS_EXPLORER_LOCATOR';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
export type DocumentFieldGridColumnOptions = {
|
||||
type: 'document-field';
|
||||
field: string;
|
||||
width?: number;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
export type SmartFieldGridColumnOptions = {
|
||||
type: 'smart-field';
|
||||
smartField: 'content' | 'resource';
|
||||
width?: number;
|
||||
};
|
||||
|
||||
export type GridColumnDisplayOptions = DocumentFieldGridColumnOptions | SmartFieldGridColumnOptions;
|
||||
|
||||
export interface LogsExplorerNavigationParams extends SerializableRecord {
|
||||
/**
|
||||
* Optionally set the time range in the time picker.
|
||||
*/
|
||||
timeRange?: TimeRange;
|
||||
/**
|
||||
* Optionally set the refresh interval.
|
||||
*/
|
||||
refreshInterval?: RefreshInterval;
|
||||
/**
|
||||
* Optionally set a query.
|
||||
*/
|
||||
query?: Query | AggregateQuery;
|
||||
/**
|
||||
* Columns displayed in the table
|
||||
*/
|
||||
columns?: GridColumnDisplayOptions[];
|
||||
/**
|
||||
* Optionally apply free-form filters.
|
||||
*/
|
||||
filters?: Filter[];
|
||||
/**
|
||||
* Optionally apply curated filter controls
|
||||
*/
|
||||
filterControls?: FilterControls;
|
||||
/**
|
||||
* Optionally set chart's breakdown field
|
||||
*/
|
||||
breakdownField?: string;
|
||||
}
|
||||
|
||||
export interface LogsExplorerLocatorParams extends LogsExplorerNavigationParams {
|
||||
/**
|
||||
* Dataset name to be selected.
|
||||
*/
|
||||
dataset?: string;
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
*/
|
||||
|
||||
import { SerializableRecord } from '@kbn/utility-types';
|
||||
import { LogsExplorerNavigationParams } from './logs_explorer';
|
||||
|
||||
// Will become a union once we have more origins
|
||||
export interface ObservabilityLogsExplorerLocationState extends SerializableRecord {
|
||||
|
@ -17,38 +16,5 @@ export interface ObservabilityLogsExplorerLocationState extends SerializableReco
|
|||
};
|
||||
}
|
||||
|
||||
export type DatasetLocatorParams = LogsExplorerNavigationParams &
|
||||
ObservabilityLogsExplorerLocationState;
|
||||
|
||||
// All datasets locator
|
||||
export const ALL_DATASETS_LOCATOR_ID = 'ALL_DATASETS_LOCATOR';
|
||||
|
||||
export type AllDatasetsLocatorParams = DatasetLocatorParams;
|
||||
|
||||
// Single dataset locator
|
||||
export const SINGLE_DATASET_LOCATOR_ID = 'SINGLE_DATASET_LOCATOR';
|
||||
|
||||
export interface SingleDatasetLocatorParams extends DatasetLocatorParams {
|
||||
/**
|
||||
* Integration name to be selected.
|
||||
*/
|
||||
integration?: string;
|
||||
/**
|
||||
* Dataset name to be selected.
|
||||
* ex: system.syslog
|
||||
*/
|
||||
dataset: string;
|
||||
}
|
||||
|
||||
// Data view locator
|
||||
export const OBS_LOGS_EXPLORER_DATA_VIEW_LOCATOR_ID = 'OBS_LOGS_EXPLORER_DATA_VIEW_LOCATOR';
|
||||
|
||||
export interface ObsLogsExplorerDataViewLocatorParams extends DatasetLocatorParams {
|
||||
/**
|
||||
* Data view id to select
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
// To store the last used logs viewer (either of discover or observability-logs-explorer)
|
||||
export const OBS_LOGS_EXPLORER_LOGS_VIEWER_KEY = 'obs-logs-explorer:lastUsedViewer';
|
||||
|
|
|
@ -17,6 +17,5 @@
|
|||
],
|
||||
"kbn_references": [
|
||||
"@kbn/utility-types",
|
||||
"@kbn/es-query",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -502,7 +502,9 @@ export type DataViewSpec = {
|
|||
*/
|
||||
version?: string;
|
||||
/**
|
||||
* Data view title
|
||||
* Contrary to its name, this property sets the index pattern of the data view. (e.g. `logs-*,metrics-*`)
|
||||
*
|
||||
* Use the `name` property instead to set a human readable name for the data view.
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
|
@ -546,7 +548,7 @@ export type DataViewSpec = {
|
|||
*/
|
||||
namespaces?: string[];
|
||||
/**
|
||||
* Name of the data view. Human readable name used to differentiate data view.
|
||||
* Human readable name used to differentiate the data view.
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
|
|
|
@ -110,37 +110,4 @@ describe('DiscoverTopNavInline', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('LogsExplorerTabs', () => {
|
||||
it('should render when showLogsExplorerTabs is true', async () => {
|
||||
const props = getProps();
|
||||
props.stateContainer.customizationContext.inlineTopNav.showLogsExplorerTabs = true;
|
||||
render(
|
||||
<DiscoverMainProvider value={props.stateContainer}>
|
||||
<DiscoverTopNavInline {...props} />
|
||||
</DiscoverMainProvider>
|
||||
);
|
||||
const topNav = screen.queryByTestId('discoverTopNavInline');
|
||||
expect(topNav).not.toBeNull();
|
||||
await waitFor(() => {
|
||||
const logsExplorerTabs = screen.queryByTestId('logsExplorerTabs');
|
||||
expect(logsExplorerTabs).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not render when showLogsExplorerTabs is false', async () => {
|
||||
const props = getProps();
|
||||
render(
|
||||
<DiscoverMainProvider value={props.stateContainer}>
|
||||
<DiscoverTopNavInline {...props} />
|
||||
</DiscoverMainProvider>
|
||||
);
|
||||
const topNav = screen.queryByTestId('discoverTopNavInline');
|
||||
expect(topNav).not.toBeNull();
|
||||
await waitFor(() => {
|
||||
const logsExplorerTabs = screen.queryByTestId('logsExplorerTabs');
|
||||
expect(logsExplorerTabs).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,8 +11,6 @@ import React from 'react';
|
|||
import { EuiHeader, EuiHeaderSection, EuiHeaderSectionItem } from '@elastic/eui';
|
||||
import { TopNavMenuBadges, TopNavMenuItems } from '@kbn/navigation-plugin/public';
|
||||
import { euiThemeVars } from '@kbn/ui-theme';
|
||||
import { LogsExplorerTabs } from '../../../../components/logs_explorer_tabs';
|
||||
import { useDiscoverServices } from '../../../../hooks/use_discover_services';
|
||||
import { useDiscoverTopNav } from './use_discover_topnav';
|
||||
import type { DiscoverStateContainer } from '../../state_management/discover_state';
|
||||
|
||||
|
@ -24,7 +22,6 @@ export const DiscoverTopNavInline = ({
|
|||
hideNavMenuItems?: boolean;
|
||||
}) => {
|
||||
const { customizationContext } = stateContainer;
|
||||
const services = useDiscoverServices();
|
||||
const { topNavBadges, topNavMenu } = useDiscoverTopNav({ stateContainer });
|
||||
|
||||
if (
|
||||
|
@ -39,13 +36,6 @@ export const DiscoverTopNavInline = ({
|
|||
css={{ boxShadow: 'none', backgroundColor: euiThemeVars.euiPageBackgroundColor }}
|
||||
data-test-subj="discoverTopNavInline"
|
||||
>
|
||||
{customizationContext.inlineTopNav.showLogsExplorerTabs && (
|
||||
<EuiHeaderSection>
|
||||
<EuiHeaderSectionItem>
|
||||
<LogsExplorerTabs services={services} selectedTab="discover" />
|
||||
</EuiHeaderSectionItem>
|
||||
</EuiHeaderSection>
|
||||
)}
|
||||
{!hideNavMenuItems && (
|
||||
<EuiHeaderSection side="right" data-test-subj="topNavMenuItems">
|
||||
<EuiHeaderSectionItem>
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { withSuspense } from '@kbn/shared-ux-utility';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export type { LogsExplorerTabsProps } from './logs_explorer_tabs';
|
||||
|
||||
export const LogsExplorerTabs = withSuspense(lazy(() => import('./logs_explorer_tabs')));
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { DISCOVER_APP_ID } from '@kbn/deeplinks-analytics';
|
||||
import {
|
||||
ALL_DATASETS_LOCATOR_ID,
|
||||
OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
} from '@kbn/deeplinks-observability';
|
||||
import { discoverServiceMock } from '../../__mocks__/services';
|
||||
import { LogsExplorerTabs, LogsExplorerTabsProps } from './logs_explorer_tabs';
|
||||
import { DISCOVER_APP_LOCATOR } from '../../../common';
|
||||
|
||||
const mockSetLastUsedViewer = jest.fn();
|
||||
jest.mock('react-use/lib/useLocalStorage', () => {
|
||||
return jest.fn((key: string, _initialValue: string) => {
|
||||
return [undefined, mockSetLastUsedViewer]; // Always use undefined as the initial value
|
||||
});
|
||||
});
|
||||
|
||||
const createMockLocator = (id: string) => ({
|
||||
navigate: jest.fn(),
|
||||
getRedirectUrl: jest.fn().mockReturnValue(id),
|
||||
});
|
||||
|
||||
describe('LogsExplorerTabs', () => {
|
||||
const renderTabs = (selectedTab: LogsExplorerTabsProps['selectedTab'] = 'discover') => {
|
||||
const mockDiscoverLocator = createMockLocator(DISCOVER_APP_LOCATOR);
|
||||
const mockLogsExplorerLocator = createMockLocator(ALL_DATASETS_LOCATOR_ID);
|
||||
const services = {
|
||||
...discoverServiceMock,
|
||||
share: {
|
||||
...discoverServiceMock.share,
|
||||
url: {
|
||||
...discoverServiceMock.share?.url,
|
||||
locators: {
|
||||
get: jest.fn((id) => {
|
||||
switch (id) {
|
||||
case DISCOVER_APP_LOCATOR:
|
||||
return mockDiscoverLocator;
|
||||
case ALL_DATASETS_LOCATOR_ID:
|
||||
return mockLogsExplorerLocator;
|
||||
default:
|
||||
throw new Error(`Unknown locator id: ${id}`);
|
||||
}
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as typeof discoverServiceMock;
|
||||
|
||||
const { unmount } = render(<LogsExplorerTabs services={services} selectedTab={selectedTab} />);
|
||||
|
||||
return {
|
||||
mockDiscoverLocator,
|
||||
mockLogsExplorerLocator,
|
||||
unmount,
|
||||
};
|
||||
};
|
||||
|
||||
const getDiscoverTab = () => screen.getByText('Discover').closest('a')!;
|
||||
const getLogsExplorerTab = () => screen.getByText('Logs Explorer').closest('a')!;
|
||||
|
||||
it('should render properly', () => {
|
||||
const { mockDiscoverLocator, mockLogsExplorerLocator } = renderTabs();
|
||||
expect(getDiscoverTab()).toBeInTheDocument();
|
||||
expect(mockDiscoverLocator.getRedirectUrl).toHaveBeenCalledWith({});
|
||||
expect(getDiscoverTab()).toHaveAttribute('href', DISCOVER_APP_LOCATOR);
|
||||
expect(getLogsExplorerTab()).toBeInTheDocument();
|
||||
expect(mockLogsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith({});
|
||||
expect(getLogsExplorerTab()).toHaveAttribute('href', ALL_DATASETS_LOCATOR_ID);
|
||||
});
|
||||
|
||||
it('should render Discover as the selected tab', async () => {
|
||||
const { mockDiscoverLocator, mockLogsExplorerLocator } = renderTabs();
|
||||
expect(getDiscoverTab()).toHaveAttribute('aria-selected', 'true');
|
||||
await userEvent.click(getDiscoverTab());
|
||||
expect(mockDiscoverLocator.navigate).not.toHaveBeenCalled();
|
||||
expect(getLogsExplorerTab()).toHaveAttribute('aria-selected', 'false');
|
||||
await userEvent.click(getLogsExplorerTab());
|
||||
expect(mockLogsExplorerLocator.navigate).toHaveBeenCalledWith({});
|
||||
});
|
||||
|
||||
it('should render Log Explorer as the selected tab', async () => {
|
||||
const { mockDiscoverLocator, mockLogsExplorerLocator } = renderTabs('logs-explorer');
|
||||
expect(getLogsExplorerTab()).toHaveAttribute('aria-selected', 'true');
|
||||
await userEvent.click(getLogsExplorerTab());
|
||||
expect(mockLogsExplorerLocator.navigate).not.toHaveBeenCalled();
|
||||
expect(getDiscoverTab()).toHaveAttribute('aria-selected', 'false');
|
||||
await userEvent.click(getDiscoverTab());
|
||||
expect(mockDiscoverLocator.navigate).toHaveBeenCalledWith({});
|
||||
});
|
||||
|
||||
it('should update the last used viewer in local storage for selectedTab', async () => {
|
||||
const { unmount } = renderTabs('discover');
|
||||
expect(mockSetLastUsedViewer).toHaveBeenCalledWith(DISCOVER_APP_ID);
|
||||
|
||||
unmount();
|
||||
mockSetLastUsedViewer.mockClear();
|
||||
renderTabs('logs-explorer');
|
||||
expect(mockSetLastUsedViewer).toHaveBeenCalledWith(OBSERVABILITY_LOGS_EXPLORER_APP_ID);
|
||||
});
|
||||
});
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
||||
* Public License v 1"; you may not use this file except in compliance with, at
|
||||
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { EuiTab, EuiTabs, useEuiTheme } from '@elastic/eui';
|
||||
import { DISCOVER_APP_ID } from '@kbn/deeplinks-analytics';
|
||||
import {
|
||||
AllDatasetsLocatorParams,
|
||||
ALL_DATASETS_LOCATOR_ID,
|
||||
OBS_LOGS_EXPLORER_LOGS_VIEWER_KEY,
|
||||
OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
} from '@kbn/deeplinks-observability';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { MouseEvent, useEffect } from 'react';
|
||||
import useLocalStorage from 'react-use/lib/useLocalStorage';
|
||||
import { DiscoverAppLocatorParams, DISCOVER_APP_LOCATOR } from '../../../common';
|
||||
import type { DiscoverServices } from '../../build_services';
|
||||
|
||||
export interface LogsExplorerTabsProps {
|
||||
services: Pick<DiscoverServices, 'share'>;
|
||||
selectedTab: 'discover' | 'logs-explorer';
|
||||
}
|
||||
|
||||
const emptyParams = {};
|
||||
|
||||
export const LogsExplorerTabs = ({ services, selectedTab }: LogsExplorerTabsProps) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const locators = services.share?.url.locators;
|
||||
const discoverLocator = locators?.get<DiscoverAppLocatorParams>(DISCOVER_APP_LOCATOR);
|
||||
const logsExplorerLocator = locators?.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID);
|
||||
const discoverUrl = discoverLocator?.getRedirectUrl(emptyParams);
|
||||
const logsExplorerUrl = logsExplorerLocator?.getRedirectUrl(emptyParams);
|
||||
|
||||
const [lastUsedViewer, setLastUsedViewer] = useLocalStorage<
|
||||
typeof DISCOVER_APP_ID | typeof OBSERVABILITY_LOGS_EXPLORER_APP_ID
|
||||
>(OBS_LOGS_EXPLORER_LOGS_VIEWER_KEY, OBSERVABILITY_LOGS_EXPLORER_APP_ID);
|
||||
|
||||
const navigateToDiscover = createNavigateHandler(() => {
|
||||
if (selectedTab !== 'discover') {
|
||||
discoverLocator?.navigate(emptyParams);
|
||||
}
|
||||
});
|
||||
|
||||
const navigateToLogsExplorer = createNavigateHandler(() => {
|
||||
if (selectedTab !== 'logs-explorer') {
|
||||
logsExplorerLocator?.navigate(emptyParams);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTab === 'discover' && lastUsedViewer !== DISCOVER_APP_ID) {
|
||||
setLastUsedViewer(DISCOVER_APP_ID);
|
||||
}
|
||||
|
||||
if (selectedTab === 'logs-explorer' && lastUsedViewer !== OBSERVABILITY_LOGS_EXPLORER_APP_ID) {
|
||||
setLastUsedViewer(OBSERVABILITY_LOGS_EXPLORER_APP_ID);
|
||||
}
|
||||
}, [setLastUsedViewer, lastUsedViewer, selectedTab]);
|
||||
|
||||
return (
|
||||
<EuiTabs bottomBorder={false} data-test-subj="logsExplorerTabs">
|
||||
<EuiTab
|
||||
isSelected={selectedTab === 'discover'}
|
||||
href={discoverUrl}
|
||||
onClick={navigateToDiscover}
|
||||
css={{ '.euiTab__content': { lineHeight: euiTheme.size.xxxl } }}
|
||||
data-test-subj="discoverTab"
|
||||
>
|
||||
{i18n.translate('discover.logsExplorerTabs.discover', {
|
||||
defaultMessage: 'Discover',
|
||||
})}
|
||||
</EuiTab>
|
||||
<EuiTab
|
||||
isSelected={selectedTab === 'logs-explorer'}
|
||||
href={logsExplorerUrl}
|
||||
onClick={navigateToLogsExplorer}
|
||||
css={{ '.euiTab__content': { lineHeight: euiTheme.size.xxxl } }}
|
||||
data-test-subj="logsExplorerTab"
|
||||
>
|
||||
{i18n.translate('discover.logsExplorerTabs.logsExplorer', {
|
||||
defaultMessage: 'Logs Explorer',
|
||||
})}
|
||||
</EuiTab>
|
||||
</EuiTabs>
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default LogsExplorerTabs;
|
||||
|
||||
const isModifiedEvent = (event: MouseEvent) =>
|
||||
event.metaKey || event.altKey || event.ctrlKey || event.shiftKey;
|
||||
|
||||
const isLeftClickEvent = (event: MouseEvent) => event.button === 0;
|
||||
|
||||
const createNavigateHandler = (onClick: () => void) => (e: MouseEvent) => {
|
||||
if (isModifiedEvent(e) || !isLeftClickEvent(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
onClick();
|
||||
};
|
|
@ -40,5 +40,4 @@ export {
|
|||
type NonPersistedDisplayOptions,
|
||||
} from './embeddable';
|
||||
export { loadSharingDataHelpers } from './utils';
|
||||
export { LogsExplorerTabs, type LogsExplorerTabsProps } from './components/logs_explorer_tabs';
|
||||
export type { DiscoverServices } from './build_services';
|
||||
|
|
|
@ -162,7 +162,6 @@ export const applicationUsageSchema = {
|
|||
monitoring: commonSchema,
|
||||
'observability-log-explorer': commonSchema,
|
||||
'observability-logs-explorer': commonSchema,
|
||||
'last-used-logs-viewer': commonSchema,
|
||||
'observability-overview': commonSchema,
|
||||
observabilityOnboarding: commonSchema,
|
||||
observabilityAIAssistant: commonSchema,
|
||||
|
|
|
@ -5504,137 +5504,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"last-used-logs-viewer": {
|
||||
"properties": {
|
||||
"appId": {
|
||||
"type": "keyword",
|
||||
"_meta": {
|
||||
"description": "The application being tracked"
|
||||
}
|
||||
},
|
||||
"viewId": {
|
||||
"type": "keyword",
|
||||
"_meta": {
|
||||
"description": "Always `main`"
|
||||
}
|
||||
},
|
||||
"clicks_total": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "General number of clicks in the application since we started counting them"
|
||||
}
|
||||
},
|
||||
"clicks_7_days": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "General number of clicks in the application over the last 7 days"
|
||||
}
|
||||
},
|
||||
"clicks_30_days": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "General number of clicks in the application over the last 30 days"
|
||||
}
|
||||
},
|
||||
"clicks_90_days": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "General number of clicks in the application over the last 90 days"
|
||||
}
|
||||
},
|
||||
"minutes_on_screen_total": {
|
||||
"type": "float",
|
||||
"_meta": {
|
||||
"description": "Minutes the application is active and on-screen since we started counting them."
|
||||
}
|
||||
},
|
||||
"minutes_on_screen_7_days": {
|
||||
"type": "float",
|
||||
"_meta": {
|
||||
"description": "Minutes the application is active and on-screen over the last 7 days"
|
||||
}
|
||||
},
|
||||
"minutes_on_screen_30_days": {
|
||||
"type": "float",
|
||||
"_meta": {
|
||||
"description": "Minutes the application is active and on-screen over the last 30 days"
|
||||
}
|
||||
},
|
||||
"minutes_on_screen_90_days": {
|
||||
"type": "float",
|
||||
"_meta": {
|
||||
"description": "Minutes the application is active and on-screen over the last 90 days"
|
||||
}
|
||||
},
|
||||
"views": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"properties": {
|
||||
"appId": {
|
||||
"type": "keyword",
|
||||
"_meta": {
|
||||
"description": "The application being tracked"
|
||||
}
|
||||
},
|
||||
"viewId": {
|
||||
"type": "keyword",
|
||||
"_meta": {
|
||||
"description": "The application view being tracked"
|
||||
}
|
||||
},
|
||||
"clicks_total": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "General number of clicks in the application sub view since we started counting them"
|
||||
}
|
||||
},
|
||||
"clicks_7_days": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "General number of clicks in the active application sub view over the last 7 days"
|
||||
}
|
||||
},
|
||||
"clicks_30_days": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "General number of clicks in the active application sub view over the last 30 days"
|
||||
}
|
||||
},
|
||||
"clicks_90_days": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "General number of clicks in the active application sub view over the last 90 days"
|
||||
}
|
||||
},
|
||||
"minutes_on_screen_total": {
|
||||
"type": "float",
|
||||
"_meta": {
|
||||
"description": "Minutes the application sub view is active and on-screen since we started counting them."
|
||||
}
|
||||
},
|
||||
"minutes_on_screen_7_days": {
|
||||
"type": "float",
|
||||
"_meta": {
|
||||
"description": "Minutes the application is active and on-screen active application sub view over the last 7 days"
|
||||
}
|
||||
},
|
||||
"minutes_on_screen_30_days": {
|
||||
"type": "float",
|
||||
"_meta": {
|
||||
"description": "Minutes the application is active and on-screen active application sub view over the last 30 days"
|
||||
}
|
||||
},
|
||||
"minutes_on_screen_90_days": {
|
||||
"type": "float",
|
||||
"_meta": {
|
||||
"description": "Minutes the application is active and on-screen active application sub view over the last 90 days"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"observability-overview": {
|
||||
"properties": {
|
||||
"appId": {
|
||||
|
|
|
@ -2640,8 +2640,6 @@
|
|||
"discover.logs.popoverAction.filterFor": "Filtrer sur",
|
||||
"discover.logs.popoverAction.filterOut": "Exclure",
|
||||
"discover.logs.popoverAction.openPopover": "Ouvrir la fenêtre contextuelle",
|
||||
"discover.logsExplorerTabs.discover": "Discover",
|
||||
"discover.logsExplorerTabs.logsExplorer": "Explorateur de logs",
|
||||
"discover.noMatchRoute.bannerText": "L'application Discover ne reconnaît pas cet itinéraire : {route}",
|
||||
"discover.noMatchRoute.bannerTitleText": "Page introuvable",
|
||||
"discover.noResults.kqlExamples.combineMultipleText": "Combinaison de plusieurs requêtes avec AND/OR",
|
||||
|
@ -15056,9 +15054,7 @@
|
|||
"xpack.datasetQuality.details.integrationActionsText": "Actions d'intégration",
|
||||
"xpack.datasetQuality.details.integrationnameText": "Intégration",
|
||||
"xpack.datasetQuality.details.integrationVersionText": "Version",
|
||||
"xpack.datasetQuality.details.logsExplorerAriaText": "Explorateur de logs",
|
||||
"xpack.datasetQuality.details.openInDiscoverText": "Ouvrir dans Discover",
|
||||
"xpack.datasetQuality.details.openInLogsExplorerText": "Ouvrir dans l'explorateur de logs",
|
||||
"xpack.datasetQuality.details.overviewPanel.datasetQuality.degradedDocs": "Documents dégradés",
|
||||
"xpack.datasetQuality.details.overviewPanel.datasetQuality.title": "Qualité de l'ensemble de données",
|
||||
"xpack.datasetQuality.details.overviewPanel.documents.size": "Taille",
|
||||
|
@ -20047,7 +20043,6 @@
|
|||
"xpack.fleet.agentLogs.logDisabledCallOutTitle": "La collecte de logs est désactivée",
|
||||
"xpack.fleet.agentLogs.logLevelSelectText": "Niveau du log",
|
||||
"xpack.fleet.agentLogs.oldAgentWarningTitle": "La vue Logs requiert Elastic Agent 7.11 ou une version ultérieure. Pour mettre à niveau un agent, accédez au menu Actions ou {downloadLink} une version plus récente.",
|
||||
"xpack.fleet.agentLogs.openInLogsUiLinkText": "Ouvrir dans l'explorateur de logs",
|
||||
"xpack.fleet.agentLogs.resetLogLevel.errorTitleText": "Erreur lors de la réinitialisation du niveau de logging de l'agent",
|
||||
"xpack.fleet.agentLogs.resetLogLevel.successText": "Réinitialiser le niveau de logging de l'agent pour la politique",
|
||||
"xpack.fleet.agentLogs.resetLogLevelLabelText": "Réinitialiser pour rétablir la politique",
|
||||
|
@ -20279,7 +20274,6 @@
|
|||
"xpack.fleet.appNavigation.settingsLinkText": "Paramètres",
|
||||
"xpack.fleet.appNavigation.uninstallTokensText": "Désinstaller les jetons",
|
||||
"xpack.fleet.appTitle": "Fleet",
|
||||
"xpack.fleet.assets.customLogs.description": "Afficher les données des logs personnalisés dans Logs Explorer",
|
||||
"xpack.fleet.assets.customLogs.name": "Logs",
|
||||
"xpack.fleet.azureArmTemplate.guide.description": "Un modèle Azure Resource Manager (ARM) crée toutes les ressources nécessaires pour évaluer le niveau de sécurité de votre organisation Azure. Suivez les étapes ci-dessous pour lancer le modèle ARM. En savoir plus sur {learnMore}.",
|
||||
"xpack.fleet.azureArmTemplate.guide.learnMoreLinkText": "Azure Resource Manager",
|
||||
|
@ -24696,8 +24690,6 @@
|
|||
"xpack.infra.profiling.threadsInfoPopoverBody": "Visualisez les traces d'appel de profilage regroupées par noms de threads de processus. Cette vue vous permet d'identifier les threads qui consomment le plus de ressources de processeur et d'examiner la pile d'appels de chaque thread. Vous pouvez ainsi identifier rapidement les lignes de codes consommant beaucoup de ressources dans le thread.",
|
||||
"xpack.infra.registerFeatures.infraOpsDescription": "Explorez les indicateurs et logs d'infrastructure pour les serveurs, conteneurs et services courants.",
|
||||
"xpack.infra.registerFeatures.infraOpsTitle": "Indicateurs",
|
||||
"xpack.infra.registerFeatures.logsDescription": "Diffusez les logs en temps réel ou faites défiler les vues d'historique comme sur une console.",
|
||||
"xpack.infra.registerFeatures.logsTitle": "Logs",
|
||||
"xpack.infra.routes.customDashboards": "Les tableaux de bord personnalisés ne sont pas activés",
|
||||
"xpack.infra.sampleDataLinkLabel": "Logs",
|
||||
"xpack.infra.saveDashboardModal.euiIcon.iconWithTooltipLabel": "Icône avec infobulle",
|
||||
|
@ -33849,7 +33841,6 @@
|
|||
"xpack.observability.overview.guidedSetupTourDismissButton": "Rejeter",
|
||||
"xpack.observability.overview.guidedSetupTourTitle": "L'assistant de données est toujours disponible",
|
||||
"xpack.observability.overview.loadingObservability": "Chargement d'Observability",
|
||||
"xpack.observability.overview.logs.appLink": "Essayer Logs Explorer",
|
||||
"xpack.observability.overview.logs.subtitle": "Taux de logs par minute",
|
||||
"xpack.observability.overview.logs.title": "Événements de log",
|
||||
"xpack.observability.overview.logsLabel": "Logs",
|
||||
|
@ -33975,7 +33966,6 @@
|
|||
"xpack.observability.statusVisualization.apm.link": "Ajouter des données",
|
||||
"xpack.observability.statusVisualization.apm.title": "APM",
|
||||
"xpack.observability.statusVisualization.logs.description": "Un monitoring rapide, simple, évolutif et centralisé des logs avec un support technique dédié pour les sources de données les plus communes.",
|
||||
"xpack.observability.statusVisualization.logs.goToAppTitle": "Essayer Logs Explorer",
|
||||
"xpack.observability.statusVisualization.logs.link": "Ajouter des intégrations",
|
||||
"xpack.observability.statusVisualization.logs.title": "Logs",
|
||||
"xpack.observability.statusVisualization.metrics.description": "Diffusez, visualisez et analysez vos indicateurs d'infrastructure.",
|
||||
|
|
|
@ -2639,8 +2639,6 @@
|
|||
"discover.logs.popoverAction.filterFor": "フィルター",
|
||||
"discover.logs.popoverAction.filterOut": "除外",
|
||||
"discover.logs.popoverAction.openPopover": "ポップオーバーを開く",
|
||||
"discover.logsExplorerTabs.discover": "Discover",
|
||||
"discover.logsExplorerTabs.logsExplorer": "ログエクスプローラー",
|
||||
"discover.noMatchRoute.bannerText": "Discoverアプリケーションはこのルート{route}を認識できません",
|
||||
"discover.noMatchRoute.bannerTitleText": "ページが見つかりません",
|
||||
"discover.noResults.kqlExamples.combineMultipleText": "AND/ORを使用して複数のクエリーを結合",
|
||||
|
@ -14921,9 +14919,7 @@
|
|||
"xpack.datasetQuality.details.integrationActionsText": "統合アクション",
|
||||
"xpack.datasetQuality.details.integrationnameText": "統合",
|
||||
"xpack.datasetQuality.details.integrationVersionText": "Version",
|
||||
"xpack.datasetQuality.details.logsExplorerAriaText": "ログエクスプローラー",
|
||||
"xpack.datasetQuality.details.openInDiscoverText": "Discoverで開く",
|
||||
"xpack.datasetQuality.details.openInLogsExplorerText": "ログエクスプローラーで開く",
|
||||
"xpack.datasetQuality.details.overviewPanel.datasetQuality.degradedDocs": "劣化したドキュメント",
|
||||
"xpack.datasetQuality.details.overviewPanel.datasetQuality.title": "データセット品質",
|
||||
"xpack.datasetQuality.details.overviewPanel.documents.size": "サイズ",
|
||||
|
@ -19904,7 +19900,6 @@
|
|||
"xpack.fleet.agentLogs.logDisabledCallOutTitle": "ログ収集は無効です",
|
||||
"xpack.fleet.agentLogs.logLevelSelectText": "ログレベル",
|
||||
"xpack.fleet.agentLogs.oldAgentWarningTitle": "ログの表示には、Elastic Agent 7.11以降が必要です。エージェントをアップグレードするには、[アクション]メニューに移動するか、新しいバージョンを{downloadLink}。",
|
||||
"xpack.fleet.agentLogs.openInLogsUiLinkText": "ログエクスプローラーで開く",
|
||||
"xpack.fleet.agentLogs.resetLogLevel.errorTitleText": "エージェントログレベルのリセットエラー",
|
||||
"xpack.fleet.agentLogs.resetLogLevel.successText": "エージェントログレベルをポリシーにリセット",
|
||||
"xpack.fleet.agentLogs.resetLogLevelLabelText": "ポリシーにリセット",
|
||||
|
@ -20136,7 +20131,6 @@
|
|||
"xpack.fleet.appNavigation.settingsLinkText": "設定",
|
||||
"xpack.fleet.appNavigation.uninstallTokensText": "トークンをアンインストール",
|
||||
"xpack.fleet.appTitle": "Fleet",
|
||||
"xpack.fleet.assets.customLogs.description": "ログエクスプローラーでカスタムログデータを表示",
|
||||
"xpack.fleet.assets.customLogs.name": "ログ",
|
||||
"xpack.fleet.azureArmTemplate.guide.description": "Azure Resource Manager(ARM)テンプレートは、Azure組織のセキュリティ態勢を評価するために必要なすべてのリソースを作成します。以下の手順に従って、ARMテンプレートを起動します。{learnMore}の詳細をご覧ください。",
|
||||
"xpack.fleet.azureArmTemplate.guide.learnMoreLinkText": "Azure Resource Manager",
|
||||
|
@ -24555,8 +24549,6 @@
|
|||
"xpack.infra.profiling.threadsInfoPopoverBody": "プロセススレッド名別にグループ化されたプロファイリングスタックトレースを可視化します。このビューでは、CPUリソースを消費している上位のスレッドを特定し、各スレッドのコールスタックにドリルダウンすることで、スレッド内でリソース消費が多いコードの行をすばやく特定できます。",
|
||||
"xpack.infra.registerFeatures.infraOpsDescription": "共通のサーバー、コンテナー、サービスのインフラストラクチャーメトリックとログを閲覧します。",
|
||||
"xpack.infra.registerFeatures.infraOpsTitle": "メトリック",
|
||||
"xpack.infra.registerFeatures.logsDescription": "ログをリアルタイムでストリームするか、コンソール式の UI で履歴ビューをスクロールします。",
|
||||
"xpack.infra.registerFeatures.logsTitle": "ログ",
|
||||
"xpack.infra.routes.customDashboards": "カスタムダッシュボードは有効ではありません",
|
||||
"xpack.infra.sampleDataLinkLabel": "ログ",
|
||||
"xpack.infra.saveDashboardModal.euiIcon.iconWithTooltipLabel": "ツールチップが表示されるアイコン",
|
||||
|
@ -33710,7 +33702,6 @@
|
|||
"xpack.observability.overview.guidedSetupTourDismissButton": "閉じる",
|
||||
"xpack.observability.overview.guidedSetupTourTitle": "データアシスタントは常に使用できます",
|
||||
"xpack.observability.overview.loadingObservability": "オブザーバビリティを読み込んでいます",
|
||||
"xpack.observability.overview.logs.appLink": "ログエクスプローラーを開く",
|
||||
"xpack.observability.overview.logs.subtitle": "毎分のログレート",
|
||||
"xpack.observability.overview.logs.title": "ログイベント",
|
||||
"xpack.observability.overview.logsLabel": "ログ",
|
||||
|
@ -33837,7 +33828,6 @@
|
|||
"xpack.observability.statusVisualization.apm.link": "データの追加",
|
||||
"xpack.observability.statusVisualization.apm.title": "APM",
|
||||
"xpack.observability.statusVisualization.logs.description": "共通データソースのアウトオブボックスサポートで、一元化されたログ監視の速度、容易性、拡張性を高めます。",
|
||||
"xpack.observability.statusVisualization.logs.goToAppTitle": "ログエクスプローラーを開く",
|
||||
"xpack.observability.statusVisualization.logs.link": "統合の追加",
|
||||
"xpack.observability.statusVisualization.logs.title": "ログ",
|
||||
"xpack.observability.statusVisualization.metrics.description": "インフラストラクチャーメトリックをストリーム、可視化、分析します。",
|
||||
|
|
|
@ -2630,8 +2630,6 @@
|
|||
"discover.logs.popoverAction.filterFor": "筛留",
|
||||
"discover.logs.popoverAction.filterOut": "筛除",
|
||||
"discover.logs.popoverAction.openPopover": "打开弹出框",
|
||||
"discover.logsExplorerTabs.discover": "Discover",
|
||||
"discover.logsExplorerTabs.logsExplorer": "日志浏览器",
|
||||
"discover.noMatchRoute.bannerText": "Discover 应用程序无法识别此路由:{route}",
|
||||
"discover.noMatchRoute.bannerTitleText": "未找到页面",
|
||||
"discover.noResults.kqlExamples.combineMultipleText": "正在用 AND/OR 组合多个请求",
|
||||
|
@ -14652,9 +14650,7 @@
|
|||
"xpack.datasetQuality.details.integrationActionsText": "集成操作",
|
||||
"xpack.datasetQuality.details.integrationnameText": "集成",
|
||||
"xpack.datasetQuality.details.integrationVersionText": "版本",
|
||||
"xpack.datasetQuality.details.logsExplorerAriaText": "日志浏览器",
|
||||
"xpack.datasetQuality.details.openInDiscoverText": "在 Discover 中打开",
|
||||
"xpack.datasetQuality.details.openInLogsExplorerText": "在日志浏览器中打开",
|
||||
"xpack.datasetQuality.details.overviewPanel.datasetQuality.degradedDocs": "已降级文档",
|
||||
"xpack.datasetQuality.details.overviewPanel.datasetQuality.title": "数据集质量",
|
||||
"xpack.datasetQuality.details.overviewPanel.documents.size": "大小",
|
||||
|
@ -19596,7 +19592,6 @@
|
|||
"xpack.fleet.agentLogs.logDisabledCallOutTitle": "日志收集已禁用",
|
||||
"xpack.fleet.agentLogs.logLevelSelectText": "日志级别",
|
||||
"xpack.fleet.agentLogs.oldAgentWarningTitle": "'日志'视图需要 Elastic Agent 7.11 或更高版本。要升级代理,请前往'操作'菜单或{downloadLink}更新的版本。",
|
||||
"xpack.fleet.agentLogs.openInLogsUiLinkText": "在日志浏览器中打开",
|
||||
"xpack.fleet.agentLogs.resetLogLevel.errorTitleText": "重置代理日志记录级别时出错",
|
||||
"xpack.fleet.agentLogs.resetLogLevel.successText": "将代理日志记录级别重置为策略",
|
||||
"xpack.fleet.agentLogs.resetLogLevelLabelText": "重置为策略",
|
||||
|
@ -19827,7 +19822,6 @@
|
|||
"xpack.fleet.appNavigation.settingsLinkText": "设置",
|
||||
"xpack.fleet.appNavigation.uninstallTokensText": "卸载令牌",
|
||||
"xpack.fleet.appTitle": "Fleet",
|
||||
"xpack.fleet.assets.customLogs.description": "在日志浏览器中查看定制日志数据",
|
||||
"xpack.fleet.assets.customLogs.name": "日志",
|
||||
"xpack.fleet.azureArmTemplate.guide.description": "Azure Resource Manager (ARM) 模板将创建所有必要资源来评估您的 Azure 组织的安全态势。请按照以下步骤启动 ARM 模板。详细了解 {learnMore}。",
|
||||
"xpack.fleet.azureArmTemplate.guide.learnMoreLinkText": "Azure 资源管理器",
|
||||
|
@ -24172,8 +24166,6 @@
|
|||
"xpack.infra.profiling.threadsInfoPopoverBody": "可视化按进程线程名称分组的分析堆栈跟踪。此视图有助于您识别消耗 CPU 资源的排名靠前线程,并允许您向下钻取到每个线程的调用堆栈,以便您快速确定线程中的资源密集型代码行。",
|
||||
"xpack.infra.registerFeatures.infraOpsDescription": "浏览常用服务器、容器和服务的基础设施指标和日志。",
|
||||
"xpack.infra.registerFeatures.infraOpsTitle": "指标",
|
||||
"xpack.infra.registerFeatures.logsDescription": "实时流式传输日志或在类似控制台的工具中滚动浏览历史视图。",
|
||||
"xpack.infra.registerFeatures.logsTitle": "日志",
|
||||
"xpack.infra.routes.customDashboards": "未启用定制仪表板",
|
||||
"xpack.infra.sampleDataLinkLabel": "日志",
|
||||
"xpack.infra.saveDashboardModal.euiIcon.iconWithTooltipLabel": "带工具提示的图标",
|
||||
|
@ -33226,7 +33218,6 @@
|
|||
"xpack.observability.overview.guidedSetupTourDismissButton": "关闭",
|
||||
"xpack.observability.overview.guidedSetupTourTitle": "数据助手始终可用",
|
||||
"xpack.observability.overview.loadingObservability": "正在加载可观测性",
|
||||
"xpack.observability.overview.logs.appLink": "显示日志浏览器",
|
||||
"xpack.observability.overview.logs.subtitle": "每分钟日志速率",
|
||||
"xpack.observability.overview.logs.title": "日志事件",
|
||||
"xpack.observability.overview.logsLabel": "日志",
|
||||
|
@ -33353,7 +33344,6 @@
|
|||
"xpack.observability.statusVisualization.apm.link": "添加数据",
|
||||
"xpack.observability.statusVisualization.apm.title": "APM",
|
||||
"xpack.observability.statusVisualization.logs.description": "通过开箱支持常用数据源,实现快速、轻松而可扩展的集中式日志监测。",
|
||||
"xpack.observability.statusVisualization.logs.goToAppTitle": "显示日志浏览器",
|
||||
"xpack.observability.statusVisualization.logs.link": "添加集成",
|
||||
"xpack.observability.statusVisualization.logs.title": "日志",
|
||||
"xpack.observability.statusVisualization.metrics.description": "流式传输、可视化并分析您的基础架构指标。",
|
||||
|
|
|
@ -43,20 +43,6 @@ export const flyoutCancelText = i18n.translate('xpack.datasetQuality.flyoutCance
|
|||
defaultMessage: 'Cancel',
|
||||
});
|
||||
|
||||
export const openInLogsExplorerText = i18n.translate(
|
||||
'xpack.datasetQuality.details.openInLogsExplorerText',
|
||||
{
|
||||
defaultMessage: 'Open in Logs Explorer',
|
||||
}
|
||||
);
|
||||
|
||||
export const logsExplorerAriaText = i18n.translate(
|
||||
'xpack.datasetQuality.details.logsExplorerAriaText',
|
||||
{
|
||||
defaultMessage: 'Logs Explorer',
|
||||
}
|
||||
);
|
||||
|
||||
export const openInDiscoverText = i18n.translate(
|
||||
'xpack.datasetQuality.details.openInDiscoverText',
|
||||
{
|
||||
|
|
|
@ -33,9 +33,7 @@ import {
|
|||
degradedFieldMessageIssueDoesNotExistInLatestIndex,
|
||||
discoverAriaText,
|
||||
fieldIgnoredText,
|
||||
logsExplorerAriaText,
|
||||
openInDiscoverText,
|
||||
openInLogsExplorerText,
|
||||
overviewDegradedFieldsSectionTitle,
|
||||
} from '../../../../common/translations';
|
||||
import { DegradedFieldInfo } from './field_info';
|
||||
|
@ -95,21 +93,11 @@ export default function DegradedFieldFlyout() {
|
|||
{expandedDegradedField} <span style={{ fontWeight: 400 }}>{fieldIgnoredText}</span>
|
||||
</EuiText>
|
||||
</EuiTitle>
|
||||
<EuiToolTip
|
||||
content={
|
||||
redirectLinkProps.isLogsExplorerAvailable
|
||||
? openInLogsExplorerText
|
||||
: openInDiscoverText
|
||||
}
|
||||
>
|
||||
<EuiToolTip content={openInDiscoverText}>
|
||||
<EuiButtonIcon
|
||||
display="base"
|
||||
iconType={
|
||||
redirectLinkProps.isLogsExplorerAvailable ? 'logoObservability' : 'discoverApp'
|
||||
}
|
||||
aria-label={
|
||||
redirectLinkProps.isLogsExplorerAvailable ? logsExplorerAriaText : discoverAriaText
|
||||
}
|
||||
iconType="discoverApp"
|
||||
aria-label={discoverAriaText}
|
||||
size="s"
|
||||
data-test-subj="datasetQualityDetailsDegradedFieldFlyoutTitleLinkToDiscover"
|
||||
{...redirectLinkProps.linkProps}
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import React from 'react';
|
||||
import { openInDiscoverText, openInLogsExplorerText } from '../../../common/translations';
|
||||
import { openInDiscoverText } from '../../../common/translations';
|
||||
import {
|
||||
useDatasetDetailsRedirectLinkTelemetry,
|
||||
useDatasetDetailsTelemetry,
|
||||
|
@ -89,13 +89,9 @@ export function Header() {
|
|||
data-test-subj="datasetQualityDetailsHeaderButton"
|
||||
size="s"
|
||||
{...redirectLinkProps.linkProps}
|
||||
iconType={
|
||||
redirectLinkProps.isLogsExplorerAvailable ? 'logoObservability' : 'discoverApp'
|
||||
}
|
||||
iconType="discoverApp"
|
||||
>
|
||||
{redirectLinkProps.isLogsExplorerAvailable
|
||||
? openInLogsExplorerText
|
||||
: openInDiscoverText}
|
||||
{openInDiscoverText}
|
||||
</EuiButton>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -27,9 +27,7 @@ import { css } from '@emotion/react';
|
|||
import { UnifiedBreakdownFieldSelector } from '@kbn/unified-histogram-plugin/public';
|
||||
import {
|
||||
discoverAriaText,
|
||||
logsExplorerAriaText,
|
||||
openInDiscoverText,
|
||||
openInLogsExplorerText,
|
||||
overviewDegradedDocsText,
|
||||
} from '../../../../../../common/translations';
|
||||
import { DegradedDocsChart } from './degraded_docs_chart';
|
||||
|
@ -133,25 +131,11 @@ export default function DegradedDocs({ lastReloadTime }: { lastReloadTime: numbe
|
|||
onBreakdownFieldChange={breakdown.onChange}
|
||||
/>
|
||||
</EuiSkeletonRectangle>
|
||||
<EuiToolTip
|
||||
content={
|
||||
degradedDocLinkLogsExplorer.isLogsExplorerAvailable
|
||||
? openInLogsExplorerText
|
||||
: openInDiscoverText
|
||||
}
|
||||
>
|
||||
<EuiToolTip content={openInDiscoverText}>
|
||||
<EuiButtonIcon
|
||||
display="base"
|
||||
iconType={
|
||||
degradedDocLinkLogsExplorer.isLogsExplorerAvailable
|
||||
? 'logoObservability'
|
||||
: 'discoverApp'
|
||||
}
|
||||
aria-label={
|
||||
degradedDocLinkLogsExplorer.isLogsExplorerAvailable
|
||||
? logsExplorerAriaText
|
||||
: discoverAriaText
|
||||
}
|
||||
iconType="discoverApp"
|
||||
aria-label={discoverAriaText}
|
||||
size="s"
|
||||
data-test-subj="datasetQualityDetailsLinkToDiscover"
|
||||
{...degradedDocLinkLogsExplorer.linkProps}
|
||||
|
|
|
@ -5,20 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { map } from 'rxjs';
|
||||
import { useMemo } from 'react';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
import { AppStatus } from '@kbn/core-application-browser';
|
||||
import {
|
||||
OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
SINGLE_DATASET_LOCATOR_ID,
|
||||
SingleDatasetLocatorParams,
|
||||
} from '@kbn/deeplinks-observability';
|
||||
import { DiscoverAppLocatorParams, DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common';
|
||||
import { Query, AggregateQuery, buildPhraseFilter } from '@kbn/es-query';
|
||||
import { getRouterLinkProps } from '@kbn/router-utils';
|
||||
import { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { LocatorClient } from '@kbn/shared-ux-prompt-no-data-views-types';
|
||||
import { useKibanaContextForPlugin } from '../utils';
|
||||
import { BasicDataStream, TimeRangeConfig } from '../../common/types';
|
||||
|
@ -38,53 +29,24 @@ export const useRedirectLink = <T extends BasicDataStream>({
|
|||
sendTelemetry: SendTelemetryFn;
|
||||
}) => {
|
||||
const {
|
||||
services: { share, application },
|
||||
services: { share },
|
||||
} = useKibanaContextForPlugin();
|
||||
|
||||
const { from, to } = timeRangeConfig;
|
||||
|
||||
const logsExplorerLocator =
|
||||
share.url.locators.get<SingleDatasetLocatorParams>(SINGLE_DATASET_LOCATOR_ID);
|
||||
|
||||
const isLogsExplorerAppAccessible = useObservable(
|
||||
useMemo(
|
||||
() =>
|
||||
application.applications$.pipe(
|
||||
map(
|
||||
(apps) =>
|
||||
(apps.get(OBSERVABILITY_LOGS_EXPLORER_APP_ID)?.status ?? AppStatus.inaccessible) ===
|
||||
AppStatus.accessible
|
||||
)
|
||||
),
|
||||
[application.applications$]
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
return useMemo<{
|
||||
linkProps: RouterLinkProps;
|
||||
navigate: () => void;
|
||||
isLogsExplorerAvailable: boolean;
|
||||
}>(() => {
|
||||
const isLogsExplorerAvailable =
|
||||
isLogsExplorerAppAccessible && !!logsExplorerLocator && dataStreamStat.type === 'logs';
|
||||
const config = isLogsExplorerAvailable
|
||||
? buildLogsExplorerConfig({
|
||||
locator: logsExplorerLocator,
|
||||
dataStreamStat,
|
||||
query,
|
||||
from,
|
||||
to,
|
||||
breakdownField,
|
||||
})
|
||||
: buildDiscoverConfig({
|
||||
locatorClient: share.url.locators,
|
||||
dataStreamStat,
|
||||
query,
|
||||
from,
|
||||
to,
|
||||
breakdownField,
|
||||
});
|
||||
const config = buildDiscoverConfig({
|
||||
locatorClient: share.url.locators,
|
||||
dataStreamStat,
|
||||
query,
|
||||
from,
|
||||
to,
|
||||
breakdownField,
|
||||
});
|
||||
|
||||
const onClickWithTelemetry = (event: Parameters<RouterLinkProps['onClick']>[0]) => {
|
||||
sendTelemetry();
|
||||
|
@ -104,68 +66,9 @@ export const useRedirectLink = <T extends BasicDataStream>({
|
|||
onClick: onClickWithTelemetry,
|
||||
},
|
||||
navigate: navigateWithTelemetry,
|
||||
isLogsExplorerAvailable,
|
||||
isLogsExplorerAvailable: false,
|
||||
};
|
||||
}, [
|
||||
breakdownField,
|
||||
dataStreamStat,
|
||||
from,
|
||||
to,
|
||||
logsExplorerLocator,
|
||||
query,
|
||||
sendTelemetry,
|
||||
share.url.locators,
|
||||
isLogsExplorerAppAccessible,
|
||||
]);
|
||||
};
|
||||
|
||||
const buildLogsExplorerConfig = <T extends BasicDataStream>({
|
||||
locator,
|
||||
dataStreamStat,
|
||||
query,
|
||||
from,
|
||||
to,
|
||||
breakdownField,
|
||||
}: {
|
||||
locator: LocatorPublic<SingleDatasetLocatorParams>;
|
||||
dataStreamStat: T;
|
||||
query?: Query | AggregateQuery;
|
||||
from: string;
|
||||
to: string;
|
||||
breakdownField?: string;
|
||||
}): {
|
||||
navigate: () => void;
|
||||
routerLinkProps: RouterLinkProps;
|
||||
} => {
|
||||
const params: SingleDatasetLocatorParams = {
|
||||
dataset: dataStreamStat.name,
|
||||
timeRange: {
|
||||
from,
|
||||
to,
|
||||
},
|
||||
integration: dataStreamStat.integration?.name,
|
||||
query,
|
||||
filterControls: {
|
||||
namespace: {
|
||||
mode: 'include',
|
||||
values: [dataStreamStat.namespace],
|
||||
},
|
||||
},
|
||||
breakdownField,
|
||||
};
|
||||
|
||||
const urlToLogsExplorer = locator.getRedirectUrl(params);
|
||||
|
||||
const navigateToLogsExplorer = () => {
|
||||
locator.navigate(params) as Promise<void>;
|
||||
};
|
||||
|
||||
const logsExplorerLinkProps = getRouterLinkProps({
|
||||
href: urlToLogsExplorer,
|
||||
onClick: navigateToLogsExplorer,
|
||||
});
|
||||
|
||||
return { routerLinkProps: logsExplorerLinkProps, navigate: navigateToLogsExplorer };
|
||||
}, [breakdownField, dataStreamStat, from, to, query, sendTelemetry, share.url.locators]);
|
||||
};
|
||||
|
||||
const buildDiscoverConfig = <T extends BasicDataStream>({
|
||||
|
|
|
@ -7,14 +7,9 @@
|
|||
|
||||
import { useCallback } from 'react';
|
||||
import { AggregateQuery, Query } from '@kbn/es-query';
|
||||
import {
|
||||
SINGLE_DATASET_LOCATOR_ID,
|
||||
SingleDatasetLocatorParams,
|
||||
} from '@kbn/deeplinks-observability';
|
||||
import { NavigationSource } from '../services/telemetry';
|
||||
import { useDatasetTelemetry } from './use_dataset_telemetry';
|
||||
import { useDatasetDetailsTelemetry } from './use_dataset_details_telemetry';
|
||||
import { useKibanaContextForPlugin } from '../utils';
|
||||
|
||||
export type SendTelemetryFn =
|
||||
| ReturnType<typeof useDatasetRedirectLinkTelemetry>['sendTelemetry']
|
||||
|
@ -47,27 +42,13 @@ export const useDatasetDetailsRedirectLinkTelemetry = ({
|
|||
navigationSource: NavigationSource;
|
||||
query?: Query | AggregateQuery;
|
||||
}) => {
|
||||
const {
|
||||
services: { share },
|
||||
} = useKibanaContextForPlugin();
|
||||
const logsExplorerLocator =
|
||||
share.url.locators.get<SingleDatasetLocatorParams>(SINGLE_DATASET_LOCATOR_ID);
|
||||
const isLogsExplorer = !!logsExplorerLocator;
|
||||
const { trackDetailsNavigated, navigationTargets } = useDatasetDetailsTelemetry();
|
||||
|
||||
const sendTelemetry = useCallback(() => {
|
||||
const isIgnoredFilter = query ? JSON.stringify(query).includes('_ignored') : false;
|
||||
const target = isLogsExplorer ? navigationTargets.LogsExplorer : navigationTargets.Discover;
|
||||
|
||||
trackDetailsNavigated(target, navigationSource, isIgnoredFilter);
|
||||
}, [
|
||||
query,
|
||||
isLogsExplorer,
|
||||
navigationTargets.LogsExplorer,
|
||||
navigationTargets.Discover,
|
||||
trackDetailsNavigated,
|
||||
navigationSource,
|
||||
]);
|
||||
trackDetailsNavigated(navigationTargets.Discover, navigationSource, isIgnoredFilter);
|
||||
}, [query, navigationTargets.Discover, trackDetailsNavigated, navigationSource]);
|
||||
|
||||
return {
|
||||
sendTelemetry,
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
"@kbn/usage-collection-plugin",
|
||||
"@kbn/rison",
|
||||
"@kbn/task-manager-plugin",
|
||||
"@kbn/core-application-browser",
|
||||
"@kbn/field-utils",
|
||||
"@kbn/logging"
|
||||
],
|
||||
|
|
|
@ -26,11 +26,14 @@ jest.mock('@kbn/logs-shared-plugin/public', () => {
|
|||
LogStream: () => <div />,
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('@kbn/logs-shared-plugin/common', () => {
|
||||
const originalModule = jest.requireActual('@kbn/logs-shared-plugin/common');
|
||||
return {
|
||||
getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({
|
||||
logsLocator: { getRedirectUrl: jest.fn(() => 'https://logs-explorer-redirect-url') },
|
||||
}),
|
||||
...originalModule,
|
||||
getLogsLocatorFromUrlService: jest
|
||||
.fn()
|
||||
.mockReturnValue({ getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') }),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -130,7 +133,7 @@ describe('AgentLogsUI', () => {
|
|||
const result = renderComponent();
|
||||
expect(result.getByTestId('viewInLogsBtn')).toHaveAttribute(
|
||||
'href',
|
||||
`https://logs-explorer-redirect-url`
|
||||
`https://discover-redirect-url`
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import {
|
||||
getLogsLocatorFromUrlService,
|
||||
getTimeRangeStartFromTime,
|
||||
getTimeRangeEndFromTime,
|
||||
} from '@kbn/logs-shared-plugin/common';
|
||||
|
||||
import moment from 'moment';
|
||||
|
||||
|
@ -35,7 +39,7 @@ export const ViewLogsButton: React.FunctionComponent<ViewLogsProps> = ({
|
|||
endTime,
|
||||
}) => {
|
||||
const { share } = useStartServices();
|
||||
const { logsLocator } = getLogsLocatorsFromUrlService(share.url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(share.url);
|
||||
const authz = useAuthz();
|
||||
|
||||
const logsUrl = useMemo(() => {
|
||||
|
@ -44,21 +48,21 @@ export const ViewLogsButton: React.FunctionComponent<ViewLogsProps> = ({
|
|||
const defaultStartTime = getFormattedRange(oneDayAgo);
|
||||
const defaultEndTime = getFormattedRange(now);
|
||||
|
||||
return logsLocator.getRedirectUrl({
|
||||
return logsLocator?.getRedirectUrl({
|
||||
time: endTime ? endTime : defaultEndTime,
|
||||
timeRange: {
|
||||
startTime: startTime ? startTime : defaultStartTime,
|
||||
endTime: endTime ? endTime : defaultEndTime,
|
||||
from: getTimeRangeStartFromTime(startTime ? startTime : defaultStartTime),
|
||||
to: getTimeRangeEndFromTime(endTime ? endTime : defaultEndTime),
|
||||
},
|
||||
filter: logStreamQuery,
|
||||
});
|
||||
}, [endTime, logStreamQuery, logsLocator, startTime]);
|
||||
|
||||
return authz.fleet.readAgents && logsLocator ? (
|
||||
<EuiButton href={logsUrl} iconType="popout" data-test-subj="viewInLogsBtn">
|
||||
return authz.fleet.readAgents && logsUrl ? (
|
||||
<EuiButton href={logsUrl} iconType="discoverApp" data-test-subj="viewInLogsBtn">
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.agentLogs.openInLogsUiLinkText"
|
||||
defaultMessage="Open in Logs Explorer"
|
||||
id="xpack.fleet.agentLogs.openInDiscoverUiLinkText"
|
||||
defaultMessage="Open in Discover"
|
||||
/>
|
||||
</EuiButton>
|
||||
) : null;
|
||||
|
|
|
@ -28,10 +28,12 @@ const mockUseStartServices = useStartServices as jest.Mock;
|
|||
const mockedUseAuthz = useAuthz as jest.Mock;
|
||||
|
||||
jest.mock('@kbn/logs-shared-plugin/common', () => {
|
||||
const originalModule = jest.requireActual('@kbn/logs-shared-plugin/common');
|
||||
return {
|
||||
getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({
|
||||
logsLocator: { getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') },
|
||||
}),
|
||||
...originalModule,
|
||||
getLogsLocatorFromUrlService: jest
|
||||
.fn()
|
||||
.mockReturnValue({ getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') }),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -40,10 +40,12 @@ jest.mock('@kbn/shared-ux-link-redirect-app', () => ({
|
|||
}));
|
||||
|
||||
jest.mock('@kbn/logs-shared-plugin/common', () => {
|
||||
const originalModule = jest.requireActual('@kbn/logs-shared-plugin/common');
|
||||
return {
|
||||
getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({
|
||||
logsLocator: { getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') },
|
||||
}),
|
||||
...originalModule,
|
||||
getLogsLocatorFromUrlService: jest
|
||||
.fn()
|
||||
.mockReturnValue({ getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') }),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import { getLogsLocatorFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
|
||||
import { CustomAssetsAccordion } from './components/custom_assets_accordion';
|
||||
import type { CustomAssetsAccordionProps } from './components/custom_assets_accordion';
|
||||
|
@ -19,14 +19,14 @@ export const CustomLogsAssetsExtension: PackageAssetsComponent = () => {
|
|||
const {
|
||||
share: { url },
|
||||
} = useStartServices();
|
||||
const { logsLocator } = getLogsLocatorsFromUrlService(url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(url)!;
|
||||
|
||||
const views: CustomAssetsAccordionProps['views'] = [
|
||||
{
|
||||
name: i18n.translate('xpack.fleet.assets.customLogs.name', { defaultMessage: 'Logs' }),
|
||||
url: logsLocator.getRedirectUrl({}),
|
||||
description: i18n.translate('xpack.fleet.assets.customLogs.description', {
|
||||
defaultMessage: 'View Custom logs data in Logs Explorer',
|
||||
defaultMessage: 'View custom logs data in Discover',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
|
|
@ -62,10 +62,12 @@ export {
|
|||
|
||||
// Locators
|
||||
export {
|
||||
type LogsLocatorParams,
|
||||
LOGS_LOCATOR_ID,
|
||||
TRACE_LOGS_LOCATOR_ID,
|
||||
NODE_LOGS_LOCATOR_ID,
|
||||
getLogsLocatorsFromUrlService,
|
||||
getLogsLocatorFromUrlService,
|
||||
getTimeRange,
|
||||
getTimeRangeEndFromTime,
|
||||
getTimeRangeStartFromTime,
|
||||
getNodeQuery,
|
||||
getTraceQuery,
|
||||
} from './locators';
|
||||
export type { LogsLocatorParams, NodeLogsLocatorParams, TraceLogsLocatorParams } from './locators';
|
||||
export { createNodeLogsQuery } from './locators/helpers';
|
||||
|
|
|
@ -5,21 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { UrlService } from '@kbn/share-plugin/common/url_service';
|
||||
import { type UrlService } from '@kbn/share-plugin/common/url_service';
|
||||
import { type LogsLocatorParams, LOGS_LOCATOR_ID } from './logs_locator';
|
||||
|
||||
import { LogsLocatorParams, NodeLogsLocatorParams, TraceLogsLocatorParams } from './types';
|
||||
import { LOGS_LOCATOR_ID } from './logs_locator';
|
||||
import { NODE_LOGS_LOCATOR_ID } from './node_logs_locator';
|
||||
import { TRACE_LOGS_LOCATOR_ID } from './trace_logs_locator';
|
||||
|
||||
export const getLogsLocatorsFromUrlService = (urlService: UrlService) => {
|
||||
const logsLocator = urlService.locators.get<LogsLocatorParams>(LOGS_LOCATOR_ID)!;
|
||||
const nodeLogsLocator = urlService.locators.get<NodeLogsLocatorParams>(NODE_LOGS_LOCATOR_ID)!;
|
||||
const traceLogsLocator = urlService.locators.get<TraceLogsLocatorParams>(TRACE_LOGS_LOCATOR_ID)!;
|
||||
|
||||
return {
|
||||
logsLocator,
|
||||
traceLogsLocator,
|
||||
nodeLogsLocator,
|
||||
};
|
||||
};
|
||||
export function getLogsLocatorFromUrlService(urlService: UrlService) {
|
||||
return urlService.locators.get<LogsLocatorParams>(LOGS_LOCATOR_ID);
|
||||
}
|
||||
|
|
|
@ -6,26 +6,29 @@
|
|||
*/
|
||||
|
||||
import moment, { DurationInputObject } from 'moment';
|
||||
import { LogsLocatorParams, NodeLogsLocatorParams, TraceLogsLocatorParams } from './types';
|
||||
import type { LogsLocatorParams } from './logs_locator';
|
||||
|
||||
export const getLogsQuery = (params: LogsLocatorParams) => {
|
||||
const { filter } = params;
|
||||
export interface NodeLogsParams {
|
||||
nodeField: string;
|
||||
nodeId: string;
|
||||
filter?: string;
|
||||
}
|
||||
|
||||
return filter ? { language: 'kuery', query: filter } : undefined;
|
||||
};
|
||||
|
||||
export const createNodeLogsQuery = (params: NodeLogsLocatorParams) => {
|
||||
export const getNodeQuery = (params: NodeLogsParams): LogsLocatorParams['query'] => {
|
||||
const { nodeField, nodeId, filter } = params;
|
||||
|
||||
const nodeFilter = `${nodeField}: ${nodeId}`;
|
||||
return filter ? `(${nodeFilter}) and (${filter})` : nodeFilter;
|
||||
const query = filter ? `(${nodeFilter}) and (${filter})` : nodeFilter;
|
||||
|
||||
return { language: 'kuery', query };
|
||||
};
|
||||
|
||||
export const getNodeQuery = (params: NodeLogsLocatorParams) => {
|
||||
return { language: 'kuery', query: createNodeLogsQuery(params) };
|
||||
};
|
||||
export interface TraceLogsParams {
|
||||
traceId: string;
|
||||
filter?: string;
|
||||
}
|
||||
|
||||
export const getTraceQuery = (params: TraceLogsLocatorParams) => {
|
||||
export const getTraceQuery = (params: TraceLogsParams): LogsLocatorParams['query'] => {
|
||||
const { traceId, filter } = params;
|
||||
|
||||
const traceFilter = `trace.id:"${traceId}" OR (not trace.id:* AND "${traceId}")`;
|
||||
|
@ -36,6 +39,16 @@ export const getTraceQuery = (params: TraceLogsLocatorParams) => {
|
|||
|
||||
const defaultTimeRangeFromPositionOffset: DurationInputObject = { hours: 1 };
|
||||
|
||||
export function getTimeRange(time: number | undefined): LogsLocatorParams['timeRange'] {
|
||||
if (time === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
from: getTimeRangeStartFromTime(time),
|
||||
to: getTimeRangeEndFromTime(time),
|
||||
};
|
||||
}
|
||||
|
||||
export const getTimeRangeStartFromTime = (time: number): string =>
|
||||
moment(time).subtract(defaultTimeRangeFromPositionOffset).toISOString();
|
||||
|
||||
|
|
|
@ -6,13 +6,6 @@
|
|||
*/
|
||||
|
||||
export * from './logs_locator';
|
||||
export * from './trace_logs_locator';
|
||||
export * from './node_logs_locator';
|
||||
export * from './get_logs_locators';
|
||||
|
||||
export type {
|
||||
LogsSharedLocators,
|
||||
LogsLocatorParams,
|
||||
NodeLogsLocatorParams,
|
||||
TraceLogsLocatorParams,
|
||||
} from './types';
|
||||
export * from './helpers';
|
||||
export * from './types';
|
||||
|
|
|
@ -5,34 +5,48 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ALL_DATASETS_LOCATOR_ID, AllDatasetsLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import { LocatorDefinition } from '@kbn/share-plugin/common';
|
||||
import { LocatorClient } from '@kbn/share-plugin/common/url_service';
|
||||
import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public';
|
||||
import type { DataViewSpec } from '@kbn/data-views-plugin/common';
|
||||
|
||||
import { LogsLocatorParams } from './types';
|
||||
import { getLogsQuery, getTimeRangeEndFromTime, getTimeRangeStartFromTime } from './helpers';
|
||||
|
||||
/**
|
||||
* Locator used to link to all log sources in Discover.
|
||||
*/
|
||||
export const LOGS_LOCATOR_ID = 'LOGS_LOCATOR';
|
||||
|
||||
/**
|
||||
* Accepts the same parameters as `DiscoverAppLocatorParams`, but automatically sets the `dataViewSpec` param to all log sources.
|
||||
*/
|
||||
export type LogsLocatorParams = DiscoverAppLocatorParams;
|
||||
|
||||
export class LogsLocatorDefinition implements LocatorDefinition<LogsLocatorParams> {
|
||||
public readonly id = LOGS_LOCATOR_ID;
|
||||
|
||||
constructor(private readonly locators: LocatorClient) {}
|
||||
constructor(
|
||||
private readonly deps: {
|
||||
locators: LocatorClient;
|
||||
getLogSourcesService(): Promise<LogsDataAccessPluginStart['services']['logSourcesService']>;
|
||||
}
|
||||
) {}
|
||||
|
||||
public readonly getLocation = async (params: LogsLocatorParams) => {
|
||||
const allDatasetsLocator =
|
||||
this.locators.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID)!;
|
||||
const { time } = params;
|
||||
return allDatasetsLocator.getLocation({
|
||||
query: getLogsQuery(params),
|
||||
...(time
|
||||
? {
|
||||
timeRange: {
|
||||
from: getTimeRangeStartFromTime(time),
|
||||
to: getTimeRangeEndFromTime(time),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
const discoverAppLocator =
|
||||
this.deps.locators.get<DiscoverAppLocatorParams>('DISCOVER_APP_LOCATOR')!;
|
||||
|
||||
return discoverAppLocator.getLocation({
|
||||
dataViewSpec: params.dataViewSpec ?? (await this.getLogSourcesDataViewSpec()),
|
||||
...params,
|
||||
});
|
||||
};
|
||||
|
||||
private async getLogSourcesDataViewSpec(): Promise<DataViewSpec> {
|
||||
const logSourcesService = await this.deps.getLogSourcesService();
|
||||
const logSources = await logSourcesService.getLogSources();
|
||||
return {
|
||||
title: logSources.map((logSource) => logSource.indexPattern).join(','),
|
||||
timeFieldName: '@timestamp',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
AllDatasetsLocatorParams,
|
||||
ALL_DATASETS_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { LocatorClient, LocatorDefinition } from '@kbn/share-plugin/common/url_service';
|
||||
|
||||
import { NodeLogsLocatorParams } from './types';
|
||||
import { getNodeQuery, getTimeRangeStartFromTime, getTimeRangeEndFromTime } from './helpers';
|
||||
|
||||
export const NODE_LOGS_LOCATOR_ID = 'NODE_LOGS_LOCATOR';
|
||||
|
||||
export class NodeLogsLocatorDefinition implements LocatorDefinition<NodeLogsLocatorParams> {
|
||||
public readonly id = NODE_LOGS_LOCATOR_ID;
|
||||
|
||||
constructor(private readonly locators: LocatorClient) {}
|
||||
|
||||
public readonly getLocation = async (params: NodeLogsLocatorParams) => {
|
||||
const allDatasetsLocator =
|
||||
this.locators.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID)!;
|
||||
const { time } = params;
|
||||
return allDatasetsLocator.getLocation({
|
||||
query: getNodeQuery(params),
|
||||
...(time
|
||||
? {
|
||||
timeRange: {
|
||||
from: getTimeRangeStartFromTime(time),
|
||||
to: getTimeRangeEndFromTime(time),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
};
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ALL_DATASETS_LOCATOR_ID, AllDatasetsLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import { LocatorDefinition } from '@kbn/share-plugin/common';
|
||||
import { LocatorClient } from '@kbn/share-plugin/common/url_service';
|
||||
import { TraceLogsLocatorParams } from './types';
|
||||
|
||||
import { getTraceQuery, getTimeRangeEndFromTime, getTimeRangeStartFromTime } from './helpers';
|
||||
|
||||
export const TRACE_LOGS_LOCATOR_ID = 'TRACE_LOGS_LOCATOR';
|
||||
|
||||
export class TraceLogsLocatorDefinition implements LocatorDefinition<TraceLogsLocatorParams> {
|
||||
public readonly id = TRACE_LOGS_LOCATOR_ID;
|
||||
|
||||
constructor(private readonly locators: LocatorClient) {}
|
||||
|
||||
public readonly getLocation = async (params: TraceLogsLocatorParams) => {
|
||||
const { time } = params;
|
||||
const allDatasetsLocator =
|
||||
this.locators.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID)!;
|
||||
return allDatasetsLocator.getLocation({
|
||||
query: getTraceQuery(params),
|
||||
...(time
|
||||
? {
|
||||
timeRange: {
|
||||
from: getTimeRangeStartFromTime(time),
|
||||
to: getTimeRangeEndFromTime(time),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
};
|
||||
}
|
|
@ -5,33 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SerializableRecord } from '@kbn/utility-types';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { LogViewReference } from '../log_views/types';
|
||||
import { TimeRange } from './time_range';
|
||||
|
||||
export interface LogsLocatorParams extends SerializableRecord {
|
||||
/** Defines log position */
|
||||
time?: number;
|
||||
/**
|
||||
* Optionally set the time range in the time picker.
|
||||
*/
|
||||
timeRange?: TimeRange;
|
||||
filter?: string;
|
||||
logView?: LogViewReference;
|
||||
}
|
||||
|
||||
export interface TraceLogsLocatorParams extends LogsLocatorParams {
|
||||
traceId: string;
|
||||
}
|
||||
|
||||
export interface NodeLogsLocatorParams extends LogsLocatorParams {
|
||||
nodeField: string;
|
||||
nodeId: string;
|
||||
}
|
||||
import type { LogsLocatorParams } from './logs_locator';
|
||||
|
||||
export interface LogsSharedLocators {
|
||||
logsLocator: LocatorPublic<LogsLocatorParams>;
|
||||
nodeLogsLocator: LocatorPublic<NodeLogsLocatorParams>;
|
||||
traceLogsLocator: LocatorPublic<TraceLogsLocatorParams>;
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ type OpenInLogsExplorerButtonProps = Pick<EuiButtonEmptyProps, 'href' | 'flush'
|
|||
const OpenInLogsExplorerButton = ({ testSubject, ...rest }: OpenInLogsExplorerButtonProps) => {
|
||||
return (
|
||||
<EuiButtonEmpty
|
||||
iconType="popout"
|
||||
iconType="discoverApp"
|
||||
data-test-subj={testSubject ?? 'logsSharedOpenInLogsExplorerButton'}
|
||||
{...rest}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.logsShared.openInLogsExplorerButtonText"
|
||||
defaultMessage="Open in Logs Explorer"
|
||||
defaultMessage="Open in Discover"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
);
|
||||
|
|
|
@ -6,11 +6,7 @@
|
|||
*/
|
||||
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import {
|
||||
LogsLocatorDefinition,
|
||||
NodeLogsLocatorDefinition,
|
||||
TraceLogsLocatorDefinition,
|
||||
} from '../common/locators';
|
||||
import { LogsLocatorDefinition } from '../common/locators';
|
||||
import { createLogAIAssistant, createLogsAIAssistantRenderer } from './components/log_ai_assistant';
|
||||
import { createLogsOverview } from './components/logs_overview';
|
||||
import { LogViewsService } from './services/log_views';
|
||||
|
@ -28,24 +24,21 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass {
|
|||
this.logViews = new LogViewsService();
|
||||
}
|
||||
|
||||
public setup(_: LogsSharedClientCoreSetup, pluginsSetup: LogsSharedClientSetupDeps) {
|
||||
public setup(coreSetup: LogsSharedClientCoreSetup, pluginsSetup: LogsSharedClientSetupDeps) {
|
||||
const logViews = this.logViews.setup();
|
||||
|
||||
const logsLocator = pluginsSetup.share.url.locators.create(
|
||||
new LogsLocatorDefinition(pluginsSetup.share.url.locators)
|
||||
);
|
||||
const nodeLogsLocator = pluginsSetup.share.url.locators.create(
|
||||
new NodeLogsLocatorDefinition(pluginsSetup.share.url.locators)
|
||||
);
|
||||
|
||||
const traceLogsLocator = pluginsSetup.share.url.locators.create(
|
||||
new TraceLogsLocatorDefinition(pluginsSetup.share.url.locators)
|
||||
new LogsLocatorDefinition({
|
||||
locators: pluginsSetup.share.url.locators,
|
||||
getLogSourcesService: async () => {
|
||||
const [_, pluginsStart] = await coreSetup.getStartServices();
|
||||
return pluginsStart.logsDataAccess.services.logSourcesService;
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const locators = {
|
||||
logsLocator,
|
||||
nodeLogsLocator,
|
||||
traceLogsLocator,
|
||||
};
|
||||
|
||||
return { logViews, locators };
|
||||
|
|
|
@ -8,9 +8,15 @@
|
|||
import type { ChartsPluginStart } from '@kbn/charts-plugin/public';
|
||||
import type { CoreSetup, CoreStart, Plugin as PluginClass } from '@kbn/core/public';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import type {
|
||||
DataViewsPublicPluginSetup,
|
||||
DataViewsPublicPluginStart,
|
||||
} from '@kbn/data-views-plugin/public';
|
||||
import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public';
|
||||
import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public';
|
||||
import type {
|
||||
LogsDataAccessPluginSetup,
|
||||
LogsDataAccessPluginStart,
|
||||
} from '@kbn/logs-data-access-plugin/public';
|
||||
import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public';
|
||||
import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type { UiActionsStart } from '@kbn/ui-actions-plugin/public';
|
||||
|
@ -36,6 +42,8 @@ export interface LogsSharedClientStartExports {
|
|||
|
||||
export interface LogsSharedClientSetupDeps {
|
||||
share: SharePluginSetup;
|
||||
dataViews: DataViewsPublicPluginSetup;
|
||||
logsDataAccess: LogsDataAccessPluginSetup;
|
||||
}
|
||||
|
||||
export interface LogsSharedClientStartDeps {
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
import { PluginStart as DataViewsPluginStart } from '@kbn/data-views-plugin/server';
|
||||
import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/server';
|
||||
import type { SpacesPluginStart } from '@kbn/spaces-plugin/server';
|
||||
import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/server';
|
||||
import { LogsSharedDomainLibs } from './lib/logs_shared_types';
|
||||
import { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views/types';
|
||||
|
||||
|
@ -32,10 +33,12 @@ export interface LogsSharedPluginStart {
|
|||
}
|
||||
|
||||
export interface LogsSharedServerPluginSetupDeps {
|
||||
share: SharePluginSetup;
|
||||
data: DataPluginSetup;
|
||||
}
|
||||
|
||||
export interface LogsSharedServerPluginStartDeps {
|
||||
share: SharePluginStart;
|
||||
data: DataPluginStart;
|
||||
dataViews: DataViewsPluginStart;
|
||||
logsDataAccess: LogsDataAccessPluginStart;
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
"@kbn/field-formats-plugin",
|
||||
"@kbn/embeddable-plugin",
|
||||
"@kbn/saved-search-plugin",
|
||||
"@kbn/discover-plugin",
|
||||
"@kbn/spaces-plugin",
|
||||
"@kbn/analytics",
|
||||
"@kbn/usage-collection-plugin",
|
||||
|
|
|
@ -21,7 +21,6 @@ import { apiService } from '../../../public/application/lib/api';
|
|||
import { breadcrumbService } from '../../../public/application/lib/breadcrumbs';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { cloudMock } from '@kbn/cloud-plugin/public/mocks';
|
||||
import { OBS_LOGS_EXPLORER_DATA_VIEW_LOCATOR_ID } from '@kbn/deeplinks-observability';
|
||||
|
||||
const data = dataPluginMock.createStartContract();
|
||||
const dataViews = { ...data.dataViews };
|
||||
|
@ -52,7 +51,6 @@ const servicesMock = {
|
|||
const idToUrlMap = {
|
||||
SNAPSHOT_RESTORE_LOCATOR: 'snapshotAndRestoreUrl',
|
||||
DISCOVER_APP_LOCATOR: 'discoverUrl',
|
||||
[OBS_LOGS_EXPLORER_DATA_VIEW_LOCATOR_ID]: 'logsExplorerUrl',
|
||||
};
|
||||
type IdKey = keyof typeof idToUrlMap;
|
||||
|
||||
|
|
|
@ -39,11 +39,10 @@
|
|||
"@kbn/shared-ux-link-redirect-app",
|
||||
"@kbn/react-kibana-context-render",
|
||||
"@kbn/data-views-plugin",
|
||||
"@kbn/deeplinks-observability",
|
||||
"@kbn/core-logging-server-mocks",
|
||||
"@kbn/core-http-server-mocks",
|
||||
"@kbn/core-http-server-utils",
|
||||
"@kbn/core-elasticsearch-server"
|
||||
"@kbn/core-elasticsearch-server",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -15,9 +15,7 @@ import {
|
|||
SectionSubtitle,
|
||||
SectionTitle,
|
||||
} from '@kbn/observability-shared-plugin/public';
|
||||
import type { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability/locators';
|
||||
import { ALL_DATASETS_LOCATOR_ID } from '@kbn/deeplinks-observability/locators';
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import { getLogsLocatorFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import {
|
||||
ASSET_DETAILS_LOCATOR_ID,
|
||||
type AssetDetailsLocatorParams,
|
||||
|
@ -54,9 +52,7 @@ export function InstanceActionsMenu({ serviceName, serviceNodeName, kuery, onClo
|
|||
const metricOverviewHref = useMetricOverviewHref(serviceName);
|
||||
const history = useHistory();
|
||||
|
||||
const allDatasetsLocator =
|
||||
share.url.locators.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID)!;
|
||||
const { nodeLogsLocator } = getLogsLocatorsFromUrlService(share.url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(share.url)!;
|
||||
const assetDetailsLocator =
|
||||
share.url.locators.get<AssetDetailsLocatorParams>(ASSET_DETAILS_LOCATOR_ID);
|
||||
|
||||
|
@ -97,8 +93,7 @@ export function InstanceActionsMenu({ serviceName, serviceNodeName, kuery, onClo
|
|||
basePath: core.http.basePath,
|
||||
onFilterByInstanceClick: handleFilterByInstanceClick,
|
||||
metricsHref,
|
||||
allDatasetsLocator,
|
||||
nodeLogsLocator,
|
||||
logsLocator,
|
||||
assetDetailsLocator,
|
||||
});
|
||||
|
||||
|
|
|
@ -8,9 +8,8 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import type { IBasePath } from '@kbn/core/public';
|
||||
import moment from 'moment';
|
||||
import type { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability/locators';
|
||||
import type { LocatorPublic } from '@kbn/share-plugin/public';
|
||||
import type { NodeLogsLocatorParams } from '@kbn/logs-shared-plugin/common';
|
||||
import { type LogsLocatorParams, getNodeQuery, getTimeRange } from '@kbn/logs-shared-plugin/common';
|
||||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { type AssetDetailsLocator } from '@kbn/observability-shared-plugin/common';
|
||||
import type { APIReturnType } from '../../../../../services/rest/create_call_apm_api';
|
||||
|
@ -41,16 +40,14 @@ export function getMenuSections({
|
|||
basePath,
|
||||
onFilterByInstanceClick,
|
||||
metricsHref,
|
||||
allDatasetsLocator,
|
||||
nodeLogsLocator,
|
||||
logsLocator,
|
||||
assetDetailsLocator,
|
||||
}: {
|
||||
instanceDetails: InstaceDetails;
|
||||
basePath: IBasePath;
|
||||
onFilterByInstanceClick: () => void;
|
||||
metricsHref: string;
|
||||
allDatasetsLocator: LocatorPublic<AllDatasetsLocatorParams>;
|
||||
nodeLogsLocator: LocatorPublic<NodeLogsLocatorParams>;
|
||||
logsLocator: LocatorPublic<LogsLocatorParams>;
|
||||
assetDetailsLocator?: AssetDetailsLocator;
|
||||
}) {
|
||||
const podId = instanceDetails.kubernetes?.pod?.uid;
|
||||
|
@ -60,16 +57,20 @@ export function getMenuSections({
|
|||
: undefined;
|
||||
const infraMetricsQuery = getInfraMetricsQuery(instanceDetails['@timestamp']);
|
||||
|
||||
const podLogsHref = nodeLogsLocator.getRedirectUrl({
|
||||
nodeField: findInventoryFields('pod').id,
|
||||
nodeId: podId!,
|
||||
time,
|
||||
const podLogsHref = logsLocator.getRedirectUrl({
|
||||
query: getNodeQuery({
|
||||
nodeField: findInventoryFields('pod').id,
|
||||
nodeId: podId!,
|
||||
}),
|
||||
timeRange: getTimeRange(time),
|
||||
});
|
||||
|
||||
const containerLogsHref = nodeLogsLocator.getRedirectUrl({
|
||||
nodeField: findInventoryFields('container').id,
|
||||
nodeId: containerId!,
|
||||
time,
|
||||
const containerLogsHref = logsLocator.getRedirectUrl({
|
||||
query: getNodeQuery({
|
||||
nodeField: findInventoryFields('container').id,
|
||||
nodeId: containerId!,
|
||||
}),
|
||||
timeRange: getTimeRange(time),
|
||||
});
|
||||
|
||||
const hasPodLink = !!podId && !!assetDetailsLocator;
|
||||
|
|
|
@ -13,10 +13,9 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import type { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import { ALL_DATASETS_LOCATOR_ID } from '@kbn/deeplinks-observability';
|
||||
import { EuiButtonEmpty } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { type LogsLocatorParams, LOGS_LOCATOR_ID } from '@kbn/logs-shared-plugin/common';
|
||||
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
||||
import { buildLogsExplorerLocatorConfig } from './logs_explorer_locator_config';
|
||||
|
||||
|
@ -31,15 +30,14 @@ export function ExploreLogsButton({
|
|||
}) {
|
||||
const { share } = useApmPluginContext();
|
||||
|
||||
const logsExplorerLocator =
|
||||
share.url.locators.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID)!;
|
||||
const logsLocator = share.url.locators.get<LogsLocatorParams>(LOGS_LOCATOR_ID);
|
||||
|
||||
if (!logsExplorerLocator) {
|
||||
if (!logsLocator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { logsExplorerLinkProps } = buildLogsExplorerLocatorConfig({
|
||||
locator: logsExplorerLocator,
|
||||
locator: logsLocator,
|
||||
from: start,
|
||||
to: end,
|
||||
kuery,
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import type { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { getRouterLinkProps } from '@kbn/router-utils';
|
||||
import type { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props';
|
||||
import type { LogsLocatorParams } from '@kbn/logs-shared-plugin/common';
|
||||
|
||||
export const buildLogsExplorerLocatorConfig = ({
|
||||
locator,
|
||||
|
@ -16,14 +16,14 @@ export const buildLogsExplorerLocatorConfig = ({
|
|||
from,
|
||||
to,
|
||||
}: {
|
||||
locator: LocatorPublic<AllDatasetsLocatorParams>;
|
||||
locator: LocatorPublic<LogsLocatorParams>;
|
||||
kuery?: string;
|
||||
from: string;
|
||||
to: string;
|
||||
}): {
|
||||
logsExplorerLinkProps: RouterLinkProps;
|
||||
} => {
|
||||
const params: AllDatasetsLocatorParams = {
|
||||
const params: LogsLocatorParams = {
|
||||
timeRange: {
|
||||
from,
|
||||
to,
|
||||
|
|
|
@ -10,9 +10,8 @@ import rison from '@kbn/rison';
|
|||
import type { IBasePath } from '@kbn/core/public';
|
||||
import type { Transaction } from '../../../../typings/es_schemas/ui/transaction';
|
||||
import { getSections } from './sections';
|
||||
import type { ApmRouter } from '../../routing/apm_route_config';
|
||||
import { apmRouter as apmRouterBase } from '../../routing/apm_route_config';
|
||||
import { logsLocatorsMock } from '../../../context/apm_plugin/mock_apm_plugin_context';
|
||||
import { apmRouter as apmRouterBase, type ApmRouter } from '../../routing/apm_route_config';
|
||||
import { logsLocatorMock } from '../../../context/apm_plugin/mock_apm_plugin_context';
|
||||
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
|
||||
import type {
|
||||
AssetDetailsLocatorParams,
|
||||
|
@ -24,7 +23,6 @@ const apmRouter = {
|
|||
link: (...args: [any]) => `some-basepath/app/apm${apmRouterBase.link(...args)}`,
|
||||
} as ApmRouter;
|
||||
|
||||
const { nodeLogsLocator, traceLogsLocator } = logsLocatorsMock;
|
||||
const uptimeLocator = sharePluginMock.createLocator();
|
||||
|
||||
const mockAssetDetailsLocator = {
|
||||
|
@ -36,9 +34,8 @@ const mockAssetDetailsLocator = {
|
|||
),
|
||||
} as unknown as jest.Mocked<AssetDetailsLocator>;
|
||||
|
||||
const expectLogsLocatorsToBeCalled = () => {
|
||||
expect(nodeLogsLocator.getRedirectUrl).toBeCalledTimes(3);
|
||||
expect(traceLogsLocator.getRedirectUrl).toBeCalledTimes(1);
|
||||
const expectLogsLocatorToBeCalled = () => {
|
||||
expect(logsLocatorMock.getRedirectUrl).toBeCalledTimes(4);
|
||||
};
|
||||
|
||||
const expectUptimeLocatorToBeCalled = () => {
|
||||
|
@ -77,7 +74,7 @@ describe('Transaction action menu', () => {
|
|||
basePath,
|
||||
location,
|
||||
apmRouter,
|
||||
logsLocators: logsLocatorsMock,
|
||||
logsLocator: logsLocatorMock,
|
||||
uptimeLocator,
|
||||
infraLinksAvailable: false,
|
||||
rangeFrom: 'now-24h',
|
||||
|
@ -129,7 +126,7 @@ describe('Transaction action menu', () => {
|
|||
],
|
||||
]);
|
||||
expectUptimeLocatorToBeCalled();
|
||||
expectLogsLocatorsToBeCalled();
|
||||
expectLogsLocatorToBeCalled();
|
||||
});
|
||||
|
||||
it('shows pod and required sections only', () => {
|
||||
|
@ -147,7 +144,7 @@ describe('Transaction action menu', () => {
|
|||
location,
|
||||
apmRouter,
|
||||
uptimeLocator,
|
||||
logsLocators: logsLocatorsMock,
|
||||
logsLocator: logsLocatorMock,
|
||||
infraLinksAvailable: true,
|
||||
rangeFrom: 'now-24h',
|
||||
rangeTo: 'now',
|
||||
|
@ -216,7 +213,7 @@ describe('Transaction action menu', () => {
|
|||
],
|
||||
]);
|
||||
expectUptimeLocatorToBeCalled();
|
||||
expectLogsLocatorsToBeCalled();
|
||||
expectLogsLocatorToBeCalled();
|
||||
});
|
||||
|
||||
it('shows host and required sections only', () => {
|
||||
|
@ -234,7 +231,7 @@ describe('Transaction action menu', () => {
|
|||
location,
|
||||
apmRouter,
|
||||
uptimeLocator,
|
||||
logsLocators: logsLocatorsMock,
|
||||
logsLocator: logsLocatorMock,
|
||||
infraLinksAvailable: true,
|
||||
rangeFrom: 'now-24h',
|
||||
rangeTo: 'now',
|
||||
|
@ -303,6 +300,6 @@ describe('Transaction action menu', () => {
|
|||
],
|
||||
]);
|
||||
expectUptimeLocatorToBeCalled();
|
||||
expectLogsLocatorsToBeCalled();
|
||||
expectLogsLocatorToBeCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,7 +10,12 @@ import type { Location } from 'history';
|
|||
import type { IBasePath } from '@kbn/core/public';
|
||||
import { isEmpty, pickBy } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import type { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import {
|
||||
type LogsLocatorParams,
|
||||
getNodeQuery,
|
||||
getTraceQuery,
|
||||
getTimeRange,
|
||||
} from '@kbn/logs-shared-plugin/common';
|
||||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public';
|
||||
import type { AssetDetailsLocator } from '@kbn/observability-shared-plugin/common';
|
||||
|
@ -46,7 +51,7 @@ export const getSections = ({
|
|||
rangeFrom,
|
||||
rangeTo,
|
||||
environment,
|
||||
logsLocators,
|
||||
logsLocator,
|
||||
dataViewId,
|
||||
assetDetailsLocator,
|
||||
}: {
|
||||
|
@ -60,7 +65,7 @@ export const getSections = ({
|
|||
rangeFrom: string;
|
||||
rangeTo: string;
|
||||
environment: Environment;
|
||||
logsLocators: ReturnType<typeof getLogsLocatorsFromUrlService>;
|
||||
logsLocator: LocatorPublic<LogsLocatorParams>;
|
||||
dataViewId?: string;
|
||||
assetDetailsLocator?: AssetDetailsLocator;
|
||||
}) => {
|
||||
|
@ -85,25 +90,31 @@ export const getSections = ({
|
|||
);
|
||||
|
||||
// Logs hrefs
|
||||
const podLogsHref = logsLocators.nodeLogsLocator.getRedirectUrl({
|
||||
nodeField: findInventoryFields('pod').id,
|
||||
nodeId: podId!,
|
||||
time,
|
||||
const podLogsHref = logsLocator.getRedirectUrl({
|
||||
query: getNodeQuery({
|
||||
nodeField: findInventoryFields('pod').id,
|
||||
nodeId: podId!,
|
||||
}),
|
||||
timeRange: getTimeRange(time),
|
||||
});
|
||||
const containerLogsHref = logsLocators.nodeLogsLocator.getRedirectUrl({
|
||||
nodeField: findInventoryFields('container').id,
|
||||
nodeId: containerId!,
|
||||
time,
|
||||
const containerLogsHref = logsLocator.getRedirectUrl({
|
||||
query: getNodeQuery({
|
||||
nodeField: findInventoryFields('container').id,
|
||||
nodeId: containerId!,
|
||||
}),
|
||||
timeRange: getTimeRange(time),
|
||||
});
|
||||
const hostLogsHref = logsLocators.nodeLogsLocator.getRedirectUrl({
|
||||
nodeField: findInventoryFields('host').id,
|
||||
nodeId: hostName!,
|
||||
time,
|
||||
const hostLogsHref = logsLocator.getRedirectUrl({
|
||||
query: getNodeQuery({
|
||||
nodeField: findInventoryFields('host').id,
|
||||
nodeId: hostName!,
|
||||
}),
|
||||
timeRange: getTimeRange(time),
|
||||
});
|
||||
|
||||
const traceLogsHref = logsLocators.traceLogsLocator.getRedirectUrl({
|
||||
traceId: transaction.trace.id!,
|
||||
time,
|
||||
const traceLogsHref = logsLocator.getRedirectUrl({
|
||||
query: getTraceQuery({ traceId: transaction.trace.id! }),
|
||||
timeRange: getTimeRange(time),
|
||||
});
|
||||
|
||||
const hasPodLink = !!podId && infraLinksAvailable && !!assetDetailsLocator;
|
||||
|
|
|
@ -11,17 +11,13 @@ import { MemoryRouter } from 'react-router-dom';
|
|||
import { createMemoryHistory } from 'history';
|
||||
import { License } from '@kbn/licensing-plugin/common/license';
|
||||
import rison from '@kbn/rison';
|
||||
import {
|
||||
LOGS_LOCATOR_ID,
|
||||
NODE_LOGS_LOCATOR_ID,
|
||||
TRACE_LOGS_LOCATOR_ID,
|
||||
} from '@kbn/logs-shared-plugin/common';
|
||||
import { LOGS_LOCATOR_ID } from '@kbn/logs-shared-plugin/common';
|
||||
import type { Transaction } from '../../../../typings/es_schemas/ui/transaction';
|
||||
import type { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context';
|
||||
import {
|
||||
mockApmPluginContextValue,
|
||||
MockApmPluginContextWrapper,
|
||||
logsLocatorsMock,
|
||||
logsLocatorMock,
|
||||
} from '../../../context/apm_plugin/mock_apm_plugin_context';
|
||||
import { LicenseContext } from '../../../context/license/license_context';
|
||||
import * as hooks from '../../../hooks/use_fetcher';
|
||||
|
@ -59,15 +55,7 @@ const apmContextMock = {
|
|||
locators: {
|
||||
get: (id: string) => {
|
||||
if (id === LOGS_LOCATOR_ID) {
|
||||
return logsLocatorsMock.logsLocator;
|
||||
}
|
||||
|
||||
if (id === NODE_LOGS_LOCATOR_ID) {
|
||||
return logsLocatorsMock.nodeLogsLocator;
|
||||
}
|
||||
|
||||
if (id === TRACE_LOGS_LOCATOR_ID) {
|
||||
return logsLocatorsMock.traceLogsLocator;
|
||||
return logsLocatorMock;
|
||||
}
|
||||
if (id === uptimeOverviewLocatorID) {
|
||||
return {
|
||||
|
@ -131,9 +119,8 @@ const renderTransaction = async (transaction: Record<string, any>) => {
|
|||
return rendered;
|
||||
};
|
||||
|
||||
const expectLogsLocatorsToBeCalled = () => {
|
||||
expect(logsLocatorsMock.nodeLogsLocator.getRedirectUrl).toBeCalled();
|
||||
expect(logsLocatorsMock.traceLogsLocator.getRedirectUrl).toBeCalled();
|
||||
const expectLogsLocatorToBeCalled = () => {
|
||||
expect(logsLocatorMock.getRedirectUrl).toBeCalled();
|
||||
};
|
||||
|
||||
let useAdHocApmDataViewSpy: jest.SpyInstance;
|
||||
|
@ -175,7 +162,7 @@ describe('TransactionActionMenu ', () => {
|
|||
it('should call logs locators getRedirectUrl function', async () => {
|
||||
await renderTransaction(Transactions.transactionWithMinimalData);
|
||||
|
||||
expectLogsLocatorsToBeCalled();
|
||||
expectLogsLocatorToBeCalled();
|
||||
});
|
||||
|
||||
describe('when there is no pod id', () => {
|
||||
|
@ -196,7 +183,7 @@ describe('TransactionActionMenu ', () => {
|
|||
it('should call logs locators getRedirectUrl function', async () => {
|
||||
await renderTransaction(Transactions.transactionWithKubernetesData);
|
||||
|
||||
expectLogsLocatorsToBeCalled();
|
||||
expectLogsLocatorToBeCalled();
|
||||
});
|
||||
|
||||
it('renders the pod metrics link', async () => {
|
||||
|
@ -226,7 +213,7 @@ describe('TransactionActionMenu ', () => {
|
|||
it('renders the Container logs link', async () => {
|
||||
await renderTransaction(Transactions.transactionWithContainerData);
|
||||
|
||||
expectLogsLocatorsToBeCalled();
|
||||
expectLogsLocatorToBeCalled();
|
||||
});
|
||||
|
||||
it('renders the Container metrics link', async () => {
|
||||
|
@ -256,7 +243,7 @@ describe('TransactionActionMenu ', () => {
|
|||
it('should call logs locators getRedirectUrl function', async () => {
|
||||
await renderTransaction(Transactions.transactionWithHostData);
|
||||
|
||||
expectLogsLocatorsToBeCalled();
|
||||
expectLogsLocatorToBeCalled();
|
||||
});
|
||||
|
||||
it('renders the Host metrics link', async () => {
|
||||
|
|
|
@ -26,7 +26,7 @@ import React, { useState } from 'react';
|
|||
import { useLocation } from 'react-router-dom';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public';
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import { getLogsLocatorFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/common';
|
||||
import { useAnyOfApmParams } from '../../../hooks/use_apm_params';
|
||||
import { ApmFeatureFlagName } from '../../../../common/apm_feature_flags';
|
||||
|
@ -125,7 +125,7 @@ function ActionMenuSections({
|
|||
const apmRouter = useApmRouter();
|
||||
const { dataView } = useAdHocApmDataView();
|
||||
|
||||
const logsLocators = getLogsLocatorsFromUrlService(share.url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(share.url)!;
|
||||
|
||||
const uptimeLocator = share.url.locators.get(uptimeOverviewLocatorID);
|
||||
|
||||
|
@ -154,7 +154,7 @@ function ActionMenuSections({
|
|||
rangeFrom,
|
||||
rangeTo,
|
||||
environment,
|
||||
logsLocators,
|
||||
logsLocator,
|
||||
dataViewId: dataView?.id,
|
||||
assetDetailsLocator,
|
||||
});
|
||||
|
|
|
@ -8,11 +8,7 @@
|
|||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { UI_SETTINGS } from '@kbn/data-plugin/common';
|
||||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import type {
|
||||
LogsLocatorParams,
|
||||
NodeLogsLocatorParams,
|
||||
TraceLogsLocatorParams,
|
||||
} from '@kbn/logs-shared-plugin/common';
|
||||
import type { LogsLocatorParams } from '@kbn/logs-shared-plugin/common';
|
||||
import { MlLocatorDefinition } from '@kbn/ml-plugin/public';
|
||||
import { apmEnableProfilingIntegration } from '@kbn/observability-plugin/common';
|
||||
import {
|
||||
|
@ -162,11 +158,7 @@ export const observabilityLogsExplorerLocatorsMock = {
|
|||
singleDatasetLocator: sharePluginMock.createLocator(),
|
||||
};
|
||||
|
||||
export const logsLocatorsMock = {
|
||||
logsLocator: sharePluginMock.createLocator<LogsLocatorParams>(),
|
||||
nodeLogsLocator: sharePluginMock.createLocator<NodeLogsLocatorParams>(),
|
||||
traceLogsLocator: sharePluginMock.createLocator<TraceLogsLocatorParams>(),
|
||||
};
|
||||
export const logsLocatorMock = sharePluginMock.createLocator<LogsLocatorParams>();
|
||||
|
||||
const mockCorePlugins = {
|
||||
embeddable: {},
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { UrlService } from '@kbn/share-plugin/common/url_service';
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import { getLogsLocatorFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import type { ObservabilityRuleTypeModel } from '@kbn/observability-plugin/public';
|
||||
import type { PartialRuleParams } from '../../../common/alerting/logs/log_threshold';
|
||||
import { LOG_DOCUMENT_COUNT_RULE_TYPE_ID } from '../../../common/alerting/logs/log_threshold';
|
||||
import {
|
||||
LOG_DOCUMENT_COUNT_RULE_TYPE_ID,
|
||||
type PartialRuleParams,
|
||||
} from '../../../common/alerting/logs/log_threshold';
|
||||
import { createLazyComponentWithKibanaContext } from '../../hooks/use_kibana';
|
||||
import type { InfraClientCoreSetup } from '../../types';
|
||||
import { createRuleFormatter } from './rule_data_formatters';
|
||||
|
@ -54,7 +56,7 @@ export function createLogThresholdRuleType(
|
|||
() => import('./components/alert_details_app_section')
|
||||
);
|
||||
|
||||
const { logsLocator } = getLogsLocatorsFromUrlService(urlService);
|
||||
const logsLocator = getLogsLocatorFromUrlService(urlService)!;
|
||||
|
||||
return {
|
||||
id: LOG_DOCUMENT_COUNT_RULE_TYPE_ID,
|
||||
|
|
|
@ -12,8 +12,7 @@ import ReactDOM from 'react-dom';
|
|||
import { Router, Routes, Route } from '@kbn/shared-ux-router';
|
||||
import type { AppMountParameters } from '@kbn/core/public';
|
||||
import { Storage } from '@kbn/kibana-utils-plugin/public';
|
||||
import type { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import { ALL_DATASETS_LOCATOR_ID } from '@kbn/deeplinks-observability';
|
||||
import { type LogsLocatorParams, LOGS_LOCATOR_ID } from '@kbn/logs-shared-plugin/common';
|
||||
import { LinkToLogsPage } from '../pages/link_to/link_to_logs';
|
||||
import { LogsPage } from '../pages/logs';
|
||||
import type { InfraClientStartDeps, InfraClientStartExports } from '../types';
|
||||
|
@ -93,7 +92,7 @@ const LogsApp: React.FC<{
|
|||
exact
|
||||
render={() => {
|
||||
plugins.share.url.locators
|
||||
.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID)
|
||||
.get<LogsLocatorParams>(LOGS_LOCATOR_ID)
|
||||
?.navigate({});
|
||||
|
||||
return null;
|
||||
|
|
|
@ -11,10 +11,15 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiFieldSearch, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { LogStream } from '@kbn/logs-shared-plugin/public';
|
||||
import type { LogViewReference } from '@kbn/logs-shared-plugin/common';
|
||||
import { DEFAULT_LOG_VIEW, getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import {
|
||||
DEFAULT_LOG_VIEW,
|
||||
getLogsLocatorFromUrlService,
|
||||
getNodeQuery,
|
||||
type LogViewReference,
|
||||
} from '@kbn/logs-shared-plugin/common';
|
||||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { OpenInLogsExplorerButton } from '@kbn/logs-shared-plugin/public';
|
||||
import moment from 'moment';
|
||||
import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
|
||||
import { InfraLoadingPanel } from '../../../loading';
|
||||
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
|
||||
|
@ -35,7 +40,7 @@ export const Logs = () => {
|
|||
const { loading: logViewLoading, reference: logViewReference } = logs ?? {};
|
||||
|
||||
const { services } = useKibanaContextForPlugin();
|
||||
const { nodeLogsLocator } = getLogsLocatorsFromUrlService(services.share.url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(services.share.url)!;
|
||||
const [textQuery, setTextQuery] = useState(urlState?.logsSearch ?? '');
|
||||
const [textQueryDebounced, setTextQueryDebounced] = useState(urlState?.logsSearch ?? '');
|
||||
|
||||
|
@ -78,14 +83,27 @@ export const Logs = () => {
|
|||
);
|
||||
|
||||
const logsUrl = useMemo(() => {
|
||||
return nodeLogsLocator.getRedirectUrl({
|
||||
nodeField: findInventoryFields(asset.type).id,
|
||||
nodeId: asset.id,
|
||||
time: state.startTimestamp,
|
||||
filter: textQueryDebounced,
|
||||
return logsLocator.getRedirectUrl({
|
||||
query: getNodeQuery({
|
||||
nodeField: findInventoryFields(asset.type).id,
|
||||
nodeId: asset.id,
|
||||
filter: textQueryDebounced,
|
||||
}),
|
||||
timeRange: {
|
||||
from: moment(state.startTimestamp).toISOString(),
|
||||
to: moment(state.currentTimestamp).toISOString(),
|
||||
},
|
||||
logView,
|
||||
});
|
||||
}, [nodeLogsLocator, asset.id, asset.type, state.startTimestamp, textQueryDebounced, logView]);
|
||||
}, [
|
||||
logsLocator,
|
||||
asset.id,
|
||||
asset.type,
|
||||
state.startTimestamp,
|
||||
state.currentTimestamp,
|
||||
textQueryDebounced,
|
||||
logView,
|
||||
]);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="column" ref={ref}>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import { getLogsLocatorFromUrlService, getTimeRange } from '@kbn/logs-shared-plugin/common';
|
||||
import { getFilterFromLocation, getTimeFromLocation } from './query_params';
|
||||
import { useKibanaContextForPlugin } from '../../hooks/use_kibana';
|
||||
|
||||
|
@ -17,7 +17,7 @@ export const RedirectToLogs = () => {
|
|||
const {
|
||||
services: { share },
|
||||
} = useKibanaContextForPlugin();
|
||||
const { logsLocator } = getLogsLocatorsFromUrlService(share.url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(share.url)!;
|
||||
|
||||
const filter = getFilterFromLocation(location);
|
||||
const time = getTimeFromLocation(location);
|
||||
|
@ -25,8 +25,8 @@ export const RedirectToLogs = () => {
|
|||
useEffect(() => {
|
||||
logsLocator.navigate(
|
||||
{
|
||||
time,
|
||||
filter,
|
||||
query: { language: 'kuery', query: filter },
|
||||
timeRange: getTimeRange(time),
|
||||
},
|
||||
{ replace: true }
|
||||
);
|
||||
|
|
|
@ -7,9 +7,15 @@
|
|||
|
||||
import { useEffect } from 'react';
|
||||
import type { RouteComponentProps } from 'react-router-dom';
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import {
|
||||
getLogsLocatorFromUrlService,
|
||||
getNodeQuery,
|
||||
getTimeRange,
|
||||
} from '@kbn/logs-shared-plugin/common';
|
||||
import {
|
||||
findInventoryFields,
|
||||
type InventoryItemType,
|
||||
} from '@kbn/metrics-data-access-plugin/common';
|
||||
|
||||
import { useKibanaContextForPlugin } from '../../hooks/use_kibana';
|
||||
import { getFilterFromLocation, getTimeFromLocation } from './query_params';
|
||||
|
@ -29,22 +35,24 @@ export const RedirectToNodeLogs = ({
|
|||
const {
|
||||
services: { share },
|
||||
} = useKibanaContextForPlugin();
|
||||
const { nodeLogsLocator } = getLogsLocatorsFromUrlService(share.url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(share.url)!;
|
||||
|
||||
const filter = getFilterFromLocation(location);
|
||||
const time = getTimeFromLocation(location);
|
||||
|
||||
useEffect(() => {
|
||||
nodeLogsLocator.navigate(
|
||||
logsLocator.navigate(
|
||||
{
|
||||
nodeField: findInventoryFields(nodeType).id,
|
||||
nodeId,
|
||||
time,
|
||||
filter,
|
||||
query: getNodeQuery({
|
||||
nodeField: findInventoryFields(nodeType).id,
|
||||
nodeId,
|
||||
filter,
|
||||
}),
|
||||
timeRange: getTimeRange(time),
|
||||
},
|
||||
{ replace: true }
|
||||
);
|
||||
}, [filter, nodeLogsLocator, nodeId, nodeType, time]);
|
||||
}, [filter, logsLocator, nodeId, nodeType, time]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
|
|
@ -12,16 +12,13 @@ import { Routes, Route } from '@kbn/shared-ux-router';
|
|||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { HeaderMenuPortal, useLinkProps } from '@kbn/observability-shared-plugin/public';
|
||||
import type { SharePublicStart } from '@kbn/share-plugin/public/plugin';
|
||||
import type {
|
||||
ObservabilityOnboardingLocatorParams,
|
||||
AllDatasetsLocatorParams,
|
||||
} from '@kbn/deeplinks-observability';
|
||||
import {
|
||||
type ObservabilityOnboardingLocatorParams,
|
||||
OBSERVABILITY_ONBOARDING_LOCATOR,
|
||||
ALL_DATASETS_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability';
|
||||
import { dynamic } from '@kbn/shared-ux-utility';
|
||||
import { isDevMode } from '@kbn/xstate-utils';
|
||||
import { type LogsLocatorParams, LOGS_LOCATOR_ID } from '@kbn/logs-shared-plugin/common';
|
||||
import { LazyAlertDropdownWrapper } from '../../alerting/log_threshold';
|
||||
import { HelpCenterContent } from '../../components/help_center_content';
|
||||
import { useReadOnlyBadge } from '../../hooks/use_readonly_badge';
|
||||
|
@ -94,7 +91,7 @@ export const LogsPageContent: React.FunctionComponent = () => {
|
|||
path="/stream"
|
||||
exact
|
||||
render={() => {
|
||||
share.url.locators.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID)?.navigate({});
|
||||
share.url.locators.get<LogsLocatorParams>(LOGS_LOCATOR_ID)?.navigate({});
|
||||
|
||||
return null;
|
||||
}}
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import React from 'react';
|
||||
import type { LogViewReference } from '@kbn/logs-shared-plugin/common';
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import {
|
||||
getLogsLocatorFromUrlService,
|
||||
type LogViewReference,
|
||||
} from '@kbn/logs-shared-plugin/common';
|
||||
import { OpenInLogsExplorerButton } from '@kbn/logs-shared-plugin/public';
|
||||
import moment from 'moment';
|
||||
import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana';
|
||||
|
||||
interface LogsLinkToStreamProps {
|
||||
|
@ -20,15 +23,14 @@ interface LogsLinkToStreamProps {
|
|||
export const LogsLinkToStream = ({ startTime, endTime, query, logView }: LogsLinkToStreamProps) => {
|
||||
const { services } = useKibanaContextForPlugin();
|
||||
const { share } = services;
|
||||
const { logsLocator } = getLogsLocatorsFromUrlService(share.url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(share.url)!;
|
||||
|
||||
return (
|
||||
<OpenInLogsExplorerButton
|
||||
href={logsLocator.getRedirectUrl({
|
||||
time: endTime,
|
||||
timeRange: {
|
||||
startTime,
|
||||
endTime,
|
||||
from: moment(startTime).toISOString(),
|
||||
to: moment(endTime).toISOString(),
|
||||
},
|
||||
filter: query,
|
||||
logView,
|
||||
|
|
|
@ -26,7 +26,11 @@ import {
|
|||
type InventoryItemType,
|
||||
} from '@kbn/metrics-data-access-plugin/common';
|
||||
import { useAssetDetailsRedirect } from '@kbn/metrics-data-access-plugin/public';
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import {
|
||||
getLogsLocatorFromUrlService,
|
||||
getNodeQuery,
|
||||
getTimeRange,
|
||||
} from '@kbn/logs-shared-plugin/common';
|
||||
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/common';
|
||||
import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana';
|
||||
import { AlertFlyout } from '../../../../../alerting/inventory/components/alert_flyout';
|
||||
|
@ -52,7 +56,7 @@ export const NodeContextMenu = withEuiTheme(
|
|||
const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000;
|
||||
const { services } = useKibanaContextForPlugin();
|
||||
const { application, share } = services;
|
||||
const { nodeLogsLocator } = getLogsLocatorsFromUrlService(share.url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(share.url)!;
|
||||
const uptimeLocator = share.url.locators.get(uptimeOverviewLocatorID);
|
||||
const uiCapabilities = application?.capabilities;
|
||||
// Due to the changing nature of the fields between APM and this UI,
|
||||
|
@ -119,10 +123,12 @@ export const NodeContextMenu = withEuiTheme(
|
|||
defaultMessage: '{inventoryName} logs',
|
||||
values: { inventoryName: inventoryModel.singularDisplayName },
|
||||
}),
|
||||
href: nodeLogsLocator.getRedirectUrl({
|
||||
nodeField: findInventoryFields(nodeType).id,
|
||||
nodeId: node.id,
|
||||
time: currentTime,
|
||||
href: logsLocator.getRedirectUrl({
|
||||
query: getNodeQuery({
|
||||
nodeField: findInventoryFields(nodeType).id,
|
||||
nodeId: node.id,
|
||||
}),
|
||||
timeRange: getTimeRange(currentTime),
|
||||
}),
|
||||
'data-test-subj': 'viewLogsContextMenuItem',
|
||||
isDisabled: !showLogsLink,
|
||||
|
|
|
@ -23,19 +23,4 @@ export const registerFeatures = (homePlugin: HomePublicPluginSetup) => {
|
|||
showOnHomePage: false,
|
||||
category: 'data',
|
||||
});
|
||||
|
||||
homePlugin.featureCatalogue.register({
|
||||
id: 'observability-logs-explorer',
|
||||
title: i18n.translate('xpack.infra.registerFeatures.logsTitle', {
|
||||
defaultMessage: 'Logs',
|
||||
}),
|
||||
description: i18n.translate('xpack.infra.registerFeatures.logsDescription', {
|
||||
defaultMessage:
|
||||
'Stream logs in real time or scroll through historical views in a console-like experience.',
|
||||
}),
|
||||
icon: 'logsApp',
|
||||
path: `/app/observability-logs-explorer`,
|
||||
showOnHomePage: false,
|
||||
category: 'data',
|
||||
});
|
||||
};
|
||||
|
|
|
@ -11,7 +11,8 @@ import type {
|
|||
FetchDataParams,
|
||||
LogsFetchDataResponse,
|
||||
} from '@kbn/observability-plugin/public';
|
||||
import { DEFAULT_LOG_VIEW, getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import { DEFAULT_LOG_VIEW, getLogsLocatorFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import moment from 'moment';
|
||||
import { TIMESTAMP_FIELD } from '../../common/constants';
|
||||
import type { InfraClientStartDeps, InfraClientStartServicesAccessor } from '../types';
|
||||
|
||||
|
@ -67,13 +68,13 @@ export function getLogsOverviewDataFetcher(
|
|||
params,
|
||||
data
|
||||
);
|
||||
const { logsLocator } = getLogsLocatorsFromUrlService(share.url);
|
||||
const logsLocator = getLogsLocatorFromUrlService(share.url)!;
|
||||
const timeSpanInMinutes = (params.absoluteTime.end - params.absoluteTime.start) / (1000 * 60);
|
||||
|
||||
const appLink = logsLocator.getRedirectUrl({
|
||||
timeRange: {
|
||||
startTime: params.absoluteTime.start,
|
||||
endTime: params.absoluteTime.end,
|
||||
from: moment(params.absoluteTime.start).toISOString(),
|
||||
to: moment(params.absoluteTime.end).toISOString(),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { LogsExplorerLocator } from './logs_explorer/logs_explorer_locator';
|
||||
|
||||
export * from './logs_explorer';
|
||||
|
||||
export interface LogsExplorerLocators {
|
||||
logsExplorerLocator: LogsExplorerLocator;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './logs_explorer_locator';
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
|
||||
import { LogsExplorerLocatorDefinition } from './logs_explorer_locator';
|
||||
import { LogsExplorerLocatorDependencies } from './types';
|
||||
|
||||
const setup = async () => {
|
||||
const logsExplorerLocatorDependencies: LogsExplorerLocatorDependencies = {
|
||||
discoverAppLocator: sharePluginMock.createLocator(),
|
||||
};
|
||||
const logsExplorerLocator = new LogsExplorerLocatorDefinition(logsExplorerLocatorDependencies);
|
||||
|
||||
return {
|
||||
logsExplorerLocator,
|
||||
discoverGetLocation: logsExplorerLocatorDependencies.discoverAppLocator?.getLocation,
|
||||
};
|
||||
};
|
||||
|
||||
describe('Logs Explorer Locators', () => {
|
||||
const dataset = 'logs-*-*';
|
||||
it('should call discover locator with empty params', async () => {
|
||||
const { logsExplorerLocator, discoverGetLocation } = await setup();
|
||||
await logsExplorerLocator.getLocation({});
|
||||
|
||||
expect(discoverGetLocation).toBeCalledWith({});
|
||||
});
|
||||
|
||||
it('should call discover locator with correct dataViewId if dataset is sent', async () => {
|
||||
const { logsExplorerLocator, discoverGetLocation } = await setup();
|
||||
await logsExplorerLocator.getLocation({ dataset });
|
||||
|
||||
expect(discoverGetLocation).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
dataViewId: 'logs-*-*',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should call discover locator with correct dataViewSpec if dataset is sent', async () => {
|
||||
const { logsExplorerLocator, discoverGetLocation } = await setup();
|
||||
await logsExplorerLocator.getLocation({ dataset });
|
||||
|
||||
expect(discoverGetLocation).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
dataViewId: 'logs-*-*',
|
||||
dataViewSpec: {
|
||||
id: 'logs-*-*',
|
||||
title: 'logs-*-*',
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { DataViewSpec } from '@kbn/data-views-plugin/common';
|
||||
import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
|
||||
import {
|
||||
LogsExplorerLocatorParams,
|
||||
LOGS_EXPLORER_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { LogsExplorerLocatorDependencies } from './types';
|
||||
|
||||
export type LogsExplorerLocator = LocatorPublic<LogsExplorerLocatorParams>;
|
||||
|
||||
export class LogsExplorerLocatorDefinition implements LocatorDefinition<LogsExplorerLocatorParams> {
|
||||
public readonly id = LOGS_EXPLORER_LOCATOR_ID;
|
||||
|
||||
constructor(protected readonly deps: LogsExplorerLocatorDependencies) {}
|
||||
|
||||
public readonly getLocation = (params: LogsExplorerLocatorParams) => {
|
||||
const { dataset, columns } = params;
|
||||
const dataViewSpec: DataViewSpec | undefined = dataset
|
||||
? {
|
||||
id: dataset,
|
||||
title: dataset,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const discoverColumns = columns?.map((column) => {
|
||||
return column.type === 'document-field' ? column.field : column.smartField;
|
||||
});
|
||||
|
||||
return this.deps.discoverAppLocator?.getLocation({
|
||||
...params,
|
||||
columns: discoverColumns,
|
||||
dataViewId: dataset,
|
||||
dataViewSpec,
|
||||
})!;
|
||||
};
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
|
||||
export interface LogsExplorerLocatorDependencies {
|
||||
discoverAppLocator?: LocatorPublic<DiscoverAppLocatorParams>;
|
||||
}
|
|
@ -6,8 +6,6 @@
|
|||
*/
|
||||
|
||||
import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public';
|
||||
import { DISCOVER_APP_LOCATOR, DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import { LogsExplorerLocatorDefinition, LogsExplorerLocators } from '../common/locators';
|
||||
import { createLogsExplorer } from './components/logs_explorer';
|
||||
import { createLogsExplorerControllerLazyFactory } from './controller/lazy_create_controller';
|
||||
import type {
|
||||
|
@ -20,29 +18,10 @@ import type {
|
|||
export class LogsExplorerPlugin
|
||||
implements Plugin<LogsExplorerPluginSetup, LogsExplorerPluginStart>
|
||||
{
|
||||
private locators?: LogsExplorerLocators;
|
||||
|
||||
constructor(context: PluginInitializerContext) {}
|
||||
|
||||
public setup(core: CoreSetup, plugins: LogsExplorerSetupDeps) {
|
||||
const { share } = plugins;
|
||||
const discoverAppLocator =
|
||||
share.url.locators.get<DiscoverAppLocatorParams>(DISCOVER_APP_LOCATOR);
|
||||
|
||||
// Register Locators
|
||||
const logsExplorerLocator = share.url.locators.create(
|
||||
new LogsExplorerLocatorDefinition({
|
||||
discoverAppLocator,
|
||||
})
|
||||
);
|
||||
|
||||
this.locators = {
|
||||
logsExplorerLocator,
|
||||
};
|
||||
|
||||
return {
|
||||
locators: this.locators,
|
||||
};
|
||||
return {};
|
||||
}
|
||||
|
||||
public start(core: CoreStart, plugins: LogsExplorerStartDeps) {
|
||||
|
|
|
@ -13,13 +13,12 @@ import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
|||
import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
|
||||
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public';
|
||||
import type { LogsExplorerLocators } from '../common/locators';
|
||||
import type { LogsExplorerProps } from './components/logs_explorer';
|
||||
import type { CreateLogsExplorerController } from './controller';
|
||||
|
||||
export interface LogsExplorerPluginSetup {
|
||||
locators: LogsExplorerLocators;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface LogsExplorerPluginSetup {}
|
||||
|
||||
export interface LogsExplorerPluginStart {
|
||||
LogsExplorer: ComponentType<LogsExplorerProps>;
|
||||
createLogsExplorerController: CreateLogsExplorerController;
|
||||
|
|
|
@ -6,36 +6,14 @@
|
|||
*/
|
||||
|
||||
import { Plugin, CoreSetup } from '@kbn/core/server';
|
||||
import { DISCOVER_APP_LOCATOR, DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import { LogsExplorerLocatorDefinition, LogsExplorerLocators } from '../common/locators';
|
||||
import { uiSettings } from '../common/ui_settings';
|
||||
import type { LogsExplorerSetupDeps } from './types';
|
||||
|
||||
export class LogsExplorerServerPlugin implements Plugin {
|
||||
private locators?: LogsExplorerLocators;
|
||||
|
||||
setup(core: CoreSetup, plugins: LogsExplorerSetupDeps) {
|
||||
const { share } = plugins;
|
||||
|
||||
core.uiSettings.register(uiSettings);
|
||||
|
||||
const discoverAppLocator =
|
||||
share.url.locators.get<DiscoverAppLocatorParams>(DISCOVER_APP_LOCATOR);
|
||||
|
||||
// Register Locators
|
||||
const logsExplorerLocator = share.url.locators.create(
|
||||
new LogsExplorerLocatorDefinition({
|
||||
discoverAppLocator,
|
||||
})
|
||||
);
|
||||
|
||||
this.locators = {
|
||||
logsExplorerLocator,
|
||||
};
|
||||
|
||||
return {
|
||||
locators: this.locators,
|
||||
};
|
||||
return {};
|
||||
}
|
||||
|
||||
start() {}
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
|
||||
import { Aggregators } from './types';
|
||||
import { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { LogsExplorerLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import type { LogsLocatorParams } from '@kbn/logs-shared-plugin/common';
|
||||
import { getViewInAppUrl, GetViewInAppUrlArgs } from './get_view_in_app_url';
|
||||
|
||||
describe('getViewInAppUrl', () => {
|
||||
const logsExplorerLocator = {
|
||||
const logsLocator = {
|
||||
getRedirectUrl: jest.fn(() => 'mockedGetRedirectUrl'),
|
||||
} as unknown as LocatorPublic<LogsExplorerLocatorParams>;
|
||||
} as unknown as LocatorPublic<LogsLocatorParams>;
|
||||
const startedAt = '2023-12-07T16:30:15.403Z';
|
||||
const endedAt = '2023-12-07T20:30:15.403Z';
|
||||
const returnedTimeRange = {
|
||||
|
@ -26,7 +26,7 @@ describe('getViewInAppUrl', () => {
|
|||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('Should return empty string if logsExplorerLocator is not provided', () => {
|
||||
it('Should return empty string if logsLocator is not provided', () => {
|
||||
const args: GetViewInAppUrlArgs = {
|
||||
metrics: [],
|
||||
startedAt,
|
||||
|
@ -45,7 +45,7 @@ describe('getViewInAppUrl', () => {
|
|||
filter: 'mockedCountFilter',
|
||||
},
|
||||
],
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
searchConfiguration: {
|
||||
|
@ -59,9 +59,10 @@ describe('getViewInAppUrl', () => {
|
|||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
expect(logsLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: args.dataViewId,
|
||||
dataViewId: args.dataViewId,
|
||||
dataViewSpec: {},
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
|
@ -82,13 +83,13 @@ describe('getViewInAppUrl', () => {
|
|||
filter: 'mockedCountFilter',
|
||||
},
|
||||
],
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
expect(logsLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
|
@ -104,7 +105,7 @@ describe('getViewInAppUrl', () => {
|
|||
|
||||
it('should call getRedirectUrl with only filter', () => {
|
||||
const args: GetViewInAppUrlArgs = {
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
searchConfiguration: {
|
||||
|
@ -117,9 +118,10 @@ describe('getViewInAppUrl', () => {
|
|||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
expect(logsLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
dataViewId: undefined,
|
||||
dataViewSpec: {},
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [],
|
||||
query: {
|
||||
|
@ -133,13 +135,13 @@ describe('getViewInAppUrl', () => {
|
|||
|
||||
it('should call getRedirectUrl with empty query if metrics and filter are not not provided', () => {
|
||||
const args: GetViewInAppUrlArgs = {
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
expect(logsLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
|
@ -167,13 +169,13 @@ describe('getViewInAppUrl', () => {
|
|||
field: 'mockedAvgField',
|
||||
},
|
||||
],
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
expect(logsLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
|
@ -201,7 +203,7 @@ describe('getViewInAppUrl', () => {
|
|||
field: 'mockedAvgField',
|
||||
},
|
||||
],
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
searchConfiguration: {
|
||||
|
@ -232,9 +234,10 @@ describe('getViewInAppUrl', () => {
|
|||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
expect(logsLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
dataViewId: undefined,
|
||||
dataViewSpec: {},
|
||||
timeRange: returnedTimeRange,
|
||||
filters: [
|
||||
{
|
||||
|
@ -275,14 +278,14 @@ describe('getViewInAppUrl', () => {
|
|||
filter: 'mockedCountFilter',
|
||||
},
|
||||
],
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
startedAt,
|
||||
endedAt,
|
||||
spaceId,
|
||||
};
|
||||
|
||||
expect(getViewInAppUrl(args)).toBe('mockedGetRedirectUrl');
|
||||
expect(logsExplorerLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
expect(logsLocator.getRedirectUrl).toHaveBeenCalledWith(
|
||||
{
|
||||
dataset: undefined,
|
||||
timeRange: returnedTimeRange,
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { LogsExplorerLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util';
|
||||
import type { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import { getGroupFilters } from './helpers/get_group';
|
||||
import { SearchConfigurationWithExtractedReferenceType } from './types';
|
||||
import type { CustomThresholdExpressionMetric } from './types';
|
||||
|
@ -19,7 +19,7 @@ export interface GetViewInAppUrlArgs {
|
|||
dataViewId?: string;
|
||||
endedAt?: string;
|
||||
groups?: Group[];
|
||||
logsExplorerLocator?: LocatorPublic<LogsExplorerLocatorParams>;
|
||||
logsLocator?: LocatorPublic<DiscoverAppLocatorParams>;
|
||||
metrics?: CustomThresholdExpressionMetric[];
|
||||
startedAt?: string;
|
||||
spaceId?: string;
|
||||
|
@ -29,15 +29,14 @@ export const getViewInAppUrl = ({
|
|||
dataViewId,
|
||||
endedAt,
|
||||
groups,
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
metrics = [],
|
||||
searchConfiguration,
|
||||
startedAt = new Date().toISOString(),
|
||||
spaceId,
|
||||
}: GetViewInAppUrlArgs) => {
|
||||
if (!logsExplorerLocator) return '';
|
||||
if (!logsLocator) return '';
|
||||
|
||||
const dataset = searchConfiguration?.index.title ?? dataViewId;
|
||||
const searchConfigurationQuery = searchConfiguration?.query.query;
|
||||
const searchConfigurationFilters = searchConfiguration?.filter || [];
|
||||
const groupFilters = getGroupFilters(groups);
|
||||
|
@ -58,9 +57,10 @@ export const getViewInAppUrl = ({
|
|||
query.query = searchConfigurationQuery;
|
||||
}
|
||||
|
||||
return logsExplorerLocator?.getRedirectUrl(
|
||||
return logsLocator.getRedirectUrl(
|
||||
{
|
||||
dataset,
|
||||
dataViewId,
|
||||
dataViewSpec: searchConfiguration?.index,
|
||||
timeRange,
|
||||
query,
|
||||
filters: [...searchConfigurationFilters, ...groupFilters],
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
],
|
||||
"requiredBundles": [
|
||||
"data",
|
||||
"discover",
|
||||
"kibanaReact",
|
||||
"kibanaUtils",
|
||||
"unifiedSearch",
|
||||
|
@ -71,4 +72,4 @@
|
|||
"common"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ import type {
|
|||
RangeEventAnnotationConfig,
|
||||
} from '@kbn/event-annotation-common';
|
||||
import moment from 'moment';
|
||||
import { LOGS_EXPLORER_LOCATOR_ID, LogsExplorerLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import { DISCOVER_APP_LOCATOR, DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import { TimeRange } from '@kbn/es-query';
|
||||
import { getGroupFilters } from '../../../../../common/custom_threshold_rule/helpers/get_group';
|
||||
import { useLicense } from '../../../../hooks/use_license';
|
||||
|
@ -137,7 +137,7 @@ export default function AlertDetailsAppSection({ alert }: AppSectionProps) {
|
|||
const appUrl = getViewInAppUrl({
|
||||
dataViewId: dataView?.id,
|
||||
groups,
|
||||
logsExplorerLocator: locators.get<LogsExplorerLocatorParams>(LOGS_EXPLORER_LOCATOR_ID),
|
||||
logsLocator: locators.get<DiscoverAppLocatorParams>(DISCOVER_APP_LOCATOR),
|
||||
metrics: criterion?.metrics,
|
||||
searchConfiguration:
|
||||
ruleParams.searchConfiguration as SearchConfigurationWithExtractedReferenceType,
|
||||
|
|
|
@ -37,21 +37,7 @@ function createNavTree({ streamsAvailable }: { streamsAvailable?: boolean }) {
|
|||
title: i18n.translate('xpack.observability.obltNav.discover', {
|
||||
defaultMessage: 'Discover',
|
||||
}),
|
||||
// 'last-used-logs-viewer' is wrapper app to handle the navigation between observability-log-explorer and discover
|
||||
link: 'last-used-logs-viewer',
|
||||
breadcrumbStatus: 'hidden', // avoid duplicate "Discover" breadcrumbs
|
||||
renderAs: 'item',
|
||||
children: [
|
||||
{
|
||||
link: 'discover',
|
||||
children: [
|
||||
{
|
||||
// This is to show "observability-log-explorer" breadcrumbs when navigating from "discover" to "log explorer"
|
||||
link: 'observability-logs-explorer',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
link: 'discover',
|
||||
},
|
||||
{
|
||||
link: 'dashboards',
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import React, { useEffect } from 'react';
|
||||
import {
|
||||
AllDatasetsLocatorParams,
|
||||
ALL_DATASETS_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { type LogsLocatorParams, LOGS_LOCATOR_ID } from '@kbn/logs-shared-plugin/common';
|
||||
import { useHasData } from '../../hooks/use_has_data';
|
||||
import { useKibana } from '../../utils/kibana_react';
|
||||
|
||||
|
@ -27,10 +24,8 @@ export function LandingPage() {
|
|||
const hasLogsData = logs?.hasData;
|
||||
|
||||
if (hasLogsData) {
|
||||
const allDataSetsLocator =
|
||||
url.locators.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID);
|
||||
|
||||
allDataSetsLocator?.navigate({});
|
||||
const logsLocator = url.locators.get<LogsLocatorParams>(LOGS_LOCATOR_ID);
|
||||
logsLocator?.navigate({});
|
||||
} else if (hasApmData) {
|
||||
navigateToUrl(basePath.prepend('/app/apm/services'));
|
||||
} else {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { HttpSetup, DocLinksStart } from '@kbn/core/public';
|
||||
import { BrowserUrlService } from '@kbn/share-plugin/public';
|
||||
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import { getLogsLocatorFromUrlService } from '@kbn/logs-shared-plugin/common';
|
||||
import { ObservabilityFetchDataPlugins } from '../../../../typings/fetch_overview_data';
|
||||
import { paths } from '../../../../../common/locators/paths';
|
||||
|
||||
|
@ -28,7 +28,7 @@ export const getContent = (
|
|||
docLinks: DocLinksStart,
|
||||
urlService: BrowserUrlService
|
||||
): ObservabilityStatusContent[] => {
|
||||
const { logsLocator } = getLogsLocatorsFromUrlService(urlService);
|
||||
const logsLocator = getLogsLocatorFromUrlService(urlService)!;
|
||||
return [
|
||||
{
|
||||
id: 'infra_logs',
|
||||
|
@ -45,7 +45,7 @@ export const getContent = (
|
|||
addLink: http.basePath.prepend('/app/integrations/browse?q=logs'),
|
||||
learnMoreLink: docLinks.links.observability.monitorLogs,
|
||||
goToAppTitle: i18n.translate('xpack.observability.statusVisualization.logs.goToAppTitle', {
|
||||
defaultMessage: 'Show Logs Explorer',
|
||||
defaultMessage: 'Show logs',
|
||||
}),
|
||||
goToAppLink: logsLocator.getRedirectUrl({}),
|
||||
weight: 1,
|
||||
|
|
|
@ -101,7 +101,7 @@ export function LogsSection({ bucketSize }: Props) {
|
|||
appLink={{
|
||||
href: appLink,
|
||||
label: i18n.translate('xpack.observability.overview.logs.appLink', {
|
||||
defaultMessage: 'Show Logs Explorer',
|
||||
defaultMessage: 'Show logs',
|
||||
}),
|
||||
prependBasePath: false,
|
||||
}}
|
||||
|
|
|
@ -25,7 +25,7 @@ import {
|
|||
import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public';
|
||||
import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { LOGS_EXPLORER_LOCATOR_ID, LogsExplorerLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import { DISCOVER_APP_LOCATOR, type DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import type { DiscoverStart } from '@kbn/discover-plugin/public';
|
||||
import type { EmbeddableStart } from '@kbn/embeddable-plugin/public';
|
||||
import type { FieldFormatsSetup, FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
|
@ -252,8 +252,8 @@ export class Plugin
|
|||
new RuleDetailsLocatorDefinition()
|
||||
);
|
||||
|
||||
const logsExplorerLocator =
|
||||
pluginsSetup.share.url.locators.get<LogsExplorerLocatorParams>(LOGS_EXPLORER_LOCATOR_ID);
|
||||
const logsLocator =
|
||||
pluginsSetup.share.url.locators.get<DiscoverAppLocatorParams>(DISCOVER_APP_LOCATOR);
|
||||
|
||||
const mount = async (params: AppMountParameters<unknown>) => {
|
||||
// Load application bundle
|
||||
|
@ -314,7 +314,7 @@ export class Plugin
|
|||
registerObservabilityRuleTypes(
|
||||
this.observabilityRuleTypeRegistry,
|
||||
coreSetup.uiSettings,
|
||||
logsExplorerLocator
|
||||
logsLocator
|
||||
);
|
||||
|
||||
if (pluginsSetup.home) {
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
OBSERVABILITY_THRESHOLD_RULE_TYPE_ID,
|
||||
} from '@kbn/rule-data-utils';
|
||||
import type { LocatorPublic } from '@kbn/share-plugin/common';
|
||||
import { LogsExplorerLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
|
||||
import type {
|
||||
CustomMetricExpressionParams,
|
||||
|
@ -59,7 +59,7 @@ const getDataViewId = (searchConfiguration?: SearchConfigurationWithExtractedRef
|
|||
export const registerObservabilityRuleTypes = (
|
||||
observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry,
|
||||
uiSettings: IUiSettingsClient,
|
||||
logsExplorerLocator?: LocatorPublic<LogsExplorerLocatorParams>
|
||||
logsLocator?: LocatorPublic<DiscoverAppLocatorParams>
|
||||
) => {
|
||||
const validateCustomThresholdWithUiSettings = ({
|
||||
criteria,
|
||||
|
@ -102,7 +102,7 @@ export const registerObservabilityRuleTypes = (
|
|||
link: getViewInAppUrl({
|
||||
dataViewId,
|
||||
groups,
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
metrics,
|
||||
searchConfiguration,
|
||||
startedAt: fields[ALERT_START],
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import { isEqual } from 'lodash';
|
||||
import { LogsExplorerLocatorParams } from '@kbn/deeplinks-observability';
|
||||
import {
|
||||
ALERT_EVALUATION_VALUES,
|
||||
ALERT_EVALUATION_THRESHOLD,
|
||||
|
@ -18,6 +17,7 @@ import { RecoveredActionGroup } from '@kbn/alerting-plugin/common';
|
|||
import { IBasePath, Logger } from '@kbn/core/server';
|
||||
import { AlertsClientError, RuleExecutorOptions } from '@kbn/alerting-plugin/server';
|
||||
import { getEcsGroups } from '@kbn/observability-alerting-rule-utils';
|
||||
import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import { getEsQueryConfig } from '../../../utils/get_es_query_config';
|
||||
import { AlertsLocatorParams, getAlertDetailsUrl } from '../../../../common';
|
||||
import { getViewInAppUrl } from '../../../../common/custom_threshold_rule/get_view_in_app_url';
|
||||
|
@ -50,14 +50,14 @@ import { MissingGroupsRecord } from './lib/check_missing_group';
|
|||
|
||||
export interface CustomThresholdLocators {
|
||||
alertsLocator?: LocatorPublic<AlertsLocatorParams>;
|
||||
logsExplorerLocator?: LocatorPublic<LogsExplorerLocatorParams>;
|
||||
logsLocator?: LocatorPublic<DiscoverAppLocatorParams>;
|
||||
}
|
||||
|
||||
export const createCustomThresholdExecutor = ({
|
||||
basePath,
|
||||
logger,
|
||||
config,
|
||||
locators: { logsExplorerLocator },
|
||||
locators: { logsLocator },
|
||||
}: {
|
||||
basePath: IBasePath;
|
||||
logger: Logger;
|
||||
|
@ -281,7 +281,7 @@ export const createCustomThresholdExecutor = ({
|
|||
viewInAppUrl: getViewInAppUrl({
|
||||
dataViewId: params.searchConfiguration?.index?.title ?? dataViewId,
|
||||
groups,
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
metrics: alertResults.length === 1 ? alertResults[0][group].metrics : [],
|
||||
searchConfiguration: params.searchConfiguration,
|
||||
startedAt: indexedStartedAt,
|
||||
|
@ -317,7 +317,7 @@ export const createCustomThresholdExecutor = ({
|
|||
viewInAppUrl: getViewInAppUrl({
|
||||
dataViewId,
|
||||
groups: group,
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
metrics: params.criteria[0]?.metrics,
|
||||
searchConfiguration: params.searchConfiguration,
|
||||
startedAt: indexedStartedAt,
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
Plugin,
|
||||
PluginInitializerContext,
|
||||
} from '@kbn/core/server';
|
||||
import { LogsExplorerLocatorParams, LOGS_EXPLORER_LOCATOR_ID } from '@kbn/deeplinks-observability';
|
||||
import { DISCOVER_APP_LOCATOR, type DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
|
||||
import { FeaturesPluginSetup } from '@kbn/features-plugin/server';
|
||||
import type { GuidedOnboardingPluginSetup } from '@kbn/guided-onboarding-plugin/server';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -94,8 +94,8 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> {
|
|||
|
||||
const alertsLocator = plugins.share.url.locators.create(new AlertsLocatorDefinition());
|
||||
|
||||
const logsExplorerLocator =
|
||||
plugins.share.url.locators.get<LogsExplorerLocatorParams>(LOGS_EXPLORER_LOCATOR_ID);
|
||||
const logsLocator =
|
||||
plugins.share.url.locators.get<DiscoverAppLocatorParams>(DISCOVER_APP_LOCATOR);
|
||||
|
||||
const alertDetailsContextualInsightsService = new AlertDetailsContextualInsightsService();
|
||||
|
||||
|
@ -177,7 +177,7 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> {
|
|||
|
||||
registerRuleTypes(plugins.alerting, core.http.basePath, config, this.logger, {
|
||||
alertsLocator,
|
||||
logsExplorerLocator,
|
||||
logsLocator,
|
||||
});
|
||||
|
||||
void core.getStartServices().then(([coreStart, pluginStart]) => {
|
||||
|
|
|
@ -5,11 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export {
|
||||
type ObservabilityLogsExplorerLocators,
|
||||
SingleDatasetLocatorDefinition,
|
||||
AllDatasetsLocatorDefinition,
|
||||
} from './locators';
|
||||
export {
|
||||
OBSERVABILITY_LOGS_EXPLORER_URL_STATE_KEY,
|
||||
logsExplorerUrlSchemaV1,
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
|
||||
import {
|
||||
AllDatasetsLocatorParams,
|
||||
ALL_DATASETS_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { AllDatasetSelection } from '@kbn/logs-explorer-plugin/common';
|
||||
import { ObsLogsExplorerLocatorDependencies } from './types';
|
||||
import { constructLocatorPath } from './utils';
|
||||
|
||||
export type AllDatasetsLocator = LocatorPublic<AllDatasetsLocatorParams>;
|
||||
|
||||
export class AllDatasetsLocatorDefinition implements LocatorDefinition<AllDatasetsLocatorParams> {
|
||||
public readonly id = ALL_DATASETS_LOCATOR_ID;
|
||||
|
||||
constructor(protected readonly deps: ObsLogsExplorerLocatorDependencies) {}
|
||||
|
||||
public readonly getLocation = (params: AllDatasetsLocatorParams) => {
|
||||
const { useHash } = this.deps;
|
||||
|
||||
return constructLocatorPath({
|
||||
dataSourceSelection: AllDatasetSelection.getLocatorPlainSelection(),
|
||||
locatorParams: params,
|
||||
useHash,
|
||||
});
|
||||
};
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
|
||||
import { DataViewSelection } from '@kbn/logs-explorer-plugin/common';
|
||||
import {
|
||||
ObsLogsExplorerDataViewLocatorParams,
|
||||
OBS_LOGS_EXPLORER_DATA_VIEW_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { constructLocatorPath } from './utils';
|
||||
import { ObsLogsExplorerLocatorDependencies } from './types';
|
||||
|
||||
export type DataViewLocator = LocatorPublic<ObsLogsExplorerDataViewLocatorParams>;
|
||||
|
||||
export class DataViewLocatorDefinition
|
||||
implements LocatorDefinition<ObsLogsExplorerDataViewLocatorParams>
|
||||
{
|
||||
public readonly id = OBS_LOGS_EXPLORER_DATA_VIEW_LOCATOR_ID;
|
||||
|
||||
constructor(protected readonly deps: ObsLogsExplorerLocatorDependencies) {}
|
||||
|
||||
public readonly getLocation = (params: ObsLogsExplorerDataViewLocatorParams) => {
|
||||
const { useHash } = this.deps;
|
||||
const { id, ...locatorParams } = params;
|
||||
|
||||
const dataViewSelection = DataViewSelection.fromSelection({
|
||||
dataView: { id },
|
||||
});
|
||||
|
||||
return constructLocatorPath({
|
||||
dataSourceSelection: dataViewSelection.toPlainSelection(),
|
||||
locatorParams,
|
||||
useHash,
|
||||
});
|
||||
};
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export type { ObservabilityLogsExplorerLocationState } from '@kbn/deeplinks-observability/locators';
|
||||
import { AllDatasetsLocator } from './all_datasets_locator';
|
||||
import { DataViewLocator } from './data_view_locator';
|
||||
import { SingleDatasetLocator } from './single_dataset_locator';
|
||||
|
||||
export * from './single_dataset_locator';
|
||||
export * from './all_datasets_locator';
|
||||
export * from './utils';
|
||||
|
||||
export interface ObservabilityLogsExplorerLocators {
|
||||
allDatasetsLocator: AllDatasetsLocator;
|
||||
dataViewLocator: DataViewLocator;
|
||||
singleDatasetLocator: SingleDatasetLocator;
|
||||
}
|
|
@ -1,426 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { OBSERVABILITY_LOGS_EXPLORER_APP_ID } from '@kbn/deeplinks-observability';
|
||||
import {
|
||||
AllDatasetsLocatorParams,
|
||||
SingleDatasetLocatorParams,
|
||||
ObsLogsExplorerDataViewLocatorParams,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { AllDatasetsLocatorDefinition } from './all_datasets_locator';
|
||||
import { DataViewLocatorDefinition } from './data_view_locator';
|
||||
import { SingleDatasetLocatorDefinition } from './single_dataset_locator';
|
||||
import { ObsLogsExplorerLocatorDependencies } from './types';
|
||||
|
||||
const setup = async () => {
|
||||
const dep: ObsLogsExplorerLocatorDependencies = {
|
||||
useHash: false,
|
||||
};
|
||||
const allDatasetsLocator = new AllDatasetsLocatorDefinition(dep);
|
||||
const dataViewLocator = new DataViewLocatorDefinition(dep);
|
||||
const singleDatasetLocator = new SingleDatasetLocatorDefinition(dep);
|
||||
|
||||
return {
|
||||
allDatasetsLocator,
|
||||
dataViewLocator,
|
||||
singleDatasetLocator,
|
||||
};
|
||||
};
|
||||
|
||||
describe('Observability Logs Explorer Locators', () => {
|
||||
const timeRange = { to: 'now', from: 'now-30m' };
|
||||
|
||||
describe('All Dataset Locator', () => {
|
||||
it('should create a link with no state', async () => {
|
||||
const { allDatasetsLocator } = await setup();
|
||||
const location = await allDatasetsLocator.getLocation({});
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: '/?pageState=(dataSourceSelection:(selectionType:all),v:2)',
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying time range', async () => {
|
||||
const params: AllDatasetsLocatorParams = {
|
||||
timeRange,
|
||||
};
|
||||
|
||||
const { allDatasetsLocator } = await setup();
|
||||
const location = await allDatasetsLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: '/?pageState=(dataSourceSelection:(selectionType:all),time:(from:now-30m,to:now),v:2)',
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
it('should allow specifying query', async () => {
|
||||
const params: AllDatasetsLocatorParams = {
|
||||
query: {
|
||||
language: 'kuery',
|
||||
query: 'foo',
|
||||
},
|
||||
};
|
||||
|
||||
const { allDatasetsLocator } = await setup();
|
||||
const location = await allDatasetsLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: '/?pageState=(dataSourceSelection:(selectionType:all),query:(language:kuery,query:foo),v:2)',
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying refresh interval', async () => {
|
||||
const params: AllDatasetsLocatorParams = {
|
||||
refreshInterval: {
|
||||
pause: false,
|
||||
value: 666,
|
||||
},
|
||||
};
|
||||
|
||||
const { allDatasetsLocator } = await setup();
|
||||
const location = await allDatasetsLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: '/?pageState=(dataSourceSelection:(selectionType:all),refreshInterval:(pause:!f,value:666),v:2)',
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying breakdown field', async () => {
|
||||
const params: AllDatasetsLocatorParams = {
|
||||
breakdownField: 'service.name',
|
||||
};
|
||||
|
||||
const { allDatasetsLocator } = await setup();
|
||||
const location = await allDatasetsLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: '/?pageState=(breakdownField:service.name,dataSourceSelection:(selectionType:all),v:2)',
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying columns', async () => {
|
||||
const params: AllDatasetsLocatorParams = {
|
||||
columns: [{ field: '_source', type: 'document-field' }],
|
||||
};
|
||||
|
||||
const { allDatasetsLocator } = await setup();
|
||||
const location = await allDatasetsLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: '/?pageState=(columns:!((field:_source,type:document-field)),dataSourceSelection:(selectionType:all),v:2)',
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying filters', async () => {
|
||||
const params: AllDatasetsLocatorParams = {
|
||||
filters: [
|
||||
{
|
||||
meta: {
|
||||
alias: 'foo',
|
||||
disabled: false,
|
||||
negate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
meta: {
|
||||
alias: 'bar',
|
||||
disabled: false,
|
||||
negate: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { allDatasetsLocator } = await setup();
|
||||
const location = await allDatasetsLocator.getLocation(params);
|
||||
|
||||
expect(location.path).toMatchInlineSnapshot(
|
||||
`"/?pageState=(dataSourceSelection:(selectionType:all),filters:!((meta:(alias:foo,disabled:!f,negate:!f)),(meta:(alias:bar,disabled:!f,negate:!f))),v:2)"`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Data View Locator', () => {
|
||||
it('should create a link with correct index', async () => {
|
||||
const { dataViewLocator } = await setup();
|
||||
const location = await dataViewLocator.getLocation({
|
||||
id: 'data-view-id',
|
||||
});
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(dataSourceSelection:(selection:(dataView:(dataType:unresolved,id:data-view-id)),selectionType:dataView),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying time range', async () => {
|
||||
const params: ObsLogsExplorerDataViewLocatorParams = {
|
||||
id: 'data-view-id',
|
||||
timeRange,
|
||||
};
|
||||
|
||||
const { dataViewLocator } = await setup();
|
||||
const location = await dataViewLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(dataSourceSelection:(selection:(dataView:(dataType:unresolved,id:data-view-id)),selectionType:dataView),time:(from:now-30m,to:now),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying query', async () => {
|
||||
const params: ObsLogsExplorerDataViewLocatorParams = {
|
||||
id: 'data-view-id',
|
||||
query: {
|
||||
language: 'kuery',
|
||||
query: 'foo',
|
||||
},
|
||||
};
|
||||
|
||||
const { dataViewLocator } = await setup();
|
||||
const location = await dataViewLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(dataSourceSelection:(selection:(dataView:(dataType:unresolved,id:data-view-id)),selectionType:dataView),query:(language:kuery,query:foo),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying refresh interval', async () => {
|
||||
const params: ObsLogsExplorerDataViewLocatorParams = {
|
||||
id: 'data-view-id',
|
||||
refreshInterval: {
|
||||
pause: false,
|
||||
value: 666,
|
||||
},
|
||||
};
|
||||
|
||||
const { dataViewLocator } = await setup();
|
||||
const location = await dataViewLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(dataSourceSelection:(selection:(dataView:(dataType:unresolved,id:data-view-id)),selectionType:dataView),refreshInterval:(pause:!f,value:666),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying breakdown field', async () => {
|
||||
const params: ObsLogsExplorerDataViewLocatorParams = {
|
||||
id: 'data-view-id',
|
||||
breakdownField: 'service.name',
|
||||
};
|
||||
|
||||
const { dataViewLocator } = await setup();
|
||||
const location = await dataViewLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(breakdownField:service.name,dataSourceSelection:(selection:(dataView:(dataType:unresolved,id:data-view-id)),selectionType:dataView),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying columns', async () => {
|
||||
const params: ObsLogsExplorerDataViewLocatorParams = {
|
||||
id: 'data-view-id',
|
||||
columns: [{ field: '_source', type: 'document-field' }],
|
||||
};
|
||||
|
||||
const { dataViewLocator } = await setup();
|
||||
const location = await dataViewLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(columns:!((field:_source,type:document-field)),dataSourceSelection:(selection:(dataView:(dataType:unresolved,id:data-view-id)),selectionType:dataView),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying filters', async () => {
|
||||
const params: ObsLogsExplorerDataViewLocatorParams = {
|
||||
id: 'data-view-id',
|
||||
filters: [
|
||||
{
|
||||
meta: {
|
||||
alias: 'foo',
|
||||
disabled: false,
|
||||
negate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
meta: {
|
||||
alias: 'bar',
|
||||
disabled: false,
|
||||
negate: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { dataViewLocator } = await setup();
|
||||
const location = await dataViewLocator.getLocation(params);
|
||||
|
||||
expect(location.path).toMatchInlineSnapshot(
|
||||
`"/?pageState=(dataSourceSelection:(selection:(dataView:(dataType:unresolved,id:data-view-id)),selectionType:dataView),filters:!((meta:(alias:foo,disabled:!f,negate:!f)),(meta:(alias:bar,disabled:!f,negate:!f))),v:2)"`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Single Dataset Locator', () => {
|
||||
const integration = 'Test';
|
||||
const dataset = 'test-*';
|
||||
it('should create a link with correct index', async () => {
|
||||
const { singleDatasetLocator } = await setup();
|
||||
const location = await singleDatasetLocator.getLocation({
|
||||
integration,
|
||||
dataset,
|
||||
});
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(dataSourceSelection:(selection:(dataset:(name:'logs-test-*-*',title:test),name:Test),selectionType:unresolved),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying time range', async () => {
|
||||
const params: SingleDatasetLocatorParams = {
|
||||
integration,
|
||||
dataset,
|
||||
timeRange,
|
||||
};
|
||||
|
||||
const { singleDatasetLocator } = await setup();
|
||||
const location = await singleDatasetLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(dataSourceSelection:(selection:(dataset:(name:'logs-test-*-*',title:test),name:Test),selectionType:unresolved),time:(from:now-30m,to:now),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying query', async () => {
|
||||
const params: SingleDatasetLocatorParams = {
|
||||
integration,
|
||||
dataset,
|
||||
query: {
|
||||
language: 'kuery',
|
||||
query: 'foo',
|
||||
},
|
||||
};
|
||||
|
||||
const { singleDatasetLocator } = await setup();
|
||||
const location = await singleDatasetLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(dataSourceSelection:(selection:(dataset:(name:'logs-test-*-*',title:test),name:Test),selectionType:unresolved),query:(language:kuery,query:foo),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying refresh interval', async () => {
|
||||
const params: SingleDatasetLocatorParams = {
|
||||
integration,
|
||||
dataset,
|
||||
refreshInterval: {
|
||||
pause: false,
|
||||
value: 666,
|
||||
},
|
||||
};
|
||||
|
||||
const { singleDatasetLocator } = await setup();
|
||||
const location = await singleDatasetLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(dataSourceSelection:(selection:(dataset:(name:'logs-test-*-*',title:test),name:Test),selectionType:unresolved),refreshInterval:(pause:!f,value:666),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying breakdown field', async () => {
|
||||
const params: SingleDatasetLocatorParams = {
|
||||
integration,
|
||||
dataset,
|
||||
breakdownField: 'service.name',
|
||||
};
|
||||
|
||||
const { singleDatasetLocator } = await setup();
|
||||
const location = await singleDatasetLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(breakdownField:service.name,dataSourceSelection:(selection:(dataset:(name:'logs-test-*-*',title:test),name:Test),selectionType:unresolved),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying columns', async () => {
|
||||
const params: SingleDatasetLocatorParams = {
|
||||
integration,
|
||||
dataset,
|
||||
columns: [{ field: '_source', type: 'document-field' }],
|
||||
};
|
||||
|
||||
const { singleDatasetLocator } = await setup();
|
||||
const location = await singleDatasetLocator.getLocation(params);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: `/?pageState=(columns:!((field:_source,type:document-field)),dataSourceSelection:(selection:(dataset:(name:'logs-test-*-*',title:test),name:Test),selectionType:unresolved),v:2)`,
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow specifying filters', async () => {
|
||||
const params: SingleDatasetLocatorParams = {
|
||||
integration,
|
||||
dataset,
|
||||
filters: [
|
||||
{
|
||||
meta: {
|
||||
alias: 'foo',
|
||||
disabled: false,
|
||||
negate: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
meta: {
|
||||
alias: 'bar',
|
||||
disabled: false,
|
||||
negate: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { singleDatasetLocator } = await setup();
|
||||
const location = await singleDatasetLocator.getLocation(params);
|
||||
|
||||
expect(location.path).toMatchInlineSnapshot(
|
||||
`"/?pageState=(dataSourceSelection:(selection:(dataset:(name:'logs-test-*-*',title:test),name:Test),selectionType:unresolved),filters:!((meta:(alias:foo,disabled:!f,negate:!f)),(meta:(alias:bar,disabled:!f,negate:!f))),v:2)"`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
|
||||
import { UnresolvedDatasetSelection } from '@kbn/logs-explorer-plugin/common';
|
||||
import type { IndexPattern } from '@kbn/io-ts-utils';
|
||||
import {
|
||||
SingleDatasetLocatorParams,
|
||||
SINGLE_DATASET_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { ObsLogsExplorerLocatorDependencies } from './types';
|
||||
import { constructLocatorPath } from './utils';
|
||||
|
||||
export type SingleDatasetLocator = LocatorPublic<SingleDatasetLocatorParams>;
|
||||
|
||||
export class SingleDatasetLocatorDefinition
|
||||
implements LocatorDefinition<SingleDatasetLocatorParams>
|
||||
{
|
||||
public readonly id = SINGLE_DATASET_LOCATOR_ID;
|
||||
|
||||
constructor(protected readonly deps: ObsLogsExplorerLocatorDependencies) {}
|
||||
|
||||
public readonly getLocation = (params: SingleDatasetLocatorParams) => {
|
||||
const { useHash } = this.deps;
|
||||
const { integration, dataset } = params;
|
||||
|
||||
const unresolvedDatasetSelection = UnresolvedDatasetSelection.fromSelection({
|
||||
name: integration,
|
||||
dataset: {
|
||||
name: this.composeIndexPattern(dataset),
|
||||
},
|
||||
});
|
||||
|
||||
return constructLocatorPath({
|
||||
dataSourceSelection: unresolvedDatasetSelection.toPlainSelection(),
|
||||
locatorParams: params,
|
||||
useHash,
|
||||
});
|
||||
};
|
||||
|
||||
private composeIndexPattern(datasetName: SingleDatasetLocatorParams['dataset']) {
|
||||
return `logs-${datasetName}-*` as IndexPattern;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
export interface ObsLogsExplorerLocatorDependencies {
|
||||
useHash: boolean;
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
DatasetLocatorParams,
|
||||
FilterControls,
|
||||
ListFilterControl,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/common';
|
||||
import {
|
||||
AvailableControlPanels,
|
||||
availableControlsPanels,
|
||||
DataSourceSelectionPlain,
|
||||
SMART_FALLBACK_FIELDS,
|
||||
} from '@kbn/logs-explorer-plugin/common';
|
||||
import { OBSERVABILITY_LOGS_EXPLORER_APP_ID } from '@kbn/deeplinks-observability';
|
||||
import {
|
||||
OBSERVABILITY_LOGS_EXPLORER_URL_STATE_KEY,
|
||||
logsExplorerUrlSchemaV2,
|
||||
} from '../../url_schema';
|
||||
import { deepCompactObject } from '../../utils/deep_compact_object';
|
||||
|
||||
type ControlsPageState = NonNullable<logsExplorerUrlSchemaV2.UrlSchema['controls']>;
|
||||
|
||||
interface LocatorPathConstructionParams {
|
||||
dataSourceSelection: DataSourceSelectionPlain;
|
||||
locatorParams: DatasetLocatorParams;
|
||||
useHash: boolean;
|
||||
}
|
||||
|
||||
export const constructLocatorPath = async (params: LocatorPathConstructionParams) => {
|
||||
const {
|
||||
dataSourceSelection,
|
||||
locatorParams: {
|
||||
filterControls,
|
||||
filters,
|
||||
query,
|
||||
refreshInterval,
|
||||
timeRange,
|
||||
columns,
|
||||
origin,
|
||||
breakdownField,
|
||||
},
|
||||
useHash,
|
||||
} = params;
|
||||
|
||||
const pageState = logsExplorerUrlSchemaV2.urlSchemaRT.encode(
|
||||
deepCompactObject({
|
||||
v: 2,
|
||||
dataSourceSelection,
|
||||
filters,
|
||||
query,
|
||||
refreshInterval,
|
||||
time: timeRange,
|
||||
breakdownField,
|
||||
columns: columns?.map((column) => {
|
||||
return column.type === 'smart-field' ? SMART_FALLBACK_FIELDS[column.smartField] : column;
|
||||
}),
|
||||
controls: getControlsPageStateFromFilterControlsParams(filterControls ?? {}),
|
||||
})
|
||||
);
|
||||
|
||||
const path = setStateToKbnUrl(
|
||||
OBSERVABILITY_LOGS_EXPLORER_URL_STATE_KEY,
|
||||
pageState,
|
||||
{ useHash, storeInHashQuery: false },
|
||||
'/'
|
||||
);
|
||||
|
||||
return {
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path,
|
||||
state: {
|
||||
...(origin ? { origin } : {}),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const getControlsPageStateFromFilterControlsParams = (
|
||||
filterControls: FilterControls
|
||||
): ControlsPageState => ({
|
||||
...(filterControls.namespace != null
|
||||
? getFilterControlPageStateFromListFilterControlsParams(
|
||||
availableControlsPanels.NAMESPACE,
|
||||
filterControls.namespace
|
||||
)
|
||||
: {}),
|
||||
});
|
||||
|
||||
const getFilterControlPageStateFromListFilterControlsParams = (
|
||||
controlId: AvailableControlPanels[keyof AvailableControlPanels],
|
||||
listFilterControl: ListFilterControl
|
||||
): ControlsPageState => ({
|
||||
[controlId]: {
|
||||
mode: listFilterControl.mode,
|
||||
selection: {
|
||||
type: 'options',
|
||||
selectedOptions: listFilterControl.values,
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './construct_locator_path';
|
|
@ -36,10 +36,7 @@
|
|||
"lens",
|
||||
"observabilityAIAssistant"
|
||||
],
|
||||
"requiredBundles": [
|
||||
"kibanaReact",
|
||||
"triggersActionsUi"
|
||||
],
|
||||
"requiredBundles": [],
|
||||
"extraPublicDirs": [
|
||||
"common"
|
||||
]
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { Router } from '@kbn/shared-ux-router';
|
||||
import { AppMountParameters, CoreStart } from '@kbn/core/public';
|
||||
import { DISCOVER_APP_ID } from '@kbn/deeplinks-analytics';
|
||||
|
||||
export const renderDiscoverRedirect = (core: CoreStart, appParams: AppMountParameters) => {
|
||||
ReactDOM.render(
|
||||
<Router history={appParams.history}>
|
||||
<DiscoverRedirect core={core} />
|
||||
</Router>,
|
||||
appParams.element
|
||||
);
|
||||
|
||||
return () => {
|
||||
ReactDOM.unmountComponentAtNode(appParams.element);
|
||||
};
|
||||
};
|
||||
|
||||
export const DiscoverRedirect = ({ core }: { core: CoreStart }) => {
|
||||
const location = useLocation();
|
||||
const path = `${location.pathname}${location.search}`;
|
||||
core.application.navigateToApp(DISCOVER_APP_ID, { replace: true, path });
|
||||
return <></>;
|
||||
};
|
|
@ -17,7 +17,6 @@ import { css } from '@emotion/react';
|
|||
import styled from '@emotion/styled';
|
||||
import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public';
|
||||
import { toMountPoint } from '@kbn/react-kibana-mount';
|
||||
import { LogsExplorerTabs } from '@kbn/discover-plugin/public';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import useObservable from 'react-use/lib/useObservable';
|
||||
import { filter, take } from 'rxjs';
|
||||
|
@ -45,18 +44,12 @@ export const LogsExplorerTopNavMenu = () => {
|
|||
|
||||
const ProjectTopNav = () => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const { services } = useKibanaContextForPlugin();
|
||||
|
||||
return (
|
||||
<EuiHeader
|
||||
data-test-subj="logsExplorerHeaderMenu"
|
||||
css={{ boxShadow: 'none', backgroundColor: euiTheme.colors.backgroundBasePlain }}
|
||||
>
|
||||
<EuiHeaderSection>
|
||||
<EuiHeaderSectionItem>
|
||||
<LogsExplorerTabs services={services} selectedTab="logs-explorer" />
|
||||
</EuiHeaderSectionItem>
|
||||
</EuiHeaderSection>
|
||||
<EuiHeaderSection
|
||||
side="right"
|
||||
css={css`
|
||||
|
|
|
@ -7,22 +7,12 @@
|
|||
|
||||
import {
|
||||
AppMountParameters,
|
||||
AppStatus,
|
||||
AppUpdater,
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
DEFAULT_APP_CATEGORIES,
|
||||
Plugin,
|
||||
PluginInitializerContext,
|
||||
} from '@kbn/core/public';
|
||||
import { OBSERVABILITY_LOGS_EXPLORER_APP_ID } from '@kbn/deeplinks-observability';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import {
|
||||
AllDatasetsLocatorDefinition,
|
||||
ObservabilityLogsExplorerLocators,
|
||||
SingleDatasetLocatorDefinition,
|
||||
} from '../common/locators';
|
||||
import { DataViewLocatorDefinition } from '../common/locators/data_view_locator';
|
||||
import { type ObservabilityLogsExplorerConfig } from '../common/plugin_config';
|
||||
import { DATA_RECEIVED_TELEMETRY_EVENT } from '../common/telemetry_events';
|
||||
import { logsExplorerAppTitle } from '../common/translations';
|
||||
|
@ -33,122 +23,46 @@ import type {
|
|||
ObservabilityLogsExplorerSetupDeps,
|
||||
ObservabilityLogsExplorerStartDeps,
|
||||
} from './types';
|
||||
|
||||
export class ObservabilityLogsExplorerPlugin
|
||||
implements Plugin<ObservabilityLogsExplorerPluginSetup, ObservabilityLogsExplorerPluginStart>
|
||||
{
|
||||
private locators?: ObservabilityLogsExplorerLocators;
|
||||
private appStateUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
|
||||
|
||||
constructor(context: PluginInitializerContext<ObservabilityLogsExplorerConfig>) {}
|
||||
|
||||
public setup(
|
||||
core: CoreSetup<ObservabilityLogsExplorerStartDeps, ObservabilityLogsExplorerPluginStart>,
|
||||
_pluginsSetup: ObservabilityLogsExplorerSetupDeps
|
||||
) {
|
||||
const { discover, share } = _pluginsSetup;
|
||||
const useHash = core.uiSettings.get('state:storeInSessionStorage');
|
||||
|
||||
// App used solely to redirect from "/app/observability-logs-explorer" to "/app/discover"
|
||||
core.application.register({
|
||||
id: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
title: logsExplorerAppTitle,
|
||||
category: DEFAULT_APP_CATEGORIES.observability,
|
||||
euiIconType: 'logoLogging',
|
||||
visibleIn: ['globalSearch'],
|
||||
keywords: ['logs', 'log', 'explorer', 'logs explorer'],
|
||||
updater$: this.appStateUpdater,
|
||||
visibleIn: [],
|
||||
mount: async (appMountParams: ObservabilityLogsExplorerAppMountParameters) => {
|
||||
const [coreStart, pluginsStart, ownPluginStart] = await core.getStartServices();
|
||||
const { renderObservabilityLogsExplorer } = await import(
|
||||
'./applications/observability_logs_explorer'
|
||||
);
|
||||
|
||||
return renderObservabilityLogsExplorer(
|
||||
coreStart,
|
||||
pluginsStart,
|
||||
ownPluginStart,
|
||||
appMountParams
|
||||
);
|
||||
const [coreStart] = await core.getStartServices();
|
||||
const { renderDiscoverRedirect } = await import('./applications/redirect_to_discover');
|
||||
return renderDiscoverRedirect(coreStart, appMountParams);
|
||||
},
|
||||
});
|
||||
|
||||
// ensure the tabs are shown when in the observability nav mode
|
||||
discover.configureInlineTopNav('oblt', {
|
||||
enabled: true,
|
||||
showLogsExplorerTabs: true,
|
||||
});
|
||||
|
||||
// App used solely to redirect from "/app/observability-log-explorer" to "/app/observability-logs-explorer"
|
||||
// App used solely to redirect from "/app/observability-log-explorer" to "/app/discover"
|
||||
core.application.register({
|
||||
id: 'observability-log-explorer',
|
||||
title: logsExplorerAppTitle,
|
||||
visibleIn: [],
|
||||
mount: async (appMountParams: AppMountParameters) => {
|
||||
const [coreStart] = await core.getStartServices();
|
||||
const { renderObservabilityLogsExplorerRedirect } = await import(
|
||||
'./applications/redirect_to_observability_logs_explorer'
|
||||
);
|
||||
|
||||
return renderObservabilityLogsExplorerRedirect(coreStart, appMountParams);
|
||||
},
|
||||
});
|
||||
|
||||
// App used solely to redirect to either "/app/observability-logs-explorer" or "/app/discover"
|
||||
// based on the last used app value in localStorage
|
||||
core.application.register({
|
||||
id: 'last-used-logs-viewer',
|
||||
title: logsExplorerAppTitle,
|
||||
visibleIn: [],
|
||||
mount: async (appMountParams: AppMountParameters) => {
|
||||
const [coreStart] = await core.getStartServices();
|
||||
const { renderLastUsedLogsViewerRedirect } = await import(
|
||||
'./applications/last_used_logs_viewer'
|
||||
);
|
||||
|
||||
return renderLastUsedLogsViewerRedirect(coreStart, appMountParams);
|
||||
const { renderDiscoverRedirect } = await import('./applications/redirect_to_discover');
|
||||
return renderDiscoverRedirect(coreStart, appMountParams);
|
||||
},
|
||||
});
|
||||
|
||||
core.analytics.registerEventType(DATA_RECEIVED_TELEMETRY_EVENT);
|
||||
|
||||
// Register Locators
|
||||
const allDatasetsLocator = share.url.locators.create(
|
||||
new AllDatasetsLocatorDefinition({
|
||||
useHash,
|
||||
})
|
||||
);
|
||||
|
||||
const dataViewLocator = share.url.locators.create(
|
||||
new DataViewLocatorDefinition({
|
||||
useHash,
|
||||
})
|
||||
);
|
||||
const singleDatasetLocator = share.url.locators.create(
|
||||
new SingleDatasetLocatorDefinition({
|
||||
useHash,
|
||||
})
|
||||
);
|
||||
|
||||
this.locators = {
|
||||
allDatasetsLocator,
|
||||
dataViewLocator,
|
||||
singleDatasetLocator,
|
||||
};
|
||||
|
||||
return {
|
||||
locators: this.locators,
|
||||
};
|
||||
return {};
|
||||
}
|
||||
|
||||
public start(core: CoreStart, _pluginsStart: ObservabilityLogsExplorerStartDeps) {
|
||||
const { discover, fleet, logs } = core.application.capabilities;
|
||||
|
||||
if (!(discover?.show && fleet?.read && logs?.show)) {
|
||||
this.appStateUpdater.next(() => ({
|
||||
status: AppStatus.inaccessible,
|
||||
visibleIn: [],
|
||||
}));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,14 +27,10 @@ import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public';
|
|||
import { LensPublicStart } from '@kbn/lens-plugin/public';
|
||||
import { SLOPublicStart } from '@kbn/slo-plugin/public';
|
||||
import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public';
|
||||
import {
|
||||
ObservabilityLogsExplorerLocators,
|
||||
ObservabilityLogsExplorerLocationState,
|
||||
} from '../common/locators';
|
||||
import type { ObservabilityLogsExplorerLocationState } from '@kbn/deeplinks-observability/locators';
|
||||
|
||||
export interface ObservabilityLogsExplorerPluginSetup {
|
||||
locators: ObservabilityLogsExplorerLocators;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface ObservabilityLogsExplorerPluginSetup {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface ObservabilityLogsExplorerPluginStart {}
|
||||
|
|
|
@ -488,10 +488,7 @@ describe('[Logs onboarding] Custom logs - install elastic agent', () => {
|
|||
cy.wait('@checkOnboardingProgress');
|
||||
cy.getByTestSubj('obltOnboardingExploreLogs').should('exist').click();
|
||||
|
||||
cy.url().should('include', '/app/observability-logs-explorer');
|
||||
cy.get('[data-test-subj="dataSourceSelectorPopoverButton"]')
|
||||
.contains('[Mylogs] mylogs', { matchCase: false })
|
||||
.should('exist');
|
||||
cy.url().should('include', '/app/discover');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"type": "plugin",
|
||||
"id": "@kbn/observability-onboarding-plugin",
|
||||
"owner": ["@elastic/obs-ux-logs-team"],
|
||||
"owner": [
|
||||
"@elastic/obs-ux-logs-team"
|
||||
],
|
||||
"group": "observability",
|
||||
"visibility": "private",
|
||||
"plugin": {
|
||||
|
@ -16,6 +18,7 @@
|
|||
"data",
|
||||
"observability",
|
||||
"observabilityShared",
|
||||
"logsShared",
|
||||
"discover",
|
||||
"share",
|
||||
"fleet",
|
||||
|
|
|
@ -14,23 +14,20 @@ import {
|
|||
EuiSpacer,
|
||||
EuiSkeletonText,
|
||||
EuiText,
|
||||
EuiButtonEmpty,
|
||||
useGeneratedHtmlId,
|
||||
EuiIcon,
|
||||
} from '@elastic/eui';
|
||||
import {
|
||||
type SingleDatasetLocatorParams,
|
||||
SINGLE_DATASET_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics';
|
||||
import { ASSET_DETAILS_LOCATOR_ID } from '@kbn/observability-shared-plugin/common';
|
||||
import { type LogsLocatorParams, LOGS_LOCATOR_ID } from '@kbn/logs-shared-plugin/common';
|
||||
import { getAutoDetectCommand } from './get_auto_detect_command';
|
||||
import { DASHBOARDS, useOnboardingFlow } from './use_onboarding_flow';
|
||||
import { ProgressIndicator } from '../shared/progress_indicator';
|
||||
import { AccordionWithIcon } from '../shared/accordion_with_icon';
|
||||
import { EmptyPrompt } from '../shared/empty_prompt';
|
||||
import { CopyToClipboardButton } from '../shared/copy_to_clipboard_button';
|
||||
import { LocatorButtonEmpty } from '../shared/locator_button_empty';
|
||||
import { GetStartedPanel } from '../shared/get_started_panel';
|
||||
import { isSupportedLogo, LogoIcon } from '../../shared/logo_icon';
|
||||
import { FeedbackButtons } from '../shared/feedback_buttons';
|
||||
|
@ -66,6 +63,7 @@ export const AutoDetectPanel: FunctionComponent = () => {
|
|||
const customIntegrations = installedIntegrations.filter(
|
||||
(integration) => integration.installSource === 'custom'
|
||||
);
|
||||
const logsLocator = share.url.locators.get<LogsLocatorParams>(LOGS_LOCATOR_ID);
|
||||
const dashboardLocator = share.url.locators.get(DASHBOARD_APP_LOCATOR);
|
||||
const assetDetailsLocator = share.url.locators.get(ASSET_DETAILS_LOCATOR_ID);
|
||||
|
||||
|
@ -295,12 +293,15 @@ export const AutoDetectPanel: FunctionComponent = () => {
|
|||
{customIntegrations.map((integration) =>
|
||||
integration.dataStreams.map((datastream) => (
|
||||
<li key={`${integration.pkgName}/${datastream.dataset}`}>
|
||||
<LocatorButtonEmpty<SingleDatasetLocatorParams>
|
||||
locator={SINGLE_DATASET_LOCATOR_ID}
|
||||
params={{
|
||||
integration: integration.pkgName,
|
||||
dataset: datastream.dataset,
|
||||
}}
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="observabilityOnboardingAutoDetectPanelButton"
|
||||
href={logsLocator?.getRedirectUrl({
|
||||
dataViewSpec: {
|
||||
name: integration.pkgName,
|
||||
title: `${datastream.type}-${datastream.dataset}-*`,
|
||||
timeFieldName: '@timestamp',
|
||||
},
|
||||
})}
|
||||
target="_blank"
|
||||
iconType="document"
|
||||
isDisabled={status !== 'dataReceived'}
|
||||
|
@ -308,7 +309,7 @@ export const AutoDetectPanel: FunctionComponent = () => {
|
|||
size="s"
|
||||
>
|
||||
{integration.pkgName}
|
||||
</LocatorButtonEmpty>
|
||||
</EuiButtonEmpty>
|
||||
</li>
|
||||
))
|
||||
)}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue