Skip to content

Commit b8f4fba

Browse files
committed
Fix alert creation bug related to the Slack integration
1 parent 26aad58 commit b8f4fba

File tree

4 files changed

+93
-42
lines changed

4 files changed

+93
-42
lines changed

apps/webapp/app/presenters/v3/NewAlertChannelPresenter.server.ts

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import {
2-
AuthenticatableIntegration,
2+
type AuthenticatableIntegration,
33
OrgIntegrationRepository,
44
} from "~/models/orgIntegration.server";
5-
import { logger } from "~/services/logger.server";
65
import { BasePresenter } from "./basePresenter.server";
7-
import { WebClient } from "@slack/web-api";
6+
import { type WebClient } from "@slack/web-api";
7+
import { tryCatch } from "@trigger.dev/core";
8+
import { logger } from "~/services/logger.server";
89

910
export class NewAlertChannelPresenter extends BasePresenter {
1011
public async call(projectId: string) {
@@ -30,42 +31,58 @@ export class NewAlertChannelPresenter extends BasePresenter {
3031

3132
// If there is a slack integration, then we need to get a list of Slack Channels
3233
if (slackIntegration) {
33-
const channels = await getSlackChannelsForToken(slackIntegration);
34+
const [error, channels] = await tryCatch(getSlackChannelsForToken(slackIntegration));
35+
36+
if (error) {
37+
if (isSlackError(error) && error.data.error === "token_revoked") {
38+
return {
39+
slack: {
40+
status: "ACCESS_REVOKED" as const,
41+
},
42+
};
43+
}
44+
45+
logger.error("Failed fetching Slack channels for creating alerts", {
46+
error,
47+
slackIntegrationId: slackIntegration.id,
48+
});
49+
50+
return {
51+
slack: {
52+
status: "FAILED_FETCHING_CHANNELS" as const,
53+
},
54+
};
55+
}
3456

3557
return {
3658
slack: {
3759
status: "READY" as const,
38-
channels,
60+
channels: channels ?? [],
3961
integrationId: slackIntegration.id,
4062
},
4163
};
42-
} else {
43-
if (OrgIntegrationRepository.isSlackSupported) {
44-
return {
45-
slack: {
46-
status: "NOT_CONFIGURED" as const,
47-
},
48-
};
49-
} else {
50-
return {
51-
slack: {
52-
status: "NOT_AVAILABLE" as const,
53-
},
54-
};
55-
}
5664
}
65+
66+
if (OrgIntegrationRepository.isSlackSupported) {
67+
return {
68+
slack: {
69+
status: "NOT_CONFIGURED" as const,
70+
},
71+
};
72+
}
73+
74+
return {
75+
slack: {
76+
status: "NOT_AVAILABLE" as const,
77+
},
78+
};
5779
}
5880
}
5981

6082
async function getSlackChannelsForToken(integration: AuthenticatableIntegration) {
6183
const client = await OrgIntegrationRepository.getAuthenticatedClientForIntegration(integration);
62-
6384
const channels = await getAllSlackConversations(client);
6485

65-
logger.debug("Received a list of slack conversations", {
66-
channels,
67-
});
68-
6986
return (channels ?? [])
7087
.filter((channel) => !channel.is_archived)
7188
.filter((channel) => channel.is_channel)
@@ -100,3 +117,15 @@ async function getAllSlackConversations(client: WebClient) {
100117

101118
return channels;
102119
}
120+
121+
function isSlackError(obj: unknown): obj is { data: { error: string } } {
122+
return Boolean(
123+
typeof obj === "object" &&
124+
obj !== null &&
125+
"data" in obj &&
126+
typeof obj.data === "object" &&
127+
obj.data !== null &&
128+
"error" in obj.data &&
129+
typeof obj.data.error === "string"
130+
);
131+
}
Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
22
import { prisma } from "~/db.server";
3-
import { env } from "~/env.server";
43
import { redirectWithSuccessMessage } from "~/models/message.server";
54
import { OrgIntegrationRepository } from "~/models/orgIntegration.server";
65
import { findProjectBySlug } from "~/models/project.server";
76
import { requireUserId } from "~/services/session.server";
87
import {
98
EnvironmentParamSchema,
10-
ProjectParamSchema,
119
v3NewProjectAlertPath,
1210
v3NewProjectAlertPathConnectToSlackPath,
1311
} from "~/utils/pathBuilder";
@@ -16,6 +14,9 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
1614
const userId = await requireUserId(request);
1715
const { organizationSlug, projectParam, envParam } = EnvironmentParamSchema.parse(params);
1816

17+
const url = new URL(request.url);
18+
const shouldReinstall = url.searchParams.get("reinstall") === "true";
19+
1920
const project = await findProjectBySlug(organizationSlug, projectParam, userId);
2021

2122
if (!project) {
@@ -30,23 +31,24 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
3031
},
3132
});
3233

