Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

hasData service #127068

Merged
merged 11 commits into from
Mar 17, 2022
4 changes: 2 additions & 2 deletions packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pageLoadAssetSize:
bfetch: 22837
kibanaUtils: 79713
data: 491273
dataViews: 42532
dataViews: 43532
expressions: 140958
fieldFormats: 65209
kibanaReact: 74422
Expand All @@ -123,4 +123,4 @@ pageLoadAssetSize:
ux: 20784
sessionView: 77750
cloudSecurityPosture: 19109
visTypeGauge: 24113
visTypeGauge: 24113
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import useAsync from 'react-use/lib/useAsync';

import { useKibana } from '../../shared_imports';

import { MatchedItem, ResolveIndexResponseItemAlias, DataViewEditorContext } from '../../types';
import { MatchedItem, DataViewEditorContext } from '../../types';

import { getIndices } from '../../lib';

Expand All @@ -20,8 +20,7 @@ import { EmptyIndexPatternPrompt } from './empty_index_pattern_prompt';
import { PromptFooter } from './prompt_footer';
import { DEFAULT_ASSETS_TO_IGNORE } from '../../../../data/common';

const removeAliases = (item: MatchedItem) =>
!(item as unknown as ResolveIndexResponseItemAlias).indices;
const removeAliases = (mItem: MatchedItem) => !mItem.item.indices;
shivindera marked this conversation as resolved.
Show resolved Hide resolved

