mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[dataViews] dedupe data view loading toasts (#131779)
* debounce data view toasts * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * more debounce * fix debounce * debounce tdata view toast usage * debounce tdata view toast u * lets try adding some code comments Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
605020d79c
commit
0f3af54f6e
5 changed files with 134 additions and 31 deletions
|
@ -113,7 +113,17 @@ export class DataViewsService {
|
|||
private savedObjectsCache?: Array<SavedObject<IndexPatternSavedObjectAttrs>> | null;
|
||||
private apiClient: IDataViewsApiClient;
|
||||
private fieldFormats: FieldFormatsStartCommon;
|
||||
/**
|
||||
* Handler for service notifications
|
||||
* @param toastInputFields notification content in toast format
|
||||
* @param key used to indicate uniqueness of the notification
|
||||
*/
|
||||
private onNotification: OnNotification;
|
||||
/*
|
||||
* Handler for service errors
|
||||
* @param error notification content in toast format
|
||||
* @param key used to indicate uniqueness of the error
|
||||
*/
|
||||
private onError: OnError;
|
||||
private dataViewCache: ReturnType<typeof createDataViewCache>;
|
||||
public getCanSave: () => Promise<boolean>;
|
||||
|
@ -333,15 +343,22 @@ export class DataViewsService {
|
|||
indexPattern.fields.replaceAll(fieldsWithSavedAttrs);
|
||||
} catch (err) {
|
||||
if (err instanceof DataViewMissingIndices) {
|
||||
this.onNotification({ title: err.message, color: 'danger', iconType: 'alert' });
|
||||
this.onNotification(
|
||||
{ title: err.message, color: 'danger', iconType: 'alert' },
|
||||
`refreshFields:${indexPattern.title}`
|
||||
);
|
||||
}
|
||||
|
||||
this.onError(err, {
|
||||
title: i18n.translate('dataViews.fetchFieldErrorTitle', {
|
||||
defaultMessage: 'Error fetching fields for data view {title} (ID: {id})',
|
||||
values: { id: indexPattern.id, title: indexPattern.title },
|
||||
}),
|
||||
});
|
||||
this.onError(
|
||||
err,
|
||||
{
|
||||
title: i18n.translate('dataViews.fetchFieldErrorTitle', {
|
||||
defaultMessage: 'Error fetching fields for data view {title} (ID: {id})',
|
||||
values: { id: indexPattern.id, title: indexPattern.title },
|
||||
}),
|
||||
},
|
||||
indexPattern.title
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -378,16 +395,23 @@ export class DataViewsService {
|
|||
return this.fieldArrayToMap(updatedFieldList, fieldAttrs);
|
||||
} catch (err) {
|
||||
if (err instanceof DataViewMissingIndices) {
|
||||
this.onNotification({ title: err.message, color: 'danger', iconType: 'alert' });
|
||||
this.onNotification(
|
||||
{ title: err.message, color: 'danger', iconType: 'alert' },
|
||||
`refreshFieldSpecMap:${title}`
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
this.onError(err, {
|
||||
title: i18n.translate('dataViews.fetchFieldErrorTitle', {
|
||||
defaultMessage: 'Error fetching fields for data view {title} (ID: {id})',
|
||||
values: { id, title },
|
||||
}),
|
||||
});
|
||||
this.onError(
|
||||
err,
|
||||
{
|
||||
title: i18n.translate('dataViews.fetchFieldErrorTitle', {
|
||||
defaultMessage: 'Error fetching fields for data view {title} (ID: {id})',
|
||||
values: { id, title },
|
||||
}),
|
||||
},
|
||||
title
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
@ -530,18 +554,25 @@ export class DataViewsService {
|
|||
}
|
||||
} catch (err) {
|
||||
if (err instanceof DataViewMissingIndices) {
|
||||
this.onNotification({
|
||||
title: err.message,
|
||||
color: 'danger',
|
||||
iconType: 'alert',
|
||||
});
|
||||
this.onNotification(
|
||||
{
|
||||
title: err.message,
|
||||
color: 'danger',
|
||||
iconType: 'alert',
|
||||
},
|
||||
`initFromSavedObject:${title}`
|
||||
);
|
||||
} else {
|
||||
this.onError(err, {
|
||||
title: i18n.translate('dataViews.fetchFieldErrorTitle', {
|
||||
defaultMessage: 'Error fetching fields for data view {title} (ID: {id})',
|
||||
values: { id: savedObject.id, title },
|
||||
}),
|
||||
});
|
||||
this.onError(
|
||||
err,
|
||||
{
|
||||
title: i18n.translate('dataViews.fetchFieldErrorTitle', {
|
||||
defaultMessage: 'Error fetching fields for data view {title} (ID: {id})',
|
||||
values: { id: savedObject.id, title },
|
||||
}),
|
||||
},
|
||||
title || ''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -718,7 +749,10 @@ export class DataViewsService {
|
|||
'Unable to write data view! Refresh the page to get the most up to date changes for this data view.',
|
||||
});
|
||||
|
||||
this.onNotification({ title, color: 'danger' });
|
||||
this.onNotification(
|
||||
{ title, color: 'danger' },
|
||||
`updateSavedObject:${indexPattern.title}`
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
|
||||
|
|
|
@ -123,8 +123,8 @@ export interface FieldAttrSet {
|
|||
count?: number;
|
||||
}
|
||||
|
||||
export type OnNotification = (toastInputFields: ToastInputFields) => void;
|
||||
export type OnError = (error: Error, toastInputFields: ErrorToastOptions) => void;
|
||||
export type OnNotification = (toastInputFields: ToastInputFields, key: string) => void;
|
||||
export type OnError = (error: Error, toastInputFields: ErrorToastOptions, key: string) => void;
|
||||
|
||||
export interface UiSettingsCommon {
|
||||
get: <T = any>(key: string) => Promise<T>;
|
||||
|
|
31
src/plugins/data_views/public/debounce_by_key.test.ts
Normal file
31
src/plugins/data_views/public/debounce_by_key.test.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 { debounceByKey } from './debounce_by_key';
|
||||
|
||||
describe('debounceByKey', () => {
|
||||
test('debounce, confirm params', async () => {
|
||||
const fn = jest.fn();
|
||||
const fn2 = jest.fn();
|
||||
|
||||
const debouncedFn = debounceByKey(fn, 1000);
|
||||
const debouncedFn2 = debounceByKey(fn2, 1000);
|
||||
|
||||
// debounces based on key, not params
|
||||
debouncedFn('a')(1);
|
||||
debouncedFn('a')(2);
|
||||
|
||||
debouncedFn2('b')(2);
|
||||
debouncedFn2('b')(1);
|
||||
|
||||
expect(fn).toBeCalledTimes(1);
|
||||
expect(fn).toBeCalledWith(1);
|
||||
expect(fn2).toBeCalledTimes(1);
|
||||
expect(fn2).toBeCalledWith(2);
|
||||
});
|
||||
});
|
24
src/plugins/data_views/public/debounce_by_key.ts
Normal file
24
src/plugins/data_views/public/debounce_by_key.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 { debounce } from 'lodash';
|
||||
|
||||
export const debounceByKey = <F extends (...args: any) => any>(
|
||||
fn: F,
|
||||
waitInMs: number
|
||||
): ((key: string) => F) => {
|
||||
const debouncerCollector: Record<string, F> = {};
|
||||
return (key: string) => {
|
||||
if (!debouncerCollector[key]) {
|
||||
debouncerCollector[key] = debounce(fn, waitInMs, {
|
||||
leading: true,
|
||||
});
|
||||
}
|
||||
return debouncerCollector[key];
|
||||
};
|
||||
};
|
|
@ -25,6 +25,8 @@ import {
|
|||
import { DataViewsServicePublic } from './data_views_service_public';
|
||||
import { HasData } from './services';
|
||||
|
||||
import { debounceByKey } from './debounce_by_key';
|
||||
|
||||
export class DataViewsPublicPlugin
|
||||
implements
|
||||
Plugin<
|
||||
|
@ -50,16 +52,28 @@ export class DataViewsPublicPlugin
|
|||
{ fieldFormats }: DataViewsPublicStartDependencies
|
||||
): DataViewsPublicPluginStart {
|
||||
const { uiSettings, http, notifications, savedObjects, theme, overlays, application } = core;
|
||||
|
||||
const onNotifDebounced = debounceByKey(
|
||||
notifications.toasts.add.bind(notifications.toasts),
|
||||
10000
|
||||
);
|
||||
const onErrorDebounced = debounceByKey(
|
||||
notifications.toasts.addError.bind(notifications.toasts),
|
||||
10000
|
||||
);
|
||||
|
||||
return new DataViewsServicePublic({
|
||||
hasData: this.hasData.start(core),
|
||||
uiSettings: new UiSettingsPublicToCommon(uiSettings),
|
||||
savedObjectsClient: new SavedObjectsClientPublicToCommon(savedObjects.client),
|
||||
apiClient: new DataViewsApiClient(http),
|
||||
fieldFormats,
|
||||
onNotification: (toastInputFields) => {
|
||||
notifications.toasts.add(toastInputFields);
|
||||
onNotification: (toastInputFields, key) => {
|
||||
onNotifDebounced(key)(toastInputFields);
|
||||
},
|
||||
onError: (error, toastInputFields, key) => {
|
||||
onErrorDebounced(key)(error, toastInputFields);
|
||||
},
|
||||
onError: notifications.toasts.addError.bind(notifications.toasts),
|
||||
onRedirectNoIndexPattern: onRedirectNoIndexPattern(
|
||||
application.capabilities,
|
||||
application.navigateToApp,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue