Skip to content

Commit

Permalink
[Discover] Suppress "Missing index" toasts (#149625)
Browse files Browse the repository at this point in the history
Closes #129020

<img width="1339" alt="Screenshot 2023-01-27 at 16 56 16"
src="https://user-images.githubusercontent.com/1415710/215130435-d5185670-0f34-4ecd-a646-22313ebe3b75.png">

---------

Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>
Co-authored-by: Matthew Kime <matt@mattki.me>
  • Loading branch information
3 people authored Feb 14, 2023
1 parent 6e58c2d commit 668fe89
Show file tree
Hide file tree
Showing 15 changed files with 174 additions and 63 deletions.
41 changes: 40 additions & 1 deletion src/plugins/data_views/common/data_views/data_views.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ describe('IndexPatterns', () => {
describe('getDefaultDataView', () => {
beforeEach(() => {
indexPatterns.clearCache();
jest.resetAllMocks();
jest.clearAllMocks();
});

test('gets default data view', async () => {
Expand All @@ -434,6 +434,44 @@ describe('IndexPatterns', () => {
expect(savedObjectsClient.find).toBeCalledTimes(1);
});

test('gets default data view and passes down defined arguments (refreshFields and displayErrors)', async () => {
uiSettings.get = jest.fn().mockResolvedValue(indexPatternObj.id);
savedObjectsClient.get = jest.fn().mockResolvedValue(indexPatternObj);
savedObjectsClient.find = jest.fn().mockResolvedValue([indexPatternObj]);
jest.spyOn(indexPatterns, 'get');
jest.spyOn(indexPatterns, 'refreshFields');

const dataView = await indexPatterns.get(indexPatternObj.id); // and to cache the result

const refreshFields = true;
const displayErrors = false;
expect(
await indexPatterns.getDefaultDataView({ refreshFields, displayErrors })
).toBeInstanceOf(DataView);
expect(savedObjectsClient.get).toBeCalledTimes(1);
expect(savedObjectsClient.find).toBeCalledTimes(1);

expect(indexPatterns.get).toBeCalledWith(indexPatternObj.id, displayErrors, refreshFields);
expect(indexPatterns.refreshFields).toBeCalledWith(dataView, displayErrors);
});

test('gets default data view and passes down undefined arguments (refreshFields and displayErrors)', async () => {
uiSettings.get = jest.fn().mockResolvedValue(indexPatternObj.id);
savedObjectsClient.get = jest.fn().mockResolvedValue(indexPatternObj);
savedObjectsClient.find = jest.fn().mockResolvedValue([indexPatternObj]);
jest.spyOn(indexPatterns, 'get');
jest.spyOn(indexPatterns, 'refreshFields');

await indexPatterns.get(indexPatternObj.id); // to cache the result

expect(await indexPatterns.getDefaultDataView()).toBeInstanceOf(DataView);
expect(savedObjectsClient.get).toBeCalledTimes(1);
expect(savedObjectsClient.find).toBeCalledTimes(1);

expect(indexPatterns.get).toBeCalledWith(indexPatternObj.id, true, undefined);
expect(indexPatterns.refreshFields).not.toBeCalled();
});

test('returns undefined if no data views exist', async () => {
uiSettings.get = jest.fn().mockResolvedValue('foo');
savedObjectsClient.find = jest.fn().mockResolvedValue([]);
Expand Down Expand Up @@ -487,6 +525,7 @@ describe('IndexPatterns', () => {
});

test('dont set defaultIndex without capability allowing advancedSettings save', async () => {
uiSettings.get = jest.fn().mockResolvedValue(null);
savedObjectsClient.find = jest.fn().mockResolvedValue([
{
id: 'id1',
Expand Down
45 changes: 32 additions & 13 deletions src/plugins/data_views/common/data_views/data_views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,14 @@ export interface DataViewsServicePublicMethods {
getDefaultId: () => Promise<string | null>;
/**
* Get default data view, if it doesn't exist, choose and save new default data view and return it.
* @param refreshFields - refresh field list when true
* @param {Object} options
* @param {boolean} options.refreshFields - If true, will refresh the fields of the default data view
* @param {boolean} [options.displayErrors=true] - If set false, API consumer is responsible for displaying and handling errors.
*/
getDefaultDataView: (refreshFields?: boolean) => Promise<DataView | null>;
getDefaultDataView: (options?: {
refreshFields?: boolean;
displayErrors?: boolean;
}) => Promise<DataView | null>;
/**
* Get fields for data view
* @param dataView - Data view instance or spec
Expand Down Expand Up @@ -259,7 +264,6 @@ export interface DataViewsServicePublicMethods {
/**
* Converts data view saved object to spec
* @params savedObject - Data view saved object
* @params displayErrors - If set false, API consumer is responsible for displaying and handling errors.
*/
savedObjectToSpec: (savedObject: SavedObject<DataViewAttributes>) => DataViewSpec;
/**
Expand Down Expand Up @@ -610,7 +614,8 @@ export class DataViewsService {
id: string,
title: string,
options: GetFieldsOptions,
fieldAttrs: FieldAttrs = {}
fieldAttrs: FieldAttrs = {},
displayErrors: boolean = true
) => {
const fieldsAsArr = Object.values(fields);
const scriptedFields = fieldsAsArr.filter((field) => field.scripted);
Expand All @@ -630,10 +635,12 @@ export class DataViewsService {
return { fields: this.fieldArrayToMap(updatedFieldList, fieldAttrs), indices };
} catch (err) {
if (err instanceof DataViewMissingIndices) {
this.onNotification(
{ title: err.message, color: 'danger', iconType: 'alert' },
`refreshFieldSpecMap:${title}`
);
if (displayErrors) {
this.onNotification(
{ title: err.message, color: 'danger', iconType: 'alert' },
`refreshFieldSpecMap:${title}`
);
}
return {};
}

Expand Down Expand Up @@ -739,9 +746,11 @@ export class DataViewsService {
private initFromSavedObjectLoadFields = async ({
savedObjectId,
spec,
displayErrors = true,
}: {
savedObjectId: string;
spec: DataViewSpec;
displayErrors?: boolean;
}) => {
const { title, type, typeMeta, runtimeFieldMap } = spec;
const { fields, indices } = await this.refreshFieldSpecMap(
Expand All @@ -755,7 +764,8 @@ export class DataViewsService {
rollupIndex: typeMeta?.params?.rollup_index,
allowNoIndex: spec.allowNoIndex,
},
spec.fieldAttrs
spec.fieldAttrs,
displayErrors
);

const runtimeFieldSpecs = this.getRuntimeFields(runtimeFieldMap, spec.fieldAttrs);
Expand All @@ -779,6 +789,7 @@ export class DataViewsService {
const fieldsAndIndices = await this.initFromSavedObjectLoadFields({
savedObjectId: savedObject.id,
spec,
displayErrors,
});
fields = fieldsAndIndices.fields;
indices = fieldsAndIndices.indices;
Expand Down Expand Up @@ -883,7 +894,7 @@ export class DataViewsService {
): Promise<DataView> => {
const dataViewFromCache = this.dataViewCache.get(id)?.then(async (dataView) => {
if (dataView && refreshFields) {
await this.refreshFields(dataView);
await this.refreshFields(dataView, displayErrors);
}
return dataView;
});
Expand Down Expand Up @@ -1144,10 +1155,18 @@ export class DataViewsService {
* another data view is selected as default and returned.
* If no possible data view found to become a default returns null.
*
* @param {boolean} refreshFields - if true, will refresh the fields of the default data view
* @param {Object} options
* @param {boolean} options.refreshFields - If true, will refresh the fields of the default data view
* @param {boolean} [options.displayErrors=true] - If set false, API consumer is responsible for displaying and handling errors.
* @returns default data view
*/
async getDefaultDataView(refreshFields?: boolean): Promise<DataView | null> {
async getDefaultDataView(
options: {
displayErrors?: boolean;
refreshFields?: boolean;
} = {}
): Promise<DataView | null> {
const { displayErrors = true, refreshFields } = options;
const patterns = await this.getIdsWithTitle();
let defaultId: string | undefined = await this.config.get('defaultIndex');
const exists = defaultId ? patterns.some((pattern) => pattern.id === defaultId) : false;
Expand All @@ -1168,7 +1187,7 @@ export class DataViewsService {
}

if (defaultId) {
return this.get(defaultId, undefined, refreshFields);
return this.get(defaultId, displayErrors, refreshFields);
} else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export function DiscoverNoResults({
<EuiCallOut
title={
<FormattedMessage
id="discover.noResults.searchExamples.noResultsBecauseOfError"
defaultMessage="We encountered an error retrieving search results"
id="discover.noResults.searchExamples.noResultsErrorTitle"
defaultMessage="Unable to retrieve search results"
/>
}
color="danger"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,36 @@

import React from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiText } from '@elastic/eui';
import { EuiText, EuiCode } from '@elastic/eui';
import type { DataView } from '@kbn/data-views-plugin/common';

export interface NoResultsSuggestionDefaultProps {
dataView: DataView;
}

export const NoResultsSuggestionDefault: React.FC<NoResultsSuggestionDefaultProps> = ({
dataView,
}) => {
const dataViewName = dataView?.getName();
const dataViewPattern = dataView?.getIndexPattern();

export function NoResultsSuggestionDefault() {
return (
<EuiText data-test-subj="discoverNoResultsCheckIndices">
<FormattedMessage
id="discover.noResults.noDocumentsOrCheckPermissionsDescription"
defaultMessage="Make sure you have permission to view the indices and that they contain documents."
/>
{dataViewName && dataViewPattern ? (
<FormattedMessage
id="discover.noResults.noDocumentsOrCheckIndicesAndPermissionsDescription"
defaultMessage="Make sure that the data view {dataViewName} with index pattern {dataViewPattern} has matching indices and documents and that you have permission to view them."
values={{
dataViewName: <strong>{dataViewName}</strong>,
dataViewPattern: <EuiCode>{dataViewPattern}</EuiCode>,
}}
/>
) : (
<FormattedMessage
id="discover.noResults.noDocumentsOrCheckPermissionsDescription"
defaultMessage="Make sure that you have permission to view the indices and that they contain documents."
/>
)}
</EuiText>
);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export const NoResultsSuggestions: React.FC<NoResultsSuggestionProps> = ({
</ul>
</>
) : (
<NoResultsSuggestionDefault />
<NoResultsSuggestionDefault dataView={dataView} />
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,27 @@ export const useFetchOccurrencesRange = (params: Params): Result => {
const fetchOccurrences = useCallback(
async (dataView?: DataView, query?: Query | AggregateQuery, filters?: Filter[]) => {
let occurrencesRange = null;
if (!dataView?.timeFieldName || !query || !mountedRef.current) {
return null;
}

abortControllerRef.current?.abort();
abortControllerRef.current = new AbortController();

try {
const dslQuery = buildEsQuery(
dataView,
query ?? [],
filters ?? [],
getEsQueryConfig(uiSettings)
);
occurrencesRange = await fetchDocumentsTimeRange({
data,
dataView,
dslQuery,
abortSignal: abortControllerRef.current?.signal,
});
} catch (error) {
//
if (dataView?.isTimeBased() && query && mountedRef.current) {
abortControllerRef.current?.abort();
abortControllerRef.current = new AbortController();

try {
const dslQuery = buildEsQuery(
dataView,
query ?? [],
filters ?? [],
getEsQueryConfig(uiSettings)
);
occurrencesRange = await fetchDocumentsTimeRange({
data,
dataView,
dslQuery,
abortSignal: abortControllerRef.current?.signal,
});
} catch (error) {
//
}
}

if (mountedRef.current) {
Expand Down Expand Up @@ -115,7 +114,7 @@ async function fetchDocumentsTimeRange({
data.search.search(
{
params: {
index: dataView.title,
index: dataView.getIndexPattern(),
size: 0,
body: {
query: dslQuery ?? { match_all: {} },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,12 @@ export function DiscoverMainRoute(props: Props) {
return;
}

const defaultDataView = await data.dataViews.getDefaultDataView();
let defaultDataView: DataView | null = null;
try {
defaultDataView = await data.dataViews.getDefaultDataView({ displayErrors: false });
} catch (e) {
//
}

if (!defaultDataView) {
setShowNoDataPage(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ export async function changeDataView(
const { dataViews, uiSettings } = services;
const dataView = discoverState.internalState.getState().dataView;
const state = discoverState.appState.getState();
const nextDataView = await dataViews.get(id);
let nextDataView: DataView | null = null;

try {
nextDataView = await dataViews.get(id, false);
} catch (e) {
//
}

if (nextDataView && dataView) {
const nextAppState = getDataViewAppState(
dataView,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ export async function loadDataView(
fetchId = dataViewSpec.id!;
}

let fetchedDataView: DataView | undefined;
let fetchedDataView: DataView | null = null;
// try to fetch adhoc data view first
try {
fetchedDataView = fetchId ? await dataViews.get(fetchId) : undefined;
fetchedDataView = fetchId ? await dataViews.get(fetchId, false) : null;
if (fetchedDataView && !fetchedDataView.isPersisted()) {
return {
list: dataViewList || [],
Expand All @@ -82,13 +82,20 @@ export async function loadDataView(
// eslint-disable-next-line no-empty
} catch (e) {}

let defaultDataView: DataView | null = null;
if (!fetchedDataView) {
try {
defaultDataView = await dataViews.getDefaultDataView({ displayErrors: false });
} catch (e) {
//
}
}

// fetch persisted data view
return {
list: dataViewList || [],
loaded: fetchedDataView
? fetchedDataView
: // we can be certain that the data view exists due to an earlier hasData check
((await dataViews.getDefaultDataView()) as DataView),
// we can be certain that the data view exists due to an earlier hasData check
loaded: fetchedDataView || defaultDataView!,
stateVal: fetchId,
stateValFound: !!fetchId && !!fetchedDataView,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,13 @@ export const useExistingFieldsFetcher = (
}

const numberOfFetches = (currentInfo?.numberOfFetches ?? 0) + 1;
const dataView = await dataViews.get(dataViewId);
let dataView: DataView | null = null;

try {
dataView = await dataViews.get(dataViewId, false);
} catch (e) {
//
}

if (!dataView?.title) {
return;
Expand Down Expand Up @@ -155,8 +161,6 @@ export const useExistingFieldsFetcher = (
info.existingFieldsByFieldNameMap = booleanMap(existingFieldNames);
info.fetchStatus = ExistenceFetchStatus.succeeded;
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
info.fetchStatus = ExistenceFetchStatus.failed;
}
}
Expand Down
Loading

0 comments on commit 668fe89

Please sign in to comment.