mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[Dataset Quality] Added Dataset Quality Locator (#177000)
closes https://github.com/elastic/kibana/issues/170611
## 📝 Summary
This PR adds the infrastructure work for the locators needed to create
the navigation link from the Logs Explorer to the Dataset Quality Page,
but the links themselves are to be added with a later ticket.
## 💡For Reviewers
To be abled to test this PR you can add the below code
[here](https://github.com/elastic/kibana/blob/main/x-pack/plugins/observability_solution/observability_logs_explorer/public/components/logs_explorer_top_nav_menu.tsx#L150)
to make the link visible in the Logs Explorer Page.
`<ConnectedDatasetQualityLink />
<VerticalRule />`
## 🎥 Demo
1f3ce10a
-3b8c-4027-b72d-1ed71b782fa5
This commit is contained in:
parent
03e8e9c5f0
commit
9a473879af
13 changed files with 283 additions and 4 deletions
33
packages/deeplinks/observability/locators/dataset_quality.ts
Normal file
33
packages/deeplinks/observability/locators/dataset_quality.ts
Normal file
|
@ -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 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 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SerializableRecord } from '@kbn/utility-types';
|
||||
|
||||
export const DATASET_QUALITY_LOCATOR_ID = 'DATASET_QUALITY_LOCATOR';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
type RefreshInterval = {
|
||||
isPaused: boolean;
|
||||
interval: number;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
type TimeRangeConfig = {
|
||||
from: string;
|
||||
to: string;
|
||||
refresh: RefreshInterval;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
type Filters = {
|
||||
timeRange: TimeRangeConfig;
|
||||
};
|
||||
|
||||
export interface DatasetQualityLocatorParams extends SerializableRecord {
|
||||
filters?: Filters;
|
||||
}
|
|
@ -9,3 +9,4 @@
|
|||
export * from './logs_explorer';
|
||||
export * from './observability_logs_explorer';
|
||||
export * from './observability_onboarding';
|
||||
export * from './dataset_quality';
|
||||
|
|
|
@ -31,8 +31,10 @@ import { mapPercentagesToQualityCounts } from '../../quality_indicator';
|
|||
import { InfoIndicators } from '../../common';
|
||||
|
||||
export function DatasetsQualityIndicators() {
|
||||
const { datasetsQuality, isDatasetsQualityLoading } = useSummaryPanelContext();
|
||||
const { datasetsQuality, isDatasetsQualityLoading, datasetsActivity } = useSummaryPanelContext();
|
||||
const qualityCounts = mapPercentagesToQualityCounts(datasetsQuality.percentages);
|
||||
const datasetsWithoutIgnoredField =
|
||||
datasetsActivity.total > 0 ? datasetsActivity.total - datasetsQuality.percentages.length : 0;
|
||||
|
||||
return (
|
||||
<EuiPanel hasBorder>
|
||||
|
@ -61,7 +63,7 @@ export function DatasetsQualityIndicators() {
|
|||
/>
|
||||
<span css={verticalRule} />
|
||||
<QualityIndicator
|
||||
value={qualityCounts.good}
|
||||
value={qualityCounts.good + datasetsWithoutIgnoredField}
|
||||
quality="success"
|
||||
description={summaryPanelQualityGoodText}
|
||||
isLoading={isDatasetsQualityLoading}
|
||||
|
|
|
@ -34,7 +34,9 @@ const useSummaryPanel = ({ dataStreamStatsClient, toasts }: SummaryPanelContextD
|
|||
const isDatasetsQualityLoading = useSelector(
|
||||
summaryPanelStateService,
|
||||
(state) =>
|
||||
state.matches('datasetsQuality.fetching') || state.matches('datasetsQuality.retrying')
|
||||
state.matches('datasetsQuality.fetching') ||
|
||||
state.matches('datasetsQuality.retrying') ||
|
||||
state.matches('datasetsActivity.fetching')
|
||||
);
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 {
|
||||
DatasetQualityLocatorParams,
|
||||
DATASET_QUALITY_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { DatasetQualityLocatorDependencies } from './types';
|
||||
import { constructDatasetQualityLocatorPath } from './utils';
|
||||
|
||||
export type DatasetQualityLocator = LocatorPublic<DatasetQualityLocatorParams>;
|
||||
|
||||
export class DatasetQualityLocatorDefinition
|
||||
implements LocatorDefinition<DatasetQualityLocatorParams>
|
||||
{
|
||||
public readonly id = DATASET_QUALITY_LOCATOR_ID;
|
||||
|
||||
constructor(protected readonly deps: DatasetQualityLocatorDependencies) {}
|
||||
|
||||
public readonly getLocation = async (params: DatasetQualityLocatorParams) => {
|
||||
const { useHash } = this.deps;
|
||||
return constructDatasetQualityLocatorPath({ useHash, locatorParams: params });
|
||||
};
|
||||
}
|
|
@ -9,7 +9,9 @@ export type { ObservabilityLogsExplorerLocationState } from '@kbn/deeplinks-obse
|
|||
import { AllDatasetsLocator } from './all_datasets_locator';
|
||||
import { DataViewLocator } from './data_view_locator';
|
||||
import { SingleDatasetLocator } from './single_dataset_locator';
|
||||
import { DatasetQualityLocator } from './dataset_quality_locator';
|
||||
|
||||
export * from './dataset_quality_locator';
|
||||
export * from './single_dataset_locator';
|
||||
export * from './all_datasets_locator';
|
||||
export * from './utils';
|
||||
|
@ -18,4 +20,5 @@ export interface ObservabilityLogsExplorerLocators {
|
|||
allDatasetsLocator: AllDatasetsLocator;
|
||||
dataViewLocator: DataViewLocator;
|
||||
singleDatasetLocator: SingleDatasetLocator;
|
||||
datasetQualityLocator: DatasetQualityLocator;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
import { OBSERVABILITY_LOGS_EXPLORER_APP_ID } from '@kbn/deeplinks-observability';
|
||||
import {
|
||||
AllDatasetsLocatorParams,
|
||||
ObsLogsExplorerDataViewLocatorParams,
|
||||
SingleDatasetLocatorParams,
|
||||
ObsLogsExplorerDataViewLocatorParams,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { DatasetQualityLocatorDefinition } from './dataset_quality_locator';
|
||||
import { AllDatasetsLocatorDefinition } from './all_datasets_locator';
|
||||
import { DataViewLocatorDefinition } from './data_view_locator';
|
||||
import { SingleDatasetLocatorDefinition } from './single_dataset_locator';
|
||||
|
@ -23,11 +24,13 @@ const setup = async () => {
|
|||
const allDatasetsLocator = new AllDatasetsLocatorDefinition(dep);
|
||||
const dataViewLocator = new DataViewLocatorDefinition(dep);
|
||||
const singleDatasetLocator = new SingleDatasetLocatorDefinition(dep);
|
||||
const datasetQualityLocator = new DatasetQualityLocatorDefinition(dep);
|
||||
|
||||
return {
|
||||
allDatasetsLocator,
|
||||
dataViewLocator,
|
||||
singleDatasetLocator,
|
||||
datasetQualityLocator,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -375,4 +378,41 @@ describe('Observability Logs Explorer Locators', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dataset Quality Locator', () => {
|
||||
it('should create a link with correct path and no state', async () => {
|
||||
const { datasetQualityLocator } = await setup();
|
||||
const location = await datasetQualityLocator.getLocation({});
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: '/dataset-quality?pageState=(v:1)',
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a link with correct timeRange', async () => {
|
||||
const refresh = {
|
||||
isPaused: false,
|
||||
interval: 0,
|
||||
};
|
||||
const locatorParams = {
|
||||
filters: {
|
||||
timeRange: {
|
||||
...timeRange,
|
||||
refresh,
|
||||
},
|
||||
},
|
||||
};
|
||||
const { datasetQualityLocator } = await setup();
|
||||
|
||||
const location = await datasetQualityLocator.getLocation(locatorParams);
|
||||
|
||||
expect(location).toMatchObject({
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path: '/dataset-quality?pageState=(filters:(timeRange:(from:now-30m,refresh:(interval:0,isPaused:!f),to:now)),v:1)',
|
||||
state: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,3 +7,7 @@
|
|||
export interface ObsLogsExplorerLocatorDependencies {
|
||||
useHash: boolean;
|
||||
}
|
||||
|
||||
export interface DatasetQualityLocatorDependencies {
|
||||
useHash: boolean;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 { DatasetQualityLocatorParams } from '@kbn/deeplinks-observability/locators';
|
||||
import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/common';
|
||||
import { OBSERVABILITY_LOGS_EXPLORER_APP_ID } from '@kbn/deeplinks-observability';
|
||||
import {
|
||||
OBSERVABILITY_DATASET_QUALITY_URL_STATE_KEY,
|
||||
datasetQualityUrlSchemaV1,
|
||||
} from '../../url_schema';
|
||||
import { deepCompactObject } from '../../utils/deep_compact_object';
|
||||
|
||||
interface LocatorPathConstructionParams {
|
||||
locatorParams: DatasetQualityLocatorParams;
|
||||
useHash: boolean;
|
||||
}
|
||||
|
||||
export const constructDatasetQualityLocatorPath = async (params: LocatorPathConstructionParams) => {
|
||||
const {
|
||||
locatorParams: { filters },
|
||||
useHash,
|
||||
} = params;
|
||||
|
||||
const pageState = datasetQualityUrlSchemaV1.urlSchemaRT.encode(
|
||||
deepCompactObject({
|
||||
v: 1,
|
||||
filters,
|
||||
})
|
||||
);
|
||||
|
||||
const path = setStateToKbnUrl(
|
||||
OBSERVABILITY_DATASET_QUALITY_URL_STATE_KEY,
|
||||
pageState,
|
||||
{ useHash, storeInHashQuery: false },
|
||||
'/dataset-quality'
|
||||
);
|
||||
|
||||
return {
|
||||
app: OBSERVABILITY_LOGS_EXPLORER_APP_ID,
|
||||
path,
|
||||
state: {},
|
||||
};
|
||||
};
|
|
@ -6,3 +6,4 @@
|
|||
*/
|
||||
|
||||
export * from './construct_locator_path';
|
||||
export * from './construct_dataset_quality_locator_path';
|
||||
|
|
|
@ -53,3 +53,10 @@ export const feedbackLinkTitle = i18n.translate(
|
|||
defaultMessage: 'Give feedback',
|
||||
}
|
||||
);
|
||||
|
||||
export const datasetQualityLinkTitle = i18n.translate(
|
||||
'xpack.observabilityLogsExplorer.datasetQualityLinkTitle',
|
||||
{
|
||||
defaultMessage: 'Datasets',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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 { EuiHeaderLink } from '@elastic/eui';
|
||||
import {
|
||||
DatasetQualityLocatorParams,
|
||||
DATASET_QUALITY_LOCATOR_ID,
|
||||
} from '@kbn/deeplinks-observability/locators';
|
||||
import { LogsExplorerPublicState } from '@kbn/logs-explorer-plugin/public';
|
||||
import { getRouterLinkProps } from '@kbn/router-utils';
|
||||
import { BrowserUrlService } from '@kbn/share-plugin/public';
|
||||
import { MatchedStateFromActor } from '@kbn/xstate-utils';
|
||||
import { useActor } from '@xstate/react';
|
||||
import React from 'react';
|
||||
import { datasetQualityLinkTitle } from '../../common/translations';
|
||||
import {
|
||||
ObservabilityLogsExplorerService,
|
||||
useObservabilityLogsExplorerPageStateContext,
|
||||
} from '../state_machines/observability_logs_explorer/src';
|
||||
import { useKibanaContextForPlugin } from '../utils/use_kibana';
|
||||
|
||||
export const ConnectedDatasetQualityLink = React.memo(() => {
|
||||
const {
|
||||
services: {
|
||||
share: { url },
|
||||
},
|
||||
} = useKibanaContextForPlugin();
|
||||
const [pageState] = useActor(useObservabilityLogsExplorerPageStateContext());
|
||||
|
||||
if (pageState.matches({ initialized: 'validLogsExplorerState' })) {
|
||||
return <DatasetQualityLink urlService={url} pageState={pageState} />;
|
||||
} else {
|
||||
return <DatasetQualityLink urlService={url} />;
|
||||
}
|
||||
});
|
||||
|
||||
type InitializedPageState = MatchedStateFromActor<
|
||||
ObservabilityLogsExplorerService,
|
||||
{ initialized: 'validLogsExplorerState' }
|
||||
>;
|
||||
|
||||
const constructLocatorParams = (
|
||||
logsExplorerState: LogsExplorerPublicState
|
||||
): DatasetQualityLocatorParams => {
|
||||
const { time, refreshInterval } = logsExplorerState;
|
||||
const locatorParams: DatasetQualityLocatorParams = {
|
||||
filters: {
|
||||
timeRange: {
|
||||
from: time?.from || 'now-24h',
|
||||
to: time?.to || 'now',
|
||||
refresh: {
|
||||
isPaused: refreshInterval ? refreshInterval.pause : false,
|
||||
interval: refreshInterval ? refreshInterval.value : 60000,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return locatorParams;
|
||||
};
|
||||
|
||||
export const DatasetQualityLink = React.memo(
|
||||
({
|
||||
urlService,
|
||||
pageState,
|
||||
}: {
|
||||
urlService: BrowserUrlService;
|
||||
pageState?: InitializedPageState;
|
||||
}) => {
|
||||
const locator = urlService.locators.get<DatasetQualityLocatorParams>(
|
||||
DATASET_QUALITY_LOCATOR_ID
|
||||
);
|
||||
const locatorParams: DatasetQualityLocatorParams = pageState
|
||||
? constructLocatorParams(pageState.context.logsExplorerState)
|
||||
: {};
|
||||
|
||||
const datasetQualityUrl = locator?.useUrl(locatorParams);
|
||||
|
||||
const navigateToDatasetQuality = () => {
|
||||
locator?.navigate(locatorParams);
|
||||
};
|
||||
|
||||
const datasetQualityLinkProps = getRouterLinkProps({
|
||||
href: datasetQualityUrl,
|
||||
onClick: navigateToDatasetQuality,
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiHeaderLink
|
||||
{...datasetQualityLinkProps}
|
||||
color="primary"
|
||||
data-test-subj="logsExplorerDatasetQualityLink"
|
||||
>
|
||||
{datasetQualityLinkTitle}
|
||||
</EuiHeaderLink>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -16,6 +16,7 @@ import {
|
|||
import { OBSERVABILITY_LOGS_EXPLORER_APP_ID } from '@kbn/deeplinks-observability';
|
||||
import {
|
||||
AllDatasetsLocatorDefinition,
|
||||
DatasetQualityLocatorDefinition,
|
||||
ObservabilityLogsExplorerLocators,
|
||||
SingleDatasetLocatorDefinition,
|
||||
} from '../common/locators';
|
||||
|
@ -95,6 +96,12 @@ export class ObservabilityLogsExplorerPlugin
|
|||
useHash,
|
||||
})
|
||||
);
|
||||
const datasetQualityLocator = share.url.locators.create(
|
||||
new DatasetQualityLocatorDefinition({
|
||||
useHash,
|
||||
})
|
||||
);
|
||||
|
||||
const dataViewLocator = share.url.locators.create(
|
||||
new DataViewLocatorDefinition({
|
||||
useHash,
|
||||
|
@ -108,6 +115,7 @@ export class ObservabilityLogsExplorerPlugin
|
|||
|
||||
this.locators = {
|
||||
allDatasetsLocator,
|
||||
datasetQualityLocator,
|
||||
dataViewLocator,
|
||||
singleDatasetLocator,
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue