Merge pull request #871 from outline/less-with-router

Reduce withRouter usage
This commit is contained in:
Tom Moor
2019-01-19 13:33:12 -08:00
committed by GitHub
23 changed files with 197 additions and 175 deletions

View File

@@ -2,8 +2,8 @@
import * as React from 'react';
import { observable } from 'mobx';
import { observer, inject } from 'mobx-react';
import { Redirect } from 'react-router-dom';
import { createGlobalStyle } from 'styled-components';
import { omit } from 'lodash';
import invariant from 'invariant';
import importFile from 'utils/importFile';
import Dropzone from 'react-dropzone';
@@ -18,11 +18,11 @@ type Props = {
rejectClassName?: string,
documents: DocumentsStore,
disabled: boolean,
history: Object,
};
const GlobalStyles = createGlobalStyle`
export const GlobalStyles = createGlobalStyle`
.activeDropZone {
border-radius: 4px;
background: ${props => props.theme.slateDark};
svg { fill: ${props => props.theme.white}; }
}
@@ -35,6 +35,7 @@ const GlobalStyles = createGlobalStyle`
@observer
class DropToImport extends React.Component<Props> {
@observable isImporting: boolean = false;
@observable redirectTo: ?string;
onDropAccepted = async (files = []) => {
this.isImporting = true;
@@ -59,7 +60,7 @@ class DropToImport extends React.Component<Props> {
});
if (redirect) {
this.props.history.push(doc.url);
this.redirectTo = doc.url;
}
}
} finally {
@@ -68,16 +69,15 @@ class DropToImport extends React.Component<Props> {
};
render() {
const props = omit(
this.props,
'history',
'documentId',
'collectionId',
'documents',
'disabled',
'menuOpen'
);
const {
documentId,
collectionId,
documents,
disabled,
...rest
} = this.props;
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
if (this.props.disabled) return this.props.children;
return (
@@ -88,9 +88,8 @@ class DropToImport extends React.Component<Props> {
disableClick
disablePreview
multiple
{...props}
{...rest}
>
<GlobalStyles />
{this.isImporting && <LoadingIndicator />}
{this.props.children}
</Dropzone>

View File

@@ -1,5 +1,8 @@
// @flow
import * as React from 'react';
import { Redirect } from 'react-router-dom';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
import RichMarkdownEditor from 'rich-markdown-editor';
import { uploadFile } from 'utils/uploadFile';
import isInternalUrl from 'utils/isInternalUrl';
@@ -11,11 +14,13 @@ type Props = {
readOnly?: boolean,
disableEmbeds?: boolean,
forwardedRef: *,
history: *,
ui: *,
};
@observer
class Editor extends React.Component<Props> {
@observable redirectTo: ?string;
onUploadImage = async (file: File) => {
const result = await uploadFile(file);
return result.url;
@@ -42,7 +47,7 @@ class Editor extends React.Component<Props> {
}
}
this.props.history.push(navigateTo);
this.redirectTo = navigateTo;
} else {
window.open(href, '_blank');
}
@@ -69,6 +74,8 @@ class Editor extends React.Component<Props> {
};
render() {
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
return (
<RichMarkdownEditor
ref={this.props.forwardedRef}

View File

@@ -1,8 +1,7 @@
// @flow
import * as React from 'react';
import { observable } from 'mobx';
import { observer, inject } from 'mobx-react';
import { withRouter } from 'react-router-dom';
import { observer } from 'mobx-react';
import styled from 'styled-components';
import Input, { LabelText, Outline } from 'components/Input';
@@ -11,13 +10,11 @@ type Props = {
minHeight?: number,
maxHeight?: number,
readOnly?: boolean,
history: *,
ui: *,
};
@observer
class InputRich extends React.Component<Props> {
@observable editorComponent;
@observable editorComponent: *;
componentDidMount() {
this.loadEditor();
@@ -63,4 +60,4 @@ const StyledOutline = styled(Outline)`
}
`;
export default inject('ui')(withRouter(InputRich));
export default InputRich;

View File

@@ -1,10 +1,10 @@
// @flow
import * as React from 'react';
import { Switch, Route, withRouter } from 'react-router-dom';
import type { Location } from 'react-router-dom';
import { Switch, Route, Redirect } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import styled from 'styled-components';
import breakpoint from 'styled-components-breakpoint';
import { observable } from 'mobx';
import { observer, inject } from 'mobx-react';
import keydown from 'react-keydown';
import Analytics from 'components/Analytics';
@@ -12,18 +12,16 @@ import Flex from 'shared/components/Flex';
import { documentEditUrl, homeUrl, searchUrl } from 'utils/routeHelpers';
import { LoadingIndicatorBar } from 'components/LoadingIndicator';
import { GlobalStyles } from 'components/DropToImport';
import Sidebar from 'components/Sidebar';
import SettingsSidebar from 'components/Sidebar/Settings';
import Modals from 'components/Modals';
import ErrorSuspended from 'scenes/ErrorSuspended';
import AuthStore from 'stores/AuthStore';
import UiStore from 'stores/UiStore';
import DocumentsStore from 'stores/DocumentsStore';
type Props = {
history: Object,
location: Location,
documents: DocumentsStore,
children?: ?React.Node,
actions?: ?React.Node,
@@ -36,17 +34,24 @@ type Props = {
@observer
class Layout extends React.Component<Props> {
scrollable: ?HTMLDivElement;
@observable redirectTo: ?string;
componentDidUpdate() {
if (this.redirectTo) {
this.redirectTo = undefined;
}
}
@keydown(['/', 't', 'meta+k'])
goToSearch(ev) {
ev.preventDefault();
ev.stopPropagation();
this.props.history.push(searchUrl());
this.redirectTo = searchUrl();
}
@keydown('d')
goToDashboard() {
this.props.history.push(homeUrl());
this.redirectTo = homeUrl();
}
@keydown('e')
@@ -56,7 +61,7 @@ class Layout extends React.Component<Props> {
ev.preventDefault();
ev.stopPropagation();
this.props.history.push(documentEditUrl(activeDocument));
this.redirectTo = documentEditUrl(activeDocument);
}
@keydown('shift+/')
@@ -70,6 +75,7 @@ class Layout extends React.Component<Props> {
const showSidebar = auth.authenticated && user && team;
if (auth.isSuspended) return <ErrorSuspended />;
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
return (
<Container column auto>
@@ -98,6 +104,7 @@ class Layout extends React.Component<Props> {
</Content>
</Flex>
<Modals ui={ui} />
<GlobalStyles />
</Container>
);
}
@@ -122,4 +129,4 @@ const Content = styled(Flex)`
`};
`;
export default withRouter(inject('auth', 'ui', 'documents')(Layout));
export default inject('auth', 'ui', 'documents')(Layout);

