import React from 'react'; import PropTypes from 'prop-types'; import { withTranslation } from 'react-i18next'; import { createSubscribedElement } from '../../UnstatedUtils'; import AppContainer from '../../../services/AppContainer'; import WebsocketContainer from '../../../services/WebsocketContainer'; import { toastSuccess, toastError } from '../../../util/apiNotification'; import ProgressBar from '../Common/ProgressBar'; class RebuildIndex extends React.Component { constructor(props) { super(props); this.state = { isNormalized: undefined, indicesData: null, aliasesData: null, isProcessing: false, isCompleted: false, total: 0, current: 0, skip: 0, }; this.normalizeIndices = this.normalizeIndices.bind(this); this.rebuildIndices = this.rebuildIndices.bind(this); } async componentWillMount() { this.retrieveIndicesStatus(); } componentDidMount() { this.initWebSockets(); } initWebSockets() { const socket = this.props.websocketContainer.getWebSocket(); socket.on('admin:addPageProgress', (data) => { this.setState({ isProcessing: true, ...data, }); }); socket.on('admin:finishAddPage', (data) => { this.setState({ isProcessing: false, isCompleted: true, ...data, }); }); } async retrieveIndicesStatus() { const { appContainer } = this.props; try { const { info } = await appContainer.apiv3Get('/search/indices'); this.setState({ indicesData: info.indices, aliasesData: info.aliases, isNormalized: info.isNormalized, }); } catch (e) { toastError(e); } } async normalizeIndices() { const { appContainer } = this.props; try { await appContainer.apiv3Put('/search/indices', { operation: 'normalize' }); } catch (e) { toastError(e); } await this.retrieveIndicesStatus(); toastSuccess('Normalizing has succeeded'); } async rebuildIndices() { const { appContainer } = this.props; try { await appContainer.apiv3Put('/search/indices', { operation: 'rebuild' }); this.setState({ isProcessing: true }); toastSuccess('Rebuilding is requested'); } catch (e) { toastError(e); } } renderIndexInfoPanel(indexName, body = {}, aliases = []) { const collapseId = `collapse-${indexName}`; const aliasLabels = aliases.map((aliasName) => { return ( {aliasName} ); }); return (

{indexName} {aliasLabels}

              {JSON.stringify(body, null, 2)}
            
); } renderIndexInfoPanels() { const { indicesData, aliasesData, } = this.state; // data is null if (indicesData == null) { return null; } /* "indices": { "growi": { ... } }, */ const indexNameToDataMap = {}; for (const [indexName, indexData] of Object.entries(indicesData)) { indexNameToDataMap[indexName] = indexData; } // no indices if (indexNameToDataMap.length === 0) { return null; } /* "aliases": { "growi": { "aliases": { "growi-alias": {} } } }, */ const indexNameToAliasMap = {}; for (const [indexName, aliasData] of Object.entries(aliasesData)) { indexNameToAliasMap[indexName] = Object.keys(aliasData.aliases); } return (
{ Object.keys(indexNameToDataMap).map((indexName) => { return (
{ this.renderIndexInfoPanel(indexName, indexNameToDataMap[indexName], indexNameToAliasMap[indexName]) }
); }) }
); } renderProgressBar() { const { total, current, skip, isProcessing, isCompleted, } = this.state; const showProgressBar = isProcessing || isCompleted; if (!showProgressBar) { return null; } const header = isCompleted ? 'Completed' : `Processing.. (${skip} skips)`; return ( ); } renderNormalizeControls() { const { t } = this.props; const isEnabled = !this.state.isNormalized && !this.state.isProcessing; return ( <>

{ t('full_text_search_management.normalize_description') }

); } renderRebuildControls() { const { t } = this.props; const isEnabled = this.state.isNormalized && !this.state.isProcessing; return ( <> { this.renderProgressBar() }

{ t('full_text_search_management.rebuild_description_1') }
{ t('full_text_search_management.rebuild_description_2') }

); } render() { const { t } = this.props; const { isNormalized } = this.state; let statusLabel = ――; if (isNormalized != null) { statusLabel = isNormalized ? { t('full_text_search_management.indices_status_label_normalized') } : { t('full_text_search_management.indices_status_label_unnormalized') }; } return ( <>
{ t('full_text_search_management.indices_status') } {statusLabel}
{ t('full_text_search_management.indices_summary') } { this.renderIndexInfoPanels() }

{/* Controls */}
{ this.renderNormalizeControls() }

{ this.renderRebuildControls() }
); } } /** * Wrapper component for using unstated */ const RebuildIndexWrapper = (props) => { return createSubscribedElement(RebuildIndex, props, [AppContainer, WebsocketContainer]); }; RebuildIndex.propTypes = { t: PropTypes.func.isRequired, // i18next appContainer: PropTypes.instanceOf(AppContainer).isRequired, websocketContainer: PropTypes.instanceOf(WebsocketContainer).isRequired, }; export default withTranslation()(RebuildIndexWrapper);