/* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ import React, { Component, Fragment } from "react"; import { EuiSpacer, EuiFormRow, EuiCallOut, EuiPopover, EuiFlexGroup, EuiFlexItem, EuiText, EuiButtonEmpty, EuiHorizontalRule, EuiComboBoxOptionOption, EuiBadge, EuiLink, } from "@elastic/eui"; import _ from "lodash"; import EuiComboBox from "../../../../components/ComboBoxWithoutWarning"; import { ContentPanel } from "../../../../components/ContentPanel"; import IndexFilterPopover from "../IndexFilterPopover"; import { FieldItem, IndexItem } from "../../../../../models/interfaces"; import IndexService from "../../../../services/IndexService"; import { CoreServicesContext } from "../../../../components/core_services"; import { wildcardOption } from "../../../../utils/helpers"; interface TransformIndicesProps { indexService: IndexService; sourceIndex: { label: string; value?: IndexItem }[]; sourceIndexFilter: string; sourceIndexFilterError: string; sourceIndexError: string; targetIndex: { label: string; value?: IndexItem }[]; targetIndexError: string; onChangeSourceIndex: (options: EuiComboBoxOptionOption[]) => void; onChangeSourceIndexFilter: (sourceIndexFilter: string) => void; onChangeTargetIndex: (options: EuiComboBoxOptionOption[]) => void; hasAggregation: boolean; fields: FieldItem[]; beenWarned: boolean; } interface TransformIndicesState { isLoading: boolean; indexOptions: { label: string; value?: IndexItem }[]; targetIndexOptions: { label: string; value?: IndexItem }[]; isPopoverOpen: boolean; selectFieldValue: string; } export default class TransformIndices extends Component { static contextType = CoreServicesContext; _isMount: boolean; constructor(props: TransformIndicesProps) { super(props); this.state = { isLoading: true, indexOptions: [], targetIndexOptions: [], isPopoverOpen: false, selectFieldValue: "", }; this._isMount = true; this.onIndexSearchChange = _.debounce(this.onIndexSearchChange, 500, { leading: true }); } async componentDidMount(): Promise { await this.onIndexSearchChange(""); } componentWillUnmount(): void { this._isMount = false; } // TODO: created shared method with rollup indices to reduce duplicate code. onIndexSearchChange = async (searchValue: string): Promise => { if (!this._isMount) { return; } const { indexService } = this.props; this.setState({ isLoading: true, indexOptions: [] }); try { const dataStreamsAndIndicesNamesResponse = await indexService.getDataStreamsAndIndicesNames(searchValue); if (!this._isMount) { return; } if (dataStreamsAndIndicesNamesResponse.ok) { // Adding wildcard to search value const options = searchValue.trim() ? [{ label: wildcardOption(searchValue) }] : []; const dataStreams = dataStreamsAndIndicesNamesResponse.response.dataStreams.map((label) => ({ label })); const indices = dataStreamsAndIndicesNamesResponse.response.indices.map((label) => ({ label })); this.setState({ indexOptions: options.concat(dataStreams, indices), targetIndexOptions: indices }); } else { if (dataStreamsAndIndicesNamesResponse.error.startsWith("[index_not_found_exception]")) { this.context.notifications.toasts.addDanger("No index available"); } else { this.context.notifications.toasts.addDanger(dataStreamsAndIndicesNamesResponse.error); } } } catch (err) { this.context.notifications.toasts.addDanger(err.message); } this.setState({ isLoading: false }); }; onCreateOption = (searchValue: string, flattenedOptions: { label: string; value?: IndexItem }[]): void => { const { targetIndexOptions } = this.state; const { onChangeTargetIndex } = this.props; const normalizedSearchValue = searchValue.trim(); if (!normalizedSearchValue) { return; } const newOption = { label: searchValue, }; // Create the option if it doesn't exist. if (flattenedOptions.findIndex((option) => option.label.trim() === normalizedSearchValue) === -1) { targetIndexOptions.concat(newOption); this.setState({ targetIndexOptions: targetIndexOptions }); } onChangeTargetIndex([newOption]); }; onButtonClick = () => { const { isPopoverOpen } = this.state; if (isPopoverOpen) { this.setState({ isPopoverOpen: false }); } else { this.setState({ isPopoverOpen: true }); } }; closePopover = () => this.setState({ isPopoverOpen: false }); render() { const { sourceIndex, sourceIndexError, sourceIndexFilter, sourceIndexFilterError, targetIndex, targetIndexError, onChangeSourceIndex, onChangeSourceIndexFilter, onChangeTargetIndex, hasAggregation, beenWarned, } = this.props; const { isLoading, indexOptions, targetIndexOptions, isPopoverOpen } = this.state; const clearIndexFilter = () => { onChangeSourceIndexFilter(""); }; return (
{hasAggregation && (

Note: changing source index will erase all existing definitions about aggregations and metrics.

)}

Source index filter

– optional
You can use the custom DSL to filter a subset of the source index to use in the transform job, which optimizes the job for performance and computing resources. You cannot change these filters once the job is created. {" "} Learn more this.onButtonClick()} onClickAriaLabel="Edit Source Index Filter" iconOnClick={() => clearIndexFilter()} iconOnClickAriaLabel="Clear Source Index Filter" > {sourceIndexFilter} this.onButtonClick()} data-test-subj="addFilter" className="globalFilterBar__addButton" > Edit data filter } isOpen={isPopoverOpen} closePopover={this.closePopover} > {sourceIndexFilterError}

You can't change indices after creating a job. Double-check the source and target index names before proceeding.

); } }