Files
outline/plugins/slack/client/Settings.tsx
Tom Moor 21a1257d06 chore: Move remaining auth methods to plugins (#4900)
* Move Google, Email, and Azure to plugins

* Move OIDC provider, remove old loading code

* Move AuthLogo to plugin

* AuthLogo -> PluginIcon

* Lazy load plugin settings
2023-02-19 19:52:08 -08:00

177 lines
5.3 KiB
TypeScript

import { find } from "lodash";
import { observer } from "mobx-react";
import * as React from "react";
import { useTranslation, Trans } from "react-i18next";
import styled from "styled-components";
import { IntegrationType } from "@shared/types";
import Collection from "~/models/Collection";
import Integration from "~/models/Integration";
import Button from "~/components/Button";
import Heading from "~/components/Heading";
import CollectionIcon from "~/components/Icons/CollectionIcon";
import List from "~/components/List";
import ListItem from "~/components/List/Item";
import Notice from "~/components/Notice";
import Scene from "~/components/Scene";
import Text from "~/components/Text";
import env from "~/env";
import useCurrentTeam from "~/hooks/useCurrentTeam";
import useQuery from "~/hooks/useQuery";
import useStores from "~/hooks/useStores";
import SlackIcon from "./Icon";
import SlackButton from "./components/SlackButton";
import SlackListItem from "./components/SlackListItem";
function Slack() {
const team = useCurrentTeam();
const { collections, integrations } = useStores();
const { t } = useTranslation();
const query = useQuery();
const error = query.get("error");
React.useEffect(() => {
collections.fetchPage({
limit: 100,
});
integrations.fetchPage({
limit: 100,
});
}, [collections, integrations]);
const commandIntegration = find(
integrations.slackIntegrations,
(i) => i.type === IntegrationType.Command
);
const groupedCollections = collections.orderedData
.map<[Collection, Integration | undefined]>((collection) => {
const integration = find(integrations.slackIntegrations, {
collectionId: collection.id,
});
return [collection, integration];
})
.sort((a) => (a[1] ? -1 : 1));
const appName = env.APP_NAME;
return (
<Scene title="Slack" icon={<SlackIcon />}>
<Heading>Slack</Heading>
{error === "access_denied" && (
<Notice>
<Trans>
Whoops, you need to accept the permissions in Slack to connect
{{ appName }} to your team. Try again?
</Trans>
</Notice>
)}
{error === "unauthenticated" && (
<Notice>
<Trans>
Something went wrong while authenticating your request. Please try
logging in again?
</Trans>
</Notice>
)}
<Text type="secondary">
<Trans
defaults="Get rich previews of {{ appName }} links shared in Slack and use the <em>{{ command }}</em> slash command to search for documents without leaving your chat."
values={{
command: "/outline",
appName,
}}
components={{
em: <Code />,
}}
/>
</Text>
{env.SLACK_CLIENT_ID ? (
<>
<p>
{commandIntegration ? (
<Button onClick={() => commandIntegration.delete()}>
{t("Disconnect")}
</Button>
) : (
<SlackButton
scopes={[
"commands",
"links:read",
"links:write",
// TODO: Wait forever for Slack to approve these scopes.
//"users:read",
//"users:read.email",
]}
redirectUri={`${env.URL}/auth/slack.commands`}
state={team.id}
icon={<SlackIcon />}
/>
)}
</p>
<p>&nbsp;</p>
<h2>{t("Collections")}</h2>
<Text type="secondary">
<Trans>
Connect {{ appName }} collections to Slack channels. Messages will
be automatically posted to Slack when documents are published or
updated.
</Trans>
</Text>
<List>
{groupedCollections.map(([collection, integration]) => {
if (integration) {
return (
<SlackListItem
key={integration.id}
collection={collection}
integration={
integration as Integration<IntegrationType.Post>
}
/>
);
}
return (
<ListItem
key={collection.id}
title={collection.name}
image={<CollectionIcon collection={collection} />}
actions={
<SlackButton
scopes={["incoming-webhook"]}
redirectUri={`${env.URL}/auth/slack.post`}
state={collection.id}
label={t("Connect")}
/>
}
/>
);
})}
</List>
</>
) : (
<Notice>
<Trans>
The Slack integration is currently disabled. Please set the
associated environment variables and restart the server to enable
the integration.
</Trans>
</Notice>
)}
</Scene>
);
}
const Code = styled.code`
padding: 4px 6px;
margin: 0 2px;
background: ${(props) => props.theme.codeBackground};
border-radius: 4px;
`;
export default observer(Slack);