Skip to content

Commit

Permalink
Merge pull request #39 from folio-org/dev
Browse files Browse the repository at this point in the history
Back to Master
  • Loading branch information
ViktorSoroka07 committed Dec 13, 2018
2 parents fe39d8b + 1c12e26 commit d899f5e
Show file tree
Hide file tree
Showing 26 changed files with 537 additions and 154 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -1,6 +1,9 @@
# Change history for ui-data-import

## 1.0.1 (IN-PROGRESS)
* Add file extensions validation and `InvalidFilesModal` component for file upload (UIDATIMP-46)
* Hide popover when user clicks on the link button (UIDATIMP-71)
* Write documentation for `FileUploader` component and some code refactor (UIDATIMP-65)

## [1.0.0](https://github.com/folio-org/ui-data-import/tree/v1.0.0) (2018-11-10)

Expand Down
82 changes: 36 additions & 46 deletions src/components/DataFetcher/DataFetcher.js
Expand Up @@ -4,17 +4,41 @@ import { get } from 'lodash';

import jobPropTypes from '../Jobs/components/Job/jobPropTypes';
import jobLogPropTypes from '../JobLogs/jobLogPropTypes';
import { createUrl } from '../../utils';
import {
PROCESSING_IN_PROGRESS,
PROCESSING_FINISHED,
PARSING_IN_PROGRESS,
COMMITTED,
} from '../Jobs/jobStatuses';
import { DataFetcherContextProvider } from './DataFetcherContext';
import { DataFetcherContextProvider } from '.';

const DEFAULT_UPDATE_INTERVAL = 5000;

const jobsUrl = createUrl('metadata-provider/jobExecutions', {
query: `(status=("${PROCESSING_IN_PROGRESS}" OR "${PROCESSING_FINISHED}" OR "${PARSING_IN_PROGRESS}"))`,
});

const logsUrl = createUrl('metadata-provider/logs', {
landingPage: true,
limit: 25,
});