View File

@@ -1,23 +0,0 @@
// @flow
import * as React from 'react';
import { withRouter } from 'react-router-dom';
class ScrollToAnchor extends React.Component<*> {
componentDidUpdate(prevProps) {
if (this.props.location.hash === prevProps.location.hash) return;
if (window.location.hash === '') return;
// Delay on timeout to ensure that the DOM is updated first
setImmediate(() => {
const id = window.location.hash.replace('#', '');
const element = document.getElementById(id);
if (element) element.scrollIntoView();
});
}
render() {
return this.props.children;
}
}
export default withRouter(ScrollToAnchor);

View File

@@ -1,7 +1,5 @@
// @flow
import * as React from 'react';
import { withRouter } from 'react-router-dom';
import type { Location } from 'react-router-dom';
import { observer, inject } from 'mobx-react';
import { HomeIcon, EditIcon, SearchIcon, StarredIcon } from 'outline-icons';
@@ -20,8 +18,6 @@ import DocumentsStore from 'stores/DocumentsStore';
import UiStore from 'stores/UiStore';
type Props = {
history: Object,
location: Location,
auth: AuthStore,
documents: DocumentsStore,
ui: UiStore,
@@ -93,11 +89,7 @@ class MainSidebar extends React.Component<Props> {
/>
</Section>
<Section>
<Collections
history={this.props.history}
location={this.props.location}
onCreateCollection={this.handleCreateCollection}
/>
<Collections onCreateCollection={this.handleCreateCollection} />
</Section>
</Scrollable>
</Flex>
@@ -106,4 +98,4 @@ class MainSidebar extends React.Component<Props> {
}
}
export default withRouter(inject('documents', 'auth', 'ui')(MainSidebar));
export default inject('documents', 'auth', 'ui')(MainSidebar);

View File

@@ -12,7 +12,6 @@ import UiStore from 'stores/UiStore';
type Props = {
children: React.Node,
history: Object,
location: Location,
ui: UiStore,
};

View File

@@ -13,7 +13,6 @@ import DropToImport from 'components/DropToImport';
import Flex from 'shared/components/Flex';
type Props = {
history: Object,
collection: Collection,
ui: UiStore,
activeDocument: ?Document,
@@ -25,19 +24,12 @@ class CollectionLink extends React.Component<Props> {
@observable menuOpen = false;
render() {
const {
history,
collection,
activeDocument,
prefetchDocument,
ui,
} = this.props;
const { collection, activeDocument, prefetchDocument, ui } = this.props;
const expanded = collection.id === ui.activeCollectionId;
return (
<DropToImport
key={collection.id}
history={history}
collectionId={collection.id}
activeClassName="activeDropZone"
>
@@ -62,7 +54,6 @@ class CollectionLink extends React.Component<Props> {
exact={false}
menu={
<CollectionMenu
history={history}
collection={collection}
onOpen={() => (this.menuOpen = true)}
onClose={() => (this.menuOpen = false)}
@@ -73,7 +64,6 @@ class CollectionLink extends React.Component<Props> {
{collection.documents.map(document => (
<DocumentLink
key={document.id}
history={history}
document={document}
activeDocument={activeDocument}
prefetchDocument={prefetchDocument}

View File

@@ -1,6 +1,7 @@
// @flow
import * as React from 'react';
import { observer, inject } from 'mobx-react';
import { withRouter } from 'react-router-dom';
import type { Location } from 'react-router-dom';
import Flex from 'shared/components/Flex';
import { PlusIcon } from 'outline-icons';
@@ -62,4 +63,6 @@ class Collections extends React.Component<Props> {
}
}
export default inject('collections', 'ui', 'documents')(Collections);
export default inject('collections', 'ui', 'documents')(
withRouter(Collections)
);

View File

@@ -10,7 +10,6 @@ import { type NavigationNode } from 'types';
type Props = {
document: NavigationNode,
history: Object,
activeDocument: ?Document,
activeDocumentRef?: (?HTMLElement) => *,
prefetchDocument: (documentId: string) => Promise<void>,
@@ -34,7 +33,6 @@ class DocumentLink extends React.Component<Props> {
activeDocumentRef,
prefetchDocument,
depth,
history,
} = this.props;
const isActiveDocument =
@@ -55,11 +53,7 @@ class DocumentLink extends React.Component<Props> {
ref={isActiveDocument ? activeDocumentRef : undefined}
onMouseEnter={this.handleMouseEnter}
>
<DropToImport
history={history}
documentId={document.id}
activeClassName="activeDropZone"
>
<DropToImport documentId={document.id} activeClassName="activeDropZone">
<SidebarLink
to={{
pathname: document.url,
@@ -74,7 +68,6 @@ class DocumentLink extends React.Component<Props> {
{document.children.map(childDocument => (
<DocumentLink
key={childDocument.id}
history={history}
document={childDocument}
activeDocument={activeDocument}
prefetchDocument={prefetchDocument}

View File

@@ -9,6 +9,7 @@ import Team from '../models/Team';
type Props = {
team: Team,
disabled: boolean,
};
@observer
@@ -20,7 +21,8 @@ class TipInvite extends React.Component<Props> {
};
render() {
const { team } = this.props;
const { team, disabled } = this.props;
if (disabled) return null;
return (
<Tip id="subdomain-invite">

View File

@@ -12,7 +12,6 @@ import 'shared/styles/prism.css';
import ErrorBoundary from 'components/ErrorBoundary';
import ScrollToTop from 'components/ScrollToTop';
import ScrollToAnchor from 'components/ScrollToAnchor';
import Toasts from 'components/Toasts';
import Routes from './routes';
@@ -33,9 +32,7 @@ if (element) {
<Router>
<React.Fragment>
<ScrollToTop>
<ScrollToAnchor>
<Routes />
</ScrollToAnchor>
<Routes />
</ScrollToTop>
<Toasts />
</React.Fragment>

View File

@@ -1,6 +1,7 @@
// @flow
import * as React from 'react';
import { withRouter } from 'react-router-dom';
import { Redirect } from 'react-router-dom';
import { observable } from 'mobx';
import { inject, observer } from 'mobx-react';
import UiStore from 'stores/UiStore';
import AuthStore from 'stores/AuthStore';
@@ -15,19 +16,24 @@ import {
type Props = {
label: React.Node,
history: Object,
ui: UiStore,
auth: AuthStore,
};
@observer
class AccountMenu extends React.Component<Props> {
@observable redirectTo: ?string;
componentDidUpdate() {
this.redirectTo = undefined;
}
handleOpenKeyboardShortcuts = () => {
this.props.ui.setActiveModal('keyboard-shortcuts');
};
handleOpenSettings = () => {
this.props.history.push('/settings');
this.redirectTo = '/settings';
};
handleLogout = () => {
@@ -35,6 +41,8 @@ class AccountMenu extends React.Component<Props> {
};
render() {
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
return (
<DropdownMenu
style={{ marginRight: 10, marginTop: -10 }}
@@ -69,4 +77,4 @@ class AccountMenu extends React.Component<Props> {
}
}
export default withRouter(inject('ui', 'auth')(AccountMenu));
export default inject('ui', 'auth')(AccountMenu);

View File

@@ -2,6 +2,7 @@
import * as React from 'react';
import { observable } from 'mobx';
import { inject, observer } from 'mobx-react';
import { Redirect } from 'react-router-dom';
import styled from 'styled-components';
import { MoreIcon } from 'outline-icons';
import Modal from 'components/Modal';
@@ -18,7 +19,6 @@ type Props = {
label?: React.Node,
onOpen?: () => *,
onClose?: () => *,
history: Object,
ui: UiStore,
documents: DocumentsStore,
collection: Collection,
@@ -28,11 +28,16 @@ type Props = {
class CollectionMenu extends React.Component<Props> {
file: ?HTMLInputElement;
@observable permissionsModalOpen: boolean = false;
@observable redirectTo: ?string;
componentDidUpdate() {
this.redirectTo = undefined;
}
onNewDocument = (ev: SyntheticEvent<*>) => {
ev.preventDefault();
const { collection, history } = this.props;
history.push(`${collection.url}/new`);
const { collection } = this.props;
this.redirectTo = `${collection.url}/new`;
};
onImportDocument = (ev: SyntheticEvent<*>) => {
@@ -51,7 +56,7 @@ class CollectionMenu extends React.Component<Props> {
documents: this.props.documents,
collectionId: this.props.collection.id,
});
this.props.history.push(document.url);
this.redirectTo = document.url;
} catch (err) {
this.props.ui.showToast(err.message);
}
@@ -85,6 +90,8 @@ class CollectionMenu extends React.Component<Props> {
};
render() {
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
const { collection, label, onOpen, onClose } = this.props;
return (

View File

@@ -1,6 +1,7 @@
// @flow
import * as React from 'react';
import { withRouter } from 'react-router-dom';
import { Redirect } from 'react-router-dom';
import { observable } from 'mobx';
import { inject, observer } from 'mobx-react';
import { MoreIcon } from 'outline-icons';
@@ -14,7 +15,6 @@ type Props = {
ui: UiStore,
auth: AuthStore,
label?: React.Node,
history: Object,
document: Document,
className: string,
showPrint?: boolean,
@@ -23,11 +23,17 @@ type Props = {
@observer
class DocumentMenu extends React.Component<Props> {
@observable redirectTo: ?string;
componentDidUpdate() {
this.redirectTo = undefined;
}
handleNewChild = (ev: SyntheticEvent<*>) => {
const { history, document } = this.props;
history.push(
`${document.collection.url}/new?parentDocument=${document.id}`
);
const { document } = this.props;
this.redirectTo = `${document.collection.url}/new?parentDocument=${
document.id
}`;
};
handleDelete = (ev: SyntheticEvent<*>) => {
@@ -36,16 +42,16 @@ class DocumentMenu extends React.Component<Props> {
};
handleDocumentHistory = () => {
this.props.history.push(documentHistoryUrl(this.props.document));
this.redirectTo = documentHistoryUrl(this.props.document);
};
handleMove = (ev: SyntheticEvent<*>) => {
this.props.history.push(documentMoveUrl(this.props.document));
this.redirectTo = documentMoveUrl(this.props.document);
};
handleDuplicate = async (ev: SyntheticEvent<*>) => {
const duped = await this.props.document.duplicate();
this.props.history.push(duped.url);
this.redirectTo = duped.url;
};
handlePin = (ev: SyntheticEvent<*>) => {
@@ -76,6 +82,8 @@ class DocumentMenu extends React.Component<Props> {
};
render() {
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
const { document, label, className, showPrint, auth } = this.props;
const canShareDocuments = auth.team && auth.team.sharing;
@@ -136,4 +144,4 @@ class DocumentMenu extends React.Component<Props> {
}
}
export default withRouter(inject('ui', 'auth')(DocumentMenu));
export default inject('ui', 'auth')(DocumentMenu);

View File

@@ -1,6 +1,8 @@
// @flow
import * as React from 'react';
import { withRouter } from 'react-router-dom';
import { Redirect } from 'react-router-dom';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
import { MoreIcon } from 'outline-icons';
import { newDocumentUrl } from 'utils/routeHelpers';
@@ -9,25 +11,32 @@ import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
type Props = {
label?: React.Node,
history: Object,
document: Document,
};
@observer
class NewChildDocumentMenu extends React.Component<Props> {
@observable redirectTo: ?string;
componentDidUpdate() {
this.redirectTo = undefined;
}
handleNewDocument = () => {
const { history, document } = this.props;
history.push(newDocumentUrl(document.collection));
this.redirectTo = newDocumentUrl(this.props.document.collection);
};
handleNewChild = () => {
const { history, document } = this.props;
history.push(
`${document.collection.url}/new?parentDocument=${document.id}`
);
const { document } = this.props;
this.redirectTo = `${document.collection.url}/new?parentDocument=${
document.id
}`;
};
render() {
const { label, document, history, ...rest } = this.props;
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
const { label, document, ...rest } = this.props;
const { collection } = document;
return (
@@ -45,4 +54,4 @@ class NewChildDocumentMenu extends React.Component<Props> {
}
}
export default withRouter(NewChildDocumentMenu);
export default NewChildDocumentMenu;

View File

@@ -1,7 +1,8 @@
// @flow
import * as React from 'react';
import { withRouter } from 'react-router-dom';
import { inject } from 'mobx-react';
import { observable } from 'mobx';
import { inject, observer } from 'mobx-react';
import { Redirect } from 'react-router-dom';
import { MoreIcon, CollectionIcon, PrivateCollectionIcon } from 'outline-icons';
import { newDocumentUrl } from 'utils/routeHelpers';
@@ -10,13 +11,19 @@ import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
type Props = {
label?: React.Node,
history: Object,
collections: CollectionsStore,
};
@observer
class NewDocumentMenu extends React.Component<Props> {
@observable redirectTo: ?string;
componentDidUpdate() {
this.redirectTo = undefined;
}
handleNewDocument = collection => {
this.props.history.push(newDocumentUrl(collection));
this.redirectTo = newDocumentUrl(collection);
};
onOpen = () => {
@@ -28,7 +35,9 @@ class NewDocumentMenu extends React.Component<Props> {
};
render() {
const { collections, label, history, ...rest } = this.props;
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
const { collections, label, ...rest } = this.props;
return (
<DropdownMenu
@@ -55,4 +64,4 @@ class NewDocumentMenu extends React.Component<Props> {
}
}
export default withRouter(inject('collections')(NewDocumentMenu));
export default inject('collections')(NewDocumentMenu);

View File

@@ -1,12 +1,12 @@
// @flow
import * as React from 'react';
import { withRouter } from 'react-router-dom';
import { inject } from 'mobx-react';
import { Redirect } from 'react-router-dom';
import { inject, observer } from 'mobx-react';
import { observable } from 'mobx';
import { MoreIcon } from 'outline-icons';
import CopyToClipboard from 'components/CopyToClipboard';
import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
import SharesStore from 'stores/SharesStore';
import UiStore from 'stores/UiStore';
import Share from 'models/Share';
@@ -15,16 +15,22 @@ type Props = {
label?: React.Node,
onOpen?: () => *,
onClose: () => *,
history: Object,
shares: SharesStore,
ui: UiStore,
share: Share,
};
@observer
class ShareMenu extends React.Component<Props> {
@observable redirectTo: ?string;
componentDidUpdate() {
this.redirectTo = undefined;
}
handleGoToDocument = (ev: SyntheticEvent<*>) => {
ev.preventDefault();
this.props.history.push(this.props.share.documentUrl);
this.redirectTo = this.props.share.documentUrl;
};
handleRevoke = (ev: SyntheticEvent<*>) => {
@@ -38,6 +44,8 @@ class ShareMenu extends React.Component<Props> {
};
render() {
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
const { share, label, onOpen, onClose } = this.props;
return (
@@ -61,4 +69,4 @@ class ShareMenu extends React.Component<Props> {
}
}
export default withRouter(inject('shares', 'ui')(ShareMenu));
export default inject('shares', 'ui')(ShareMenu);

View File

@@ -2,7 +2,7 @@
import * as React from 'react';
import { observable } from 'mobx';
import { observer, inject } from 'mobx-react';
import { withRouter, Link, Switch, Route } from 'react-router-dom';
import { Redirect, Link, Switch, Route } from 'react-router-dom';
import styled from 'styled-components';
import {
@@ -42,7 +42,6 @@ type Props = {
ui: UiStore,
documents: DocumentsStore,
collections: CollectionsStore,
history: Object,
match: Object,
};
@@ -51,6 +50,7 @@ class CollectionScene extends React.Component<Props> {
@observable collection: ?Collection;
@observable isFetching: boolean = true;
@observable permissionsModalOpen: boolean = false;
@observable redirectTo: ?string;
componentDidMount() {
this.loadContent(this.props.match.params.id);
@@ -85,7 +85,7 @@ class CollectionScene extends React.Component<Props> {
ev.preventDefault();
if (this.collection) {
this.props.history.push(`${this.collection.url}/new`);
this.redirectTo = `${this.collection.url}/new`;
}
};
@@ -102,10 +102,7 @@ class CollectionScene extends React.Component<Props> {
return (
<Actions align="center" justify="flex-end">
<Action>
<CollectionMenu
history={this.props.history}
collection={this.collection}
/>
<CollectionMenu collection={this.collection} />
</Action>
<Separator />
<Action>
@@ -117,16 +114,11 @@ class CollectionScene extends React.Component<Props> {
);
}
renderNotFound() {
return <Search notFound />;
}
render() {
const { documents } = this.props;
if (!this.isFetching && !this.collection) {
return this.renderNotFound();
}
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
if (!this.isFetching && !this.collection) return <Search notFound />;
const pinnedDocuments = this.collection
? documents.pinnedInCollection(this.collection.id)
@@ -296,6 +288,4 @@ const Wrapper = styled(Flex)`
margin: 10px 0;
`;
export default withRouter(
inject('collections', 'documents', 'ui')(CollectionScene)
);
export default inject('collections', 'documents', 'ui')(CollectionScene);

View File

@@ -41,6 +41,7 @@ import Revision from 'models/Revision';
import schema from './schema';
let EditorImport;
const AUTOSAVE_DELAY = 3000;
const IS_DIRTY_DELAY = 500;
const MARK_AS_VIEWED_AFTER = 3000;
@@ -69,7 +70,7 @@ class DocumentScene extends React.Component<Props> {
viewTimeout: TimeoutID;
getEditorText: () => string;
@observable editorComponent;
@observable editorComponent = EditorImport;
@observable document: ?Document;
@observable revision: ?Revision;
@observable newDocument: ?Document;
@@ -167,10 +168,13 @@ class DocumentScene extends React.Component<Props> {
}
if (!this.revision) {
// Update url to match the current one
this.props.history.replace(
updateDocumentUrl(props.match.url, document.url)
const canonicalUrl = updateDocumentUrl(
props.match.url,
document.url
);
if (this.props.location.pathname !== canonicalUrl) {
this.props.history.replace(canonicalUrl);
}
}
}
} else {
@@ -181,8 +185,11 @@ class DocumentScene extends React.Component<Props> {
};
loadEditor = async () => {
const EditorImport = await import('./components/Editor');
this.editorComponent = EditorImport.default;
if (this.editorComponent) return;
const Imported = await import('./components/Editor');
EditorImport = Imported.default;
this.editorComponent = EditorImport;
};
get isEditing() {
@@ -357,7 +364,6 @@ class DocumentScene extends React.Component<Props> {
isSaving={this.isSaving}
isPublishing={this.isPublishing}
savingIsDisabled={!document.allowSave}
history={this.props.history}
onDiscard={this.onDiscard}
onSave={this.onSave}
/>
@@ -376,7 +382,6 @@ class DocumentScene extends React.Component<Props> {
onCancel={this.onDiscard}
readOnly={!this.isEditing}
toc={!revision}
history={this.props.history}
ui={this.props.ui}
schema={schema}
/>

View File

@@ -3,6 +3,7 @@ import * as React from 'react';
import { throttle } from 'lodash';
import { observable } from 'mobx';
import { observer, inject } from 'mobx-react';
import { Redirect } from 'react-router-dom';
import styled from 'styled-components';
import breakpoint from 'styled-components-breakpoint';
import { NewDocumentIcon } from 'outline-icons';
@@ -33,7 +34,6 @@ type Props = {
publish?: boolean,
autosave?: boolean,
}) => *,
history: Object,
auth: AuthStore,
};
@@ -41,6 +41,7 @@ type Props = {
class Header extends React.Component<Props> {
@observable isScrolled = false;
@observable showShareModal = false;
@observable redirectTo: ?string;
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
@@ -57,7 +58,7 @@ class Header extends React.Component<Props> {
handleScroll = throttle(this.updateIsScrolled, 50);
handleEdit = () => {
this.props.history.push(documentEditUrl(this.props.document));
this.redirectTo = documentEditUrl(this.props.document);
};
handleSave = () => {
@@ -86,6 +87,8 @@ class Header extends React.Component<Props> {
};
render() {
if (this.redirectTo) return <Redirect to={this.redirectTo} />;
const {
document,
isEditing,

View File

@@ -157,7 +157,7 @@
"react-waypoint": "^7.3.1",
"redis": "^2.6.2",
"redis-lock": "^0.1.0",
"rich-markdown-editor": "^8.0.0",
"rich-markdown-editor": "^8.0.2",
"safestart": "1.1.0",
"sequelize": "4.28.6",
"sequelize-cli": "^2.7.0",
@@ -166,7 +166,7 @@
"string-hash": "^1.1.0",
"string-replace-to-array": "^1.0.3",
"style-loader": "^0.18.2",
"styled-components": "4.0.3",
"styled-components": "^4.1.3",
"styled-components-breakpoint": "^1.0.1",
"styled-components-grid": "^2.2.0",
"styled-normalize": "^2.2.1",

View File

@@ -39,6 +39,12 @@
dependencies:
"@babel/types" "7.0.0-beta.31"
"@babel/helper-module-imports@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
dependencies:
"@babel/types" "^7.0.0"
"@babel/template@7.0.0-beta.31":
version "7.0.0-beta.31"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.31.tgz#577bb29389f6c497c3e7d014617e7d6713f68bda"
@@ -77,15 +83,19 @@
lodash "^4.17.10"
to-fast-properties "^2.0.0"
"@emotion/is-prop-valid@^0.6.8":
version "0.6.8"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.6.8.tgz#68ad02831da41213a2089d2cab4e8ac8b30cbd85"
"@emotion/is-prop-valid@^0.7.3":
version "0.7.3"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz#a6bf4fa5387cbba59d44e698a4680f481a8da6cc"
dependencies:
"@emotion/memoize" "^0.6.6"
"@emotion/memoize" "0.7.1"
"@emotion/memoize@^0.6.6":
version "0.6.6"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.6.6.tgz#004b98298d04c7ca3b4f50ca2035d4f60d2eed1b"
"@emotion/memoize@0.7.1":
version "0.7.1"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.1.tgz#e93c13942592cf5ef01aa8297444dc192beee52f"
"@emotion/unitless@^0.7.0":
version "0.7.3"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.3.tgz#6310a047f12d21a1036fb031317219892440416f"
"@tommoor/remove-markdown@0.3.1":
version "0.3.1"
@@ -8803,9 +8813,9 @@ retry-axios@0.3.2, retry-axios@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/retry-axios/-/retry-axios-0.3.2.tgz#5757c80f585b4cc4c4986aa2ffd47a60c6d35e13"
rich-markdown-editor@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/rich-markdown-editor/-/rich-markdown-editor-8.0.0.tgz#d11a7b81e819bcef1680b60359b8761baeadbb01"
rich-markdown-editor@^8.0.2:
version "8.0.2"
resolved "https://registry.yarnpkg.com/rich-markdown-editor/-/rich-markdown-editor-8.0.2.tgz#b642d8c85794eca1df4e6026b2c07f66eb7445ad"
dependencies:
"@wikifactory/slate-edit-blockquote" "^0.7.1"
"@wikifactory/slate-edit-code" "^0.16.0"
@@ -8836,7 +8846,7 @@ rich-markdown-editor@^8.0.0:
slate-react "^0.21.15"
slate-schema-violations "^0.1.39"
slugify "^1.3.0"
styled-components "4.0.3"
styled-components "^4.1.3"
right-align@^0.1.1:
version "0.1.3"
@@ -9637,11 +9647,13 @@ styled-components-grid@^2.2.0:
react-create-component-from-tag-prop "^1.4.0"
styled-components-breakpoint "^2.0.2"
styled-components@4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.0.3.tgz#6c1a95a93857aa613fdfc26ad40899217100d8c3"
styled-components@^4.1.3:
version "4.1.3"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.1.3.tgz#4472447208e618b57e84deaaeb6acd34a5e0fe9b"
dependencies:
"@emotion/is-prop-valid" "^0.6.8"
"@babel/helper-module-imports" "^7.0.0"
"@emotion/is-prop-valid" "^0.7.3"
"@emotion/unitless" "^0.7.0"
babel-plugin-styled-components ">= 1"
css-to-react-native "^2.2.2"
memoize-one "^4.0.0"