Taichi Masuyama 4 ani în urmă
părinte
comite
831ae49181

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

@@ -449,5 +449,16 @@ export default class AdminAppContainer extends Container {
     return pluginSettingParams;
   }
 
+  // TODO: define data to interact
+  /**
+   * Start v5 page migration
+   * @memberOf AdminAppContainer
+   * @property action takes either 'notNow' or 'upgrade'. 'upgrade' will start or resume migration
+   */
+  async startV5PageMigrationHandler(/* get action */) {
+    const response = await this.appContainer.apiv3.post('/pages/v5-schema-migration', { /* TODO: pass 'notNow' or 'upgrade' */ });
+    const { ok, status } = response.data;
+    return { ok, status };
+  }
 
 }

+ 2 - 0
packages/app/src/client/services/AdminHomeContainer.js

@@ -32,6 +32,7 @@ export default class AdminHomeContainer extends Container {
       yarnVersion: '',
       copyState: this.copyStateValues.DEFAULT,
       installedPlugins: [],
+      isV5Compatible: null,
     };
 
   }
@@ -63,6 +64,7 @@ export default class AdminHomeContainer extends Container {
         yarnVersion: adminHomeParams.yarnVersion,
         installedPlugins: adminHomeParams.installedPlugins,
         envVars: adminHomeParams.envVars,
+        isV5Compatible: adminHomeParams.isV5Compatible,
       }));
     }
     catch (err) {

+ 3 - 4
packages/app/src/components/Admin/AdminHome/AdminHome.jsx

@@ -33,8 +33,8 @@ class AdminHome extends React.Component {
   }
 
   render() {
-    const { t, adminHomeContainer, adminAppContainer } = this.props;
-    const { isV5Compatible } = adminAppContainer.state;
+    const { t, adminHomeContainer } = this.props;
+    const { isV5Compatible } = adminHomeContainer.state;
 
     let alertStyle = 'alert-info';
     if (isV5Compatible == null) alertStyle = 'alert-warning';
@@ -115,13 +115,12 @@ class AdminHome extends React.Component {
 
 }
 
-const AdminHomeWrapper = withUnstatedContainers(AdminHome, [AppContainer, AdminHomeContainer, AdminAppContainer]);
+const AdminHomeWrapper = withUnstatedContainers(AdminHome, [AppContainer, AdminHomeContainer]);
 
 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);

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

@@ -8,7 +8,7 @@ import SiteUrlSetting from './SiteUrlSetting';
 import MailSetting from './MailSetting';
 import PluginSetting from './PluginSetting';
 import FileUploadSetting from './FileUploadSetting';
-import { V5PageMigration } from './V5PageMigration';
+import V5PageMigration from './V5PageMigration';
 
 import AdminAppContainer from '~/client/services/AdminAppContainer';
 
@@ -26,7 +26,7 @@ class AppSettingsPageContents extends React.Component {
             <div className="row">
               <div className="col-lg-12">
                 <h2 className="admin-setting-header">V5 Page Migration</h2>
-                <V5PageMigration isV5Compatible={isV5Compatible} />
+                <V5PageMigration />
               </div>
             </div>
           )

+ 27 - 8
packages/app/src/components/Admin/App/V5PageMigration.tsx

@@ -1,13 +1,28 @@
-import React, { FC } from 'react';
+import React, { FC, useState } from 'react';
 import PropTypes from 'prop-types';
-import { withTranslation } from 'react-i18next';
+import { useTranslation } from 'react-i18next';
+import { V5PageMigrationModal } from './V5PageMigrationModal';
+import AdminAppContainer from '../../../client/services/AdminAppContainer';
+import { withUnstatedContainers } from '../../UnstatedUtils';
 
 
-export const V5PageMigration: FC<any> = (props) => {
-  const { t, isV5Compatible } = props;
+const V5PageMigration: FC<any> = (props) => {
+  const [isV5PageMigrationModalShown, setIsV5PageMigrationModalShown] = useState(false);
+  const { adminAppContainer } = props;
+  const { isV5Compatible } = adminAppContainer.state;
+  const { t } = useTranslation();
+
+  const onConfirm = async() => {
+    await adminAppContainer.startV5PageMigrationHandler();
+  };
 
   return (
     <>
+      <V5PageMigrationModal
+        isModalOpen={isV5PageMigrationModalShown}
+        onConfirm={onConfirm}
+        onCancel={() => setIsV5PageMigrationModalShown(false)}
+      />
       <p className="card well">
         GROWI is running with v4 compatible pages.<br />
         To use new features such as Page tree or easy renaming, please migrate page schema to v5.<br />
@@ -21,16 +36,20 @@ export const V5PageMigration: FC<any> = (props) => {
         <div className="mx-auto">
           {
             isV5Compatible == null
-            && (<button type="button" className="btn btn-secondary mr-3" onClick={() => { /* Set false */ }}>Not now</button>)
+            && (<button type="button" className="btn btn-secondary mr-3" onClick={() => { /* TODO: POST to set false 80202 */ }}>Not now</button>)
           }
-          <button type="button" className="btn btn-warning" onClick={() => { /* Show modal, then start migration */ }}>Upgrade to v5</button>
+          <button type="button" className="btn btn-warning" onClick={() => setIsV5PageMigrationModalShown(true)}>Upgrade to v5</button>
         </div>
       </div>
     </>
   );
 };
 
+/**
+ * Wrapper component for using unstated
+ */
+export default withUnstatedContainers(V5PageMigration, [AdminAppContainer]);
+
 V5PageMigration.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  isV5Compatible: PropTypes.bool,
+  adminAppContainer: PropTypes.instanceOf(AdminAppContainer).isRequired,
 };

+ 57 - 0
packages/app/src/components/Admin/App/V5PageMigrationModal.tsx

@@ -0,0 +1,57 @@
+import React, { FC, useCallback } from 'react';
+import PropTypes from 'prop-types';
+import {
+  Modal, ModalHeader, ModalBody, ModalFooter,
+} from 'reactstrap';
+import { useTranslation } from 'react-i18next';
+
+type V5PageMigrationModalProps = {
+  isModalOpen: boolean
+  onConfirm: () => Promise<any>;
+  onCancel: () => void;
+};
+
+export const V5PageMigrationModal: FC<V5PageMigrationModalProps> = (props) => {
+  const { t } = useTranslation();
+
+  const onCancel = () => {
+    props.onCancel();
+  };
+
+  return (
+    <Modal isOpen={props.isModalOpen} toggle={onCancel} className="">
+      <ModalHeader tag="h4" toggle={onCancel} className="bg-warning">
+        <i className="icon-fw icon-question" />
+        Warning
+      </ModalHeader>
+      <ModalBody>
+        TODO: tell user
+        that this process may take long,
+        that the admin user is responsible for telling users not to do important interaction until it ends,
+        and that Page schema will no longer have a unique constraint in page path.
+      </ModalBody>
+      <ModalFooter>
+        <button
+          type="button"
+          className="btn btn-outline-secondary"
+          onClick={onCancel}
+        >
+          {t('Cancel')}
+        </button>
+        <button
+          type="button"
+          className="btn btn-outline-primary ml-3"
+          onClick={props.onConfirm}
+        >
+          Start Upgrading
+        </button>
+      </ModalFooter>
+    </Modal>
+  );
+};
+
+V5PageMigrationModal.propTypes = {
+  isModalOpen: PropTypes.bool.isRequired,
+  onConfirm: PropTypes.func.isRequired,
+  onCancel: PropTypes.func.isRequired,
+};

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

@@ -73,6 +73,7 @@ module.exports = (crowi) => {
       yarnVersion: crowi.runtimeVersions.versions.yarn ? crowi.runtimeVersions.versions.yarn.version.version : '-',
       installedPlugins: pluginUtils.listPlugins(crowi.rootDir),
       envVars: await ConfigLoader.getEnvVarsForDisplay(true),
+      isV5Compatible: crowi.configManager.getConfig('crowi', 'app:isV5Compatible'),
     };
 
     return res.apiv3({ adminHomeParams });

+ 2 - 1
packages/app/src/server/routes/apiv3/pages.js

@@ -681,8 +681,9 @@ module.exports = (crowi) => {
 
   });
 
+  // TODO: handle 'notNow' and 'upgrade' to either set config to false or start/resume migration 80202
   // TODO: use socket conn to show progress
-  router.get('/v5-schema-migration', /* accessTokenParser, loginRequired, adminRequired, csrf, */ async(req, res) => {
+  router.post('/v5-schema-migration', /* accessTokenParser, loginRequired, adminRequired, csrf, */ async(req, res) => {
     try {
       const Page = crowi.model('Page');
       // TODO: not await but should be dealed as a job