Improving interface for media uploads

This commit is contained in:
Alex Hunt 2019-08-10 08:28:32 -07:00
parent d14518ac91
commit 9fcc14c8e6
10 changed files with 88 additions and 24 deletions

View File

@ -13,17 +13,18 @@ sys.path.insert(0,'..')
# Hack to work around ascii encode error
# TODO: Figure out which dependency tries to encode input to ascii
reload(sys)
sys.setdefaultencoding("utf-8")
sys.setdefaultencoding('utf-8')
s3 = boto3.client('s3')
def create_presigned_post():
bucket_name = config.JOYCE_S3_BUCKET
key_name = str(uuid.uuid4())
key_name = 'images/' + str(uuid.uuid4())
response = s3.generate_presigned_post(
bucket_name,
key_name,
ExpiresIn = 3600
ExpiresIn = 3600,
Conditions = [[ 'eq', '$acl', 'public-read' ]],
)
return response
@ -158,19 +159,19 @@ def es_search_text(body):
'from': 0,
'size': 10,
'query': {
"nested": {
"path": "search_text",
"query": {
"bool": {
"must": [
{ "match": { "search_text.text": body}}
'nested': {
'path': 'search_text',
'query': {
'bool': {
'must': [
{ 'match': { 'search_text.text': body}}
]
}
},
"inner_hits": {
"highlight": {
"fields": {
"search_text.text": {}
'inner_hits': {
'highlight': {
'fields': {
'search_text.text': {}
}
}
}

View File

@ -128,7 +128,11 @@ const userActions = {
({
type: 'UPLOAD_MEDIA_SUBMIT',
data: input
})
}),
clearLoadedMedia: () =>
({
type: 'CLEAR_LOADED_MEDIA'
}),
}
export default userActions

View File

@ -29,7 +29,7 @@ export const EditorEditModeRichTextOptions = ({editorState, onToolButtonClick, d
</div>
export const EditorSubmitOptions = ({cancelEdit, onSubmitClick}) =>
<div className='row'>
<div className='row mt-2'>
<div className='submit_option_button col-5'>
<EditorCancelButton onClick={()=>cancelEdit()}/>
</div>
@ -46,4 +46,4 @@ export const EditorAnnotateOptions = ({onNewAnnotationClick, onRemoveAnnotationC
<div className='annotate_option_button col-5 offset-2'>
<AnnotatorRemoveButton onClick={onRemoveAnnotationClick} disabled={removeDisabled} />
</div>
</div>
</div>

View File

@ -0,0 +1,24 @@
import React from 'react'
import { MediaList } from './list'
const NoteMediaPicker = ({media}) =>
<div id='note_media_picker' className='row'>
<div className='col-12'>
<div className="btn-group">
<button className="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
Select Media
</button>
<div className="dropdown-menu">
{media.map(media =>
<div key={media.id}>
<input type="checkbox" />
<div>{media.title}</div>
</div>
)}
</div>
</div>
</div>
</div>
export default NoteMediaPicker

View File

@ -8,10 +8,12 @@ import actions from '../actions'
import DocumentTitle from '../components/documentTitle'
import DocumentTitleInput from '../components/documentTitleInput'
import TagColorPicker from '../components/tagColorPicker'
import NoteMediaPicker from '../components/noteMediaPicker'
import MediaUploadInput from '../components/mediaUploadInput'
import LoadingSpinner from '../components/loadingSpinner'
const EditorEditMode = ({
media,
currentDocument,
docType,
editorState,
@ -22,6 +24,7 @@ const EditorEditMode = ({
onDocumentTitleChange,
onColorPickerInputChange,
onColorSwatchClick,
onClearLoadedMedia,
onMediaInputChange,
onMediaUpload,
cancelEdit,
@ -50,6 +53,9 @@ const EditorEditMode = ({
/>
</EditorTextContentBlock>
<EditorAttributeContentBlock>
{docType === 'notes' &&
<NoteMediaPicker media={media} />
}
{docType === 'tags' &&
<TagColorPicker
input={inputs.colorPicker}
@ -58,7 +64,14 @@ const EditorEditMode = ({
/>
}
{docType === 'media' && inputs.s3Path &&
<p>File uploaded!</p>
<div className='row'>
<div className='col-8'>File uploaded!</div>
<div className='col-2 offset-2'>
<button type='button' onClick={onClearLoadedMedia} className='btn btn-outline-info btn-sm'>
<i className={'fas fa-trash-alt'}></i>
</button>
</div>
</div>
}
{docType === 'media' && !inputs.s3Path &&
<MediaUploadInput input={inputs.uploadFile} onChange={onMediaInputChange} onUpload={onMediaUpload}/>
@ -79,6 +92,7 @@ const EditorEditMode = ({
const mapStateToProps = (state, props) => {
return {
media: state.media,
currentDocument: state.currentDocument,
docType: state.docType,
editorState: state.editorState,
@ -107,6 +121,9 @@ const mapDispatchToProps = dispatch => {
onMediaUpload: input => {
dispatch(actions.uploadMediaInput(input))
},
onClearLoadedMedia: () => {
dispatch(actions.clearLoadedMedia())
},
cancelEdit: () => {
dispatch(actions.cancelEdit())
},

View File

@ -54,8 +54,9 @@ const joyceAPI = store => next => action => {
case 'UPLOAD_TO_S3_REQUEST':
const formData = new FormData()
const url = action.signed_post.url
formData.append('AWSAccessKeyId', action.signed_post.fields.AWSAccessKeyId)
formData.append('key', action.signed_post.fields.key)
formData.append('AWSAccessKeyId', action.signed_post.fields.AWSAccessKeyId)
formData.append('acl', 'public-read')
formData.append('policy', action.signed_post.fields.policy)
formData.append('signature', action.signed_post.fields.signature)
formData.append('file', action.file)

View File

@ -52,7 +52,7 @@ const api = {
return {status: 'error', data: error}
}),
HTTPPostMedia: (url, formData) =>
axios.post(url, formData, {headers: {'Content-Type': 'image/*', 'ACL': 'public-read'}}).then(res=> {
axios.post(url, formData, {headers: {'Content-Type': formData.get('file').type}}).then(res=> {
return {status: 'success', url: url + formData.get('key')}
}).catch(error => {
return {status: 'error', data: error}

View File

@ -9,6 +9,11 @@ export const validateSubmittedDocument = (docType, inputs) => {
errors.push('Please select a valid hex code color.')
}
}
if (docType === 'media') {
if (inputs.s3Path === undefined) {
errors.push('Please upload an image first.')
}
}
if (inputs.documentTitle.length < 1) {
errors.push('Please enter a title.')
}

View File

@ -2,6 +2,7 @@ const initialState = {
documentTitle: '',
search: '',
colorPicker: '',
noteMediaSelection: [],
uploadFile: undefined,
s3Path: undefined
}
@ -10,9 +11,6 @@ const inputs = (state=initialState, action) => {
switch(action.type) {
// Document Title
case 'GET_DOCUMENT_TEXT':
console.log('state', action.state)
console.log('status', action.status)
console.log('docType', action.docType)
if (action.status === 'success' && action.state === 'currentDocument' && ['tags', 'media'].indexOf(action.docType) <= 0 ) {
return {
...state,
@ -76,8 +74,6 @@ const inputs = (state=initialState, action) => {
...state,
uploadFile: action.data
}
default:
return state
// S3 File
case 'UPLOAD_TO_S3_RESPONSE':
if (action.status === 'success') {
@ -86,6 +82,13 @@ const inputs = (state=initialState, action) => {
s3Path: action.url
}
} else { return state }
case 'CLEAR_LOADED_MEDIA':
return {
...state,
s3Path: undefined
}
default:
return state
}
}

View File

@ -13,6 +13,15 @@
font-size: 0.8em;
}
#note_media_picker {
div {
width: 100%;
}
button {
width: 100%;
}
}
#editor_top_bar_block {
button {
width: 100%;