chore: Move settings screens to Scene component (#2092)

* chore: Convert groups and people settings screens to Scene/functional

* chore: ImportExport to Scene component

* Remaining settings scenes
This commit is contained in:
Tom Moor
2021-04-27 18:46:58 -07:00
committed by GitHub
parent b89f4c36f4
commit 7221e51b96
14 changed files with 129 additions and 239 deletions

View File

@@ -1,12 +1,12 @@
// @flow // @flow
import * as React from "react"; import * as React from "react";
import { Switch } from "react-router-dom"; import { Switch } from "react-router-dom";
import Settings from "scenes/Settings";
import Details from "scenes/Settings/Details"; import Details from "scenes/Settings/Details";
import Groups from "scenes/Settings/Groups"; import Groups from "scenes/Settings/Groups";
import ImportExport from "scenes/Settings/ImportExport"; import ImportExport from "scenes/Settings/ImportExport";
import Notifications from "scenes/Settings/Notifications"; import Notifications from "scenes/Settings/Notifications";
import People from "scenes/Settings/People"; import People from "scenes/Settings/People";
import Profile from "scenes/Settings/Profile";
import Security from "scenes/Settings/Security"; import Security from "scenes/Settings/Security";
import Shares from "scenes/Settings/Shares"; import Shares from "scenes/Settings/Shares";
import Slack from "scenes/Settings/Slack"; import Slack from "scenes/Settings/Slack";
@@ -17,7 +17,7 @@ import Route from "components/ProfiledRoute";
export default function SettingsRoutes() { export default function SettingsRoutes() {
return ( return (
<Switch> <Switch>
<Route exact path="/settings" component={Settings} /> <Route exact path="/settings" component={Profile} />
<Route exact path="/settings/details" component={Details} /> <Route exact path="/settings/details" component={Details} />
<Route exact path="/settings/security" component={Security} /> <Route exact path="/settings/security" component={Security} />
<Route exact path="/settings/people" component={People} /> <Route exact path="/settings/people" component={People} />

View File

@@ -1,17 +1,17 @@
// @flow // @flow
import { observable } from "mobx"; import { observable } from "mobx";
import { observer, inject } from "mobx-react"; import { observer, inject } from "mobx-react";
import { TeamIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import styled from "styled-components"; import styled from "styled-components";
import AuthStore from "stores/AuthStore"; import AuthStore from "stores/AuthStore";
import UiStore from "stores/UiStore"; import UiStore from "stores/UiStore";
import Button from "components/Button"; import Button from "components/Button";
import CenteredContent from "components/CenteredContent";
import Flex from "components/Flex"; import Flex from "components/Flex";
import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import Input, { LabelText } from "components/Input"; import Input, { LabelText } from "components/Input";
import PageTitle from "components/PageTitle"; import Scene from "components/Scene";
import ImageUpload from "./components/ImageUpload"; import ImageUpload from "./components/ImageUpload";
import env from "env"; import env from "env";
@@ -85,9 +85,8 @@ class Details extends React.Component<Props> {
const avatarUrl = this.avatarUrl || team.avatarUrl; const avatarUrl = this.avatarUrl || team.avatarUrl;
return ( return (
<CenteredContent> <Scene title="Details" icon={<TeamIcon color="currentColor" />}>
<PageTitle title="Details" /> <Heading>Details</Heading>
<h1>Details</h1>
<HelpText> <HelpText>
These details affect the way that your Outline appears to everyone on These details affect the way that your Outline appears to everyone on
the team. the team.
@@ -143,7 +142,7 @@ class Details extends React.Component<Props> {
{isSaving ? "Saving…" : "Save"} {isSaving ? "Saving…" : "Save"}
</Button> </Button>
</form> </form>
</CenteredContent> </Scene>
); );
} }
} }

View File

@@ -1,73 +0,0 @@
// @flow
import { observable } from "mobx";
import { observer, inject } from "mobx-react";
import * as React from "react";
import AuthStore from "stores/AuthStore";
import CollectionsStore from "stores/CollectionsStore";
import UiStore from "stores/UiStore";
import Button from "components/Button";
import CenteredContent from "components/CenteredContent";
import HelpText from "components/HelpText";
import PageTitle from "components/PageTitle";
type Props = {
auth: AuthStore,
collections: CollectionsStore,
ui: UiStore,
};
@observer
class Export extends React.Component<Props> {
@observable isLoading: boolean = false;
@observable isExporting: boolean = false;
handleSubmit = async (ev: SyntheticEvent<>) => {
ev.preventDefault();
this.isLoading = true;
try {
await this.props.collections.export();
this.isExporting = true;
this.props.ui.showToast("Export in progress…", { type: "info" });
} finally {
this.isLoading = false;
}
};
render() {
const { auth } = this.props;
if (!auth.user) return null;
return (
<CenteredContent>
<PageTitle title="Export Data" />
<h1>Export Data</h1>
<HelpText>
Exporting your teams documents may take a little time depending on
the size of your knowledge base. Consider exporting a single document
or collection instead.
</HelpText>
<HelpText>
Still want to export everything in your wiki? Well put together a zip
file of your collections and documents in Markdown format and email it
to <strong>{auth.user.email}</strong>.
</HelpText>
<Button
type="submit"
onClick={this.handleSubmit}
disabled={this.isLoading || this.isExporting}
primary
>
{this.isExporting
? "Export Requested"
: this.isLoading
? "Requesting Export…"
: "Export All Data"}
</Button>
</CenteredContent>
);
}
}
export default inject("auth", "ui", "collections")(Export);

View File

@@ -1,114 +1,83 @@
// @flow // @flow
import invariant from "invariant"; import { observer } from "mobx-react";
import { observable } from "mobx"; import { PlusIcon, GroupIcon } from "outline-icons";
import { observer, inject } from "mobx-react";
import { PlusIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { type Match } from "react-router-dom"; import { useTranslation, Trans } from "react-i18next";
import AuthStore from "stores/AuthStore";
import GroupsStore from "stores/GroupsStore";
import PoliciesStore from "stores/PoliciesStore";
import GroupNew from "scenes/GroupNew"; import GroupNew from "scenes/GroupNew";
import Button from "components/Button"; import Button from "components/Button";
import CenteredContent from "components/CenteredContent";
import Empty from "components/Empty"; import Empty from "components/Empty";
import GroupListItem from "components/GroupListItem"; import GroupListItem from "components/GroupListItem";
import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import List from "components/List";
import { ListPlaceholder } from "components/LoadingPlaceholder";
import Modal from "components/Modal"; import Modal from "components/Modal";
import PageTitle from "components/PageTitle"; import PaginatedList from "components/PaginatedList";
import Tab from "components/Tab"; import Scene from "components/Scene";
import Tabs from "components/Tabs"; import Subheading from "components/Subheading";
import useCurrentTeam from "hooks/useCurrentTeam";
import useStores from "hooks/useStores";
import GroupMenu from "menus/GroupMenu"; import GroupMenu from "menus/GroupMenu";
type Props = { function Groups() {
auth: AuthStore, const { t } = useTranslation();
groups: GroupsStore, const { policies, groups } = useStores();
policies: PoliciesStore, const team = useCurrentTeam();
match: Match, const can = policies.abilities(team.id);
}; const [newGroupModalOpen, setNewGroupModalOpen] = React.useState(false);
@observer const handleNewGroupModalOpen = React.useCallback(() => {
class Groups extends React.Component<Props> { setNewGroupModalOpen(true);
@observable newGroupModalOpen: boolean = false; }, []);
componentDidMount() { const handleNewGroupModalClose = React.useCallback(() => {
this.props.groups.fetchPage({ limit: 100 }); setNewGroupModalOpen(false);
} }, []);
handleNewGroupModalOpen = () => { return (
this.newGroupModalOpen = true; <Scene title={t("Groups")} icon={<GroupIcon color="currentColor" />}>
}; <Heading>{t("Groups")}</Heading>
<HelpText>
handleNewGroupModalClose = () => { <Trans>
this.newGroupModalOpen = false;
};
render() {
const { auth, policies, groups } = this.props;
const currentUser = auth.user;
const team = auth.team;
invariant(currentUser, "User should exist");
invariant(team, "Team should exist");
const showLoading = groups.isFetching && !groups.orderedData.length;
const showEmpty = groups.isLoaded && !groups.orderedData.length;
const can = policies.abilities(team.id);
return (
<CenteredContent>
<PageTitle title="People" />
<h1>Groups</h1>
<HelpText>
Groups can be used to organize and manage the people on your team. Groups can be used to organize and manage the people on your team.
</HelpText> </Trans>
</HelpText>
{can.createGroup && ( {can.createGroup && (
<Button <Button
type="button" type="button"
onClick={this.handleNewGroupModalOpen} onClick={handleNewGroupModalOpen}
icon={<PlusIcon />} icon={<PlusIcon />}
neutral neutral
>
New group
</Button>
)}
<Tabs>
<Tab to="/settings/groups" exact>
All Groups
</Tab>
</Tabs>
<List>
{groups.orderedData.map((group) => (
<GroupListItem
key={group.id}
group={group}
renderActions={({ openMembersModal }) => (
<GroupMenu group={group} onMembers={openMembersModal} />
)}
showFacepile
/>
))}
</List>
{showEmpty && <Empty>No groups to see here.</Empty>}
{showLoading && <ListPlaceholder count={5} />}
<Modal
title="Create a group"
onRequestClose={this.handleNewGroupModalClose}
isOpen={this.newGroupModalOpen}
> >
<GroupNew onSubmit={this.handleNewGroupModalClose} /> {`${t("New group")}`}
</Modal> </Button>
</CenteredContent> )}
);
} <Subheading>{t("All groups")}</Subheading>
<PaginatedList
items={groups.orderedData}
empty={<Empty>{t("No groups have been created yet")}</Empty>}
fetch={groups.fetchPage}
renderItem={(item) => (
<GroupListItem
key={item.id}
group={item}
renderActions={({ openMembersModal }) => (
<GroupMenu group={item} onMembers={openMembersModal} />
)}
showFacepile
/>
)}
/>
<Modal
title={t("Create a group")}
onRequestClose={handleNewGroupModalClose}
isOpen={newGroupModalOpen}
>
<GroupNew onSubmit={handleNewGroupModalClose} />
</Modal>
</Scene>
);
} }
export default inject("auth", "groups", "policies")(Groups); export default observer(Groups);

View File

@@ -1,17 +1,17 @@
// @flow // @flow
import invariant from "invariant"; import invariant from "invariant";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { CollectionIcon } from "outline-icons"; import { CollectionIcon, DocumentIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { useTranslation, Trans } from "react-i18next"; import { useTranslation, Trans } from "react-i18next";
import { VisuallyHidden } from "reakit/VisuallyHidden"; import { VisuallyHidden } from "reakit/VisuallyHidden";
import styled from "styled-components"; import styled from "styled-components";
import { parseOutlineExport } from "shared/utils/zip"; import { parseOutlineExport } from "shared/utils/zip";
import Button from "components/Button"; import Button from "components/Button";
import CenteredContent from "components/CenteredContent"; import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import Notice from "components/Notice"; import Notice from "components/Notice";
import PageTitle from "components/PageTitle"; import Scene from "components/Scene";
import useCurrentUser from "hooks/useCurrentUser"; import useCurrentUser from "hooks/useCurrentUser";
import useStores from "hooks/useStores"; import useStores from "hooks/useStores";
import getDataTransferFiles from "utils/getDataTransferFiles"; import getDataTransferFiles from "utils/getDataTransferFiles";
@@ -107,9 +107,11 @@ function ImportExport() {
const isImportable = hasCollections && hasDocuments; const isImportable = hasCollections && hasDocuments;
return ( return (
<CenteredContent> <Scene
<PageTitle title={`${t("Import")} / ${t("Export")}`} /> title={`${t("Import")} / ${t("Export")}`}
<h1>{t("Import")}</h1> icon={<DocumentIcon color="currentColor" />}
>
<Heading>{t("Import")}</Heading>
<HelpText> <HelpText>
<Trans> <Trans>
It is possible to import a zip file of folders and Markdown files It is possible to import a zip file of folders and Markdown files
@@ -176,7 +178,7 @@ function ImportExport() {
</Button> </Button>
)} )}
<h1>{t("Export")}</h1> <Heading>{t("Export")}</Heading>
<HelpText> <HelpText>
<Trans <Trans
defaults="A full export might take some time, consider exporting a single document or collection if possible. Well put together a zip of all your documents in Markdown format and email it to <em>{{ userEmail }}</em>." defaults="A full export might take some time, consider exporting a single document or collection if possible. Well put together a zip of all your documents in Markdown format and email it to <em>{{ userEmail }}</em>."
@@ -196,7 +198,7 @@ function ImportExport() {
? `${t("Requesting Export")}` ? `${t("Requesting Export")}`
: t("Export Data")} : t("Export Data")}
</Button> </Button>
</CenteredContent> </Scene>
); );
} }

View File

@@ -1,16 +1,17 @@
// @flow // @flow
import { debounce } from "lodash"; import { debounce } from "lodash";
import { observer, inject } from "mobx-react"; import { observer, inject } from "mobx-react";
import { EmailIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import styled from "styled-components"; import styled from "styled-components";
import AuthStore from "stores/AuthStore"; import AuthStore from "stores/AuthStore";
import NotificationSettingsStore from "stores/NotificationSettingsStore"; import NotificationSettingsStore from "stores/NotificationSettingsStore";
import UiStore from "stores/UiStore"; import UiStore from "stores/UiStore";
import CenteredContent from "components/CenteredContent"; import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import Input from "components/Input"; import Input from "components/Input";
import Notice from "components/Notice"; import Notice from "components/Notice";
import PageTitle from "components/PageTitle"; import Scene from "components/Scene";
import Subheading from "components/Subheading"; import Subheading from "components/Subheading";
import NotificationListItem from "./components/NotificationListItem"; import NotificationListItem from "./components/NotificationListItem";
@@ -85,16 +86,13 @@ class Notifications extends React.Component<Props> {
if (!team || !user) return null; if (!team || !user) return null;
return ( return (
<CenteredContent> <Scene title="Notifications" icon={<EmailIcon color="currentColor" />}>
{showSuccessNotice && ( {showSuccessNotice && (
<Notice> <Notice>
Unsubscription successful. Your notification settings were updated Unsubscription successful. Your notification settings were updated
</Notice> </Notice>
)} )}
<Heading>Notifications</Heading>
<PageTitle title="Notifications" />
<h1>Notifications</h1>
<HelpText> <HelpText>
Manage when and where you receive email notifications from Outline. Manage when and where you receive email notifications from Outline.
Your email address can be updated in your SSO provider. Your email address can be updated in your SSO provider.
@@ -127,7 +125,7 @@ class Notifications extends React.Component<Props> {
/> />
); );
})} })}
</CenteredContent> </Scene>
); );
} }
} }

