mizozobu 6 лет назад
Родитель
Сommit
4b9a200fe0

+ 2 - 0
resource/locales/en-US/translation.json

@@ -755,9 +755,11 @@
 
   "export_management": {
     "export_as_zip": "Export Data as Zip",
+    "export_collections": "Export Collections",
     "check_all": "Check All",
     "uncheck_all": "Uncheck All",
     "export": "Export",
+    "cancel": "Cancel",
     "file": "File",
     "growi_version": "Growi Version",
     "collections": "Collections",

+ 2 - 0
resource/locales/ja/translation.json

@@ -738,9 +738,11 @@
 
   "export_management": {
     "export_as_zip": "Zipファイルでエクスポート",
+    "export_collections": "コレクションのエクスポート",
     "check_all": "全てにチェックを付ける",
     "uncheck_all": "全てからチェックを外す",
     "export": "エクスポート",
+    "cancel": "キャンセル",
     "file": "ファイル名",
     "growi_version": "Growi バージョン",
     "collections": "コレクション",

+ 26 - 6
src/client/js/components/Admin/Export/ExportPage.jsx

@@ -2,7 +2,7 @@ import React, { Fragment } from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import ExportZipForm from './ExportZipForm';
+import ExportZipFormModal from './ExportZipFormModal';
 import ZipFileTable from './ZipFileTable';
 import { createSubscribedElement } from '../../UnstatedUtils';
 import AppContainer from '../../../services/AppContainer';
@@ -16,10 +16,13 @@ class ExportPage extends React.Component {
     this.state = {
       collections: [],
       zipFileStats: [],
+      isExportModalOpen: false,
     };
 
     this.onZipFileStatAdd = this.onZipFileStatAdd.bind(this);
     this.onZipFileStatRemove = this.onZipFileStatRemove.bind(this);
+    this.openExportModal = this.openExportModal.bind(this);
+    this.closeExportModal = this.closeExportModal.bind(this);
   }
 
   async componentDidMount() {
@@ -51,21 +54,38 @@ class ExportPage extends React.Component {
     });
   }
 
+  openExportModal() {
+    this.setState({ isExportModalOpen: true });
+  }
+
+  closeExportModal() {
+    this.setState({ isExportModalOpen: false });
+  }
+
   render() {
     const { t } = this.props;
 
     return (
       <Fragment>
         <h2>{t('export_management.export_as_zip')}</h2>
-        <ExportZipForm
+        <div className="row my-5">
+          <div className="col-xs-offset-3 col-xs-6">
+            <button type="submit" className="btn btn-sm btn-primary" onClick={this.openExportModal}>{t('export_management.export')}</button>
+          </div>
+        </div>
+        <ExportZipFormModal
+          isOpen={this.state.isExportModalOpen}
+          onClose={this.closeExportModal}
           collections={this.state.collections}
           zipFileStats={this.state.zipFileStats}
           onZipFileStatAdd={this.onZipFileStatAdd}
         />
-        <ZipFileTable
-          zipFileStats={this.state.zipFileStats}
-          onZipFileStatRemove={this.onZipFileStatRemove}
-        />
+        {this.state.zipFileStats.length > 0 && (
+          <ZipFileTable
+            zipFileStats={this.state.zipFileStats}
+            onZipFileStatRemove={this.onZipFileStatRemove}
+          />
+        )}
       </Fragment>
     );
   }

+ 0 - 125
src/client/js/components/Admin/Export/ExportZipForm.jsx

@@ -1,125 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { withTranslation } from 'react-i18next';
-
-import { createSubscribedElement } from '../../UnstatedUtils';
-import AppContainer from '../../../services/AppContainer';
-// import { toastSuccess, toastError } from '../../../util/apiNotification';
-
-class ExportZipForm extends React.Component {
-
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      collections: new Set(),
-    };
-
-    this.toggleCheckbox = this.toggleCheckbox.bind(this);
-    this.checkAll = this.checkAll.bind(this);
-    this.uncheckAll = this.uncheckAll.bind(this);
-    this.export = this.export.bind(this);
-    this.validateForm = this.validateForm.bind(this);
-  }
-
-  toggleCheckbox(e) {
-    const { target } = e;
-    const { name, checked } = target;
-
-    this.setState((prevState) => {
-      const collections = new Set(prevState.collections);
-      if (checked) {
-        collections.add(name);
-      }
-      else {
-        collections.delete(name);
-      }
-
-      return { collections };
-    });
-  }
-
-  checkAll() {
-    this.setState({ collections: new Set(this.props.collections) });
-  }
-
-  uncheckAll() {
-    this.setState({ collections: new Set() });
-  }
-
-  async export(e) {
-    e.preventDefault();
-
-    // TODO use appContainer.apiv3.post
-    const { zipFileStat } = await this.props.appContainer.apiPost('/v3/export', { collections: Array.from(this.state.collections) });
-    // TODO toastSuccess, toastError
-    this.props.onZipFileStatAdd(zipFileStat);
-  }
-
-  validateForm() {
-    return this.state.collections.size > 0;
-  }
-
-  render() {
-    const { t } = this.props;
-
-    return (
-      <form className="my-5" onSubmit={this.export}>
-        <div className="row">
-          <div className="col-sm-12">
-            <button type="button" className="btn btn-sm btn-default mr-2" onClick={this.checkAll}>
-              <i className="fa fa-check-square-o"></i> {t('export_management.check_all')}
-            </button>
-            <button type="button" className="btn btn-sm btn-default mr-2" onClick={this.uncheckAll}>
-              <i className="fa fa-square-o"></i> {t('export_management.uncheck_all')}
-            </button>
-          </div>
-        </div>
-        <div className="row checkbox checkbox-info my-5">
-          {this.props.collections.map((collectionName) => {
-          return (
-            <div className="col-md-6 my-1" key={collectionName}>
-              <input
-                type="checkbox"
-                id={collectionName}
-                name={collectionName}
-                className="form-check-input"
-                value={collectionName}
-                checked={this.state.collections.has(collectionName)}
-                onChange={this.toggleCheckbox}
-              />
-              <label className="text-capitalize form-check-label ml-3" htmlFor={collectionName}>
-                {collectionName}
-              </label>
-            </div>
-          );
-        })}
-        </div>
-        <div className="row">
-          <div className="col-sm-12 text-center">
-            <button type="submit" className="btn btn-sm btn-primary" disabled={!this.validateForm()}>{t('export_management.export')}</button>
-          </div>
-        </div>
-      </form>
-    );
-  }
-
-}
-
-ExportZipForm.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-
-  collections: PropTypes.arrayOf(PropTypes.string).isRequired,
-  zipFileStats: PropTypes.arrayOf(PropTypes.object).isRequired,
-  onZipFileStatAdd: PropTypes.func.isRequired,
-};
-
-/**
- * Wrapper component for using unstated
- */
-const ExportZipFormWrapper = (props) => {
-  return createSubscribedElement(ExportZipForm, props, [AppContainer]);
-};
-
-export default withTranslation()(ExportZipFormWrapper);