33-
if (integration) {
34+
// If integration exists and we're not reinstalling, redirect back to alerts
35+
if (integration && !shouldReinstall) {
3436
return redirectWithSuccessMessage(
3537
`${v3NewProjectAlertPath({ slug: organizationSlug }, project, {
3638
slug: envParam,
3739
})}?option=slack`,
3840
request,
3941
"Successfully connected your Slack workspace"
4042
);
41-
} else {
42-
// Redirect to Slack
43-
return await OrgIntegrationRepository.redirectToAuthService(
44-
"SLACK",
45-
project.organizationId,
46-
request,
47-
v3NewProjectAlertPathConnectToSlackPath({ slug: organizationSlug }, project, {
48-
slug: envParam,
49-
})
50-
);
5143
}
44+
45+
// Redirect to Slack for new installation or reinstallation
46+
return await OrgIntegrationRepository.redirectToAuthService(
47+
"SLACK",
48+
project.organizationId,
49+
request,
50+
v3NewProjectAlertPathConnectToSlackPath({ slug: organizationSlug }, project, {
51+
slug: envParam,
52+
})
53+
);
5254
}

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.alerts.new/route.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,31 @@ export default function Page() {
356356
<SlackIcon className="size-5" /> Connect to Slack
357357
</span>
358358
</LinkButton>
359+
) : slack.status === "ACCESS_REVOKED" ? (
360+
<div className="flex flex-col gap-4">
361+
<Callout variant="info">
362+
The Slack integration in your workspace has been revoked. Please re-connect
363+
your Slack workspace.
364+
</Callout>
365+
<LinkButton
366+
variant="tertiary/large"
367+
to={{
368+
pathname: "connect-to-slack",
369+
search: "?reinstall=true",
370+
}}
371+
fullWidth
372+
>
373+
<span className="flex items-center gap-2 text-text-bright">
374+
<SlackIcon className="size-5" /> Connect to Slack
375+
</span>
376+
</LinkButton>
377+
</div>
378+
) : slack.status === "FAILED_FETCHING_CHANNELS" ? (
379+
<div className="flex flex-col gap-4">
380+
<Callout variant="warning">
381+
Failed loading channels from Slack. Please try again later.
382+
</Callout>
383+
</div>
359384
) : (
360385
<Callout variant="warning">
361386
Slack integration is not available. Please contact your organization

apps/webapp/app/v3/services/createOrgIntegration.server.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import { OrganizationIntegration } from "@trigger.dev/database";
22
import { BaseService } from "./baseService.server";
3-
import { WebClient } from "@slack/web-api";
4-
import { env } from "~/env.server";
5-
import { $transaction } from "~/db.server";
6-
import { getSecretStore } from "~/services/secrets/secretStore.server";
7-
import { generateFriendlyId } from "../friendlyIdentifiers";
83
import { OrgIntegrationRepository } from "~/models/orgIntegration.server";
94

105
export class CreateOrgIntegrationService extends BaseService {

0 commit comments

Comments
 (0)