فهرست منبع

Merge pull request #1515 from weseek/reactify-admin/home

reactify admin home page
Yuki Takei 6 سال پیش
والد
کامیت
5b126a466a

+ 5 - 0
src/client/js/app.jsx

@@ -34,6 +34,7 @@ import MyDraftList from './components/MyDraftList/MyDraftList';
 import UserPictureList from './components/User/UserPictureList';
 import TableOfContents from './components/TableOfContents';
 
+import AdminHome from './components/Admin/AdminHome/AdminHome';
 import UserGroupDetailPage from './components/Admin/UserGroupDetail/UserGroupDetailPage';
 import MarkdownSetting from './components/Admin/MarkdownSetting/MarkDownSetting';
 import UserManagement from './components/Admin/UserManagement';
@@ -49,6 +50,7 @@ import PageContainer from './services/PageContainer';
 import CommentContainer from './services/CommentContainer';
 import EditorContainer from './services/EditorContainer';
 import TagContainer from './services/TagContainer';
+import AdminHomeContainer from './services/AdminHomeContainer';
 import AdminCustomizeContainer from './services/AdminCustomizeContainer';
 import UserGroupDetailContainer from './services/UserGroupDetailContainer';
 import AdminUsersContainer from './services/AdminUsersContainer';
@@ -155,11 +157,13 @@ Object.keys(componentMappings).forEach((key) => {
 });
 
 // create unstated container instance for admin
+const adminHomeContainer = new AdminHomeContainer(appContainer);
 const adminCustomizeContainer = new AdminCustomizeContainer(appContainer);
 const adminUsersContainer = new AdminUsersContainer(appContainer);
 const adminExternalAccountsContainer = new AdminExternalAccountsContainer(appContainer);
 const adminMarkDownContainer = new AdminMarkDownContainer(appContainer);
 const adminContainers = {
+  'admin-home': adminHomeContainer,
   'admin-customize': adminCustomizeContainer,
   'admin-user-page': adminUsersContainer,
   'admin-external-account-setting': adminExternalAccountsContainer,
@@ -173,6 +177,7 @@ const adminContainers = {
  *  value: React Element
  */
 const adminComponentMappings = {
+  'admin-home': <AdminHome />,
   'admin-customize': <Customize />,
   'admin-user-page': <UserManagement />,
   'admin-external-account-setting': <ManageExternalAccount />,

+ 68 - 0
src/client/js/components/Admin/AdminHome/AdminHome.jsx

@@ -0,0 +1,68 @@
+import React, { Fragment } from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+import loggerFactory from '@alias/logger';
+
+import { toastError } from '../../../util/apiNotification';
+
+import { createSubscribedElement } from '../../UnstatedUtils';
+import AppContainer from '../../../services/AppContainer';
+import AdminHomeContainer from '../../../services/AdminHomeContainer';
+import SystemInfomationTable from './SystemInfomationTable';
+import InstalledPluginTable from './InstalledPluginTable';
+
+const logger = loggerFactory('growi:admin');
+
+class AdminHome extends React.Component {
+
+  async componentDidMount() {
+    const { adminHomeContainer } = this.props;
+
+    try {
+      await adminHomeContainer.retrieveAdminHomeData();
+    }
+    catch (err) {
+      toastError(err);
+      adminHomeContainer.setState({ retrieveError: err });
+      logger.error(err);
+    }
+  }
+
+  render() {
+    const { t } = this.props;
+
+    return (
+      <Fragment>
+        <p>
+          {t('admin_top.wiki_administrator')}
+          <br></br>
+          {t('admin_top.assign_administrator')}
+        </p>
+
+        <div className="row mb-5">
+          <h2>{t('admin_top.System Information')}</h2>
+          <SystemInfomationTable />
+        </div>
+
+        <div className="row mb-5">
+          <h2>{t('admin_top.List of installed plugins')}</h2>
+          <InstalledPluginTable />
+
+        </div>
+      </Fragment>
+    );
+  }
+
+}
+
+const AdminHomeWrapper = (props) => {
+  return createSubscribedElement(AdminHome, props, [AppContainer, AdminHomeContainer]);
+};
+
+AdminHome.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  adminHomeContainer: PropTypes.instanceOf(AdminHomeContainer).isRequired,
+};
+
+export default withTranslation()(AdminHomeWrapper);

+ 53 - 0
src/client/js/components/Admin/AdminHome/InstalledPluginTable.jsx

@@ -0,0 +1,53 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+import { createSubscribedElement } from '../../UnstatedUtils';
+import AppContainer from '../../../services/AppContainer';
+import AdminHomeContainer from '../../../services/AdminHomeContainer';
+
+class InstalledPluginTable extends React.Component {
+
+  render() {
+    const { t, adminHomeContainer } = this.props;
+
+    return (
+      <table className="table table-bordered">
+        <thead>
+          <tr>
+            <th className="text-center">{ t('admin_top.Package name') }</th>
+            <th className="text-center">{ t('admin_top.Specified version') }</th>
+            <th className="text-center">{ t('admin_top.Installed version') }</th>
+          </tr>
+        </thead>
+        <tbody>
+          { Object.keys(adminHomeContainer.state.installedPlugins).map((pluginName) => {
+            return (
+              <tr key={pluginName}>
+                <td>{ pluginName }</td>
+                <td className="text-center">{ adminHomeContainer.state.installedPlugins[pluginName] }</td>
+                <td className="text-center"><span className="tbd">(TBD)</span></td>
+              </tr>
+            );
+          }) }
+        </tbody>
+      </table>
+    );
+  }
+
+}
+
+InstalledPluginTable.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  adminHomeContainer: PropTypes.instanceOf(AdminHomeContainer).isRequired,
+};
+
+/**
+ * Wrapper component for using unstated
+ */
+const InstalledPluginTableWrapper = (props) => {
+  return createSubscribedElement(InstalledPluginTable, props, [AppContainer, AdminHomeContainer]);
+};
+
+export default withTranslation()(InstalledPluginTableWrapper);

+ 53 - 0
src/client/js/components/Admin/AdminHome/SystemInfomationTable.jsx

@@ -0,0 +1,53 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+import { createSubscribedElement } from '../../UnstatedUtils';
+import AppContainer from '../../../services/AppContainer';
+import AdminHomeContainer from '../../../services/AdminHomeContainer';
+
+class SystemInformationTable extends React.Component {
+
+  render() {
+    const { adminHomeContainer } = this.props;
+
+    return (
+      <table className="table table-bordered">
+        <tbody>
+          <tr>
+            <th className="col-sm-4">GROWI</th>
+            <td>{ adminHomeContainer.state.growiVersion }</td>
+          </tr>
+          <tr>
+            <th>node.js</th>
+            <td>{ adminHomeContainer.state.nodeVersion }</td>
+          </tr>
+          <tr>
+            <th>npm</th>
+            <td>{ adminHomeContainer.state.npmVersion }</td>
+          </tr>
+          <tr>
+            <th>yarn</th>
+            <td>{ adminHomeContainer.state.yarnVersion }</td>
+          </tr>
+        </tbody>
+      </table>
+    );
+  }
+
+}
+
+SystemInformationTable.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  adminHomeContainer: PropTypes.instanceOf(AdminHomeContainer).isRequired,
+};
+
+/**
+ * Wrapper component for using unstated
+ */
+const SystemInformationTableWrapper = (props) => {
+  return createSubscribedElement(SystemInformationTable, props, [AppContainer, AdminHomeContainer]);
+};
+
+export default withTranslation()(SystemInformationTableWrapper);

+ 53 - 0
src/client/js/services/AdminHomeContainer.js

