2017-05-12 00:23:56 +00:00
|
|
|
// @flow
|
2016-08-12 12:56:39 +00:00
|
|
|
import _ from 'lodash';
|
2017-05-10 07:02:11 +00:00
|
|
|
import { browserHistory } from 'react-router';
|
2017-05-12 00:23:56 +00:00
|
|
|
import invariant from 'invariant';
|
2017-04-28 04:48:13 +00:00
|
|
|
import {
|
|
|
|
observable,
|
|
|
|
action,
|
|
|
|
computed,
|
|
|
|
runInAction,
|
|
|
|
toJS,
|
|
|
|
autorunAsync,
|
|
|
|
} from 'mobx';
|
2016-06-05 01:28:14 +00:00
|
|
|
import { client } from 'utils/ApiClient';
|
2017-05-13 22:36:06 +00:00
|
|
|
import type {
|
|
|
|
Document as DocumentType,
|
|
|
|
Collection,
|
|
|
|
NavigationNode,
|
|
|
|
} from 'types';
|
2016-06-05 01:28:14 +00:00
|
|
|
|
2016-07-07 07:27:11 +00:00
|
|
|
const DOCUMENT_PREFERENCES = 'DOCUMENT_PREFERENCES';
|
|
|
|
|
2017-05-12 00:23:56 +00:00
|
|
|
type Document = {
|
|
|
|
collection: Collection,
|
|
|
|
} & DocumentType;
|
|
|
|
|
2016-07-07 05:04:31 +00:00
|
|
|
class DocumentSceneStore {
|
2017-05-12 00:23:56 +00:00
|
|
|
@observable document: ?Document;
|
|
|
|
@observable collapsedNodes: string[] = [];
|
2016-06-05 01:28:14 +00:00
|
|
|
|
2017-05-12 00:23:56 +00:00
|
|
|
@observable isFetching: boolean = true;
|
|
|
|
@observable updatingContent: boolean = false;
|
|
|
|
@observable updatingStructure: boolean = false;
|
|
|
|
@observable isDeleting: boolean = false;
|
2016-06-05 01:28:14 +00:00
|
|
|
|
2016-06-23 05:57:39 +00:00
|
|
|
/* Computed */
|
|
|
|
|
2017-05-12 00:23:56 +00:00
|
|
|
@computed get isCollection(): boolean {
|
|
|
|
return !!this.document && this.document.collection.type === 'atlas';
|
2016-06-23 05:57:39 +00:00
|
|
|
}
|
|
|
|
|
2017-05-12 00:23:56 +00:00
|
|
|
@computed get collectionTree(): ?Object {
|
|
|
|
if (
|
2017-05-12 06:05:11 +00:00
|
|
|
this.document &&
|
|
|
|
this.document.collection &&
|
|
|
|
this.document.collection.type === 'atlas'
|
|
|
|
) {
|
|
|
|
const tree = this.document.collection.navigationTree;
|
|
|
|
const collapseNodes = node => {
|
|
|
|
node.collapsed = this.collapsedNodes.includes(node.id);
|
|
|
|
node.children = node.children.map(childNode => {
|
|
|
|
return collapseNodes(childNode);
|
|
|
|
});
|
2016-07-07 07:27:11 +00:00
|
|
|
|
2017-05-12 06:05:11 +00:00
|
|
|
return node;
|
|
|
|
};
|
2016-07-07 07:27:11 +00:00
|
|
|
|
2017-05-12 06:05:11 +00:00
|
|
|
return collapseNodes(toJS(tree));
|
|
|
|
}
|
2016-07-07 07:27:11 +00:00
|
|
|
}
|
|
|
|
|
2017-05-13 22:36:06 +00:00
|
|
|
@computed get pathToDocument(): ?Array<NavigationNode> {
|
|
|
|
let path;
|
|
|
|
const traveler = (node, previousPath) => {
|
|
|
|
if (this.document && node.id === this.document.id) {
|
|
|
|
path = previousPath;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
node.children.forEach(childNode => {
|
|
|
|
const newPath = [...previousPath, node];
|
|
|
|
return traveler(childNode, newPath);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (this.document && this.collectionTree) {
|
|
|
|
traveler(this.collectionTree, []);
|
|
|
|
invariant(path, 'Path is not available for collection, abort');
|
|
|
|
return path.splice(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-05 01:28:14 +00:00
|
|
|
/* Actions */
|
|
|
|
|
2017-05-12 00:23:56 +00:00
|
|
|
@action fetchDocument = async (
|
|
|
|
id: string,
|
|
|
|
options: { softLoad?: boolean, replaceUrl?: boolean } = {}
|
|
|
|
) => {
|
2016-08-27 20:48:00 +00:00
|
|
|
options = {
|
|
|
|
softLoad: false,
|
|
|
|
replaceUrl: true,
|
|
|
|
...options,
|
|
|
|
};
|
2016-08-01 16:03:17 +00:00
|
|
|
|
2016-08-27 20:48:00 +00:00
|
|
|
this.isFetching = !options.softLoad;
|
2017-04-29 21:08:15 +00:00
|
|
|
this.updatingContent = true;
|
2016-06-05 01:28:14 +00:00
|
|
|
|
|
|
|
try {
|
2017-04-29 21:08:15 +00:00
|
|
|
const res = await client.get('/documents.info', { id });
|
2017-05-12 00:23:56 +00:00
|
|
|
invariant(res && res.data, 'data should be available');
|
2016-06-05 01:28:14 +00:00
|
|
|
const { data } = res;
|
2016-07-07 05:04:31 +00:00
|
|
|
runInAction('fetchDocument', () => {
|
|
|
|
this.document = data;
|
2016-08-27 20:48:00 +00:00
|
|
|
if (options.replaceUrl) browserHistory.replace(data.url);
|
2016-07-07 05:04:31 +00:00
|
|
|
});
|
2016-06-05 01:28:14 +00:00
|
|
|
} catch (e) {
|
2017-02-10 05:18:03 +00:00
|
|
|
console.error('Something went wrong');
|
2016-06-05 01:28:14 +00:00
|
|
|
}
|
|
|
|
this.isFetching = false;
|
2016-07-07 06:27:06 +00:00
|
|
|
this.updatingContent = false;
|
2017-04-28 04:48:13 +00:00
|
|
|
};
|
2016-06-05 01:28:14 +00:00
|
|
|
|
|
|
|
@action deleteDocument = async () => {
|
2017-05-12 00:23:56 +00:00
|
|
|
if (!this.document) return;
|
2016-06-05 01:28:14 +00:00
|
|
|
this.isFetching = true;
|
|
|
|
|
|
|
|
try {
|
2016-08-01 16:03:17 +00:00
|
|
|
await client.post('/documents.delete', { id: this.document.id });
|
2017-05-12 00:23:56 +00:00
|
|
|
// $FlowFixMe don't be stupid
|
2016-08-15 19:41:51 +00:00
|
|
|
browserHistory.push(this.document.collection.url);
|
2016-06-05 01:28:14 +00:00
|
|
|
} catch (e) {
|
2017-02-10 05:18:03 +00:00
|
|
|
console.error('Something went wrong');
|
2016-06-05 01:28:14 +00:00
|
|
|
}
|
|
|
|
this.isFetching = false;
|
2017-04-28 04:48:13 +00:00
|
|
|
};
|
2016-06-26 05:27:44 +00:00
|
|
|
|
2017-05-12 00:23:56 +00:00
|
|
|
@action updateNavigationTree = async (tree: Object) => {
|
2016-07-07 04:44:14 +00:00
|
|
|
// Only update when tree changes
|
2017-05-12 00:23:56 +00:00
|
|
|
// $FlowFixMe don't be stupid
|
2016-08-12 12:56:39 +00:00
|
|
|
if (_.isEqual(toJS(tree), toJS(this.document.collection.navigationTree))) {
|
2016-07-07 04:44:14 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-07 06:26:36 +00:00
|
|
|
this.updatingStructure = true;
|
2016-06-26 05:27:44 +00:00
|
|
|
|
|
|
|
try {
|
2016-08-05 15:09:14 +00:00
|
|
|
const res = await client.post('/collections.updateNavigationTree', {
|
2017-05-12 00:23:56 +00:00
|
|
|
// $FlowFixMe don't be stupid
|
2016-08-05 15:09:14 +00:00
|
|
|
id: this.document.collection.id,
|
2016-08-01 16:03:17 +00:00
|
|
|
tree,
|
2016-06-26 05:27:44 +00:00
|
|
|
});
|
2017-05-12 00:23:56 +00:00
|
|
|
invariant(res && res.data, 'data should be available');
|
2016-07-07 05:04:31 +00:00
|
|
|
runInAction('updateNavigationTree', () => {
|
|
|
|
const { data } = res;
|
2017-05-12 00:23:56 +00:00
|
|
|
// $FlowFixMe don't be stupid
|
2016-08-05 15:09:14 +00:00
|
|
|
this.document.collection = data;
|
2016-07-07 05:04:31 +00:00
|
|
|
});
|
2016-06-26 05:27:44 +00:00
|
|
|
} catch (e) {
|
2017-02-10 05:18:03 +00:00
|
|
|
console.error('Something went wrong');
|
2016-06-26 05:27:44 +00:00
|
|
|
}
|
2016-07-07 06:26:36 +00:00
|
|
|
this.updatingStructure = false;
|
2017-04-28 04:48:13 +00:00
|
|
|
};
|
2016-07-07 07:27:11 +00:00
|
|
|
|
2017-05-12 00:23:56 +00:00
|
|
|
@action onNodeCollapse = (nodeId: string) => {
|
2017-02-17 07:04:52 +00:00
|
|
|
if (_.indexOf(this.collapsedNodes, nodeId) >= 0) {
|
|
|
|
this.collapsedNodes = _.without(this.collapsedNodes, nodeId);
|
2016-07-07 07:27:11 +00:00
|
|
|
} else {
|
2017-02-17 07:04:52 +00:00
|
|
|
this.collapsedNodes.push(nodeId);
|
2016-07-07 07:27:11 +00:00
|
|
|
}
|
2017-04-28 04:48:13 +00:00
|
|
|
};
|
2016-07-07 07:27:11 +00:00
|
|
|
|
|
|
|
// General
|
|
|
|
|
|
|
|
persistSettings = () => {
|
|
|
|
localStorage[DOCUMENT_PREFERENCES] = JSON.stringify({
|
2017-02-17 07:04:52 +00:00
|
|
|
collapsedNodes: toJS(this.collapsedNodes),
|
2016-07-07 07:27:11 +00:00
|
|
|
});
|
2017-04-28 04:48:13 +00:00
|
|
|
};
|
2016-07-07 07:27:11 +00:00
|
|
|
|
2017-05-12 00:23:56 +00:00
|
|
|
constructor(settings: { collapsedNodes: string[] }) {
|
2016-07-07 07:27:11 +00:00
|
|
|
// Rehydrate settings
|
2017-02-17 07:04:52 +00:00
|
|
|
this.collapsedNodes = settings.collapsedNodes || [];
|
2016-07-07 07:27:11 +00:00
|
|
|
|
|
|
|
// Persist settings to localStorage
|
|
|
|
// TODO: This could be done more selectively
|
2016-08-01 16:03:17 +00:00
|
|
|
autorunAsync(() => {
|
2016-07-07 07:27:11 +00:00
|
|
|
this.persistSettings();
|
|
|
|
});
|
|
|
|
}
|
2016-08-01 16:03:17 +00:00
|
|
|
}
|
2016-06-05 01:28:14 +00:00
|
|
|
|
2016-07-07 05:04:31 +00:00
|
|
|
export default DocumentSceneStore;
|
2017-04-28 04:48:13 +00:00
|
|
|
export { DOCUMENT_PREFERENCES };
|