diff --git a/x-pack/plugins/index_lifecycle_management/kibana.json b/x-pack/plugins/index_lifecycle_management/kibana.json index 1b0a73c6a0133..21e7e7888acb9 100644 --- a/x-pack/plugins/index_lifecycle_management/kibana.json +++ b/x-pack/plugins/index_lifecycle_management/kibana.json @@ -6,7 +6,8 @@ "requiredPlugins": [ "licensing", "management", - "features" + "features", + "share" ], "optionalPlugins": [ "cloud", diff --git a/x-pack/plugins/index_lifecycle_management/public/application/app.tsx b/x-pack/plugins/index_lifecycle_management/public/application/app.tsx index f7f8b30324bca..856981fe5c4f9 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/app.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/app.tsx @@ -13,6 +13,7 @@ import { UIM_APP_LOAD } from './constants/ui_metric'; import { EditPolicy } from './sections/edit_policy'; import { PolicyTable } from './sections/policy_table'; import { trackUiMetric } from './services/ui_metric'; +import { ROUTES } from './services/navigation'; export const App = ({ history, @@ -28,14 +29,14 @@ export const App = ({ return ( - + } /> } /> diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/table_content.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/table_content.tsx index 7b6521fd8a9ef..09c81efe163b5 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/table_content.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/components/table_content.tsx @@ -35,7 +35,7 @@ import { RouteComponentProps } from 'react-router-dom'; import { reactRouterNavigate } from '../../../../../../../../src/plugins/kibana_react/public'; import { getIndexListUri } from '../../../../../../index_management/public'; import { PolicyFromES } from '../../../../../common/types'; -import { getPolicyPath } from '../../../services/navigation'; +import { getPolicyEditPath } from '../../../services/navigation'; import { sortTable } from '../../../services'; import { trackUiMetric } from '../../../services/ui_metric'; @@ -229,7 +229,7 @@ export const TableContent: React.FunctionComponent = ({ return ( + {...reactRouterNavigate(history, getPolicyEditPath(value as string), () => trackUiMetric(METRIC_TYPE.CLICK, UIM_EDIT_CLICK) )} > diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/policy_table.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/policy_table.tsx index 0c396dae75783..55987bd9a62a9 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/policy_table.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_table/policy_table.tsx @@ -26,6 +26,7 @@ import { reactRouterNavigate } from '../../../../../../../src/plugins/kibana_rea import { PolicyFromES } from '../../../../common/types'; import { filterItems } from '../../services'; import { TableContent } from './components/table_content'; +import { getPolicyCreatePath } from '../../services/navigation'; interface Props { policies: PolicyFromES[]; @@ -45,7 +46,7 @@ export const PolicyTable: React.FunctionComponent = ({ const createPolicyButton = ( { +export const ROUTES = { + list: '/policies', + edit: '/policies/edit/:policyName?', + create: '/policies/edit', +}; + +export const getPolicyEditPath = (policyName: string): string => { return encodeURI(`/policies/edit/${encodeURIComponent(policyName)}`); }; + +export const getPolicyCreatePath = () => { + return ROUTES.create; +}; + +export const getPoliciesListPath = () => { + return ROUTES.list; +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/index_lifecycle_summary.tsx b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/index_lifecycle_summary.tsx index afdf726ea02f9..80c8e1414e1f8 100644 --- a/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/index_lifecycle_summary.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/extend_index_management/components/index_lifecycle_summary.tsx @@ -25,7 +25,7 @@ import { } from '@elastic/eui'; import { ApplicationStart } from 'kibana/public'; -import { getPolicyPath } from '../../application/services/navigation'; +import { getPolicyEditPath } from '../../application/services/navigation'; import { Index, IndexLifecyclePolicy } from '../../../common/types'; const getHeaders = (): Array<[keyof IndexLifecyclePolicy, string]> => { @@ -192,7 +192,7 @@ export class IndexLifecycleSummary extends Component { content = ( {value} diff --git a/x-pack/plugins/index_lifecycle_management/public/index.ts b/x-pack/plugins/index_lifecycle_management/public/index.ts index 586763188a54b..2aee76cd8b136 100644 --- a/x-pack/plugins/index_lifecycle_management/public/index.ts +++ b/x-pack/plugins/index_lifecycle_management/public/index.ts @@ -12,3 +12,5 @@ import { IndexLifecycleManagementPlugin } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => { return new IndexLifecycleManagementPlugin(initializerContext); }; + +export { ILM_URL_GENERATOR_ID, IlmUrlGeneratorState } from './url_generator'; diff --git a/x-pack/plugins/index_lifecycle_management/public/plugin.tsx b/x-pack/plugins/index_lifecycle_management/public/plugin.tsx index 6300c6bfc7eb1..deef5cfe6ef2c 100644 --- a/x-pack/plugins/index_lifecycle_management/public/plugin.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/plugin.tsx @@ -14,14 +14,15 @@ import { init as initUiMetric } from './application/services/ui_metric'; import { init as initNotification } from './application/services/notification'; import { BreadcrumbService } from './application/services/breadcrumbs'; import { addAllExtensions } from './extend_index_management'; -import { PluginsDependencies, ClientConfigType } from './types'; +import { ClientConfigType, SetupDependencies } from './types'; +import { registerUrlGenerator } from './url_generator'; export class IndexLifecycleManagementPlugin { constructor(private readonly initializerContext: PluginInitializerContext) {} private breadcrumbService = new BreadcrumbService(); - public setup(coreSetup: CoreSetup, plugins: PluginsDependencies) { + public setup(coreSetup: CoreSetup, plugins: SetupDependencies) { const { ui: { enabled: isIndexLifecycleManagementUiEnabled }, } = this.initializerContext.config.get(); @@ -34,7 +35,7 @@ export class IndexLifecycleManagementPlugin { getStartServices, } = coreSetup; - const { usageCollection, management, indexManagement, home, cloud } = plugins; + const { usageCollection, management, indexManagement, home, cloud, share } = plugins; // Initialize services even if the app isn't mounted, because they're used by index management extensions. initHttp(http); @@ -102,6 +103,8 @@ export class IndexLifecycleManagementPlugin { if (indexManagement) { addAllExtensions(indexManagement.extensionsService); } + + registerUrlGenerator(coreSetup, management, share); } } diff --git a/x-pack/plugins/index_lifecycle_management/public/types.ts b/x-pack/plugins/index_lifecycle_management/public/types.ts index 6b11830b424af..1ce43957b1444 100644 --- a/x-pack/plugins/index_lifecycle_management/public/types.ts +++ b/x-pack/plugins/index_lifecycle_management/public/types.ts @@ -9,15 +9,17 @@ import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/p import { ManagementSetup } from '../../../../src/plugins/management/public'; import { IndexManagementPluginSetup } from '../../index_management/public'; import { CloudSetup } from '../../cloud/public'; +import { SharePluginSetup } from '../../../../src/plugins/share/public'; import { BreadcrumbService } from './application/services/breadcrumbs'; -export interface PluginsDependencies { +export interface SetupDependencies { usageCollection?: UsageCollectionSetup; management: ManagementSetup; cloud?: CloudSetup; indexManagement?: IndexManagementPluginSetup; home?: HomePublicPluginSetup; + share: SharePluginSetup; } export interface ClientConfigType { diff --git a/x-pack/plugins/index_lifecycle_management/public/url_generator.ts b/x-pack/plugins/index_lifecycle_management/public/url_generator.ts new file mode 100644 index 0000000000000..a884c9a54a4b8 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/url_generator.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { CoreSetup } from 'kibana/public'; +import { UrlGeneratorsDefinition } from '../../../../src/plugins/share/public/'; +import { + getPoliciesListPath, + getPolicyCreatePath, + getPolicyEditPath, +} from './application/services/navigation'; +import { MANAGEMENT_APP_ID } from '../../../../src/plugins/management/public'; +import { SetupDependencies } from './types'; +import { PLUGIN } from '../common/constants'; + +export const ILM_URL_GENERATOR_ID = 'ILM_URL_GENERATOR_ID'; + +export interface IlmUrlGeneratorState { + page: 'policies_list' | 'policy_edit' | 'policy_create'; + policyName?: string; + absolute?: boolean; +} +export const createIlmUrlGenerator = ( + getAppBasePath: (absolute?: boolean) => Promise +): UrlGeneratorsDefinition => { + return { + id: ILM_URL_GENERATOR_ID, + createUrl: async (state: IlmUrlGeneratorState): Promise => { + switch (state.page) { + case 'policy_create': { + return `${await getAppBasePath(!!state.absolute)}${getPolicyCreatePath()}`; + } + case 'policy_edit': { + return `${await getAppBasePath(!!state.absolute)}${getPolicyEditPath(state.policyName!)}`; + } + case 'policies_list': { + return `${await getAppBasePath(!!state.absolute)}${getPoliciesListPath()}`; + } + } + }, + }; +}; + +export const registerUrlGenerator = ( + coreSetup: CoreSetup, + management: SetupDependencies['management'], + share: SetupDependencies['share'] +) => { + const getAppBasePath = async (absolute = false) => { + const [coreStart] = await coreSetup.getStartServices(); + return coreStart.application.getUrlForApp(MANAGEMENT_APP_ID, { + path: management.sections.section.data.getApp(PLUGIN.ID)!.basePath, + absolute, + }); + }; + + share.urlGenerators.registerUrlGenerator(createIlmUrlGenerator(getAppBasePath)); +}; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts index 8a610a04f8bb1..b5386dec34205 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts @@ -13,13 +13,13 @@ export type TestSubjects = | 'createTemplateButton' | 'dataStreamsEmptyPromptTemplateLink' | 'dataStreamTable' - | 'dataStreamTable' | 'deleteSystemTemplateCallOut' | 'deleteTemplateButton' | 'deleteTemplatesConfirmation' | 'documentationLink' | 'emptyPrompt' | 'filterList.filterItem' + | 'ilmPolicyLink' | 'includeStatsSwitch' | 'indexTable' | 'indexTableIncludeHiddenIndicesToggle' diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts index 82bd858240e1e..6bf6c11a37bb4 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.helpers.ts @@ -7,6 +7,7 @@ import { act } from 'react-dom/test-utils'; import { ReactWrapper } from 'enzyme'; +import { EuiDescriptionListDescription } from '@elastic/eui'; import { registerTestBed, TestBed, @@ -26,15 +27,17 @@ export interface DataStreamsTabTestBed extends TestBed { clickReloadButton: () => void; clickNameAt: (index: number) => void; clickIndicesAt: (index: number) => void; - clickDeletActionAt: (index: number) => void; + clickDeleteActionAt: (index: number) => void; clickConfirmDelete: () => void; - clickDeletDataStreamButton: () => void; + clickDeleteDataStreamButton: () => void; }; findDeleteActionAt: (index: number) => ReactWrapper; findDeleteConfirmationModal: () => ReactWrapper; findDetailPanel: () => ReactWrapper; findDetailPanelTitle: () => string; findEmptyPromptIndexTemplateLink: () => ReactWrapper; + findDetailPanelIlmPolicyLink: () => ReactWrapper; + findDetailPanelIlmPolicyName: () => ReactWrapper; } export const setup = async (overridingDependencies: any = {}): Promise => { @@ -115,7 +118,7 @@ export const setup = async (overridingDependencies: any = {}): Promise { + const clickDeleteActionAt = (index: number) => { findDeleteActionAt(index).simulate('click'); }; @@ -135,7 +138,7 @@ export const setup = async (overridingDependencies: any = {}): Promise { + const clickDeleteDataStreamButton = () => { const { find } = testBed; find('deleteDataStreamButton').simulate('click'); }; @@ -150,6 +153,17 @@ export const setup = async (overridingDependencies: any = {}): Promise { + const { find } = testBed; + return find('ilmPolicyLink'); + }; + + const findDetailPanelIlmPolicyName = () => { + const descriptionList = testBed.component.find(EuiDescriptionListDescription); + // ilm policy is the last in the details list + return descriptionList.last(); + }; + return { ...testBed, actions: { @@ -159,15 +173,17 @@ export const setup = async (overridingDependencies: any = {}): Promise { ]); setLoadDataStreamResponse(dataStreamForDetailPanel); - testBed = await setup(); + testBed = await setup({ history: createMemoryHistory() }); await act(async () => { testBed.actions.goToDataStreamsList(); }); @@ -176,19 +177,19 @@ describe('Data Streams tab', () => { describe('deleting a data stream', () => { test('shows a confirmation modal', async () => { const { - actions: { clickDeletActionAt }, + actions: { clickDeleteActionAt }, findDeleteConfirmationModal, } = testBed; - clickDeletActionAt(0); + clickDeleteActionAt(0); const confirmationModal = findDeleteConfirmationModal(); expect(confirmationModal).toBeDefined(); }); test('sends a request to the Delete API', async () => { const { - actions: { clickDeletActionAt, clickConfirmDelete }, + actions: { clickDeleteActionAt, clickConfirmDelete }, } = testBed; - clickDeletActionAt(0); + clickDeleteActionAt(0); httpRequestsMockHelpers.setDeleteDataStreamResponse({ results: { @@ -219,12 +220,12 @@ describe('Data Streams tab', () => { test('deletes the data stream when delete button is clicked', async () => { const { - actions: { clickNameAt, clickDeletDataStreamButton, clickConfirmDelete }, + actions: { clickNameAt, clickDeleteDataStreamButton, clickConfirmDelete }, } = testBed; await clickNameAt(0); - clickDeletDataStreamButton(); + clickDeleteDataStreamButton(); httpRequestsMockHelpers.setDeleteDataStreamResponse({ results: { @@ -263,7 +264,9 @@ describe('Data Streams tab', () => { setLoadDataStreamsResponse([dataStreamDollarSign]); setLoadDataStreamResponse(dataStreamDollarSign); - testBed = await setup(); + testBed = await setup({ + history: createMemoryHistory(), + }); await act(async () => { testBed.actions.goToDataStreamsList(); }); @@ -287,4 +290,82 @@ describe('Data Streams tab', () => { }); }); }); + + describe('url generators', () => { + const mockIlmUrlGenerator = { + getUrlGenerator: () => ({ + createUrl: ({ policyName }: { policyName: string }) => `/test/${policyName}`, + }), + }; + test('with an ILM url generator and an ILM policy', async () => { + const { setLoadDataStreamsResponse, setLoadDataStreamResponse } = httpRequestsMockHelpers; + + const dataStreamForDetailPanel = { + ...createDataStreamPayload('dataStream1'), + ilmPolicyName: 'my_ilm_policy', + }; + setLoadDataStreamsResponse([dataStreamForDetailPanel]); + setLoadDataStreamResponse(dataStreamForDetailPanel); + + testBed = await setup({ + history: createMemoryHistory(), + urlGenerators: mockIlmUrlGenerator, + }); + await act(async () => { + testBed.actions.goToDataStreamsList(); + }); + testBed.component.update(); + + const { actions, findDetailPanelIlmPolicyLink } = testBed; + await actions.clickNameAt(0); + expect(findDetailPanelIlmPolicyLink().prop('href')).toBe('/test/my_ilm_policy'); + }); + + test('with an ILM url generator and no ILM policy', async () => { + const { setLoadDataStreamsResponse, setLoadDataStreamResponse } = httpRequestsMockHelpers; + + const dataStreamForDetailPanel = createDataStreamPayload('dataStream1'); + setLoadDataStreamsResponse([dataStreamForDetailPanel]); + setLoadDataStreamResponse(dataStreamForDetailPanel); + + testBed = await setup({ + history: createMemoryHistory(), + urlGenerators: mockIlmUrlGenerator, + }); + await act(async () => { + testBed.actions.goToDataStreamsList(); + }); + testBed.component.update(); + + const { actions, findDetailPanelIlmPolicyLink, findDetailPanelIlmPolicyName } = testBed; + await actions.clickNameAt(0); + expect(findDetailPanelIlmPolicyLink().exists()).toBeFalsy(); + expect(findDetailPanelIlmPolicyName().contains('None')).toBeTruthy(); + }); + + test('without an ILM url generator and with an ILM policy', async () => { + const { setLoadDataStreamsResponse, setLoadDataStreamResponse } = httpRequestsMockHelpers; + + const dataStreamForDetailPanel = { + ...createDataStreamPayload('dataStream1'), + ilmPolicyName: 'my_ilm_policy', + }; + setLoadDataStreamsResponse([dataStreamForDetailPanel]); + setLoadDataStreamResponse(dataStreamForDetailPanel); + + testBed = await setup({ + history: createMemoryHistory(), + urlGenerators: { getUrlGenerator: () => {} }, + }); + await act(async () => { + testBed.actions.goToDataStreamsList(); + }); + testBed.component.update(); + + const { actions, findDetailPanelIlmPolicyLink, findDetailPanelIlmPolicyName } = testBed; + await actions.clickNameAt(0); + expect(findDetailPanelIlmPolicyLink().exists()).toBeFalsy(); + expect(findDetailPanelIlmPolicyName().contains('my_ilm_policy')).toBeTruthy(); + }); + }); }); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts index b660adb9eec08..c7af3a8f45105 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts @@ -26,8 +26,6 @@ const testBedConfig: TestBedConfig = { doMountAsync: true, }; -const initTestBed = registerTestBed(WithAppDependencies(IndexManagementHome), testBedConfig); - export interface IndicesTestBed extends TestBed { actions: { selectIndexDetailsTab: (tab: 'settings' | 'mappings' | 'stats' | 'edit_settings') => void; @@ -39,7 +37,11 @@ export interface IndicesTestBed extends TestBed { findDataStreamDetailPanelTitle: () => string; } -export const setup = async (): Promise => { +export const setup = async (overridingDependencies: any = {}): Promise => { + const initTestBed = registerTestBed( + WithAppDependencies(IndexManagementHome, overridingDependencies), + testBedConfig + ); const testBed = await initTestBed(); /** diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts index 3d6d94d165855..adc47515acaee 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.ts @@ -18,6 +18,7 @@ import { createDataStreamPayload } from './data_streams_tab.helpers'; at createWorker (//node_modules/brace/index.js:17992:5) */ import { stubWebWorker } from '../../../../../test_utils/stub_web_worker'; +import { createMemoryHistory } from 'history'; stubWebWorker(); describe('', () => { @@ -75,7 +76,9 @@ describe('', () => { httpRequestsMockHelpers.setLoadDataStreamResponse(createDataStreamPayload('dataStream1')); - testBed = await setup(); + testBed = await setup({ + history: createMemoryHistory(), + }); await act(async () => { const { component } = testBed; diff --git a/x-pack/plugins/index_management/kibana.json b/x-pack/plugins/index_management/kibana.json index 28846414ca2e8..ff6a71d53894a 100644 --- a/x-pack/plugins/index_management/kibana.json +++ b/x-pack/plugins/index_management/kibana.json @@ -7,7 +7,8 @@ "home", "licensing", "management", - "features" + "features", + "share" ], "optionalPlugins": [ "security", diff --git a/x-pack/plugins/index_management/public/application/app_context.tsx b/x-pack/plugins/index_management/public/application/app_context.tsx index 22e6f09907d75..c654288aaceb8 100644 --- a/x-pack/plugins/index_management/public/application/app_context.tsx +++ b/x-pack/plugins/index_management/public/application/app_context.tsx @@ -14,6 +14,7 @@ import { IngestManagerSetup } from '../../../ingest_manager/public'; import { IndexMgmtMetricsType } from '../types'; import { UiMetricService, NotificationService, HttpService } from './services'; import { ExtensionsService } from '../services'; +import { SharePluginStart } from '../../../../../src/plugins/share/public'; const AppContext = createContext(undefined); @@ -35,6 +36,7 @@ export interface AppDependencies { history: ScopedHistory; setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs']; uiSettings: CoreSetup['uiSettings']; + urlGenerators: SharePluginStart['urlGenerators']; } export const AppContextProvider = ({ diff --git a/x-pack/plugins/index_management/public/application/constants/ilm_url_generator.ts b/x-pack/plugins/index_management/public/application/constants/ilm_url_generator.ts new file mode 100644 index 0000000000000..1b71e389ee354 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/constants/ilm_url_generator.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const ILM_URL_GENERATOR_ID = 'ILM_URL_GENERATOR_ID'; +export const ILM_PAGES_POLICY_EDIT = 'policy_edit'; diff --git a/x-pack/plugins/index_management/public/application/constants/index.ts b/x-pack/plugins/index_management/public/application/constants/index.ts index d55d28dce7003..80c8779f2f020 100644 --- a/x-pack/plugins/index_management/public/application/constants/index.ts +++ b/x-pack/plugins/index_management/public/application/constants/index.ts @@ -15,3 +15,5 @@ export { } from './detail_panel_tabs'; export const REACT_ROOT_ID = 'indexManagementReactRoot'; + +export * from './ilm_url_generator'; diff --git a/x-pack/plugins/index_management/public/application/mount_management_section.ts b/x-pack/plugins/index_management/public/application/mount_management_section.ts index f7b728c875762..52528d3c51145 100644 --- a/x-pack/plugins/index_management/public/application/mount_management_section.ts +++ b/x-pack/plugins/index_management/public/application/mount_management_section.ts @@ -12,7 +12,7 @@ import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; import { IngestManagerSetup } from '../../../ingest_manager/public'; import { PLUGIN } from '../../common/constants'; import { ExtensionsService } from '../services'; -import { IndexMgmtMetricsType } from '../types'; +import { IndexMgmtMetricsType, StartDependencies } from '../types'; import { AppDependencies } from './app_context'; import { breadcrumbService } from './services/breadcrumbs'; import { documentationService } from './services/documentation'; @@ -28,14 +28,14 @@ interface InternalServices { } export async function mountManagementSection( - coreSetup: CoreSetup, + coreSetup: CoreSetup, usageCollection: UsageCollectionSetup, services: InternalServices, params: ManagementAppMountParams, ingestManager?: IngestManagerSetup ) { const { element, setBreadcrumbs, history } = params; - const [core] = await coreSetup.getStartServices(); + const [core, startDependencies] = await coreSetup.getStartServices(); const { docLinks, fatalErrors, @@ -44,6 +44,7 @@ export async function mountManagementSection( uiSettings, } = core; + const { urlGenerators } = startDependencies.share; docTitle.change(PLUGIN.getI18nName(i18n)); breadcrumbService.setup(setBreadcrumbs); @@ -62,6 +63,7 @@ export async function mountManagementSection( history, setBreadcrumbs, uiSettings, + urlGenerators, }; const unmountAppCallback = renderApp(element, { core, dependencies: appDependencies }); diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_detail_panel/data_stream_detail_panel.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_detail_panel/data_stream_detail_panel.tsx index 0af22b497a4c0..9ec6993717435 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_detail_panel/data_stream_detail_panel.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_detail_panel/data_stream_detail_panel.tsx @@ -28,6 +28,10 @@ import { SectionLoading, SectionError, Error, DataHealth } from '../../../../com import { useLoadDataStream } from '../../../../services/api'; import { DeleteDataStreamConfirmationModal } from '../delete_data_stream_confirmation_modal'; import { humanizeTimeStamp } from '../humanize_time_stamp'; +import { useUrlGenerator } from '../../../../services/use_url_generator'; +import { ILM_PAGES_POLICY_EDIT, ILM_URL_GENERATOR_ID } from '../../../../constants'; +import { useAppContext } from '../../../../app_context'; +import { getIndexListUri } from '../../../../..'; interface DetailsListProps { details: Array<{ @@ -72,19 +76,26 @@ const DetailsList: React.FunctionComponent = ({ details }) => interface Props { dataStreamName: string; - backingIndicesLink: ReturnType; onClose: (shouldReload?: boolean) => void; } export const DataStreamDetailPanel: React.FunctionComponent = ({ dataStreamName, - backingIndicesLink, onClose, }) => { const { error, data: dataStream, isLoading } = useLoadDataStream(dataStreamName); const [isDeleting, setIsDeleting] = useState(false); + const ilmPolicyLink = useUrlGenerator({ + urlGeneratorId: ILM_URL_GENERATOR_ID, + urlGeneratorState: { + page: ILM_PAGES_POLICY_EDIT, + policyName: dataStream?.ilmPolicyName, + }, + }); + const { history } = useAppContext(); + let content; if (isLoading) { @@ -159,7 +170,16 @@ export const DataStreamDetailPanel: React.FunctionComponent = ({ toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.indicesToolTip', { defaultMessage: `The data stream's current backing indices`, }), - content: {indices.length}, + content: ( + + {indices.length} + + ), }, { name: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.timestampFieldTitle', { @@ -196,13 +216,23 @@ export const DataStreamDetailPanel: React.FunctionComponent = ({ toolTip: i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyToolTip', { defaultMessage: `The index lifecycle policy that manages the data stream's data`, }), - content: ilmPolicyName ?? ( - - {i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyContentNoneMessage', { - defaultMessage: `None`, - })} - - ), + content: + ilmPolicyName && ilmPolicyLink ? ( + + {ilmPolicyName} + + ) : ( + ilmPolicyName || ( + + {i18n.translate('xpack.idxMgmt.dataStreamDetailPanel.ilmPolicyContentNoneMessage', { + defaultMessage: `None`, + })} + + ) + ), }, ]; diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx index 19286523055f5..ba79319b566bf 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx @@ -28,7 +28,6 @@ import { import { useAppContext } from '../../../app_context'; import { SectionError, SectionLoading, Error } from '../../../components'; import { useLoadDataStreams } from '../../../services/api'; -import { getIndexListUri } from '../../../services/routing'; import { documentationService } from '../../../services/documentation'; import { Section } from '../home'; import { DataStreamTable } from './data_stream_table'; @@ -233,10 +232,6 @@ export const DataStreamList: React.FunctionComponent { history.push(`/${Section.DataStreams}`); diff --git a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx index 0c403e69d2e76..961a171f9f05a 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/tabs/tab_summary.tsx @@ -19,9 +19,9 @@ import { EuiCodeBlock, EuiSpacer, } from '@elastic/eui'; -import { useAppContext } from '../../../../../app_context'; import { TemplateDeserialized } from '../../../../../../../common'; -import { getILMPolicyPath } from '../../../../../services/routing'; +import { ILM_PAGES_POLICY_EDIT, ILM_URL_GENERATOR_ID } from '../../../../../constants'; +import { useUrlGenerator } from '../../../../../services/use_url_generator'; interface Props { templateDetails: TemplateDeserialized; @@ -53,9 +53,13 @@ export const TabSummary: React.FunctionComponent = ({ templateDetails }) const numIndexPatterns = indexPatterns.length; - const { - core: { getUrlForApp }, - } = useAppContext(); + const ilmPolicyLink = useUrlGenerator({ + urlGeneratorId: ILM_URL_GENERATOR_ID, + urlGeneratorState: { + page: ILM_PAGES_POLICY_EDIT, + policyName: ilmPolicy?.name, + }, + }); return ( <> @@ -159,16 +163,10 @@ export const TabSummary: React.FunctionComponent = ({ templateDetails }) /> - {ilmPolicy && ilmPolicy.name ? ( - - {ilmPolicy.name} - + {ilmPolicy?.name && ilmPolicyLink ? ( + {ilmPolicy!.name} ) : ( - i18nTexts.none + ilmPolicy?.name || i18nTexts.none )} diff --git a/x-pack/plugins/index_management/public/application/services/use_url_generator.ts b/x-pack/plugins/index_management/public/application/services/use_url_generator.ts new file mode 100644 index 0000000000000..4e6bd05aa14b5 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/services/use_url_generator.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useEffect, useState } from 'react'; +import { + UrlGeneratorContract, + UrlGeneratorId, + UrlGeneratorStateMapping, +} from '../../../../../../src/plugins/share/public'; +import { useAppContext } from '../app_context'; + +export const useUrlGenerator = ({ + urlGeneratorId, + urlGeneratorState, +}: { + urlGeneratorId: UrlGeneratorId; + urlGeneratorState: UrlGeneratorStateMapping[UrlGeneratorId]['State']; +}) => { + const { urlGenerators } = useAppContext(); + const [link, setLink] = useState(); + useEffect(() => { + const updateLink = async (): Promise => { + let urlGenerator: UrlGeneratorContract; + try { + urlGenerator = urlGenerators.getUrlGenerator(urlGeneratorId); + const url = await urlGenerator.createUrl(urlGeneratorState); + setLink(url); + } catch (e) { + // do nothing + } + }; + + updateLink(); + }, [urlGeneratorId, urlGeneratorState, urlGenerators]); + return link; +}; diff --git a/x-pack/plugins/index_management/public/index.ts b/x-pack/plugins/index_management/public/index.ts index 538dcaf25c47d..da6d90f22a384 100644 --- a/x-pack/plugins/index_management/public/index.ts +++ b/x-pack/plugins/index_management/public/index.ts @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ import './index.scss'; -import { IndexMgmtUIPlugin, IndexManagementPluginSetup } from './plugin'; +import { IndexMgmtUIPlugin } from './plugin'; /** @public */ export const plugin = () => { return new IndexMgmtUIPlugin(); }; -export { IndexManagementPluginSetup }; +export { IndexManagementPluginSetup } from './types'; export { getIndexListUri } from './application/services/routing'; diff --git a/x-pack/plugins/index_management/public/plugin.ts b/x-pack/plugins/index_management/public/plugin.ts index 6139ed5d2e6ad..855486528b797 100644 --- a/x-pack/plugins/index_management/public/plugin.ts +++ b/x-pack/plugins/index_management/public/plugin.ts @@ -6,10 +6,7 @@ import { i18n } from '@kbn/i18n'; import { CoreSetup } from '../../../../src/core/public'; -import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public'; -import { ManagementSetup } from '../../../../src/plugins/management/public'; -import { IngestManagerSetup } from '../../ingest_manager/public'; import { UIM_APP_NAME, PLUGIN } from '../common/constants'; import { httpService } from './application/services/http'; @@ -19,18 +16,13 @@ import { UiMetricService } from './application/services/ui_metric'; import { setExtensionsService } from './application/store/selectors'; import { setUiMetricService } from './application/services/api'; -import { IndexMgmtMetricsType } from './types'; -import { ExtensionsService, ExtensionsSetup } from './services'; - -export interface IndexManagementPluginSetup { - extensionsService: ExtensionsSetup; -} - -interface PluginsDependencies { - ingestManager?: IngestManagerSetup; - usageCollection: UsageCollectionSetup; - management: ManagementSetup; -} +import { + IndexManagementPluginSetup, + IndexMgmtMetricsType, + SetupDependencies, + StartDependencies, +} from './types'; +import { ExtensionsService } from './services'; export class IndexMgmtUIPlugin { private uiMetricService = new UiMetricService(UIM_APP_NAME); @@ -43,7 +35,10 @@ export class IndexMgmtUIPlugin { setUiMetricService(this.uiMetricService); } - public setup(coreSetup: CoreSetup, plugins: PluginsDependencies): IndexManagementPluginSetup { + public setup( + coreSetup: CoreSetup, + plugins: SetupDependencies + ): IndexManagementPluginSetup { const { http, notifications } = coreSetup; const { ingestManager, usageCollection, management } = plugins; diff --git a/x-pack/plugins/index_management/public/types.ts b/x-pack/plugins/index_management/public/types.ts index 08fbf63450218..f860b89b0ba0c 100644 --- a/x-pack/plugins/index_management/public/types.ts +++ b/x-pack/plugins/index_management/public/types.ts @@ -4,4 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ +import { ExtensionsSetup } from './services'; +import { IngestManagerSetup } from '../../ingest_manager/public'; +import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public'; +import { ManagementSetup } from '../../../../src/plugins/management/public'; +import { SharePluginStart } from '../../../../src/plugins/share/public'; + export type IndexMgmtMetricsType = 'loaded' | 'click' | 'count'; + +export interface IndexManagementPluginSetup { + extensionsService: ExtensionsSetup; +} + +export interface SetupDependencies { + ingestManager?: IngestManagerSetup; + usageCollection: UsageCollectionSetup; + management: ManagementSetup; +} + +export interface StartDependencies { + share: SharePluginStart; +}