StatusTable.jsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import React from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import PropTypes from 'prop-types';
  4. class StatusTable extends React.PureComponent {
  5. renderPreInitializedLabel() {
  6. return <span className="badge text-bg-default">――</span>;
  7. }
  8. renderConnectionStatusLabels() {
  9. const { t } = this.props;
  10. const { isErrorOccuredOnSearchService, isConnected, isConfigured } =
  11. this.props;
  12. const errorOccuredLabel = isErrorOccuredOnSearchService ? (
  13. <span className="badge text-bg-danger ms-2">
  14. {t('full_text_search_management.connection_status_label_erroroccured')}
  15. </span>
  16. ) : null;
  17. let connectionStatusLabel = null;
  18. if (!isConfigured) {
  19. connectionStatusLabel = (
  20. <span className="badge text-bg-default">
  21. {t(
  22. 'full_text_search_management.connection_status_label_unconfigured',
  23. )}
  24. </span>
  25. );
  26. } else {
  27. connectionStatusLabel = isConnected ? (
  28. // eslint-disable-next-line max-len
  29. <span
  30. data-testid="connection-status-badge-connected"
  31. className="badge text-bg-success"
  32. >
  33. {t('full_text_search_management.connection_status_label_connected')}
  34. </span>
  35. ) : (
  36. <span className="badge text-bg-danger">
  37. {t(
  38. 'full_text_search_management.connection_status_label_disconnected',
  39. )}
  40. </span>
  41. );
  42. }
  43. return (
  44. <>
  45. {connectionStatusLabel}
  46. {errorOccuredLabel}
  47. </>
  48. );
  49. }
  50. renderIndicesStatusLabel() {
  51. const { t, isNormalized } = this.props;
  52. return isNormalized ? (
  53. <span className="badge text-bg-info">
  54. {t('full_text_search_management.indices_status_label_normalized')}
  55. </span>
  56. ) : (
  57. <span className="badge text-bg-warning">
  58. {t('full_text_search_management.indices_status_label_unnormalized')}
  59. </span>
  60. );
  61. }
  62. renderIndexInfoPanel(indexName, body = {}, aliases = []) {
  63. const collapseId = `collapse-${indexName}`;
  64. const aliasLabels = aliases.map((aliasName) => {
  65. return (
  66. <span
  67. key={`badge-${indexName}-${aliasName}`}
  68. className="badge text-bg-primary me-2"
  69. >
  70. <span className="material-symbols-outlined">sell</span>
  71. <span>{aliasName}</span>
  72. </span>
  73. );
  74. });
  75. return (
  76. <div className="card">
  77. <div className="card-header">
  78. <a
  79. role="button"
  80. className="text-nowrap me-2"
  81. data-bs-toggle="collapse"
  82. href={`#${collapseId}`}
  83. aria-expanded="true"
  84. aria-controls={collapseId}
  85. >
  86. <span className="material-symbols-outlined">database</span>{' '}
  87. {indexName}
  88. </a>
  89. <span className="ms-md-3">{aliasLabels}</span>
  90. </div>
  91. <div id={collapseId} className="collapse">
  92. <div className="card-body">
  93. <pre>{JSON.stringify(body, null, 2)}</pre>
  94. </div>
  95. </div>
  96. </div>
  97. );
  98. }
  99. renderIndexInfoPanels() {
  100. const { indicesData, aliasesData } = this.props;
  101. // data is null
  102. if (indicesData == null) {
  103. return null;
  104. }
  105. /*
  106. "indices": {
  107. "growi": {
  108. ...
  109. }
  110. },
  111. */
  112. const indexNameToDataMap = {};
  113. for (const [indexName, indexData] of Object.entries(indicesData)) {
  114. indexNameToDataMap[indexName] = indexData;
  115. }
  116. // no indices
  117. if (indexNameToDataMap.length === 0) {
  118. return null;
  119. }
  120. /*
  121. "aliases": {
  122. "growi": {
  123. "aliases": {
  124. "growi-alias": {}
  125. }
  126. }
  127. },
  128. */
  129. const indexNameToAliasMap = {};
  130. for (const [indexName, aliasData] of Object.entries(aliasesData)) {
  131. indexNameToAliasMap[indexName] = Object.keys(aliasData.aliases);
  132. }
  133. return (
  134. <div className="row">
  135. {Object.keys(indexNameToDataMap).map((indexName) => {
  136. return (
  137. <div key={`col-${indexName}`} className="col-md-6">
  138. {this.renderIndexInfoPanel(
  139. indexName,
  140. indexNameToDataMap[indexName],
  141. indexNameToAliasMap[indexName],
  142. )}
  143. </div>
  144. );
  145. })}
  146. </div>
  147. );
  148. }
  149. render() {
  150. const { t } = this.props;
  151. const { isInitialized } = this.props;
  152. return (
  153. <table className="table table-bordered">
  154. <tbody>
  155. <tr>
  156. <th className="w-25">
  157. {t('full_text_search_management.connection_status')}
  158. </th>
  159. <td className="w-75">
  160. {isInitialized
  161. ? this.renderConnectionStatusLabels()
  162. : this.renderPreInitializedLabel()}
  163. </td>
  164. </tr>
  165. <tr>
  166. <th className="w-25">
  167. {t('full_text_search_management.indices_status')}
  168. </th>
  169. <td className="w-75">
  170. {isInitialized
  171. ? this.renderIndicesStatusLabel()
  172. : this.renderPreInitializedLabel()}
  173. </td>
  174. </tr>
  175. <tr>
  176. <th className="w-25">
  177. {t('full_text_search_management.indices_summary')}
  178. </th>
  179. <td className="p-4 w-75">
  180. {isInitialized && this.renderIndexInfoPanels()}
  181. </td>
  182. </tr>
  183. </tbody>
  184. </table>
  185. );
  186. }
  187. }
  188. const StatusTableWrapperFC = (props) => {
  189. const { t } = useTranslation('admin');
  190. return <StatusTable t={t} {...props} />;
  191. };
  192. StatusTable.propTypes = {
  193. t: PropTypes.func.isRequired, // i18next
  194. isInitialized: PropTypes.bool,
  195. isErrorOccuredOnSearchService: PropTypes.bool,
  196. isConnected: PropTypes.bool,
  197. isConfigured: PropTypes.bool,
  198. isNormalized: PropTypes.bool,
  199. indicesData: PropTypes.object,
  200. aliasesData: PropTypes.object,
  201. };
  202. export default StatusTableWrapperFC;