|
|
@@ -1,11 +1,21 @@
|
|
|
import React from 'react';
|
|
|
import PropTypes from 'prop-types';
|
|
|
import { withTranslation } from 'react-i18next';
|
|
|
-import * as toastr from 'toastr';
|
|
|
+
|
|
|
+import GrowiArchiveImportOption from '@commons/models/admin/growi-archive-import-option';
|
|
|
+import ImportOptionForPages from '@commons/models/admin/import-option-for-pages';
|
|
|
+import ImportOptionForRevisions from '@commons/models/admin/import-option-for-revisions';
|
|
|
|
|
|
import { createSubscribedElement } from '../../UnstatedUtils';
|
|
|
import AppContainer from '../../../services/AppContainer';
|
|
|
-// import { toastSuccess, toastError } from '../../../util/apiNotification';
|
|
|
+import WebsocketContainer from '../../../services/WebsocketContainer';
|
|
|
+import { toastSuccess, toastError } from '../../../util/apiNotification';
|
|
|
+
|
|
|
+
|
|
|
+import GrowiZipImportItem, { DEFAULT_MODE, MODE_RESTRICTED_COLLECTION } from './GrowiZipImportItem';
|
|
|
+import GrowiZipImportConfigurationModal from './GrowiZipImportConfigurationModal';
|
|
|
+import ErrorViewer from './ErrorViewer';
|
|
|
+
|
|
|
|
|
|
const GROUPS_PAGE = [
|
|
|
'pages', 'revisions', 'tags', 'pagetagrelations',
|
|
|
@@ -18,6 +28,10 @@ const GROUPS_CONFIG = [
|
|
|
];
|
|
|
const ALL_GROUPED_COLLECTIONS = GROUPS_PAGE.concat(GROUPS_USER).concat(GROUPS_CONFIG);
|
|
|
|
|
|
+const IMPORT_OPTION_CLASS_MAPPING = {
|
|
|
+ pages: ImportOptionForPages,
|
|
|
+ revisions: ImportOptionForRevisions,
|
|
|
+};
|
|
|
|
|
|
class GrowiImportForm extends React.Component {
|
|
|
|
|
|
@@ -25,24 +39,42 @@ class GrowiImportForm extends React.Component {
|
|
|
super(props);
|
|
|
|
|
|
this.initialState = {
|
|
|
- collectionNameToFileNameMap: {},
|
|
|
+ isImporting: false,
|
|
|
+ isImported: false,
|
|
|
+ progressMap: [],
|
|
|
+ errorsMap: [],
|
|
|
+
|
|
|
selectedCollections: new Set(),
|
|
|
- schema: {
|
|
|
- pages: {},
|
|
|
- revisions: {},
|
|
|
- // ...
|
|
|
- },
|
|
|
+
|
|
|
+ // store relations from collection name to file name
|
|
|
+ collectionNameToFileNameMap: {},
|
|
|
+ // store relations from collection name to GrowiArchiveImportOption instance
|
|
|
+ optionsMap: {},
|
|
|
+
|
|
|
+ isConfigurationModalOpen: false,
|
|
|
+ collectionNameForConfiguration: null,
|
|
|
+
|
|
|
+ isErrorsViewerOpen: false,
|
|
|
+ collectionNameForErrorsViewer: null,
|
|
|
|
|
|
canImport: false,
|
|
|
- errorsForPageGroups: [],
|
|
|
- errorsForUserGroups: [],
|
|
|
- errorsForConfigGroups: [],
|
|
|
- errorsForOtherGroups: [],
|
|
|
+ warnForPageGroups: [],
|
|
|
+ warnForUserGroups: [],
|
|
|
+ warnForConfigGroups: [],
|
|
|
+ warnForOtherGroups: [],
|
|
|
};
|
|
|
|
|
|
- this.props.fileStats.forEach((fileStat) => {
|
|
|
+ this.props.innerFileStats.forEach((fileStat) => {
|
|
|
const { fileName, collectionName } = fileStat;
|
|
|
this.initialState.collectionNameToFileNameMap[collectionName] = fileName;
|
|
|
+
|
|
|
+ // determine initial mode
|
|
|
+ const initialMode = (MODE_RESTRICTED_COLLECTION[collectionName] != null)
|
|
|
+ ? MODE_RESTRICTED_COLLECTION[collectionName][0]
|
|
|
+ : DEFAULT_MODE;
|
|
|
+ // create GrowiArchiveImportOption instance
|
|
|
+ const ImportOption = IMPORT_OPTION_CLASS_MAPPING[collectionName] || GrowiArchiveImportOption;
|
|
|
+ this.initialState.optionsMap[collectionName] = new ImportOption(initialMode);
|
|
|
});
|
|
|
|
|
|
this.state = this.initialState;
|
|
|
@@ -50,6 +82,9 @@ class GrowiImportForm extends React.Component {
|
|
|
this.toggleCheckbox = this.toggleCheckbox.bind(this);
|
|
|
this.checkAll = this.checkAll.bind(this);
|
|
|
this.uncheckAll = this.uncheckAll.bind(this);
|
|
|
+ this.updateOption = this.updateOption.bind(this);
|
|
|
+ this.openConfigurationModal = this.openConfigurationModal.bind(this);
|
|
|
+ this.showErrorsViewer = this.showErrorsViewer.bind(this);
|
|
|
this.validate = this.validate.bind(this);
|
|
|
this.import = this.import.bind(this);
|
|
|
}
|
|
|
@@ -58,20 +93,71 @@ class GrowiImportForm extends React.Component {
|
|
|
return Object.keys(this.state.collectionNameToFileNameMap);
|
|
|
}
|
|
|
|
|
|
- async toggleCheckbox(e) {
|
|
|
- const { target } = e;
|
|
|
- const { name, checked } = target;
|
|
|
+ componentWillMount() {
|
|
|
+ this.setupWebsocketEventHandler();
|
|
|
+ }
|
|
|
|
|
|
- await this.setState((prevState) => {
|
|
|
- const selectedCollections = new Set(prevState.selectedCollections);
|
|
|
- if (checked) {
|
|
|
- selectedCollections.add(name);
|
|
|
- }
|
|
|
- else {
|
|
|
- selectedCollections.delete(name);
|
|
|
- }
|
|
|
- return { selectedCollections };
|
|
|
+ componentWillUnmount() {
|
|
|
+ this.teardownWebsocketEventHandler();
|
|
|
+ }
|
|
|
+
|
|
|
+ setupWebsocketEventHandler() {
|
|
|
+ const socket = this.props.websocketContainer.getWebSocket();
|
|
|
+
|
|
|
+ // websocket event
|
|
|
+ // eslint-disable-next-line object-curly-newline
|
|
|
+ socket.on('admin:onProgressForImport', ({ collectionName, collectionProgress, appendedErrors }) => {
|
|
|
+ const { progressMap, errorsMap } = this.state;
|
|
|
+ progressMap[collectionName] = collectionProgress;
|
|
|
+
|
|
|
+ const errors = errorsMap[collectionName] || [];
|
|
|
+ errorsMap[collectionName] = errors.concat(appendedErrors);
|
|
|
+
|
|
|
+ this.setState({
|
|
|
+ isImporting: true,
|
|
|
+ progressMap,
|
|
|
+ errorsMap,
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // websocket event
|
|
|
+ socket.on('admin:onTerminateForImport', () => {
|
|
|
+ this.setState({
|
|
|
+ isImporting: false,
|
|
|
+ isImported: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ toastSuccess(undefined, 'Import process has terminated.');
|
|
|
+ });
|
|
|
+
|
|
|
+ // websocket event
|
|
|
+ socket.on('admin:onErrorForImport', (err) => {
|
|
|
+ this.setState({
|
|
|
+ isImporting: false,
|
|
|
+ isImported: false,
|
|
|
+ });
|
|
|
+
|
|
|
+ toastError(err, 'Import process has failed.');
|
|
|
});
|
|
|
+ }
|
|
|
+
|
|
|
+ teardownWebsocketEventHandler() {
|
|
|
+ const socket = this.props.websocketContainer.getWebSocket();
|
|
|
+
|
|
|
+ socket.removeAllListeners('admin:onProgressForImport');
|
|
|
+ socket.removeAllListeners('admin:onTerminateForImport');
|
|
|
+ }
|
|
|
+
|
|
|
+ async toggleCheckbox(collectionName, bool) {
|
|
|
+ const selectedCollections = new Set(this.state.selectedCollections);
|
|
|
+ if (bool) {
|
|
|
+ selectedCollections.add(collectionName);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ selectedCollections.delete(collectionName);
|
|
|
+ }
|
|
|
+
|
|
|
+ await this.setState({ selectedCollections });
|
|
|
|
|
|
this.validate();
|
|
|
}
|
|
|
@@ -86,13 +172,32 @@ class GrowiImportForm extends React.Component {
|
|
|
this.validate();
|
|
|
}
|
|
|
|
|
|
+ updateOption(collectionName, data) {
|
|
|
+ const { optionsMap } = this.state;
|
|
|
+ const options = optionsMap[collectionName];
|
|
|
+
|
|
|
+ // merge
|
|
|
+ Object.assign(options, data);
|
|
|
+
|
|
|
+ optionsMap[collectionName] = options;
|
|
|
+ this.setState({ optionsMap });
|
|
|
+ }
|
|
|
+
|
|
|
+ openConfigurationModal(collectionName) {
|
|
|
+ this.setState({ isConfigurationModalOpen: true, collectionNameForConfiguration: collectionName });
|
|
|
+ }
|
|
|
+
|
|
|
+ showErrorsViewer(collectionName) {
|
|
|
+ this.setState({ isErrorsViewerOpen: true, collectionNameForErrorsViewer: collectionName });
|
|
|
+ }
|
|
|
+
|
|
|
async validate() {
|
|
|
// init errors
|
|
|
await this.setState({
|
|
|
- errorsForPageGroups: [],
|
|
|
- errorsForUserGroups: [],
|
|
|
- errorsForConfigGroups: [],
|
|
|
- errorsForOtherGroups: [],
|
|
|
+ warnForPageGroups: [],
|
|
|
+ warnForUserGroups: [],
|
|
|
+ warnForConfigGroups: [],
|
|
|
+ warnForOtherGroups: [],
|
|
|
});
|
|
|
|
|
|
await this.validateCollectionSize();
|
|
|
@@ -102,10 +207,10 @@ class GrowiImportForm extends React.Component {
|
|
|
await this.validateUserGroupRelations();
|
|
|
|
|
|
const errors = [
|
|
|
- ...this.state.errorsForPageGroups,
|
|
|
- ...this.state.errorsForUserGroups,
|
|
|
- ...this.state.errorsForConfigGroups,
|
|
|
- ...this.state.errorsForOtherGroups,
|
|
|
+ ...this.state.warnForPageGroups,
|
|
|
+ ...this.state.warnForUserGroups,
|
|
|
+ ...this.state.warnForConfigGroups,
|
|
|
+ ...this.state.warnForOtherGroups,
|
|
|
];
|
|
|
const canImport = errors.length === 0;
|
|
|
|
|
|
@@ -114,18 +219,18 @@ class GrowiImportForm extends React.Component {
|
|
|
|
|
|
async validateCollectionSize(validationErrors) {
|
|
|
const { t } = this.props;
|
|
|
- const { errorsForOtherGroups, selectedCollections } = this.state;
|
|
|
+ const { warnForOtherGroups, selectedCollections } = this.state;
|
|
|
|
|
|
if (selectedCollections.size === 0) {
|
|
|
- errorsForOtherGroups.push(t('importer_management.growi_settings.errors.at_least_one'));
|
|
|
+ warnForOtherGroups.push(t('importer_management.growi_settings.errors.at_least_one'));
|
|
|
}
|
|
|
|
|
|
- this.setState({ errorsForOtherGroups });
|
|
|
+ this.setState({ warnForOtherGroups });
|
|
|
}
|
|
|
|
|
|
async validatePagesCollectionPairs() {
|
|
|
const { t } = this.props;
|
|
|
- const { errorsForPageGroups, selectedCollections } = this.state;
|
|
|
+ const { warnForPageGroups, selectedCollections } = this.state;
|
|
|
|
|
|
const pageRelatedCollectionsLength = ['pages', 'revisions'].filter((collectionName) => {
|
|
|
return selectedCollections.has(collectionName);
|
|
|
@@ -133,98 +238,81 @@ class GrowiImportForm extends React.Component {
|
|
|
|
|
|
// MUST be included both or neither when importing
|
|
|
if (pageRelatedCollectionsLength !== 0 && pageRelatedCollectionsLength !== 2) {
|
|
|
- errorsForPageGroups.push(t('importer_management.growi_settings.errors.page_and_revision'));
|
|
|
+ warnForPageGroups.push(t('importer_management.growi_settings.errors.page_and_revision'));
|
|
|
}
|
|
|
|
|
|
- this.setState({ errorsForPageGroups });
|
|
|
+ this.setState({ warnForPageGroups });
|
|
|
}
|
|
|
|
|
|
async validateExternalAccounts() {
|
|
|
const { t } = this.props;
|
|
|
- const { errorsForUserGroups, selectedCollections } = this.state;
|
|
|
+ const { warnForUserGroups, selectedCollections } = this.state;
|
|
|
|
|
|
// MUST include also 'users' if 'externalaccounts' is selected
|
|
|
if (selectedCollections.has('externalaccounts')) {
|
|
|
if (!selectedCollections.has('users')) {
|
|
|
- errorsForUserGroups.push(t('importer_management.growi_settings.errors.depends', { target: 'Users', condition: 'Externalaccounts' }));
|
|
|
+ warnForUserGroups.push(t('importer_management.growi_settings.errors.depends', { target: 'Users', condition: 'Externalaccounts' }));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- this.setState({ errorsForUserGroups });
|
|
|
+ this.setState({ warnForUserGroups });
|
|
|
}
|
|
|
|
|
|
async validateUserGroups() {
|
|
|
const { t } = this.props;
|
|
|
- const { errorsForUserGroups, selectedCollections } = this.state;
|
|
|
+ const { warnForUserGroups, selectedCollections } = this.state;
|
|
|
|
|
|
// MUST include also 'users' if 'usergroups' is selected
|
|
|
if (selectedCollections.has('usergroups')) {
|
|
|
if (!selectedCollections.has('users')) {
|
|
|
- errorsForUserGroups.push(t('importer_management.growi_settings.errors.depends', { target: 'Users', condition: 'Usergroups' }));
|
|
|
+ warnForUserGroups.push(t('importer_management.growi_settings.errors.depends', { target: 'Users', condition: 'Usergroups' }));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- this.setState({ errorsForUserGroups });
|
|
|
+ this.setState({ warnForUserGroups });
|
|
|
}
|
|
|
|
|
|
async validateUserGroupRelations() {
|
|
|
const { t } = this.props;
|
|
|
- const { errorsForUserGroups, selectedCollections } = this.state;
|
|
|
+ const { warnForUserGroups, selectedCollections } = this.state;
|
|
|
|
|
|
// MUST include also 'usergroups' if 'usergrouprelations' is selected
|
|
|
if (selectedCollections.has('usergrouprelations')) {
|
|
|
if (!selectedCollections.has('usergroups')) {
|
|
|
- errorsForUserGroups.push(t('importer_management.growi_settings.errors.depends', { target: 'Usergroups', condition: 'Usergrouprelations' }));
|
|
|
+ warnForUserGroups.push(t('importer_management.growi_settings.errors.depends', { target: 'Usergroups', condition: 'Usergrouprelations' }));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- this.setState({ errorsForUserGroups });
|
|
|
+ this.setState({ warnForUserGroups });
|
|
|
}
|
|
|
|
|
|
async import() {
|
|
|
+ const { appContainer, fileName, onPostImport } = this.props;
|
|
|
+ const { selectedCollections, optionsMap } = this.state;
|
|
|
+
|
|
|
+ // init progress data
|
|
|
+ await this.setState({
|
|
|
+ isImporting: true,
|
|
|
+ progressMap: [],
|
|
|
+ errorsMap: [],
|
|
|
+ });
|
|
|
+
|
|
|
try {
|
|
|
// TODO: use appContainer.apiv3.post
|
|
|
- const { results } = await this.props.appContainer.apiPost('/v3/import', {
|
|
|
- fileName: this.props.fileName,
|
|
|
- collections: Array.from(this.state.selectedCollections),
|
|
|
- schema: this.state.schema,
|
|
|
+ await appContainer.apiv3Post('/import', {
|
|
|
+ fileName,
|
|
|
+ collections: Array.from(selectedCollections),
|
|
|
+ optionsMap,
|
|
|
});
|
|
|
|
|
|
- this.setState(this.initialState);
|
|
|
- this.props.onPostImport();
|
|
|
-
|
|
|
- // TODO: toastSuccess, toastError
|
|
|
- toastr.success(undefined, 'Imported documents', {
|
|
|
- closeButton: true,
|
|
|
- progressBar: true,
|
|
|
- newestOnTop: false,
|
|
|
- showDuration: '100',
|
|
|
- hideDuration: '100',
|
|
|
- timeOut: '1200',
|
|
|
- extendedTimeOut: '150',
|
|
|
- });
|
|
|
-
|
|
|
- for (const { collectionName, failedIds } of results) {
|
|
|
- if (failedIds.length > 0) {
|
|
|
- toastr.error(`failed to insert ${failedIds.join(', ')}`, collectionName, {
|
|
|
- closeButton: true,
|
|
|
- progressBar: true,
|
|
|
- newestOnTop: false,
|
|
|
- timeOut: '30000',
|
|
|
- });
|
|
|
- }
|
|
|
+ if (onPostImport != null) {
|
|
|
+ onPostImport();
|
|
|
}
|
|
|
+
|
|
|
+ toastSuccess(undefined, 'Import process has requested.');
|
|
|
}
|
|
|
catch (err) {
|
|
|
- // TODO: toastSuccess, toastError
|
|
|
- toastr.error(err, 'Error', {
|
|
|
- closeButton: true,
|
|
|
- progressBar: true,
|
|
|
- newestOnTop: false,
|
|
|
- showDuration: '100',
|
|
|
- hideDuration: '100',
|
|
|
- timeOut: '3000',
|
|
|
- });
|
|
|
+ toastError(err, 'Import request failed.');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -245,7 +333,7 @@ class GrowiImportForm extends React.Component {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- renderGroups(groupList, groupName, errors, { wellContent, color } = {}) {
|
|
|
+ renderGroups(groupList, groupName, errors, { wellContent } = {}) {
|
|
|
const collectionNames = groupList.filter((collectionName) => {
|
|
|
return this.allCollectionNames.includes(collectionName);
|
|
|
});
|
|
|
@@ -264,7 +352,7 @@ class GrowiImportForm extends React.Component {
|
|
|
</ul>
|
|
|
</div>
|
|
|
) }
|
|
|
- { this.renderCheckboxes(collectionNames, color) }
|
|
|
+ { this.renderImportItems(collectionNames) }
|
|
|
{ this.renderWarnForGroups(errors, `warnFor${groupName}`) }
|
|
|
</div>
|
|
|
);
|
|
|
@@ -275,29 +363,47 @@ class GrowiImportForm extends React.Component {
|
|
|
return !ALL_GROUPED_COLLECTIONS.includes(collectionName);
|
|
|
});
|
|
|
|
|
|
- return this.renderGroups(collectionNames, 'Other', this.state.errorsForOtherGroups);
|
|
|
+ return this.renderGroups(collectionNames, 'Other', this.state.warnForOtherGroups);
|
|
|
}
|
|
|
|
|
|
- renderCheckboxes(collectionNames, color) {
|
|
|
- const checkboxColor = color ? `checkbox-${color}` : 'checkbox-info';
|
|
|
+ renderImportItems(collectionNames) {
|
|
|
+ const {
|
|
|
+ isImporting,
|
|
|
+ isImported,
|
|
|
+ progressMap,
|
|
|
+ errorsMap,
|
|
|
+
|
|
|
+ selectedCollections,
|
|
|
+ optionsMap,
|
|
|
+ } = this.state;
|
|
|
|
|
|
return (
|
|
|
- <div className={`row checkbox ${checkboxColor}`}>
|
|
|
+ <div className="row">
|
|
|
{collectionNames.map((collectionName) => {
|
|
|
+ const collectionProgress = progressMap[collectionName];
|
|
|
+ const errors = errorsMap[collectionName];
|
|
|
+ const isConfigButtonAvailable = Object.keys(IMPORT_OPTION_CLASS_MAPPING).includes(collectionName);
|
|
|
+
|
|
|
return (
|
|
|
<div className="col-xs-6 my-1" key={collectionName}>
|
|
|
- <input
|
|
|
- type="checkbox"
|
|
|
- id={collectionName}
|
|
|
- name={collectionName}
|
|
|
- className="form-check-input"
|
|
|
- value={collectionName}
|
|
|
- checked={this.state.selectedCollections.has(collectionName)}
|
|
|
+ <GrowiZipImportItem
|
|
|
+ isImporting={isImporting}
|
|
|
+ isImported={collectionProgress ? isImported : false}
|
|
|
+ insertedCount={collectionProgress ? collectionProgress.insertedCount : 0}
|
|
|
+ modifiedCount={collectionProgress ? collectionProgress.modifiedCount : 0}
|
|
|
+ errorsCount={errors ? errors.length : 0}
|
|
|
+
|
|
|
+ collectionName={collectionName}
|
|
|
+ isSelected={selectedCollections.has(collectionName)}
|
|
|
+ option={optionsMap[collectionName]}
|
|
|
+
|
|
|
+ isConfigButtonAvailable={isConfigButtonAvailable}
|
|
|
+
|
|
|
onChange={this.toggleCheckbox}
|
|
|
+ onOptionChange={this.updateOption}
|
|
|
+ onConfigButtonClicked={this.openConfigurationModal}
|
|
|
+ onErrorLinkClicked={this.showErrorsViewer}
|
|
|
/>
|
|
|
- <label className="text-capitalize form-check-label ml-3" htmlFor={collectionName}>
|
|
|
- {collectionName}
|
|
|
- </label>
|
|
|
</div>
|
|
|
);
|
|
|
})}
|
|
|
@@ -305,10 +411,43 @@ class GrowiImportForm extends React.Component {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ renderConfigurationModal() {
|
|
|
+ const { isConfigurationModalOpen, collectionNameForConfiguration: collectionName, optionsMap } = this.state;
|
|
|
+
|
|
|
+ if (collectionName == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ <GrowiZipImportConfigurationModal
|
|
|
+ isOpen={isConfigurationModalOpen}
|
|
|
+ onClose={() => this.setState({ isConfigurationModalOpen: false })}
|
|
|
+ onOptionChange={this.updateOption}
|
|
|
+ collectionName={collectionName}
|
|
|
+ option={optionsMap[collectionName]}
|
|
|
+ />
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ renderErrorsViewer() {
|
|
|
+ const { isErrorsViewerOpen, errorsMap, collectionNameForErrorsViewer } = this.state;
|
|
|
+ const errors = errorsMap[collectionNameForErrorsViewer];
|
|
|
+
|
|
|
+ return (
|
|
|
+ <ErrorViewer
|
|
|
+ isOpen={isErrorsViewerOpen}
|
|
|
+ onClose={() => this.setState({ isErrorsViewerOpen: false })}
|
|
|
+ errors={errors}
|
|
|
+ />
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
render() {
|
|
|
const { t } = this.props;
|
|
|
- const { errorsForPageGroups, errorsForUserGroups, errorsForConfigGroups } = this.state;
|
|
|
+ const {
|
|
|
+ canImport, isImporting,
|
|
|
+ warnForPageGroups, warnForUserGroups, warnForConfigGroups,
|
|
|
+ } = this.state;
|
|
|
|
|
|
return (
|
|
|
<>
|
|
|
@@ -325,19 +464,22 @@ class GrowiImportForm extends React.Component {
|
|
|
</div>
|
|
|
</form>
|
|
|
|
|
|
- { this.renderGroups(GROUPS_PAGE, 'Page', errorsForPageGroups, { wellContent: t('importer_management.growi_settings.overwrite_documents') }) }
|
|
|
- { this.renderGroups(GROUPS_USER, 'User', errorsForUserGroups) }
|
|
|
- { this.renderGroups(GROUPS_CONFIG, 'Config', errorsForConfigGroups) }
|
|
|
+ { this.renderGroups(GROUPS_PAGE, 'Page', warnForPageGroups, { wellContent: t('importer_management.growi_settings.overwrite_documents') }) }
|
|
|
+ { this.renderGroups(GROUPS_USER, 'User', warnForUserGroups) }
|
|
|
+ { this.renderGroups(GROUPS_CONFIG, 'Config', warnForConfigGroups) }
|
|
|
{ this.renderOthers() }
|
|
|
|
|
|
- <div className="mt-5 text-center">
|
|
|
+ <div className="mt-4 text-center">
|
|
|
<button type="button" className="btn btn-default mx-1" onClick={this.props.onDiscard}>
|
|
|
{ t('importer_management.growi_settings.discard') }
|
|
|
</button>
|
|
|
- <button type="button" className="btn btn-primary mx-1" onClick={this.import} disabled={!this.state.canImport}>
|
|
|
+ <button type="button" className="btn btn-primary mx-1" onClick={this.import} disabled={!canImport || isImporting}>
|
|
|
{ t('importer_management.import') }
|
|
|
</button>
|
|
|
</div>
|
|
|
+
|
|
|
+ { this.renderConfigurationModal() }
|
|
|
+ { this.renderErrorsViewer() }
|
|
|
</>
|
|
|
);
|
|
|
}
|
|
|
@@ -347,18 +489,19 @@ class GrowiImportForm extends React.Component {
|
|
|
GrowiImportForm.propTypes = {
|
|
|
t: PropTypes.func.isRequired, // i18next
|
|
|
appContainer: PropTypes.instanceOf(AppContainer).isRequired,
|
|
|
+ websocketContainer: PropTypes.instanceOf(WebsocketContainer).isRequired,
|
|
|
|
|
|
fileName: PropTypes.string,
|
|
|
- fileStats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
|
+ innerFileStats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
|
onDiscard: PropTypes.func.isRequired,
|
|
|
- onPostImport: PropTypes.func.isRequired,
|
|
|
+ onPostImport: PropTypes.func,
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Wrapper component for using unstated
|
|
|
*/
|
|
|
const GrowiImportFormWrapper = (props) => {
|
|
|
- return createSubscribedElement(GrowiImportForm, props, [AppContainer]);
|
|
|
+ return createSubscribedElement(GrowiImportForm, props, [AppContainer, WebsocketContainer]);
|
|
|
};
|
|
|
|
|
|
export default withTranslation()(GrowiImportFormWrapper);
|