Add ability to link Slack <-> Outline accounts (#6682)

This commit is contained in:
Tom Moor
2024-03-18 19:21:38 -06:00
committed by GitHub
parent e294fafd4f
commit cbdacc7cfd
23 changed files with 647 additions and 421 deletions

View File

@@ -5,7 +5,9 @@ import styled from "styled-components";
import { IntegrationService, IntegrationType } from "@shared/types";
import Collection from "~/models/Collection";
import Integration from "~/models/Integration";
import Button from "~/components/Button";
import { ConnectedButton } from "~/scenes/Settings/components/ConnectedButton";
import SettingRow from "~/scenes/Settings/components/SettingRow";
import Flex from "~/components/Flex";
import Heading from "~/components/Heading";
import CollectionIcon from "~/components/Icons/CollectionIcon";
import List from "~/components/List";
@@ -15,6 +17,7 @@ import Scene from "~/components/Scene";
import Text from "~/components/Text";
import env from "~/env";
import useCurrentTeam from "~/hooks/useCurrentTeam";
import usePolicy from "~/hooks/usePolicy";
import useQuery from "~/hooks/useQuery";
import useStores from "~/hooks/useStores";
import { SlackUtils } from "../shared/SlackUtils";
@@ -27,6 +30,7 @@ function Slack() {
const { collections, integrations } = useStores();
const { t } = useTranslation();
const query = useQuery();
const can = usePolicy(team);
const error = query.get("error");
React.useEffect(() => {
@@ -34,6 +38,7 @@ function Slack() {
limit: 100,
});
void integrations.fetchPage({
service: IntegrationService.Slack,
limit: 100,
});
}, [collections, integrations]);
@@ -43,6 +48,11 @@ function Slack() {
service: IntegrationService.Slack,
});
const linkedAccountIntegration = integrations.find({
type: IntegrationType.LinkedAccount,
service: IntegrationService.Slack,
});
const groupedCollections = collections.orderedData
.map<[Collection, Integration | undefined]>((collection) => {
const integration = integrations.find({
@@ -76,44 +86,80 @@ function Slack() {
</Trans>
</Notice>
)}
<Text as="p" 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={SlackUtils.commandsUrl()}
state={team.id}
icon={<SlackIcon />}
/>
)}
</p>
<p>&nbsp;</p>
<h2>{t("Collections")}</h2>
<SettingRow
name="link"
label={t("Personal account")}
description={
<Trans>
Link your {{ appName }} account to Slack to enable searching the
documents you have access to directly within chat.
</Trans>
}
>
<Flex align="flex-end" column>
{linkedAccountIntegration ? (
<ConnectedButton
onClick={linkedAccountIntegration.delete}
confirmationMessage={t(
"Disconnecting your personal account will prevent searching for documents from Slack. Are you sure?"
)}
/>
) : (
<SlackButton
redirectUri={SlackUtils.connectUrl()}
state={SlackUtils.createState(
team.id,
IntegrationType.LinkedAccount
)}
label={t("Connect")}
/>
)}
</Flex>
</SettingRow>
{can.update && (
<>
<SettingRow
name="slash"
border={false}
label={t("Slash command")}
description={
<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 />,
}}
/>
}
>
<Flex align="flex-end" column>
{commandIntegration ? (
<ConnectedButton
onClick={commandIntegration.delete}
confirmationMessage={t(
"This will remove the Outline slash command from your Slack workspace. Are you sure?"
)}
/>
) : (
<SlackButton
scopes={["commands", "links:read", "links:write"]}
redirectUri={SlackUtils.connectUrl()}
state={SlackUtils.createState(
team.id,
IntegrationType.Command
)}
icon={<SlackIcon />}
/>
)}
</Flex>
</SettingRow>
<Heading as="h2">{t("Collections")}</Heading>
<Text as="p" type="secondary">
<Trans>
Connect {{ appName }} collections to Slack channels. Messages will
@@ -144,8 +190,12 @@ function Slack() {
actions={
<SlackButton
scopes={["incoming-webhook"]}
redirectUri={`${env.URL}/auth/slack.post`}
state={collection.id}
redirectUri={SlackUtils.connectUrl()}
state={SlackUtils.createState(
team.id,
IntegrationType.Post,
{ collectionId: collection.id }
)}
label={t("Connect")}
/>
}
@@ -154,14 +204,6 @@ function Slack() {
})}
</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>
);
@@ -172,6 +214,7 @@ const Code = styled.code`
margin: 0 2px;
background: ${(props) => props.theme.codeBackground};
border-radius: 4px;
font-size: 80%;
`;
export default observer(Slack);

View File

@@ -9,7 +9,7 @@ import { s } from "@shared/styles";
import { IntegrationType } from "@shared/types";
import Collection from "~/models/Collection";
import Integration from "~/models/Integration";
import Button from "~/components/Button";
import { ConnectedButton } from "~/scenes/Settings/components/ConnectedButton";
import ButtonLink from "~/components/ButtonLink";
import Flex from "~/components/Flex";
import CollectionIcon from "~/components/Icons/CollectionIcon";
@@ -100,9 +100,12 @@ function SlackListItem({ integration, collection }: Props) {
</>
}
actions={
<Button onClick={integration.delete} neutral>
{t("Disconnect")}
</Button>
<ConnectedButton
onClick={integration.delete}
confirmationMessage={t(
"This will prevent any future updates from being posted to this Slack channel. Are you sure?"
)}
/>
}
/>
);