+ 137 - 0
src/client/js/components/Admin/Export/ExportZipFormModal.jsx

@@ -0,0 +1,137 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+import Modal from 'react-bootstrap/es/Modal';
+
+import { createSubscribedElement } from '../../UnstatedUtils';
+import AppContainer from '../../../services/AppContainer';
+// import { toastSuccess, toastError } from '../../../util/apiNotification';
+
+class ExportZipFormModal extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      collections: new Set(),
+    };
+
+    this.toggleCheckbox = this.toggleCheckbox.bind(this);
+    this.checkAll = this.checkAll.bind(this);
+    this.uncheckAll = this.uncheckAll.bind(this);
+    this.export = this.export.bind(this);
+    this.validateForm = this.validateForm.bind(this);
+  }
+
+  toggleCheckbox(e) {
+    const { target } = e;
+    const { name, checked } = target;
+
+    this.setState((prevState) => {
+      const collections = new Set(prevState.collections);
+      if (checked) {
+        collections.add(name);
+      }
+      else {
+        collections.delete(name);
+      }
+
+      return { collections };
+    });
+  }
+
+  checkAll() {
+    this.setState({ collections: new Set(this.props.collections) });
+  }
+
+  uncheckAll() {
+    this.setState({ collections: new Set() });
+  }
+
+  async export(e) {
+    e.preventDefault();
+
+    // TODO use appContainer.apiv3.post
+    const { zipFileStat } = await this.props.appContainer.apiPost('/v3/export', { collections: Array.from(this.state.collections) });
+    // TODO toastSuccess, toastError
+    this.props.onZipFileStatAdd(zipFileStat);
+    this.props.onClose();
+  }
+
+  validateForm() {
+    return this.state.collections.size > 0;
+  }
+
+  render() {
+    const { t } = this.props;
+
+    return (
+      <Modal show={this.props.isOpen} onHide={this.props.onClose}>
+        <Modal.Header closeButton>
+          <Modal.Title>{t('export_management.export_collections')}</Modal.Title>
+        </Modal.Header>
+
+        <form onSubmit={this.export}>
+          <Modal.Body>
+            <div className="row">
+              <div className="col-sm-12">
+                <button type="button" className="btn btn-sm btn-default mr-2" onClick={this.checkAll}>
+                  <i className="fa fa-check-square-o"></i> {t('export_management.check_all')}
+                </button>
+                <button type="button" className="btn btn-sm btn-default mr-2" onClick={this.uncheckAll}>
+                  <i className="fa fa-square-o"></i> {t('export_management.uncheck_all')}
+                </button>
+              </div>
+            </div>
+            <div className="row checkbox checkbox-info">
+              {this.props.collections.map((collectionName) => {
+                return (
+                  <div className="col-md-6 my-1" key={collectionName}>
+                    <input
+                      type="checkbox"
+                      id={collectionName}
+                      name={collectionName}
+                      className="form-check-input"
+                      value={collectionName}
+                      checked={this.state.collections.has(collectionName)}
+                      onChange={this.toggleCheckbox}
+                    />
+                    <label className="text-capitalize form-check-label ml-3" htmlFor={collectionName}>
+                      {collectionName}
+                    </label>
+                  </div>
+                );
+              })}
+            </div>
+          </Modal.Body>
+
+          <Modal.Footer>
+            <button type="button" className="btn btn-sm btn-default" onClick={this.props.onClose}>{t('export_management.cancel')}</button>
+            <button type="submit" className="btn btn-sm btn-primary" disabled={!this.validateForm()}>{t('export_management.export')}</button>
+          </Modal.Footer>
+        </form>
+      </Modal>
+    );
+  }
+
+}
+
+ExportZipFormModal.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+
+  isOpen: PropTypes.bool.isRequired,
+  onClose: PropTypes.func.isRequired,
+  collections: PropTypes.arrayOf(PropTypes.string).isRequired,
+  zipFileStats: PropTypes.arrayOf(PropTypes.object).isRequired,
+  onZipFileStatAdd: PropTypes.func.isRequired,
+};
+
+/**
+ * Wrapper component for using unstated
+ */
+const ExportZipFormModalWrapper = (props) => {
+  return createSubscribedElement(ExportZipFormModal, props, [AppContainer]);
+};
+
+export default withTranslation()(ExportZipFormModalWrapper);

+ 1 - 0
src/client/js/components/Admin/Export/ZipFileTable.jsx

@@ -52,6 +52,7 @@ class ZipFileTable extends React.Component {
 ZipFileTable.propTypes = {
   t: PropTypes.func.isRequired, // i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+
   zipFileStats: PropTypes.arrayOf(PropTypes.object).isRequired,
   onZipFileStatRemove: PropTypes.func.isRequired,
 };