Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New login screen #1331

Merged
merged 15 commits into from
Jul 10, 2020
Prev Previous commit
fix: Entering SSO email into login form fails
fix: Tweak language around guest signin
  • Loading branch information
tommoor committed Jul 6, 2020
commit 7a5daf60d2a5ccd10ba098b187f057db3e1428d2
2 changes: 1 addition & 1 deletion app/components/Sidebar/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class SettingsSidebar extends React.Component<Props> {
<HeaderBlock
subheading={
<ReturnToApp align="center">
<BackIcon /> Return to App
<BackIcon color="currentColor" /> Return to App
</ReturnToApp>
}
teamName={team.name}
Expand Down
78 changes: 26 additions & 52 deletions app/scenes/Invite.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 "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";
Expand All @@ -33,7 +32,6 @@ type Props = {
type InviteRequest = {
email: string,
name: string,
guest: boolean,
};

@observer
Expand All @@ -42,9 +40,9 @@ class Invite extends React.Component<Props> {
@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<>) => {
Expand Down Expand Up @@ -80,7 +78,7 @@ class Invite extends React.Component<Props> {
);
}

this.invites.push({ email: "", name: "", guest: false });
this.invites.push({ email: "", name: "" });
};

@action
Expand All @@ -106,8 +104,8 @@ class Invite extends React.Component<Props> {
{team.guestSignin ? (
<HelpText>
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.
</HelpText>
) : (
<HelpText>
Expand All @@ -116,22 +114,35 @@ class Invite extends React.Component<Props> {
{can.update && (
<React.Fragment>
As an admin you can also{" "}
<Link to="/settings/security">enable guest invites</Link>.
<Link to="/settings/security">enable email sign-in</Link>.
</React.Fragment>
)}
</HelpText>
)}
{team.subdomain && (
<CopyBlock>
Want a link to share directly with your team?
<Flex>
<Input type="text" value={team.url} readOnly flex />&nbsp;&nbsp;
<Flex align="flex-end">
<Input
type="text"
value={team.url}
label="Want a link to share directly with your team?"
readOnly
flex
/>&nbsp;&nbsp;
<CopyToClipboard text={team.url} onCopy={this.handleCopy}>
<Button type="button" neutral>
<Button
type="button"
icon={<LinkIcon />}
style={{ marginBottom: "16px" }}
neutral
>
{this.linkCopied ? "Link copied" : "Copy link"}
</Button>
</CopyToClipboard>
</Flex>
<p>
<hr />
</p>
</CopyBlock>
)}
{this.invites.map((invite, index) => (
Expand Down Expand Up @@ -159,29 +170,6 @@ class Invite extends React.Component<Props> {
required={!!invite.email}
flex
/>
{team.guestSignin && (
<React.Fragment>
&nbsp;&nbsp;
<Tooltip
tooltip={
<span>
Guests can sign in with email and <br />do not require{" "}
{team.signinMethods} accounts
</span>
}
placement="top"
>
<Guest>
<Checkbox
name="guest"
label="Guest"
onChange={ev => this.handleGuestChange(ev, index)}
checked={invite.guest}
/>
</Guest>
</Tooltip>
</React.Fragment>
)}
{index !== 0 && (
<Remove>
<Tooltip tooltip="Remove invite" placement="top">
Expand Down Expand Up @@ -220,22 +208,8 @@ class Invite extends React.Component<Props> {
}

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")`
Expand Down
8 changes: 6 additions & 2 deletions app/scenes/Login/Service.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,14 @@ class Service extends React.Component<Props, State> {
this.setState({ isSubmitting: true });

try {
await client.post(event.currentTarget.action, {
const response = await client.post(event.currentTarget.action, {
email: this.state.email,
});
this.props.onEmailSuccess(this.state.email);
if (response.redirect) {
window.location.href = response.redirect;
} else {
this.props.onEmailSuccess(this.state.email);
}
} finally {
this.setState({ isSubmitting: false });
}
Expand Down
12 changes: 4 additions & 8 deletions app/scenes/Settings/Security.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ class Security extends React.Component<Props> {
}, 500);

render() {
const { team } = this.props.auth;

return (
<CenteredContent>
<PageTitle title="Security" />
Expand All @@ -72,27 +70,25 @@ class Security extends React.Component<Props> {
</HelpText>

<Checkbox
label="Allow guest invites"
label="Allow email authentication"
name="guestSignin"
checked={this.guestSignin}
onChange={this.handleChange}
note={`When enabled guests can be invited by email address and are able to signin without ${
team ? team.signinMethods : "SSO"
}`}
note="When enabled, users can sign-in using their email address"
/>
<Checkbox
label="Public document sharing"
name="sharing"
checked={this.sharing}
onChange={this.handleChange}
note="When enabled documents can be shared publicly by any team member"
note="When enabled, documents can be shared publicly on the internet by any team member"
/>
<Checkbox
label="Rich service embeds"
name="documentEmbeds"
checked={this.documentEmbeds}
onChange={this.handleChange}
note="Convert links to supported services into rich embeds within your documents"
note="Links to supported services are shown as rich embeds within your documents"
/>
</CenteredContent>
);
Expand Down
5 changes: 4 additions & 1 deletion server/auth/email.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ router.post("email", async ctx => {
// signin then just forward them directly to that service's
// login page
if (user.service && user.service !== "email") {
return ctx.redirect(`${team.url}/auth/${user.service}`);
ctx.body = {
redirect: `${team.url}/auth/${user.service}`,
};
return;
}

if (!team.guestSignin) {
Expand Down
3 changes: 1 addition & 2 deletions server/commands/userInviter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { User, Event, Team } from "../models";
import mailer from "../mailer";
import { sequelize } from "../sequelize";

type Invite = { name: string, email: string, guest: boolean };
type Invite = { name: string, email: string };

export default async function userInviter({
user,
Expand Down Expand Up @@ -77,7 +77,6 @@ export default async function userInviter({
await mailer.invite({
to: invite.email,
name: invite.name,
guest: invite.guest,
actorName: user.name,
actorEmail: user.email,
teamName: team.name,
Expand Down
9 changes: 2 additions & 7 deletions server/emails/InviteEmail.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import EmptySpace from "./components/EmptySpace";

export type Props = {
name: string,
guest: boolean,
actorName: string,
actorEmail: string,
teamName: string,
Expand All @@ -22,23 +21,21 @@ export const inviteEmailText = ({
actorName,
actorEmail,
teamUrl,
guest,
}: Props) => `
Join ${teamName} on Outline

${actorName} (${
actorEmail
}) has invited you to join Outline, a place for your team to build and share knowledge.

Join now: ${teamUrl}${guest ? "?guest=true" : ""}
Join now: ${teamUrl}
`;

export const InviteEmail = ({
teamName,
actorName,
actorEmail,
teamUrl,
guest,
}: Props) => {
return (
<EmailTemplate>
Expand All @@ -52,9 +49,7 @@ export const InviteEmail = ({
</p>
<EmptySpace height={10} />
<p>
<Button href={`${teamUrl}${guest ? "?guest=true" : ""}`}>
Join now
</Button>
<Button href={teamUrl}>Join now</Button>
</p>
</Body>

Expand Down