diff --git a/example/config.yml b/example/config.yml
index a930e59b..3d5f55bf 100644
--- a/example/config.yml
+++ b/example/config.yml
@@ -37,13 +37,6 @@ collections: # A list of collections the CMS should be able to edit
description: "General Site Settings"
fields:
- {label: "Global title", name: site_title, widget: "string"}
- - label: "Post Settings"
- name: posts
- widget: "object"
- fields:
- - {label: "Number of posts on frontpage", name: front_limit, widget: number}
- - {label: "Default Author", name: author, widget: string}
- - {label: "Default Thumbnail", name: thumb, widget: image, class: "thumb"}
- name: "authors"
label: "Authors"
diff --git a/example/index.html b/example/index.html
index cbf4ef07..3edb2778 100644
--- a/example/index.html
+++ b/example/index.html
@@ -30,7 +30,7 @@
},
_data: {
"settings.json": {
- content: '{"site_title": "CMS Demo", "posts": {"front_limit": 5, "author": "Matt Biilmann"}}'
+ content: '{"site_title": "CMS Demo"}'
},
"authors.yml": {
content: 'authors:\n - name: Mathias\n description: Co-founder @ Netlify\n'
diff --git a/src/backends/backend.js b/src/backends/backend.js
index 6c6bb778..5d566cba 100644
--- a/src/backends/backend.js
+++ b/src/backends/backend.js
@@ -3,6 +3,7 @@ import GitHubBackend from './github/implementation';
import NetlifyGitBackend from './netlify-git/implementation';
import { resolveFormat } from '../formats/formats';
import { createEntry } from '../valueObjects/Entry';
+import { FILES, FOLDER } from '../constants/collectionTypes';
class LocalStorageAuthStore {
storageKey = 'nf-cms-user';
@@ -18,15 +19,15 @@ class LocalStorageAuthStore {
}
const slugFormatter = (template, entryData) => {
- var date = new Date();
- return template.replace(/\{\{([^\}]+)\}\}/g, function(_, name) {
+ const date = new Date();
+ return template.replace(/\{\{([^\}]+)\}\}/g, (_, name) => {
switch (name) {
case 'year':
return date.getFullYear();
case 'month':
- return ('0' + (date.getMonth() + 1)).slice(-2);
+ return (`0${ date.getMonth() + 1 }`).slice(-2);
case 'day':
- return ('0' + date.getDate()).slice(-2);
+ return (`0${ date.getDate() }`).slice(-2);
case 'slug':
const identifier = entryData.get('title', entryData.get('path'));
return identifier.trim().toLowerCase().replace(/[^a-z0-9\.\-\_]+/gi, '-');
@@ -65,13 +66,31 @@ class Backend {
});
}
- listEntries(collection, page, perPage) {
- return this.implementation.entries(collection, page, perPage).then((response) => {
- return {
- pagination: response.pagination,
- entries: response.entries.map(this.entryWithFormat(collection))
- };
- });
+ listEntries(collection) {
+ const type = collection.get('type');
+ if (type === FOLDER) {
+ return this.implementation.entriesByFolder(collection)
+ .then(loadedEntries => (
+ loadedEntries.map(loadedEntry => createEntry(collection.get('name'), loadedEntry.file.path.split('/').pop().replace(/\.[^\.]+$/, ''), loadedEntry.file.path, { raw: loadedEntry.data }))
+ ))
+ .then(entries => (
+ {
+ entries: entries.map(this.entryWithFormat(collection)),
+ }
+ ));
+ } else if (type === FILES) {
+ const collectionFiles = collection.get('files').map(collectionFile => ({ path: collectionFile.get('file'), label: collectionFile.get('label') }));
+ return this.implementation.entriesByFiles(collection, collectionFiles)
+ .then(loadedEntries => (
+ loadedEntries.map(loadedEntry => createEntry(collection.get('name'), loadedEntry.file.path.split('/').pop().replace(/\.[^\.]+$/, ''), loadedEntry.file.path, { raw: loadedEntry.data, label: loadedEntry.file.label }))
+ ))
+ .then(entries => (
+ {
+ entries: entries.map(this.entryWithFormat(collection)),
+ }
+ ));
+ }
+ return Promise.reject(`Couldn't process collection type ${ type }`);
}
// We have the file path. Fetch and parse the file.
@@ -82,12 +101,19 @@ class Backend {
// Will fetch the whole list of files from GitHub and load each file, then looks up for entry.
// (Files are persisted in local storage - only expensive on the first run for each file).
lookupEntry(collection, slug) {
- return this.implementation.lookupEntry(collection, slug).then(this.entryWithFormat(collection));
+ const type = collection.get('type');
+ if (type === FOLDER) {
+ return this.implementation.entriesByFolder(collection)
+ .then(loadedEntries => (
+ loadedEntries.map(loadedEntry => createEntry(collection.get('name'), loadedEntry.file.path.split('/').pop().replace(/\.[^\.]+$/, ''), loadedEntry.file.path, { raw: loadedEntry.data }))
+ ))
+ .then(response => response.filter(entry => entry.slug === slug)[0])
+ .then(this.entryWithFormat(collection));
+ }
}
newEntry(collection) {
- const newEntry = createEntry();
- return this.entryWithFormat(collection)(newEntry);
+ return createEntry(collection.get('name'));
}
entryWithFormat(collectionOrEntity) {
@@ -95,8 +121,10 @@ class Backend {
const format = resolveFormat(collectionOrEntity, entry);
if (entry && entry.raw) {
entry.data = format && format.fromFile(entry.raw);
+ return entry;
+ } else {
+ return format.fromFile(entry);
}
- return entry;
};
}
@@ -104,7 +132,7 @@ class Backend {
return this.implementation.unpublishedEntries(page, perPage).then((response) => {
return {
pagination: response.pagination,
- entries: response.entries.map(this.entryWithFormat('editorialWorkflow'))
+ entries: response.entries.map(this.entryWithFormat('editorialWorkflow')),
};
});
}
@@ -126,28 +154,28 @@ class Backend {
if (newEntry) {
const slug = slugFormatter(collection.get('slug'), entryDraft.getIn(['entry', 'data']));
entryObj = {
- path: `${collection.get('folder')}/${slug}.md`,
- slug: slug,
- raw: this.entryToRaw(collection, entryData)
+ path: `${ collection.get('folder') }/${ slug }.md`,
+ slug,
+ raw: this.entryToRaw(collection, entryData),
};
} else {
entryObj = {
path: entryDraft.getIn(['entry', 'path']),
slug: entryDraft.getIn(['entry', 'slug']),
- raw: this.entryToRaw(collection, entryData)
+ raw: this.entryToRaw(collection, entryData),
};
}
- const commitMessage = (newEntry ? 'Created ' : 'Updated ') +
- collection.get('label') + ' “' +
- entryDraft.getIn(['entry', 'data', 'title']) + '”';
+ const commitMessage = `${ (newEntry ? 'Created ' : 'Updated ') +
+ collection.get('label') } “${
+ entryDraft.getIn(['entry', 'data', 'title']) }”`;
const mode = config.get('publish_mode');
const collectionName = collection.get('name');
return this.implementation.persistEntry(entryObj, MediaFiles, {
- newEntry, parsedData, commitMessage, collectionName, mode, ...options
+ newEntry, parsedData, commitMessage, collectionName, mode, ...options,
});
}
@@ -186,11 +214,11 @@ export function resolveBackend(config) {
case 'netlify-git':
return new Backend(new NetlifyGitBackend(config, slugFormatter), authStore);
default:
- throw `Backend not found: ${name}`;
+ throw `Backend not found: ${ name }`;
}
}
-export const currentBackend = (function() {
+export const currentBackend = (function () {
let backend = null;
return (config) => {
@@ -199,4 +227,4 @@ export const currentBackend = (function() {
return backend = resolveBackend(config);
}
};
-})();
+}());
diff --git a/src/backends/github/API.js b/src/backends/github/API.js
index 645bd4d3..31efefbb 100644
--- a/src/backends/github/API.js
+++ b/src/backends/github/API.js
@@ -112,13 +112,14 @@ export default class API {
const cache = LocalForage.getItem(`gh.meta.${ key }`);
return cache.then((cached) => {
if (cached && cached.expires > Date.now()) { return cached.data; }
-
+ console.log("%c Checking for MetaData files", "line-height: 30px;text-align: center;font-weight: bold"); // eslint-disable-line
return this.request(`${ this.repoURL }/contents/${ key }.json`, {
params: { ref: 'refs/meta/_netlify_cms' },
headers: { Accept: 'application/vnd.github.VERSION.raw' },
cache: 'no-store',
})
- .then(response => JSON.parse(response));
+ .then(response => JSON.parse(response))
+ .catch(error => console.log("%c %s does not have metadata", "line-height: 30px;text-align: center;font-weight: bold", key)); // eslint-disable-line
});
}
diff --git a/src/backends/github/implementation.js b/src/backends/github/implementation.js
index 78a6d7d5..7283cf81 100644
--- a/src/backends/github/implementation.js
+++ b/src/backends/github/implementation.js
@@ -31,33 +31,30 @@ export default class GitHub {
});
}
- entries(collection) {
- return this.api.listFiles(collection.get('folder')).then((files) => {
- const sem = semaphore(MAX_CONCURRENT_DOWNLOADS);
- const promises = [];
- files.map((file) => {
- promises.push(new Promise((resolve, reject) => {
- return sem.take(() => this.api.readFile(file.path, file.sha).then((data) => {
- resolve(createEntry(collection.get('name'), file.path.split('/').pop().replace(/\.[^\.]+$/, ''), file.path, { raw: data }));
- sem.leave();
- }).catch((err) => {
- sem.leave();
- reject(err);
- }));
- }));
- });
- return Promise.all(promises);
- }).then(entries => ({
- entries,
- }));
+ entriesByFolder(collection) {
+ return this.api.listFiles(collection.get('folder')).then(files => this.entriesByFiles(collection, files));
}
-
- // Will fetch the entire list of entries from github.
- lookupEntry(collection, slug) {
- return this.entries(collection).then(response => (
- response.entries.filter(entry => entry.slug === slug)[0]
- ));
+ entriesByFiles(collection, files) {
+ const sem = semaphore(MAX_CONCURRENT_DOWNLOADS);
+ const promises = [];
+ files.forEach((file) => {
+ promises.push(new Promise((resolve, reject) => {
+ return sem.take(() => this.api.readFile(file.path, file.sha).then((data) => {
+ resolve(
+ {
+ file,
+ data,
+ }
+ );
+ sem.leave();
+ }).catch((err) => {
+ sem.leave();
+ reject(err);
+ }));
+ }));
+ });
+ return Promise.all(promises);
}
// Fetches a single entry.
diff --git a/src/backends/test-repo/implementation.js b/src/backends/test-repo/implementation.js
index e0f9182e..d2e8ec84 100644
--- a/src/backends/test-repo/implementation.js
+++ b/src/backends/test-repo/implementation.js
@@ -24,18 +24,25 @@ export default class TestRepo {
return Promise.resolve({ email: state.email });
}
- entries(collection) {
+ entriesByFolder(collection) {
const entries = [];
const folder = collection.get('folder');
if (folder) {
for (const path in window.repoFiles[folder]) {
- entries.push(createEntry(collection.get('name'), getSlug(path), `${ folder }/${ path }`, { raw: window.repoFiles[folder][path].content }));
+ const file = { path: `${ folder }/${ path }` };
+ entries.push(
+ {
+ file,
+ data: window.repoFiles[folder][path].content,
+ }
+ );
}
}
+ return Promise.resolve(entries);
+ }
- return Promise.resolve({
- entries,
- });
+ entriesByFiles(collection, files) {
+ throw new Error('Not implemented yet');
}
lookupEntry(collection, slug) {
diff --git a/src/components/ControlPanel/ControlPane.js b/src/components/ControlPanel/ControlPane.js
index 10692cdf..4f8a96f3 100644
--- a/src/components/ControlPanel/ControlPane.js
+++ b/src/components/ControlPanel/ControlPane.js
@@ -6,7 +6,7 @@ import styles from './ControlPane.css';
export default class ControlPane extends Component {
controlFor(field) {
- const { entry, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
+ const { entry, fields, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
const widget = resolveWidget(field.get('widget'));
const fieldName = field.get('name');
const value = entry.getIn(['data', fieldName]);
@@ -29,23 +29,22 @@ export default class ControlPane extends Component {
}
render() {
- const { collection } = this.props;
- if (!collection) {
+ const { collection, fields } = this.props;
+ if (!collection || !fields) {
return null;
}
+
return (
{
- collection
- .get('fields')
- .map(field =>
-
- {this.controlFor(field)}
-
- )
+ fields.map(field =>
+
+ {this.controlFor(field)}
+
+ )
}
);
@@ -55,6 +54,7 @@ export default class ControlPane extends Component {
ControlPane.propTypes = {
collection: ImmutablePropTypes.map.isRequired,
entry: ImmutablePropTypes.map.isRequired,
+ fields: ImmutablePropTypes.list.isRequired,
getMedia: PropTypes.func.isRequired,
onAddMedia: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
diff --git a/src/components/EntryEditor/EntryEditor.js b/src/components/EntryEditor/EntryEditor.js
index dfab685d..92aae5c5 100644
--- a/src/components/EntryEditor/EntryEditor.js
+++ b/src/components/EntryEditor/EntryEditor.js
@@ -10,6 +10,7 @@ export default function EntryEditor(
{
collection,
entry,
+ fields,
getMedia,
onChange,
onAddMedia,
@@ -26,6 +27,7 @@ export default function EntryEditor(
@@ -56,6 +59,7 @@ export default function EntryEditor(
EntryEditor.propTypes = {
collection: ImmutablePropTypes.map.isRequired,
entry: ImmutablePropTypes.map.isRequired,
+ fields: ImmutablePropTypes.list.isRequired,
getMedia: PropTypes.func.isRequired,
onAddMedia: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
diff --git a/src/components/EntryListing.js b/src/components/EntryListing.js
index 09fe5407..fd9a7375 100644
--- a/src/components/EntryListing.js
+++ b/src/components/EntryListing.js
@@ -21,7 +21,7 @@ export default class EntryListing extends React.Component {
{ mq: '1005px', columns: 4, gutter: 15 },
{ mq: '1515px', columns: 5, gutter: 15 },
{ mq: '1770px', columns: 6, gutter: 15 },
- ]
+ ],
};
this.updateBricks = _.throttle(this.updateBricks.bind(this), 30);
@@ -32,7 +32,7 @@ export default class EntryListing extends React.Component {
this.bricksInstance = Bricks({
container: this._entries,
packed: this.bricksConfig.packed,
- sizes: this.bricksConfig.sizes
+ sizes: this.bricksConfig.sizes,
});
this.bricksInstance.resize(true);
@@ -65,10 +65,10 @@ export default class EntryListing extends React.Component {
const card = Cards[cartType] || Cards._unknown;
return React.createElement(card, {
key: entry.get('slug'),
- collection: collection,
+ collection,
onClick: history.push.bind(this, link),
onImageLoaded: this.updateBricks,
- text: entry.getIn(['data', collection.getIn(['card', 'text'])]),
+ text: entry.get('label') ? entry.get('label') : entry.getIn(['data', collection.getIn(['card', 'text'])]),
description: entry.getIn(['data', collection.getIn(['card', 'description'])]),
image: entry.getIn(['data', collection.getIn(['card', 'image'])]),
});
@@ -83,13 +83,13 @@ export default class EntryListing extends React.Component {
if (Map.isMap(collections)) {
const collectionName = collections.get('name');
return entries.map((entry) => {
- const path = `/collections/${collectionName}/entries/${entry.get('slug')}`;
+ const path = `/collections/${ collectionName }/entries/${ entry.get('slug') }`;
return this.cardFor(collections, entry, path);
});
} else {
return entries.map((entry) => {
const collection = collections.filter(collection => collection.get('name') === entry.get('collection')).first();
- const path = `/collections/${collection.get('name')}/entries/${entry.get('slug')}`;
+ const path = `/collections/${ collection.get('name') }/entries/${ entry.get('slug') }`;
return this.cardFor(collection, entry, path);
});
}
@@ -98,13 +98,13 @@ export default class EntryListing extends React.Component {
render() {
const { children } = this.props;
const cards = this.renderCards();
- return
+ return (
{children}
-
this._entries = c}>
+
this._entries = c}>
{cards}
-
;
+
);
}
}
@@ -112,7 +112,7 @@ EntryListing.propTypes = {
children: PropTypes.node.isRequired,
collections: PropTypes.oneOfType([
ImmutablePropTypes.map,
- ImmutablePropTypes.iterable
+ ImmutablePropTypes.iterable,
]).isRequired,
entries: ImmutablePropTypes.list,
onPaginate: PropTypes.func.isRequired,
diff --git a/src/components/PreviewPane/Preview.js b/src/components/PreviewPane/Preview.js
index 86f03071..ea7d4867 100644
--- a/src/components/PreviewPane/Preview.js
+++ b/src/components/PreviewPane/Preview.js
@@ -1,14 +1,13 @@
import React, { PropTypes } from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
-export default function Preview({ collection, widgetFor }) {
- if (!collection) {
+export default function Preview({ collection, fields, widgetFor }) {
+ if (!collection || !fields) {
return null;
}
-
return (
- {collection.get('fields').map(field => widgetFor(field.get('name')))}
+ {fields.map(field => widgetFor(field.get('name')))}
);
}
@@ -16,6 +15,7 @@ export default function Preview({ collection, widgetFor }) {
Preview.propTypes = {
collection: ImmutablePropTypes.map.isRequired,
entry: ImmutablePropTypes.map.isRequired,
+ fields: ImmutablePropTypes.list.isRequired,
getMedia: PropTypes.func.isRequired,
widgetFor: PropTypes.func.isRequired,
};
diff --git a/src/components/PreviewPane/PreviewPane.js b/src/components/PreviewPane/PreviewPane.js
index 5ee0efd2..f3c99de2 100644
--- a/src/components/PreviewPane/PreviewPane.js
+++ b/src/components/PreviewPane/PreviewPane.js
@@ -14,8 +14,8 @@ export default class PreviewPane extends React.Component {
}
widgetFor = (name) => {
- const { collection, entry, getMedia } = this.props;
- const field = collection.get('fields').find(field => field.get('name') === name);
+ const { fields, entry, getMedia } = this.props;
+ const field = fields.find(field => field.get('name') === name);
const widget = resolveWidget(field.get('widget'));
return React.createElement(widget.preview, {
key: field.get('name'),
@@ -67,6 +67,7 @@ export default class PreviewPane extends React.Component {
PreviewPane.propTypes = {
collection: ImmutablePropTypes.map.isRequired,
+ fields: ImmutablePropTypes.list.isRequired,
entry: ImmutablePropTypes.map.isRequired,
getMedia: PropTypes.func.isRequired,
scrollTop: PropTypes.number,
diff --git a/src/components/Widgets.js b/src/components/Widgets.js
index e731ed78..abb96b10 100644
--- a/src/components/Widgets.js
+++ b/src/components/Widgets.js
@@ -3,6 +3,8 @@ import UnknownControl from './Widgets/UnknownControl';
import UnknownPreview from './Widgets/UnknownPreview';
import StringControl from './Widgets/StringControl';
import StringPreview from './Widgets/StringPreview';
+import ListControl from './Widgets/ListControl';
+import ListPreview from './Widgets/ListPreview';
import TextControl from './Widgets/TextControl';
import TextPreview from './Widgets/TextPreview';
import MarkdownControl from './Widgets/MarkdownControl';
@@ -14,6 +16,7 @@ import DateTimePreview from './Widgets/DateTimePreview';
registry.registerWidget('string', StringControl, StringPreview);
registry.registerWidget('text', TextControl, TextPreview);
+registry.registerWidget('list', ListControl, ListPreview);
registry.registerWidget('markdown', MarkdownControl, MarkdownPreview);
registry.registerWidget('image', ImageControl, ImagePreview);
registry.registerWidget('datetime', DateTimeControl, DateTimePreview);
diff --git a/src/components/Widgets/ListControl.js b/src/components/Widgets/ListControl.js
new file mode 100644
index 00000000..7d58de07
--- /dev/null
+++ b/src/components/Widgets/ListControl.js
@@ -0,0 +1,17 @@
+import React, { Component, PropTypes } from 'react';
+
+export default class ListControl extends Component {
+
+ static propTypes = {
+ onChange: PropTypes.func.isRequired,
+ value: PropTypes.node,
+ };
+ handleChange = (e) => {
+ this.props.onChange(e.target.value.split(',').map(item => item.trim()));
+ };
+
+ render() {
+ const { value } = this.props;
+ return
;
+ }
+}
diff --git a/src/components/Widgets/ListPreview.js b/src/components/Widgets/ListPreview.js
new file mode 100644
index 00000000..1b68a1ec
--- /dev/null
+++ b/src/components/Widgets/ListPreview.js
@@ -0,0 +1,11 @@
+import React, { PropTypes } from 'react';
+
+export default function ListPreview({ value }) {
+ return (
+ { value && value.map(item => - {item}
) }
+
);
+}
+
+ListPreview.propTypes = {
+ value: PropTypes.node,
+};
diff --git a/src/constants/collectionTypes.js b/src/constants/collectionTypes.js
new file mode 100644
index 00000000..c660c9bc
--- /dev/null
+++ b/src/constants/collectionTypes.js
@@ -0,0 +1,2 @@
+export const FILES = 'file_based_collection';
+export const FOLDER = 'folder_based_collection';
diff --git a/src/containers/EntryPage.js b/src/containers/EntryPage.js
index 9f366bd0..20c7289c 100644
--- a/src/containers/EntryPage.js
+++ b/src/containers/EntryPage.js
@@ -12,6 +12,7 @@ import {
import { cancelEdit } from '../actions/editor';
import { addMedia, removeMedia } from '../actions/media';
import { selectEntry, getMedia } from '../reducers';
+import { FOLDER, FILES } from '../constants/collectionTypes';
import EntryEditor from '../components/EntryEditor/EntryEditor';
import entryPageHOC from './editorialWorkflow/EntryPageHOC';
import { Loader } from '../components/UI';
@@ -31,6 +32,7 @@ class EntryPage extends React.Component {
persistEntry: PropTypes.func.isRequired,
removeMedia: PropTypes.func.isRequired,
cancelEdit: PropTypes.func.isRequired,
+ fields: ImmutablePropTypes.list.isRequired,
slug: PropTypes.string,
newEntry: PropTypes.bool.isRequired,
};
@@ -41,7 +43,7 @@ class EntryPage extends React.Component {
if (newEntry) {
createEmptyDraft(collection);
} else {
- loadEntry(entry, collection, slug);
+ if (collection.get('type') === FOLDER) loadEntry(entry, collection, slug);
this.createDraft(entry);
}
}
@@ -72,6 +74,7 @@ class EntryPage extends React.Component {
const {
entry,
entryDraft,
+ fields,
boundGetMedia,
collection,
changeDraft,
@@ -90,6 +93,7 @@ class EntryPage extends React.Component {
entry={entryDraft.get('entry')}
getMedia={boundGetMedia}
collection={collection}
+ fields={fields}
onChange={changeDraft}
onAddMedia={addMedia}
onRemoveMedia={removeMedia}
@@ -102,9 +106,19 @@ class EntryPage extends React.Component {
function mapStateToProps(state, ownProps) {
const { collections, entryDraft } = state;
- const collection = collections.get(ownProps.params.name);
- const newEntry = ownProps.route && ownProps.route.newRecord === true;
const slug = ownProps.params.slug;
+ const collection = collections.get(ownProps.params.name);
+
+ let fields;
+ if (collection.get('type') === FOLDER) {
+ fields = collection.get('fields');
+ } else {
+ const files = collection.get('files');
+ const file = files.filter(f => f.get('name') === slug);
+ fields = file.getIn([0, 'fields']);
+ }
+ const newEntry = ownProps.route && ownProps.route.newRecord === true;
+
const entry = newEntry ? null : selectEntry(state, collection.get('name'), slug);
const boundGetMedia = getMedia.bind(null, state);
return {
@@ -113,6 +127,7 @@ function mapStateToProps(state, ownProps) {
newEntry,
entryDraft,
boundGetMedia,
+ fields,
slug,
entry,
};
diff --git a/src/reducers/collections.js b/src/reducers/collections.js
index 5ede1aff..8d0bf0f6 100644
--- a/src/reducers/collections.js
+++ b/src/reducers/collections.js
@@ -1,13 +1,21 @@
import { OrderedMap, fromJS } from 'immutable';
import { CONFIG_SUCCESS } from '../actions/config';
+import { FILES, FOLDER } from '../constants/collectionTypes';
+
+const hasProperty = (config, property) => ({}.hasOwnProperty.call(config, property));
const collections = (state = null, action) => {
switch (action.type) {
case CONFIG_SUCCESS:
- const collections = action.payload && action.payload.collections;
+ const configCollections = action.payload && action.payload.collections;
return OrderedMap().withMutations((map) => {
- (collections || []).forEach(function(collection) {
- map.set(collection.name, fromJS(collection));
+ (configCollections || []).forEach((configCollection) => {
+ if (hasProperty(configCollection, 'folder')) {
+ configCollection.type = FOLDER; // eslint-disable-line no-param-reassign
+ } else if (hasProperty(configCollection, 'files')) {
+ configCollection.type = FILES; // eslint-disable-line no-param-reassign
+ }
+ map.set(configCollection.name, fromJS(configCollection));
});
});
default:
diff --git a/src/valueObjects/Entry.js b/src/valueObjects/Entry.js
index ba000b24..0798960c 100644
--- a/src/valueObjects/Entry.js
+++ b/src/valueObjects/Entry.js
@@ -6,6 +6,7 @@ export function createEntry(collection, slug = '', path = '', options = {}) {
returnObj.partial = options.partial || false;
returnObj.raw = options.raw || '';
returnObj.data = options.data || {};
+ returnObj.label = options.label || null;
returnObj.metaData = options.metaData || null;
return returnObj;
}