From 5cb04d7ac1e8e32dc2e308c6a7700fae2dd42dbc Mon Sep 17 00:00:00 2001
From: Tom Moor
Date: Thu, 9 Jul 2020 22:33:07 -0700
Subject: [PATCH] New login screen (#1331)
* wip
* feat: first draft of auth.config
* chore: auth methodS
* chore: styling
* styling, styling, styling
* feat: Auth notices
* chore: Remove server-rendered pages, move shared/components -> components
* lint
* cleanup
* cleanup
* fix: Remove unused component
* fix: Ensure env variables in prod too
* style tweaks
* fix: Entering SSO email into login form fails
fix: Tweak language around guest signin
---
README.md | 1 -
app/components/Actions.js | 2 +-
app/components/Alert.js | 36 -
app/components/Authenticated.js | 3 +-
{shared => app}/components/Branding.js | 0
{shared => app}/components/Breadcrumb.js | 2 +-
{shared => app}/components/BreadcrumbMenu.js | 0
app/components/Button.js | 4 +-
app/components/ButtonLarge.js | 13 +
.../DocumentHistory/DocumentHistory.js | 2 +-
.../DocumentHistory/components/Revision.js | 4 +-
.../DocumentPreview/DocumentPreview.js | 2 +-
app/components/DropdownMenu/DropdownMenu.js | 2 +-
app/components/Facepile.js | 2 +-
{shared => app}/components/Flex.js | 0
{shared => app}/components/GithubLogo.js | 0
{shared => app}/components/GoogleLogo.js | 0
app/components/GroupListItem.js | 2 +-
app/components/IconPicker.js | 2 +-
app/components/Input.js | 2 +-
app/components/InputLarge.js | 13 +
app/components/Labeled.js | 2 +-
app/components/Layout.js | 2 +-
app/components/List/Item.js | 2 +-
app/components/List/Placeholder.js | 2 +-
.../LoadingPlaceholder/ListPlaceholder.js | 2 +-
.../LoadingPlaceholder/LoadingPlaceholder.js | 2 +-
app/components/Mask.js | 2 +-
app/components/Modal.js | 2 +-
app/components/Notice.js | 12 +
app/components/NoticeAlert.js | 24 +
{shared => app}/components/OutlineLogo.js | 0
app/components/PathToDocument.js | 2 +-
app/components/PublishingInfo.js | 6 +-
app/components/Sidebar/Main.js | 2 +-
app/components/Sidebar/Settings.js | 4 +-
app/components/Sidebar/Sidebar.js | 2 +-
.../Sidebar/components/CollectionLink.js | 2 +-
.../Sidebar/components/Collections.js | 2 +-
.../Sidebar/components/DocumentLink.js | 2 +-
app/components/Sidebar/components/Header.js | 2 +-
.../Sidebar/components/HeaderBlock.js | 4 +-
app/components/Sidebar/components/Section.js | 2 +-
.../Sidebar/components/SidebarLink.js | 2 +-
{shared => app}/components/SlackLogo.js | 0
{shared => app}/components/TeamLogo.js | 4 +-
{shared => app}/components/Time.js | 0
app/menus/AccountMenu.js | 2 +-
app/routes.js | 5 +-
app/scenes/Collection.js | 2 +-
app/scenes/CollectionDelete.js | 2 +-
app/scenes/CollectionEdit.js | 2 +-
app/scenes/CollectionExport.js | 2 +-
.../AddGroupsToCollection.js | 2 +-
.../AddPeopleToCollection.js | 2 +-
.../CollectionMembers/CollectionMembers.js | 2 +-
.../components/MemberListItem.js | 4 +-
.../components/UserListItem.js | 2 +-
app/scenes/CollectionNew.js | 2 +-
app/scenes/Document/components/Container.js | 2 +-
app/scenes/Document/components/Document.js | 8 +-
.../Document/components/DocumentMove.js | 2 +-
app/scenes/Document/components/Editor.js | 2 +-
app/scenes/Document/components/Header.js | 4 +-
app/scenes/DocumentDelete.js | 2 +-
app/scenes/DocumentNew.js | 2 +-
app/scenes/GroupDelete.js | 2 +-
app/scenes/GroupEdit.js | 2 +-
app/scenes/GroupMembers/AddPeopleToGroup.js | 2 +-
app/scenes/GroupMembers/GroupMembers.js | 2 +-
.../components/GroupMemberListItem.js | 4 +-
.../GroupMembers/components/UserListItem.js | 2 +-
app/scenes/GroupNew.js | 2 +-
app/scenes/Home.js | 17 -
app/scenes/Invite.js | 80 +-
app/scenes/KeyboardShortcuts.js | 2 +-
.../scenes/Login/Notices.js | 42 +-
app/scenes/Login/Service.js | 147 +++
app/scenes/Login/index.js | 230 +++++
app/scenes/Search/Search.js | 2 +-
app/scenes/Search/components/FilterOption.js | 2 +-
app/scenes/Search/components/SearchField.js | 2 +-
app/scenes/Settings/Details.js | 2 +-
app/scenes/Settings/Notifications.js | 2 +-
app/scenes/Settings/Profile.js | 2 +-
app/scenes/Settings/Security.js | 12 +-
app/scenes/Settings/Slack.js | 2 +-
.../Settings/components/EventListItem.js | 2 +-
app/scenes/Settings/components/ImageUpload.js | 2 +-
.../Settings/components/ShareListItem.js | 2 +-
app/scenes/Settings/components/SlackButton.js | 2 +-
.../Settings/components/UserListItem.js | 2 +-
app/scenes/UserDelete.js | 2 +-
app/scenes/UserProfile.js | 2 +-
app/stores/AuthStore.js | 38 +-
app/utils/ApiClient.js | 9 +-
.../npm/styled-components-grid_vx.x.x.js | 144 ---
index.js | 34 +-
init.js | 6 +-
package.json | 1 -
public/screenshot.png | Bin 204962 -> 0 bytes
public/screenshot@2x.png | Bin 227039 -> 0 bytes
server/api/auth.js | 94 ++
server/auth/email.js | 15 +-
server/commands/userInviter.js | 3 +-
server/emails/InviteEmail.js | 9 +-
server/pages/Home.js | 50 -
server/pages/SubdomainSignin.js | 131 ---
server/pages/components/Analytics.js | 23 -
server/pages/components/Button.js | 16 -
server/pages/components/Centered.js | 9 -
server/pages/components/Content.js | 13 -
server/pages/components/Header.js | 63 --
server/pages/components/Hero.js | 22 -
server/pages/components/HeroText.js | 13 -
server/pages/components/Layout.js | 81 --
server/pages/components/PageTitle.js | 13 -
server/pages/components/SigninButtons.js | 94 --
server/pages/developers/Api.js | 970 ------------------
server/pages/developers/index.js | 167 ---
server/routes.js | 92 +-
server/routes.test.js | 27 -
server/utils/renderpage.js | 47 -
shared/components/Notice.js | 13 -
shared/utils/domains.js | 11 +-
webpack.config.js | 3 +-
webpack.config.prod.js | 2 +
yarn.lock | 15 +-
128 files changed, 769 insertions(+), 2264 deletions(-)
delete mode 100644 app/components/Alert.js
rename {shared => app}/components/Branding.js (100%)
rename {shared => app}/components/Breadcrumb.js (98%)
rename {shared => app}/components/BreadcrumbMenu.js (100%)
create mode 100644 app/components/ButtonLarge.js
rename {shared => app}/components/Flex.js (100%)
rename {shared => app}/components/GithubLogo.js (100%)
rename {shared => app}/components/GoogleLogo.js (100%)
create mode 100644 app/components/InputLarge.js
create mode 100644 app/components/Notice.js
create mode 100644 app/components/NoticeAlert.js
rename {shared => app}/components/OutlineLogo.js (100%)
rename {shared => app}/components/SlackLogo.js (100%)
rename {shared => app}/components/TeamLogo.js (75%)
rename {shared => app}/components/Time.js (100%)
delete mode 100644 app/scenes/Home.js
rename server/pages/components/AuthNotices.js => app/scenes/Login/Notices.js (66%)
create mode 100644 app/scenes/Login/Service.js
create mode 100644 app/scenes/Login/index.js
delete mode 100644 flow-typed/npm/styled-components-grid_vx.x.x.js
delete mode 100644 public/screenshot.png
delete mode 100644 public/screenshot@2x.png
delete mode 100644 server/pages/Home.js
delete mode 100644 server/pages/SubdomainSignin.js
delete mode 100644 server/pages/components/Analytics.js
delete mode 100644 server/pages/components/Button.js
delete mode 100644 server/pages/components/Centered.js
delete mode 100644 server/pages/components/Content.js
delete mode 100644 server/pages/components/Header.js
delete mode 100644 server/pages/components/Hero.js
delete mode 100644 server/pages/components/HeroText.js
delete mode 100644 server/pages/components/Layout.js
delete mode 100644 server/pages/components/PageTitle.js
delete mode 100644 server/pages/components/SigninButtons.js
delete mode 100644 server/pages/developers/Api.js
delete mode 100644 server/pages/developers/index.js
delete mode 100644 server/routes.test.js
delete mode 100644 server/utils/renderpage.js
delete mode 100644 shared/components/Notice.js
diff --git a/README.md b/README.md
index 2f5c80e8..2e65a06c 100644
--- a/README.md
+++ b/README.md
@@ -126,7 +126,6 @@ Backend is driven by [Koa](http://koajs.com/) (API, web server), [Sequelize](htt
- `server/commands` - Domain logic, currently being refactored from /models
- `server/emails` - React rendered email templates
- `server/models` - Database models
-- `server/pages` - Server-side rendered public pages
- `server/policies` - Authorization logic
- `server/presenters` - API responses for database models
- `server/test` - Test helps and support
diff --git a/app/components/Actions.js b/app/components/Actions.js
index 920f3899..2905cd03 100644
--- a/app/components/Actions.js
+++ b/app/components/Actions.js
@@ -1,7 +1,7 @@
// @flow
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
export const Action = styled(Flex)`
justify-content: center;
diff --git a/app/components/Alert.js b/app/components/Alert.js
deleted file mode 100644
index 629a3c22..00000000
--- a/app/components/Alert.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// @flow
-import * as React from "react";
-import { observer } from "mobx-react";
-import Flex from "shared/components/Flex";
-import styled from "styled-components";
-
-type Props = {
- children: React.Node,
- type?: "info" | "success" | "warning" | "danger" | "offline",
-};
-
-@observer
-class Alert extends React.Component {
- defaultProps = {
- type: "info",
- };
-
- render() {
- return (
-
- {this.props.children}
-
- );
- }
-}
-
-const Container = styled(Flex)`
- height: $headerHeight;
- color: ${props => props.theme.white};
- font-size: 14px;
- line-height: 1;
-
- background-color: ${({ theme, type }) => theme.color[type]};
-`;
-
-export default Alert;
diff --git a/app/components/Authenticated.js b/app/components/Authenticated.js
index a81a8200..a4fc3fd4 100644
--- a/app/components/Authenticated.js
+++ b/app/components/Authenticated.js
@@ -1,6 +1,7 @@
// @flow
import * as React from "react";
import { observer, inject } from "mobx-react";
+import { Redirect } from "react-router-dom";
import AuthStore from "stores/AuthStore";
import LoadingIndicator from "components/LoadingIndicator";
import { isCustomSubdomain } from "shared/utils/domains";
@@ -35,7 +36,7 @@ const Authenticated = observer(({ auth, children }: Props) => {
}
auth.logout(true);
- return null;
+ return ;
});
export default inject("auth")(Authenticated);
diff --git a/shared/components/Branding.js b/app/components/Branding.js
similarity index 100%
rename from shared/components/Branding.js
rename to app/components/Branding.js
diff --git a/shared/components/Breadcrumb.js b/app/components/Breadcrumb.js
similarity index 98%
rename from shared/components/Breadcrumb.js
rename to app/components/Breadcrumb.js
index baae01d7..d89ac620 100644
--- a/shared/components/Breadcrumb.js
+++ b/app/components/Breadcrumb.js
@@ -9,7 +9,7 @@ import { PadlockIcon, GoToIcon, MoreIcon } from "outline-icons";
import Document from "models/Document";
import CollectionsStore from "stores/CollectionsStore";
import { collectionUrl } from "utils/routeHelpers";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import BreadcrumbMenu from "./BreadcrumbMenu";
import CollectionIcon from "components/CollectionIcon";
diff --git a/shared/components/BreadcrumbMenu.js b/app/components/BreadcrumbMenu.js
similarity index 100%
rename from shared/components/BreadcrumbMenu.js
rename to app/components/BreadcrumbMenu.js
diff --git a/app/components/Button.js b/app/components/Button.js
index 45a7e128..43c1b995 100644
--- a/app/components/Button.js
+++ b/app/components/Button.js
@@ -5,7 +5,8 @@ import { darken, lighten } from "polished";
import { ExpandedIcon } from "outline-icons";
const RealButton = styled.button`
- display: inline-block;
+ display: ${props => (props.fullwidth ? "block" : "inline-block")};
+ width: ${props => (props.fullwidth ? "100%" : "auto")};
margin: 0;
padding: 0;
border: 0;
@@ -126,6 +127,7 @@ export type Props = {
children?: React.Node,
innerRef?: React.ElementRef,
disclosure?: boolean,
+ fullwidth?: boolean,
borderOnHover?: boolean,
};
diff --git a/app/components/ButtonLarge.js b/app/components/ButtonLarge.js
new file mode 100644
index 00000000..f3611bbd
--- /dev/null
+++ b/app/components/ButtonLarge.js
@@ -0,0 +1,13 @@
+// @flow
+import styled from "styled-components";
+import Button, { Inner } from "./Button";
+
+const ButtonLarge = styled(Button)`
+ height: 40px;
+
+ ${Inner} {
+ padding: 4px 16px;
+ }
+`;
+
+export default ButtonLarge;
diff --git a/app/components/DocumentHistory/DocumentHistory.js b/app/components/DocumentHistory/DocumentHistory.js
index 47f2cfc7..bb4af4d4 100644
--- a/app/components/DocumentHistory/DocumentHistory.js
+++ b/app/components/DocumentHistory/DocumentHistory.js
@@ -11,7 +11,7 @@ import { DEFAULT_PAGINATION_LIMIT } from "stores/BaseStore";
import DocumentsStore from "stores/DocumentsStore";
import RevisionsStore from "stores/RevisionsStore";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import { ListPlaceholder } from "components/LoadingPlaceholder";
import Revision from "./components/Revision";
import { documentHistoryUrl } from "utils/routeHelpers";
diff --git a/app/components/DocumentHistory/components/Revision.js b/app/components/DocumentHistory/components/Revision.js
index 30ae6c5a..da5778c4 100644
--- a/app/components/DocumentHistory/components/Revision.js
+++ b/app/components/DocumentHistory/components/Revision.js
@@ -5,8 +5,8 @@ import styled, { withTheme } from "styled-components";
import format from "date-fns/format";
import { MoreIcon } from "outline-icons";
-import Flex from "shared/components/Flex";
-import Time from "shared/components/Time";
+import Flex from "components/Flex";
+import Time from "components/Time";
import Avatar from "components/Avatar";
import RevisionMenu from "menus/RevisionMenu";
import Document from "models/Document";
diff --git a/app/components/DocumentPreview/DocumentPreview.js b/app/components/DocumentPreview/DocumentPreview.js
index 48321d48..917c3b42 100644
--- a/app/components/DocumentPreview/DocumentPreview.js
+++ b/app/components/DocumentPreview/DocumentPreview.js
@@ -4,7 +4,7 @@ import { observer } from "mobx-react";
import { Link } from "react-router-dom";
import { StarredIcon } from "outline-icons";
import styled, { withTheme } from "styled-components";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Badge from "components/Badge";
import Tooltip from "components/Tooltip";
import Highlight from "components/Highlight";
diff --git a/app/components/DropdownMenu/DropdownMenu.js b/app/components/DropdownMenu/DropdownMenu.js
index 7a60cab3..a8addbf9 100644
--- a/app/components/DropdownMenu/DropdownMenu.js
+++ b/app/components/DropdownMenu/DropdownMenu.js
@@ -7,7 +7,7 @@ import { PortalWithState } from "react-portal";
import { MoreIcon } from "outline-icons";
import { rgba } from "polished";
import styled from "styled-components";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import { fadeAndScaleIn } from "shared/styles/animations";
import NudeButton from "components/NudeButton";
diff --git a/app/components/Facepile.js b/app/components/Facepile.js
index 9bd9970f..d2f1d6e2 100644
--- a/app/components/Facepile.js
+++ b/app/components/Facepile.js
@@ -2,7 +2,7 @@
import * as React from "react";
import { observer, inject } from "mobx-react";
import styled, { withTheme } from "styled-components";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Avatar from "components/Avatar";
import User from "models/User";
diff --git a/shared/components/Flex.js b/app/components/Flex.js
similarity index 100%
rename from shared/components/Flex.js
rename to app/components/Flex.js
diff --git a/shared/components/GithubLogo.js b/app/components/GithubLogo.js
similarity index 100%
rename from shared/components/GithubLogo.js
rename to app/components/GithubLogo.js
diff --git a/shared/components/GoogleLogo.js b/app/components/GoogleLogo.js
similarity index 100%
rename from shared/components/GoogleLogo.js
rename to app/components/GoogleLogo.js
diff --git a/app/components/GroupListItem.js b/app/components/GroupListItem.js
index be616c47..d1255d11 100644
--- a/app/components/GroupListItem.js
+++ b/app/components/GroupListItem.js
@@ -5,7 +5,7 @@ import { observable } from "mobx";
import { observer, inject } from "mobx-react";
import { MAX_AVATAR_DISPLAY } from "shared/constants";
import Modal from "components/Modal";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Facepile from "components/Facepile";
import GroupMembers from "scenes/GroupMembers";
import ListItem from "components/List/Item";
diff --git a/app/components/IconPicker.js b/app/components/IconPicker.js
index ccb367fa..c01e4c31 100644
--- a/app/components/IconPicker.js
+++ b/app/components/IconPicker.js
@@ -27,7 +27,7 @@ import styled from "styled-components";
import { LabelText } from "components/Input";
import { DropdownMenu } from "components/DropdownMenu";
import NudeButton from "components/NudeButton";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
export const icons = {
collection: {
diff --git a/app/components/Input.js b/app/components/Input.js
index ad59d6ab..18ea9be9 100644
--- a/app/components/Input.js
+++ b/app/components/Input.js
@@ -4,7 +4,7 @@ import { observer } from "mobx-react";
import { observable } from "mobx";
import styled from "styled-components";
import VisuallyHidden from "components/VisuallyHidden";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
const RealTextarea = styled.textarea`
border: 0;
diff --git a/app/components/InputLarge.js b/app/components/InputLarge.js
new file mode 100644
index 00000000..9df392c0
--- /dev/null
+++ b/app/components/InputLarge.js
@@ -0,0 +1,13 @@
+// @flow
+import styled from "styled-components";
+import Input from "./Input";
+
+const InputLarge = styled(Input)`
+ height: 40px;
+
+ input {
+ height: 40px;
+ }
+`;
+
+export default InputLarge;
diff --git a/app/components/Labeled.js b/app/components/Labeled.js
index 4fda039b..2737e34a 100644
--- a/app/components/Labeled.js
+++ b/app/components/Labeled.js
@@ -1,7 +1,7 @@
// @flow
import * as React from "react";
import { observer } from "mobx-react";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import styled from "styled-components";
type Props = {
diff --git a/app/components/Layout.js b/app/components/Layout.js
index 8349be3d..d5403e21 100644
--- a/app/components/Layout.js
+++ b/app/components/Layout.js
@@ -8,7 +8,7 @@ import { observable } from "mobx";
import { observer, inject } from "mobx-react";
import keydown from "react-keydown";
import Analytics from "components/Analytics";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import {
homeUrl,
searchUrl,
diff --git a/app/components/List/Item.js b/app/components/List/Item.js
index e4104447..bada3769 100644
--- a/app/components/List/Item.js
+++ b/app/components/List/Item.js
@@ -1,7 +1,7 @@
// @flow
import * as React from "react";
import styled from "styled-components";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
image?: React.Node,
diff --git a/app/components/List/Placeholder.js b/app/components/List/Placeholder.js
index de1fbcb0..f0f86147 100644
--- a/app/components/List/Placeholder.js
+++ b/app/components/List/Placeholder.js
@@ -4,7 +4,7 @@ import { times } from "lodash";
import styled from "styled-components";
import Mask from "components/Mask";
import Fade from "components/Fade";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
count?: number,
diff --git a/app/components/LoadingPlaceholder/ListPlaceholder.js b/app/components/LoadingPlaceholder/ListPlaceholder.js
index 586cdfd1..7dff75aa 100644
--- a/app/components/LoadingPlaceholder/ListPlaceholder.js
+++ b/app/components/LoadingPlaceholder/ListPlaceholder.js
@@ -4,7 +4,7 @@ import { times } from "lodash";
import styled from "styled-components";
import Mask from "components/Mask";
import Fade from "components/Fade";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
count?: number,
diff --git a/app/components/LoadingPlaceholder/LoadingPlaceholder.js b/app/components/LoadingPlaceholder/LoadingPlaceholder.js
index 75e0fc85..7afb5ea3 100644
--- a/app/components/LoadingPlaceholder/LoadingPlaceholder.js
+++ b/app/components/LoadingPlaceholder/LoadingPlaceholder.js
@@ -3,7 +3,7 @@ import * as React from "react";
import styled from "styled-components";
import Mask from "components/Mask";
import Fade from "components/Fade";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
export default function LoadingPlaceholder(props: Object) {
return (
diff --git a/app/components/Mask.js b/app/components/Mask.js
index cc36ee9c..e005d0c6 100644
--- a/app/components/Mask.js
+++ b/app/components/Mask.js
@@ -3,7 +3,7 @@ import * as React from "react";
import styled from "styled-components";
import { pulsate } from "shared/styles/animations";
import { randomInteger } from "shared/random";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
header?: boolean,
diff --git a/app/components/Modal.js b/app/components/Modal.js
index 3828393a..bedad776 100644
--- a/app/components/Modal.js
+++ b/app/components/Modal.js
@@ -8,7 +8,7 @@ import { transparentize } from "polished";
import { CloseIcon, BackIcon } from "outline-icons";
import NudeButton from "components/NudeButton";
import { fadeAndScaleIn } from "shared/styles/animations";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
ReactModal.setAppElement("#root");
diff --git a/app/components/Notice.js b/app/components/Notice.js
new file mode 100644
index 00000000..53e14174
--- /dev/null
+++ b/app/components/Notice.js
@@ -0,0 +1,12 @@
+// @flow
+import styled from "styled-components";
+
+const Notice = styled.p`
+ background: ${props => props.theme.sidebarBackground};
+ color: ${props => props.theme.sidebarText};
+ padding: 10px 12px;
+ border-radius: 4px;
+ position: relative;
+`;
+
+export default Notice;
diff --git a/app/components/NoticeAlert.js b/app/components/NoticeAlert.js
new file mode 100644
index 00000000..92efbed9
--- /dev/null
+++ b/app/components/NoticeAlert.js
@@ -0,0 +1,24 @@
+// @flow
+import * as React from "react";
+import Notice from "components/Notice";
+
+export default function AlertNotice({ children }: { children: React.Node }) {
+ return (
+
+ {" "}
+ {children}
+
+ );
+}
diff --git a/shared/components/OutlineLogo.js b/app/components/OutlineLogo.js
similarity index 100%
rename from shared/components/OutlineLogo.js
rename to app/components/OutlineLogo.js
diff --git a/app/components/PathToDocument.js b/app/components/PathToDocument.js
index ad1c3c62..f7c2caec 100644
--- a/app/components/PathToDocument.js
+++ b/app/components/PathToDocument.js
@@ -3,7 +3,7 @@ import * as React from "react";
import { observer } from "mobx-react";
import styled from "styled-components";
import { GoToIcon } from "outline-icons";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Document from "models/Document";
import Collection from "models/Collection";
diff --git a/app/components/PublishingInfo.js b/app/components/PublishingInfo.js
index ce9ef0ca..0c66f95f 100644
--- a/app/components/PublishingInfo.js
+++ b/app/components/PublishingInfo.js
@@ -3,9 +3,9 @@ import * as React from "react";
import { inject, observer } from "mobx-react";
import styled from "styled-components";
import Document from "models/Document";
-import Flex from "shared/components/Flex";
-import Time from "shared/components/Time";
-import Breadcrumb from "shared/components/Breadcrumb";
+import Flex from "components/Flex";
+import Time from "components/Time";
+import Breadcrumb from "components/Breadcrumb";
import CollectionsStore from "stores/CollectionsStore";
import AuthStore from "stores/AuthStore";
diff --git a/app/components/Sidebar/Main.js b/app/components/Sidebar/Main.js
index 88be199a..9306ca2d 100644
--- a/app/components/Sidebar/Main.js
+++ b/app/components/Sidebar/Main.js
@@ -12,7 +12,7 @@ import {
PlusIcon,
} from "outline-icons";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Modal from "components/Modal";
import Invite from "scenes/Invite";
import AccountMenu from "menus/AccountMenu";
diff --git a/app/components/Sidebar/Settings.js b/app/components/Sidebar/Settings.js
index 3e064039..09bf725f 100644
--- a/app/components/Sidebar/Settings.js
+++ b/app/components/Sidebar/Settings.js
@@ -19,7 +19,7 @@ import {
import ZapierIcon from "./icons/Zapier";
import SlackIcon from "./icons/Slack";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Sidebar from "./Sidebar";
import Scrollable from "components/Scrollable";
import Section from "./components/Section";
@@ -54,7 +54,7 @@ class SettingsSidebar extends React.Component {
- Return to App
+ Return to App
}
teamName={team.name}
diff --git a/app/components/Sidebar/Sidebar.js b/app/components/Sidebar/Sidebar.js
index 17394ac0..c013036f 100644
--- a/app/components/Sidebar/Sidebar.js
+++ b/app/components/Sidebar/Sidebar.js
@@ -7,7 +7,7 @@ import breakpoint from "styled-components-breakpoint";
import { observer, inject } from "mobx-react";
import { CloseIcon, MenuIcon } from "outline-icons";
import Fade from "components/Fade";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import UiStore from "stores/UiStore";
let firstRender = true;
diff --git a/app/components/Sidebar/components/CollectionLink.js b/app/components/Sidebar/components/CollectionLink.js
index 3c311ed3..3354eddf 100644
--- a/app/components/Sidebar/components/CollectionLink.js
+++ b/app/components/Sidebar/components/CollectionLink.js
@@ -11,7 +11,7 @@ import SidebarLink from "./SidebarLink";
import DocumentLink from "./DocumentLink";
import CollectionIcon from "components/CollectionIcon";
import DropToImport from "components/DropToImport";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
collection: Collection,
diff --git a/app/components/Sidebar/components/Collections.js b/app/components/Sidebar/components/Collections.js
index 771e23c5..00ad9117 100644
--- a/app/components/Sidebar/components/Collections.js
+++ b/app/components/Sidebar/components/Collections.js
@@ -3,7 +3,7 @@ import * as React from "react";
import { observer, inject } from "mobx-react";
import { withRouter, type RouterHistory } from "react-router-dom";
import keydown from "react-keydown";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import { PlusIcon } from "outline-icons";
import { newDocumentUrl } from "utils/routeHelpers";
diff --git a/app/components/Sidebar/components/DocumentLink.js b/app/components/Sidebar/components/DocumentLink.js
index 4cc216fc..97c79332 100644
--- a/app/components/Sidebar/components/DocumentLink.js
+++ b/app/components/Sidebar/components/DocumentLink.js
@@ -10,7 +10,7 @@ import DropToImport from "components/DropToImport";
import Fade from "components/Fade";
import Collection from "models/Collection";
import DocumentsStore from "stores/DocumentsStore";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import { type NavigationNode } from "types";
type Props = {
diff --git a/app/components/Sidebar/components/Header.js b/app/components/Sidebar/components/Header.js
index ef95382f..52c9e58e 100644
--- a/app/components/Sidebar/components/Header.js
+++ b/app/components/Sidebar/components/Header.js
@@ -1,5 +1,5 @@
// @flow
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import styled from "styled-components";
const Header = styled(Flex)`
diff --git a/app/components/Sidebar/components/HeaderBlock.js b/app/components/Sidebar/components/HeaderBlock.js
index 01f3807e..7f5636d9 100644
--- a/app/components/Sidebar/components/HeaderBlock.js
+++ b/app/components/Sidebar/components/HeaderBlock.js
@@ -2,8 +2,8 @@
import * as React from "react";
import styled, { withTheme } from "styled-components";
import { ExpandedIcon } from "outline-icons";
-import Flex from "shared/components/Flex";
-import TeamLogo from "shared/components/TeamLogo";
+import Flex from "components/Flex";
+import TeamLogo from "components/TeamLogo";
type Props = {
teamName: string,
diff --git a/app/components/Sidebar/components/Section.js b/app/components/Sidebar/components/Section.js
index 9ece925a..31d0c807 100644
--- a/app/components/Sidebar/components/Section.js
+++ b/app/components/Sidebar/components/Section.js
@@ -1,6 +1,6 @@
// @flow
import styled from "styled-components";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
const Section = styled(Flex)`
position: relative;
diff --git a/app/components/Sidebar/components/SidebarLink.js b/app/components/Sidebar/components/SidebarLink.js
index 34654400..84f7c16f 100644
--- a/app/components/Sidebar/components/SidebarLink.js
+++ b/app/components/Sidebar/components/SidebarLink.js
@@ -5,7 +5,7 @@ import { observer } from "mobx-react";
import { withRouter, NavLink } from "react-router-dom";
import { CollapsedIcon } from "outline-icons";
import styled, { withTheme } from "styled-components";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
to?: string | Object,
diff --git a/shared/components/SlackLogo.js b/app/components/SlackLogo.js
similarity index 100%
rename from shared/components/SlackLogo.js
rename to app/components/SlackLogo.js
diff --git a/shared/components/TeamLogo.js b/app/components/TeamLogo.js
similarity index 75%
rename from shared/components/TeamLogo.js
rename to app/components/TeamLogo.js
index cc898040..549e44e5 100644
--- a/shared/components/TeamLogo.js
+++ b/app/components/TeamLogo.js
@@ -2,10 +2,10 @@
import styled from "styled-components";
const TeamLogo = styled.img`
- width: 38px;
+ width: auto;
height: 38px;
border-radius: 4px;
- background: ${props => props.theme.white};
+ background: ${props => props.theme.background};
border: 1px solid ${props => props.theme.divider};
`;
diff --git a/shared/components/Time.js b/app/components/Time.js
similarity index 100%
rename from shared/components/Time.js
rename to app/components/Time.js
diff --git a/app/menus/AccountMenu.js b/app/menus/AccountMenu.js
index e5777f98..d9dce563 100644
--- a/app/menus/AccountMenu.js
+++ b/app/menus/AccountMenu.js
@@ -7,7 +7,7 @@ import { SunIcon, MoonIcon } from "outline-icons";
import styled from "styled-components";
import UiStore from "stores/UiStore";
import AuthStore from "stores/AuthStore";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import { DropdownMenu, DropdownMenuItem } from "components/DropdownMenu";
import Modal from "components/Modal";
import KeyboardShortcuts from "scenes/KeyboardShortcuts";
diff --git a/app/routes.js b/app/routes.js
index 6f74ba2a..a9fe169c 100644
--- a/app/routes.js
+++ b/app/routes.js
@@ -1,7 +1,7 @@
// @flow
import * as React from "react";
import { Switch, Route, Redirect } from "react-router-dom";
-import Home from "scenes/Home";
+import Login from "scenes/Login";
import Dashboard from "scenes/Dashboard";
import Starred from "scenes/Starred";
import Drafts from "scenes/Drafts";
@@ -38,7 +38,8 @@ const RedirectDocument = ({ match }: { match: Object }) => (
export default function Routes() {
return (
-
+
+
diff --git a/app/scenes/Collection.js b/app/scenes/Collection.js
index 0b6b8445..e22155c2 100644
--- a/app/scenes/Collection.js
+++ b/app/scenes/Collection.js
@@ -30,7 +30,7 @@ import HelpText from "components/HelpText";
import DocumentList from "components/DocumentList";
import Subheading from "components/Subheading";
import PageTitle from "components/PageTitle";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Modal from "components/Modal";
import CollectionMembers from "scenes/CollectionMembers";
import Tabs from "components/Tabs";
diff --git a/app/scenes/CollectionDelete.js b/app/scenes/CollectionDelete.js
index 4c79a63c..c1c7f838 100644
--- a/app/scenes/CollectionDelete.js
+++ b/app/scenes/CollectionDelete.js
@@ -5,7 +5,7 @@ import { observable } from "mobx";
import { inject, observer } from "mobx-react";
import { homeUrl } from "utils/routeHelpers";
import Button from "components/Button";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Collection from "models/Collection";
import CollectionsStore from "stores/CollectionsStore";
diff --git a/app/scenes/CollectionEdit.js b/app/scenes/CollectionEdit.js
index 23068b5a..f78f0bfb 100644
--- a/app/scenes/CollectionEdit.js
+++ b/app/scenes/CollectionEdit.js
@@ -6,7 +6,7 @@ import Input from "components/Input";
import InputRich from "components/InputRich";
import Button from "components/Button";
import Switch from "components/Switch";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import IconPicker from "components/IconPicker";
import Collection from "models/Collection";
diff --git a/app/scenes/CollectionExport.js b/app/scenes/CollectionExport.js
index 1ef04c32..c949d601 100644
--- a/app/scenes/CollectionExport.js
+++ b/app/scenes/CollectionExport.js
@@ -3,7 +3,7 @@ import * as React from "react";
import { observable } from "mobx";
import { inject, observer } from "mobx-react";
import Button from "components/Button";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Collection from "models/Collection";
import AuthStore from "stores/AuthStore";
diff --git a/app/scenes/CollectionMembers/AddGroupsToCollection.js b/app/scenes/CollectionMembers/AddGroupsToCollection.js
index 30d55811..ef7b9f6c 100644
--- a/app/scenes/CollectionMembers/AddGroupsToCollection.js
+++ b/app/scenes/CollectionMembers/AddGroupsToCollection.js
@@ -5,7 +5,7 @@ import { inject, observer } from "mobx-react";
import { observable } from "mobx";
import { debounce } from "lodash";
import Button from "components/Button";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Input from "components/Input";
import Modal from "components/Modal";
diff --git a/app/scenes/CollectionMembers/AddPeopleToCollection.js b/app/scenes/CollectionMembers/AddPeopleToCollection.js
index c53499fd..8e15b008 100644
--- a/app/scenes/CollectionMembers/AddPeopleToCollection.js
+++ b/app/scenes/CollectionMembers/AddPeopleToCollection.js
@@ -3,7 +3,7 @@ import * as React from "react";
import { inject, observer } from "mobx-react";
import { observable } from "mobx";
import { debounce } from "lodash";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Input from "components/Input";
import Modal from "components/Modal";
diff --git a/app/scenes/CollectionMembers/CollectionMembers.js b/app/scenes/CollectionMembers/CollectionMembers.js
index 2ca673a2..e5b08373 100644
--- a/app/scenes/CollectionMembers/CollectionMembers.js
+++ b/app/scenes/CollectionMembers/CollectionMembers.js
@@ -4,7 +4,7 @@ import { observable } from "mobx";
import styled from "styled-components";
import { inject, observer } from "mobx-react";
import { PlusIcon } from "outline-icons";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Subheading from "components/Subheading";
import Button from "components/Button";
diff --git a/app/scenes/CollectionMembers/components/MemberListItem.js b/app/scenes/CollectionMembers/components/MemberListItem.js
index 26815839..37b31d75 100644
--- a/app/scenes/CollectionMembers/components/MemberListItem.js
+++ b/app/scenes/CollectionMembers/components/MemberListItem.js
@@ -2,8 +2,8 @@
import * as React from "react";
import styled from "styled-components";
import Avatar from "components/Avatar";
-import Flex from "shared/components/Flex";
-import Time from "shared/components/Time";
+import Flex from "components/Flex";
+import Time from "components/Time";
import Badge from "components/Badge";
import Button from "components/Button";
import InputSelect from "components/InputSelect";
diff --git a/app/scenes/CollectionMembers/components/UserListItem.js b/app/scenes/CollectionMembers/components/UserListItem.js
index 19663088..c064ab42 100644
--- a/app/scenes/CollectionMembers/components/UserListItem.js
+++ b/app/scenes/CollectionMembers/components/UserListItem.js
@@ -1,7 +1,7 @@
// @flow
import * as React from "react";
import { PlusIcon } from "outline-icons";
-import Time from "shared/components/Time";
+import Time from "components/Time";
import Avatar from "components/Avatar";
import Button from "components/Button";
import Badge from "components/Badge";
diff --git a/app/scenes/CollectionNew.js b/app/scenes/CollectionNew.js
index ed628595..4241447a 100644
--- a/app/scenes/CollectionNew.js
+++ b/app/scenes/CollectionNew.js
@@ -10,7 +10,7 @@ import Input from "components/Input";
import InputRich from "components/InputRich";
import IconPicker, { icons } from "components/IconPicker";
import HelpText from "components/HelpText";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Collection from "models/Collection";
import CollectionsStore from "stores/CollectionsStore";
diff --git a/app/scenes/Document/components/Container.js b/app/scenes/Document/components/Container.js
index a248aa0d..b27159eb 100644
--- a/app/scenes/Document/components/Container.js
+++ b/app/scenes/Document/components/Container.js
@@ -1,6 +1,6 @@
// @flow
import styled from "styled-components";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
const Container = styled(Flex)`
position: relative;
diff --git a/app/scenes/Document/components/Document.js b/app/scenes/Document/components/Document.js
index 7fc5509c..a562feeb 100644
--- a/app/scenes/Document/components/Document.js
+++ b/app/scenes/Document/components/Document.js
@@ -8,7 +8,7 @@ import { observer, inject } from "mobx-react";
import { Prompt, Route, withRouter } from "react-router-dom";
import type { Location, RouterHistory } from "react-router-dom";
import keydown from "react-keydown";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import {
collectionUrl,
documentMoveUrl,
@@ -29,9 +29,9 @@ import MarkAsViewed from "./MarkAsViewed";
import ErrorBoundary from "components/ErrorBoundary";
import LoadingIndicator from "components/LoadingIndicator";
import PageTitle from "components/PageTitle";
-import Branding from "shared/components/Branding";
-import Notice from "shared/components/Notice";
-import Time from "shared/components/Time";
+import Branding from "components/Branding";
+import Notice from "components/Notice";
+import Time from "components/Time";
import UiStore from "stores/UiStore";
import AuthStore from "stores/AuthStore";
diff --git a/app/scenes/Document/components/DocumentMove.js b/app/scenes/Document/components/DocumentMove.js
index 22df2a86..57022869 100644
--- a/app/scenes/Document/components/DocumentMove.js
+++ b/app/scenes/Document/components/DocumentMove.js
@@ -12,7 +12,7 @@ import Modal from "components/Modal";
import Input from "components/Input";
import Labeled from "components/Labeled";
import PathToDocument from "components/PathToDocument";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Document from "models/Document";
import DocumentsStore from "stores/DocumentsStore";
diff --git a/app/scenes/Document/components/Editor.js b/app/scenes/Document/components/Editor.js
index bb8141f1..955d72b0 100644
--- a/app/scenes/Document/components/Editor.js
+++ b/app/scenes/Document/components/Editor.js
@@ -5,7 +5,7 @@ import Textarea from "react-autosize-textarea";
import { observer } from "mobx-react";
import Editor from "components/Editor";
import ClickablePadding from "components/ClickablePadding";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import parseTitle from "shared/utils/parseTitle";
import Document from "models/Document";
import DocumentMeta from "./DocumentMeta";
diff --git a/app/scenes/Document/components/Header.js b/app/scenes/Document/components/Header.js
index d53a7631..1b8d84ab 100644
--- a/app/scenes/Document/components/Header.js
+++ b/app/scenes/Document/components/Header.js
@@ -13,8 +13,8 @@ import AuthStore from "stores/AuthStore";
import { documentEditUrl } from "utils/routeHelpers";
import { meta } from "utils/keyboard";
-import Flex from "shared/components/Flex";
-import Breadcrumb, { Slash } from "shared/components/Breadcrumb";
+import Flex from "components/Flex";
+import Breadcrumb, { Slash } from "components/Breadcrumb";
import DocumentMenu from "menus/DocumentMenu";
import NewChildDocumentMenu from "menus/NewChildDocumentMenu";
import DocumentShare from "scenes/DocumentShare";
diff --git a/app/scenes/DocumentDelete.js b/app/scenes/DocumentDelete.js
index 2ba61e0b..594c85af 100644
--- a/app/scenes/DocumentDelete.js
+++ b/app/scenes/DocumentDelete.js
@@ -4,7 +4,7 @@ import { withRouter, type RouterHistory } from "react-router-dom";
import { observable } from "mobx";
import { inject, observer } from "mobx-react";
import Button from "components/Button";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Document from "models/Document";
import DocumentsStore from "stores/DocumentsStore";
diff --git a/app/scenes/DocumentNew.js b/app/scenes/DocumentNew.js
index 1bbe6b08..1664147c 100644
--- a/app/scenes/DocumentNew.js
+++ b/app/scenes/DocumentNew.js
@@ -2,7 +2,7 @@
import * as React from "react";
import { inject } from "mobx-react";
import type { RouterHistory, Location } from "react-router-dom";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import CenteredContent from "components/CenteredContent";
import LoadingPlaceholder from "components/LoadingPlaceholder";
import DocumentsStore from "stores/DocumentsStore";
diff --git a/app/scenes/GroupDelete.js b/app/scenes/GroupDelete.js
index ff9aa6c9..83ec112a 100644
--- a/app/scenes/GroupDelete.js
+++ b/app/scenes/GroupDelete.js
@@ -5,7 +5,7 @@ import { observable } from "mobx";
import { inject, observer } from "mobx-react";
import { groupSettings } from "shared/utils/routeHelpers";
import Button from "components/Button";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Group from "models/Group";
import UiStore from "stores/UiStore";
diff --git a/app/scenes/GroupEdit.js b/app/scenes/GroupEdit.js
index 7efb4de1..9f3c40aa 100644
--- a/app/scenes/GroupEdit.js
+++ b/app/scenes/GroupEdit.js
@@ -6,7 +6,7 @@ import { inject, observer } from "mobx-react";
import Button from "components/Button";
import Input from "components/Input";
import HelpText from "components/HelpText";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Group from "models/Group";
import UiStore from "stores/UiStore";
diff --git a/app/scenes/GroupMembers/AddPeopleToGroup.js b/app/scenes/GroupMembers/AddPeopleToGroup.js
index dc274bba..f0f36a0f 100644
--- a/app/scenes/GroupMembers/AddPeopleToGroup.js
+++ b/app/scenes/GroupMembers/AddPeopleToGroup.js
@@ -3,7 +3,7 @@ import * as React from "react";
import { inject, observer } from "mobx-react";
import { observable } from "mobx";
import { debounce } from "lodash";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Input from "components/Input";
import Modal from "components/Modal";
diff --git a/app/scenes/GroupMembers/GroupMembers.js b/app/scenes/GroupMembers/GroupMembers.js
index cd8d9147..1b052601 100644
--- a/app/scenes/GroupMembers/GroupMembers.js
+++ b/app/scenes/GroupMembers/GroupMembers.js
@@ -3,7 +3,7 @@ import * as React from "react";
import { observable } from "mobx";
import { inject, observer } from "mobx-react";
import { PlusIcon } from "outline-icons";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Empty from "components/Empty";
import HelpText from "components/HelpText";
import Subheading from "components/Subheading";
diff --git a/app/scenes/GroupMembers/components/GroupMemberListItem.js b/app/scenes/GroupMembers/components/GroupMemberListItem.js
index 623671a3..8e3471d8 100644
--- a/app/scenes/GroupMembers/components/GroupMemberListItem.js
+++ b/app/scenes/GroupMembers/components/GroupMemberListItem.js
@@ -1,8 +1,8 @@
// @flow
import * as React from "react";
import Avatar from "components/Avatar";
-import Flex from "shared/components/Flex";
-import Time from "shared/components/Time";
+import Flex from "components/Flex";
+import Time from "components/Time";
import Badge from "components/Badge";
import Button from "components/Button";
import ListItem from "components/List/Item";
diff --git a/app/scenes/GroupMembers/components/UserListItem.js b/app/scenes/GroupMembers/components/UserListItem.js
index cf7202c3..e99a4027 100644
--- a/app/scenes/GroupMembers/components/UserListItem.js
+++ b/app/scenes/GroupMembers/components/UserListItem.js
@@ -1,7 +1,7 @@
// @flow
import * as React from "react";
import { PlusIcon } from "outline-icons";
-import Time from "shared/components/Time";
+import Time from "components/Time";
import Avatar from "components/Avatar";
import Button from "components/Button";
import Badge from "components/Badge";
diff --git a/app/scenes/GroupNew.js b/app/scenes/GroupNew.js
index f7f7fefc..ddf01f44 100644
--- a/app/scenes/GroupNew.js
+++ b/app/scenes/GroupNew.js
@@ -8,7 +8,7 @@ import Input from "components/Input";
import HelpText from "components/HelpText";
import Modal from "components/Modal";
import GroupMembers from "scenes/GroupMembers";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Group from "models/Group";
import GroupsStore from "stores/GroupsStore";
diff --git a/app/scenes/Home.js b/app/scenes/Home.js
deleted file mode 100644
index 1f0b3f7e..00000000
--- a/app/scenes/Home.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// @flow
-import * as React from "react";
-import { observer, inject } from "mobx-react";
-import { Redirect } from "react-router-dom";
-import AuthStore from "stores/AuthStore";
-
-type Props = {
- auth: AuthStore,
-};
-
-const Home = observer(({ auth }: Props) => {
- if (auth.authenticated) return ;
- auth.logout(true);
- return null;
-});
-
-export default inject("auth")(Home);
diff --git a/app/scenes/Invite.js b/app/scenes/Invite.js
index e7aaebc4..e9ee4464 100644
--- a/app/scenes/Invite.js
+++ b/app/scenes/Invite.js
@@ -3,13 +3,12 @@ import * as React from "react";
import { Link, withRouter, type RouterHistory } from "react-router-dom";
import { observable, action } from "mobx";
import { inject, observer } from "mobx-react";
-import { CloseIcon } from "outline-icons";
+import { LinkIcon, CloseIcon } from "outline-icons";
import styled from "styled-components";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Button from "components/Button";
import Input from "components/Input";
import CopyToClipboard from "components/CopyToClipboard";
-import Checkbox from "components/Checkbox";
import HelpText from "components/HelpText";
import Tooltip from "components/Tooltip";
import NudeButton from "components/NudeButton";
@@ -33,7 +32,6 @@ type Props = {
type InviteRequest = {
email: string,
name: string,
- guest: boolean,
};
@observer
@@ -42,9 +40,9 @@ class Invite extends React.Component {
@observable linkCopied: boolean = false;
@observable
invites: InviteRequest[] = [
- { email: "", name: "", guest: false },
- { email: "", name: "", guest: false },
- { email: "", name: "", guest: false },
+ { email: "", name: "" },
+ { email: "", name: "" },
+ { email: "", name: "" },
];
handleSubmit = async (ev: SyntheticEvent<>) => {
@@ -80,7 +78,7 @@ class Invite extends React.Component {
);
}
- this.invites.push({ email: "", name: "", guest: false });
+ this.invites.push({ email: "", name: "" });
};
@action
@@ -106,8 +104,8 @@ class Invite extends React.Component {
{team.guestSignin ? (
Invite team members or guests to join your knowledge base. Team
- members can sign in with {team.signinMethods} and guests can use
- their email address.
+ members can sign in with {team.signinMethods} or use their email
+ address.
) : (
@@ -116,22 +114,35 @@ class Invite extends React.Component {
{can.update && (
As an admin you can also{" "}
- enable guest invites.
+ enable email sign-in.
)}
)}
{team.subdomain && (
- Want a link to share directly with your team?
-
-
+
+
-
+
+
+
)}
{this.invites.map((invite, index) => (
@@ -159,29 +170,6 @@ class Invite extends React.Component {
required={!!invite.email}
flex
/>
- {team.guestSignin && (
-
-
-
- Guests can sign in with email and
do not require{" "}
- {team.signinMethods} accounts
-
- }
- placement="top"
- >
-
- this.handleGuestChange(ev, index)}
- checked={invite.guest}
- />
-
-
-
- )}
{index !== 0 && (
@@ -220,22 +208,8 @@ class Invite extends React.Component {
}
const CopyBlock = styled("div")`
+ margin: 2em 0;
font-size: 14px;
- background: ${props => props.theme.secondaryBackground};
- padding: 8px 16px 4px;
- border-radius: 8px;
- margin-bottom: 24px;
-
- input {
- background: ${props => props.theme.background};
- border-radius: 4px;
- }
-`;
-
-const Guest = styled("div")`
- padding-top: 4px;
- margin: 0 4px 16px;
- align-self: flex-end;
`;
const Remove = styled("div")`
diff --git a/app/scenes/KeyboardShortcuts.js b/app/scenes/KeyboardShortcuts.js
index 86248f41..ca853ec8 100644
--- a/app/scenes/KeyboardShortcuts.js
+++ b/app/scenes/KeyboardShortcuts.js
@@ -2,7 +2,7 @@
import * as React from "react";
import styled from "styled-components";
import Key from "components/Key";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import { meta } from "utils/keyboard";
diff --git a/server/pages/components/AuthNotices.js b/app/scenes/Login/Notices.js
similarity index 66%
rename from server/pages/components/AuthNotices.js
rename to app/scenes/Login/Notices.js
index 6e032e6e..2b30f9ad 100644
--- a/server/pages/components/AuthNotices.js
+++ b/app/scenes/Login/Notices.js
@@ -1,61 +1,55 @@
// @flow
import * as React from "react";
-import Notice from "../../../shared/components/Notice";
+import NoticeAlert from "components/NoticeAlert";
type Props = {
notice?: string,
};
-export default function AuthNotices({ notice }: Props) {
+export default function Notices({ notice }: Props) {
return (
- {notice === "guest-success" && (
-
- A magic sign-in link has been sent to your email address, no password
- needed.
-
- )}
{notice === "google-hd" && (
-
+
Sorry, Google sign in cannot be used with a personal email. Please try
- signing in with your company Google account.
-
+ signing in with your company GSuite account.
+
)}
{notice === "hd-not-allowed" && (
-
+
Sorry, your Google apps domain is not allowed. Please try again with
an allowed company domain.
-
+
)}
{notice === "email-auth-required" && (
-
+
Your account uses email sign-in, please sign-in with email to
continue.
-
+
)}
{notice === "email-auth-ratelimit" && (
-
- An email sign-in link was recently sent, please check your inbox and
+
+ An email sign-in link was recently sent, please check your inbox or
try again in a few minutes.
-
+
)}
{notice === "auth-error" && (
-
+
Authentication failed - we were unable to sign you in at this time.
Please try again.
-
+
)}
{notice === "expired-token" && (
-
+
Sorry, it looks like that sign-in link is no longer valid, please try
requesting another.
-
+
)}
{notice === "suspended" && (
-
+
Your Outline account has been suspended. To re-activate your account,
please contact a team admin.
-
+
)}
);
diff --git a/app/scenes/Login/Service.js b/app/scenes/Login/Service.js
new file mode 100644
index 00000000..75fb4088
--- /dev/null
+++ b/app/scenes/Login/Service.js
@@ -0,0 +1,147 @@
+// @flow
+import * as React from "react";
+import styled from "styled-components";
+import { EmailIcon } from "outline-icons";
+import { client } from "utils/ApiClient";
+import ButtonLarge from "components/ButtonLarge";
+import SlackLogo from "components/SlackLogo";
+import GoogleLogo from "components/GoogleLogo";
+import InputLarge from "components/InputLarge";
+
+type Props = {
+ id: string,
+ name: string,
+ authUrl: string,
+ isCreate: boolean,
+ onEmailSuccess: (email: string) => void,
+};
+
+type State = {
+ showEmailSignin: boolean,
+ isSubmitting: boolean,
+ email: string,
+};
+
+class Service extends React.Component {
+ state = {
+ showEmailSignin: false,
+ isSubmitting: false,
+ email: "",
+ };
+
+ handleChangeEmail = (event: SyntheticInputEvent) => {
+ this.setState({ email: event.target.value });
+ };
+
+ handleSubmitEmail = async (event: SyntheticEvent) => {
+ event.preventDefault();
+
+ if (this.state.showEmailSignin && this.state.email) {
+ this.setState({ isSubmitting: true });
+
+ try {
+ const response = await client.post(event.currentTarget.action, {
+ email: this.state.email,
+ });
+ if (response.redirect) {
+ window.location.href = response.redirect;
+ } else {
+ this.props.onEmailSuccess(this.state.email);
+ }
+ } finally {
+ this.setState({ isSubmitting: false });
+ }
+ } else {
+ this.setState({ showEmailSignin: true });
+ }
+ };
+
+ render() {
+ const { isCreate, id, name, authUrl } = this.props;
+
+ if (id === "email") {
+ if (isCreate) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+ }
+
+ const icon =
+ id === "slack" ? (
+
+
+
+ ) : id === "google" ? (
+
+
+
+ ) : (
+ undefined
+ );
+
+ return (
+
+ (window.location.href = authUrl)}
+ icon={icon}
+ fullwidth
+ >
+ {isCreate ? "Sign up" : "Continue"} with {name}
+
+
+ );
+ }
+}
+
+const Logo = styled.div`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 24px;
+`;
+
+const Wrapper = styled.div`
+ margin-bottom: 1em;
+ width: 100%;
+`;
+
+const Form = styled.form`
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+`;
+
+export default Service;
diff --git a/app/scenes/Login/index.js b/app/scenes/Login/index.js
new file mode 100644
index 00000000..5e7e0dc7
--- /dev/null
+++ b/app/scenes/Login/index.js
@@ -0,0 +1,230 @@
+// @flow
+import * as React from "react";
+import styled from "styled-components";
+import { BackIcon, EmailIcon } from "outline-icons";
+import { observer, inject } from "mobx-react";
+import { Redirect } from "react-router-dom";
+import { find } from "lodash";
+import Flex from "components/Flex";
+import TeamLogo from "components/TeamLogo";
+import OutlineLogo from "components/OutlineLogo";
+import Heading from "components/Heading";
+import PageTitle from "components/PageTitle";
+import ButtonLarge from "components/ButtonLarge";
+import HelpText from "components/HelpText";
+import Fade from "components/Fade";
+import Service from "./Service";
+import Notices from "./Notices";
+import AuthStore from "stores/AuthStore";
+import getQueryVariable from "shared/utils/getQueryVariable";
+
+type Props = {
+ auth: AuthStore,
+ location: Object,
+};
+
+type State = {
+ emailLinkSentTo: string,
+};
+
+@observer
+class Login extends React.Component {
+ state = {
+ emailLinkSentTo: "",
+ };
+
+ handleReset = () => {
+ this.setState({ emailLinkSentTo: "" });
+ };
+
+ handleEmailSuccess = email => {
+ this.setState({ emailLinkSentTo: email });
+ };
+
+ render() {
+ const { auth, location } = this.props;
+ const { config } = auth;
+ const isCreate = location.pathname === "/create";
+
+ if (auth.authenticated) {
+ return ;
+ }
+
+ // we're counting on the config request being fast
+ if (!config) {
+ return null;
+ }
+
+ const hasMultipleServices = config.services.length > 1;
+ const defaultService = find(
+ config.services,
+ service => service.id === auth.lastSignedIn
+ );
+
+ const header =
+ process.env.DEPLOYMENT === "hosted" &&
+ (config.hostname ? (
+
+ Back to home
+
+ ) : (
+
+ Back to website
+
+ ));
+
+ if (this.state.emailLinkSentTo) {
+ return (
+
+ {header}
+
+
+
+
+ Check your email
+
+ A magic sign-in link has been sent to the email{" "}
+ {this.state.emailLinkSentTo}, no password needed.
+
+
+
+ Back to login
+
+
+
+ );
+ }
+
+ return (
+
+ {header}
+
+
+
+ {process.env.TEAM_LOGO && process.env.DEPLOYMENT !== "hosted" ? (
+
+ ) : (
+
+ )}
+
+
+ {isCreate ? (
+ Create an account
+ ) : (
+ Login to {config.name || "Outline"}
+ )}
+
+
+
+ {defaultService && (
+
+
+ {hasMultipleServices && (
+
+
+ You signed in with {defaultService.name} last time.
+
+
+
+ )}
+
+ )}
+
+ {config.services.map(service => {
+ if (service.id === auth.lastSignedIn) {
+ return null;
+ }
+
+ return (
+
+ );
+ })}
+
+
+ );
+ }
+}
+
+const CheckEmailIcon = styled(EmailIcon)`
+ margin-bottom: -1.5em;
+`;
+
+const Background = styled(Fade)`
+ width: 100vw;
+ height: 100vh;
+ background: ${props => props.theme.background};
+ display: flex;
+`;
+
+const Logo = styled.div`
+ margin-bottom: -1.5em;
+ height: 38px;
+`;
+
+const Note = styled(HelpText)`
+ text-align: center;
+ font-size: 14px;
+
+ em {
+ font-style: normal;
+ font-weight: 500;
+ }
+`;
+
+const Back = styled.a`
+ display: flex;
+ align-items: center;
+ color: inherit;
+ padding: 32px;
+ font-weight: 500;
+ position: absolute;
+
+ svg {
+ transition: transform 100ms ease-in-out;
+ }
+
+ &:hover {
+ svg {
+ transform: translateX(-4px);
+ }
+ }
+`;
+
+const Or = styled.hr`
+ margin: 1em 0;
+ position: relative;
+ width: 100%;
+
+ &:after {
+ content: "Or";
+ display: block;
+ position: absolute;
+ left: 50%;
+ transform: translate3d(-50%, -50%, 0);
+ text-transform: uppercase;
+ font-size: 11px;
+ color: ${props => props.theme.textSecondary};
+ background: ${props => props.theme.background};
+ border-radius: 2px;
+ padding: 0 4px;
+ }
+`;
+
+const Centered = styled(Flex)`
+ user-select: none;
+ width: 90vw;
+ height: 100%;
+ max-width: 320px;
+ margin: 0 auto;
+`;
+
+export default inject("auth")(Login);
diff --git a/app/scenes/Search/Search.js b/app/scenes/Search/Search.js
index 84b73862..e32a72ce 100644
--- a/app/scenes/Search/Search.js
+++ b/app/scenes/Search/Search.js
@@ -19,7 +19,7 @@ import UsersStore from "stores/UsersStore";
import { newDocumentUrl, searchUrl } from "utils/routeHelpers";
import { meta } from "utils/keyboard";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Button from "components/Button";
import Empty from "components/Empty";
import Fade from "components/Fade";
diff --git a/app/scenes/Search/components/FilterOption.js b/app/scenes/Search/components/FilterOption.js
index f6725b61..898b4df9 100644
--- a/app/scenes/Search/components/FilterOption.js
+++ b/app/scenes/Search/components/FilterOption.js
@@ -3,7 +3,7 @@ import * as React from "react";
import { CheckmarkIcon } from "outline-icons";
import styled from "styled-components";
import HelpText from "components/HelpText";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
label: string,
diff --git a/app/scenes/Search/components/SearchField.js b/app/scenes/Search/components/SearchField.js
index 6bed3cfb..91fedd19 100644
--- a/app/scenes/Search/components/SearchField.js
+++ b/app/scenes/Search/components/SearchField.js
@@ -2,7 +2,7 @@
import * as React from "react";
import styled, { withTheme } from "styled-components";
import { SearchIcon } from "outline-icons";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
onChange: string => void,
diff --git a/app/scenes/Settings/Details.js b/app/scenes/Settings/Details.js
index 120e1e66..9120049f 100644
--- a/app/scenes/Settings/Details.js
+++ b/app/scenes/Settings/Details.js
@@ -12,7 +12,7 @@ import Button from "components/Button";
import CenteredContent from "components/CenteredContent";
import PageTitle from "components/PageTitle";
import HelpText from "components/HelpText";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
auth: AuthStore,
diff --git a/app/scenes/Settings/Notifications.js b/app/scenes/Settings/Notifications.js
index 94ba1a2c..19110d35 100644
--- a/app/scenes/Settings/Notifications.js
+++ b/app/scenes/Settings/Notifications.js
@@ -9,7 +9,7 @@ import HelpText from "components/HelpText";
import Input from "components/Input";
import Subheading from "components/Subheading";
import NotificationListItem from "./components/NotificationListItem";
-import Notice from "shared/components/Notice";
+import Notice from "components/Notice";
import UiStore from "stores/UiStore";
import AuthStore from "stores/AuthStore";
diff --git a/app/scenes/Settings/Profile.js b/app/scenes/Settings/Profile.js
index 71ad9276..6e32626c 100644
--- a/app/scenes/Settings/Profile.js
+++ b/app/scenes/Settings/Profile.js
@@ -12,7 +12,7 @@ import Button from "components/Button";
import CenteredContent from "components/CenteredContent";
import PageTitle from "components/PageTitle";
import UserDelete from "scenes/UserDelete";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
type Props = {
auth: AuthStore,
diff --git a/app/scenes/Settings/Security.js b/app/scenes/Settings/Security.js
index b4c1bcc1..7d4a6447 100644
--- a/app/scenes/Settings/Security.js
+++ b/app/scenes/Settings/Security.js
@@ -60,8 +60,6 @@ class Security extends React.Component {
}, 500);
render() {
- const { team } = this.props.auth;
-
return (
@@ -72,27 +70,25 @@ class Security extends React.Component {
);
diff --git a/app/scenes/Settings/Slack.js b/app/scenes/Settings/Slack.js
index cdbe05b5..81dbd715 100644
--- a/app/scenes/Settings/Slack.js
+++ b/app/scenes/Settings/Slack.js
@@ -12,7 +12,7 @@ import SlackButton from "./components/SlackButton";
import CollectionsStore from "stores/CollectionsStore";
import IntegrationsStore from "stores/IntegrationsStore";
import AuthStore from "stores/AuthStore";
-import Notice from "shared/components/Notice";
+import Notice from "components/Notice";
import getQueryVariable from "shared/utils/getQueryVariable";
type Props = {
diff --git a/app/scenes/Settings/components/EventListItem.js b/app/scenes/Settings/components/EventListItem.js
index 08abbffb..068e3fde 100644
--- a/app/scenes/Settings/components/EventListItem.js
+++ b/app/scenes/Settings/components/EventListItem.js
@@ -3,7 +3,7 @@ import * as React from "react";
import { Link } from "react-router-dom";
import { capitalize } from "lodash";
import styled from "styled-components";
-import Time from "shared/components/Time";
+import Time from "components/Time";
import ListItem from "components/List/Item";
import Avatar from "components/Avatar";
import Event from "models/Event";
diff --git a/app/scenes/Settings/components/ImageUpload.js b/app/scenes/Settings/components/ImageUpload.js
index ac64d195..423eee56 100644
--- a/app/scenes/Settings/components/ImageUpload.js
+++ b/app/scenes/Settings/components/ImageUpload.js
@@ -5,7 +5,7 @@ import { observer, inject } from "mobx-react";
import styled from "styled-components";
import Dropzone from "react-dropzone";
import LoadingIndicator from "components/LoadingIndicator";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import Modal from "components/Modal";
import Button from "components/Button";
import AvatarEditor from "react-avatar-editor";
diff --git a/app/scenes/Settings/components/ShareListItem.js b/app/scenes/Settings/components/ShareListItem.js
index 1f054aec..466d3dcd 100644
--- a/app/scenes/Settings/components/ShareListItem.js
+++ b/app/scenes/Settings/components/ShareListItem.js
@@ -2,7 +2,7 @@
import * as React from "react";
import ShareMenu from "menus/ShareMenu";
import ListItem from "components/List/Item";
-import Time from "shared/components/Time";
+import Time from "components/Time";
import Share from "models/Share";
type Props = {
diff --git a/app/scenes/Settings/components/SlackButton.js b/app/scenes/Settings/components/SlackButton.js
index d471f2a9..7333b122 100644
--- a/app/scenes/Settings/components/SlackButton.js
+++ b/app/scenes/Settings/components/SlackButton.js
@@ -2,7 +2,7 @@
import * as React from "react";
import styled from "styled-components";
import { slackAuth } from "shared/utils/routeHelpers";
-import SlackLogo from "shared/components/SlackLogo";
+import SlackLogo from "components/SlackLogo";
import Button from "components/Button";
type Props = {
diff --git a/app/scenes/Settings/components/UserListItem.js b/app/scenes/Settings/components/UserListItem.js
index a049e8c8..485bc21c 100644
--- a/app/scenes/Settings/components/UserListItem.js
+++ b/app/scenes/Settings/components/UserListItem.js
@@ -8,7 +8,7 @@ import Avatar from "components/Avatar";
import Badge from "components/Badge";
import UserProfile from "scenes/UserProfile";
import ListItem from "components/List/Item";
-import Time from "shared/components/Time";
+import Time from "components/Time";
import User from "models/User";
type Props = {
diff --git a/app/scenes/UserDelete.js b/app/scenes/UserDelete.js
index 7309b81e..d09b49cc 100644
--- a/app/scenes/UserDelete.js
+++ b/app/scenes/UserDelete.js
@@ -3,7 +3,7 @@ import * as React from "react";
import { observable } from "mobx";
import { inject, observer } from "mobx-react";
import Button from "components/Button";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Modal from "components/Modal";
import AuthStore from "stores/AuthStore";
diff --git a/app/scenes/UserProfile.js b/app/scenes/UserProfile.js
index 7ce72313..fcbae252 100644
--- a/app/scenes/UserProfile.js
+++ b/app/scenes/UserProfile.js
@@ -5,7 +5,7 @@ import distanceInWordsToNow from "date-fns/distance_in_words_to_now";
import { inject, observer } from "mobx-react";
import { withRouter, type RouterHistory } from "react-router-dom";
import { EditIcon } from "outline-icons";
-import Flex from "shared/components/Flex";
+import Flex from "components/Flex";
import HelpText from "components/HelpText";
import Modal from "components/Modal";
import Button from "components/Button";
diff --git a/app/stores/AuthStore.js b/app/stores/AuthStore.js
index a0e9afdb..4d950c52 100644
--- a/app/stores/AuthStore.js
+++ b/app/stores/AuthStore.js
@@ -10,13 +10,27 @@ import Team from "models/Team";
const AUTH_STORE = "AUTH_STORE";
+type Service = {
+ id: string,
+ name: string,
+ authUrl: string,
+};
+
+type Config = {
+ name?: string,
+ hostname?: string,
+ services: Service[],
+};
+
export default class AuthStore {
@observable user: ?User;
@observable team: ?Team;
@observable token: ?string;
+ @observable lastSignedIn: ?string;
@observable isSaving: boolean = false;
@observable isSuspended: boolean = false;
@observable suspendedContactEmail: ?string;
+ @observable config: ?Config;
rootStore: RootStore;
constructor(rootStore: RootStore) {
@@ -32,8 +46,12 @@ export default class AuthStore {
this.user = new User(data.user);
this.team = new Team(data.team);
this.token = getCookie("accessToken");
+ this.lastSignedIn = getCookie("lastSignedIn");
+ setImmediate(() => this.fetchConfig());
- if (this.token) setImmediate(() => this.fetch());
+ if (this.token) {
+ setImmediate(() => this.fetch());
+ }
autorun(() => {
try {
@@ -63,6 +81,13 @@ export default class AuthStore {
});
}
+ @action
+ fetchConfig = async () => {
+ const res = await client.post("/auth.config");
+ invariant(res && res.data, "Config not available");
+ this.config = res.data;
+ };
+
@action
fetch = async () => {
try {
@@ -158,10 +183,16 @@ export default class AuthStore {
})
);
+ this.token = null;
+
// if this logout was forced from an authenticated route then
// save the current path so we can go back there once signed in
if (savePath) {
- setCookie("postLoginRedirectPath", window.location.pathname);
+ const pathName = window.location.pathname;
+
+ if (pathName !== "/" && pathName !== "/create") {
+ setCookie("postLoginRedirectPath", pathName);
+ }
}
// remove authentication token itself
@@ -178,8 +209,5 @@ export default class AuthStore {
});
this.team = null;
}
-
- // add a timestamp to force reload from server
- window.location.href = `${BASE_URL}?done=${new Date().getTime()}`;
};
}
diff --git a/app/utils/ApiClient.js b/app/utils/ApiClient.js
index b156ec14..44b18b8a 100644
--- a/app/utils/ApiClient.js
+++ b/app/utils/ApiClient.js
@@ -34,6 +34,7 @@ class ApiClient {
) => {
let body;
let modifiedPath;
+ let urlToFetch;
if (method === "GET") {
if (data) {
@@ -45,6 +46,12 @@ class ApiClient {
body = data ? JSON.stringify(data) : undefined;
}
+ if (path.match(/^http/)) {
+ urlToFetch = modifiedPath || path;
+ } else {
+ urlToFetch = this.baseUrl + (modifiedPath || path);
+ }
+
// Construct headers
const headers = new Headers({
Accept: "application/json",
@@ -60,7 +67,7 @@ class ApiClient {
let response;
try {
- response = await fetch(this.baseUrl + (modifiedPath || path), {
+ response = await fetch(urlToFetch, {
method,
body,
headers,
diff --git a/flow-typed/npm/styled-components-grid_vx.x.x.js b/flow-typed/npm/styled-components-grid_vx.x.x.js
deleted file mode 100644
index 67cf5e5c..00000000
--- a/flow-typed/npm/styled-components-grid_vx.x.x.js
+++ /dev/null
@@ -1,144 +0,0 @@
-// flow-typed signature: d7c6f4d4223c61be85becba99f8e5712
-// flow-typed version: <>/styled-components-grid_v^1.0.0-preview.15/flow_v0.71.0
-
-/**
- * This is an autogenerated libdef stub for:
- *
- * 'styled-components-grid'
- *
- * Fill this stub out by replacing all the `any` types.
- *
- * Once filled out, we encourage you to share your work with the
- * community by sending a pull request to:
- * https://github.com/flowtype/flow-typed
- */
-
-declare module 'styled-components-grid' {
- declare module.exports: any;
-}
-
-/**
- * We include stubs for each file inside this npm package in case you need to
- * require those files directly. Feel free to delete any files that aren't
- * needed.
- */
-declare module 'styled-components-grid/dist/cjs/components/Grid' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/cjs/components/GridUnit' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/cjs/components/index' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/cjs/index' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/cjs/mixins/grid' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/cjs/mixins/gridUnit' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/cjs/mixins/index' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/es/components/Grid' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/es/components/GridUnit' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/es/components/index' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/es/index' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/es/mixins/grid' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/es/mixins/gridUnit' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/es/mixins/index' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/example/index' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/styled-components-grid' {
- declare module.exports: any;
-}
-
-declare module 'styled-components-grid/dist/styled-components-grid.min' {
- declare module.exports: any;
-}
-
-// Filename aliases
-declare module 'styled-components-grid/dist/cjs/components/Grid.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/cjs/components/Grid'>;
-}
-declare module 'styled-components-grid/dist/cjs/components/GridUnit.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/cjs/components/GridUnit'>;
-}
-declare module 'styled-components-grid/dist/cjs/components/index.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/cjs/components/index'>;
-}
-declare module 'styled-components-grid/dist/cjs/index.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/cjs/index'>;
-}
-declare module 'styled-components-grid/dist/cjs/mixins/grid.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/cjs/mixins/grid'>;
-}
-declare module 'styled-components-grid/dist/cjs/mixins/gridUnit.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/cjs/mixins/gridUnit'>;
-}
-declare module 'styled-components-grid/dist/cjs/mixins/index.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/cjs/mixins/index'>;
-}
-declare module 'styled-components-grid/dist/es/components/Grid.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/es/components/Grid'>;
-}
-declare module 'styled-components-grid/dist/es/components/GridUnit.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/es/components/GridUnit'>;
-}
-declare module 'styled-components-grid/dist/es/components/index.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/es/components/index'>;
-}
-declare module 'styled-components-grid/dist/es/index.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/es/index'>;
-}
-declare module 'styled-components-grid/dist/es/mixins/grid.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/es/mixins/grid'>;
-}
-declare module 'styled-components-grid/dist/es/mixins/gridUnit.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/es/mixins/gridUnit'>;
-}
-declare module 'styled-components-grid/dist/es/mixins/index.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/es/mixins/index'>;
-}
-declare module 'styled-components-grid/dist/example/index.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/example/index'>;
-}
-declare module 'styled-components-grid/dist/styled-components-grid.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/styled-components-grid'>;
-}
-declare module 'styled-components-grid/dist/styled-components-grid.min.js' {
- declare module.exports: $Exports<'styled-components-grid/dist/styled-components-grid.min'>;
-}
diff --git a/index.js b/index.js
index 60a39906..00d10400 100644
--- a/index.js
+++ b/index.js
@@ -1,12 +1,12 @@
// @flow
-require('./init');
+require("./init");
if (
!process.env.SECRET_KEY ||
- process.env.SECRET_KEY === 'generate_a_new_key'
+ process.env.SECRET_KEY === "generate_a_new_key"
) {
console.error(
- 'The SECRET_KEY env variable must be set with the output of `openssl rand -hex 32`'
+ "The SECRET_KEY env variable must be set with the output of `openssl rand -hex 32`"
);
// $FlowFixMe
process.exit(1);
@@ -14,11 +14,11 @@ if (
if (process.env.AWS_ACCESS_KEY_ID) {
[
- 'AWS_REGION',
- 'AWS_SECRET_ACCESS_KEY',
- 'AWS_S3_UPLOAD_BUCKET_URL',
- 'AWS_S3_UPLOAD_BUCKET_NAME',
- 'AWS_S3_UPLOAD_MAX_SIZE',
+ "AWS_REGION",
+ "AWS_SECRET_ACCESS_KEY",
+ "AWS_S3_UPLOAD_BUCKET_URL",
+ "AWS_S3_UPLOAD_BUCKET_NAME",
+ "AWS_S3_UPLOAD_MAX_SIZE",
].forEach(key => {
if (!process.env[key]) {
console.error(`The ${key} env variable must be set when using AWS`);
@@ -40,7 +40,7 @@ if (process.env.SLACK_KEY) {
if (!process.env.URL) {
console.error(
- 'The URL env variable must be set to the externally accessible URL, e.g (https://www.getoutline.com)'
+ "The URL env variable must be set to the externally accessible URL, e.g (https://www.getoutline.com)"
);
// $FlowFixMe
process.exit(1);
@@ -48,7 +48,7 @@ if (!process.env.URL) {
if (!process.env.DATABASE_URL) {
console.error(
- 'The DATABASE_URL env variable must be set to the location of your postgres server, including authentication and port'
+ "The DATABASE_URL env variable must be set to the location of your postgres server, including authentication and port"
);
// $FlowFixMe
process.exit(1);
@@ -56,7 +56,7 @@ if (!process.env.DATABASE_URL) {
if (!process.env.REDIS_URL) {
console.error(
- 'The REDIS_URL env variable must be set to the location of your redis server, including authentication and port'
+ "The REDIS_URL env variable must be set to the location of your redis server, including authentication and port"
);
// $FlowFixMe
process.exit(1);
@@ -64,17 +64,17 @@ if (!process.env.REDIS_URL) {
if (!process.env.WEBSOCKETS_ENABLED) {
console.log(
- 'WARNING: Websockets are disabled. Set WEBSOCKETS_ENABLED env variable to true to enable'
+ "WARNING: Websockets are disabled. Set WEBSOCKETS_ENABLED env variable to true to enable"
);
}
-if (process.env.NODE_ENV === 'production') {
- console.log('\n\x1b[33m%s\x1b[0m', 'Running Outline in production mode.');
-} else if (process.env.NODE_ENV === 'development') {
+if (process.env.NODE_ENV === "production") {
+ console.log("\n\x1b[33m%s\x1b[0m", "Running Outline in production mode.");
+} else if (process.env.NODE_ENV === "development") {
console.log(
- '\n\x1b[33m%s\x1b[0m',
+ "\n\x1b[33m%s\x1b[0m",
'Running Outline in development mode with hot reloading. To run Outline in production mode set the NODE_ENV env variable to "production"'
);
}
-require('./server');
+require("./server");
diff --git a/init.js b/init.js
index d0fe5e0f..f828b21c 100644
--- a/init.js
+++ b/init.js
@@ -1,4 +1,4 @@
// @flow
-require('babel-core/register');
-require('babel-polyfill');
-require('dotenv').config({ silent: true });
+require("babel-core/register");
+require("babel-polyfill");
+require("dotenv").config({ silent: true });
diff --git a/package.json b/package.json
index c2c831de..b4a1700a 100644
--- a/package.json
+++ b/package.json
@@ -155,7 +155,6 @@
"string-replace-to-array": "^1.0.3",
"styled-components": "^5.0.0",
"styled-components-breakpoint": "^2.1.1",
- "styled-components-grid": "^2.2.1",
"styled-normalize": "^8.0.4",
"tiny-cookie": "^2.3.1",
"tmp": "0.0.33",
diff --git a/public/screenshot.png b/public/screenshot.png
deleted file mode 100644
index 85a4e122fe016134d57795303111ae0c31901515..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 204962
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