Renaming atlases to collections

This commit is contained in:
Jori Lallo
2016-08-05 18:09:14 +03:00
parent cf1563eb2f
commit c753382571
14 changed files with 119 additions and 119 deletions

View File

@ -26,7 +26,7 @@ class AtlasPreview extends React.Component {
<DocumentLink document={ document } key={ document.id } />)
})
: (
<div className={ styles.description }>No documents. Why not <Link to={ `/atlas/${data.id}/new` }>create one</Link>?</div>
<div className={ styles.description }>No documents. Why not <Link to={ `/collections/${data.id}/new` }>create one</Link>?</div>
) }
</div>
);

View File

@ -13,11 +13,11 @@ class FullscreenField extends React.Component {
<div className={ styles.container }>
<CenteredContent>
<div className={ styles.content }>
<h2>Create a new atlas</h2>
<p>Atlases are collections where you, your teams or friends can share and collect information.</p>
<h2>Create a new collection</h2>
<p>Collections are spaces where you, your teams or friends can share and collect information.</p>
<div className={ styles.field }>
<div className={ styles.label }>Atlas name</div>
<div className={ styles.label }>Collection name</div>
<input type="text" placeholder="Meeting notes" />
</div>
@ -27,7 +27,7 @@ class FullscreenField extends React.Component {
</div>
<div className={ styles.field }>
<button className={ styles.button }>Create atlas</button>
<button className={ styles.button }>Create collection</button>
</div>
</div>
</CenteredContent>

View File

@ -50,9 +50,9 @@ render((
<IndexRoute component={ Home } />
<Route path="/dashboard" component={ Dashboard } onEnter={ requireAuth } />
<Route path="/atlas/:id" component={ Atlas } onEnter={ requireAuth } />
<Route path="/collections/:id" component={ Atlas } onEnter={ requireAuth } />
<Route
path="/atlas/:id/new"
path="/collections/:id/new"
component={ DocumentEdit }
onEnter={ requireAuth }
newDocument

View File

@ -21,13 +21,13 @@ import styles from './Atlas.scss';
class Atlas extends React.Component {
componentDidMount = () => {
const { id } = this.props.params;
store.fetchAtlas(id, data => {
store.fetchCollection(id, data => {
// Forward directly to root document
if (data.type === 'atlas') {
browserHistory.replace(data.navigationTree.url);
}
})
});
}
componentWillReceiveProps = (nextProps) => {
@ -41,17 +41,17 @@ class Atlas extends React.Component {
onCreate = (event) => {
if (event) event.preventDefault();
browserHistory.push(`/atlas/${store.atlas.id}/new`);
browserHistory.push(`/collections/${store.collection.id}/new`);
}
render() {
const atlas = store.atlas;
const collection = store.collection;
let actions;
let title;
let titleText;
if (atlas) {
if (collection) {
actions = (
<Flex direction="row">
<DropdownMenu label={ <MoreIcon /> } >
@ -61,8 +61,8 @@ class Atlas extends React.Component {
</DropdownMenu>
</Flex>
);
title = <Title>{ atlas.name }</Title>;
titleText = atlas.name;
title = <Title>{ collection.name }</Title>;
titleText = collection.name;
}
return (
@ -77,15 +77,15 @@ class Atlas extends React.Component {
) : (
<div className={ styles.container }>
<div className={ styles.atlasDetails }>
<h2>{ atlas.name }</h2>
<h2>{ collection.name }</h2>
<blockquote>
{ atlas.description }
{ collection.description }
</blockquote>
</div>
<Divider />
<DocumentList documents={ atlas.recentDocuments } preview={ true } />
<DocumentList documents={ collection.recentDocuments } preview />
</div>
) }
</CenteredContent>

View File

@ -2,20 +2,20 @@ import { observable, action } from 'mobx';
import { client } from 'utils/ApiClient';
const store = new class AtlasStore {
@observable atlas;
@observable collection;
@observable isFetching = true;
/* Actions */
@action fetchAtlas = async (id, successCallback) => {
@action fetchCollection = async (id, successCallback) => {
this.isFetching = true;
this.atlas = null;
this.collection = null;
try {
const res = await client.get('/atlases.info', { id: id });
const res = await client.get('/collections.info', { id });
const { data } = res;
this.atlas = data;
this.collection = data;
successCallback(data);
} catch (e) {
console.error("Something went wrong");

View File

@ -24,7 +24,7 @@ class Dashboard extends React.Component {
}
componentDidMount = () => {
store.fetchAtlases(this.props.user.team.id);
store.fetchCollections(this.props.user.team.id);
}
onClickNewAtlas = () => {
@ -53,8 +53,8 @@ class Dashboard extends React.Component {
<Flex direction="column" flex>
{ store.isFetching ? (
<AtlasPreviewLoading />
) : store.atlases && store.atlases.map((atlas) => {
return (<AtlasPreview key={ atlas.id } data={ atlas } />);
) : store.collections && store.collections.map((collection) => {
return (<AtlasPreview key={ collection.id } data={ collection } />);
}) }
</Flex>
</CenteredContent>

View File

@ -2,21 +2,21 @@ import { observable, action, runInAction } from 'mobx';
import { client, cacheResponse } from 'utils/ApiClient';
const store = new class DashboardStore {
@observable atlases;
@observable collections;
@observable pagination;
@observable isFetching = true;
/* Actions */
@action fetchAtlases = async (teamId) => {
@action fetchCollections = async (teamId) => {
this.isFetching = true;
try {
const res = await client.post('/atlases.list', { id: teamId });
const res = await client.post('/collections.list', { id: teamId });
const { data, pagination } = res;
runInAction('fetchAtlases', () => {
this.atlases = data;
runInAction('fetchCollections', () => {
this.collections = data;
this.pagination = pagination;
data.forEach((collection) => cacheResponse(collection.recentDocuments));
});

View File

@ -47,7 +47,7 @@ class DocumentEdit extends Component {
componentDidMount = () => {
if (this.props.route.newDocument) {
this.store.atlasId = this.props.params.id;
this.store.collectionId = this.props.params.id;
this.store.newDocument = true;
} else if (this.props.route.newChildDocument) {
this.store.documentId = this.props.params.id;

View File

@ -21,7 +21,7 @@ const parseHeader = (text) => {
class DocumentEditStore {
@observable documentId = null;
@observable atlasId = null;
@observable collectionId = null;
@observable parentDocument;
@observable title;
@observable text;
@ -63,7 +63,7 @@ class DocumentEditStore {
try {
const data = await client.post('/documents.create', {
parentDocument: this.parentDocument && this.parentDocument.id,
atlas: this.atlasId || this.parentDocument.atlas.id,
collection: this.collectionId || this.parentDocument.collection.id,
title: this.title,
text: this.text,
}, { cache: true });

View File

@ -103,7 +103,7 @@ class DocumentScene extends React.Component {
onDelete = () => {
let msg;
if (this.store.document.atlas.type === 'atlas') {
if (this.store.document.collection.type === 'atlas') {
msg = 'Are you sure you want to delete this document and all it\'s child documents (if any)?';
} else {
msg = 'Are you sure you want to delete this document?';
@ -141,8 +141,8 @@ class DocumentScene extends React.Component {
} = this.props.ui;
const doc = this.store.document;
const allowDelete = doc && doc.atlas.type === 'atlas' &&
doc.id !== doc.atlas.navigationTree.id;
const allowDelete = doc && doc.collection.type === 'atlas' &&
doc.id !== doc.collection.navigationTree.id;
let title;
let titleText;
let actions;
@ -150,7 +150,8 @@ class DocumentScene extends React.Component {
actions = (
<div className={ styles.actions }>
<DropdownMenu label={ <MoreIcon /> }>
{ this.store.isAtlas && <MenuItem onClick={ this.onCreate }>New document</MenuItem> }
{ this.store.isCollection &&
<MenuItem onClick={ this.onCreate }>New document</MenuItem> }
<MenuItem onClick={ this.onEdit }>Edit</MenuItem>
<MenuItem onClick={ this.onExport }>Export</MenuItem>
{ allowDelete && <MenuItem onClick={ this.onDelete }>Delete</MenuItem> }
@ -159,11 +160,11 @@ class DocumentScene extends React.Component {
);
title = (
<span>
<Link to={ `/atlas/${doc.atlas.id}` }>{ doc.atlas.name }</Link>
<Link to={ `/collections/${doc.collection.id}` }>{ doc.collection.name }</Link>
{ ` / ${doc.title}` }
</span>
);
titleText = `${doc.atlas.name} - ${doc.title}`;
titleText = `${doc.collection.name} - ${doc.title}`;
}
return (
@ -179,13 +180,13 @@ class DocumentScene extends React.Component {
</CenteredContent>
) : (
<Flex flex>
{ this.store.isAtlas && (
{ this.store.isCollection && (
<Flex>
{ sidebar && (
<div className={ cx(styles.sidebar) }>
<Tree
paddingLeft={ 10 }
tree={ toJS(this.store.atlasTree) }
tree={ toJS(this.store.collectionTree) }
onChange={ this.store.updateNavigationTree }
onCollapse={ this.store.onNodeCollapse }
isNodeCollapsed={ this.isNodeCollapsed }

View File

@ -20,14 +20,14 @@ class DocumentSceneStore {
/* Computed */
@computed get isAtlas() {
@computed get isCollection() {
return this.document &&
this.document.atlas.type === 'atlas';
this.document.collection.type === 'atlas';
}
@computed get atlasTree() {
if (!this.document || this.document.atlas.type !== 'atlas') return;
const tree = this.document.atlas.navigationTree;
@computed get collectionTree() {
if (!this.document || this.document.collection.type !== 'atlas') return;
const tree = this.document.collection.navigationTree;
const collapseNodes = (node) => {
if (this.collapsedNodes.includes(node.id)) {
@ -74,7 +74,7 @@ class DocumentSceneStore {
try {
await client.post('/documents.delete', { id: this.document.id });
browserHistory.push(`/atlas/${this.document.atlas.id}`);
browserHistory.push(`/collections/${this.document.collection.id}`);
} catch (e) {
console.error("Something went wrong");
}
@ -83,20 +83,20 @@ class DocumentSceneStore {
@action updateNavigationTree = async (tree) => {
// Only update when tree changes
if (_isEqual(toJS(tree), toJS(this.document.atlas.navigationTree))) {
if (_isEqual(toJS(tree), toJS(this.document.collection.navigationTree))) {
return true;
}
this.updatingStructure = true;
try {
const res = await client.post('/atlases.updateNavigationTree', {
id: this.document.atlas.id,
const res = await client.post('/collections.updateNavigationTree', {
id: this.document.collection.id,
tree,
});
runInAction('updateNavigationTree', () => {
const { data } = res;
this.document.atlas = data;
this.document.collection = data;
});
} catch (e) {
console.error("Something went wrong");

View File

@ -4,12 +4,12 @@ import _orderBy from 'lodash.orderby';
import auth from './authentication';
import pagination from './middlewares/pagination';
import { presentAtlas } from '../presenters';
import { presentCollection } from '../presenters';
import { Atlas } from '../models';
const router = new Router();
router.post('atlases.create', auth(), async (ctx) => {
router.post('collections.create', auth(), async (ctx) => {
const {
name,
description,
@ -28,11 +28,11 @@ router.post('atlases.create', auth(), async (ctx) => {
});
ctx.body = {
data: await presentAtlas(atlas, true),
data: await presentCollection(atlas, true),
};
});
router.post('atlases.info', auth(), async (ctx) => {
router.post('collections.info', auth(), async (ctx) => {
const { id } = ctx.body;
ctx.assertPresent(id, 'id is required');
@ -47,14 +47,14 @@ router.post('atlases.info', auth(), async (ctx) => {
if (!atlas) throw httpErrors.NotFound();
ctx.body = {
data: await presentAtlas(atlas, true),
data: await presentCollection(atlas, true),
};
});
router.post('atlases.list', auth(), pagination(), async (ctx) => {
router.post('collections.list', auth(), pagination(), async (ctx) => {
const user = ctx.state.user;
const atlases = await Atlas.findAll({
const collections = await Atlas.findAll({
where: {
teamId: user.teamId,
},
@ -67,8 +67,8 @@ router.post('atlases.list', auth(), pagination(), async (ctx) => {
// Atlases
let data = [];
await Promise.all(atlases.map(async (atlas) => {
return data.push(await presentAtlas(atlas, true));
await Promise.all(collections.map(async (atlas) => {
return data.push(await presentCollection(atlas, true));
}));
data = _orderBy(data, ['updatedAt'], ['desc']);
@ -79,7 +79,7 @@ router.post('atlases.list', auth(), pagination(), async (ctx) => {
};
});
router.post('atlases.updateNavigationTree', auth(), async (ctx) => {
router.post('collections.updateNavigationTree', auth(), async (ctx) => {
const { id, tree } = ctx.body;
ctx.assertPresent(id, 'id is required');
@ -96,7 +96,7 @@ router.post('atlases.updateNavigationTree', auth(), async (ctx) => {
await atlas.updateNavigationTree(tree);
ctx.body = {
data: await presentAtlas(atlas, true),
data: await presentCollection(atlas, true),
};
});

View File

@ -82,19 +82,19 @@ router.post('documents.search', auth(), async (ctx) => {
router.post('documents.create', auth(), async (ctx) => {
const {
atlas,
collection,
title,
text,
parentDocument,
} = ctx.body;
ctx.assertPresent(atlas, 'atlas is required');
ctx.assertPresent(collection, 'collection is required');
ctx.assertPresent(title, 'title is required');
ctx.assertPresent(text, 'text is required');
const user = ctx.state.user;
const ownerAtlas = await Atlas.findOne({
where: {
id: atlas,
id: collection,
teamId: user.teamId,
},
});
@ -161,9 +161,9 @@ router.post('documents.update', auth(), async (ctx) => {
await document.createRevision();
// Update
const atlas = await Atlas.findById(document.atlasId);
if (atlas.type === 'atlas') {
await atlas.updateNavigationTree();
const collection = await Atlas.findById(document.atlasId);
if (collection.type === 'atlas') {
await collection.updateNavigationTree();
}
ctx.body = {
@ -184,11 +184,11 @@ router.post('documents.delete', auth(), async (ctx) => {
teamId: user.teamId,
},
});
const atlas = await Atlas.findById(document.atlasId);
const collection = await Atlas.findById(document.atlasId);
if (!document) throw httpErrors.BadRequest();
if (atlas.type === 'atlas') {
if (collection.type === 'atlas') {
// Don't allow deletion of root docs
if (!document.parentDocumentId) {
throw httpErrors.BadRequest('Unable to delete atlas\'s root document');
@ -196,8 +196,8 @@ router.post('documents.delete', auth(), async (ctx) => {
// Delete all chilren
try {
await atlas.deleteDocument(document);
await atlas.save();
await collection.deleteDocument(document);
await collection.save();
} catch (e) {
throw httpErrors.BadRequest('Error while deleting');
}

View File

@ -2,7 +2,7 @@ import _orderBy from 'lodash.orderby';
import { Document, Atlas } from './models';
export function presentUser(user) {
return new Promise(async (resolve, reject) => {
return new Promise(async (resolve, _reject) => {
const data = {
id: user.id,
name: user.name,
@ -14,7 +14,7 @@ export function presentUser(user) {
}
export function presentTeam(team) {
return new Promise(async (resolve, reject) => {
return new Promise(async (resolve, _reject) => {
resolve({
id: team.id,
name: team.name,
@ -22,42 +22,7 @@ export function presentTeam(team) {
});
}
export function presentAtlas(atlas, includeRecentDocuments=false) {
return new Promise(async (resolve, reject) => {
const data = {
id: atlas.id,
name: atlas.name,
description: atlas.description,
type: atlas.type,
}
if (atlas.type === 'atlas') {
data.navigationTree = await atlas.getStructure();
}
if (includeRecentDocuments) {
const documents = await Document.findAll({
where: {
atlasId: atlas.id,
},
limit: 10,
order: [
['updatedAt', 'DESC'],
],
});
let recentDocuments = [];
await Promise.all(documents.map(async (document) => {
recentDocuments.push(await presentDocument(document, true));
}))
data.recentDocuments = _orderBy(recentDocuments, ['updatedAt'], ['desc']);
}
resolve(data);
});
}
export async function presentDocument(document, includeAtlas=false) {
export async function presentDocument(document, includeCollection = false) {
const data = {
id: document.id,
url: document.buildUrl(),
@ -66,18 +31,17 @@ export async function presentDocument(document, includeAtlas=false) {
text: document.text,
html: document.html,
preview: document.preview,
private: document.private,
createdAt: document.createdAt,
updatedAt: document.updatedAt,
atlas: document.atlasId,
collection: document.atlasId,
team: document.teamId,
}
};
if (includeAtlas) {
const atlas = await Atlas.findOne({ where: {
if (includeCollection) {
const collection = await Atlas.findOne({ where: {
id: document.atlasId,
} });
data.atlas = await presentAtlas(atlas, false);
data.collection = await presentCollection(collection, false);
}
const user = await document.getUser();
@ -85,3 +49,38 @@ export async function presentDocument(document, includeAtlas=false) {
return data;
}
export function presentCollection(collection, includeRecentDocuments=false) {
return new Promise(async (resolve, _reject) => {
const data = {
id: collection.id,
name: collection.name,
description: collection.description,
type: collection.type,
};
if (collection.type === 'atlas') {
data.navigationTree = await collection.getStructure();
}
if (includeRecentDocuments) {
const documents = await Document.findAll({
where: {
atlasId: collection.id,
},
limit: 10,
order: [
['updatedAt', 'DESC'],
],
});
const recentDocuments = [];
await Promise.all(documents.map(async (document) => {
recentDocuments.push(await presentDocument(document, true));
}));
data.recentDocuments = _orderBy(recentDocuments, ['updatedAt'], ['desc']);
}
resolve(data);
});
}