diff --git a/README.md b/README.md
index cdfc0129..2fe74c6b 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
An open, extensible, wiki for your team built using React and Node.js.
Try out Outline using our hosted version at www.getoutline.com.
-
+
@@ -63,12 +63,13 @@ Outline is composed of separate backend and frontend application which are both
### Frontend
-Outline's frontend is a React application compiled with [Webpack](https://webpack.js.org/). It uses [Mobx](https://mobx.js.org/) for state management and [Styled Components](https://www.styled-components.com/) for component styles. Unless global, state logic and styles are always co-located with React components together with their subcomponents to make the component tree easier to manage. The editor is driven by [Slate](https://github.com/ianstormtaylor/slate) with several plugins.
+Outline's frontend is a React application compiled with [Webpack](https://webpack.js.org/). It uses [Mobx](https://mobx.js.org/) for state management and [Styled Components](https://www.styled-components.com/) for component styles. Unless global, state logic and styles are always co-located with React components together with their subcomponents to make the component tree easier to manage.
+
+The editor itself is built ontop of [Slate](https://github.com/ianstormtaylor/slate) and hosted in a separate repository to encourage reuse: [rich-markdown-editor](https://github.com/outline/rich-markdown-editor)
- `app/` - Frontend React application
- `app/scenes` - Full page views
- `app/components` - Reusable React components
-- `app/components/Editor` - Text editor and its plugins
- `app/stores` - Global state stores
- `app/models` - State models
- `app/types` - Flow types for non-models
diff --git a/app/components/Sidebar/Settings.js b/app/components/Sidebar/Settings.js
index 2022e52c..db92804b 100644
--- a/app/components/Sidebar/Settings.js
+++ b/app/components/Sidebar/Settings.js
@@ -29,7 +29,7 @@ class SettingsSidebar extends React.Component {
return (
(props.showDisclosure ? '-8px' : '0')};
+ padding-right: 24px;
font-weight: 600;
color: ${color.text};
text-decoration: none;
diff --git a/package.json b/package.json
index e48d715f..45fa310d 100644
--- a/package.json
+++ b/package.json
@@ -155,21 +155,11 @@
"react-waypoint": "^7.3.1",
"redis": "^2.6.2",
"redis-lock": "^0.1.0",
- "rich-markdown-editor": "^1.0.0",
+ "rich-markdown-editor": "^1.1.0",
"safestart": "1.1.0",
"sequelize": "4.28.6",
"sequelize-cli": "^2.7.0",
"sequelize-encrypted": "0.1.0",
- "slate": "^0.32.5",
- "slate-collapse-on-escape": "^0.6.0",
- "slate-edit-code": "^0.14.0",
- "slate-edit-list": "^0.11.2",
- "slate-md-serializer": "3.0.3",
- "slate-paste-linkify": "^0.5.0",
- "slate-plain-serializer": "0.5.4",
- "slate-prism": "^0.5.0",
- "slate-react": "^0.12.3",
- "slate-trailing-block": "^0.5.0",
"slug": "0.9.1",
"string-hash": "^1.1.0",
"string-replace-to-array": "^1.0.3",
diff --git a/server/api/__snapshots__/documents.test.js.snap b/server/api/__snapshots__/documents.test.js.snap
index eaf3a72b..b2dbf607 100644
--- a/server/api/__snapshots__/documents.test.js.snap
+++ b/server/api/__snapshots__/documents.test.js.snap
@@ -8,6 +8,15 @@ Object {
}
`;
+exports[`#documents.delete should require authentication 1`] = `
+Object {
+ "error": "authentication_required",
+ "message": "Authentication required",
+ "ok": false,
+ "status": 401,
+}
+`;
+
exports[`#documents.list should require authentication 1`] = `
Object {
"error": "authentication_required",
diff --git a/server/api/documents.js b/server/api/documents.js
index 6219c36f..18d6d109 100644
--- a/server/api/documents.js
+++ b/server/api/documents.js
@@ -428,7 +428,7 @@ router.post('documents.delete', auth(), async ctx => {
authorize(ctx.state.user, 'delete', document);
const collection = document.collection;
- if (collection.type === 'atlas') {
+ if (collection && collection.type === 'atlas') {
// Delete document and all of its children
await collection.removeDocument(document);
}
diff --git a/server/api/documents.test.js b/server/api/documents.test.js
index ccc4f81a..ba5ef342 100644
--- a/server/api/documents.test.js
+++ b/server/api/documents.test.js
@@ -618,3 +618,41 @@ describe('#documents.update', async () => {
expect(res.status).toEqual(403);
});
});
+
+describe('#documents.delete', async () => {
+ it('should allow deleting document', async () => {
+ const { user, document } = await seed();
+ const res = await server.post('/api/documents.delete', {
+ body: { token: user.getJwtToken(), id: document.id },
+ });
+ const body = await res.json();
+
+ expect(res.status).toEqual(200);
+ expect(body.success).toEqual(true);
+ });
+
+ it('should allow deleting document without collection', async () => {
+ const { user, document, collection } = await seed();
+
+ // delete collection without hooks to trigger document deletion
+ await collection.destroy({ hooks: false });
+ const res = await server.post('/api/documents.delete', {
+ body: { token: user.getJwtToken(), id: document.id },
+ });
+ const body = await res.json();
+
+ expect(res.status).toEqual(200);
+ expect(body.success).toEqual(true);
+ });
+
+ it('should require authentication', async () => {
+ const { document } = await seed();
+ const res = await server.post('/api/documents.delete', {
+ body: { id: document.id },
+ });
+ const body = await res.json();
+
+ expect(res.status).toEqual(401);
+ expect(body).toMatchSnapshot();
+ });
+});
diff --git a/shared/utils/naturalSort.js b/shared/utils/naturalSort.js
index 3cfb0a25..5c564bb4 100644
--- a/shared/utils/naturalSort.js
+++ b/shared/utils/naturalSort.js
@@ -1,9 +1,8 @@
// @flow
-
import _ from 'lodash';
import naturalSort from 'natural-sort';
-export default (sortableArray: Object[], key: string) => {
+export default (sortableArray: Object[] = [], key: string) => {
let keys = sortableArray.map(object => object[key]);
keys.sort(naturalSort());
return _.sortBy(sortableArray, object => keys.indexOf(object[key]));
diff --git a/yarn.lock b/yarn.lock
index b20e7002..589cbec4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8762,9 +8762,9 @@ retry-as-promised@^2.3.1:
bluebird "^3.4.6"
debug "^2.6.9"
-rich-markdown-editor@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/rich-markdown-editor/-/rich-markdown-editor-1.0.0.tgz#ae540474e8e4e86b41d339d20cee0572c9794d2b"
+rich-markdown-editor@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/rich-markdown-editor/-/rich-markdown-editor-1.1.0.tgz#178307255bba4777c5b0f991202b522e5e0850a1"
dependencies:
"@tommoor/slate-drop-or-paste-images" "^0.8.1"
boundless-arrow-key-navigation "^1.1.0"
@@ -8778,11 +8778,11 @@ rich-markdown-editor@^1.0.0:
react-keydown "^1.9.7"
react-medium-image-zoom "^3.0.10"
react-portal "^4.1.4"
- slate "^0.32.5"
+ slate "^0.33.6"
slate-collapse-on-escape "^0.6.0"
slate-edit-code "^0.14.0"
slate-edit-list "^0.11.2"
- slate-md-serializer "3.0.4"
+ slate-md-serializer "3.1.0"
slate-paste-linkify "^0.5.0"
slate-plain-serializer "0.5.4"
slate-prism "^0.5.0"
@@ -9143,13 +9143,9 @@ slate-edit-list@^0.11.2:
version "0.11.2"
resolved "https://registry.yarnpkg.com/slate-edit-list/-/slate-edit-list-0.11.2.tgz#c67b961d98435f9f7747d20b870cbc51d25af7a8"
-slate-md-serializer@3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/slate-md-serializer/-/slate-md-serializer-3.0.3.tgz#194aaf74b8c5158cdd45f8d2394a1a1574acaf83"
-
-slate-md-serializer@3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/slate-md-serializer/-/slate-md-serializer-3.0.4.tgz#0ee04c0c2e44954b82f9fab1410b658bb6191aad"
+slate-md-serializer@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/slate-md-serializer/-/slate-md-serializer-3.1.0.tgz#8e82899c45a607615b19e03d42cbd38cc7f64acf"
slate-paste-linkify@^0.5.0:
version "0.5.0"
@@ -9202,26 +9198,26 @@ slate-react@^0.12.3:
slate-plain-serializer "^0.5.9"
slate-prop-types "^0.4.26"
-slate-schema-violations@^0.1.3:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/slate-schema-violations/-/slate-schema-violations-0.1.7.tgz#cf2c6156eaf545f4d1985d3d1b94c50d6d273a08"
+slate-schema-violations@^0.1.10:
+ version "0.1.10"
+ resolved "https://registry.yarnpkg.com/slate-schema-violations/-/slate-schema-violations-0.1.10.tgz#165227c230ea6c1027e523b7171a73e860e73646"
slate-trailing-block@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/slate-trailing-block/-/slate-trailing-block-0.5.0.tgz#cedb4f2975f1167e0fb9d259ce1252b82f4d74ff"
-slate@^0.32.5:
- version "0.32.5"
- resolved "https://registry.yarnpkg.com/slate/-/slate-0.32.5.tgz#5386c75dec1e5b87648189c9fbb4294cec623ff0"
+slate@^0.33.6:
+ version "0.33.6"
+ resolved "https://registry.yarnpkg.com/slate/-/slate-0.33.6.tgz#0c7cb193cc5adeecec5c81e2ec0c86ab23dd6755"
dependencies:
- debug "^2.3.2"
+ debug "^3.1.0"
direction "^0.1.5"
esrever "^0.2.0"
is-empty "^1.0.0"
is-plain-object "^2.0.4"
lodash "^4.17.4"
slate-dev-logger "^0.1.39"
- slate-schema-violations "^0.1.3"
+ slate-schema-violations "^0.1.10"
type-of "^2.0.1"
slice-ansi@0.0.4: