From 6bdf6286c8d68364629fb43ac6aa698becbde44e Mon Sep 17 00:00:00 2001 From: James Date: Sat, 23 Mar 2019 16:11:13 -0400 Subject: [PATCH 1/9] begins Media file type --- demo/Page/Page.config.js | 6 ++ demo/Page/components/Edit/index.js | 7 ++ nodemon.json | 3 +- src/components.js | 3 + src/components/controls/Button/index.js | 40 ++++----- src/components/controls/Button/index.scss | 2 +- src/components/field-types/File/index.js | 28 ------ src/components/field-types/Media/index.js | 53 ++++++++++++ .../field-types/{File => Media}/index.scss | 0 src/components/modules/DragAndDrop/index.js | 85 +++++++++++++++++++ src/components/modules/DragAndDrop/index.scss | 22 +++++ 11 files changed, 199 insertions(+), 50 deletions(-) delete mode 100644 src/components/field-types/File/index.js create mode 100644 src/components/field-types/Media/index.js rename src/components/field-types/{File => Media}/index.scss (100%) create mode 100644 src/components/modules/DragAndDrop/index.js create mode 100644 src/components/modules/DragAndDrop/index.scss diff --git a/demo/Page/Page.config.js b/demo/Page/Page.config.js index 7001a3b7e7..2044f7e373 100644 --- a/demo/Page/Page.config.js +++ b/demo/Page/Page.config.js @@ -19,6 +19,12 @@ export default { height: 100, required: true }, + { + name: 'image', + label: 'Image', + type: 'media', + required: true + }, { name: 'slides', label: 'Slides', diff --git a/demo/Page/components/Edit/index.js b/demo/Page/components/Edit/index.js index 73b2e84e7a..61ecdeb1d0 100644 --- a/demo/Page/components/Edit/index.js +++ b/demo/Page/components/Edit/index.js @@ -8,6 +8,7 @@ import { Form, Input, Textarea, + Media, Group, FormSubmit, Repeater @@ -51,6 +52,12 @@ const Edit = props => { height={100} required /> + + - {this.props.children} - - ); + case 'link': + return ( + + {this.props.children} + + ); - case 'anchor': - return ( - - {this.props.children} - - ); + case 'anchor': + return ( + + {this.props.children} + + ); - default: - return ( - - ); + default: + return ( + + ); } } } diff --git a/src/components/controls/Button/index.scss b/src/components/controls/Button/index.scss index 73a6994cb3..ebca024eb1 100644 --- a/src/components/controls/Button/index.scss +++ b/src/components/controls/Button/index.scss @@ -23,7 +23,7 @@ &.btn-secondary { border: $stroke-width solid $primary; - color: $primary; + color: $black; background: none; &.btn-icon { diff --git a/src/components/field-types/File/index.js b/src/components/field-types/File/index.js deleted file mode 100644 index ba13272ba2..0000000000 --- a/src/components/field-types/File/index.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import { fieldType } from 'payload/components'; - -import './index.scss'; - -const error = 'There was a problem uploading your file.'; - -const validate = () => true; - -const File = props => { - return ( -
- -
- ) -} - -export default fieldType(File, 'file', validate, error); diff --git a/src/components/field-types/Media/index.js b/src/components/field-types/Media/index.js new file mode 100644 index 0000000000..7350327ad7 --- /dev/null +++ b/src/components/field-types/Media/index.js @@ -0,0 +1,53 @@ +import React, { Component } from 'react'; +import { fieldType, DragAndDrop } from 'payload/components'; + +import './index.scss'; + +const error = 'There was a problem uploading your file.'; + +const validate = () => true; + +class Media extends Component { + + constructor(props) { + super(props); + + this.state = { + file: this.props.initialValue + } + + this.inputRef = React.createRef(); + } + + handleDrop = file => { + this.inputRef.current.files = file; + } + + handleSelectFile = () => { + this.inputRef.current.click(); + } + + render() { + return ( +
+ {this.props.label} + + {!this.props.value && + + } +
+ ) + } +} + +export default fieldType(Media, 'media', validate, error); diff --git a/src/components/field-types/File/index.scss b/src/components/field-types/Media/index.scss similarity index 100% rename from src/components/field-types/File/index.scss rename to src/components/field-types/Media/index.scss diff --git a/src/components/modules/DragAndDrop/index.js b/src/components/modules/DragAndDrop/index.js new file mode 100644 index 0000000000..cd72f3391f --- /dev/null +++ b/src/components/modules/DragAndDrop/index.js @@ -0,0 +1,85 @@ +import React, { Component } from 'react'; +import { Button } from 'payload/components'; + +import './index.scss'; + +class DragAndDrop extends Component { + + constructor() { + super(); + + this.state = { + dragging: false + } + + this.dropRef = React.createRef(); + this.dragCounter = 0; + } + + componentDidMount() { + let div = this.dropRef.current + div.addEventListener('dragenter', this.handleDragIn) + div.addEventListener('dragleave', this.handleDragOut) + div.addEventListener('dragover', this.handleDrag) + div.addEventListener('drop', this.handleDrop) + } + + componentWillUnmount() { + let div = this.dropRef.current + div.removeEventListener('dragenter', this.handleDragIn) + div.removeEventListener('dragleave', this.handleDragOut) + div.removeEventListener('dragover', this.handleDrag) + div.removeEventListener('drop', this.handleDrop) + } + + handleDrag = e => { + e.preventDefault(); + e.stopPropagation(); + } + + handleDragIn = e => { + e.preventDefault(); + e.stopPropagation(); + this.dragCounter++; + if (e.dataTransfer.items && e.dataTransfer.items.length > 0) { + this.setState({ dragging: true }) + } + } + + handleDragOut = e => { + e.preventDefault(); + e.stopPropagation(); + this.dragCounter--; + if (this.dragCounter > 0) return; + this.setState({ dragging: false }) + } + + handleDrop = e => { + e.preventDefault(); + e.stopPropagation(); + this.setState({ dragging: false }) + if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { + this.props.handleDrop(e.dataTransfer.files) + e.dataTransfer.clearData() + this.dragCounter = 0 + } + } + + onSelectFile = e => { + e.preventDefault(); + e.stopPropagation(); + this.props.handleSelectFile(); + } + + render() { + return ( +
+ Drag and drop a file here + —or— + +
+ ) + } +} + +export default DragAndDrop; diff --git a/src/components/modules/DragAndDrop/index.scss b/src/components/modules/DragAndDrop/index.scss new file mode 100644 index 0000000000..39679fe3af --- /dev/null +++ b/src/components/modules/DragAndDrop/index.scss @@ -0,0 +1,22 @@ +@import '~payload/scss/styles'; + +.drag-and-drop { + padding: rem(1); + display: flex; + align-items: center; + flex-direction: column; + border: $stroke-width solid $primary; + + &.dragging { + background: rgba($primary, .1); + } + + .or { + @extend %uppercase-label; + display: block; + } + + .btn { + margin: rem(.125) 0 0; + } +} From 1b7f94fdeb0ddad2b50aa7db2326ab21fb1e4e92 Mon Sep 17 00:00:00 2001 From: James Date: Sat, 23 Mar 2019 16:46:59 -0400 Subject: [PATCH 2/9] scaffolds beginning of Media Library --- demo/client/components/Routes.js | 4 +++- src/components.js | 1 + src/components/controls/Button/index.scss | 2 +- src/components/layout/Sidebar/index.js | 14 ++++++++++++-- src/components/layout/Table/index.js | 5 +++-- src/components/modals/asModal/index.js | 0 src/components/modules/SearchableTable/index.js | 5 +++-- src/components/views/MediaLibrary/index.js | 16 ++++++++++++++++ 8 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 src/components/modals/asModal/index.js create mode 100644 src/components/views/MediaLibrary/index.js diff --git a/demo/client/components/Routes.js b/demo/client/components/Routes.js index 5a0f6af3f4..8f4bb3a220 100644 --- a/demo/client/components/Routes.js +++ b/demo/client/components/Routes.js @@ -6,7 +6,8 @@ import { DefaultTemplate, Dashboard, Login, - CreateUser + CreateUser, + MediaLibrary } from 'payload/components'; import Logo from '../components/graphics/Logo'; import Icon from '../components/graphics/Icon'; @@ -22,6 +23,7 @@ const Routes = props => { if (cookies.get('token')) { return ( + diff --git a/src/components.js b/src/components.js index 6a7f758323..ac796bea77 100644 --- a/src/components.js +++ b/src/components.js @@ -64,5 +64,6 @@ export { default as SetSearchParams } from './components/utilities/SetSearchPara export { default as Dashboard } from './components/views/Dashboard'; export { default as Login } from './components/views/Login'; export { default as CreateUser } from './components/views/CreateUser'; +export { default as MediaLibrary } from './components/views/MediaLibrary'; export { default as ListView } from './components/views/collections/List'; export { default as EditView } from './components/views/collections/Edit'; diff --git a/src/components/controls/Button/index.scss b/src/components/controls/Button/index.scss index ebca024eb1..73a6994cb3 100644 --- a/src/components/controls/Button/index.scss +++ b/src/components/controls/Button/index.scss @@ -23,7 +23,7 @@ &.btn-secondary { border: $stroke-width solid $primary; - color: $black; + color: $primary; background: none; &.btn-icon { diff --git a/src/components/layout/Sidebar/index.js b/src/components/layout/Sidebar/index.js index 9dae336b8e..9312b5eda2 100644 --- a/src/components/layout/Sidebar/index.js +++ b/src/components/layout/Sidebar/index.js @@ -37,8 +37,18 @@ const Sidebar = props => { Globals ); diff --git a/src/components/layout/Table/index.js b/src/components/layout/Table/index.js index a62bfd4747..4482a834c1 100644 --- a/src/components/layout/Table/index.js +++ b/src/components/layout/Table/index.js @@ -18,10 +18,11 @@ const Table = props => { return ( {props.columns.map((col, i) => { + const value = col.handler ? col.handler(row[col.key]) : row[col.key]; return ( - {row[col.key] - ? row[col.key] + {value + ? value : } diff --git a/src/components/modals/asModal/index.js b/src/components/modals/asModal/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/components/modules/SearchableTable/index.js b/src/components/modules/SearchableTable/index.js index 559f48f79f..960bdad0aa 100644 --- a/src/components/modules/SearchableTable/index.js +++ b/src/components/modules/SearchableTable/index.js @@ -16,8 +16,9 @@ class SearchableTable extends Component { key: '_id', label: 'ID' }, { - key: 'published', - label: 'Published On' + key: 'createdAt', + label: 'Created At', + handler: time => new Date(time).toDateString() }] } } diff --git a/src/components/views/MediaLibrary/index.js b/src/components/views/MediaLibrary/index.js new file mode 100644 index 0000000000..8da8f88d12 --- /dev/null +++ b/src/components/views/MediaLibrary/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { SetStepNav } from 'payload/components'; + +const MediaLibrary = props => { + + return ( +
+ +

Media Library

+
+ ) +} + +export default MediaLibrary; From 514dbed271a847d2d9393c68b5a89930c7e86423 Mon Sep 17 00:00:00 2001 From: James Date: Sat, 23 Mar 2019 19:16:33 -0400 Subject: [PATCH 3/9] adds modal framework, builds UploadMedia module, but seeing unauthorized --- demo/client/index.html | 20 ++- src/Media/Media.model.js | 10 ++ src/components.js | 5 +- src/components/controls/Button/index.js | 2 +- src/components/controls/Button/index.scss | 29 ++-- src/components/field-types/Media/index.js | 6 +- src/components/modals/asModal/index.js | 106 ++++++++++++ src/components/modals/asModal/index.scss | 21 +++ src/components/modules/DragAndDrop/index.js | 85 ---------- src/components/modules/UploadMedia/index.js | 151 ++++++++++++++++++ .../{DragAndDrop => UploadMedia}/index.scss | 2 +- src/reducers/common.js | 8 - src/scss/styles.scss | 1 + src/scss/z-index.scss | 9 ++ 14 files changed, 338 insertions(+), 117 deletions(-) create mode 100644 src/Media/Media.model.js create mode 100644 src/components/modals/asModal/index.scss delete mode 100644 src/components/modules/DragAndDrop/index.js create mode 100644 src/components/modules/UploadMedia/index.js rename src/components/modules/{DragAndDrop => UploadMedia}/index.scss (94%) create mode 100644 src/scss/z-index.scss diff --git a/demo/client/index.html b/demo/client/index.html index c55bc7b58d..2f76fce509 100644 --- a/demo/client/index.html +++ b/demo/client/index.html @@ -1,11 +1,15 @@ - - - - Payload - - -
- + + + + + Payload + + + +
+
+ + diff --git a/src/Media/Media.model.js b/src/Media/Media.model.js new file mode 100644 index 0000000000..5d76de4c86 --- /dev/null +++ b/src/Media/Media.model.js @@ -0,0 +1,10 @@ +import mongoose from 'mongoose'; + +const MediaSchema = new mongoose.Schema({ + name: { type: String }, + caption: { type: String }, + description: { type: String }, + filename: { type: String } +}); + +export default mongoose.model('Media', MediaSchema); diff --git a/src/components.js b/src/components.js index ac796bea77..6962e7bb1a 100644 --- a/src/components.js +++ b/src/components.js @@ -36,6 +36,9 @@ export { default as ContentBlock } from './components/layout/ContentBlock'; export { default as Table } from './components/layout/Table'; export { default as Section } from './components/layout/Section'; +// Modals +export { default as asModal } from './components/modals/asModal'; + // Modules export { default as Status } from './components/modules/Status'; export { default as StickyHeader } from './components/modules/StickyHeader'; @@ -46,7 +49,7 @@ export { default as StepNav } from './components/modules/StepNav'; export { default as Tooltip } from './components/modules/Tooltip'; export { default as SearchableTable } from './components/modules/SearchableTable'; export { default as Localizer } from './components/modules/Localizer'; -export { default as DragAndDrop } from './components/modules/DragAndDrop'; +export { default as UploadMedia } from './components/modules/UploadMedia'; // Routes diff --git a/src/components/controls/Button/index.js b/src/components/controls/Button/index.js index b2d4cacb8a..5371540f34 100644 --- a/src/components/controls/Button/index.js +++ b/src/components/controls/Button/index.js @@ -33,7 +33,7 @@ class Button extends Component { switch (this.props.el) { case 'link': return ( - + {this.props.children} ); diff --git a/src/components/controls/Button/index.scss b/src/components/controls/Button/index.scss index 73a6994cb3..757ac115a0 100644 --- a/src/components/controls/Button/index.scss +++ b/src/components/controls/Button/index.scss @@ -11,16 +11,6 @@ margin-bottom: rem(1); cursor: pointer; - &.btn-icon { - width: rem(1.5); - height: rem(1.5); - - svg { - width: rem(.75); - height: rem(.75); - } - } - &.btn-secondary { border: $stroke-width solid $primary; color: $primary; @@ -60,6 +50,25 @@ } } + &.btn-icon { + background: none; + padding: 0; + border-radius: 0; + border: 0; + width: rem(1.5); + height: rem(1.5); + + svg { + width: rem(.75); + height: rem(.75); + } + + &:hover { + background: none; + border: 0; + } + } + &:hover { border: 1px solid $primary; background: $primary; diff --git a/src/components/field-types/Media/index.js b/src/components/field-types/Media/index.js index 7350327ad7..902c704b8c 100644 --- a/src/components/field-types/Media/index.js +++ b/src/components/field-types/Media/index.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { fieldType, DragAndDrop } from 'payload/components'; +import { fieldType, UploadMedia } from 'payload/components'; import './index.scss'; @@ -39,11 +39,11 @@ class Media extends Component { ref={this.inputRef} value={this.props.value || ''} onChange={this.props.onChange} - type="file" + type="hidden" id={this.props.id ? this.props.id : this.props.name} name={this.props.name} /> {!this.props.value && - + } ) diff --git a/src/components/modals/asModal/index.js b/src/components/modals/asModal/index.js index e69de29bb2..c29b6c300d 100644 --- a/src/components/modals/asModal/index.js +++ b/src/components/modals/asModal/index.js @@ -0,0 +1,106 @@ +/////////////////////////////////////////////////////// +// Takes a modal component and +// a slug to match against a 'modal' URL param +/////////////////////////////////////////////////////// + +import React, { Component } from 'react'; +import { createPortal } from 'react-dom'; +import { connect } from 'react-redux'; +import { withRouter } from 'react-router'; +import queryString from 'qs'; +import { Close, Button } from 'payload/components'; + +import './index.scss'; + +const mapStateToProps = state => ({ + searchParams: state.common.searchParams +}) + +const asModal = (PassedComponent, modalSlug) => { + + class AsModal extends Component { + + constructor(props) { + super(props); + + this.state = { + open: false, + el: null + } + } + + bindEsc = event => { + if (event.keyCode === 27) { + const params = { ...this.props.searchParams }; + delete params.modal; + + this.props.history.push({ + search: queryString.stringify(params) + }) + } + } + + isOpen = () => { + + // Slug can come from either a HOC or from a prop + const slug = this.props.modalSlug ? this.props.modalSlug : modalSlug; + + if (this.props.searchParams.modal === slug) { + return true; + } + + return false; + } + + componentDidMount() { + document.addEventListener('keydown', this.bindEsc, false); + + if (this.isOpen()) { + this.setState({ open: true }) + } + + // Slug can come from either a HOC or from a prop + const slug = this.props.modalSlug ? this.props.modalSlug : modalSlug; + + this.setState({ + el: document.querySelector(`#${slug}`) + }) + } + + componentWillUnmount() { + document.removeEventListener('keydown', this.bindEsc, false); + } + + componentDidUpdate(prevProps, prevState) { + + let open = this.isOpen(); + + if (open !== prevState.open && open) { + this.setState({ open: true }) + } else if (open !== prevState.open) { + this.setState({ open: false }) + } + } + + render() { + + // Slug can come from either a HOC or from a prop + const slug = this.props.modalSlug ? this.props.modalSlug : modalSlug; + const modalDomNode = document.getElementById('portal'); + + return createPortal( +
+ + +
, + modalDomNode + ); + } + } + + return withRouter(connect(mapStateToProps)(AsModal)); +} + +export default asModal; diff --git a/src/components/modals/asModal/index.scss b/src/components/modals/asModal/index.scss new file mode 100644 index 0000000000..d3d25c9f48 --- /dev/null +++ b/src/components/modals/asModal/index.scss @@ -0,0 +1,21 @@ +@import '~payload/scss/styles'; + +.modal { + transform: translateZ(0); + opacity: 0; + visibility: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: -1; + height: 100vh; + background-color: rgba(white, .96); + + &.open { + opacity: 1; + visibility: visible; + z-index: $z-modal; + } +} diff --git a/src/components/modules/DragAndDrop/index.js b/src/components/modules/DragAndDrop/index.js deleted file mode 100644 index cd72f3391f..0000000000 --- a/src/components/modules/DragAndDrop/index.js +++ /dev/null @@ -1,85 +0,0 @@ -import React, { Component } from 'react'; -import { Button } from 'payload/components'; - -import './index.scss'; - -class DragAndDrop extends Component { - - constructor() { - super(); - - this.state = { - dragging: false - } - - this.dropRef = React.createRef(); - this.dragCounter = 0; - } - - componentDidMount() { - let div = this.dropRef.current - div.addEventListener('dragenter', this.handleDragIn) - div.addEventListener('dragleave', this.handleDragOut) - div.addEventListener('dragover', this.handleDrag) - div.addEventListener('drop', this.handleDrop) - } - - componentWillUnmount() { - let div = this.dropRef.current - div.removeEventListener('dragenter', this.handleDragIn) - div.removeEventListener('dragleave', this.handleDragOut) - div.removeEventListener('dragover', this.handleDrag) - div.removeEventListener('drop', this.handleDrop) - } - - handleDrag = e => { - e.preventDefault(); - e.stopPropagation(); - } - - handleDragIn = e => { - e.preventDefault(); - e.stopPropagation(); - this.dragCounter++; - if (e.dataTransfer.items && e.dataTransfer.items.length > 0) { - this.setState({ dragging: true }) - } - } - - handleDragOut = e => { - e.preventDefault(); - e.stopPropagation(); - this.dragCounter--; - if (this.dragCounter > 0) return; - this.setState({ dragging: false }) - } - - handleDrop = e => { - e.preventDefault(); - e.stopPropagation(); - this.setState({ dragging: false }) - if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { - this.props.handleDrop(e.dataTransfer.files) - e.dataTransfer.clearData() - this.dragCounter = 0 - } - } - - onSelectFile = e => { - e.preventDefault(); - e.stopPropagation(); - this.props.handleSelectFile(); - } - - render() { - return ( -
- Drag and drop a file here - —or— - -
- ) - } -} - -export default DragAndDrop; diff --git a/src/components/modules/UploadMedia/index.js b/src/components/modules/UploadMedia/index.js new file mode 100644 index 0000000000..36c4f85d6d --- /dev/null +++ b/src/components/modules/UploadMedia/index.js @@ -0,0 +1,151 @@ +import React, { Component } from 'react'; +import { createPortal } from 'react-dom'; +import { connect } from 'react-redux'; +import { Button } from 'payload/components'; +import api from 'payload/api'; + +import './index.scss'; + +const mapState = state => ({ + config: state.common.config +}) + +class UploadMedia extends Component { + + constructor() { + super(); + + this.state = { + dragging: false, + selectingFile: false, + files: null + } + + this.dropRef = React.createRef(); + this.dragCounter = 0; + } + + componentDidMount() { + let div = this.dropRef.current + div.addEventListener('dragenter', this.handleDragIn) + div.addEventListener('dragleave', this.handleDragOut) + div.addEventListener('dragover', this.handleDrag) + div.addEventListener('drop', this.handleDrop) + } + + componentWillUnmount() { + let div = this.dropRef.current + div.removeEventListener('dragenter', this.handleDragIn) + div.removeEventListener('dragleave', this.handleDragOut) + div.removeEventListener('dragover', this.handleDrag) + div.removeEventListener('drop', this.handleDrop) + } + + handleDrag = e => { + e.preventDefault(); + e.stopPropagation(); + } + + handleDragIn = e => { + e.preventDefault(); + e.stopPropagation(); + this.dragCounter++; + if (e.dataTransfer.items && e.dataTransfer.items.length > 0) { + this.setState({ dragging: true }) + } + } + + handleDragOut = e => { + e.preventDefault(); + e.stopPropagation(); + this.dragCounter--; + if (this.dragCounter > 0) return; + this.setState({ dragging: false }) + } + + handleDrop = e => { + e.preventDefault(); + e.stopPropagation(); + this.setState({ dragging: false }) + if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { + this.setState({ + files: e.dataTransfer.files, + dragging: false + }) + + e.dataTransfer.clearData(); + this.dragCounter = 0; + } else { + this.setState({ dragging: false }) + } + } + + handleSelectFile = e => { + e.preventDefault(); + e.stopPropagation(); + this.setState({ + selectingFile: true + }) + } + + setSelectingFile = selectingFile => { + this.setState({ selectingFile }) + } + + render() { + return ( +
+ Drag and drop a file here + —or— + + +
+ ) + } +} + +// Need to set up a separate component with a Portal +// to make sure forms are not embedded within other forms +class UploadMediaForm extends Component { + + constructor() { + super(); + this.state = { + submitted: false + } + this.formRef = React.createRef(); + this.inputRef = React.createRef(); + } + + componentDidUpdate(prevProps) { + if (prevProps.files !== this.props.files && this.props.files) { + this.inputRef.current.files = this.props.files; + this.handleSubmit(); + } + + if (prevProps.selectingFile !== this.props.selectingFile && this.props.selectingFile) { + this.inputRef.current.click(); + this.props.setSelectingFile(false); + } + } + + handleSubmit = () => { + const data = new FormData(this.formRef.current); + api.requests.post(`${this.props.config.serverUrl}/upload`, data).then( + res => console.log(res), + err => { + console.warn(err); + } + ); + } + + render() { + return createPortal( +
+ +
, + document.getElementById('portal')) + } +} + +export default connect(mapState)(UploadMedia); diff --git a/src/components/modules/DragAndDrop/index.scss b/src/components/modules/UploadMedia/index.scss similarity index 94% rename from src/components/modules/DragAndDrop/index.scss rename to src/components/modules/UploadMedia/index.scss index 39679fe3af..77b5197946 100644 --- a/src/components/modules/DragAndDrop/index.scss +++ b/src/components/modules/UploadMedia/index.scss @@ -1,6 +1,6 @@ @import '~payload/scss/styles'; -.drag-and-drop { +.upload-media { padding: rem(1); display: flex; align-items: center; diff --git a/src/reducers/common.js b/src/reducers/common.js index ae8322a2fe..e9ea1a69a8 100644 --- a/src/reducers/common.js +++ b/src/reducers/common.js @@ -4,7 +4,6 @@ const defaultState = { windowHeight: 900, viewWidth: false, viewHeight: false, - modalState: false, stepNav: [], locale: null, config: null, @@ -39,13 +38,6 @@ export default (state = defaultState, action) => { viewHeight: action.payload.height }; - case 'SET_MODAL': - - return { - ...state, - modalStatus: action.payload - }; - case 'SET_STEP_NAV': return { diff --git a/src/scss/styles.scss b/src/scss/styles.scss index 75f113806e..11e73da5ae 100644 --- a/src/scss/styles.scss +++ b/src/scss/styles.scss @@ -1,3 +1,4 @@ +@import 'z-index'; @import 'vars'; @import 'structure'; @import 'type'; diff --git a/src/scss/z-index.scss b/src/scss/z-index.scss new file mode 100644 index 0000000000..ec02636df2 --- /dev/null +++ b/src/scss/z-index.scss @@ -0,0 +1,9 @@ +///////////////////////////// +// Z-INDEX CHART +///////////////////////////// + +$z-bg: 10; +$z-page: 20; +$z-footer: 30; +$z-modal: 40; +$z-header: 50; From 2e742189c8202fe3adc63e276ec27b591a1bbd0c Mon Sep 17 00:00:00 2001 From: James Date: Sat, 23 Mar 2019 19:19:30 -0400 Subject: [PATCH 4/9] fixes bug with UploadMediaForm --- src/components/modules/UploadMedia/index.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/components/modules/UploadMedia/index.js b/src/components/modules/UploadMedia/index.js index 36c4f85d6d..13dcb0c78c 100644 --- a/src/components/modules/UploadMedia/index.js +++ b/src/components/modules/UploadMedia/index.js @@ -129,6 +129,21 @@ class UploadMediaForm extends Component { } } + componentDidMount() { + this.inputRef.current.addEventListener('change', e => { + this.props.setSelectingFile(false); + + // If there are files, submit the form + if (this.inputRef.current.files[0]) { + this.handleSubmit(); + } + }, false); + } + + componentWillUnmount() { + this.inputRef.current.removeEventListener('change'); + } + handleSubmit = () => { const data = new FormData(this.formRef.current); api.requests.post(`${this.props.config.serverUrl}/upload`, data).then( From f16b4ae9ad8b08604618f16023f972b9fff16528 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 25 Mar 2019 18:26:01 -0400 Subject: [PATCH 5/9] removes unused deps --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 45cfc7ea7e..a5e396d9ec 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "dotenv": "^6.0.0", "express-fileupload": "^1.1.1-alpha.1", "express-validation": "^1.0.2", - "file-loader": "^1.1.11", "http-status": "^1.2.0", "ignore-styles": "^5.0.1", "image-size": "^0.7.1", From dd95f0a8b0d681bd59ab60c134901942b9cda468 Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Thu, 28 Mar 2019 23:36:12 -0400 Subject: [PATCH 6/9] Populate model on upload --- package.json | 1 + src/controllers/uploads.controller.js | 20 ++++++++++++++++++-- src/{Media => models}/Media.model.js | 2 +- src/routes/uploads.routes.js | 2 +- 4 files changed, 21 insertions(+), 4 deletions(-) rename src/{Media => models}/Media.model.js (88%) diff --git a/package.json b/package.json index 45cfc7ea7e..ab7615dc9b 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "joi": "^13.6.0", "jsonwebtoken": "^8.4.0", "method-override": "^3.0.0", + "mkdirp": "^0.5.1", "passport": "^0.4.0", "passport-jwt": "^4.0.0", "passport-local": "^1.0.0", diff --git a/src/controllers/uploads.controller.js b/src/controllers/uploads.controller.js index 7b82be3901..804929f310 100644 --- a/src/controllers/uploads.controller.js +++ b/src/controllers/uploads.controller.js @@ -1,6 +1,6 @@ import mkdirp from 'mkdirp'; import { resize } from '../../src/utils/imageResizer'; - +import Media from '../models/Media.model'; function upload(req, res, next, config) { if (Object.keys(req.files).length === 0) { @@ -21,7 +21,23 @@ function upload(req, res, next, config) { if (req.files.file.mimetype.split('/')[0] === 'image') { resize(config, req.files.file); } - res.status(200).send('File uploaded.'); + + Media.create({ + name: req.files.file.name, + filename: req.files.file.name + }, (err, result) => { + if (err) + return res.status(500).json({ error: err }); + + return res.status(201) + .json({ + message: 'success', + result: { + id: result.id, + name: result.name + } + }); + }); }) } diff --git a/src/Media/Media.model.js b/src/models/Media.model.js similarity index 88% rename from src/Media/Media.model.js rename to src/models/Media.model.js index 5d76de4c86..7a2e5b836d 100644 --- a/src/Media/Media.model.js +++ b/src/models/Media.model.js @@ -4,7 +4,7 @@ const MediaSchema = new mongoose.Schema({ name: { type: String }, caption: { type: String }, description: { type: String }, - filename: { type: String } + filename: { type: String }, }); export default mongoose.model('Media', MediaSchema); diff --git a/src/routes/uploads.routes.js b/src/routes/uploads.routes.js index a7993ccddf..949665ba44 100644 --- a/src/routes/uploads.routes.js +++ b/src/routes/uploads.routes.js @@ -2,7 +2,7 @@ import express from 'express'; import passport from 'passport'; import uploadsCtrl from '../controllers/uploads.controller'; -const router = new express.Router(); +const router = express.Router(); const uploadRouter = config => { router .route('') From 2623c7d49c263f85b9ec713f23baf78cbfca3360 Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Fri, 29 Mar 2019 17:13:39 -0400 Subject: [PATCH 7/9] Make media a proper model, use /media instead of /uploads --- src/index.js | 4 ++-- src/models/Media.model.js | 5 +++++ src/requestHandlers/query.js | 2 +- .../{uploads.routes.js => media.routes.js} | 16 ++++++++++++++-- 4 files changed, 22 insertions(+), 5 deletions(-) rename src/routes/{uploads.routes.js => media.routes.js} (50%) diff --git a/src/index.js b/src/index.js index e050a6279e..4a58c1bf2b 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,7 @@ import methodOverride from 'method-override'; import jwtStrategy from './auth/jwt'; import User from '../demo/User/User.model'; import fileUpload from 'express-fileupload'; -import assetRoutes from './routes/uploads.routes' +import assetRoutes from './routes/media.routes'; import config from '../demo/payload.config'; import locale from './middleware/locale'; @@ -48,7 +48,7 @@ module.exports = { }); } - options.router.use('/upload', assetRoutes(options.config)); + options.router.use('/media', assetRoutes(options.config)); options.app.use(express.json()); options.app.use(methodOverride('X-HTTP-Method-Override')); diff --git a/src/models/Media.model.js b/src/models/Media.model.js index 7a2e5b836d..77ed1dafeb 100644 --- a/src/models/Media.model.js +++ b/src/models/Media.model.js @@ -1,4 +1,6 @@ import mongoose from 'mongoose'; +import buildQuery from '../plugins/buildQuery'; +import paginate from '../plugins/paginate'; const MediaSchema = new mongoose.Schema({ name: { type: String }, @@ -7,4 +9,7 @@ const MediaSchema = new mongoose.Schema({ filename: { type: String }, }); +MediaSchema.plugin(paginate); +MediaSchema.plugin(buildQuery); + export default mongoose.model('Media', MediaSchema); diff --git a/src/requestHandlers/query.js b/src/requestHandlers/query.js index e682203cf9..dff61082fd 100644 --- a/src/requestHandlers/query.js +++ b/src/requestHandlers/query.js @@ -9,7 +9,7 @@ const query = (req, res) => { return res.json({ ...result, docs: result.docs.map(doc => { - if (req.locale) { + if (req.locale && doc.setLocale) { doc.setLocale(req.locale, req.query['fallback-locale']); } diff --git a/src/routes/uploads.routes.js b/src/routes/media.routes.js similarity index 50% rename from src/routes/uploads.routes.js rename to src/routes/media.routes.js index 949665ba44..453d96aa59 100644 --- a/src/routes/uploads.routes.js +++ b/src/routes/media.routes.js @@ -1,9 +1,15 @@ import express from 'express'; import passport from 'passport'; import uploadsCtrl from '../controllers/uploads.controller'; +import { query } from '../requestHandlers'; +import bindModel from '../middleware/bindModel'; +import Media from '../models/Media.model'; const router = express.Router(); -const uploadRouter = config => { +const mediaRouter = config => { + + router.all('*', bindModel(Media)); + router .route('') .post( @@ -11,7 +17,13 @@ const uploadRouter = config => { (req, res, next) => uploadsCtrl.upload(req, res, next, config) ); + router.route('') + .get( + passport.authenticate('jwt', { session: false }), + query + ); + return router; }; -export default uploadRouter; +export default mediaRouter; From 06c23d195f87e13030facb1d7ee348fa5a2914e3 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 31 Mar 2019 11:52:20 -0400 Subject: [PATCH 8/9] updates naming conventions for Media --- .gitignore | 3 +++ demo/payload.config.json | 4 ++-- src/index.js | 4 ++-- src/routes/media.routes.js | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 4e339c2ca3..2186866682 100644 --- a/.gitignore +++ b/.gitignore @@ -223,3 +223,6 @@ $RECYCLE.BIN/ src/**/*.css demo**/*.css dist + +# Ignore demo/uploads +demo/uploads diff --git a/demo/payload.config.json b/demo/payload.config.json index 70ec289d52..42d4425f10 100644 --- a/demo/payload.config.json +++ b/demo/payload.config.json @@ -24,8 +24,8 @@ "defaultLocale": "en", "fallback": true }, - "staticUrl": "/uploads", - "staticDir": "demo/uploads", + "staticUrl": "/media", + "staticDir": "demo/media", "imageSizes": [ { "name": "tablet", diff --git a/src/index.js b/src/index.js index 4a58c1bf2b..5b95c6db21 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,7 @@ import methodOverride from 'method-override'; import jwtStrategy from './auth/jwt'; import User from '../demo/User/User.model'; import fileUpload from 'express-fileupload'; -import assetRoutes from './routes/media.routes'; +import mediaRoutes from './routes/Media.routes'; import config from '../demo/payload.config'; import locale from './middleware/locale'; @@ -48,7 +48,7 @@ module.exports = { }); } - options.router.use('/media', assetRoutes(options.config)); + options.router.use(options.config.staticUrl, mediaRoutes(options.config)); options.app.use(express.json()); options.app.use(methodOverride('X-HTTP-Method-Override')); diff --git a/src/routes/media.routes.js b/src/routes/media.routes.js index 453d96aa59..d2e13f1f63 100644 --- a/src/routes/media.routes.js +++ b/src/routes/media.routes.js @@ -6,7 +6,7 @@ import bindModel from '../middleware/bindModel'; import Media from '../models/Media.model'; const router = express.Router(); -const mediaRouter = config => { +const mediaRoutes = config => { router.all('*', bindModel(Media)); @@ -26,4 +26,4 @@ const mediaRouter = config => { return router; }; -export default mediaRouter; +export default mediaRoutes; From dc3d88180dd6bf6003d8ee1e2336015545724546 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 9 Apr 2019 18:07:16 -0400 Subject: [PATCH 9/9] adds reference to Author example into Page.config.js --- demo/Page/Page.config.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/demo/Page/Page.config.js b/demo/Page/Page.config.js index 2044f7e373..72dc328e77 100644 --- a/demo/Page/Page.config.js +++ b/demo/Page/Page.config.js @@ -25,6 +25,16 @@ export default { type: 'media', required: true }, + { + name: 'author', + label: 'Written by:', + type: 'reference', + reference: { + to: 'Author', + nested: true, + relationship: 'oneToMany' + } + }, { name: 'slides', label: 'Slides',