interface Props {
onCancel: () => void;
Expand Down
15 changes: 0 additions & 15 deletions src/plugins/data_view_editor/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,21 +127,6 @@ export interface IndexPatternTableItem {
sort: string;
}

// copied from index pattern management, needs review
shivindera marked this conversation as resolved.
Show resolved Hide resolved
export interface MatchedItem {
name: string;
tags: Tag[];
item: {
name: string;
backing_indices?: string[];
timestamp_field?: string;
indices?: string[];
aliases?: string[];
attributes?: ResolveIndexResponseItemIndexAttrs[];
data_stream?: string;
};
}

export enum ResolveIndexResponseItemIndexAttrs {
OPEN = 'open',
CLOSED = 'closed',
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/data_views/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ and field lists across the various Kibana apps. Its typically used in conjunctio

*Note: Kibana index patterns are currently being renamed to data views. There will be some naming inconsistencies until the transition is complete.*

### Services

**hasData:** A standardized way to check the empty state for indices and data views.
- `hasESData: () => Promise<boolean>; // Check to see if ES data exists`
- `hasDataView: () => Promise<boolean>; // Check to see if any data view exists (primitive or user created)`
- `hasUserDataView: () => Promise; // Check to see if user created data views exists`
38 changes: 38 additions & 0 deletions src/plugins/data_views/common/data_views/data_views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,44 @@ export interface DataViewsServiceDeps {
getCanSave: () => Promise<boolean>;
}

export interface DataViewsServicePublicMethods {
clearCache: (id?: string | undefined) => void;
create: (spec: DataViewSpec, skipFetchFields?: boolean) => Promise<DataView>;
createAndSave: (
spec: DataViewSpec,
override?: boolean,
skipFetchFields?: boolean
) => Promise<DataView>;
createSavedObject: (indexPattern: DataView, override?: boolean) => Promise<DataView>;
delete: (indexPatternId: string) => Promise<{}>;
ensureDefaultDataView: EnsureDefaultDataView;
fieldArrayToMap: (fields: FieldSpec[], fieldAttrs?: FieldAttrs | undefined) => DataViewFieldMap;
find: (search: string, size?: number) => Promise<DataView[]>;
get: (id: string) => Promise<DataView>;
getCache: () => Promise<Array<SavedObject<IndexPatternSavedObjectAttrs>> | null | undefined>;
getCanSave: () => Promise<boolean>;
getDefault: () => Promise<DataView | null>;
getDefaultId: () => Promise<string | null>;
getDefaultDataView: () => Promise<DataView | null>;
getFieldsForIndexPattern: (
indexPattern: DataView | DataViewSpec,
options?: GetFieldsOptions | undefined
) => Promise<FieldSpec[]>;
getFieldsForWildcard: (options: GetFieldsOptions) => Promise<FieldSpec[]>;
getIds: (refresh?: boolean) => Promise<string[]>;
getIdsWithTitle: (refresh?: boolean) => Promise<DataViewListItem[]>;
getTitles: (refresh?: boolean) => Promise<string[]>;
hasUserDataView: () => Promise<boolean>;
refreshFields: (indexPattern: DataView) => Promise<void>;
savedObjectToSpec: (savedObject: SavedObject<DataViewAttributes>) => DataViewSpec;
setDefault: (id: string | null, force?: boolean) => Promise<void>;
updateSavedObject: (
indexPattern: DataView,
saveAttempts?: number,
ignoreErrors?: boolean
) => Promise<void | Error>;
}

export class DataViewsService {
private config: UiSettingsCommon;
private savedObjectsClient: SavedObjectsClientCommon;
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/data_views/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,16 @@ export type {
DataViewFieldMap,
DataViewSpec,
SourceFilter,
HasDataService,
} from './types';
export { DataViewType } from './types';
export type { IndexPatternsContract, DataViewsContract } from './data_views';
export { IndexPatternsService, DataViewsService } from './data_views';
export type { DataViewListItem, TimeBasedDataView } from './data_views';
export type {
DataViewListItem,
DataViewsServicePublicMethods,
TimeBasedDataView,
} from './data_views';
export { IndexPattern, DataView } from './data_views';
export {
DuplicateDataViewError,
Expand Down
6 changes: 6 additions & 0 deletions src/plugins/data_views/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,9 @@ export interface DataViewSpec {
export interface SourceFilter {
value: string;
}

export interface HasDataService {
hasESData: () => Promise<boolean>;
hasUserDataView: () => Promise<boolean>;
hasDataView: () => Promise<boolean>;
}
4 changes: 2 additions & 2 deletions src/plugins/data_views/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"version": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["fieldFormats","expressions"],
"requiredPlugins": ["fieldFormats", "expressions"],
"optionalPlugins": ["usageCollection"],
"extraPublicDirs": ["common"],
"requiredBundles": ["kibanaUtils","kibanaReact"],
"requiredBundles": ["kibanaUtils", "kibanaReact"],
"owner": {
"name": "App Services",
"githubTeam": "kibana-app-services"
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/data_views/public/data_views_service_public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@
import { DataViewsService } from '.';

import { DataViewsServiceDeps } from '../common/data_views/data_views';
import { HasDataService } from '../common';

interface DataViewsServicePublicDeps extends DataViewsServiceDeps {
getCanSaveSync: () => boolean;
hasData: HasDataService;
}

export class DataViewsServicePublic extends DataViewsService {
public getCanSaveSync: () => boolean;
public hasData: HasDataService;

constructor(deps: DataViewsServicePublicDeps) {
super(deps);
this.getCanSaveSync = deps.getCanSaveSync;
this.hasData = deps.hasData;
}
}
3 changes: 3 additions & 0 deletions src/plugins/data_views/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export type {
DataViewsPublicPluginSetup,
DataViewsPublicPluginStart,
DataViewsContract,
HasDataViewsResponse,
IndicesResponse,
IndicesResponseModified,
} from './types';

// Export plugin after all other imports
Expand Down
5 changes: 4 additions & 1 deletion src/plugins/data_views/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from '.';

import { DataViewsServicePublic } from './data_views_service_public';
import { HasData } from './services';

export class DataViewsPublicPlugin
implements
Expand All @@ -33,6 +34,8 @@ export class DataViewsPublicPlugin
DataViewsPublicStartDependencies
>
{
private readonly hasData = new HasData();

public setup(
core: CoreSetup<DataViewsPublicStartDependencies, DataViewsPublicPluginStart>,
{ expressions }: DataViewsPublicSetupDependencies
Expand All @@ -47,8 +50,8 @@ export class DataViewsPublicPlugin
{ fieldFormats }: DataViewsPublicStartDependencies
): DataViewsPublicPluginStart {
const { uiSettings, http, notifications, savedObjects, theme, overlays, application } = core;

return new DataViewsServicePublic({
hasData: this.hasData.start(core),
uiSettings: new UiSettingsPublicToCommon(uiSettings),
savedObjectsClient: new SavedObjectsClientPublicToCommon(savedObjects.client),
apiClient: new DataViewsApiClient(http),
Expand Down
147 changes: 147 additions & 0 deletions src/plugins/data_views/public/services/has_data.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* 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 { coreMock } from '../../../../core/public/mocks';

import { HasData } from './has_data';

describe('when calling hasData service', () => {
it('should return true for hasESData when indices exist', async () => {
const coreStart = coreMock.createStart();
const http = coreStart.http;

// Mock getIndices
const spy = jest.spyOn(http, 'get').mockImplementation(() =>
Promise.resolve({
aliases: [],
data_streams: [],
indices: [
{
aliases: [],
attributes: ['open'],
name: 'sample_data_logs',
},
],
})
);

const hasData = new HasData();
const hasDataService = hasData.start(coreStart);
const reponse = hasDataService.hasESData();

expect(spy).toHaveBeenCalledTimes(1);

expect(await reponse).toBe(true);
});

it('should return false for hasESData when no indices exist', async () => {
const coreStart = coreMock.createStart();
const http = coreStart.http;

// Mock getIndices
const spy = jest.spyOn(http, 'get').mockImplementation(() =>
Promise.resolve({
aliases: [],
data_streams: [],
indices: [],
})
);

const hasData = new HasData();
const hasDataService = hasData.start(coreStart);
const reponse = hasDataService.hasESData();

expect(spy).toHaveBeenCalledTimes(1);

expect(await reponse).toBe(false);
});

it('should return true for hasDataView when server returns true', async () => {
const coreStart = coreMock.createStart();
const http = coreStart.http;

// Mock getIndices
const spy = jest.spyOn(http, 'get').mockImplementation(() =>
Promise.resolve({
hasDataView: true,
hasUserDataView: true,
})
);

const hasData = new HasData();
const hasDataService = hasData.start(coreStart);
const reponse = hasDataService.hasDataView();

expect(spy).toHaveBeenCalledTimes(1);

expect(await reponse).toBe(true);
});

it('should return false for hasDataView when server returns false', async () => {
const coreStart = coreMock.createStart();
const http = coreStart.http;

// Mock getIndices
const spy = jest.spyOn(http, 'get').mockImplementation(() =>
Promise.resolve({
hasDataView: false,
hasUserDataView: true,
})
);

const hasData = new HasData();
const hasDataService = hasData.start(coreStart);
const reponse = hasDataService.hasDataView();

expect(spy).toHaveBeenCalledTimes(1);

expect(await reponse).toBe(false);
});

it('should return false for hasUserDataView when server returns false', async () => {
const coreStart = coreMock.createStart();
const http = coreStart.http;

// Mock getIndices
const spy = jest.spyOn(http, 'get').mockImplementation(() =>
Promise.resolve({
hasDataView: true,
hasUserDataView: false,
})
);

const hasData = new HasData();
const hasDataService = hasData.start(coreStart);
const reponse = hasDataService.hasUserDataView();

expect(spy).toHaveBeenCalledTimes(1);

expect(await reponse).toBe(false);
});

it('should return true for hasUserDataView when server returns true', async () => {
const coreStart = coreMock.createStart();
const http = coreStart.http;

// Mock getIndices
const spy = jest.spyOn(http, 'get').mockImplementation(() =>
Promise.resolve({
hasDataView: true,
hasUserDataView: true,
})
);

const hasData = new HasData();
const hasDataService = hasData.start(coreStart);
const reponse = hasDataService.hasUserDataView();

expect(spy).toHaveBeenCalledTimes(1);

expect(await reponse).toBe(true);
});
});
Loading