diff --git a/client/modules/IDE/actions/assets.js b/client/modules/IDE/actions/assets.js index 5b72791e..e2b49cf6 100644 --- a/client/modules/IDE/actions/assets.js +++ b/client/modules/IDE/actions/assets.js @@ -1,26 +1,32 @@ import axios from 'axios'; - import * as ActionTypes from '../../../constants'; +import { startLoader, stopLoader } from './loader'; const __process = (typeof global !== 'undefined' ? global : window).process; const ROOT_URL = __process.env.API_URL; -function setAssets(assets) { +function setAssets(assets, totalSize) { return { type: ActionTypes.SET_ASSETS, - assets + assets, + totalSize }; } export function getAssets() { - return (dispatch, getState) => { + return (dispatch) => { + dispatch(startLoader()); axios.get(`${ROOT_URL}/S3/objects`, { withCredentials: true }) .then((response) => { - dispatch(setAssets(response.data.assets)); + dispatch(setAssets(response.data.assets, response.data.totalSize)); + dispatch(stopLoader()); }) - .catch(response => dispatch({ - type: ActionTypes.ERROR - })); + .catch(() => { + dispatch({ + type: ActionTypes.ERROR + }); + dispatch(stopLoader()); + }); }; } diff --git a/client/modules/IDE/components/AssetList.jsx b/client/modules/IDE/components/AssetList.jsx index ab548322..a658fedf 100644 --- a/client/modules/IDE/components/AssetList.jsx +++ b/client/modules/IDE/components/AssetList.jsx @@ -4,12 +4,11 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { Link } from 'react-router'; import { Helmet } from 'react-helmet'; - import prettyBytes from 'pretty-bytes'; +import Loader from '../../App/components/loader'; import * as AssetActions from '../actions/assets'; - class AssetList extends React.Component { constructor(props) { super(props); @@ -23,17 +22,37 @@ class AssetList extends React.Component { return `p5.js Web Editor | ${this.props.username}'s assets`; } + hasAssets() { + return !this.props.loading && this.props.assetList.length > 0; + } + + renderLoader() { + if (this.props.loading) return ; + return null; + } + + renderEmptyTable() { + if (!this.props.loading && this.props.assetList.length === 0) { + return (

No uploaded assets.

); + } + return null; + } + render() { const username = this.props.username !== undefined ? this.props.username : this.props.user.username; + const { assetList, totalSize } = this.props; return (
+ {/* Eventually, this copy should be Total / 250 MB Used */} + {this.hasAssets() && +

{`${prettyBytes(totalSize)} Total`}

+ } {this.getAssetsTitle()} - {this.props.assets.length === 0 && -

No uploaded assets.

- } - {this.props.assets.length > 0 && + {this.renderLoader()} + {this.renderEmptyTable()} + {this.hasAssets() && @@ -44,7 +63,7 @@ class AssetList extends React.Component { - {this.props.assets.map(asset => + {assetList.map(asset => ( @@ -65,20 +84,24 @@ AssetList.propTypes = { username: PropTypes.string }).isRequired, username: PropTypes.string.isRequired, - assets: PropTypes.arrayOf(PropTypes.shape({ + assetList: PropTypes.arrayOf(PropTypes.shape({ key: PropTypes.string.isRequired, name: PropTypes.string.isRequired, url: PropTypes.string.isRequired, sketchName: PropTypes.string.isRequired, sketchId: PropTypes.string.isRequired })).isRequired, + totalSize: PropTypes.number.isRequired, getAssets: PropTypes.func.isRequired, + loading: PropTypes.bool.isRequired }; function mapStateToProps(state) { return { user: state.user, - assets: state.assets + assetList: state.assets.list, + totalSize: state.assets.totalSize, + loading: state.loading }; } diff --git a/client/modules/IDE/reducers/assets.js b/client/modules/IDE/reducers/assets.js index 260660f2..9ddd1cbe 100644 --- a/client/modules/IDE/reducers/assets.js +++ b/client/modules/IDE/reducers/assets.js @@ -1,9 +1,15 @@ import * as ActionTypes from '../../../constants'; -const assets = (state = [], action) => { +// 1,000,000 bytes in a MB. can't upload if totalSize is bigger than this. +const initialState = { + list: [], + totalSize: 0 +}; + +const assets = (state = initialState, action) => { switch (action.type) { case ActionTypes.SET_ASSETS: - return action.assets; + return { list: action.assets, totalSize: action.totalSize }; default: return state; } diff --git a/client/styles/components/_asset-list.scss b/client/styles/components/_asset-list.scss index 76013deb..e9258f3a 100644 --- a/client/styles/components/_asset-list.scss +++ b/client/styles/components/_asset-list.scss @@ -54,3 +54,7 @@ text-align: center; font-size: #{16 / $base-font-size}rem; } + +.asset-table__total { + padding: 0 #{20 / $base-font-size}rem; +} diff --git a/server/controllers/aws.controller.js b/server/controllers/aws.controller.js index 4e94e24e..dd9122f6 100644 --- a/server/controllers/aws.controller.js +++ b/server/controllers/aws.controller.js @@ -126,6 +126,7 @@ export function listObjectsInS3ForUser(req, res) { .on('end', () => { const projectAssets = []; getProjectsForUserId(userId).then((projects) => { + let totalSize = 0; assets.forEach((asset) => { const name = asset.key.split('/').pop(); const foundAsset = { @@ -134,6 +135,7 @@ export function listObjectsInS3ForUser(req, res) { size: asset.size, url: `${process.env.S3_BUCKET_URL_BASE}${asset.key}` }; + totalSize += asset.size; projects.some((project) => { let found = false; project.files.some((file) => { @@ -152,7 +154,7 @@ export function listObjectsInS3ForUser(req, res) { }); projectAssets.push(foundAsset); }); - res.json({ assets: projectAssets }); + res.json({ assets: projectAssets, totalSize }); }); }); });
{asset.name}