From 224f94a79e04740b9c845a5c1444ab4b151c3cf2 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sat, 2 Dec 2017 16:27:45 -0800 Subject: [PATCH 01/15] Added ability to print a document --- app/components/Actions/Actions.js | 4 ++++ app/components/Editor/Editor.js | 4 ++++ app/components/Editor/components/Contents.js | 4 ++++ app/components/Layout/Layout.js | 4 ++++ app/components/Sidebar/Sidebar.js | 5 +++++ app/menus/DocumentMenu.js | 1 + 6 files changed, 22 insertions(+) diff --git a/app/components/Actions/Actions.js b/app/components/Actions/Actions.js index 7296f1d55..0aebc3694 100644 --- a/app/components/Actions/Actions.js +++ b/app/components/Actions/Actions.js @@ -29,6 +29,10 @@ const Actions = styled(Flex)` border-radius: 3px; background: rgba(255, 255, 255, 0.9); -webkit-backdrop-filter: blur(20px); + + @media print { + display: none; + } `; export default Actions; diff --git a/app/components/Editor/Editor.js b/app/components/Editor/Editor.js index 8fa84d74e..92b5e6ef5 100644 --- a/app/components/Editor/Editor.js +++ b/app/components/Editor/Editor.js @@ -238,6 +238,10 @@ const Header = styled(Flex)` flex-shrink: 0; align-items: flex-end; ${({ readOnly }) => !readOnly && 'cursor: text;'}; + + @media print { + display: none; + } `; const StyledEditor = styled(Editor)` diff --git a/app/components/Editor/components/Contents.js b/app/components/Editor/components/Contents.js index b92ef7ceb..d89facb08 100644 --- a/app/components/Editor/components/Contents.js +++ b/app/components/Editor/components/Contents.js @@ -92,6 +92,10 @@ const Wrapper = styled.div` right: 0; top: 150px; z-index: 100; + + @media print { + display: none; + } `; const Anchor = styled.a` diff --git a/app/components/Layout/Layout.js b/app/components/Layout/Layout.js index 29878ed11..b5d755d00 100644 --- a/app/components/Layout/Layout.js +++ b/app/components/Layout/Layout.js @@ -124,6 +124,10 @@ const Container = styled(Flex)` const Content = styled(Flex)` margin-left: ${props => (props.editMode ? 0 : layout.sidebarWidth)}; transition: margin-left 200ms ease-in-out; + + @media print { + margin-left: 0; + } `; export default withRouter(inject('user', 'auth', 'ui', 'documents')(Layout)); diff --git a/app/components/Sidebar/Sidebar.js b/app/components/Sidebar/Sidebar.js index 92fbf89a0..348d7dcaa 100644 --- a/app/components/Sidebar/Sidebar.js +++ b/app/components/Sidebar/Sidebar.js @@ -106,6 +106,11 @@ const Container = styled(Flex)` width: ${layout.sidebarWidth}; background: ${color.smoke}; transition: left 200ms ease-in-out; + + @media print { + display: none; + left: 0; + } `; const Section = styled(Flex)` diff --git a/app/menus/DocumentMenu.js b/app/menus/DocumentMenu.js index e4dedde06..e6103d6e7 100644 --- a/app/menus/DocumentMenu.js +++ b/app/menus/DocumentMenu.js @@ -67,6 +67,7 @@ class DocumentMenu extends Component { Download + Print Move… {allowDelete && ( From 81d0072449a946b4cceb8bc857e646a3b2bf0dff Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sat, 2 Dec 2017 17:44:45 -0800 Subject: [PATCH 02/15] Added media print style to dropdowns --- app/components/DropdownMenu/DropdownMenu.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/components/DropdownMenu/DropdownMenu.js b/app/components/DropdownMenu/DropdownMenu.js index cf5cfa22e..f7ec529ff 100644 --- a/app/components/DropdownMenu/DropdownMenu.js +++ b/app/components/DropdownMenu/DropdownMenu.js @@ -96,6 +96,10 @@ const Menu = styled.div` overflow: hidden; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05), 0 4px 8px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.08); + + @media print { + display: none; + } `; export default DropdownMenu; From b42f123b1a15509e40a1ec552a16807e3883827e Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sat, 2 Dec 2017 18:04:34 -0800 Subject: [PATCH 03/15] Fixed sidebar styles when open collection --- app/components/Sidebar/components/Collections.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/components/Sidebar/components/Collections.js b/app/components/Sidebar/components/Collections.js index 3fa4066fb..b09e365b9 100644 --- a/app/components/Sidebar/components/Collections.js +++ b/app/components/Sidebar/components/Collections.js @@ -5,7 +5,7 @@ import { observer, inject } from 'mobx-react'; import type { Location } from 'react-router-dom'; import Flex from 'shared/components/Flex'; import styled from 'styled-components'; -import { color } from 'shared/styles/constants'; +import { color, fontWeight } from 'shared/styles/constants'; import Header from './Header'; import SidebarLink from './SidebarLink'; @@ -264,6 +264,8 @@ const StyledDropToImport = styled(DropToImport)` const Children = styled(Flex)` margin-left: 12px; + font-weight: ${fontWeight.regular}; + color: ${color.slateDark}; `; export default inject('collections', 'ui', 'documents')(Collections); From c13451186a8b062b7e992e1e6b4b837059eed31e Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sat, 2 Dec 2017 22:50:24 -0800 Subject: [PATCH 04/15] Hiding toolbars for printing --- app/components/Editor/components/Toolbar/BlockToolbar.js | 4 ++++ app/components/Editor/components/Toolbar/Toolbar.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/app/components/Editor/components/Toolbar/BlockToolbar.js b/app/components/Editor/components/Toolbar/BlockToolbar.js index 165d5cca6..bdeb70285 100644 --- a/app/components/Editor/components/Toolbar/BlockToolbar.js +++ b/app/components/Editor/components/Toolbar/BlockToolbar.js @@ -182,6 +182,10 @@ const Bar = styled(Flex)` left: auto; right: -100%; } + + @media print { + display: none; + } `; const HiddenInput = styled.input` diff --git a/app/components/Editor/components/Toolbar/Toolbar.js b/app/components/Editor/components/Toolbar/Toolbar.js index 696e3ed45..929d60e9f 100644 --- a/app/components/Editor/components/Toolbar/Toolbar.js +++ b/app/components/Editor/components/Toolbar/Toolbar.js @@ -150,4 +150,8 @@ const Menu = styled.div` transform: translateY(-6px) scale(1); opacity: 1; `}; + + @media print { + display: none; + } `; From 36b8e4935380ebe6d2429e95b09b8b5b8a6512a3 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sun, 3 Dec 2017 11:04:17 -0800 Subject: [PATCH 05/15] Fixed search ordering --- server/models/Document.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/server/models/Document.js b/server/models/Document.js index 3bbf8c9ed..1f4e2892f 100644 --- a/server/models/Document.js +++ b/server/models/Document.js @@ -160,16 +160,20 @@ Document.findById = async id => { } }; -Document.searchForUser = async (user, query, options = {}) => { +Document.searchForUser = async ( + user, + query, + options = {} +): Promise => { const limit = options.limit || 15; const offset = options.offset || 0; const sql = ` - SELECT * FROM documents + SELECT *, ts_rank(documents."searchVector", plainto_tsquery('english', :query)) as "searchRanking" FROM documents WHERE "searchVector" @@ plainto_tsquery('english', :query) AND "teamId" = '${user.teamId}'::uuid AND "deletedAt" IS NULL - ORDER BY ts_rank(documents."searchVector", plainto_tsquery('english', :query)) DESC + ORDER BY "searchRanking" DESC LIMIT :limit OFFSET :offset; `; @@ -184,10 +188,17 @@ Document.searchForUser = async (user, query, options = {}) => { }) .map(document => document.id); + // Second query to get views for the data const withViewsScope = { method: ['withViews', user.id] }; - return Document.scope('defaultScope', withViewsScope).findAll({ + const documents = await Document.scope( + 'defaultScope', + withViewsScope + ).findAll({ where: { id: ids }, }); + + // Order the documents in the same order as the first query + return _.sortBy(documents, doc => ids.indexOf(doc.id)); }; // Instance methods From 5df2983ef610be8ab34bbd7a6681b1dbbd986660 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sun, 3 Dec 2017 16:50:50 -0800 Subject: [PATCH 06/15] Search improvements --- app/scenes/Search/Search.js | 46 ++++++++++++++++++++++++++++++++---- app/stores/DocumentsStore.js | 21 ++++++++++++---- app/types/index.js | 9 +++++++ package.json | 1 + server/api/documents.js | 8 +++++-- yarn.lock | 13 +++++++++- 6 files changed, 86 insertions(+), 12 deletions(-) diff --git a/app/scenes/Search/Search.js b/app/scenes/Search/Search.js index 9d63fde7b..8766e3789 100644 --- a/app/scenes/Search/Search.js +++ b/app/scenes/Search/Search.js @@ -2,10 +2,13 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import keydown from 'react-keydown'; +import Waypoint from 'react-waypoint'; import { observable, action } from 'mobx'; import { observer, inject } from 'mobx-react'; import _ from 'lodash'; -import DocumentsStore from 'stores/DocumentsStore'; +import DocumentsStore, { + DEFAULT_PAGINATION_LIMIT, +} from 'stores/DocumentsStore'; import { withRouter } from 'react-router-dom'; import { searchUrl } from 'utils/routeHelpers'; @@ -44,6 +47,7 @@ const ResultsWrapper = styled(Flex)` `; const ResultList = styled(Flex)` + margin-bottom: 150px; opacity: ${props => (props.visible ? '1' : '0')}; transition: all 400ms cubic-bezier(0.65, 0.05, 0.36, 1); `; @@ -61,6 +65,8 @@ class Search extends Component { @observable resultIds: string[] = []; // Document IDs @observable query: string = ''; + @observable offset: number = 0; + @observable allowLoadMore: boolean = true; @observable isFetching = false; componentDidMount() { @@ -98,10 +104,27 @@ class Search extends Component { handleQueryChange = () => { const query = this.props.match.params.query; this.query = query ? decodeURIComponent(query) : ''; + this.allowLoadMore = true; + + // To prevent "no results" showing before debounce kicks in + if (this.query) this.isFetching = true; + this.fetchResultsDebounced(); }; - fetchResultsDebounced = _.debounce(this.fetchResults, 250); + fetchResultsDebounced = _.debounce(this.fetchResults, 350, { + leading: false, + trailing: true, + }); + + @action + loadMoreResults = async () => { + // Don't paginate if there aren't more results or we're in the middle of fetching + if (!this.allowLoadMore || this.isFetching) return; + + // Fetch more results + await this.fetchResults(); + }; @action fetchResults = async () => { @@ -109,7 +132,19 @@ class Search extends Component { if (this.query) { try { - this.resultIds = await this.props.documents.search(this.query); + const newResults = await this.props.documents.search(this.query, { + offset: this.offset, + limit: DEFAULT_PAGINATION_LIMIT, + }); + this.resultIds = this.resultIds.concat(newResults); + if ( + newResults.length === 0 || + newResults.length < DEFAULT_PAGINATION_LIMIT + ) { + this.allowLoadMore = false; + } else { + this.offset += DEFAULT_PAGINATION_LIMIT; + } } catch (e) { console.error('Something went wrong'); } @@ -157,7 +192,7 @@ class Search extends Component { value={this.query} /> {showEmpty && No matching documents.} - + + {this.allowLoadMore && ( + + )} diff --git a/app/stores/DocumentsStore.js b/app/stores/DocumentsStore.js index 8bdc77eac..f0191904d 100644 --- a/app/stores/DocumentsStore.js +++ b/app/stores/DocumentsStore.js @@ -17,8 +17,10 @@ import Document from 'models/Document'; import ErrorsStore from 'stores/ErrorsStore'; import CacheStore from 'stores/CacheStore'; import UiStore from 'stores/UiStore'; +import type { PaginationParams } from 'types'; const DOCUMENTS_CACHE_KEY = 'DOCUMENTS_CACHE_KEY'; +export const DEFAULT_PAGINATION_LIMIT = 25; type Options = { cache: CacheStore, @@ -77,7 +79,10 @@ class DocumentsStore extends BaseStore { /* Actions */ @action - fetchAll = async (request: string = 'list', options: ?Object): Promise<*> => { + fetchAll = async ( + request: string = 'list', + options: ?PaginationParams + ): Promise<*> => { this.isFetching = true; try { @@ -99,12 +104,12 @@ class DocumentsStore extends BaseStore { }; @action - fetchRecentlyModified = async (options: ?Object): Promise<*> => { + fetchRecentlyModified = async (options: ?PaginationParams): Promise<*> => { return await this.fetchAll('list', options); }; @action - fetchRecentlyViewed = async (options: ?Object): Promise<*> => { + fetchRecentlyViewed = async (options: ?PaginationParams): Promise<*> => { const data = await this.fetchAll('viewed', options); runInAction('DocumentsStore#fetchRecentlyViewed', () => { @@ -119,8 +124,14 @@ class DocumentsStore extends BaseStore { }; @action - search = async (query: string): Promise<*> => { - const res = await client.get('/documents.search', { query }); + search = async ( + query: string, + options: PaginationParams + ): Promise => { + const res = await client.get('/documents.search', { + ...options, + query, + }); invariant(res && res.data, 'res or res.data missing'); const { data } = res; data.forEach(documentData => this.add(new Document(documentData))); diff --git a/app/types/index.js b/app/types/index.js index 63d861398..a03ef21eb 100644 --- a/app/types/index.js +++ b/app/types/index.js @@ -39,12 +39,21 @@ export type Document = { views: number, }; +// Pagination response in an API call export type Pagination = { limit: number, nextPath: string, offset: number, }; +// Pagination request params +export type PaginationParams = { + limit?: number, + offset?: number, + sort?: string, + direction?: 'ASC' | 'DESC', +}; + export type ApiKey = { id: string, name: ?string, diff --git a/package.json b/package.json index d80f7a16b..6d730d68f 100644 --- a/package.json +++ b/package.json @@ -153,6 +153,7 @@ "react-modal": "^3.1.2", "react-portal": "^4.0.0", "react-router-dom": "^4.2.0", + "react-waypoint": "^7.3.1", "redis": "^2.6.2", "redis-lock": "^0.1.0", "rimraf": "^2.5.4", diff --git a/server/api/documents.js b/server/api/documents.js index 2aeae2787..1c29fead3 100644 --- a/server/api/documents.js +++ b/server/api/documents.js @@ -142,13 +142,17 @@ router.post('documents.revisions', auth(), pagination(), async ctx => { }; }); -router.post('documents.search', auth(), async ctx => { +router.post('documents.search', auth(), pagination(), async ctx => { const { query } = ctx.body; + const { offset, limit } = ctx.state.pagination; ctx.assertPresent(query, 'query is required'); const user = await ctx.state.user; - const documents = await Document.searchForUser(user, query); + const documents = await Document.searchForUser(user, query, { + offset, + limit, + }); const data = await Promise.all( documents.map(async document => await presentDocument(ctx, document)) diff --git a/yarn.lock b/yarn.lock index 2d541e7d0..6c993f020 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1825,6 +1825,10 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" +consolidated-events@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/consolidated-events/-/consolidated-events-1.1.1.tgz#25395465b35e531395418b7bbecb5ecaf198d179" + constant-case@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46" @@ -7207,7 +7211,7 @@ prop-types@>=15.5.6, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8 fbjs "^0.8.9" loose-envify "^1.3.1" -prop-types@^15.5.7, prop-types@^15.6.0: +prop-types@^15.0.0, prop-types@^15.5.7, prop-types@^15.6.0: version "15.6.0" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" dependencies: @@ -7498,6 +7502,13 @@ react-transform-hmr@^1.0.3: global "^4.3.0" react-proxy "^1.1.7" +react-waypoint@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/react-waypoint/-/react-waypoint-7.3.1.tgz#abb165d9b6c9590f8d82ceafbe61c2c887262a37" + dependencies: + consolidated-events "^1.1.0" + prop-types "^15.0.0" + react@^15.5.4: version "15.6.2" resolved "https://registry.npmjs.org/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72" From 060066ceeeafe31e16308b890a971ce01230f938 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sun, 3 Dec 2017 19:18:22 -0800 Subject: [PATCH 07/15] More detailed error boundary for Document --- .../CenteredContent/CenteredContent.js | 2 +- app/components/ErrorBoundary/ErrorBoundary.js | 13 +- app/scenes/Document/Document.js | 139 +++++++++--------- 3 files changed, 83 insertions(+), 71 deletions(-) diff --git a/app/components/CenteredContent/CenteredContent.js b/app/components/CenteredContent/CenteredContent.js index bcfaedb8f..b3736f6c8 100644 --- a/app/components/CenteredContent/CenteredContent.js +++ b/app/components/CenteredContent/CenteredContent.js @@ -8,7 +8,7 @@ type Props = { const Container = styled.div` width: 100%; - margin: 60px; + padding: 60px; `; const Content = styled.div` diff --git a/app/components/ErrorBoundary/ErrorBoundary.js b/app/components/ErrorBoundary/ErrorBoundary.js index 7577017a9..02bbc5188 100644 --- a/app/components/ErrorBoundary/ErrorBoundary.js +++ b/app/components/ErrorBoundary/ErrorBoundary.js @@ -9,6 +9,14 @@ import PageTitle from 'components/PageTitle'; class ErrorBoundary extends Component { @observable error: boolean = false; + componentWillReceiveProps(nextProps: Object) { + if ( + (this.props.location || nextProps.location) && + this.props.location.pathname !== nextProps.location.pathname + ) + this.error = false; + } + componentDidCatch(error: Error, info: Object) { this.error = true; @@ -27,9 +35,10 @@ class ErrorBoundary extends Component { return ( -

Something went wrong

+

🛸 Something unexpected happened

- An unrecoverable error occurred. Please try{' '} + An unrecoverable error occurred{window.Bugsnag || + (true && ' and our engineers have been notified')}. Please try{' '} reloading.

diff --git a/app/scenes/Document/Document.js b/app/scenes/Document/Document.js index 7aa08b9cb..af22e5536 100644 --- a/app/scenes/Document/Document.js +++ b/app/scenes/Document/Document.js @@ -33,6 +33,7 @@ import CenteredContent from 'components/CenteredContent'; import PageTitle from 'components/PageTitle'; import NewDocumentIcon from 'components/Icon/NewDocumentIcon'; import Actions, { Action, Separator } from 'components/Actions'; +import ErrorBoundary from 'components/ErrorBoundary'; import Search from 'scenes/Search'; const DISCARD_CHANGES = ` @@ -216,75 +217,77 @@ class DocumentScene extends Component { return ( - {isMoving && document && } - {titleText && } - {(this.isLoading || this.isSaving) && } - {isFetching && ( - - - - )} - {!isFetching && - document && ( - - - - - {!isNew && - !this.isEditing && } - - {this.isEditing ? ( - - ) : ( - Edit - )} - - {this.isEditing && ( - - Discard - - )} - {!this.isEditing && ( - - - - )} - {!this.isEditing && } - - {!this.isEditing && ( - - - - )} - - - + + {isMoving && document && } + {titleText && } + {(this.isLoading || this.isSaving) && } + {isFetching && ( + + + )} + {!isFetching && + document && ( + + + + + {!isNew && + !this.isEditing && } + + {this.isEditing ? ( + + ) : ( + Edit + )} + + {this.isEditing && ( + + Discard + + )} + {!this.isEditing && ( + + + + )} + {!this.isEditing && } + + {!this.isEditing && ( + + + + )} + + + + )} + ); } From f3e3e6d2ca142824c9f3fe21a7c7a15920219887 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sun, 3 Dec 2017 19:21:58 -0800 Subject: [PATCH 08/15] props --- app/components/ErrorBoundary/ErrorBoundary.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/components/ErrorBoundary/ErrorBoundary.js b/app/components/ErrorBoundary/ErrorBoundary.js index 02bbc5188..60a380364 100644 --- a/app/components/ErrorBoundary/ErrorBoundary.js +++ b/app/components/ErrorBoundary/ErrorBoundary.js @@ -2,16 +2,23 @@ import React, { Component } from 'react'; import { observer } from 'mobx-react'; import { observable } from 'mobx'; +import type { Location } from 'react-router-dom'; import CenteredContent from 'components/CenteredContent'; import PageTitle from 'components/PageTitle'; +type Props = { + location?: Location, +}; + @observer class ErrorBoundary extends Component { + props: Props; @observable error: boolean = false; componentWillReceiveProps(nextProps: Object) { if ( - (this.props.location || nextProps.location) && + this.props.location && + nextProps.location && this.props.location.pathname !== nextProps.location.pathname ) this.error = false; From 42d5686182ead5b6a8f8e506e24e3660b79bf499 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sun, 3 Dec 2017 19:29:04 -0800 Subject: [PATCH 09/15] linting --- app/components/ErrorBoundary/ErrorBoundary.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/components/ErrorBoundary/ErrorBoundary.js b/app/components/ErrorBoundary/ErrorBoundary.js index 60a380364..162e164f5 100644 --- a/app/components/ErrorBoundary/ErrorBoundary.js +++ b/app/components/ErrorBoundary/ErrorBoundary.js @@ -8,6 +8,7 @@ import PageTitle from 'components/PageTitle'; type Props = { location?: Location, + children?: ?React.Element, }; @observer From 98124a1c4b5dcdf6098fef78817391e82718b726 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sun, 3 Dec 2017 19:48:50 -0800 Subject: [PATCH 10/15] linting --- app/stores/DocumentsStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/stores/DocumentsStore.js b/app/stores/DocumentsStore.js index f0191904d..6e280d5ff 100644 --- a/app/stores/DocumentsStore.js +++ b/app/stores/DocumentsStore.js @@ -126,7 +126,7 @@ class DocumentsStore extends BaseStore { @action search = async ( query: string, - options: PaginationParams + options?: PaginationParams ): Promise => { const res = await client.get('/documents.search', { ...options, From 564748cfc0678f2295fa6edc787e329c9bca559c Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Sun, 3 Dec 2017 20:56:45 -0800 Subject: [PATCH 11/15] Use key instead --- app/components/ErrorBoundary/ErrorBoundary.js | 11 ----------- app/scenes/Document/Document.js | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/app/components/ErrorBoundary/ErrorBoundary.js b/app/components/ErrorBoundary/ErrorBoundary.js index 162e164f5..f34df8fac 100644 --- a/app/components/ErrorBoundary/ErrorBoundary.js +++ b/app/components/ErrorBoundary/ErrorBoundary.js @@ -2,12 +2,10 @@ import React, { Component } from 'react'; import { observer } from 'mobx-react'; import { observable } from 'mobx'; -import type { Location } from 'react-router-dom'; import CenteredContent from 'components/CenteredContent'; import PageTitle from 'components/PageTitle'; type Props = { - location?: Location, children?: ?React.Element, }; @@ -16,15 +14,6 @@ class ErrorBoundary extends Component { props: Props; @observable error: boolean = false; - componentWillReceiveProps(nextProps: Object) { - if ( - this.props.location && - nextProps.location && - this.props.location.pathname !== nextProps.location.pathname - ) - this.error = false; - } - componentDidCatch(error: Error, info: Object) { this.error = true; diff --git a/app/scenes/Document/Document.js b/app/scenes/Document/Document.js index af22e5536..084d96f68 100644 --- a/app/scenes/Document/Document.js +++ b/app/scenes/Document/Document.js @@ -217,7 +217,7 @@ class DocumentScene extends Component { return ( - + {isMoving && document && } {titleText && } {(this.isLoading || this.isSaving) && } From 553095692cbd8e6358ed1a82187cebf2500dce40 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Tue, 5 Dec 2017 00:15:34 -0800 Subject: [PATCH 12/15] Clear active collection if navigating out of it directly Fixes #474 --- app/scenes/Collection/Collection.js | 4 ++++ app/scenes/Document/Document.js | 2 +- app/stores/UiStore.js | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/scenes/Collection/Collection.js b/app/scenes/Collection/Collection.js index 9375ac37a..74bc1b4a5 100644 --- a/app/scenes/Collection/Collection.js +++ b/app/scenes/Collection/Collection.js @@ -49,6 +49,10 @@ class CollectionScene extends Component { } } + componentWillUnmount() { + this.props.ui.clearActiveCollection(); + } + loadContent = async (id: string) => { const { collections } = this.props; diff --git a/app/scenes/Document/Document.js b/app/scenes/Document/Document.js index 084d96f68..da430b8ef 100644 --- a/app/scenes/Document/Document.js +++ b/app/scenes/Document/Document.js @@ -63,7 +63,7 @@ class DocumentScene extends Component { @observable notFound = false; @observable moveModalOpen: boolean = false; - componentWillMount() { + componentDidMount() { this.loadDocument(this.props); } diff --git a/app/stores/UiStore.js b/app/stores/UiStore.js index 3fc05269d..09e42feb9 100644 --- a/app/stores/UiStore.js +++ b/app/stores/UiStore.js @@ -35,6 +35,11 @@ class UiStore { this.activeCollectionId = collection.id; }; + @action + clearActiveCollection = (): void => { + this.activeCollectionId = undefined; + }; + @action clearActiveDocument = (): void => { this.activeDocumentId = undefined; From 5a0f3d027afcf4da4f04ab1686a9df8e55f8194b Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Tue, 5 Dec 2017 00:16:05 -0800 Subject: [PATCH 13/15] Remove sidebar scrolling Fixes #473 --- app/components/Sidebar/Sidebar.js | 18 +----------------- .../Sidebar/components/Collections.js | 14 +------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/app/components/Sidebar/Sidebar.js b/app/components/Sidebar/Sidebar.js index 348d7dcaa..d337d4220 100644 --- a/app/components/Sidebar/Sidebar.js +++ b/app/components/Sidebar/Sidebar.js @@ -29,7 +29,6 @@ type Props = { @observer class Sidebar extends Component { props: Props; - scrollable: ?HTMLDivElement; handleCreateCollection = () => { this.props.ui.setActiveModal('collection-new'); @@ -39,20 +38,6 @@ class Sidebar extends Component { this.props.ui.setActiveModal('collection-edit'); }; - setScrollableRef = ref => { - this.scrollable = ref; - }; - - scrollToActiveDocument = ref => { - const scrollable = this.scrollable; - if (!ref || !scrollable) return; - - const container = scrollable.getBoundingClientRect(); - const bounds = ref.getBoundingClientRect(); - const scrollTop = bounds.top + container.top; - scrollable.scrollTop = scrollTop; - }; - render() { const { auth, ui } = this.props; const { user, team } = auth; @@ -71,7 +56,7 @@ class Sidebar extends Component { /> - +
}> Home @@ -88,7 +73,6 @@ class Sidebar extends Component { history={this.props.history} location={this.props.location} onCreateCollection={this.handleCreateCollection} - activeDocumentRef={this.scrollToActiveDocument} />
diff --git a/app/components/Sidebar/components/Collections.js b/app/components/Sidebar/components/Collections.js index b09e365b9..dcafa20ee 100644 --- a/app/components/Sidebar/components/Collections.js +++ b/app/components/Sidebar/components/Collections.js @@ -27,7 +27,6 @@ type Props = { collections: CollectionsStore, documents: DocumentsStore, onCreateCollection: () => void, - activeDocumentRef: HTMLElement => void, ui: UiStore, }; @@ -36,14 +35,7 @@ class Collections extends Component { props: Props; render() { - const { - history, - location, - collections, - ui, - activeDocumentRef, - documents, - } = this.props; + const { history, location, collections, ui, documents } = this.props; return ( @@ -55,7 +47,6 @@ class Collections extends Component { location={location} collection={collection} activeDocument={documents.active} - activeDocumentRef={activeDocumentRef} prefetchDocument={documents.prefetchDocument} ui={ui} /> @@ -79,7 +70,6 @@ type CollectionLinkProps = { collection: Collection, ui: UiStore, activeDocument: ?Document, - activeDocumentRef: HTMLElement => void, prefetchDocument: (id: string) => Promise, }; @@ -100,7 +90,6 @@ class CollectionLink extends Component { collection, activeDocument, ui, - activeDocumentRef, prefetchDocument, } = this.props; const expanded = collection.id === ui.activeCollectionId; @@ -140,7 +129,6 @@ class CollectionLink extends Component { {collection.documents.map(document => ( Date: Tue, 5 Dec 2017 01:22:22 -0800 Subject: [PATCH 14/15] Fixed React warnings --- app/components/Collaborators/Collaborators.js | 4 ++-- app/components/DocumentPreview/DocumentPreview.js | 8 ++++---- app/scenes/Dashboard/Dashboard.js | 14 ++++++++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/components/Collaborators/Collaborators.js b/app/components/Collaborators/Collaborators.js index d7eaf16e2..88b88cfb4 100644 --- a/app/components/Collaborators/Collaborators.js +++ b/app/components/Collaborators/Collaborators.js @@ -29,8 +29,8 @@ const Collaborators = ({ document }: Props) => { {collaborators.map(user => ( - - + + ))} diff --git a/app/components/DocumentPreview/DocumentPreview.js b/app/components/DocumentPreview/DocumentPreview.js index 244162aa1..ae7e089c7 100644 --- a/app/components/DocumentPreview/DocumentPreview.js +++ b/app/components/DocumentPreview/DocumentPreview.js @@ -98,13 +98,13 @@ class DocumentPreview extends Component {

{document.starred ? ( - + - + ) : ( - + - + )}

{hasRecentlyViewed && [ - Recently viewed, - , + Recently viewed, + , ]} {hasRecentlyEdited && [ - Recently edited, - , + Recently edited, + , ]} ) : ( From c9fc437888ae2cd865dc4da1e51892203a40ea96 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Tue, 5 Dec 2017 21:09:15 -0800 Subject: [PATCH 15/15] Fixes --- .../Sidebar/components/Collections.js | 58 +++++++++++-------- .../Sidebar/components/SidebarLink.js | 21 +++++-- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/app/components/Sidebar/components/Collections.js b/app/components/Sidebar/components/Collections.js index dcafa20ee..0ad66df5a 100644 --- a/app/components/Sidebar/components/Collections.js +++ b/app/components/Sidebar/components/Collections.js @@ -5,7 +5,7 @@ import { observer, inject } from 'mobx-react'; import type { Location } from 'react-router-dom'; import Flex from 'shared/components/Flex'; import styled from 'styled-components'; -import { color, fontWeight } from 'shared/styles/constants'; +import { color } from 'shared/styles/constants'; import Header from './Header'; import SidebarLink from './SidebarLink'; @@ -84,14 +84,32 @@ class CollectionLink extends Component { this.dropzoneRef.open(); }; - render() { + renderDocuments() { const { history, collection, activeDocument, - ui, prefetchDocument, } = this.props; + + return ( + + {collection.documents.map(document => ( + + ))} + + ); + } + + render() { + const { history, collection, ui } = this.props; const expanded = collection.id === ui.activeCollectionId; return ( @@ -108,6 +126,9 @@ class CollectionLink extends Component { to={collection.url} icon={} iconColor={collection.color} + expandedContent={this.renderDocuments()} + hideExpandToggle + expand={expanded} > {collection.name} @@ -123,21 +144,6 @@ class CollectionLink extends Component { /> - - {expanded && ( - - {collection.documents.map(document => ( - - ))} - - )} ); @@ -194,7 +200,7 @@ const DocumentLink = observer( expand={showChildren} expandedContent={ document.children.length ? ( - + {document.children.map(childDocument => ( ))} - + ) : ( undefined ) @@ -223,7 +229,7 @@ const CollectionName = styled(Flex)` padding: 0 0 4px; `; -const CollectionAction = styled.a` +const CollectionAction = styled.span` position: absolute; right: 0; color: ${color.slate}; @@ -250,10 +256,14 @@ const StyledDropToImport = styled(DropToImport)` } `; -const Children = styled(Flex)` +const CollectionChildren = styled(Flex)` + margin-top: -4px; + margin-left: 36px; +`; + +const DocumentChildren = styled(Flex)` + margin-top: -4px; margin-left: 12px; - font-weight: ${fontWeight.regular}; - color: ${color.slateDark}; `; export default inject('collections', 'ui', 'documents')(Collections); diff --git a/app/components/Sidebar/components/SidebarLink.js b/app/components/Sidebar/components/SidebarLink.js index fe43ff2d2..d52b8dd5a 100644 --- a/app/components/Sidebar/components/SidebarLink.js +++ b/app/components/Sidebar/components/SidebarLink.js @@ -33,7 +33,7 @@ const StyledNavLink = styled(NavLink)` overflow: hidden; text-overflow: ellipsis; padding: 4px 0; - margin-left: ${({ hasChildren }) => (hasChildren ? '-20px;' : '0')}; + margin-left: ${({ iconVisible }) => (iconVisible ? '-20px;' : '0')}; color: ${color.slateDark}; font-size: 15px; cursor: pointer; @@ -52,6 +52,7 @@ type Props = { icon?: React$Element<*>, expand?: boolean, expandedContent?: React$Element<*>, + hideExpandToggle?: boolean, iconColor?: string, }; @@ -81,25 +82,35 @@ class SidebarLink extends Component { }; render() { - const { icon, children, onClick, to, expandedContent } = this.props; + const { + icon, + children, + onClick, + to, + expandedContent, + expand, + hideExpandToggle, + } = this.props; const Component = to ? StyledNavLink : StyledDiv; + const showExpandIcon = expandedContent && !hideExpandToggle; return ( {icon && {icon}} - {expandedContent && ( + {showExpandIcon && ( )} {children} - {this.expanded && expandedContent} + {/* Collection */ expand && hideExpandToggle && expandedContent} + {/* Document */ this.expanded && !hideExpandToggle && expandedContent} ); }