@@ -0,0 +1,53 @@
+import { Container } from 'unstated';
+
+import loggerFactory from '@alias/logger';
+
+import { toastError } from '../util/apiNotification';
+
+// eslint-disable-next-line no-unused-vars
+const logger = loggerFactory('growi:services:AdminHomeContainer');
+
+/**
+ * Service container for admin home page (AdminHome.jsx)
+ * @extends {Container} unstated Container
+ */
+export default class AdminHomeContainer extends Container {
+
+  constructor(appContainer) {
+    super();
+
+    this.appContainer = appContainer;
+
+    this.state = {
+      retrieveError: null,
+      growiVersion: '',
+      nodeVersion: '',
+      npmVersion: '',
+      yarnVersion: '',
+      installedPlugins: {},
+    };
+
+  }
+
+  /**
+   * Workaround for the mangling in production build to break constructor.name
+   */
+  static getClassName() {
+    return 'AdminHomeContainer';
+  }
+
+  /**
+   * retrieve admin home data
+   */
+  async retrieveAdminHomeData() {
+    try {
+      // [TODO GW-727] create api endpoint for retrieve admin home data
+      // const response = await this.appContainer.apiv3.get('/home/');
+    }
+    catch (err) {
+      logger.error(err);
+      toastError(new Error('Failed to fetch data'));
+    }
+  }
+
+}

+ 1 - 1
src/server/routes/apiv3/customize-setting.js

@@ -123,7 +123,7 @@ module.exports = (crowi) => {
    *    /customize-setting/:
    *      get:
    *        tags: [CustomizeSetting]
-   *        description: Get customize paramators
+   *        description: Get customize paramaters
    *        responses:
    *          200:
    *            description: params of customize

+ 2 - 2
src/server/routes/apiv3/markdown-setting.js

@@ -91,8 +91,8 @@ module.exports = (crowi) => {
    *
    *    /markdown-setting/:
    *      get:
-   *        tags: [MarkDownSettind]
-   *        description: Get markdown paramators
+   *        tags: [MarkDownSetting]
+   *        description: Get markdown paramaters
    *        responses:
    *          200:
    *            description: params of markdown

+ 1 - 47
src/server/views/admin/index.html

@@ -25,53 +25,7 @@
       {% include './widget/menu.html' %}
     </div>
     <div class="col-md-9">
-      <p> {{ t("admin_top.wiki_administrator") }}<br>
-      {{ t("admin_top.assign_administrator") }}
-      </p>
-
-      <legend>
-        <h2>{{ t('admin_top.System Information') }}</h2>
-      </legend>
-      <table class="table table-bordered">
-        <tr>
-          <th class="col-sm-4">GROWI</th>
-          <td>{{ growiVersion() }}</td>
-        </tr>
-        <tr>
-          <th>node.js</th>
-          <td>{{ nodeVersion() }}</td>
-        </tr>
-        <tr>
-          <th>npm</th>
-          <td>{{ npmVersion() }}</td>
-        </tr>
-        <tr>
-          <th>yarn</th>
-          <td>{{ yarnVersion() }}</td>
-        </tr>
-      </table>
-
-      <legend>
-        <h2>{{ t('admin_top.List of installed plugins') }}</h2>
-      </legend>
-      <table class="table table-bordered">
-        <th class="text-center">
-          {{ t('admin_top.Package name') }}
-        </th>
-        <th class="text-center">
-          {{ t('admin_top.Specified version') }}
-        </th>
-        <th class="text-center">
-          {{ t('admin_top.Installed version') }}
-        </th>
-        {% for pluginName in Object.keys(plugins) %}
-        <tr>
-          <td>{{ pluginName }}</td>
-          <td class="text-center">{{ plugins[pluginName] }}</td>
-          <td class="text-center"><span class="tbd">(TBD)</span></td>
-        </tr>
-        {% endfor %}
-      </table>
+      <div id="admin-home"></div>
     </div>
   </div>