View File

@@ -2,7 +2,7 @@
import invariant from "invariant"; import invariant from "invariant";
import { observable } from "mobx"; import { observable } from "mobx";
import { observer, inject } from "mobx-react"; import { observer, inject } from "mobx-react";
import { PlusIcon } from "outline-icons"; import { PlusIcon, UserIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { withTranslation, type TFunction, Trans } from "react-i18next"; import { withTranslation, type TFunction, Trans } from "react-i18next";
import { type Match } from "react-router-dom"; import { type Match } from "react-router-dom";
@@ -12,15 +12,14 @@ import UsersStore from "stores/UsersStore";
import Invite from "scenes/Invite"; import Invite from "scenes/Invite";
import Bubble from "components/Bubble"; import Bubble from "components/Bubble";
import Button from "components/Button"; import Button from "components/Button";
import CenteredContent from "components/CenteredContent";
import Empty from "components/Empty"; import Empty from "components/Empty";
import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import Modal from "components/Modal"; import Modal from "components/Modal";
import PageTitle from "components/PageTitle";
import PaginatedList from "components/PaginatedList"; import PaginatedList from "components/PaginatedList";
import Scene from "components/Scene";
import Tab from "components/Tab"; import Tab from "components/Tab";
import Tabs, { Separator } from "components/Tabs"; import Tabs, { Separator } from "components/Tabs";
import UserListItem from "./components/UserListItem"; import UserListItem from "./components/UserListItem";
type Props = { type Props = {
@@ -79,9 +78,8 @@ class People extends React.Component<Props> {
const { counts } = this.props.users; const { counts } = this.props.users;
return ( return (
<CenteredContent> <Scene title={t("People")} icon={<UserIcon color="currentColor" />}>
<PageTitle title={t("People")} /> <Heading>{t("People")}</Heading>
<h1>{t("People")}</h1>
<HelpText> <HelpText>
<Trans> <Trans>
Everyone that has signed into Outline appears here. Its possible Everyone that has signed into Outline appears here. Its possible
@@ -151,7 +149,7 @@ class People extends React.Component<Props> {
<Invite onSubmit={this.handleInviteModalClose} /> <Invite onSubmit={this.handleInviteModalClose} />
</Modal> </Modal>
)} )}
</CenteredContent> </Scene>
); );
} }
} }

