diff --git a/src/plugins/index_pattern_management/opensearch_dashboards.json b/src/plugins/index_pattern_management/opensearch_dashboards.json index 20bb7b907597..b6b04ab2bf6c 100644 --- a/src/plugins/index_pattern_management/opensearch_dashboards.json +++ b/src/plugins/index_pattern_management/opensearch_dashboards.json @@ -4,5 +4,5 @@ "server": true, "ui": true, "requiredPlugins": ["management", "data", "urlForwarding"], - "requiredBundles": ["opensearchDashboardsReact", "opensearchDashboardsUtils"] + "requiredBundles": ["opensearchDashboardsReact", "opensearchDashboardsUtils", "savedObjects"] } diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/components/header/header.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/components/header/header.tsx new file mode 100644 index 000000000000..ad2013e0086e --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/components/header/header.tsx @@ -0,0 +1,96 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; + +import { EuiTitle, EuiSpacer, EuiText, EuiFlexItem, EuiFormRow, EuiButton } from '@elastic/eui'; + +import { FormattedMessage } from '@osd/i18n/react'; +import { i18n } from '@osd/i18n'; +import { + DataSourceRef, + IndexPatternManagmentContext, +} from 'src/plugins/index_pattern_management/public/types'; +import { SavedObjectFinderUi } from '../../../../../../../../../plugins/saved_objects/public'; +import { useOpenSearchDashboards } from '../../../../../../../../../plugins/opensearch_dashboards_react/public'; + +interface HeaderProps { + onSearchSelected: (id: string, type: string) => void; + dataSourceRef: DataSourceRef; + goToNextStep: (dataSourceRef: DataSourceRef) => void; + isNextStepDisabled: boolean; +} + +const DATA_SOURCE_PAGE_SIZE = 5; + +export const Header: React.FC = (props: HeaderProps) => { + const { dataSourceRef, onSearchSelected, goToNextStep, isNextStepDisabled } = props; + + const { savedObjects, uiSettings } = useOpenSearchDashboards< + IndexPatternManagmentContext + >().services; + + return ( +
+ +

+ +

+
+ + + + + + 'apps', // todo: #2034 + name: i18n.translate( + 'indexPatternManagement.createIndexPattern.searchSelection.savedObjectType.dataSource', + { + defaultMessage: 'Data Source', + } + ), + }, + ]} + fixedPageSize={DATA_SOURCE_PAGE_SIZE} + uiSettings={uiSettings} + savedObjects={savedObjects} + /> + + goToNextStep(dataSourceRef)} + isDisabled={isNextStepDisabled} + > + + + + +
+ ); +}; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/components/header/index.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/components/header/index.ts new file mode 100644 index 000000000000..3c25d4c42f03 --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/components/header/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { Header } from './header'; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/index.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/index.ts new file mode 100644 index 000000000000..6cea2c4957bc --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { StepDataSource } from './step_data_source'; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/step_data_source.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/step_data_source.tsx new file mode 100644 index 000000000000..eccea5be875f --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_data_source/step_data_source.tsx @@ -0,0 +1,43 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiPageContent } from '@elastic/eui'; +import React, { useState } from 'react'; +import { DataSourceRef } from 'src/plugins/index_pattern_management/public/types'; + +import { Header } from './components/header'; + +interface StepDataSourceProps { + goToNextStep: (dataSourceRef: DataSourceRef) => void; +} + +export const StepDataSource = (props: StepDataSourceProps) => { + const { goToNextStep } = props; + + const [selectedDataSource, setSelectedDataSource] = useState(); + const [isNextStepDisabled, setIsNextStepDisabled] = useState(true); + + const onSearchSelected = (id: string, selectedType: string) => { + const selected = { id, type: selectedType }; + + setSelectedDataSource(selected); + setIsNextStepDisabled(false); + }; + + const renderContent = () => { + return ( + +
goToNextStep(selectedDataSource!)} + isNextStepDisabled={isNextStepDisabled} + /> + + ); + }; + + return <>{renderContent()}; +}; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx index 0b81d14d0e0d..af94ff6f1f05 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx @@ -29,7 +29,14 @@ */ import React, { Component } from 'react'; -import { EuiSpacer, EuiCallOut, EuiSwitchEvent } from '@elastic/eui'; +import { + EuiSpacer, + EuiCallOut, + EuiSwitchEvent, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, +} from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; import { indexPatterns, IndexPatternAttributes, UI_SETTINGS } from '../../../../../../data/public'; @@ -52,6 +59,7 @@ import { IndexPatternManagmentContextValue } from '../../../../types'; interface StepIndexPatternProps { allIndices: MatchedItem[]; indexPatternCreationType: IndexPatternCreationConfig; + goToPreviousStep: () => void; goToNextStep: (query: string, timestampField?: string) => void; initialQuery?: string; showSystemIndices: boolean; @@ -116,6 +124,8 @@ export class StepIndexPattern extends Component + + + + + + + ); + } + renderStatusMessage(matchedIndices: { allIndices: MatchedItem[]; exactMatchedIndices: MatchedItem[]; @@ -383,6 +411,7 @@ export class StepIndexPattern extends Component {this.renderList(matchedIndices)} + {this.dataSrouceEnabled && this.renderGoToPrevious()} ); } diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx index 59b0e8bfc6a6..c10deeed93ef 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx @@ -47,14 +47,25 @@ import { LoadingState } from './components/loading_state'; import { context as contextType } from '../../../../opensearch_dashboards_react/public'; import { getCreateBreadcrumbs } from '../breadcrumbs'; -import { ensureMinimumTime, getIndices } from './lib'; +import { + DATA_SOURCE_STEP, + ensureMinimumTime, + getIndices, + getInitialStepName, + getNextStep, + getPrevStep, + INDEX_PATTERN_STEP, + StepType, + TIME_FIELD_STEP, +} from './lib'; import { IndexPatternCreationConfig } from '../..'; -import { IndexPatternManagmentContextValue } from '../../types'; +import { DataSourceRef, IndexPatternManagmentContextValue } from '../../types'; import { MatchedItem } from './types'; import { DuplicateIndexPatternError, IndexPattern } from '../../../../data/public'; +import { StepDataSource } from './components/step_data_source'; interface CreateIndexPatternWizardState { - step: number; + step: StepType; indexPattern: string; allIndices: MatchedItem[]; remoteClustersExist: boolean; @@ -63,6 +74,7 @@ interface CreateIndexPatternWizardState { indexPatternCreationType: IndexPatternCreationConfig; selectedTimeField?: string; docLinks: DocLinksStart; + dataSourceRef?: DataSourceRef; } export class CreateIndexPatternWizard extends Component< @@ -73,6 +85,8 @@ export class CreateIndexPatternWizard extends Component< public readonly context!: IndexPatternManagmentContextValue; + dataSourceEnabled: boolean; + constructor(props: RouteComponentProps, context: IndexPatternManagmentContextValue) { super(props, context); @@ -80,8 +94,10 @@ export class CreateIndexPatternWizard extends Component< const type = new URLSearchParams(props.location.search).get('type') || undefined; + this.dataSourceEnabled = context.services.dataSourceEnabled; + this.state = { - step: 1, + step: getInitialStepName(this.dataSourceEnabled), indexPattern: '', allIndices: [], remoteClustersExist: false, @@ -209,12 +225,26 @@ export class CreateIndexPatternWizard extends Component< history.push(`/patterns/${emptyPattern.id}`); }; - goToTimeFieldStep = (indexPattern: string, selectedTimeField?: string) => { - this.setState({ step: 2, indexPattern, selectedTimeField }); + goToNextFromIndexPattern = (indexPattern: string, selectedTimeField?: string) => { + this.setState({ indexPattern, selectedTimeField }); + this.goToNextStep(); + }; + + goToNextFromDataSource = (dataSourceRef: DataSourceRef) => { + this.setState({ dataSourceRef }); + this.goToNextStep(); }; - goToIndexPatternStep = () => { - this.setState({ step: 1 }); + goToNextStep = () => { + this.setState((prevState) => ({ + step: getNextStep(prevState.step, this.dataSourceEnabled)!, + })); + }; + + goToPreviousStep = () => { + this.setState((prevState) => ({ + step: getPrevStep(prevState.step, this.dataSourceEnabled)!, + })); }; renderHeader() { @@ -238,7 +268,17 @@ export class CreateIndexPatternWizard extends Component< const header = this.renderHeader(); - if (step === 1) { + if (step === DATA_SOURCE_STEP) { + return ( + + {header} + + + + ); + } + + if (step === INDEX_PATTERN_STEP) { const { location } = this.props; const initialQuery = new URLSearchParams(location.search).get('id') || undefined; @@ -250,23 +290,25 @@ export class CreateIndexPatternWizard extends Component< allIndices={allIndices} initialQuery={indexPattern || initialQuery} indexPatternCreationType={this.state.indexPatternCreationType} - goToNextStep={this.goToTimeFieldStep} + goToPreviousStep={this.goToPreviousStep} + goToNextStep={this.goToNextFromIndexPattern} showSystemIndices={ - this.state.indexPatternCreationType.getShowSystemIndices() && this.state.step === 1 + this.state.indexPatternCreationType.getShowSystemIndices() && + this.state.step === INDEX_PATTERN_STEP } /> ); } - if (step === 2) { + if (step === TIME_FIELD_STEP) { return ( {header} { + if (supportsDataSource) { + return DATA_SOURCE_STEP; + } + + return INDEX_PATTERN_STEP; +}; + +export const getNextStep = ( + currentStep: StepType, + supportsDataSource: boolean +): StepType | null => { + if (supportsDataSource) { + return CREATION_FLOW_WITH_DATA_SOURCE_MAP.get(currentStep).next; + } + + return DEFAULT_CREATION_FLOW_MAP.get(currentStep).next; +}; + +export const getPrevStep = ( + currentStep: StepType, + supportsDataSource: boolean +): StepType | null => { + if (supportsDataSource) { + return CREATION_FLOW_WITH_DATA_SOURCE_MAP.get(currentStep).prev; + } + + return CREATION_FLOW_WITH_DATA_SOURCE_MAP.get(currentStep).prev; +}; + +export const getCurrentStepNumber = ( + currentStep: StepType, + supportsDataSource: boolean +): number => { + if (supportsDataSource) { + return CREATION_FLOW_WITH_DATA_SOURCE_MAP.get(currentStep).stepNumber; + } + + return CREATION_FLOW_WITH_DATA_SOURCE_MAP.get(currentStep).stepNumber; +}; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/index.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/index.ts index b9e7771be27f..09644bc4d8dc 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/index.ts +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/index.ts @@ -39,3 +39,5 @@ export { getMatchedIndices } from './get_matched_indices'; export { containsIllegalCharacters } from './contains_illegal_characters'; export { extractTimeFields } from './extract_time_fields'; + +export * from './creation_flow'; diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx index 205c657421ee..9a412ec89e18 100644 --- a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx @@ -103,6 +103,7 @@ export const IndexPatternTable = ({ canSave, history }: Props) => { http, getMlCardState, data, + dataSourceEnabled, } = useOpenSearchDashboards().services; const [indexPatterns, setIndexPatterns] = useState([]); const [creationOptions, setCreationOptions] = useState([]); @@ -210,16 +211,18 @@ export const IndexPatternTable = ({ canSave, history }: Props) => { const hasDataIndices = sources.some(({ name }: MatchedItem) => !name.startsWith('.')); if (!indexPatterns.length) { - if (!hasDataIndices && !remoteClustersExist) { - return ( - - ); + if (!dataSourceEnabled) { + if (!hasDataIndices && !remoteClustersExist) { + return ( + + ); + } } else { return ( MlCardState; + dataSourceEnabled: boolean; } export type IndexPatternManagmentContextValue = OpenSearchDashboardsReactContextValue< @@ -67,3 +69,5 @@ export enum MlCardState { DISABLED, ENABLED, } + +export type DataSourceRef = Pick;