mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 16:16:21 -06:00
fix: Slack integration pagination issue (#2733)
This commit is contained in:
committed by
GitHub
parent
c8aece8003
commit
7b4db30efd
@@ -22,7 +22,8 @@ export const metadata = {
|
||||
The slack integration allows you to automatically send responses to a Slack channel of your choice.
|
||||
|
||||
<Note>
|
||||
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow the guides [here](/self-hosting/integrations) to configure integrations on your self-hosted instance.
|
||||
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow
|
||||
the guides [here](/self-hosting/integrations) to configure integrations on your self-hosted instance.
|
||||
</Note>
|
||||
|
||||
## Formbricks Cloud
|
||||
|
||||
@@ -171,7 +171,7 @@ export const AddChannelMappingModal = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal open={open} setOpen={setOpenWithStates} noPadding closeOnOutsideClick={false}>
|
||||
<Modal open={open} setOpen={setOpenWithStates} noPadding closeOnOutsideClick={true}>
|
||||
<div className="flex h-full flex-col rounded-lg">
|
||||
<div className="rounded-t-lg bg-slate-100">
|
||||
<div className="flex w-full items-center justify-between p-6">
|
||||
|
||||
@@ -7,32 +7,51 @@ import { TIntegrationSlack, TIntegrationSlackCredential } from "@formbricks/type
|
||||
import { deleteIntegration, getIntegrationByType } from "../integration/service";
|
||||
|
||||
export const fetchChannels = async (slackIntegration: TIntegration): Promise<TIntegrationItem[]> => {
|
||||
const response = await fetch("https://slack.com/api/conversations.list", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${slackIntegration.config.key.access_token}`,
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
});
|
||||
let channels: TIntegrationItem[] = [];
|
||||
// `nextCursor` is a pagination token returned by the Slack API. It indicates the presence of additional pages of data.
|
||||
// When `nextCursor` is not empty, it should be included in subsequent requests to fetch the next page of data.
|
||||
let nextCursor: string | undefined = undefined;
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.ok) {
|
||||
if (data.error === "token_expired") {
|
||||
// temporary fix to reset integration if token rotation is enabled
|
||||
await deleteIntegration(slackIntegration.id);
|
||||
do {
|
||||
const url = new URL("https://slack.com/api/conversations.list");
|
||||
url.searchParams.append("limit", "200");
|
||||
if (nextCursor) {
|
||||
url.searchParams.append("cursor", nextCursor);
|
||||
}
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
return data.channels.map((channel: { name: string; id: string }) => ({
|
||||
name: channel.name,
|
||||
id: channel.id,
|
||||
}));
|
||||
const response = await fetch(url.toString(), {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${slackIntegration.config.key.access_token}`,
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.ok) {
|
||||
if (data.error === "token_expired") {
|
||||
// Temporary fix to reset integration if token rotation is enabled
|
||||
await deleteIntegration(slackIntegration.id);
|
||||
}
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
channels = channels.concat(
|
||||
data.channels.map((channel: { name: string; id: string }) => ({
|
||||
name: channel.name,
|
||||
id: channel.id,
|
||||
}))
|
||||
);
|
||||
|
||||
nextCursor = data.response_metadata?.next_cursor;
|
||||
} while (nextCursor);
|
||||
|
||||
return channels;
|
||||
};
|
||||
|
||||
export const getSlackChannels = async (environmentId: string): Promise<TIntegrationItem[]> => {
|
||||
|
||||
@@ -51,10 +51,11 @@ export const DropdownSelector = ({
|
||||
{!disabled && (
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuContent
|
||||
className="z-50 max-h-64 min-w-[220px] overflow-auto rounded-md bg-white text-sm text-slate-800 shadow-md"
|
||||
className="z-50 max-h-64 min-w-[220px] max-w-[90%] overflow-auto rounded-md bg-white text-sm text-slate-800 shadow-md"
|
||||
align="start">
|
||||
{items &&
|
||||
items.map((item) => (
|
||||
{items
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((item) => (
|
||||
<DropdownMenuItem
|
||||
key={item.id}
|
||||
className="flex cursor-pointer items-center p-3 hover:bg-slate-100 hover:outline-none data-[disabled]:cursor-default data-[disabled]:opacity-50"
|
||||
|
||||
Reference in New Issue
Block a user