Taichi Masuyama 4 лет назад
Родитель
Сommit
a0e270f380

+ 9 - 0
packages/app/src/client/services/AdminAppContainer.js

@@ -22,6 +22,7 @@ export default class AdminAppContainer extends Container {
       isEmailPublishedForNewUser: true,
       fileUpload: '',
 
+      isPageSchemaV4Compatible: false,
       siteUrl: '',
       envSiteUrl: '',
       isSetSiteUrl: true,
@@ -81,6 +82,7 @@ export default class AdminAppContainer extends Container {
       globalLang: appSettingsParams.globalLang,
       isEmailPublishedForNewUser: appSettingsParams.isEmailPublishedForNewUser,
       fileUpload: appSettingsParams.fileUpload,
+      isPageSchemaV4Compatible: appSettingsParams.isPageSchemaV4Compatible,
       siteUrl: appSettingsParams.siteUrl,
       envSiteUrl: appSettingsParams.envSiteUrl,
       isSetSiteUrl: !!appSettingsParams.siteUrl,
@@ -160,6 +162,13 @@ export default class AdminAppContainer extends Container {
     this.setState({ fileUpload });
   }
 
+  /**
+   * Change site url
+   */
+  changeIsPageSchemaV4Compatible(isPageSchemaV4Compatible) {
+    this.setState({ isPageSchemaV4Compatible });
+  }
+
   /**
    * Change site url
    */

+ 17 - 2
packages/app/src/components/Admin/AdminHome/AdminHome.jsx

@@ -10,6 +10,7 @@ import { toastError } from '~/client/util/apiNotification';
 import { withUnstatedContainers } from '../../UnstatedUtils';
 import AppContainer from '~/client/services/AppContainer';
 import AdminHomeContainer from '~/client/services/AdminHomeContainer';
+import AdminAppContainer from '~/client/services/AdminAppContainer';
 import SystemInfomationTable from './SystemInfomationTable';
 import InstalledPluginTable from './InstalledPluginTable';
 import EnvVarsTable from './EnvVarsTable';
@@ -32,10 +33,23 @@ class AdminHome extends React.Component {
   }
 
   render() {
-    const { t, adminHomeContainer } = this.props;
+    const { t, adminHomeContainer, adminAppContainer } = this.props;
+    const { isPageSchemaV4Compatible } = adminAppContainer.state;
 
     return (
       <Fragment>
+        {
+          !isPageSchemaV4Compatible
+          && (
+            <div className="alert alert-warning">
+              GROWI is running with v4 compatible mode. To use new features such as Page tree or easy renaming, please migrate page schema to v5.<br />
+              <a className="btn-link" href="/admin/app" rel="noopener noreferrer">
+                <i className="fa fa-link ml-1" aria-hidden="true"></i>
+                <strong>Upgrade to v5</strong>
+              </a>
+            </div>
+          )
+        }
         <p>
           {t('admin:admin_top.wiki_administrator')}
           <br></br>
@@ -97,12 +111,13 @@ class AdminHome extends React.Component {
 
 }
 
-const AdminHomeWrapper = withUnstatedContainers(AdminHome, [AppContainer, AdminHomeContainer]);
+const AdminHomeWrapper = withUnstatedContainers(AdminHome, [AppContainer, AdminHomeContainer, AdminAppContainer]);
 
 AdminHome.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   adminHomeContainer: PropTypes.instanceOf(AdminHomeContainer).isRequired,
+  adminAppContainer: PropTypes.instanceOf(AdminAppContainer).isRequired,
 };
 
 export default withTranslation()(AdminHomeWrapper);

+ 25 - 2
packages/app/src/components/Admin/App/AppSettingsPageContents.jsx

@@ -2,19 +2,36 @@ import React, { Fragment } from 'react';
 import { withTranslation } from 'react-i18next';
 import PropTypes from 'prop-types';
 
+import { withUnstatedContainers } from '../../UnstatedUtils';
 import AppSetting from './AppSetting';
 import SiteUrlSetting from './SiteUrlSetting';
 import MailSetting from './MailSetting';
 import PluginSetting from './PluginSetting';
 import FileUploadSetting from './FileUploadSetting';
+import { V4PageMigration } from './V4PageMigration';
+
+import AdminAppContainer from '~/client/services/AdminAppContainer';
 
 class AppSettingsPageContents extends React.Component {
 
   render() {
-    const { t } = this.props;
+    const { t, adminAppContainer } = this.props;
+    const { isPageSchemaV4Compatible } = adminAppContainer.state;
 
     return (
       <Fragment>
+        {
+          !isPageSchemaV4Compatible
+          && (
+            <div className="row">
+              <div className="col-lg-12">
+                <h2 className="admin-setting-header">V4 Page Migration</h2>
+                <V4PageMigration />
+              </div>
+            </div>
+          )
+        }
+
         <div className="row">
           <div className="col-lg-12">
             <h2 className="admin-setting-header">{t('App Settings')}</h2>
@@ -55,8 +72,14 @@ class AppSettingsPageContents extends React.Component {
 
 }
 
+/**
+ * Wrapper component for using unstated
+ */
+const AppSettingsPageContentsWrapper = withUnstatedContainers(AppSettingsPageContents, [AdminAppContainer]);
+
 AppSettingsPageContents.propTypes = {
   t: PropTypes.func.isRequired, // i18next
+  adminAppContainer: PropTypes.instanceOf(AdminAppContainer).isRequired,
 };
 
-export default withTranslation()(AppSettingsPageContents);
+export default withTranslation()(AppSettingsPageContentsWrapper);

+ 33 - 0
packages/app/src/components/Admin/App/V4PageMigration.tsx

@@ -0,0 +1,33 @@
+import React, { FC } from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+
+export const V4PageMigration: FC<any> = (props) => {
+  const { t } = props;
+
+  return (
+    <>
+      <p className="card well">
+        GROWI is running with v4 compatible mode.<br />
+        To use new features such as Page tree or easy renaming, please migrate page schema to v5.<br />
+        <br />
+        <span className="text-danger">
+          <i className="icon-exclamation icon-fw"></i>
+          Note: You will lose unique constraint from page path.
+        </span>
+      </p>
+      <div className="row my-3">
+        <div className="mx-auto">
+          <button type="button" className="btn btn-warning" onClick={() => { /* Show modal, then start migration */ }}>Upgrade to v5</button>
+        </div>
+      </div>
+    </>
+  );
+};
+
+V4PageMigration.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+};
+
+export default withTranslation()(V4PageMigration);

+ 1 - 0
packages/app/src/server/routes/apiv3/app-settings.js

@@ -225,6 +225,7 @@ module.exports = (crowi) => {
       globalLang: crowi.configManager.getConfig('crowi', 'app:globalLang'),
       isEmailPublishedForNewUser: crowi.configManager.getConfig('crowi', 'customize:isEmailPublishedForNewUser'),
       fileUpload: crowi.configManager.getConfig('crowi', 'app:fileUpload'),
+      isPageSchemaV4Compatible: crowi.configManager.getConfig('crowi', 'app:isPageSchemaV4Compatible'),
       siteUrl: crowi.configManager.getConfig('crowi', 'app:siteUrl'),
       envSiteUrl: crowi.configManager.getConfigFromEnvVars('crowi', 'app:siteUrl'),
       isMailerSetup: crowi.mailService.isMailerSetup,

+ 6 - 0
packages/app/src/server/service/config-loader.ts

@@ -172,6 +172,12 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = {
     type:    ValueType.BOOLEAN,
     default: false,
   },
+  IS_PAGE_SCHEMA_V4_COMPATIBLE: {
+    ns:      'crowi',
+    key:     'app:isPageSchemaV4Compatible',
+    type:    ValueType.STRING,
+    default: false,
+  },
   S2SMSG_PUBSUB_SERVER_TYPE: {
     ns:      'crowi',
     key:     's2sMessagingPubsub:serverType',