Преглед изворни кода

Merge pull request #6230 from weseek/imprv/99687-show-admin-navigation

imprv/ show admin navigation
cao пре 3 година
родитељ
комит
312b7dab76

+ 12 - 11
packages/app/src/components/Admin/Common/AdminNavigation.jsx

@@ -5,22 +5,22 @@
 import React from 'react';
 import React from 'react';
 
 
 import { pathUtils } from '@growi/core';
 import { pathUtils } from '@growi/core';
-import PropTypes from 'prop-types';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
+import PropTypes from 'prop-types';
 import urljoin from 'url-join';
 import urljoin from 'url-join';
 
 
 
 
-import AppContainer from '~/client/services/AppContainer';
+// import AppContainer from '~/client/services/AppContainer';
 
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
+// import { withUnstatedContainers } from '../../UnstatedUtils';
 
 
 const AdminNavigation = (props) => {
 const AdminNavigation = (props) => {
   const { t } = useTranslation();
   const { t } = useTranslation();
-  const { appContainer } = props;
+  // const { appContainer } = props;
   const pathname = window.location.pathname;
   const pathname = window.location.pathname;
 
 
-  const growiCloudUri = appContainer.config.env.GROWI_CLOUD_URI;
-  const growiAppIdForGrowiCloud = appContainer.config.env.GROWI_APP_ID_FOR_GROWI_CLOUD;
+  // const growiCloudUri = appContainer.config.env.GROWI_CLOUD_URI;
+  // const growiAppIdForGrowiCloud = appContainer.config.env.GROWI_APP_ID_FOR_GROWI_CLOUD;
 
 
   // eslint-disable-next-line react/prop-types
   // eslint-disable-next-line react/prop-types
   const MenuLabel = ({ menu }) => {
   const MenuLabel = ({ menu }) => {
@@ -89,7 +89,7 @@ const AdminNavigation = (props) => {
         <MenuLink menu="user-groups"  isListGroupItems isActive={isActiveMenu('/user-groups')} />
         <MenuLink menu="user-groups"  isListGroupItems isActive={isActiveMenu('/user-groups')} />
         <MenuLink menu="search"       isListGroupItems isActive={isActiveMenu('/search')} />
         <MenuLink menu="search"       isListGroupItems isActive={isActiveMenu('/search')} />
         <MenuLink menu="audit-log"    isListGroupItems isActive={isActiveMenu('/audit-log')} />
         <MenuLink menu="audit-log"    isListGroupItems isActive={isActiveMenu('/audit-log')} />
-        {growiCloudUri != null && growiAppIdForGrowiCloud != null
+        {/* {growiCloudUri != null && growiAppIdForGrowiCloud != null
           && (
           && (
             <a
             <a
               href={`${growiCloudUri}/my/apps/${growiAppIdForGrowiCloud}`}
               href={`${growiCloudUri}/my/apps/${growiAppIdForGrowiCloud}`}
@@ -98,7 +98,7 @@ const AdminNavigation = (props) => {
               <MenuLabel menu="cloud" />
               <MenuLabel menu="cloud" />
             </a>
             </a>
           )
           )
-        }
+        } */}
       </>
       </>
     );
     );
   };
   };
@@ -146,10 +146,11 @@ const AdminNavigation = (props) => {
   );
   );
 };
 };
 
 
-const AdminNavigationWrapper = withUnstatedContainers(AdminNavigation, [AppContainer]);
+// const AdminNavigationWrapper = withUnstatedContainers(AdminNavigation, [AppContainer]);
 
 
 AdminNavigation.propTypes = {
 AdminNavigation.propTypes = {
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  // appContainer: PropTypes.instanceOf(AppContainer).isRequired,
 };
 };
 
 
-export default AdminNavigationWrapper;
+// export default AdminNavigationWrapper;
+export default AdminNavigation;

+ 55 - 0
packages/app/src/components/AdminLayout.tsx

