Skip to content

Commit

Permalink
Removed file_upload component (#29007)
Browse files Browse the repository at this point in the history
Moved filepicker style to main.scss. Removed workpad_upload component

    Added filepicker to asset manager

    Removed check for assets in workpad header to always show asset manager button

    Deduped image uploads in asset manager. Added loading indicator to asset manager

    Added empty prompt to display when there are no assets

    Adds additional image upload type checking

    Updated verbiage

    Undid CSS changes to  workpad_loader filepicker
  • Loading branch information
cqliu1 authored Jan 30, 2019
1 parent 6eeccb8 commit cc0e2d0
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,21 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { EuiFilePicker } from '@elastic/eui';
import { Loading } from '../../../../../public/components/loading/loading';
import { FileUpload } from '../../../../../public/components/file_upload';

export const FileForm = ({ loading, onUpload }) =>
loading ? <Loading animated text="Image uploading" /> : <FileUpload onUpload={onUpload} />;
export const FileForm = ({ loading, onChange }) =>
loading ? (
<Loading animated text="Image uploading" />
) : (
<EuiFilePicker
initialPromptText="Select or drag and drop an image"
onChange={onChange}
compressed
className="canvasImageUpload"
accept="image/*"
/>
);

FileForm.propTypes = {
loading: PropTypes.bool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import { EuiSpacer, EuiButtonGroup } from '@elastic/eui';
import { get } from 'lodash';
import { AssetPicker } from '../../../../public/components/asset_picker';
import { elasticOutline } from '../../../lib/elastic_outline';
import { resolveFromArgs } from '../../../../common/lib/resolve_dataurl';
import { isValidHttpUrl } from '../../../../common/lib/httpurl';
import { encode } from '../../../../common/lib/dataurl';
import { templateFromReactComponent } from '../../../../public/lib/template_from_react_component';
import './image_upload.scss';
import { VALID_IMAGE_TYPES } from '../../../../common/lib/constants';
import { FileForm, LinkForm } from './forms';

class ImageUpload extends React.Component {
Expand Down Expand Up @@ -71,17 +73,21 @@ class ImageUpload extends React.Component {

handleUpload = files => {
const { onAssetAdd } = this.props;
const [upload] = files;
this.setState({ loading: true }); // start loading indicator
const [file] = files;

encode(upload)
.then(dataurl => onAssetAdd('dataurl', dataurl))
.then(assetId => {
this.updateAST(assetId);
const [type, subtype] = get(file, 'type', '').split('/');
if (type === 'image' && VALID_IMAGE_TYPES.indexOf(subtype) >= 0) {
this.setState({ loading: true }); // start loading indicator

// this component can go away when onValueChange is called, check for _isMounted
this._isMounted && this.setState({ loading: false }); // set loading state back to false
});
encode(file)
.then(dataurl => onAssetAdd('dataurl', dataurl))
.then(assetId => {
this.updateAST(assetId);

// this component can go away when onValueChange is called, check for _isMounted
this._isMounted && this.setState({ loading: false }); // set loading state back to false
});
}
};

changeUrlType = optionId => {
Expand Down Expand Up @@ -119,7 +125,7 @@ class ImageUpload extends React.Component {
);

const forms = {
file: <FileForm loading={loading} onUpload={this.handleUpload} />,
file: <FileForm loading={loading} onChange={this.handleUpload} />,
link: (
<LinkForm
url={url}
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/canvas/common/lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export const FETCH_TIMEOUT = 30000; // 30 seconds
export const CANVAS_USAGE_TYPE = 'canvas';
export const SECURITY_AUTH_MESSAGE = 'Authentication failed';
export const DEFAULT_WORKPAD_CSS = '.canvasPage {\n\n}';
export const VALID_IMAGE_TYPES = ['gif', 'jpeg', 'png', 'svg+xml'];
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,31 @@ import {
EuiSpacer,
EuiTextColor,
EuiToolTip,
EuiFilePicker,
EuiEmptyPrompt,
} from '@elastic/eui';
import { ConfirmModal } from '../confirm_modal';
import { Clipboard } from '../clipboard';
import { Download } from '../download';
import { Loading } from '../loading';

export class AssetManager extends React.PureComponent {
static propTypes = {
assets: PropTypes.array,
addImageElement: PropTypes.func,
removeAsset: PropTypes.func,
copyAsset: PropTypes.func,
removeAsset: PropTypes.func.isRequired,
copyAsset: PropTypes.func.isRequired,
onAssetAdd: PropTypes.func.isRequired,
};

state = {
deleteId: null,
isModalVisible: false,
loading: false,
};

_isMounted = true;

showModal = () => this.setState({ isModalVisible: true });
closeModal = () => this.setState({ isModalVisible: false });

Expand All @@ -52,6 +59,13 @@ export class AssetManager extends React.PureComponent {
this.props.removeAsset(this.state.deleteId);
};

handleFileUpload = files => {
this.setState({ loading: true });
Promise.all(Array.from(files).map(file => this.props.onAssetAdd(file))).finally(() => {
this._isMounted && this.setState({ loading: false });
});
};

addElement = assetId => {
this.props.addImageElement(assetId);
};
Expand Down Expand Up @@ -132,16 +146,32 @@ export class AssetManager extends React.PureComponent {
);

render() {
const { isModalVisible } = this.state;
const { isModalVisible, loading } = this.state;
const { assets } = this.props;

const assetMaxLimit = 25000;

const assetsTotal = Math.round(
this.props.assets.reduce((total, asset) => total + asset.value.length, 0) / 1024
assets.reduce((total, asset) => total + asset.value.length, 0) / 1024
);

const percentageUsed = Math.round((assetsTotal / assetMaxLimit) * 100);

const emptyAssets = (
<EuiPanel className="canvasAssetManager__emptyPanel">
<EuiEmptyPrompt
iconType="importAction"
title={<h2>No available assets</h2>}
titleSize="s"
body={
<Fragment>
<p>Upload your assets above to get started</p>
</Fragment>
}
/>
</EuiPanel>
);

const assetModal = isModalVisible ? (
<EuiOverlayMask>
<EuiModal
Expand All @@ -153,6 +183,40 @@ export class AssetManager extends React.PureComponent {
<EuiModalHeaderTitle className="canvasAssetManager__modalHeaderTitle">
Manage workpad assets
</EuiModalHeaderTitle>
<EuiFlexGroup className="canvasAssetManager__fileUploadWrapper">
<EuiFlexItem grow={false}>
{loading ? (
<Loading animated text="Uploading images" />
) : (
<EuiFilePicker
initialPromptText="Select or drag and drop images"
compressed
multiple
onChange={this.handleFileUpload}
accept="image/*"
/>
)}
</EuiFlexItem>
</EuiFlexGroup>
</EuiModalHeader>
<EuiModalBody>
<EuiText size="s" color="subdued">
<p>
Below are the image assets that you added to this workpad. To reclaim space, delete
assets that you no longer need. Unfortunately, any assets that are actually in use
cannot be determined at this time.
</p>
</EuiText>
<EuiSpacer />
{assets.length ? (
<EuiFlexGrid responsive={false} columns={4}>
{assets.map(this.renderAsset)}
</EuiFlexGrid>
) : (
emptyAssets
)}
</EuiModalBody>
<EuiModalFooter className="canvasAssetManager__modalFooter">
<EuiFlexGroup className="canvasAssetManager__meterWrapper" responsive={false}>
<EuiFlexItem>
<EuiProgress
Expand All @@ -167,20 +231,6 @@ export class AssetManager extends React.PureComponent {
<EuiText id="CanvasAssetManagerLabel">{percentageUsed}% space used</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiModalHeader>
<EuiModalBody>
<EuiText size="s" color="subdued">
<p>
Below are the image assets that you added to this workpad. To reclaim space, delete
assets that you no longer need. Unfortunately, any assets that are actually in use
cannot be determined at this time.
</p>
</EuiText>
<EuiFlexGrid responsive={false} columns={4}>
{this.props.assets.map(this.renderAsset)}
</EuiFlexGrid>
</EuiModalBody>
<EuiModalFooter>
<EuiButton size="s" onClick={this.closeModal}>
Close
</EuiButton>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.canvasAssetManager {

.canvasAssetManager__modalHeader {
flex-wrap: wrap;
}
Expand All @@ -15,8 +14,6 @@
flex-grow: 0;
min-width: 40%;
align-items: center;
justify-content: flex-end;
padding-right: $euiSize;

@include euiBreakpoint('xs', 's') {
flex-grow: 1;
Expand All @@ -27,13 +24,23 @@
margin: 0;
}

.canvasAssetManager__fileUploadWrapper {
justify-content: flex-end;
padding-right: $euiSize;
}

// ASSETS LIST

.canvasAssetManager__asset {
text-align: center;
overflow: hidden; // hides image from outer panel boundaries
}

.canvasAssetManager__emptyPanel {
max-width: 400px;
margin: 0 auto;
}

.canvasAssetManager__thumb {
margin: -$euiSizeS;
margin-bottom: 0;
Expand All @@ -52,4 +59,8 @@
opacity: 0; // only show the background image (which will properly keep proportions)
}
}

.canvasAssetManager__modalFooter {
justify-content: space-between;
}
}
33 changes: 31 additions & 2 deletions x-pack/plugins/canvas/public/components/asset_manager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@

import { connect } from 'react-redux';
import { compose, withProps } from 'recompose';
import { set } from 'lodash';
import { set, get } from 'lodash';
import { fromExpression, toExpression } from '@kbn/interpreter/common';
import { notify } from '../../lib/notify';
import { getAssets } from '../../state/selectors/assets';
import { removeAsset } from '../../state/actions/assets';
import { removeAsset, createAsset } from '../../state/actions/assets';
import { elementsRegistry } from '../../lib/elements_registry';
import { addElement } from '../../state/actions/elements';
import { getSelectedPage } from '../../state/selectors/workpad';
import { encode } from '../../../common/lib/dataurl';
import { getId } from '../../lib/get_id';
import { findExistingAsset } from '../../lib/find_existing_asset';
import { VALID_IMAGE_TYPES } from '../../../common/lib/constants';
import { AssetManager as Component } from './asset_manager';

const mapStateToProps = state => ({
Expand Down Expand Up @@ -44,15 +48,40 @@ const mapDispatchToProps = dispatch => ({
imageElement.expression = toExpression(newAST);
dispatch(addElement(pageId, imageElement));
},
onAssetAdd: (type, content) => {
// make the ID here and pass it into the action
const assetId = getId('asset');
dispatch(createAsset(type, content, assetId));

// then return the id, so the caller knows the id that will be created
return assetId;
},
removeAsset: assetId => dispatch(removeAsset(assetId)),
});

const mergeProps = (stateProps, dispatchProps, ownProps) => {
const { assets } = stateProps;
const { onAssetAdd } = dispatchProps;
return {
...ownProps,
...stateProps,
...dispatchProps,
addImageElement: dispatchProps.addImageElement(stateProps.selectedPage),
onAssetAdd: file => {
const [type, subtype] = get(file, 'type', '').split('/');
if (type === 'image' && VALID_IMAGE_TYPES.indexOf(subtype) >= 0) {
return encode(file).then(dataurl => {
const type = 'dataurl';
const existingId = findExistingAsset(type, dataurl, assets);
if (existingId) {
return existingId;
}
return onAssetAdd(type, dataurl);
});
}

return false;
},
};
};

Expand Down
19 changes: 0 additions & 19 deletions x-pack/plugins/canvas/public/components/file_upload/file_upload.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getContextForIndex,
} from '../../state/selectors/workpad';
import { getAssets } from '../../state/selectors/assets';
import { findExistingAsset } from '../../lib/find_existing_asset';
import { FunctionForm as Component } from './function_form';

const mapStateToProps = (state, { expressionIndex }) => ({
Expand Down Expand Up @@ -93,9 +94,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
onValueAdd: addArgument(element, pageId),
onValueRemove: deleteArgument(element, pageId),
onAssetAdd: (type, content) => {
const existingId = Object.keys(assets).find(
assetId => assets[assetId].type === type && assets[assetId].value === content
);
const existingId = findExistingAsset(type, content, assets);
if (existingId) {
return existingId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { connect } from 'react-redux';
import { canUserWrite } from '../../state/selectors/app';
import { getWorkpadName, getSelectedPage, isWriteable } from '../../state/selectors/workpad';
import { setWriteable } from '../../state/actions/workpad';
import { getAssets } from '../../state/selectors/assets';
import { addElement } from '../../state/actions/elements';
import { WorkpadHeader as Component } from './workpad_header';

Expand All @@ -18,7 +17,6 @@ const mapStateToProps = state => ({
canUserWrite: canUserWrite(state),
workpadName: getWorkpadName(state),
selectedPage: getSelectedPage(state),
hasAssets: Object.keys(getAssets(state)).length ? true : false,
});

const mapDispatchToProps = dispatch => ({
Expand Down
Loading

0 comments on commit cc0e2d0

Please sign in to comment.