class DataFetcher extends Component {
static manifest = Object.freeze({
jobs: {
type: 'okapi',
path: jobsUrl,
accumulate: true,
throwErrors: false,
},
logs: {
type: 'okapi',
path: logsUrl + '&query=(status=COMMITTED)', // TODO: remove query once backend issue is fixed
accumulate: true,
throwErrors: false,
},
});

static propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
Expand Down Expand Up @@ -51,27 +75,13 @@ class DataFetcher extends Component {
updateInterval: DEFAULT_UPDATE_INTERVAL,
};

static manifest = Object.freeze({
jobs: {
type: 'okapi',
path: `metadata-provider/jobExecutions?query=(status=(${PROCESSING_IN_PROGRESS} OR ${PROCESSING_FINISHED} OR ${PARSING_IN_PROGRESS}))`,
accumulate: true,
throwErrors: false,
},
logs: {
type: 'okapi',
path: `metadata-provider/logs?query=(status=${COMMITTED})&landingPage=true&limit=25`,
accumulate: true,
throwErrors: false,
},
});

state = {
contextData: {},
contextData: {
hasLoaded: false,
},
};

componentDidMount() {
this.setInitialState();
this.getResourcesData();
this.updateResourcesData();
}
Expand All @@ -88,22 +98,6 @@ class DataFetcher extends Component {
this.intervalId = setInterval(this.getResourcesData, updateInterval);
}

setInitialState() {
const { mutator } = this.props;
const initialContextData = {};

Object.keys(mutator)
.forEach(resourceName => {
initialContextData[resourceName] = {
hasLoaded: false,
};
});

this.setState({
contextData: initialContextData,
});
}

getResourcesData = async () => {
const { mutator } = this.props;

Expand All @@ -126,7 +120,10 @@ class DataFetcher extends Component {
}
};

async getResourceData({ GET, reset }) {
async getResourceData({
GET,
reset,
}) {
// accumulate: true in manifest saves the results of all requests
// because of that it is required to clear old data by invoking reset method before each request
reset();
Expand All @@ -138,21 +135,14 @@ class DataFetcher extends Component {
*/
mapResourcesToState(isEmpty) {
const { resources } = this.props;
const contextData = {};
const contextData = { hasLoaded: true };

Object.entries(resources)
.forEach(([resourceName, resourceValue]) => {
const itemsObject = isEmpty ? {} : get(resourceValue, ['records', 0], {});

contextData[resourceName] = {
hasLoaded: true,
itemsObject,
};
contextData[resourceName] = isEmpty ? {} : get(resourceValue, ['records', 0], {});
});

this.setState({
contextData,
});
this.setState({ contextData });
}

render() {
Expand Down
1 change: 1 addition & 0 deletions src/components/DataFetcher/index.js
@@ -1 +1,2 @@
export { default } from './DataFetcher';
export * from './DataFetcherContext';
68 changes: 53 additions & 15 deletions src/components/ImportJobs/ImportJobs.js
Expand Up @@ -2,8 +2,10 @@ import React, { Component } from 'react';
import { withRouter, Redirect } from 'react-router';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { get } from 'lodash';

import FileUploader from './components/FileUploader';
import InvalidFilesModal from './components/InvalidFilesModal';

import css from './components/FileUploader/FileUploader.css';

Expand All @@ -16,42 +18,70 @@ class ImportJobs extends Component {

state = {
isDropZoneActive: false,
isModalOpen: false,
redirect: false,
};

onDragEnter = () => {
this.setState({
isDropZoneActive: true,
});
this.setState({ isDropZoneActive: true });
};

onDragLeave = () => {
this.setState({
isDropZoneActive: false,
});
this.setState({ isDropZoneActive: false });
};

/**
* @param {Array<File>} acceptedFiles
* @param {Array<File>} rejectedFiles
*/
onDrop = (acceptedFiles, rejectedFiles) => {
this.setState({
isDropZoneActive: false,
acceptedFiles,
rejectedFiles,
redirect: true,
});
const isValidFileExtensions = this.validateFileExtensions(acceptedFiles);

if (isValidFileExtensions) {
this.setState({
isDropZoneActive: false,
redirect: true,
acceptedFiles,
rejectedFiles,
});

return;
}

this.setState({ isDropZoneActive: false });
this.showModal();
};

getMessageById = (idEnding, moduleName = 'ui-data-import') => {
/**
* @param {Array<File>} files
*/
validateFileExtensions(files = []) {
const filesType = get(files, [0, 'type'], '');

return files.every(({ type }) => type === filesType);
}

showModal() {
this.setState({ isModalOpen: true });
}

hideModal = () => {
this.setState({ isModalOpen: false });
};

getMessageById(idEnding, moduleName = 'ui-data-import') {
const id = `${moduleName}.${idEnding}`;

return <FormattedMessage id={id} />;
};
}

render() {
const {
acceptedFiles,
rejectedFiles,
redirect,
isDropZoneActive,
isModalOpen,
} = this.state;
const { match } = this.props;
const titleMessageIdEnding = isDropZoneActive ? 'activeUploadTitle' : 'uploadTitle';
Expand Down Expand Up @@ -82,7 +112,15 @@ class ImportJobs extends Component {
onDragEnter={this.onDragEnter}
onDragLeave={this.onDragLeave}
onDrop={this.onDrop}
/>
>
{openFileUploadDialogWindow => (
<InvalidFilesModal
isModalOpen={isModalOpen}
onConfirmModal={this.hideModal}
openFileUploadDialogWindow={openFileUploadDialogWindow}
/>
)}
</FileUploader>
);
}
}
Expand Down
36 changes: 15 additions & 21 deletions src/components/ImportJobs/components/FileUploader/FileUploader.js
@@ -1,7 +1,8 @@
import React from 'react';
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import ReactDropzone from 'react-dropzone';
import classNames from 'classnames/bind';
import { isFunction } from 'lodash';

import { Button } from '@folio/stripes/components';

Expand All @@ -10,18 +11,7 @@ import css from './FileUploader.css';

const cx = classNames.bind(css);

const getTitleClassName = dropZoneState => {
return cx({
uploadTitle: true,
activeUploadTitle: dropZoneState,
});
};

const getUsedStyle = (styleFromProps, classNameFromProps) => {
return classNameFromProps ? null : styleFromProps;
};

const FileUploader = (props) => {
const FileUploader = props => {
const {
title,
uploadBtnText,
Expand All @@ -40,15 +30,16 @@ const FileUploader = (props) => {
onDragEnter,
onDragLeave,
} = props;

const titleClassName = getTitleClassName(isDropZoneActive);
const usedStyle = getUsedStyle(style, className);
const titleClassName = cx({
uploadTitle: true,
activeUploadTitle: isDropZoneActive,
});

return (
<ReactDropzone
disableClick
className={className}
style={usedStyle}
style={style}
activeClassName={activeClassName}
accept={accept}
acceptClassName={acceptClassName}
Expand All @@ -61,8 +52,10 @@ const FileUploader = (props) => {
onDragLeave={onDragLeave}
>
{({ open }) => (
<React.Fragment>
<span className={titleClassName}>{title}</span>
<Fragment>
<span className={titleClassName}>
{title}
</span>
<div hidden={isDropZoneActive}>
<Button
buttonStyle="primary"
Expand All @@ -72,9 +65,9 @@ const FileUploader = (props) => {
</Button>
</div>
<div hidden={isDropZoneActive}>
{children}
{isFunction(children) ? children(open) : children}
</div>
</React.Fragment>
</Fragment>
)}
</ReactDropzone>
);
Expand Down Expand Up @@ -102,6 +95,7 @@ FileUploader.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
PropTypes.func,
]),
};

Expand Down

0 comments on commit d899f5e

Please sign in to comment.