Improving interface for media uploads
This commit is contained in:
parent
d14518ac91
commit
9fcc14c8e6
|
@ -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': {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,11 @@ const userActions = {
|
|||
({
|
||||
type: 'UPLOAD_MEDIA_SUBMIT',
|
||||
data: input
|
||||
})
|
||||
}),
|
||||
clearLoadedMedia: () =>
|
||||
({
|
||||
type: 'CLEAR_LOADED_MEDIA'
|
||||
}),
|
||||
}
|
||||
|
||||
export default userActions
|
|
@ -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>
|
|
@ -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
|
|
@ -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())
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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.')
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,15 @@
|
|||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
#note_media_picker {
|
||||
div {
|
||||
width: 100%;
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#editor_top_bar_block {
|
||||
button {
|
||||
width: 100%;
|
||||
|
|
Loading…
Reference in New Issue