Skip to content

Commit 990c6c8

Browse files
committed
feat(webapp): add GitHub onboarding flow to empty Tasks and Deployments pages
- Create new resource route for GitHub settings management with loader and actions - Add GitHubSettingsPresenter to fetch connected repos and installations - Implement GitHubSettingsPanel component for reusable GitHub configuration UI - Refactor project settings page to use shared GitHubSettingsPanel component - Integrate GitHub connection flow into empty state onboarding for Tasks and Deployments - Add support for GitHub repo connection, disconnection, and branch tracking settings - Include redirect URL support for seamless navigation after GitHub actions - Remove duplicate GitHub connection code from project settings route
1 parent ca4d157 commit 990c6c8

File tree

4 files changed

+1030
-673
lines changed

4 files changed

+1030
-673
lines changed

apps/webapp/app/components/BlankStatePanels.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,13 @@ import {
5252
} from "./SetupCommands";
5353
import { StepContentContainer } from "./StepContentContainer";
5454
import { V4Badge } from "./V4Badge";
55-
import { GitHubConnectionPrompt } from "~/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route";
56-
import SegmentedControl from "./primitives/SegmentedControl";
57-
import { useState } from "react";
5855
import {
5956
ClientTabs,
6057
ClientTabsContent,
6158
ClientTabsList,
6259
ClientTabsTrigger,
6360
} from "./primitives/ClientTabs";
61+
import { GitHubSettingsPanel } from "~/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.github";
6462

6563
export function HasNoTasksDev() {
6664
return (
@@ -651,11 +649,11 @@ function DeploymentOnboardingSteps() {
651649
<TextLink to={docsPath("github-integration")}>full guide</TextLink>.
652650
</Paragraph>
653651
<div className="w-fit">
654-
<GitHubConnectionPrompt
655-
gitHubAppInstallations={[]}
652+
<GitHubSettingsPanel
656653
organizationSlug={organization.slug}
657654
projectSlug={project.slug}
658655
environmentSlug={environment.slug}
656+
billingPath={v3BillingPath({ slug: organization.slug })}
659657
/>
660658
</div>
661659
</StepContentContainer>
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { type PrismaClient } from "@trigger.dev/database";
2+
import { err, fromPromise, ok, ResultAsync } from "neverthrow";
3+
import { env } from "~/env.server";
4+
import { BranchTrackingConfigSchema } from "~/v3/github";
5+
import { BasePresenter } from "./basePresenter.server";
6+
7+
type GitHubSettingsOptions = {
8+
projectId: string;
9+
organizationId: string;
10+
};
11+
12+
export class GitHubSettingsPresenter extends BasePresenter {
13+
public call({ projectId, organizationId }: GitHubSettingsOptions) {
14+
const githubAppEnabled = env.GITHUB_APP_ENABLED === "1";
15+
16+
if (!githubAppEnabled) {
17+
return ok({
18+
enabled: false,
19+
connectedRepository: undefined,
20+
installations: undefined,
21+
isPreviewEnvironmentEnabled: undefined,
22+
});
23+
}
24+
25+
const findConnectedGithubRepository = () =>
26+
fromPromise(
27+
(this._replica as PrismaClient).connectedGithubRepository.findFirst({
28+
where: {
29+
projectId,
30+
repository: {
31+
installation: {
32+
deletedAt: null,
33+
suspendedAt: null,
34+
},
35+
},
36+
},
37+
select: {
38+
branchTracking: true,
39+
previewDeploymentsEnabled: true,
40+
createdAt: true,
41+
repository: {
42+
select: {
43+
id: true,
44+
name: true,
45+
fullName: true,
46+
htmlUrl: true,
47+
private: true,
48+
},
49+
},
50+
},
51+
}),
52+
(error) => ({
53+
type: "other" as const,
54+
cause: error,
55+
})
56+
).map((connectedGithubRepository) => {
57+
if (!connectedGithubRepository) {
58+
return undefined;
59+
}
60+
61+
const branchTrackingOrFailure = BranchTrackingConfigSchema.safeParse(
62+
connectedGithubRepository.branchTracking
63+
);
64+
const branchTracking = branchTrackingOrFailure.success
65+
? branchTrackingOrFailure.data
66+
: undefined;
67+
68+
return {
69+
...connectedGithubRepository,
70+
branchTracking,
71+
};
72+
});
73+
74+
const listGithubAppInstallations = () =>
75+
fromPromise(
76+
(this._replica as PrismaClient).githubAppInstallation.findMany({
77+
where: {
78+
organizationId,
79+
deletedAt: null,
80+
suspendedAt: null,
81+
},
82+
select: {
83+
id: true,
84+
accountHandle: true,
85+
targetType: true,
86+
appInstallationId: true,
87+
repositories: {
88+
select: {
89+
id: true,
90+
name: true,
91+
fullName: true,
92+
htmlUrl: true,
93+
private: true,
94+
},
95+
take: 200,
96+
},
97+
},
98+
take: 20,
99+
orderBy: {
100+
createdAt: "desc",
101+
},
102+
}),
103+
(error) => ({
104+
type: "other" as const,
105+
cause: error,
106+
})
107+
);
108+
109+
const isPreviewEnvironmentEnabled = () =>
110+
fromPromise(
111+
(this._replica as PrismaClient).runtimeEnvironment.findFirst({
112+
select: {
113+
id: true,
114+
},
115+
where: {
116+
projectId: projectId,
117+
slug: "preview",
118+
},
119+
}),
120+
(error) => ({
121+
type: "other" as const,
122+
cause: error,
123+
})
124+
).map((previewEnvironment) => previewEnvironment !== null);
125+
126+
return ResultAsync.combine([
127+
isPreviewEnvironmentEnabled(),
128+
findConnectedGithubRepository(),
129+
listGithubAppInstallations(),
130+
]).map(([isPreviewEnvironmentEnabled, connectedGithubRepository, githubAppInstallations]) => ({
131+
enabled: true,
132+
connectedRepository: connectedGithubRepository,
133+
installations: githubAppInstallations,
134+
isPreviewEnvironmentEnabled,
135+
}));
136+
}
137+
}

0 commit comments

Comments
 (0)