Allow the creation of new entries
This commit is contained in:
parent
fd79381160
commit
b717874e7b
@ -13,6 +13,7 @@ export const ENTRIES_SUCCESS = 'ENTRIES_SUCCESS';
|
||||
export const ENTRIES_FAILURE = 'ENTRIES_FAILURE';
|
||||
|
||||
export const DRAFT_CREATE_FROM_ENTRY = 'DRAFT_CREATE_FROM_ENTRY';
|
||||
export const DRAFT_CREATE_EMPTY = 'DRAFT_CREATE_EMPTY';
|
||||
export const DRAFT_DISCARD = 'DRAFT_DISCARD';
|
||||
export const DRAFT_CHANGE = 'DRAFT_CHANGE';
|
||||
|
||||
@ -102,6 +103,13 @@ function entryPersistFail(collection, entry, error) {
|
||||
};
|
||||
}
|
||||
|
||||
function emmptyDraftCreated(entry) {
|
||||
return {
|
||||
type: DRAFT_CREATE_EMPTY,
|
||||
payload: entry
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported simple Action Creators
|
||||
*/
|
||||
@ -153,6 +161,15 @@ export function loadEntries(collection) {
|
||||
};
|
||||
}
|
||||
|
||||
export function createEmptyDraft(collection) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const backend = currentBackend(state.config);
|
||||
const newEntry = backend.newEntry(collection);
|
||||
dispatch(emmptyDraftCreated(newEntry));
|
||||
};
|
||||
}
|
||||
|
||||
export function persistEntry(collection, entry) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
|
@ -1,6 +1,7 @@
|
||||
import TestRepoBackend from './test-repo/implementation';
|
||||
import GitHubBackend from './github/implementation';
|
||||
import { resolveFormat } from '../formats/formats';
|
||||
import { createEntry } from '../valueObjects/Entry';
|
||||
|
||||
class LocalStorageAuthStore {
|
||||
storageKey = 'nf-cms-user';
|
||||
@ -57,6 +58,11 @@ class Backend {
|
||||
return this.implementation.entry(collection, slug).then(this.entryWithFormat(collection));
|
||||
}
|
||||
|
||||
newEntry(collection) {
|
||||
const newEntry = createEntry();
|
||||
return this.entryWithFormat(collection)(newEntry);
|
||||
}
|
||||
|
||||
entryWithFormat(collection) {
|
||||
return (entry) => {
|
||||
const format = resolveFormat(collection, entry);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import LocalForage from 'localforage';
|
||||
import MediaProxy from '../../valueObjects/MediaProxy';
|
||||
import { createEntry } from '../../valueObjects/Entry';
|
||||
import AuthenticationPage from './AuthenticationPage';
|
||||
import { Base64 } from 'js-base64';
|
||||
|
||||
@ -210,9 +211,7 @@ export default class GitHub {
|
||||
return this.api.listFiles(collection.get('folder')).then((files) => (
|
||||
Promise.all(files.map((file) => (
|
||||
this.api.readFile(file.path, file.sha).then((data) => {
|
||||
file.slug = file.path.split('/').pop().replace(/\.[^\.]+$/, '');
|
||||
file.raw = data;
|
||||
return file;
|
||||
return createEntry(file.path, file.path.split('/').pop().replace(/\.[^\.]+$/, ''), data);
|
||||
})
|
||||
)))
|
||||
)).then((entries) => ({
|
||||
|
@ -1,4 +1,5 @@
|
||||
import AuthenticationPage from './AuthenticationPage';
|
||||
import { createEntry } from '../../valueObjects/Entry';
|
||||
|
||||
function getSlug(path) {
|
||||
const m = path.match(/([^\/]+?)(\.[^\/\.]+)?$/);
|
||||
@ -28,11 +29,7 @@ export default class TestRepo {
|
||||
const folder = collection.get('folder');
|
||||
if (folder) {
|
||||
for (var path in window.repoFiles[folder]) {
|
||||
entries.push({
|
||||
path: folder + '/' + path,
|
||||
slug: getSlug(path),
|
||||
raw: window.repoFiles[folder][path].content
|
||||
});
|
||||
entries.push(createEntry(folder + '/' + path, getSlug(path), window.repoFiles[folder][path].content));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ export default class StringControl extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
return <input value={this.props.value} onChange={this.handleChange}/>;
|
||||
return <input type="text" value={this.props.value || ''} onChange={this.handleChange}/>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { connect } from 'react-redux';
|
||||
import {
|
||||
loadEntry,
|
||||
createDraftFromEntry,
|
||||
createEmptyDraft,
|
||||
discardDraft,
|
||||
changeDraft,
|
||||
persistEntry
|
||||
@ -15,19 +16,27 @@ import EntryEditor from '../components/EntryEditor';
|
||||
class EntryPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.props.loadEntry(props.collection, props.slug);
|
||||
this.createDraft = this.createDraft.bind(this);
|
||||
this.handlePersistEntry = this.handlePersistEntry.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.entry) {
|
||||
this.props.createDraftFromEntry(this.props.entry);
|
||||
if (!this.props.newEntry) {
|
||||
this.props.loadEntry(this.props.collection, this.props.slug);
|
||||
|
||||
this.createDraft(this.props.entry);
|
||||
} else {
|
||||
this.props.createEmptyDraft(this.props.collection);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.entry !== nextProps.entry && !nextProps.entry.get('isFetching')) {
|
||||
this.props.createDraftFromEntry(nextProps.entry);
|
||||
if (this.props.entry === nextProps.entry) return;
|
||||
|
||||
if (nextProps.entry && !nextProps.entry.get('isFetching')) {
|
||||
this.createDraft(nextProps.entry);
|
||||
} else if (nextProps.newEntry) {
|
||||
this.props.createEmptyDraft(nextProps.collection);
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,17 +44,19 @@ class EntryPage extends React.Component {
|
||||
this.props.discardDraft();
|
||||
}
|
||||
|
||||
createDraft(entry) {
|
||||
if (entry) this.props.createDraftFromEntry(entry);
|
||||
}
|
||||
|
||||
handlePersistEntry() {
|
||||
this.props.persistEntry(this.props.collection, this.props.entryDraft);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const {
|
||||
entry, entryDraft, boundGetMedia, collection, changeDraft, addMedia, removeMedia
|
||||
} = this.props;
|
||||
|
||||
if (entry == null || entryDraft.get('entry') == undefined || entry.get('isFetching')) {
|
||||
if (entryDraft == null || entryDraft.get('entry') == undefined || entry && entry.get('isFetching')) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
return (
|
||||
@ -68,22 +79,25 @@ EntryPage.propTypes = {
|
||||
changeDraft: PropTypes.func.isRequired,
|
||||
collection: ImmutablePropTypes.map.isRequired,
|
||||
createDraftFromEntry: PropTypes.func.isRequired,
|
||||
createEmptyDraft: PropTypes.func.isRequired,
|
||||
discardDraft: PropTypes.func.isRequired,
|
||||
entry: ImmutablePropTypes.map.isRequired,
|
||||
entry: ImmutablePropTypes.map,
|
||||
entryDraft: ImmutablePropTypes.map.isRequired,
|
||||
loadEntry: PropTypes.func.isRequired,
|
||||
persistEntry: PropTypes.func.isRequired,
|
||||
removeMedia: PropTypes.func.isRequired,
|
||||
slug: PropTypes.string.isRequired,
|
||||
slug: PropTypes.string,
|
||||
newEntry: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
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 entry = selectEntry(state, collection.get('name'), slug);
|
||||
const entry = newEntry ? null : selectEntry(state, collection.get('name'), slug);
|
||||
const boundGetMedia = getMedia.bind(null, state);
|
||||
return { collection, collections, entryDraft, boundGetMedia, slug, entry };
|
||||
return { collection, collections, newEntry, entryDraft, boundGetMedia, slug, entry };
|
||||
}
|
||||
|
||||
export default connect(
|
||||
@ -94,6 +108,7 @@ export default connect(
|
||||
removeMedia,
|
||||
loadEntry,
|
||||
createDraftFromEntry,
|
||||
createEmptyDraft,
|
||||
discardDraft,
|
||||
persistEntry
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Map, List } from 'immutable';
|
||||
import { DRAFT_CREATE_FROM_ENTRY, DRAFT_DISCARD, DRAFT_CHANGE } from '../actions/entries';
|
||||
import { Map, List, fromJS } from 'immutable';
|
||||
import { DRAFT_CREATE_FROM_ENTRY, DRAFT_CREATE_EMPTY, DRAFT_DISCARD, DRAFT_CHANGE } from '../actions/entries';
|
||||
import { ADD_MEDIA, REMOVE_MEDIA } from '../actions/media';
|
||||
|
||||
const initialState = Map({ entry: Map(), mediaFiles: List() });
|
||||
@ -7,14 +7,15 @@ const initialState = Map({ entry: Map(), mediaFiles: List() });
|
||||
const entryDraft = (state = Map(), action) => {
|
||||
switch (action.type) {
|
||||
case DRAFT_CREATE_FROM_ENTRY:
|
||||
if (!action.payload) {
|
||||
// New entry
|
||||
return initialState;
|
||||
}
|
||||
// Existing Entry
|
||||
return state.withMutations((state) => {
|
||||
state.set('entry', action.payload);
|
||||
state.setIn(['entry', 'newRecord'], false);
|
||||
state.set('mediaFiles', List());
|
||||
});
|
||||
case DRAFT_CREATE_EMPTY:
|
||||
// New Entry
|
||||
return state.withMutations((state) => {
|
||||
state.set('entry', fromJS(action.payload));
|
||||
state.set('mediaFiles', List());
|
||||
});
|
||||
case DRAFT_DISCARD:
|
||||
|
@ -10,7 +10,8 @@ export default (
|
||||
<Route path="/" component={App}>
|
||||
<IndexRoute component={CollectionPage}/>
|
||||
<Route path="/collections/:name" component={CollectionPage}/>
|
||||
<Route path="/collections/:name/entries/:slug" component={EntryPage}/>
|
||||
<Route path="/collections/:name/entries/new" component={EntryPage} newRecord />
|
||||
<Route path="/collections/:name/entries/:slug" component={EntryPage} />
|
||||
<Route path="/search" component={SearchPage}/>
|
||||
<Route path="*" component={NotFoundPage}/>
|
||||
</Route>
|
||||
|
8
src/valueObjects/Entry.js
Normal file
8
src/valueObjects/Entry.js
Normal file
@ -0,0 +1,8 @@
|
||||
export function createEntry(path = '', slug = '', raw = '') {
|
||||
const returnObj = {};
|
||||
returnObj.path = path;
|
||||
returnObj.slug = slug;
|
||||
returnObj.raw = raw;
|
||||
returnObj.data = {};
|
||||
return returnObj;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user