Renaming atlases to collections
This commit is contained in:
@ -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>
|
||||
);
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
|
@ -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>
|
||||
|
@ -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));
|
||||
});
|
||||
|
@ -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;
|
||||
|
@ -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 });
|
||||
|
@ -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 }
|
||||
|
@ -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");
|
||||
|
@ -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),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user