View File

@@ -1,21 +1,21 @@
// @flow // @flow
import { observable } from "mobx"; import { observable } from "mobx";
import { observer, inject } from "mobx-react"; import { observer, inject } from "mobx-react";
import { ProfileIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { Trans, withTranslation, type TFunction } from "react-i18next"; import { Trans, withTranslation, type TFunction } from "react-i18next";
import styled from "styled-components"; import styled from "styled-components";
import { languageOptions } from "shared/i18n"; import { languageOptions } from "shared/i18n";
import AuthStore from "stores/AuthStore"; import AuthStore from "stores/AuthStore";
import UiStore from "stores/UiStore"; import UiStore from "stores/UiStore";
import UserDelete from "scenes/UserDelete"; import UserDelete from "scenes/UserDelete";
import Button from "components/Button"; import Button from "components/Button";
import CenteredContent from "components/CenteredContent";
import Flex from "components/Flex"; import Flex from "components/Flex";
import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import Input, { LabelText } from "components/Input"; import Input, { LabelText } from "components/Input";
import InputSelect from "components/InputSelect"; import InputSelect from "components/InputSelect";
import PageTitle from "components/PageTitle"; import Scene from "components/Scene";
import ImageUpload from "./components/ImageUpload"; import ImageUpload from "./components/ImageUpload";
type Props = { type Props = {
@@ -99,9 +99,8 @@ class Profile extends React.Component<Props> {
const avatarUrl = this.avatarUrl || user.avatarUrl; const avatarUrl = this.avatarUrl || user.avatarUrl;
return ( return (
<CenteredContent> <Scene title={t("Profile")} icon={<ProfileIcon color="currentColor" />}>
<PageTitle title={t("Profile")} /> <Heading>{t("Profile")}</Heading>
<h1>{t("Profile")}</h1>
<ProfilePicture column> <ProfilePicture column>
<LabelText>{t("Photo")}</LabelText> <LabelText>{t("Photo")}</LabelText>
<AvatarContainer> <AvatarContainer>
@@ -168,7 +167,7 @@ class Profile extends React.Component<Props> {
{this.showDeleteModal && ( {this.showDeleteModal && (
<UserDelete onRequestClose={this.toggleDeleteAccount} /> <UserDelete onRequestClose={this.toggleDeleteAccount} />
)} )}
</CenteredContent> </Scene>
); );
} }
} }

View File

@@ -2,14 +2,14 @@
import { debounce } from "lodash"; import { debounce } from "lodash";
import { observable } from "mobx"; import { observable } from "mobx";
import { observer, inject } from "mobx-react"; import { observer, inject } from "mobx-react";
import { PadlockIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import AuthStore from "stores/AuthStore"; import AuthStore from "stores/AuthStore";
import UiStore from "stores/UiStore"; import UiStore from "stores/UiStore";
import CenteredContent from "components/CenteredContent";
import Checkbox from "components/Checkbox"; import Checkbox from "components/Checkbox";
import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import PageTitle from "components/PageTitle"; import Scene from "components/Scene";
type Props = { type Props = {
auth: AuthStore, auth: AuthStore,
@@ -61,9 +61,8 @@ class Security extends React.Component<Props> {
render() { render() {
return ( return (
<CenteredContent> <Scene title="Security" icon={<PadlockIcon color="currentColor" />}>
<PageTitle title="Security" /> <Heading>Security</Heading>
<h1>Security</h1>
<HelpText> <HelpText>
Settings that impact the access, security, and content of your Settings that impact the access, security, and content of your
knowledge base. knowledge base.
@@ -90,7 +89,7 @@ class Security extends React.Component<Props> {
onChange={this.handleChange} onChange={this.handleChange}
note="Links to supported services are shown as rich embeds within your documents" note="Links to supported services are shown as rich embeds within your documents"
/> />
</CenteredContent> </Scene>
); );
} }
} }

View File

@@ -1,13 +1,14 @@
// @flow // @flow
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { LinkIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import { useTranslation, Trans } from "react-i18next"; import { useTranslation, Trans } from "react-i18next";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import CenteredContent from "components/CenteredContent";
import Empty from "components/Empty"; import Empty from "components/Empty";
import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import PageTitle from "components/PageTitle";
import PaginatedList from "components/PaginatedList"; import PaginatedList from "components/PaginatedList";
import Scene from "components/Scene";
import Subheading from "components/Subheading"; import Subheading from "components/Subheading";
import ShareListItem from "./components/ShareListItem"; import ShareListItem from "./components/ShareListItem";
import useCurrentTeam from "hooks/useCurrentTeam"; import useCurrentTeam from "hooks/useCurrentTeam";
@@ -21,9 +22,8 @@ function Shares() {
const can = policies.abilities(team.id); const can = policies.abilities(team.id);
return ( return (
<CenteredContent> <Scene title={t("Share Links")} icon={<LinkIcon color="currentColor" />}>
<PageTitle title={t("Share Links")} /> <Heading>{t("Share Links")}</Heading>
<h1>{t("Share Links")}</h1>
<HelpText> <HelpText>
<Trans> <Trans>
Documents that have been shared are listed below. Anyone that has the Documents that have been shared are listed below. Anyone that has the
@@ -49,7 +49,7 @@ function Shares() {
fetch={shares.fetchPage} fetch={shares.fetchPage}
renderItem={(item) => <ShareListItem key={item.id} share={item} />} renderItem={(item) => <ShareListItem key={item.id} share={item} />}
/> />
</CenteredContent> </Scene>
); );
} }

View File

@@ -1,16 +1,16 @@
// @flow // @flow
import { observable } from "mobx"; import { observable } from "mobx";
import { observer, inject } from "mobx-react"; import { observer, inject } from "mobx-react";
import { CodeIcon } from "outline-icons";
import * as React from "react"; import * as React from "react";
import ApiKeysStore from "stores/ApiKeysStore"; import ApiKeysStore from "stores/ApiKeysStore";
import UiStore from "stores/UiStore"; import UiStore from "stores/UiStore";
import Button from "components/Button"; import Button from "components/Button";
import CenteredContent from "components/CenteredContent"; import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import Input from "components/Input"; import Input from "components/Input";
import List from "components/List"; import List from "components/List";
import PageTitle from "components/PageTitle"; import Scene from "components/Scene";
import TokenListItem from "./components/TokenListItem"; import TokenListItem from "./components/TokenListItem";
type Props = { type Props = {
@@ -45,10 +45,8 @@ class Tokens extends React.Component<Props> {
const hasApiKeys = apiKeys.orderedData.length > 0; const hasApiKeys = apiKeys.orderedData.length > 0;
return ( return (
<CenteredContent> <Scene title="API Tokens" icon={<CodeIcon color="currentColor" />}>
<PageTitle title="API Tokens" /> <Heading>API Tokens</Heading>
<h1>API Tokens</h1>
<HelpText> <HelpText>
You can create an unlimited amount of personal tokens to authenticate You can create an unlimited amount of personal tokens to authenticate
with the API. For more details about the API take a look at the{" "} with the API. For more details about the API take a look at the{" "}
@@ -83,7 +81,7 @@ class Tokens extends React.Component<Props> {
disabled={apiKeys.isSaving} disabled={apiKeys.isSaving}
/> />
</form> </form>
</CenteredContent> </Scene>
); );
} }
} }

View File

@@ -1,15 +1,15 @@
// @flow // @flow
import * as React from "react"; import * as React from "react";
import Button from "components/Button"; import Button from "components/Button";
import CenteredContent from "components/CenteredContent"; import Heading from "components/Heading";
import HelpText from "components/HelpText"; import HelpText from "components/HelpText";
import PageTitle from "components/PageTitle"; import Scene from "components/Scene";
import ZapierIcon from "components/ZapierIcon";
function Zapier() { function Zapier() {
return ( return (
<CenteredContent> <Scene title="Zapier" icon={<ZapierIcon color="currentColor" />}>
<PageTitle title="Zapier" /> <Heading>Zapier</Heading>
<h1>Zapier</h1>
<HelpText> <HelpText>
Zapier is a platform that allows Outline to easily integrate with Zapier is a platform that allows Outline to easily integrate with
thousands of other business tools. Head over to Zapier to setup a "Zap" thousands of other business tools. Head over to Zapier to setup a "Zap"
@@ -24,7 +24,7 @@ function Zapier() {
Open Zapier Open Zapier
</Button> </Button>
</p> </p>
</CenteredContent> </Scene>
); );
} }

View File

@@ -1,3 +0,0 @@
// @flow
import Profile from "./Profile";
export default Profile;

View File

@@ -361,6 +361,10 @@
"by {{ name }}": "by {{ name }}", "by {{ name }}": "by {{ name }}",
"Last accessed": "Last accessed", "Last accessed": "Last accessed",
"Add to Slack": "Add to Slack", "Add to Slack": "Add to Slack",
"Groups can be used to organize and manage the people on your team.": "Groups can be used to organize and manage the people on your team.",
"New group": "New group",
"All groups": "All groups",
"No groups have been created yet": "No groups have been created yet",
"Import started": "Import started", "Import started": "Import started",
"Export in progress…": "Export in progress…", "Export in progress…": "Export in progress…",
"It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.": "It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.", "It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.": "It is possible to import a zip file of folders and Markdown files previously exported from an Outline instance. Support will soon be added for importing from other services.",