AdminNavigation.jsx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import React from 'react';
  2. import { pathUtils } from '@growi/core';
  3. import { useTranslation } from 'next-i18next';
  4. import Link from 'next/link';
  5. import PropTypes from 'prop-types';
  6. import urljoin from 'url-join';
  7. import { useGrowiCloudUri, useGrowiAppIdForGrowiCloud } from '../../../stores/context';
  8. // import AppContainer from '~/client/services/AppContainer';
  9. // import { withUnstatedContainers } from '../../UnstatedUtils';
  10. const AdminNavigation = (props) => {
  11. const { t } = useTranslation(['admin', 'commons']);
  12. // const { appContainer } = props;
  13. const pathname = window.location.pathname;
  14. const { data: growiCloudUri } = useGrowiCloudUri();
  15. const { data: growiAppIdForGrowiCloud } = useGrowiAppIdForGrowiCloud();
  16. // eslint-disable-next-line react/prop-types
  17. const MenuLabel = ({ menu }) => {
  18. switch (menu) {
  19. /* eslint-disable no-multi-spaces, max-len */
  20. case 'app': return <><i className="mr-1 icon-fw icon-settings"></i>{ t('headers.app_settings', { ns: 'commons' }) }</>;
  21. case 'security': return <><i className="mr-1 icon-fw icon-shield"></i>{ t('security_settings.security_settings') }</>;
  22. case 'markdown': return <><i className="mr-1 icon-fw icon-note"></i>{ t('markdown_settings.markdown_settings') }</>;
  23. case 'customize': return <><i className="mr-1 icon-fw icon-wrench"></i>{ t('customize_settings.customize_settings') }</>;
  24. case 'importer': return <><i className="mr-1 icon-fw icon-cloud-upload"></i>{ t('importer_management.import_data') }</>;
  25. case 'export': return <><i className="mr-1 icon-fw icon-cloud-download"></i>{ t('export_management.export_archive_data') }</>;
  26. case 'data-transfer': return <><i className="mr-1 icon-fw icon-plane"></i>{ t('g2g_data_transfer.data_transfer', { ns: 'commons' })}</>;
  27. case 'notification': return <><i className="mr-1 icon-fw icon-bell"></i>{ t('external_notification.external_notification')}</>;
  28. case 'slack-integration': return <><i className="mr-1 icon-fw icon-shuffle"></i>{ t('slack_integration.slack_integration') }</>;
  29. case 'slack-integration-legacy': return <><i className="mr-1 icon-fw icon-shuffle"></i>{ t('slack_integration_legacy.slack_integration_legacy')}</>;
  30. case 'users': return <><i className="mr-1 icon-fw icon-user"></i>{ t('user_management.user_management') }</>;
  31. case 'user-groups': return <><i className="mr-1 icon-fw icon-people"></i>{ t('user_group_management.user_group_management') }</>;
  32. case 'audit-log': return <><i className="mr-1 icon-fw icon-feed"></i>{ t('audit_log_management.audit_log')}</>;
  33. case 'plugins': return <><i className="mr-1 icon-fw icon-puzzle"></i>{ t('plugins.plugins')}</>;
  34. case 'search': return <><i className="mr-1 icon-fw icon-magnifier"></i>{ t('full_text_search_management.full_text_search_management') }</>;
  35. case 'cloud': return <><i className="mr-1 icon-fw icon-share-alt"></i>{ t('cloud_setting_management.to_cloud_settings')} </>;
  36. default: return <><i className="mr-1 icon-fw icon-home"></i>{ t('wiki_management_home_page') }</>;
  37. /* eslint-enable no-multi-spaces, max-len */
  38. }
  39. };
  40. const MenuLink = ({
  41. // eslint-disable-next-line react/prop-types
  42. menu, isRoot, isListGroupItems, isActive,
  43. }) => {
  44. const pageTransitionClassName = isListGroupItems
  45. ? 'list-group-item list-group-item-action border-0 round-corner'
  46. : 'dropdown-item px-3 py-2';
  47. const href = isRoot ? '/admin' : urljoin('/admin', menu);
  48. return (
  49. <Link
  50. href={href}
  51. className={`${pageTransitionClassName} ${isActive ? 'active' : ''}`}
  52. >
  53. <MenuLabel menu={menu} />
  54. </Link>
  55. );
  56. };
  57. const isActiveMenu = (path) => {
  58. const basisPath = pathUtils.normalizePath(urljoin('/admin', path));
  59. const basisParentPath = pathUtils.addTrailingSlash(basisPath);
  60. return (
  61. pathname === basisPath
  62. || pathname.startsWith(basisParentPath)
  63. );
  64. };
  65. const getListGroupItemOrDropdownItemList = (isListGroupItems) => {
  66. return (
  67. <>
  68. {/* eslint-disable no-multi-spaces */}
  69. <MenuLink menu="home" isListGroupItems isActive={pathname === '/admin'} isRoot />
  70. <MenuLink menu="app" isListGroupItems isActive={isActiveMenu('/app')} />
  71. <MenuLink menu="security" isListGroupItems isActive={isActiveMenu('/security')} />
  72. <MenuLink menu="markdown" isListGroupItems isActive={isActiveMenu('/markdown')} />
  73. <MenuLink menu="customize" isListGroupItems isActive={isActiveMenu('/customize')} />
  74. <MenuLink menu="importer" isListGroupItems isActive={isActiveMenu('/importer')} />
  75. <MenuLink menu="export" isListGroupItems isActive={isActiveMenu('/export')} />
  76. <MenuLink menu="data-transfer" isListGroupItems isActive={isActiveMenu('/data-transfer')} />
  77. <MenuLink menu="notification" isListGroupItems isActive={isActiveMenu('/notification') || isActiveMenu('/global-notification')} />
  78. <MenuLink menu="slack-integration" isListGroupItems isActive={isActiveMenu('/slack-integration')} />
  79. <MenuLink menu="slack-integration-legacy" isListGroupItems isActive={isActiveMenu('/slack-integration-legacy')} />
  80. <MenuLink menu="users" isListGroupItems isActive={isActiveMenu('/users')} />
  81. <MenuLink menu="user-groups" isListGroupItems isActive={isActiveMenu('/user-groups')} />
  82. <MenuLink menu="audit-log" isListGroupItems isActive={isActiveMenu('/audit-log')} />
  83. <MenuLink menu="plugins" isListGroupItems isActive={isActiveMenu('/plugins')} />
  84. <MenuLink menu="search" isListGroupItems isActive={isActiveMenu('/search')} />
  85. {growiCloudUri != null && growiAppIdForGrowiCloud != null
  86. && (
  87. <a
  88. href={`${growiCloudUri}/my/apps/${growiAppIdForGrowiCloud}`}
  89. className="list-group-item list-group-item-action border-0 round-corner"
  90. >
  91. <MenuLabel menu="cloud" />
  92. </a>
  93. )
  94. }
  95. {/* eslint-enable no-multi-spaces */}
  96. </>
  97. );
  98. };
  99. return (
  100. <React.Fragment>
  101. {/* List group */}
  102. <div className="list-group admin-navigation sticky-top d-none d-lg-block">
  103. {getListGroupItemOrDropdownItemList(true)}
  104. </div>
  105. {/* Dropdown */}
  106. <div className="dropdown d-block d-lg-none mb-5">
  107. <button
  108. className="btn btn-outline-primary btn-lg dropdown-toggle col-12 text-right"
  109. type="button"
  110. id="dropdown-admin-navigation"
  111. data-display="static"
  112. data-toggle="dropdown"
  113. aria-haspopup="true"
  114. aria-expanded="false"
  115. >
  116. <span className="float-left">
  117. {/* eslint-disable no-multi-spaces */}
  118. {pathname === '/admin' && <MenuLabel menu="home" />}
  119. {isActiveMenu('/app') && <MenuLabel menu="app" />}
  120. {isActiveMenu('/security') && <MenuLabel menu="security" />}
  121. {isActiveMenu('/markdown') && <MenuLabel menu="markdown" />}
  122. {isActiveMenu('/customize') && <MenuLabel menu="customize" />}
  123. {isActiveMenu('/importer') && <MenuLabel menu="importer" />}
  124. {isActiveMenu('/export') && <MenuLabel menu="export" />}
  125. {(isActiveMenu('/notification') || isActiveMenu('/global-notification')) && <MenuLabel menu="notification" />}
  126. {isActiveMenu('/slack-integration') && <MenuLabel menu="slack-integration" />}
  127. {isActiveMenu('/users') && <MenuLabel menu="users" />}
  128. {isActiveMenu('/user-groups') && <MenuLabel menu="user-groups" />}
  129. {isActiveMenu('/search') && <MenuLabel menu="search" />}
  130. {isActiveMenu('/audit-log') && <MenuLabel menu="audit-log" />}
  131. {isActiveMenu('/plugins') && <MenuLabel menu="plugins" />}
  132. {isActiveMenu('/data-transfer') && <MenuLabel menu="data-transfer" />}
  133. {/* eslint-enable no-multi-spaces */}
  134. </span>
  135. </button>
  136. <div className="dropdown-menu" aria-labelledby="dropdown-admin-navigation">
  137. {getListGroupItemOrDropdownItemList(false)}
  138. </div>
  139. </div>
  140. </React.Fragment>
  141. );
  142. };
  143. // const AdminNavigationWrapper = withUnstatedContainers(AdminNavigation, [AppContainer]);
  144. AdminNavigation.propTypes = {
  145. // appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  146. };
  147. // export default AdminNavigationWrapper;
  148. export default AdminNavigation;