ElasticsearchManagement.jsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import { createSubscribedElement } from '../../UnstatedUtils';
  5. import AppContainer from '../../../services/AppContainer';
  6. import WebsocketContainer from '../../../services/WebsocketContainer';
  7. import { toastSuccess, toastError } from '../../../util/apiNotification';
  8. import StatusTable from './StatusTable';
  9. import ReconnectControls from './ReconnectControls';
  10. import NormalizeIndicesControls from './NormalizeIndicesControls';
  11. import RebuildIndexControls from './RebuildIndexControls';
  12. class ElasticsearchManagement extends React.Component {
  13. constructor(props) {
  14. super(props);
  15. this.state = {
  16. isInitialized: false,
  17. isConnected: false,
  18. isConfigured: false,
  19. isRebuildingProcessing: false,
  20. isRebuildingCompleted: false,
  21. isNormalized: null,
  22. indicesData: null,
  23. aliasesData: null,
  24. };
  25. this.reconnect = this.reconnect.bind(this);
  26. this.normalizeIndices = this.normalizeIndices.bind(this);
  27. this.rebuildIndices = this.rebuildIndices.bind(this);
  28. }
  29. async componentWillMount() {
  30. this.retrieveIndicesStatus();
  31. }
  32. componentDidMount() {
  33. this.initWebSockets();
  34. }
  35. initWebSockets() {
  36. const socket = this.props.websocketContainer.getWebSocket();
  37. socket.on('admin:addPageProgress', (data) => {
  38. this.setState({
  39. isRebuildingProcessing: true,
  40. });
  41. });
  42. socket.on('admin:finishAddPage', (data) => {
  43. this.setState({
  44. isRebuildingProcessing: false,
  45. isRebuildingCompleted: true,
  46. });
  47. });
  48. socket.on('admin:rebuildingFailed', (data) => {
  49. toastError(new Error(data.error), 'Rebuilding Index has failed.');
  50. });
  51. }
  52. async retrieveIndicesStatus() {
  53. const { appContainer } = this.props;
  54. try {
  55. const { info } = await appContainer.apiv3Get('/search/indices');
  56. this.setState({
  57. isConnected: true,
  58. isConfigured: true,
  59. indicesData: info.indices,
  60. aliasesData: info.aliases,
  61. isNormalized: info.isNormalized,
  62. });
  63. }
  64. catch (errors) {
  65. this.setState({ isConnected: false });
  66. // evaluate whether configured or not
  67. for (const error of errors) {
  68. if (error.code === 'search-service-unconfigured') {
  69. this.setState({ isConfigured: false });
  70. }
  71. }
  72. toastError(errors);
  73. }
  74. finally {
  75. this.setState({ isInitialized: true });
  76. }
  77. }
  78. async reconnect() {
  79. const { appContainer } = this.props;
  80. this.setState({ isInitialized: false });
  81. try {
  82. await appContainer.apiv3Post('/search/connection');
  83. toastSuccess('Reconnecting to Elasticsearch has succeeded');
  84. }
  85. catch (e) {
  86. toastError(e);
  87. return;
  88. }
  89. await this.retrieveIndicesStatus();
  90. }
  91. async normalizeIndices() {
  92. const { appContainer } = this.props;
  93. try {
  94. await appContainer.apiv3Put('/search/indices', { operation: 'normalize' });
  95. }
  96. catch (e) {
  97. toastError(e);
  98. }
  99. await this.retrieveIndicesStatus();
  100. toastSuccess('Normalizing has succeeded');
  101. }
  102. async rebuildIndices() {
  103. const { appContainer } = this.props;
  104. this.setState({ isRebuildingProcessing: true });
  105. try {
  106. await appContainer.apiv3Put('/search/indices', { operation: 'rebuild' });
  107. toastSuccess('Rebuilding is requested');
  108. }
  109. catch (e) {
  110. toastError(e);
  111. }
  112. await this.retrieveIndicesStatus();
  113. }
  114. render() {
  115. const { t, appContainer } = this.props;
  116. const {
  117. isInitialized,
  118. isConnected, isConfigured, isRebuildingProcessing, isRebuildingCompleted,
  119. isNormalized, indicesData, aliasesData,
  120. } = this.state;
  121. const isErrorOccuredOnSearchService = !appContainer.config.isSearchServiceReachable;
  122. const isReconnectBtnEnabled = !isInitialized || !isConnected || isErrorOccuredOnSearchService;
  123. return (
  124. <>
  125. <div className="row">
  126. <div className="col-xs-12">
  127. <StatusTable
  128. isInitialized={isInitialized}
  129. isErrorOccuredOnSearchService={isErrorOccuredOnSearchService}
  130. isConnected={isConnected}
  131. isConfigured={isConfigured}
  132. isNormalized={isNormalized}
  133. indicesData={indicesData}
  134. aliasesData={aliasesData}
  135. />
  136. </div>
  137. </div>
  138. <hr />
  139. {/* Controls */}
  140. <div className="row">
  141. <label className="col-xs-3 control-label">{ t('full_text_search_management.reconnect') }</label>
  142. <div className="col-xs-6">
  143. <ReconnectControls
  144. isEnabled={isReconnectBtnEnabled}
  145. onReconnectingRequested={this.reconnect}
  146. />
  147. </div>
  148. </div>
  149. <hr />
  150. <div className="row">
  151. <label className="col-xs-3 control-label">{ t('full_text_search_management.normalize') }</label>
  152. <div className="col-xs-6">
  153. <NormalizeIndicesControls
  154. isRebuildingProcessing={isRebuildingProcessing}
  155. isRebuildingCompleted={isRebuildingCompleted}
  156. isNormalized={isNormalized}
  157. onNormalizingRequested={this.normalizeIndices}
  158. />
  159. </div>
  160. </div>
  161. <hr />
  162. <div className="row">
  163. <label className="col-xs-3 control-label">{ t('full_text_search_management.rebuild') }</label>
  164. <div className="col-xs-6">
  165. <RebuildIndexControls
  166. isRebuildingProcessing={isRebuildingProcessing}
  167. isRebuildingCompleted={isRebuildingCompleted}
  168. isNormalized={isNormalized}
  169. onRebuildingRequested={this.rebuildIndices}
  170. />
  171. </div>
  172. </div>
  173. </>
  174. );
  175. }
  176. }
  177. /**
  178. * Wrapper component for using unstated
  179. */
  180. const ElasticsearchManagementWrapper = (props) => {
  181. return createSubscribedElement(ElasticsearchManagement, props, [AppContainer, WebsocketContainer]);
  182. };
  183. ElasticsearchManagement.propTypes = {
  184. t: PropTypes.func.isRequired, // i18next
  185. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  186. websocketContainer: PropTypes.instanceOf(WebsocketContainer).isRequired,
  187. };
  188. export default withTranslation()(ElasticsearchManagementWrapper);