diff --git a/src/plugins/data_view_management/kibana.json b/src/plugins/data_view_management/kibana.json index 43d22f545bf97..8c8ace32169ca 100644 --- a/src/plugins/data_view_management/kibana.json +++ b/src/plugins/data_view_management/kibana.json @@ -3,7 +3,7 @@ "version": "kibana", "server": true, "ui": true, - "requiredPlugins": ["management", "data", "urlForwarding", "dataViewFieldEditor", "dataViewEditor", "dataViews", "fieldFormats", "unifiedSearch"], + "requiredPlugins": ["management", "data", "urlForwarding", "dataViewFieldEditor", "dataViewEditor", "dataViews", "fieldFormats", "unifiedSearch", "savedObjectsManagement"], "requiredBundles": ["kibanaReact", "kibanaUtils"], "optionalPlugins": ["spaces"], "owner": { diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/constants.ts b/src/plugins/data_view_management/public/components/edit_index_pattern/constants.ts index 26fcdb27524aa..94fd6082fd28c 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/constants.ts +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/constants.ts @@ -9,3 +9,4 @@ export const TAB_INDEXED_FIELDS = 'indexedFields'; export const TAB_SCRIPTED_FIELDS = 'scriptedFields'; export const TAB_SOURCE_FILTERS = 'sourceFilters'; +export const TAB_RELATIONSHIPS = 'relationships'; diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx index ca6f34ffcb8de..1077a1a768d4f 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx @@ -21,7 +21,12 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { DataView, DataViewField } from '@kbn/data-views-plugin/public'; +import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { + SavedObjectRelation, + SavedObjectManagementTypeInfo, +} from '@kbn/saved-objects-management-plugin/public'; import { IndexPatternManagmentContext } from '../../types'; import { Tabs } from './tabs'; import { IndexHeader } from './index_header'; @@ -32,6 +37,10 @@ export interface EditIndexPatternProps extends RouteComponentProps { indexPattern: DataView; } +export interface SavedObjectRelationWithTitle extends SavedObjectRelation { + title: string; +} + const mappingAPILink = i18n.translate( 'indexPatternManagement.editIndexPattern.timeFilterLabel.mappingAPILink', { @@ -57,7 +66,7 @@ const securitySolution = 'security-solution'; export const EditIndexPattern = withRouter( ({ indexPattern, history, location }: EditIndexPatternProps) => { - const { uiSettings, overlays, chrome, dataViews } = + const { uiSettings, overlays, chrome, dataViews, savedObjectsManagement } = useKibana().services; const [fields, setFields] = useState(indexPattern.getNonScriptedFields()); const [conflictedFields, setConflictedFields] = useState( @@ -65,6 +74,26 @@ export const EditIndexPattern = withRouter( ); const [defaultIndex, setDefaultIndex] = useState(uiSettings.get('defaultIndex')); const [tags, setTags] = useState([]); + const [relationships, setRelationships] = useState([]); + const [allowedTypes, setAllowedTypes] = useState([]); + + useEffect(() => { + savedObjectsManagement.getAllowedTypes().then((resp) => { + setAllowedTypes(resp); + }); + }, [savedObjectsManagement]); + + useEffect(() => { + if (allowedTypes.length === 0) { + return; + } + const allowedAsString = allowedTypes.map((item) => item.name); + savedObjectsManagement + .getRelationships(DATA_VIEW_SAVED_OBJECT_TYPE, indexPattern.id!, allowedAsString) + .then((resp) => { + setRelationships(resp.relations.map((r) => ({ ...r, title: r.meta.title! }))); + }); + }, [savedObjectsManagement, indexPattern, allowedTypes]); useEffect(() => { setFields(indexPattern.getNonScriptedFields()); @@ -200,6 +229,8 @@ export const EditIndexPattern = withRouter( indexPattern={indexPattern} saveIndexPattern={dataViews.updateSavedObject.bind(dataViews)} fields={fields} + relationships={relationships} + allowedTypes={allowedTypes} history={history} location={location} refreshFields={() => { diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/relationships_table/i18n.ts b/src/plugins/data_view_management/public/components/edit_index_pattern/relationships_table/i18n.ts new file mode 100644 index 0000000000000..c3b4dedee713e --- /dev/null +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/relationships_table/i18n.ts @@ -0,0 +1,38 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const typeFieldName = i18n.translate( + 'indexPatternManagement.objectsTable.relationships.columnTypeName', + { + defaultMessage: 'Type', + } +); + +export const typeFieldDescription = i18n.translate( + 'indexPatternManagement.objectsTable.relationships.columnTypeDescription', + { defaultMessage: 'Type of the saved object' } +); + +export const titleFieldName = i18n.translate( + 'indexPatternManagement.objectsTable.relationships.columnTitleName', + { + defaultMessage: 'Title', + } +); + +export const titleFieldDescription = i18n.translate( + 'indexPatternManagement.objectsTable.relationships.columnTitleDescription', + { defaultMessage: 'Title of the saved object' } +); + +export const filterTitle = i18n.translate( + 'indexPatternManagement.objectsTable.relationships.search.filters.type.name', + { defaultMessage: 'Type' } +); diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/relationships_table/index.ts b/src/plugins/data_view_management/public/components/edit_index_pattern/relationships_table/index.ts new file mode 100644 index 0000000000000..da93da3a9f535 --- /dev/null +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/relationships_table/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export { RelationshipsTable } from './relationships_table'; diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/relationships_table/relationships_table.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/relationships_table/relationships_table.tsx new file mode 100644 index 0000000000000..ade3224b6db17 --- /dev/null +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/relationships_table/relationships_table.tsx @@ -0,0 +1,154 @@ +/* + * 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 React from 'react'; +import { + EuiInMemoryTable, + HorizontalAlignment, + EuiText, + EuiLink, + EuiTableDataType, +} from '@elastic/eui'; +import { CoreStart } from '@kbn/core/public'; +import { get } from 'lodash'; +import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; + +import { + SavedObjectRelation, + SavedObjectManagementTypeInfo, + SavedObjectsManagementPluginStart, +} from '@kbn/saved-objects-management-plugin/public'; + +import { EuiToolTip, EuiIcon, SearchFilterConfig } from '@elastic/eui'; +import { IPM_APP_ID } from '../../../plugin'; +import { + typeFieldName, + typeFieldDescription, + titleFieldName, + titleFieldDescription, + filterTitle, +} from './i18n'; + +const canGoInApp = ( + savedObject: SavedObjectRelation, + capabilities: CoreStart['application']['capabilities'] +) => { + const { inAppUrl } = savedObject.meta; + if (!inAppUrl) return false; + if (!inAppUrl.uiCapabilitiesPath) return true; + return Boolean(get(capabilities, inAppUrl.uiCapabilitiesPath)); +}; + +export const RelationshipsTable = ({ + basePath, + capabilities, + id, + navigateToUrl, + getDefaultTitle, + getSavedObjectLabel, + relationships, + allowedTypes, +}: { + basePath: CoreStart['http']['basePath']; + capabilities: CoreStart['application']['capabilities']; + navigateToUrl: CoreStart['application']['navigateToUrl']; + id: string; + getDefaultTitle: SavedObjectsManagementPluginStart['getDefaultTitle']; + getSavedObjectLabel: SavedObjectsManagementPluginStart['getSavedObjectLabel']; + relationships: SavedObjectRelation[]; + allowedTypes: SavedObjectManagementTypeInfo[]; +}) => { + const columns = [ + { + field: 'type', + name: typeFieldName, + width: '50px', + align: 'center' as HorizontalAlignment, + description: typeFieldDescription, + sortable: false, + render: (type: string, object: SavedObjectRelation) => { + const typeLabel = getSavedObjectLabel(type, allowedTypes); + return ( + + + + ); + }, + }, + { + field: 'title', + name: titleFieldName, + description: titleFieldDescription, + dataType: 'string' as EuiTableDataType, + sortable: false, + render: (title: string, object: SavedObjectRelation) => { + const path = object.meta.inAppUrl?.path || ''; + const showUrl = canGoInApp(object, capabilities); + const titleDisplayed = title || getDefaultTitle(object); + + return showUrl ? ( + + {titleDisplayed} + + ) : ( + + {titleDisplayed} + + ); + }, + }, + ]; + + const filterTypesMap = new Map( + relationships.map((relationship) => [ + relationship.type, + { + value: relationship.type, + name: relationship.type, + view: relationship.type, + }, + ]) + ); + + const search = { + // query, + // onChange: handleOnChange, + box: { + incremental: true, + schema: true, + }, + filters: [ + { + type: 'field_value_selection', + field: 'type', + name: filterTitle, + multiSelect: 'or', + options: [...filterTypesMap.values()], + }, + ] as SearchFilterConfig[], + }; + + return ( + + + items={relationships} + columns={columns} + pagination={true} + search={search} + rowProps={() => ({ + 'data-test-subj': `relationshipsTableRow`, + })} + /> + + ); +}; diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx index 35323d90a7efb..de4e455cd48af 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/tabs.tsx @@ -30,13 +30,23 @@ import { DataViewsPublicPluginStart, META_FIELDS, } from '@kbn/data-views-plugin/public'; +import { + SavedObjectRelation, + SavedObjectManagementTypeInfo, +} from '@kbn/saved-objects-management-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { IndexPatternManagmentContext } from '../../../types'; import { createEditIndexPatternPageStateContainer } from '../edit_index_pattern_state_container'; -import { TAB_INDEXED_FIELDS, TAB_SCRIPTED_FIELDS, TAB_SOURCE_FILTERS } from '../constants'; +import { + TAB_INDEXED_FIELDS, + TAB_SCRIPTED_FIELDS, + TAB_SOURCE_FILTERS, + TAB_RELATIONSHIPS, +} from '../constants'; import { SourceFiltersTable } from '../source_filters_table'; import { IndexedFieldsTable } from '../indexed_fields_table'; import { ScriptedFieldsTable } from '../scripted_fields_table'; +import { RelationshipsTable } from '../relationships_table'; import { getTabs, getPath, convertToEuiFilterOptions } from './utils'; import { getFieldInfo } from '../../utils'; @@ -45,6 +55,8 @@ interface TabsProps extends Pick { fields: DataViewField[]; saveIndexPattern: DataViewsPublicPluginStart['updateSavedObject']; refreshFields: () => void; + relationships: SavedObjectRelation[]; + allowedTypes: SavedObjectManagementTypeInfo[]; } interface FilterItems { @@ -131,9 +143,20 @@ export function Tabs({ history, location, refreshFields, + relationships, + allowedTypes, }: TabsProps) { - const { uiSettings, docLinks, dataViewFieldEditor, overlays, theme, dataViews } = - useKibana().services; + const { + uiSettings, + docLinks, + dataViewFieldEditor, + overlays, + theme, + dataViews, + http, + application, + savedObjectsManagement, + } = useKibana().services; const [fieldFilter, setFieldFilter] = useState(''); const [syncingStateFunc, setSyncingStateFunc] = useState({ getCurrentTab: () => TAB_INDEXED_FIELDS, @@ -492,6 +515,22 @@ export function Tabs({ /> ); + case TAB_RELATIONSHIPS: + return ( + + + + + ); } }, [ @@ -513,18 +552,25 @@ export function Tabs({ overlays, theme, dataViews, + http, + application, + savedObjectsManagement, + allowedTypes, + relationships, ] ); const euiTabs: EuiTabbedContentTab[] = useMemo( () => - getTabs(indexPattern, fieldFilter).map((tab: Pick) => { - return { - ...tab, - content: getContent(tab.id), - }; - }), - [fieldFilter, getContent, indexPattern] + getTabs(indexPattern, fieldFilter, relationships.length).map( + (tab: Pick) => { + return { + ...tab, + content: getContent(tab.id), + }; + } + ), + [fieldFilter, getContent, indexPattern, relationships] ); const [selectedTabId, setSelectedTabId] = useState(euiTabs[0].id); diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/utils.ts b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/utils.ts index 6b29057926a64..00b08037e52fe 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/utils.ts +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/tabs/utils.ts @@ -9,7 +9,12 @@ import { Dictionary, countBy, defaults, uniq } from 'lodash'; import { i18n } from '@kbn/i18n'; import { DataView, DataViewField } from '@kbn/data-views-plugin/public'; -import { TAB_INDEXED_FIELDS, TAB_SCRIPTED_FIELDS, TAB_SOURCE_FILTERS } from '../constants'; +import { + TAB_INDEXED_FIELDS, + TAB_SCRIPTED_FIELDS, + TAB_SOURCE_FILTERS, + TAB_RELATIONSHIPS, +} from '../constants'; import { areScriptedFieldsEnabled } from '../../utils'; function filterByName(items: DataViewField[], filter: string) { @@ -68,7 +73,7 @@ function getTitle(type: string, filteredCount: Dictionary, totalCount: D return title + count; } -export function getTabs(indexPattern: DataView, fieldFilter: string) { +export function getTabs(indexPattern: DataView, fieldFilter: string, relationshipCount = 0) { const totalCount = getCounts(indexPattern.fields.getAll(), indexPattern.getSourceFiltering()); const filteredCount = getCounts( indexPattern.fields.getAll(), @@ -98,6 +103,15 @@ export function getTabs(indexPattern: DataView, fieldFilter: string) { 'data-test-subj': 'tab-sourceFilters', }); + tabs.push({ + name: i18n.translate('indexPatternManagement.editIndexPattern.tabs.relationshipsHeader', { + defaultMessage: 'Relationships ({count})', + values: { count: relationshipCount }, + }), + id: TAB_RELATIONSHIPS, + 'data-test-subj': 'tab-relationships', + }); + return tabs; } diff --git a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx index ecff28546e409..f8d26c9508d95 100644 --- a/src/plugins/data_view_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/data_view_management/public/management_app/mount_management_section.tsx @@ -40,7 +40,16 @@ export async function mountManagementSection( ) { const [ { application, chrome, uiSettings, notifications, overlays, http, docLinks, theme }, - { data, dataViewFieldEditor, dataViewEditor, dataViews, fieldFormats, unifiedSearch, spaces }, + { + data, + dataViewFieldEditor, + dataViewEditor, + dataViews, + fieldFormats, + unifiedSearch, + spaces, + savedObjectsManagement, + }, indexPatternManagementStart, ] = await getStartServices(); const canSave = dataViews.getCanSaveSync(); @@ -68,6 +77,7 @@ export async function mountManagementSection( fieldFormats, spaces, theme, + savedObjectsManagement, }; ReactDOM.render( diff --git a/src/plugins/data_view_management/public/mocks.ts b/src/plugins/data_view_management/public/mocks.ts index d1e5eac4b2be0..8f43b736c89ec 100644 --- a/src/plugins/data_view_management/public/mocks.ts +++ b/src/plugins/data_view_management/public/mocks.ts @@ -16,6 +16,7 @@ import { indexPatternFieldEditorPluginMock } from '@kbn/data-view-field-editor-p import { indexPatternEditorPluginMock } from '@kbn/data-view-editor-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; +import { savedObjectsManagementPluginMock } from '@kbn/saved-objects-management-plugin/public/mocks'; import { IndexPatternManagementSetup, IndexPatternManagementStart, @@ -63,6 +64,7 @@ const createIndexPatternManagmentContext = (): { const dataViewFieldEditor = indexPatternFieldEditorPluginMock.createStartContract(); const dataViews = dataViewPluginMocks.createStartContract(); const unifiedSearch = unifiedSearchPluginMock.createStartContract(); + const savedObjectsManagement = savedObjectsManagementPluginMock.createStartContract(); return { application, @@ -83,6 +85,7 @@ const createIndexPatternManagmentContext = (): { indexPatternEditorPluginMock.createStartContract().IndexPatternEditorComponent, fieldFormats: fieldFormatsServiceMock.createStartContract(), theme, + savedObjectsManagement, }; }; diff --git a/src/plugins/data_view_management/public/plugin.ts b/src/plugins/data_view_management/public/plugin.ts index 02ea4aac4421e..3aefcbc047f16 100644 --- a/src/plugins/data_view_management/public/plugin.ts +++ b/src/plugins/data_view_management/public/plugin.ts @@ -18,6 +18,7 @@ import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; +import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; export interface IndexPatternManagementSetupDependencies { management: ManagementSetup; @@ -32,6 +33,7 @@ export interface IndexPatternManagementStartDependencies { fieldFormats: FieldFormatsStart; spaces?: SpacesPluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; + savedObjectsManagement: SavedObjectsManagementPluginStart; } // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -44,7 +46,7 @@ const sectionsHeader = i18n.translate('indexPatternManagement.dataView.sectionsH defaultMessage: 'Data Views', }); -const IPM_APP_ID = 'dataViews'; +export const IPM_APP_ID = 'dataViews'; export class IndexPatternManagementPlugin implements diff --git a/src/plugins/data_view_management/public/types.ts b/src/plugins/data_view_management/public/types.ts index 0901ba72d050b..bb29945b386bc 100644 --- a/src/plugins/data_view_management/public/types.ts +++ b/src/plugins/data_view_management/public/types.ts @@ -25,6 +25,7 @@ import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; +import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import { IndexPatternManagementStart } from '.'; export interface IndexPatternManagmentContext { @@ -46,6 +47,7 @@ export interface IndexPatternManagmentContext { fieldFormats: FieldFormatsStart; spaces?: SpacesPluginStart; theme: ThemeServiceStart; + savedObjectsManagement: SavedObjectsManagementPluginStart; } export type IndexPatternManagmentContextValue = diff --git a/src/plugins/data_view_management/tsconfig.json b/src/plugins/data_view_management/tsconfig.json index 9b8a7e688e0c0..374cea271ed90 100644 --- a/src/plugins/data_view_management/tsconfig.json +++ b/src/plugins/data_view_management/tsconfig.json @@ -21,6 +21,7 @@ { "path": "../data_view_field_editor/tsconfig.json" }, { "path": "../data_view_editor/tsconfig.json" }, { "path": "../unified_search/tsconfig.json" }, + { "path": "../saved_objects_management/tsconfig.json" }, { "path": "../../../x-pack/plugins/spaces/tsconfig.json" } ] } diff --git a/src/plugins/saved_objects_management/public/index.ts b/src/plugins/saved_objects_management/public/index.ts index d9aad59688fb5..223a6333a0db7 100644 --- a/src/plugins/saved_objects_management/public/index.ts +++ b/src/plugins/saved_objects_management/public/index.ts @@ -24,7 +24,12 @@ export type { export { SavedObjectsManagementAction } from './services'; export type { ProcessedImportResponse, FailedImport } from './lib'; export { processImportResponse } from './lib'; -export type { SavedObjectRelation, SavedObjectWithMetadata, SavedObjectMetadata } from './types'; +export type { + SavedObjectRelation, + SavedObjectWithMetadata, + SavedObjectMetadata, + SavedObjectManagementTypeInfo, +} from './types'; export function plugin(initializerContext: PluginInitializerContext) { return new SavedObjectsManagementPlugin(); diff --git a/src/plugins/saved_objects_management/public/mocks.ts b/src/plugins/saved_objects_management/public/mocks.ts index b8ad4cd1ea885..8e12d0bde3a0e 100644 --- a/src/plugins/saved_objects_management/public/mocks.ts +++ b/src/plugins/saved_objects_management/public/mocks.ts @@ -22,6 +22,10 @@ const createStartContractMock = (): jest.Mocked Promise; + getRelationships: ( + type: string, + id: string, + savedObjectTypes: string[] + ) => Promise; + getSavedObjectLabel: typeof getSavedObjectLabel; + getDefaultTitle: typeof getDefaultTitle; } export interface SetupDependencies { @@ -109,6 +120,11 @@ export class SavedObjectsManagementPlugin return { actions: actionStart, columns: columnStart, + getAllowedTypes: () => getAllowedTypes(_core.http), + getRelationships: (type: string, id: string, savedObjectTypes: string[]) => + getRelationships(_core.http, type, id, savedObjectTypes), + getSavedObjectLabel, + getDefaultTitle, }; } } diff --git a/src/plugins/saved_objects_management/public/types.ts b/src/plugins/saved_objects_management/public/types.ts index 61766e1cb8c10..91e6e58e3dd0c 100644 --- a/src/plugins/saved_objects_management/public/types.ts +++ b/src/plugins/saved_objects_management/public/types.ts @@ -13,4 +13,5 @@ export type { SavedObjectRelation, SavedObjectInvalidRelation, SavedObjectGetRelationshipsResponse, + SavedObjectManagementTypeInfo, } from '../common'; diff --git a/test/functional/apps/management/_data_view_relationships.ts b/test/functional/apps/management/_data_view_relationships.ts new file mode 100644 index 0000000000000..c8e78eab4ce64 --- /dev/null +++ b/test/functional/apps/management/_data_view_relationships.ts @@ -0,0 +1,35 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const browser = getService('browser'); + const PageObjects = getPageObjects(['common', 'home', 'settings', 'discover', 'header']); + + describe('data view relationships', function describeIndexTests() { + before(async function () { + await browser.setWindowSize(1200, 800); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + }); + + after(async () => { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + }); + + it('Render relationships tab and verify count', async function () { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaIndexPatterns(); + await PageObjects.settings.clickIndexPatternLogstash(); + await PageObjects.settings.clickRelationshipsTab(); + expect(parseInt(await PageObjects.settings.getRelationshipsTabCount(), 10)).to.be(1); + }); + }); +} diff --git a/test/functional/apps/management/index.ts b/test/functional/apps/management/index.ts index 840d04d0d1aed..09f9001d0236a 100644 --- a/test/functional/apps/management/index.ts +++ b/test/functional/apps/management/index.ts @@ -40,5 +40,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_test_huge_fields')); loadTestFile(require.resolve('./_handle_alias')); loadTestFile(require.resolve('./_handle_version_conflict')); + loadTestFile(require.resolve('./_data_view_relationships')); }); } diff --git a/test/functional/page_objects/settings_page.ts b/test/functional/page_objects/settings_page.ts index 29fbe04f59e97..2d803016afd15 100644 --- a/test/functional/page_objects/settings_page.ts +++ b/test/functional/page_objects/settings_page.ts @@ -244,6 +244,13 @@ export class SettingsPageObject extends FtrService { }); } + async getRelationshipsTabCount() { + return await this.retry.try(async () => { + const text = await this.testSubjects.getVisibleText('tab-relationships'); + return text.split(' ')[1].replace(/\((.*)\)/, '$1'); + }); + } + async getFieldNames() { const fieldNameCells = await this.testSubjects.findAll('editIndexPattern > indexedFieldName'); return await Promise.all( @@ -562,6 +569,11 @@ export class SettingsPageObject extends FtrService { await this.testSubjects.click('tab-sourceFilters'); } + async clickRelationshipsTab() { + this.log.debug('click Relationships tab'); + await this.testSubjects.click('tab-relationships'); + } + async editScriptedField(name: string) { await this.filterField(name); await this.find.clickByCssSelector('.euiTableRowCell--hasActions button:first-child');