Skip to content

Commit 710d6ec

Browse files
committed
feat(webapp): add triggered via field to deployment details page
Display the deployment trigger source (CLI, CI/CD, Dashboard, GitHub Integration) with appropriate icons on the deployment details page. The triggeredVia field was already in the database but not displayed.
1 parent 7d29f5a commit 710d6ec

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ export class DeploymentPresenter {
156156
},
157157
},
158158
buildServerMetadata: true,
159+
triggeredVia: true,
159160
},
160161
});
161162

@@ -225,6 +226,7 @@ export class DeploymentPresenter {
225226
isBuilt: !!deployment.builtAt,
226227
type: deployment.type,
227228
git: gitMetadata,
229+
triggeredVia: deployment.triggeredVia,
228230
},
229231
};
230232
}

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

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,16 @@ import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
33
import { typedjson, useTypedLoaderData } from "remix-typedjson";
44
import { useEffect, useState, useRef, useCallback } from "react";
55
import { S2, S2Error } from "@s2-dev/streamstore";
6-
import { Clipboard, ClipboardCheck, ChevronDown, ChevronUp } from "lucide-react";
6+
import {
7+
Clipboard,
8+
ClipboardCheck,
9+
ChevronDown,
10+
ChevronUp,
11+
TerminalSquareIcon,
12+
LayoutDashboardIcon,
13+
GitBranchIcon,
14+
ServerIcon,
15+
} from "lucide-react";
716
import { ExitIcon } from "~/assets/icons/ExitIcon";
817
import { GitMetadata } from "~/components/GitMetadata";
918
import { RuntimeIcon } from "~/components/RuntimeIcon";
@@ -73,6 +82,90 @@ type LogEntry = {
7382
level: "info" | "error" | "warn" | "debug";
7483
};
7584

85+
function getTriggeredViaDisplay(triggeredVia: string | null | undefined): {
86+
icon: React.ReactNode;
87+
label: string;
88+
} | null {
89+
if (!triggeredVia) return null;
90+
91+
const iconClass = "size-4 text-text-dimmed";
92+
93+
switch (triggeredVia) {
94+
case "cli:manual":
95+
return {
96+
icon: <TerminalSquareIcon className={iconClass} />,
97+
label: "CLI (Manual)",
98+
};
99+
case "cli:github_actions":
100+
return {
101+
icon: <GitBranchIcon className={iconClass} />,
102+
label: "CLI (GitHub Actions)",
103+
};
104+
case "cli:gitlab_ci":
105+
return {
106+
icon: <ServerIcon className={iconClass} />,
107+
label: "CLI (GitLab CI)",
108+
};
109+
case "cli:circleci":
110+
return {
111+
icon: <ServerIcon className={iconClass} />,
112+
label: "CLI (CircleCI)",
113+
};
114+
case "cli:jenkins":
115+
return {
116+
icon: <ServerIcon className={iconClass} />,
117+
label: "CLI (Jenkins)",
118+
};
119+
case "cli:azure_pipelines":
120+
return {
121+
icon: <ServerIcon className={iconClass} />,
122+
label: "CLI (Azure Pipelines)",
123+
};
124+
case "cli:bitbucket_pipelines":
125+
return {
126+
icon: <ServerIcon className={iconClass} />,
127+
label: "CLI (Bitbucket Pipelines)",
128+
};
129+
case "cli:travis_ci":
130+
return {
131+
icon: <ServerIcon className={iconClass} />,
132+
label: "CLI (Travis CI)",
133+
};
134+
case "cli:buildkite":
135+
return {
136+
icon: <ServerIcon className={iconClass} />,
137+
label: "CLI (Buildkite)",
138+
};
139+
case "cli:ci_other":
140+
return {
141+
icon: <ServerIcon className={iconClass} />,
142+
label: "CLI (CI)",
143+
};
144+
case "git_integration:github":
145+
return {
146+
icon: <GitBranchIcon className={iconClass} />,
147+
label: "GitHub Integration",
148+
};
149+
case "dashboard":
150+
return {
151+
icon: <LayoutDashboardIcon className={iconClass} />,
152+
label: "Dashboard",
153+
};
154+
default:
155+
// Handle any unknown values gracefully
156+
if (triggeredVia.startsWith("cli:")) {
157+
return {
158+
icon: <TerminalSquareIcon className={iconClass} />,
159+
label: `CLI (${triggeredVia.replace("cli:", "")})`,
160+
};
161+
}
162+
return {
163+
icon: <ServerIcon className={iconClass} />,
164+
label: triggeredVia,
165+
};
166+
}
167+
}
168+
76169
export default function Page() {
77170
const { deployment, eventStream } = useTypedLoaderData<typeof loader>();
78171
const organization = useOrganization();
@@ -408,6 +501,21 @@ export default function Page() {
408501
)}
409502
</Property.Value>
410503
</Property.Item>
504+
<Property.Item>
505+
<Property.Label>Triggered via</Property.Label>
506+
<Property.Value>
507+
{(() => {
508+
const display = getTriggeredViaDisplay(deployment.triggeredVia);
509+
if (!display) return "–";
510+
return (
511+
<span className="flex items-center gap-1.5">
512+
{display.icon}
513+
{display.label}
514+
</span>
515+
);
516+
})()}
517+
</Property.Value>
518+
</Property.Item>
411519
</Property.Table>
412520
</div>
413521

0 commit comments

Comments
 (0)