From 6750c975bc9217e23be75c2d6fd2687e376b66d4 Mon Sep 17 00:00:00 2001 From: Vaclav Klecanda Date: Fri, 21 Jul 2017 14:36:53 +0200 Subject: [PATCH 1/7] uploads into separate folders --- docs/quick-start.md | 10 ++++++++++ src/components/Widgets/FileControl.js | 2 +- src/components/Widgets/ImageControl.js | 2 +- src/valueObjects/AssetProxy.js | 21 ++++++++++++--------- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/docs/quick-start.md b/docs/quick-start.md index d2943745c7fb..dd9a700d3f21 100755 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -110,6 +110,16 @@ This configuration adds a new setting, `public_folder`. While `media_folder` spe >If `public_folder` is not set, Netlify CMS will default to the same value as `media_folder`, adding an opening `/` if one is not included. +The same settings can be applied on Image/File widget if you store your file in different folders. +E.g. you have cover images for your posts in assets/postcovers folder so you just add __media_folder__ and __public_folder__ to your post image widged conf. +It would then look like this: + +``` +... + - {label: "Cover Image", name: "image", widget: "image", media_folder: "assets/postcovers", public_folder: "/assets/postcovers"} +... +``` + ### Collections Collections define the structure for the different content types on your static site. Since every site is different, the `collections` settings will be very different from one site to the next. Let's say your site has a blog, with the posts stored in `_posts/blog`, and files saved in a date-title format, like `1999-12-31-lets-party.md`. Each post begins with settings in yaml-formatted front matter, like so: diff --git a/src/components/Widgets/FileControl.js b/src/components/Widgets/FileControl.js index 468b41074253..2d0d98b1eea4 100644 --- a/src/components/Widgets/FileControl.js +++ b/src/components/Widgets/FileControl.js @@ -53,7 +53,7 @@ export default class FileControl extends React.Component { this.props.onRemoveAsset(this.props.value); if (file) { this.setState({ processing: true }); - this.promise = createAssetProxy(file.name, file, false, this.props.field.get('private', false)) + this.promise = createAssetProxy(file.name, file, false, this.props.field) .then((assetProxy) => { this.setState({ processing: false }); this.props.onAddAsset(assetProxy); diff --git a/src/components/Widgets/ImageControl.js b/src/components/Widgets/ImageControl.js index cd8fb46b4637..cfaf236b81c1 100644 --- a/src/components/Widgets/ImageControl.js +++ b/src/components/Widgets/ImageControl.js @@ -57,7 +57,7 @@ export default class ImageControl extends React.Component { this.props.onRemoveAsset(this.props.value); if (file) { this.setState({ processing: true }); - this.promise = createAssetProxy(file.name, file) + this.promise = createAssetProxy(file.name, file, false, this.props.field) .then((assetProxy) => { this.setState({ processing: false }); this.props.onAddAsset(assetProxy); diff --git a/src/valueObjects/AssetProxy.js b/src/valueObjects/AssetProxy.js index e88b2c1b0f36..231ced4a8ecf 100644 --- a/src/valueObjects/AssetProxy.js +++ b/src/valueObjects/AssetProxy.js @@ -8,14 +8,16 @@ export const setStore = (storeObj) => { store = storeObj; }; -export default function AssetProxy(value, fileObj, uploaded = false) { +export default function AssetProxy(value, fileObj, uploaded = false, field_config = null) { const config = store.getState().config; + const media_folder = field_config && field_config.has('media_folder') ? field_config.get('media_folder') : config.get('media_folder'); + const public_folder = field_config && field_config.has('public_folder') ? field_config.get('public_folder') : '/' + media_folder; this.value = value; this.fileObj = fileObj; this.uploaded = uploaded; this.sha = null; - this.path = config.get('media_folder') && !uploaded ? resolvePath(value, config.get('media_folder')) : value; - this.public_path = !uploaded ? resolvePath(value, config.get('public_folder')) : value; + this.path = media_folder && !uploaded ? resolvePath(value, media_folder) : value; + this.public_path = !uploaded ? resolvePath(value, public_folder) : value; } AssetProxy.prototype.toString = function () { @@ -39,20 +41,21 @@ AssetProxy.prototype.toBase64 = function () { }); }; -export function createAssetProxy(value, fileObj, uploaded = false, privateUpload = false) { +export function createAssetProxy(value, fileObj, uploaded = false, field_config = null) { const state = store.getState(); + const privateUpload = field_config ? field_config.get('private', false) : false; const integration = selectIntegration(state, null, 'assetStore'); if (integration && !uploaded) { const provider = integration && getIntegrationProvider(state.integrations, currentBackend(state.config).getToken, integration); return provider.upload(fileObj, privateUpload).then( response => ( - new AssetProxy(response.assetURL.replace(/^(https?):/, ''), null, true) + new AssetProxy(response.assetURL.replace(/^(https?):/, ''), null, true, field_config) ), - error => new AssetProxy(value, fileObj, false) - ); + error => new AssetProxy(value, fileObj, false, field_config) + ); } else if (privateUpload) { throw new Error('The Private Upload option is only avaible for Asset Store Integration'); } - - return Promise.resolve(new AssetProxy(value, fileObj, uploaded)); + + return Promise.resolve(new AssetProxy(value, fileObj, uploaded, field_config)); } From db0555d5171ab8c06b58a073fb4d19f75de1d7b4 Mon Sep 17 00:00:00 2001 From: Vaclav Klecanda Date: Sat, 22 Jul 2017 08:48:32 +0200 Subject: [PATCH 2/7] field_config -> config --- src/valueObjects/AssetProxy.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/valueObjects/AssetProxy.js b/src/valueObjects/AssetProxy.js index 231ced4a8ecf..833810dcb625 100644 --- a/src/valueObjects/AssetProxy.js +++ b/src/valueObjects/AssetProxy.js @@ -8,10 +8,10 @@ export const setStore = (storeObj) => { store = storeObj; }; -export default function AssetProxy(value, fileObj, uploaded = false, field_config = null) { +export default function AssetProxy(value, fileObj, uploaded = false, field = null) { const config = store.getState().config; - const media_folder = field_config && field_config.has('media_folder') ? field_config.get('media_folder') : config.get('media_folder'); - const public_folder = field_config && field_config.has('public_folder') ? field_config.get('public_folder') : '/' + media_folder; + const media_folder = (field && field.has('media_folder')) ? field.get('media_folder') : config.get('media_folder'); + const public_folder = (field && field.has('public_folder')) ? field.get('public_folder') : '/' + media_folder; this.value = value; this.fileObj = fileObj; this.uploaded = uploaded; @@ -41,21 +41,21 @@ AssetProxy.prototype.toBase64 = function () { }); }; -export function createAssetProxy(value, fileObj, uploaded = false, field_config = null) { +export function createAssetProxy(value, fileObj, uploaded = false, field = null) { const state = store.getState(); - const privateUpload = field_config ? field_config.get('private', false) : false; + const privateUpload = field ? field.get('private', false) : false; const integration = selectIntegration(state, null, 'assetStore'); if (integration && !uploaded) { const provider = integration && getIntegrationProvider(state.integrations, currentBackend(state.config).getToken, integration); return provider.upload(fileObj, privateUpload).then( response => ( - new AssetProxy(response.assetURL.replace(/^(https?):/, ''), null, true, field_config) + new AssetProxy(response.assetURL.replace(/^(https?):/, ''), null, true, field) ), - error => new AssetProxy(value, fileObj, false, field_config) + error => new AssetProxy(value, fileObj, false, field) ); } else if (privateUpload) { throw new Error('The Private Upload option is only avaible for Asset Store Integration'); } - return Promise.resolve(new AssetProxy(value, fileObj, uploaded, field_config)); + return Promise.resolve(new AssetProxy(value, fileObj, uploaded, field)); } From 99fe8eabc8314296f1ee63d58e3cc7a5e1136c59 Mon Sep 17 00:00:00 2001 From: Vaclav Klecanda Date: Sat, 22 Jul 2017 08:55:34 +0200 Subject: [PATCH 3/7] Image/File Widget section --- docs/widgets.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/widgets.md b/docs/widgets.md index 4f4d484540fe..b2eb2fc39d22 100644 --- a/docs/widgets.md +++ b/docs/widgets.md @@ -61,3 +61,14 @@ collections: searchFields: [name, twitterHandle] valueField: name ``` + +### Image/File Widget + +If you store your files in different folders e.g. cover images for your posts in **assets/postcovers** folder you can add __media_folder__ and __public_folder__ to your widged conf allowing the media go into appropriate folder. +It would then look like this: + +``` +... + - {label: "Cover Image", name: "image", widget: "image", media_folder: "assets/postcovers", public_folder: "/assets/postcovers"} +... +``` From 44d39f432227eab5268a6d490d889d4a38a4c876 Mon Sep 17 00:00:00 2001 From: Vaclav Klecanda Date: Sat, 22 Jul 2017 08:57:17 +0200 Subject: [PATCH 4/7] Removed what has been moved to widget doc --- docs/quick-start.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/docs/quick-start.md b/docs/quick-start.md index dd9a700d3f21..8bcd6dcb322d 100755 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -110,15 +110,7 @@ This configuration adds a new setting, `public_folder`. While `media_folder` spe >If `public_folder` is not set, Netlify CMS will default to the same value as `media_folder`, adding an opening `/` if one is not included. -The same settings can be applied on Image/File widget if you store your file in different folders. -E.g. you have cover images for your posts in assets/postcovers folder so you just add __media_folder__ and __public_folder__ to your post image widged conf. -It would then look like this: - -``` -... - - {label: "Cover Image", name: "image", widget: "image", media_folder: "assets/postcovers", public_folder: "/assets/postcovers"} -... -``` +The same settings can be applied on [Image/File widget](../widgets#imagefile-widget) if you store your file in different folders. ### Collections Collections define the structure for the different content types on your static site. Since every site is different, the `collections` settings will be very different from one site to the next. Let's say your site has a blog, with the posts stored in `_posts/blog`, and files saved in a date-title format, like `1999-12-31-lets-party.md`. Each post From b9870a44b722bc99e9404eb99e05a78c2dd5d834 Mon Sep 17 00:00:00 2001 From: Shawn Erquhart Date: Mon, 24 Jul 2017 12:38:39 -0400 Subject: [PATCH 5/7] remove `field` refs from AssetProxy --- src/components/Widgets/FileControl.js | 7 ++++++- src/components/Widgets/ImageControl.js | 6 +++++- src/valueObjects/AssetProxy.js | 17 +++++++++-------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/components/Widgets/FileControl.js b/src/components/Widgets/FileControl.js index 2d0d98b1eea4..ccd019b5f1bb 100644 --- a/src/components/Widgets/FileControl.js +++ b/src/components/Widgets/FileControl.js @@ -46,6 +46,11 @@ export default class FileControl extends React.Component { const fileList = e.dataTransfer ? e.dataTransfer.files : e.target.files; const files = [...fileList]; const imageType = /^image\//; + const assetProxyOpts = { + isPrivate: this.props.field.get('private', false), + mediaFolder: this.props.field.get('media_folder'), + publicFolder: this.props.field.get('public_folder'), + }; // Return the first file on the list const file = files[0]; @@ -53,7 +58,7 @@ export default class FileControl extends React.Component { this.props.onRemoveAsset(this.props.value); if (file) { this.setState({ processing: true }); - this.promise = createAssetProxy(file.name, file, false, this.props.field) + this.promise = createAssetProxy(file.name, file, false, assetProxyOpts) .then((assetProxy) => { this.setState({ processing: false }); this.props.onAddAsset(assetProxy); diff --git a/src/components/Widgets/ImageControl.js b/src/components/Widgets/ImageControl.js index cfaf236b81c1..3567150511ed 100644 --- a/src/components/Widgets/ImageControl.js +++ b/src/components/Widgets/ImageControl.js @@ -46,6 +46,10 @@ export default class ImageControl extends React.Component { const fileList = e.dataTransfer ? e.dataTransfer.files : e.target.files; const files = [...fileList]; const imageType = /^image\//; + const assetProxyOpts = { + mediaFolder: this.props.field.get('media_folder'), + publicFolder: this.props.field.get('public_folder'), + }; // Iterate through the list of files and return the first image on the list const file = files.find((currentFile) => { @@ -57,7 +61,7 @@ export default class ImageControl extends React.Component { this.props.onRemoveAsset(this.props.value); if (file) { this.setState({ processing: true }); - this.promise = createAssetProxy(file.name, file, false, this.props.field) + this.promise = createAssetProxy(file.name, file, false, assetProxyOpts) .then((assetProxy) => { this.setState({ processing: false }); this.props.onAddAsset(assetProxy); diff --git a/src/valueObjects/AssetProxy.js b/src/valueObjects/AssetProxy.js index 833810dcb625..ca07611cbcea 100644 --- a/src/valueObjects/AssetProxy.js +++ b/src/valueObjects/AssetProxy.js @@ -8,16 +8,16 @@ export const setStore = (storeObj) => { store = storeObj; }; -export default function AssetProxy(value, fileObj, uploaded = false, field = null) { +export default function AssetProxy(value, fileObj, uploaded = false, opts = {}) { const config = store.getState().config; - const media_folder = (field && field.has('media_folder')) ? field.get('media_folder') : config.get('media_folder'); - const public_folder = (field && field.has('public_folder')) ? field.get('public_folder') : '/' + media_folder; + const mediaFolder = opts.mediaFolder || config.get('media_folder'); + const publicFolder = opts.mediaFolder || config.get('public_folder'); this.value = value; this.fileObj = fileObj; this.uploaded = uploaded; this.sha = null; - this.path = media_folder && !uploaded ? resolvePath(value, media_folder) : value; - this.public_path = !uploaded ? resolvePath(value, public_folder) : value; + this.path = mediaFolder && !uploaded ? resolvePath(value, mediaFolder) : value; + this.public_path = !uploaded ? resolvePath(value, publicFolder) : value; } AssetProxy.prototype.toString = function () { @@ -41,15 +41,16 @@ AssetProxy.prototype.toBase64 = function () { }); }; -export function createAssetProxy(value, fileObj, uploaded = false, field = null) { +export function createAssetProxy(value, fileObj, uploaded = false, opts = {}) { const state = store.getState(); - const privateUpload = field ? field.get('private', false) : false; + const privateUpload = opts.isPrivate || false; + const assetProxyOpts = { mediaFolder: opts.mediaFolder, publicFolder: opts.publicFolder }; const integration = selectIntegration(state, null, 'assetStore'); if (integration && !uploaded) { const provider = integration && getIntegrationProvider(state.integrations, currentBackend(state.config).getToken, integration); return provider.upload(fileObj, privateUpload).then( response => ( - new AssetProxy(response.assetURL.replace(/^(https?):/, ''), null, true, field) + new AssetProxy(response.assetURL.replace(/^(https?):/, ''), null, true, assetProxyOpts) ), error => new AssetProxy(value, fileObj, false, field) ); From 414fb7657b1d342640fe1cecc1fe882207cc36a1 Mon Sep 17 00:00:00 2001 From: Shawn Erquhart Date: Mon, 24 Jul 2017 12:49:14 -0400 Subject: [PATCH 6/7] improve media folder config docs --- docs/quick-start.md | 2 +- docs/widgets.md | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/quick-start.md b/docs/quick-start.md index 8bcd6dcb322d..d3e1ac6cb1ed 100755 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -110,7 +110,7 @@ This configuration adds a new setting, `public_folder`. While `media_folder` spe >If `public_folder` is not set, Netlify CMS will default to the same value as `media_folder`, adding an opening `/` if one is not included. -The same settings can be applied on [Image/File widget](../widgets#imagefile-widget) if you store your file in different folders. +The `media_folder` and `public_folder` settings can also be applied for individual [Image and File widgets](widgets#imagefile-widget). ### Collections Collections define the structure for the different content types on your static site. Since every site is different, the `collections` settings will be very different from one site to the next. Let's say your site has a blog, with the posts stored in `_posts/blog`, and files saved in a date-title format, like `1999-12-31-lets-party.md`. Each post diff --git a/docs/widgets.md b/docs/widgets.md index b2eb2fc39d22..7db095ae5a36 100644 --- a/docs/widgets.md +++ b/docs/widgets.md @@ -64,11 +64,12 @@ collections: ### Image/File Widget -If you store your files in different folders e.g. cover images for your posts in **assets/postcovers** folder you can add __media_folder__ and __public_folder__ to your widged conf allowing the media go into appropriate folder. -It would then look like this: +If you store your images and files in different folders, you can add `media_folder` and `public_folder` properties to the widget configuration: -``` -... - - {label: "Cover Image", name: "image", widget: "image", media_folder: "assets/postcovers", public_folder: "/assets/postcovers"} -... +```yaml + - label: Image + name: image + widget: image + media_folder: repo/path/to/assets + public_folder: /public/path/to/assets ``` From 54bbb7f996f9f943bd90d89eaa35afef4d0a4795 Mon Sep 17 00:00:00 2001 From: Vaclav Klecanda Date: Mon, 24 Jul 2017 20:42:08 +0200 Subject: [PATCH 7/7] fixes --- src/valueObjects/AssetProxy.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/valueObjects/AssetProxy.js b/src/valueObjects/AssetProxy.js index ca07611cbcea..1474ae926e1e 100644 --- a/src/valueObjects/AssetProxy.js +++ b/src/valueObjects/AssetProxy.js @@ -11,7 +11,7 @@ export const setStore = (storeObj) => { export default function AssetProxy(value, fileObj, uploaded = false, opts = {}) { const config = store.getState().config; const mediaFolder = opts.mediaFolder || config.get('media_folder'); - const publicFolder = opts.mediaFolder || config.get('public_folder'); + const publicFolder = opts.publicFolder || config.get('public_folder'); this.value = value; this.fileObj = fileObj; this.uploaded = uploaded; @@ -44,7 +44,10 @@ AssetProxy.prototype.toBase64 = function () { export function createAssetProxy(value, fileObj, uploaded = false, opts = {}) { const state = store.getState(); const privateUpload = opts.isPrivate || false; - const assetProxyOpts = { mediaFolder: opts.mediaFolder, publicFolder: opts.publicFolder }; + const assetProxyOpts = { + mediaFolder: opts.mediaFolder, + publicFolder: opts.publicFolder + }; const integration = selectIntegration(state, null, 'assetStore'); if (integration && !uploaded) { const provider = integration && getIntegrationProvider(state.integrations, currentBackend(state.config).getToken, integration); @@ -52,11 +55,11 @@ export function createAssetProxy(value, fileObj, uploaded = false, opts = {}) { response => ( new AssetProxy(response.assetURL.replace(/^(https?):/, ''), null, true, assetProxyOpts) ), - error => new AssetProxy(value, fileObj, false, field) + error => new AssetProxy(value, fileObj, false, assetProxyOpts) ); } else if (privateUpload) { throw new Error('The Private Upload option is only avaible for Asset Store Integration'); } - return Promise.resolve(new AssetProxy(value, fileObj, uploaded, field)); + return Promise.resolve(new AssetProxy(value, fileObj, uploaded, assetProxyOpts)); }