/* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ import { EuiBasicTable, EuiButton, EuiEmptyPrompt, EuiFieldSearch, EuiHorizontalRule, EuiTableFieldDataColumnType, EuiTableSortingType, SortDirection, } from '@elastic/eui'; import { Criteria } from '@elastic/eui/src/components/basic_table/basic_table'; import { Pagination } from '@elastic/eui/src/components/basic_table/pagination_bar'; import _ from 'lodash'; import React, { Component } from 'react'; import { CoreStart } from '../../../../../../../src/core/public'; import { SESSenderItemType, TableState, } from '../../../../../models/interfaces'; import { ContentPanel, ContentPanelActions, } from '../../../../components/ContentPanel'; import { ModalConsumer } from '../../../../components/Modal'; import { ServicesContext } from '../../../../services'; import { ROUTES } from '../../../../utils/constants'; import { getErrorMessage } from '../../../../utils/helpers'; import { DEFAULT_PAGE_SIZE_OPTIONS } from '../../../Notifications/utils/constants'; import { DeleteSenderModal } from '../modals/DeleteSenderModal'; interface SESSendersTableProps { coreContext: CoreStart; } interface SESSendersTableState extends TableState<SESSenderItemType> {} export class SESSendersTable extends Component< SESSendersTableProps, SESSendersTableState > { static contextType = ServicesContext; columns: EuiTableFieldDataColumnType<SESSenderItemType>[]; constructor(props: SESSendersTableProps) { super(props); this.state = { total: 0, from: 0, size: 5, search: '', sortField: 'name', sortDirection: SortDirection.ASC, items: [], selectedItems: [], loading: true, }; this.columns = [ { field: 'name', name: 'Name', sortable: true, truncateText: true, width: '200px', }, { field: 'ses_account.from_address', name: 'Outbound email address', sortable: true, truncateText: true, }, { field: 'ses_account.region', name: 'AWS region', sortable: true, truncateText: true, }, { field: 'ses_account.role_arn', name: 'Role ARN', sortable: false, truncateText: true, }, ]; this.refresh = this.refresh.bind(this); } async componentDidMount() { await this.refresh(); } async componentDidUpdate( prevProps: SESSendersTableProps, prevState: SESSendersTableState ) { const prevQuery = SESSendersTable.getQueryObjectFromState(prevState); const currQuery = SESSendersTable.getQueryObjectFromState(this.state); if (!_.isEqual(prevQuery, currQuery)) { await this.refresh(); } } static getQueryObjectFromState(state: SESSendersTableState) { return { from_index: state.from, max_items: state.size, query: state.search, config_type: 'ses_account', sort_field: state.sortField, sort_order: state.sortDirection, }; } async refresh() { this.setState({ loading: true }); try { const queryObject = SESSendersTable.getQueryObjectFromState(this.state); const senders = await this.context.notificationService.getSESSenders( queryObject ); this.setState({ items: senders.items, total: senders.total }); } catch (error) { this.props.coreContext.notifications.toasts.addDanger( getErrorMessage(error, 'There was a problem loading SES senders.') ); } this.setState({ loading: false }); } onTableChange = ({ page: tablePage, sort, }: Criteria<SESSenderItemType>): void => { const { index: page, size } = tablePage!; const { field: sortField, direction: sortDirection } = sort!; this.setState({ from: page * size, size, sortField, sortDirection }); }; onSelectionChange = (selectedItems: SESSenderItemType[]): void => { this.setState({ selectedItems }); }; onSearchChange = (search: string): void => { this.setState({ from: 0, search }); }; render() { const page = Math.floor(this.state.from / this.state.size); const pagination: Pagination = { pageIndex: page, pageSize: this.state.size, pageSizeOptions: DEFAULT_PAGE_SIZE_OPTIONS, totalItemCount: this.state.total, }; const sorting: EuiTableSortingType<SESSenderItemType> = { sort: { direction: this.state.sortDirection, field: this.state.sortField, }, }; const selection = { selectable: () => true, onSelectionChange: this.onSelectionChange, }; return ( <ContentPanel actions={ <ContentPanelActions actions={[ { component: ( <ModalConsumer> {({ onShow }) => ( <EuiButton data-test-subj="ses-senders-table-delete-button" disabled={this.state.selectedItems.length === 0} onClick={() => onShow(DeleteSenderModal, { senders: this.state.selectedItems, refresh: this.refresh, }) } > Delete </EuiButton> )} </ModalConsumer> ), }, { component: ( <EuiButton data-test-subj="ses-senders-table-edit-button" disabled={this.state.selectedItems.length !== 1} onClick={() => location.assign( `#${ROUTES.EDIT_SES_SENDER}/${this.state.selectedItems[0]?.config_id}` ) } > Edit </EuiButton> ), }, { component: ( <EuiButton fill href={`#${ROUTES.CREATE_SES_SENDER}`}> Create SES sender </EuiButton> ), }, ]} /> } bodyStyles={{ padding: 'initial' }} title="SES senders" titleSize="m" total={this.state.total} > <EuiFieldSearch data-test-subj="ses-senders-table-search-input" fullWidth={true} placeholder="Search" onSearch={this.onSearchChange} /> <EuiHorizontalRule margin="s" /> <EuiBasicTable columns={this.columns} items={this.state.items} itemId="config_id" isSelectable={true} selection={selection} noItemsMessage={ <EuiEmptyPrompt title={<h2>No SES senders to display</h2>} body="Set up an outbound email server by creating a sender. You will select a sender when configuring email channels." actions={ <EuiButton href={`#${ROUTES.CREATE_SES_SENDER}`}> Create SES sender </EuiButton> } /> } onChange={this.onTableChange} pagination={pagination} sorting={sorting} loading={this.state.loading} tableLayout="auto" /> </ContentPanel> ); } }