@@ -0,0 +1,55 @@
+import React, { ReactNode } from 'react';
+
+import dynamic from 'next/dynamic';
+import { Provider } from 'unstated';
+
+import { GrowiNavbar } from './Navbar/GrowiNavbar';
+import { RawLayout } from './RawLayout';
+
+// import { injectableContainers } from '~/client/admin';
+
+type Props = {
+  title: string
+  /**
+   * Set the current option of AdminNavigation
+   * Expected it is in ["home", "app", "security", "markdown", "customize", "importer", "export",
+   * "notification", 'global-notification', "users", "user-groups", "search"]
+   */
+  selectedNavOpt: string
+  children?: ReactNode
+}
+
+
+const AdminLayout = ({
+  children, title, selectedNavOpt,
+}: Props): JSX.Element => {
+
+  const AdminNavigation = dynamic(() => import('~/components/Admin/Common/AdminNavigation'), { ssr: false });
+
+  return (
+    <RawLayout title={title}>
+      <GrowiNavbar />
+
+      <header className="py-0">
+        <h1 className="title">{title}</h1>
+      </header>
+      <div id="main" className="main">
+        <div className="container-fluid">
+          <div className="row">
+            <div className="col-lg-3">
+              <AdminNavigation selected={selectedNavOpt} />
+            </div>
+            <div className="col-lg-9">
+              {/* TODO: inject Admincontainer (injectableContainers & adminSecurityContainers) by https://redmine.weseek.co.jp/issues/100072 */}
+              <Provider>
+                {children}
+              </Provider>
+            </div>
+          </div>
+        </div>
+      </div>
+    </RawLayout>
+  );
+};
+
+export default AdminLayout;

+ 177 - 0
packages/app/src/pages/admin/[[...path]].page.tsx

