Fix merge conflicts for cherry picking 0bac332a9eb360978e686d6be8bff92f0fa1740c

This commit is contained in:
Cassie Tarakajian 2019-09-10 18:42:23 -04:00
parent b8fb51d283
commit 7c1aa2e589
9 changed files with 246 additions and 48 deletions

View File

@ -129,6 +129,7 @@ export const CLEAR_PERSISTED_STATE = 'CLEAR_PERSISTED_STATE';
export const HIDE_RUNTIME_ERROR_WARNING = 'HIDE_RUNTIME_ERROR_WARNING';
export const SHOW_RUNTIME_ERROR_WARNING = 'SHOW_RUNTIME_ERROR_WARNING';
export const SET_ASSETS = 'SET_ASSETS';
export const DELETE_ASSET = 'DELETE_ASSET';
export const TOGGLE_DIRECTION = 'TOGGLE_DIRECTION';
export const SET_SORTING = 'SET_SORTING';

View File

@ -30,8 +30,23 @@ export function getAssets() {
};
}
export function deleteAsset(assetKey, userId) {
export function deleteAsset(assetKey) {
return {
type: 'PLACEHOLDER'
type: ActionTypes.DELETE_ASSET,
key: assetKey
};
}
export function deleteAssetRequest(assetKey) {
return (dispatch) => {
axios.delete(`${ROOT_URL}/S3/${assetKey}`, { withCredentials: true })
.then((response) => {
dispatch(deleteAsset(assetKey));
})
.catch(() => {
dispatch({
type: ActionTypes.ERROR
});
});
};
}

View File

@ -5,9 +5,144 @@ import { bindActionCreators } from 'redux';
import { Link } from 'react-router';
import { Helmet } from 'react-helmet';
import prettyBytes from 'pretty-bytes';
import InlineSVG from 'react-inlinesvg';
import Loader from '../../App/components/loader';
import * as AssetActions from '../actions/assets';
import downFilledTriangle from '../../../images/down-filled-triangle.svg';
class AssetListRowBase extends React.Component {
constructor(props) {
super(props);
this.state = {
isFocused: false,
optionsOpen: false
};
}
onFocusComponent = () => {
this.setState({ isFocused: true });
}
onBlurComponent = () => {
this.setState({ isFocused: false });
setTimeout(() => {
if (!this.state.isFocused) {
this.closeAll();
}
}, 200);
}
openOptions = () => {
this.setState({
optionsOpen: true
});
}
closeOptions = () => {
this.setState({
optionsOpen: false
});
}
toggleOptions = () => {
if (this.state.optionsOpen) {
this.closeOptions();
} else {
this.openOptions();
}
}
handleDropdownOpen = () => {
this.closeOptions();
this.openOptions();
}
handleAssetDelete = () => {
const { key, name } = this.props.asset;
this.closeOptions();
if (window.confirm(`Are you sure you want to delete "${name}"?`)) {
this.props.deleteAssetRequest(key);
}
}
render() {
const { asset, username } = this.props;
const { optionsOpen } = this.state;
return (
<tr className="asset-table__row" key={asset.key}>
<th scope="row">
<Link to={asset.url} target="_blank">
{asset.name}
</Link>
</th>
<td>{prettyBytes(asset.size)}</td>
<td>
{ asset.sketchId && <Link to={`/${username}/sketches/${asset.sketchId}`}>{asset.sketchName}</Link> }
</td>
<td className="asset-table__dropdown-column">
<button
className="asset-table__dropdown-button"
onClick={this.toggleOptions}
onBlur={this.onBlurComponent}
onFocus={this.onFocusComponent}
>
<InlineSVG src={downFilledTriangle} alt="Menu" />
</button>
{optionsOpen &&
<ul
className="asset-table__action-dialogue"
>
<li>
<button
className="asset-table__action-option"
onClick={this.handleAssetDelete}
onBlur={this.onBlurComponent}
onFocus={this.onFocusComponent}
>
Delete
</button>
</li>
<li>
<Link
to={asset.url}
target="_blank"
onBlur={this.onBlurComponent}
onFocus={this.onFocusComponent}
>
Open in New Tab
</Link>
</li>
</ul>}
</td>
</tr>
);
}
}
AssetListRowBase.propTypes = {
asset: PropTypes.shape({
key: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
sketchId: PropTypes.string,
sketchName: PropTypes.string,
name: PropTypes.string.isRequired
}).isRequired,
deleteAssetRequest: PropTypes.func.isRequired,
username: PropTypes.string.isRequired
};
function mapStateToPropsAssetListRow(state) {
return {
username: state.user.username
};
}
function mapDispatchToPropsAssetListRow(dispatch) {
return bindActionCreators(AssetActions, dispatch);
}
const AssetListRow = connect(mapStateToPropsAssetListRow, mapDispatchToPropsAssetListRow)(AssetListRowBase);
class AssetList extends React.Component {
constructor(props) {
@ -16,10 +151,7 @@ class AssetList extends React.Component {
}
getAssetsTitle() {
if (!this.props.username || this.props.username === this.props.user.username) {
return 'p5.js Web Editor | My assets';
}
return `p5.js Web Editor | ${this.props.username}'s assets`;
return 'p5.js Web Editor | My assets';
}
hasAssets() {
@ -39,10 +171,13 @@ class AssetList extends React.Component {
}
render() {
const username = this.props.username !== undefined ? this.props.username : this.props.user.username;
const { assetList } = this.props;
const { assetList, totalSize } = this.props;
return (
<div className="asset-table-container">
{/* Eventually, this copy should be Total / 250 MB Used */}
{this.hasAssets() && totalSize &&
<p className="asset-table__total">{`${prettyBytes(totalSize)} Total`}</p>
}
<Helmet>
<title>{this.getAssetsTitle()}</title>
</Helmet>
@ -52,24 +187,14 @@ class AssetList extends React.Component {
<table className="asset-table">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Size</th>
<th scope="col">Sketch</th>
<th>Name</th>
<th>Size</th>
<th>Sketch</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{assetList.map(asset =>
(
<tr className="asset-table__row" key={asset.key}>
<th scope="row">
<Link to={asset.url} target="_blank">
{asset.name}
</Link>
</th>
<td>{prettyBytes(asset.size)}</td>
<td><Link to={`/${username}/sketches/${asset.sketchId}`}>{asset.sketchName}</Link></td>
</tr>
))}
{assetList.map(asset => <AssetListRow asset={asset} key={asset.key} />)}
</tbody>
</table>}
</div>
@ -81,7 +206,6 @@ AssetList.propTypes = {
user: PropTypes.shape({
username: PropTypes.string
}).isRequired,
username: PropTypes.string.isRequired,
assetList: PropTypes.arrayOf(PropTypes.shape({
key: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
@ -89,15 +213,20 @@ AssetList.propTypes = {
sketchName: PropTypes.string,
sketchId: PropTypes.string
})).isRequired,
totalSize: PropTypes.number,
getAssets: PropTypes.func.isRequired,
loading: PropTypes.bool.isRequired
};
AssetList.defaultProps = {
totalSize: undefined
};
function mapStateToProps(state) {
return {
user: state.user,
assetList: state.assets.list,
totalSize: state.assets.totalSize,
totalSize: state.user.totalSize,
loading: state.loading
};
}

View File

@ -110,7 +110,7 @@ class Sidebar extends React.Component {
onBlur={this.onBlurComponent}
onFocus={this.onFocusComponent}
>
Add file
Create file
</button>
</li>
<li>
@ -123,7 +123,7 @@ class Sidebar extends React.Component {
onBlur={this.onBlurComponent}
onFocus={this.onFocusComponent}
>
Add file
Upload file
</button>
</li>
</ul>

View File

@ -2,33 +2,54 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import InlineSVG from 'react-inlinesvg';
import FileUploader from './FileUploader';
import { getreachedTotalSizeLimit } from '../selectors/users';
import exitUrl from '../../../images/exit.svg';
class UploadFileModal extends React.Component {
propTypes = {
reachedTotalSizeLimit: PropTypes.bool.isRequired
reachedTotalSizeLimit: PropTypes.bool.isRequired,
closeModal: PropTypes.func.isRequired
}
componentDidMount() {
this.focusOnModal();
}
focusOnModal = () => {
this.modal.focus();
}
render() {
return (
<section className="modal" ref={(element) => { this.modal = element; }}>
{ this.props.reachedTotalSizeLimit &&
<p>
{
`You have reached the size limit for the number of files you can upload to your account.
If you would like to upload more, please remove the ones you aren't using anymore by
looking through your `
}
<Link to="/assets">assets</Link>
{'.'}
</p>
}
{ !this.props.reachedTotalSizeLimit &&
<div>
<FileUploader />
<div className="modal-content">
<div className="modal__header">
<h2 className="modal__title">Upload File</h2>
<button className="modal__exit-button" onClick={this.props.closeModal}>
<InlineSVG src={exitUrl} alt="Close New File Modal" />
</button>
</div>
}
{ this.props.reachedTotalSizeLimit &&
<p>
{
`You have reached the size limit for the number of files you can upload to your account.
If you would like to upload more, please remove the ones you aren't using anymore by
looking through your `
}
<Link to="/assets">assets</Link>
{'.'}
</p>
}
{ !this.props.reachedTotalSizeLimit &&
<div>
<FileUploader />
</div>
}
</div>
</section>
);
}

View File

@ -239,6 +239,8 @@ class IDEView extends React.Component {
newFolder={this.props.newFolder}
user={this.props.user}
owner={this.props.project.owner}
openUploadFileModal={this.props.openUploadFileModal}
closeUploadFileModal={this.props.closeUploadFileModal}
/>
<SplitPane
split="vertical"
@ -578,6 +580,7 @@ IDEView.propTypes = {
showRuntimeErrorWarning: PropTypes.func.isRequired,
hideRuntimeErrorWarning: PropTypes.func.isRequired,
startSketch: PropTypes.func.isRequired,
openUploadFileModal: PropTypes.func.isRequired,
closeUploadFileModal: PropTypes.func.isRequired
};

View File

@ -2,14 +2,15 @@ import * as ActionTypes from '../../../constants';
// 1,000,000 bytes in a MB. can't upload if totalSize is bigger than this.
const initialState = {
list: [],
totalSize: 0
list: []
};
const assets = (state = initialState, action) => {
switch (action.type) {
case ActionTypes.SET_ASSETS:
return { list: action.assets, totalSize: action.totalSize };
return { list: action.assets };
case ActionTypes.DELETE_ASSET:
return { list: state.list.filter(asset => asset.key !== action.key) };
default:
return state;
}

View File

@ -18,7 +18,8 @@ export const getCanUploadMedia = createSelector(
export const getreachedTotalSizeLimit = createSelector(
getTotalSize,
(totalSize) => {
if (totalSize > 250000000) return true;
// if (totalSize > 250000000) return true;
if (totalSize > 1000) return true;
return false;
}
);

View File

@ -9,7 +9,8 @@
max-height: 100%;
border-spacing: 0;
& .sketch-list__dropdown-column {
position: relative;
& .asset-table__dropdown-column {
width: #{60 / $base-font-size}rem;
position: relative;
}
@ -66,3 +67,29 @@
font-size: #{16 / $base-font-size}rem;
padding: #{42 / $base-font-size}rem 0;
}
.asset-table__total {
padding: 0 #{20 / $base-font-size}rem;
position: sticky;
top: 0;
@include themify() {
background-color: getThemifyVariable('background-color');
}
}
.asset-table__dropdown-button {
width:#{25 / $base-font-size}rem;
height:#{25 / $base-font-size}rem;
@include themify() {
& polygon {
fill: getThemifyVariable('dropdown-color');
}
}
}
.asset-table__action-dialogue {
@extend %dropdown-open-right;
top: 63%;
right: calc(100% - 26px);
}