Skip to content

Commit

Permalink
[Graph] Migrate from savedObjectsClient to dataViews and fix the disp…
Browse files Browse the repository at this point in the history
…layed data view name (elastic#135142)

* [Graph] Migrate from savedObjectsClient to dataViews

* [Graph] Update tests

* [Graph] Fix "no data views" view

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
2 people authored and patrykkopycinski committed Jun 28, 2022
1 parent 5cf06a9 commit 7bdf572
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 99 deletions.
4 changes: 2 additions & 2 deletions x-pack/plugins/graph/public/apps/workspace_route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,14 @@ export const WorkspaceRoute = ({
savedObjectsClient,
spaces,
coreStart,
data,
});

if (!loaded) {
return null;
}

const { savedWorkspace, indexPatterns, sharingSavedObjectProps } = loaded;
const { savedWorkspace, sharingSavedObjectProps } = loaded;

return (
<I18nProvider>
Expand All @@ -145,7 +146,6 @@ export const WorkspaceRoute = ({
coreStart={coreStart}
canEditDrillDownUrls={canEditDrillDownUrls}
overlays={overlays}
indexPatterns={indexPatterns}
savedWorkspace={savedWorkspace}
indexPatternProvider={indexPatternProvider}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React, { ReactNode } from 'react';
import React, { ReactNode, useEffect, useState } from 'react';
import {
EuiPanel,
EuiFlexGroup,
Expand Down Expand Up @@ -38,7 +38,6 @@ export interface GuidancePanelProps {
hasDatasource: boolean;
hasFields: boolean;
onIndexPatternSelected: (indexPattern: IndexPatternSavedObject) => void;
noIndexPatterns: boolean;
}

function ListItem({
Expand Down Expand Up @@ -73,18 +72,21 @@ function ListItem({
}

function GuidancePanelComponent(props: GuidancePanelProps) {
const {
onFillWorkspace,
onOpenFieldPicker,
onIndexPatternSelected,
hasDatasource,
hasFields,
noIndexPatterns,
} = props;
const { onFillWorkspace, onOpenFieldPicker, onIndexPatternSelected, hasDatasource, hasFields } =
props;

const kibana = useKibana<IDataPluginServices>();
const { services, overlays } = kibana;
const { savedObjects, uiSettings, application } = services;
const { savedObjects, uiSettings, application, data } = services;
const [hasDataViews, setHasDataViews] = useState<boolean>(true);

useEffect(() => {
const checkIfDataViewsExist = async () => {
setHasDataViews(await data.dataViews.hasData.hasUserDataView());
};
checkIfDataViewsExist();
}, [setHasDataViews, data.dataViews]);

if (!overlays || !application) return null;

const onOpenDatasourcePicker = () => {
Expand Down Expand Up @@ -146,9 +148,9 @@ function GuidancePanelComponent(props: GuidancePanelProps) {
</EuiPanel>
);

if (noIndexPatterns) {
const indexPatternUrl = application.getUrlForApp('management', {
path: '/kibana/indexPatterns',
if (!hasDataViews) {
const dataViewManagementUrl = application.getUrlForApp('management', {
path: '/kibana/dataViews',
});
const sampleDataUrl = `${application.getUrlForApp('home')}#/tutorial_directory/sampleData`;
content = (
Expand All @@ -174,7 +176,7 @@ function GuidancePanelComponent(props: GuidancePanelProps) {
defaultMessage="No data sources found. Go to {managementIndexPatternsLink} and create a data view for your Elasticsearch indices."
values={{
managementIndexPatternsLink: (
<a href={indexPatternUrl}>
<a href={dataViewManagementUrl}>
<FormattedMessage
id="xpack.graph.noDataSourceNotificationMessageText.managementDataViewLinkText"
defaultMessage="Management &gt; Data views"
Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/graph/public/components/search_bar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ describe('search_bar', () => {
const defaultProps = {
isLoading: false,
indexPatternProvider: {
get: jest.fn(() => Promise.resolve({ fields: [] } as unknown as DataView)),
get: jest.fn(() =>
Promise.resolve({ fields: [], getName: () => 'Test Name' } as unknown as DataView)
),
},
confirmWipeWorkspace: (callback: () => void) => {
callback();
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/graph/public/components/search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps)
}}
>
{currentIndexPattern
? currentIndexPattern.title
? currentIndexPattern.getName()
: // This branch will be shown if the user exits the
// initial picker modal
i18n.translate('xpack.graph.bar.pickSourceLabel', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,7 @@ import {
workspaceInitializedSelector,
} from '../../state_management';
import { FieldManager } from '../field_manager';
import {
ControlType,
IndexPatternProvider,
IndexPatternSavedObject,
TermIntersect,
WorkspaceNode,
} from '../../types';
import { ControlType, IndexPatternProvider, TermIntersect, WorkspaceNode } from '../../types';
import { WorkspaceTopNavMenu } from './workspace_top_nav_menu';
import { InspectPanel } from '../inspect_panel';
import { GuidancePanel } from '../guidance_panel';
Expand Down Expand Up @@ -59,7 +53,6 @@ type WorkspaceLayoutProps = Pick<
renderCounter: number;
workspace?: Workspace;
loading: boolean;
indexPatterns: IndexPatternSavedObject[];
savedWorkspace: GraphWorkspaceSavedObject;
indexPatternProvider: IndexPatternProvider;
sharingSavedObjectProps?: SharingSavedObjectProps;
Expand All @@ -78,7 +71,6 @@ export const WorkspaceLayoutComponent = ({
hasFields,
overlays,
workspaceInitialized,
indexPatterns,
indexPatternProvider,
capabilities,
coreStart,
Expand Down Expand Up @@ -222,10 +214,7 @@ export const WorkspaceLayoutComponent = ({
{getLegacyUrlConflictCallout()}
{!isInitialized && (
<div>
<GuidancePanelMemoized
noIndexPatterns={indexPatterns.length === 0}
onOpenFieldPicker={onOpenFieldPicker}
/>
<GuidancePanelMemoized onOpenFieldPicker={onOpenFieldPicker} />
</div>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
import { useWorkspaceLoader, UseWorkspaceLoaderProps } from './use_workspace_loader';
import { coreMock } from '@kbn/core/public/mocks';
import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks';
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { createMockGraphStore } from '../state_management/mocks';
import { Workspace } from '../types';
import { SavedObjectsClientCommon } from '@kbn/data-views-plugin/public';
import { renderHook, act, RenderHookOptions } from '@testing-library/react-hooks';
import type { SavedObjectsClientContract } from '@kbn/core/public';

jest.mock('react-router-dom', () => {
const useLocation = () => ({
Expand Down Expand Up @@ -40,13 +42,14 @@ const mockSavedObjectsClient = {
} as unknown as SavedObjectsClientCommon;

describe('use_workspace_loader', () => {
const defaultProps = {
const defaultProps: UseWorkspaceLoaderProps = {
workspaceRef: { current: {} as Workspace },
store: createMockGraphStore({}).store,
savedObjectsClient: mockSavedObjectsClient,
savedObjectsClient: mockSavedObjectsClient as unknown as SavedObjectsClientContract,
coreStart: coreMock.createStart(),
spaces: spacesPluginMock.createStartContract(),
} as unknown as UseWorkspaceLoaderProps;
data: dataPluginMock.createStartContract(),
};

it('should not redirect if outcome is exactMatch', async () => {
await act(async () => {
Expand Down
60 changes: 14 additions & 46 deletions x-pack/plugins/graph/public/helpers/use_workspace_loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@
* 2.0.
*/

import { SavedObjectsClientContract } from '@kbn/core/public';
import type { SavedObjectsResolveResponse } from '@kbn/core/public';
import { useEffect, useState } from 'react';
import { useHistory, useLocation, useParams } from 'react-router-dom';
import type { SavedObjectsClientContract } from '@kbn/core/public';
import type { SavedObjectsResolveResponse } from '@kbn/core/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import { i18n } from '@kbn/i18n';
import { CoreStart } from '@kbn/core/public';
import { SpacesApi } from '@kbn/spaces-plugin/public';
import type { DataViewListItem } from '@kbn/data-views-plugin/common';
import { GraphStore } from '../state_management';
import { GraphWorkspaceSavedObject, IndexPatternSavedObject, Workspace } from '../types';
import { GraphWorkspaceSavedObject, Workspace } from '../types';
import { getEmptyWorkspace, getSavedWorkspace } from './saved_workspace_utils';
import { getEditUrl } from '../services/url';

export interface UseWorkspaceLoaderProps {
store: GraphStore;
workspaceRef: React.MutableRefObject<Workspace | undefined>;
savedObjectsClient: SavedObjectsClientContract;
coreStart: CoreStart;
spaces?: SpacesApi;
data: DataPublicPluginStart;
}

interface WorkspaceUrlParams {
Expand All @@ -35,7 +39,6 @@ export interface SharingSavedObjectProps {

interface WorkspaceLoadedState {
savedWorkspace: GraphWorkspaceSavedObject;
indexPatterns: IndexPatternSavedObject[];
sharingSavedObjectProps?: SharingSavedObjectProps;
}

Expand All @@ -45,6 +48,7 @@ export const useWorkspaceLoader = ({
workspaceRef,
store,
savedObjectsClient,
data,
}: UseWorkspaceLoaderProps) => {
const [state, setState] = useState<WorkspaceLoadedState>();
const { replace: historyReplace } = useHistory();
Expand All @@ -60,13 +64,13 @@ export const useWorkspaceLoader = ({

function loadWorkspace(
fetchedSavedWorkspace: GraphWorkspaceSavedObject,
fetchedIndexPatterns: IndexPatternSavedObject[]
dataViews: DataViewListItem[]
) {
store.dispatch({
type: 'x-pack/graph/LOAD_WORKSPACE',
payload: {
savedWorkspace: fetchedSavedWorkspace,
indexPatterns: fetchedIndexPatterns,
dataViews,
urlQuery,
},
});
Expand All @@ -76,43 +80,6 @@ export const useWorkspaceLoader = ({
store.dispatch({ type: 'x-pack/graph/RESET' });
}

async function* pageThroughIndexPatterns() {
let perPage = 1000;
let total = 0;
let savedObjects: IndexPatternSavedObject[] = [];

async function* makeRequest(page: number): AsyncGenerator<IndexPatternSavedObject[]> {
await savedObjectsClient
.find<{ title: string }>({
type: 'index-pattern',
fields: ['title', 'type'],
perPage,
page,
})
.then((response) => {
perPage = response.perPage;
total = response.total;
savedObjects = response.savedObjects;
});

yield savedObjects;

if (total > page * perPage) {
yield* makeRequest(++page);
}
}
yield* makeRequest(1);
}

async function fetchIndexPatterns() {
const result = pageThroughIndexPatterns();
let fetchedIndexPatterns: IndexPatternSavedObject[] = [];
for await (const page of result) {
fetchedIndexPatterns = fetchedIndexPatterns.concat(page);
}
return fetchedIndexPatterns;
}

async function fetchSavedWorkspace(): Promise<{
savedObject: GraphWorkspaceSavedObject;
sharingSavedObjectProps?: SharingSavedObjectProps;
Expand All @@ -132,7 +99,6 @@ export const useWorkspaceLoader = ({
}

async function initializeWorkspace() {
const fetchedIndexPatterns = await fetchIndexPatterns();
const {
savedObject: fetchedSavedWorkspace,
sharingSavedObjectProps: fetchedSharingSavedObjectProps,
Expand All @@ -152,18 +118,19 @@ export const useWorkspaceLoader = ({
return null;
}

const dataViews = await data.dataViews.getIdsWithTitle();

/**
* Deal with situation of request to open saved workspace. Otherwise clean up store,
* when navigating to a new workspace from existing one.
*/
if (fetchedSavedWorkspace.id) {
loadWorkspace(fetchedSavedWorkspace, fetchedIndexPatterns);
loadWorkspace(fetchedSavedWorkspace, dataViews);
} else if (workspaceRef.current) {
clearStore();
}
setState({
savedWorkspace: fetchedSavedWorkspace,
indexPatterns: fetchedIndexPatterns,
sharingSavedObjectProps: fetchedSharingSavedObjectProps,
});
}
Expand All @@ -179,6 +146,7 @@ export const useWorkspaceLoader = ({
coreStart,
workspaceRef,
spaces,
data.dataViews,
]);

return state;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* 2.0.
*/

import { GraphWorkspaceSavedObject, IndexPatternSavedObject, Workspace } from '../../types';
import { GraphWorkspaceSavedObject, Workspace } from '../../types';
import { migrateLegacyIndexPatternRef, savedWorkspaceToAppState, mapFields } from './deserialize';
import { createWorkspace } from '../workspace/graph_client_workspace';
import { outlinkEncoders } from '../../helpers/outlink_encoders';
import type { DataView } from '@kbn/data-views-plugin/public';
import type { DataView, DataViewListItem } from '@kbn/data-views-plugin/public';

describe('deserialize', () => {
let savedWorkspace: GraphWorkspaceSavedObject;
Expand Down Expand Up @@ -214,8 +214,8 @@ describe('deserialize', () => {
it('should migrate legacy index pattern ref', () => {
const workspacePayload = { ...savedWorkspace, legacyIndexPatternRef: 'Testpattern' };
const success = migrateLegacyIndexPatternRef(workspacePayload, [
{ id: '678', attributes: { title: 'Testpattern' } } as IndexPatternSavedObject,
{ id: '123', attributes: { title: 'otherpattern' } } as IndexPatternSavedObject,
{ id: '678', title: 'Testpattern' } as DataViewListItem,
{ id: '123', title: 'otherpattern' } as DataViewListItem,
]);
expect(success).toEqual({ success: true });
expect(workspacePayload.legacyIndexPatternRef).toBeUndefined();
Expand All @@ -225,7 +225,7 @@ describe('deserialize', () => {
it('should return false if migration fails', () => {
const workspacePayload = { ...savedWorkspace, legacyIndexPatternRef: 'Testpattern' };
const success = migrateLegacyIndexPatternRef(workspacePayload, [
{ id: '123', attributes: { title: 'otherpattern' } } as IndexPatternSavedObject,
{ id: '123', title: 'otherpattern' } as DataViewListItem,
]);
expect(success).toEqual({ success: false, missingIndexPattern: 'Testpattern' });
});
Expand Down
Loading

0 comments on commit 7bdf572

Please sign in to comment.