AdminHome.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import type { FC } from 'react';
  2. import { useRef, useState } from 'react';
  3. import { useTranslation } from 'next-i18next';
  4. import { CopyToClipboard } from 'react-copy-to-clipboard';
  5. import { Tooltip } from 'reactstrap';
  6. import { useSWRxAdminHome } from '~/stores/admin/admin-home';
  7. import { useSWRxV5MigrationStatus } from '~/stores/page-listing';
  8. import { generatePrefilledHostInformationMarkdown } from '~/utils/admin-home';
  9. import { EnvVarsTable } from './EnvVarsTable';
  10. import SystemInfomationTable from './SystemInfomationTable';
  11. const COPY_STATE = {
  12. DEFAULT: 'default',
  13. DONE: 'done',
  14. } as const;
  15. export const AdminHome: FC = () => {
  16. const { t } = useTranslation();
  17. const { data: adminHomeData } = useSWRxAdminHome();
  18. const { data: migrationStatus } = useSWRxV5MigrationStatus();
  19. const [copyState, setCopyState] = useState<string>(COPY_STATE.DEFAULT);
  20. const handleCopyPrefilledHostInformation = () => {
  21. setCopyState(COPY_STATE.DONE);
  22. setTimeout(() => {
  23. setCopyState(COPY_STATE.DEFAULT);
  24. }, 500);
  25. };
  26. const copyIconRef = useRef<HTMLSpanElement>(null);
  27. return (
  28. <div data-testid="admin-home">
  29. {
  30. // Alert message will be displayed in case that the GROWI is under maintenance
  31. adminHomeData?.isMaintenanceMode && (
  32. <div className="alert alert-danger alert-link" role="alert">
  33. <h3 className="alert-heading">
  34. {t('admin:maintenance_mode.maintenance_mode')}
  35. </h3>
  36. <p>{t('admin:maintenance_mode.description')}</p>
  37. <hr />
  38. <a className="btn-link" href="/admin/app" rel="noopener noreferrer">
  39. <span
  40. className="material-symbols-outlined ms-1"
  41. aria-hidden="true"
  42. >
  43. link
  44. </span>
  45. <strong>
  46. {t('admin:maintenance_mode.end_maintenance_mode')}
  47. </strong>
  48. </a>
  49. </div>
  50. )
  51. }
  52. {
  53. // Alert message will be displayed in case that V5 migration has not been compleated
  54. migrationStatus != null && !migrationStatus.isV5Compatible && (
  55. <div
  56. className={`alert ${migrationStatus.isV5Compatible == null ? 'alert-warning' : 'alert-info'}`}
  57. >
  58. {t('admin:v5_page_migration.migration_desc')}
  59. <a className="btn-link" href="/admin/app" rel="noopener noreferrer">
  60. <span
  61. className="material-symbols-outlined ms-1"
  62. aria-hidden="true"
  63. >
  64. link
  65. </span>
  66. <strong>{t('admin:v5_page_migration.upgrade_to_v5')}</strong>
  67. </a>
  68. </div>
  69. )
  70. }
  71. <p>
  72. {t('admin:admin_top.wiki_administrator')}
  73. <br></br>
  74. {t('admin:admin_top.assign_administrator')}
  75. </p>
  76. <div className="row mb-5">
  77. <div className="col-lg-12">
  78. <h2 className="admin-setting-header">
  79. {t('admin:admin_top.system_information')}
  80. </h2>
  81. <SystemInfomationTable />
  82. </div>
  83. </div>
  84. <div className="row mb-5">
  85. <div className="col-md-12">
  86. <h2 className="admin-setting-header">
  87. {t('admin:admin_top.list_of_env_vars')}
  88. </h2>
  89. <p>{t('admin:admin_top.env_var_priority')}</p>
  90. <p
  91. // biome-ignore lint/security/noDangerouslySetInnerHtml: ignore
  92. dangerouslySetInnerHTML={{
  93. __html: t('admin:admin_top.about_security'),
  94. }}
  95. />
  96. <EnvVarsTable envVars={adminHomeData?.envVars} />
  97. </div>
  98. </div>
  99. <div className="row mb-5">
  100. <div className="col-md-12">
  101. <h2 className="admin-setting-header">
  102. {t('admin:admin_top.bug_report')}
  103. </h2>
  104. <ol className="mb-0">
  105. <li className="mb-3">
  106. <CopyToClipboard
  107. text={generatePrefilledHostInformationMarkdown({
  108. growiVersion: adminHomeData?.growiVersion,
  109. nodeVersion: adminHomeData?.nodeVersion,
  110. npmVersion: adminHomeData?.npmVersion,
  111. pnpmVersion: adminHomeData?.pnpmVersion,
  112. })}
  113. onCopy={handleCopyPrefilledHostInformation}
  114. >
  115. <button
  116. type="button"
  117. className="btn btn-outline-secondary btn-sm"
  118. style={{ verticalAlign: 'baseline' }}
  119. onClick={(e) => e.preventDefault()}
  120. >
  121. <span
  122. ref={copyIconRef}
  123. className="material-symbols-outlined"
  124. aria-hidden="true"
  125. >
  126. content_copy
  127. </span>
  128. {t('admin:admin_top:copy_prefilled_host_information:default')}
  129. </button>
  130. </CopyToClipboard>
  131. <Tooltip
  132. placement="bottom"
  133. isOpen={copyState === COPY_STATE.DONE}
  134. target={copyIconRef}
  135. fade={false}
  136. >
  137. {t('admin:admin_top:copy_prefilled_host_information:done')}
  138. </Tooltip>
  139. </li>
  140. <li>
  141. <a
  142. className="link-secondary link-offset-1"
  143. style={{ textDecoration: 'underline' }}
  144. href="https://github.com/growilabs/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A"
  145. target="_blank"
  146. rel="noreferrer"
  147. >
  148. {t('admin:admin_top:submit_bug_report')}
  149. </a>
  150. </li>
  151. </ol>
  152. </div>
  153. </div>
  154. </div>
  155. );
  156. };