StatusTable.jsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { withTranslation } from 'react-i18next';
  4. import { createSubscribedElement } from '../../UnstatedUtils';
  5. class StatusTable extends React.PureComponent {
  6. renderIndexInfoPanel(indexName, body = {}, aliases = []) {
  7. const collapseId = `collapse-${indexName}`;
  8. const aliasLabels = aliases.map((aliasName) => {
  9. return (
  10. <span key={`badge-${indexName}-${aliasName}`} className="badge badge-pill badge-primary mr-2">
  11. <i className="icon-tag"></i> {aliasName}
  12. </span>
  13. );
  14. });
  15. return (
  16. <div className="card">
  17. <div className="card-header">
  18. <a role="button" data-toggle="collapse" href={`#${collapseId}`} aria-expanded="true" aria-controls={collapseId}>
  19. <i className="fa fa-fw fa-database"></i> {indexName}
  20. </a>
  21. <span className="ml-3">{aliasLabels}</span>
  22. </div>
  23. <div id={collapseId} className="collapse">
  24. <div className="card-body">
  25. <pre>
  26. {JSON.stringify(body, null, 2)}
  27. </pre>
  28. </div>
  29. </div>
  30. </div>
  31. );
  32. }
  33. renderIndexInfoPanels() {
  34. const {
  35. indicesData,
  36. aliasesData,
  37. } = this.props;
  38. // data is null
  39. if (indicesData == null) {
  40. return null;
  41. }
  42. /*
  43. "indices": {
  44. "growi": {
  45. ...
  46. }
  47. },
  48. */
  49. const indexNameToDataMap = {};
  50. for (const [indexName, indexData] of Object.entries(indicesData)) {
  51. indexNameToDataMap[indexName] = indexData;
  52. }
  53. // no indices
  54. if (indexNameToDataMap.length === 0) {
  55. return null;
  56. }
  57. /*
  58. "aliases": {
  59. "growi": {
  60. "aliases": {
  61. "growi-alias": {}
  62. }
  63. }
  64. },
  65. */
  66. const indexNameToAliasMap = {};
  67. for (const [indexName, aliasData] of Object.entries(aliasesData)) {
  68. indexNameToAliasMap[indexName] = Object.keys(aliasData.aliases);
  69. }
  70. return (
  71. <div className="row">
  72. { Object.keys(indexNameToDataMap).map((indexName) => {
  73. return (
  74. <div key={`col-${indexName}`} className="col-6">
  75. { this.renderIndexInfoPanel(indexName, indexNameToDataMap[indexName], indexNameToAliasMap[indexName]) }
  76. </div>
  77. );
  78. }) }
  79. </div>
  80. );
  81. }
  82. render() {
  83. const { t } = this.props;
  84. const { isConfigured, isConnected, isNormalized } = this.props;
  85. let connectionStatusLabel = <span className="badge badge-pill badge-secondary">――</span>;
  86. if (isConfigured != null && !isConfigured) {
  87. connectionStatusLabel = <span className="badge badge-pill badge-secondary">{t('full_text_search_management.connection_status_label_unconfigured')}</span>;
  88. }
  89. else if (isConnected != null) {
  90. connectionStatusLabel = isConnected
  91. ? <span className="badge badge-pill badge-success">{ t('full_text_search_management.connection_status_label_connected') }</span>
  92. : <span className="badge badge-pill badge-danger">{ t('full_text_search_management.connection_status_label_disconnected') }</span>;
  93. }
  94. let indicesStatusLabel = <span className="badge badge-pill badge-secondary">――</span>;
  95. if (isNormalized != null) {
  96. indicesStatusLabel = isNormalized
  97. ? <span className="badge badge-pill badge-info">{ t('full_text_search_management.indices_status_label_normalized') }</span>
  98. : <span className="badge badge-pill badge-warning">{ t('full_text_search_management.indices_status_label_unnormalized') }</span>;
  99. }
  100. return (
  101. <table className="table table-bordered">
  102. <tbody>
  103. <tr>
  104. <th className="w-25">{t('full_text_search_management.connection_status')}</th>
  105. <td className="w-75">{connectionStatusLabel}</td>
  106. </tr>
  107. <tr>
  108. <th className="w-25">{t('full_text_search_management.indices_status')}</th>
  109. <td className="w-75">{indicesStatusLabel}</td>
  110. </tr>
  111. <tr>
  112. <th className="w-25">{t('full_text_search_management.indices_summary')}</th>
  113. <td className="p-4 w-75">{this.renderIndexInfoPanels()}</td>
  114. </tr>
  115. </tbody>
  116. </table>
  117. );
  118. }
  119. }
  120. /**
  121. * Wrapper component for using unstated
  122. */
  123. const StatusTableWrapper = (props) => {
  124. return createSubscribedElement(StatusTable, props, []);
  125. };
  126. StatusTable.propTypes = {
  127. t: PropTypes.func.isRequired, // i18next
  128. isConfigured: PropTypes.bool,
  129. isConnected: PropTypes.bool,
  130. isNormalized: PropTypes.bool,
  131. indicesData: PropTypes.object,
  132. aliasesData: PropTypes.object,
  133. };
  134. export default withTranslation()(StatusTableWrapper);