@@ -0,0 +1,177 @@
+import {
+  NextPage, GetServerSideProps, GetServerSidePropsContext,
+} from 'next';
+import { useTranslation } from 'next-i18next';
+import dynamic from 'next/dynamic';
+import { useRouter } from 'next/router';
+
+import UserGroupPage from '~/components/Admin/UserGroup/UserGroupPage';
+import UserManagement from '~/components/Admin/UserManagement';
+import AdminLayout from '~/components/AdminLayout';
+import { CrowiRequest } from '~/interfaces/crowi-request';
+import { CommonProps, getServerSideCommonProps, useCustomTitle } from '~/pages/commons';
+import PluginUtils from '~/server/plugins/plugin-utils';
+import ConfigLoader from '~/server/service/config-loader';
+
+// import AdminHome from '~/components/Admin/AdminHome/AdminHome';
+// import AppSettingsPageContents from '~/components/Admin/App/AppSettingsPageContents';
+// import SecurityManagementContents from '~/components/Admin/Security/SecurityManagementContents';
+// import MarkDownSettingContents from '~/components/Admin/MarkdownSetting/MarkDownSettingContents';
+// import DataImportPageContents from '~/components/Admin/ImportData/ImportDataPageContents';
+// import ExportArchiveDataPage from '~/components/Admin/ExportArchiveDataPage';
+// import ElasticsearchManagement from '~/components/Admin/ElasticsearchManagement/ElasticsearchManagement';
+import {
+  useCurrentUser,
+  /* useSearchServiceConfigured, useSearchServiceReachable, */ useSiteUrl,
+} from '~/stores/context';
+// import { useEnvVars } from '~/stores/admin-context';
+
+const pluginUtils = new PluginUtils();
+
+type Props = CommonProps & {
+  currentUser: any,
+
+  nodeVersion: string,
+  npmVersion: string,
+  yarnVersion: string,
+  installedPlugins: any,
+  envVars: any,
+
+  isSearchServiceConfigured: boolean,
+  isSearchServiceReachable: boolean,
+
+  siteUrl: string,
+
+};
+
+const AdminMarkdownSettingsPage: NextPage<Props> = (props: Props) => {
+
+  const { t } = useTranslation();
+  const router = useRouter();
+  const path = router.query.path || 'home';
+  const name = Array.isArray(path) ? path[0] : path;
+
+  // const CustomizeSettingContents = dynamic(() => import('../../components/Admin/Customize/Customize'), { ssr: false });
+
+  const adminPagesMap = {
+    home: {
+      title: useCustomTitle(props, t('Wiki Management Home Page')),
+      // component: <AdminHome
+      //   nodeVersion={props.nodeVersion}
+      //   npmVersion={props.npmVersion}
+      //   yarnVersion={props.yarnVersion}
+      //   installedPlugins={props.installedPlugins}
+      // />,
+      component: <>AdminHome</>,
+    },
+    app: {
+      title: useCustomTitle(props, t('App Settings')),
+      // component: <AppSettingsPageContents />,
+      component: <>AppSettingsPageContents</>,
+    },
+    security: {
+      title: useCustomTitle(props, t('security_settings')),
+      // component: <SecurityManagementContents />,
+      component: <>SecurityManagementContents</>,
+    },
+    markdown: {
+      title: useCustomTitle(props, t('Markdown Settings')),
+      // component: <MarkDownSettingContents />,
+      component: <>MarkDownSettingContents</>,
+    },
+    customize: {
+      title: useCustomTitle(props, t('Customize Settings')),
+      // component: <CustomizeSettingContents />,
+      component: <>CustomizeSettingContents</>,
+    },
+    importer: {
+      title: useCustomTitle(props, t('Import Data')),
+      // component: <DataImportPageContents />,
+      component: <>DataImportPageContents</>,
+    },
+    export: {
+      title: useCustomTitle(props, t('Export Archive Data')),
+      // component: <ExportArchiveDataPage />,
+      component: <>ExportArchiveDataPage</>,
+    },
+    notification: {
+      title: useCustomTitle(props, t('Notification Settings')),
+      component: <>notification</>,
+    },
+    'global-notification': {
+      title: '',
+      component: <>global-notification</>,
+    },
+    users: {
+      title: useCustomTitle(props, t('User_Management')),
+      // component: <UserManagement />,
+      component: <>UserManagement</>,
+    },
+    'user-groups': {
+      title: useCustomTitle(props, t('UserGroup Management')),
+      component: <>user-groups</>,
+    },
+    search: {
+      title: useCustomTitle(props, t('Full Text Search Management')),
+      // component: <ElasticsearchManagement />,
+      component: <>ElasticsearchManagement</>,
+    },
+  };
+
+  const content = adminPagesMap[name];
+  const title = content.title;
+
+  useCurrentUser(props.currentUser != null ? JSON.parse(props.currentUser) : null);
+
+  // useSearchServiceConfigured(props.isSearchServiceConfigured);
+  // useSearchServiceReachable(props.isSearchServiceReachable);
+
+  useSiteUrl(props.siteUrl);
+
+  // useEnvVars(props.envVars);
+
+  return (
+    <AdminLayout title={title} selectedNavOpt={name}>
+      {content.component}
+    </AdminLayout>
+  );
+};
+
+export const getServerSideProps: GetServerSideProps = async(context: GetServerSidePropsContext) => {
+  const req: CrowiRequest = context.req as CrowiRequest;
+  const { crowi } = req;
+  const {
+    appService, searchService,
+  } = crowi;
+
+  const { user } = req;
+
+  const result = await getServerSideCommonProps(context);
+
+  // check for presence
+  // see: https://github.com/vercel/next.js/issues/19271#issuecomment-730006862
+  if (!('props' in result)) {
+    throw new Error('invalid getSSP result');
+  }
+  const props: Props = result.props as Props;
+  if (user != null) {
+    // props.currentUser = JSON.stringify(user.toObject());
+    props.currentUser = JSON.stringify(user);
+  }
+
+  props.siteUrl = appService.getSiteUrl();
+  props.nodeVersion = crowi.runtimeVersions.versions.node ? crowi.runtimeVersions.versions.node.version.version : null;
+  props.npmVersion = crowi.runtimeVersions.versions.npm ? crowi.runtimeVersions.versions.npm.version.version : null;
+  props.yarnVersion = crowi.runtimeVersions.versions.yarn ? crowi.runtimeVersions.versions.yarn.version.version : null;
+  props.installedPlugins = pluginUtils.listPlugins();
+  props.envVars = await ConfigLoader.getEnvVarsForDisplay(true);
+
+  props.isSearchServiceConfigured = searchService.isConfigured;
+  props.isSearchServiceReachable = searchService.isReachable;
+
+  return {
+    props,
+  };
+};
+
+export default AdminMarkdownSettingsPage;

+ 22 - 21
packages/app/src/server/routes/index.js

@@ -87,8 +87,9 @@ module.exports = function(crowi, app) {
   app.post('/register'                , applicationInstalled, registerFormValidator.registerRules(), registerFormValidator.registerValidation, csrfProtection, addActivity, login.register);
   app.post('/register'                , applicationInstalled, registerFormValidator.registerRules(), registerFormValidator.registerValidation, csrfProtection, addActivity, login.register);
   app.get('/register'                 , applicationInstalled, login.preLogin, login.register);
   app.get('/register'                 , applicationInstalled, login.preLogin, login.register);
 
 
-  app.get('/admin'                    , applicationInstalled, loginRequiredStrictly , adminRequired , admin.index);
-  app.get('/admin/app'                , applicationInstalled, loginRequiredStrictly , adminRequired , admin.app.index);
+  app.get('/admin/*'                    , applicationInstalled, loginRequiredStrictly , adminRequired , next.delegateToNext);
+  // app.get('/admin'                    , applicationInstalled, loginRequiredStrictly , adminRequired , admin.index);
+  // app.get('/admin/app'                , applicationInstalled, loginRequiredStrictly , adminRequired , admin.app.index);
 
 
   // installer
   // installer
   if (!isInstalled) {
   if (!isInstalled) {
@@ -114,39 +115,39 @@ module.exports = function(crowi, app) {
   app.post('/_api/login/testLdap'    , loginRequiredStrictly , loginFormValidator.loginRules() , loginFormValidator.loginValidation , loginPassport.testLdapCredentials);
   app.post('/_api/login/testLdap'    , loginRequiredStrictly , loginFormValidator.loginRules() , loginFormValidator.loginValidation , loginPassport.testLdapCredentials);
 
 
   // security admin
   // security admin
-  app.get('/admin/security'          , loginRequiredStrictly , adminRequired , admin.security.index);
+  // app.get('/admin/security'          , loginRequiredStrictly , adminRequired , admin.security.index);
 
 
   // markdown admin
   // markdown admin
-  app.get('/admin/markdown'          , loginRequiredStrictly , adminRequired , admin.markdown.index);
+  // app.get('/admin/markdown'          , loginRequiredStrictly , adminRequired , admin.markdown.index);
 
 
   // customize admin
   // customize admin
-  app.get('/admin/customize'         , loginRequiredStrictly , adminRequired , admin.customize.index);
+  // app.get('/admin/customize'         , loginRequiredStrictly , adminRequired , admin.customize.index);
 
 
   // search admin
   // search admin
-  app.get('/admin/search'            , loginRequiredStrictly , adminRequired , admin.search.index);
+  // app.get('/admin/search'            , loginRequiredStrictly , adminRequired , admin.search.index);
 
 
   // notification admin
   // notification admin
-  app.get('/admin/notification'                         , loginRequiredStrictly , adminRequired , admin.notification.index);
-  app.get('/admin/notification/slackAuth'               , loginRequiredStrictly , adminRequired , admin.notification.slackAuth);
-  app.get('/admin/notification/slackSetting/disconnect' , loginRequiredStrictly , adminRequired , admin.notification.disconnectFromSlack);
-  app.get('/admin/global-notification/new'              , loginRequiredStrictly , adminRequired , admin.globalNotification.detail);
-  app.get('/admin/global-notification/:id'              , loginRequiredStrictly , adminRequired , admin.globalNotification.detail);
-  app.get('/admin/slack-integration-legacy'             , loginRequiredStrictly , adminRequired,  admin.slackIntegrationLegacy);
-  app.get('/admin/slack-integration'                    , loginRequiredStrictly , adminRequired,  admin.slackIntegration);
+  // app.get('/admin/notification'                         , loginRequiredStrictly , adminRequired , admin.notification.index);
+  // app.get('/admin/notification/slackAuth'               , loginRequiredStrictly , adminRequired , admin.notification.slackAuth);
+  // app.get('/admin/notification/slackSetting/disconnect' , loginRequiredStrictly , adminRequired , admin.notification.disconnectFromSlack);
+  // app.get('/admin/global-notification/new'              , loginRequiredStrictly , adminRequired , admin.globalNotification.detail);
+  // app.get('/admin/global-notification/:id'              , loginRequiredStrictly , adminRequired , admin.globalNotification.detail);
+  // app.get('/admin/slack-integration-legacy'             , loginRequiredStrictly , adminRequired,  admin.slackIntegrationLegacy);
+  // app.get('/admin/slack-integration'                    , loginRequiredStrictly , adminRequired,  admin.slackIntegration);
 
 
-  app.get('/admin/users'                                , loginRequiredStrictly , adminRequired , admin.user.index);
+  // app.get('/admin/users'                                , loginRequiredStrictly , adminRequired , admin.user.index);
 
 
-  app.get('/admin/users/external-accounts'              , loginRequiredStrictly , adminRequired , admin.externalAccount.index);
+  // app.get('/admin/users/external-accounts'              , loginRequiredStrictly , adminRequired , admin.externalAccount.index);
 
 
   // user-groups admin
   // user-groups admin
-  app.get('/admin/user-groups'                          , loginRequiredStrictly, adminRequired, admin.userGroup.index);
-  app.get('/admin/user-group-detail/:id'                , loginRequiredStrictly, adminRequired, admin.userGroup.detail);
+  // app.get('/admin/user-groups'                          , loginRequiredStrictly, adminRequired, admin.userGroup.index);
+  // app.get('/admin/user-group-detail/:id'                , loginRequiredStrictly, adminRequired, admin.userGroup.detail);
 
 
   // auditLog admin
   // auditLog admin
   app.get('/admin/audit-log'                            , loginRequiredStrictly, adminRequired, admin.auditLog.index);
   app.get('/admin/audit-log'                            , loginRequiredStrictly, adminRequired, admin.auditLog.index);
 
 
   // importer management for admin
   // importer management for admin
-  app.get('/admin/importer'                     , loginRequiredStrictly , adminRequired , admin.importer.index);
+  // app.get('/admin/importer'                     , loginRequiredStrictly , adminRequired , admin.importer.index);
   app.post('/_api/admin/settings/importerEsa'   , loginRequiredStrictly , adminRequired , csrfProtection, addActivity, admin.importer.api.validators.importer.esa(),admin.api.importerSettingEsa);
   app.post('/_api/admin/settings/importerEsa'   , loginRequiredStrictly , adminRequired , csrfProtection, addActivity, admin.importer.api.validators.importer.esa(),admin.api.importerSettingEsa);
   app.post('/_api/admin/settings/importerQiita' , loginRequiredStrictly , adminRequired , csrfProtection, addActivity, admin.importer.api.validators.importer.qiita(), admin.api.importerSettingQiita);
   app.post('/_api/admin/settings/importerQiita' , loginRequiredStrictly , adminRequired , csrfProtection, addActivity, admin.importer.api.validators.importer.qiita(), admin.api.importerSettingQiita);
   app.post('/_api/admin/import/esa'             , loginRequiredStrictly , adminRequired , csrfProtection, addActivity, admin.api.importDataFromEsa);
   app.post('/_api/admin/import/esa'             , loginRequiredStrictly , adminRequired , csrfProtection, addActivity, admin.api.importDataFromEsa);
@@ -155,10 +156,10 @@ module.exports = function(crowi, app) {
   app.post('/_api/admin/import/testQiitaAPI'    , loginRequiredStrictly , adminRequired , csrfProtection, addActivity, admin.api.testQiitaAPI);
   app.post('/_api/admin/import/testQiitaAPI'    , loginRequiredStrictly , adminRequired , csrfProtection, addActivity, admin.api.testQiitaAPI);
 
 
   // export management for admin
   // export management for admin
-  app.get('/admin/export'                       , loginRequiredStrictly , adminRequired ,admin.export.index);
-  app.get('/admin/export/:fileName'             , loginRequiredStrictly , adminRequired ,admin.export.api.validators.export.download(), admin.export.download);
+  // app.get('/admin/export'                       , loginRequiredStrictly , adminRequired ,admin.export.index);
+  // app.get('/admin/export/:fileName'             , loginRequiredStrictly , adminRequired ,admin.export.api.validators.export.download(), admin.export.download);
 
 
-  app.get('/admin/*'                            , loginRequiredStrictly ,adminRequired, admin.notFound.index);
+  // app.get('/admin/*'                            , loginRequiredStrictly ,adminRequired, admin.notFound.index);
 
 
   /*
   /*
    * Routes below are unavailable when maintenance mode
    * Routes below are unavailable when maintenance mode