feat(webapp): add triggered via field to deployment details page (#2850)

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.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Saadi Myftija
2026-02-05 15:24:23 +01:00
committed by GitHub
parent c55af7bead
commit 283f88b203
2 changed files with 111 additions and 1 deletions
@@ -156,6 +156,7 @@ export class DeploymentPresenter {
},
},
buildServerMetadata: true,
triggeredVia: true,
},
});
@@ -225,6 +226,7 @@ export class DeploymentPresenter {
isBuilt: !!deployment.builtAt,
type: deployment.type,
git: gitMetadata,
triggeredVia: deployment.triggeredVia,
},
};
}
@@ -3,7 +3,16 @@ import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import { useEffect, useState, useRef, useCallback } from "react";
import { S2, S2Error } from "@s2-dev/streamstore";
import { Clipboard, ClipboardCheck, ChevronDown, ChevronUp } from "lucide-react";
import {
Clipboard,
ClipboardCheck,
ChevronDown,
ChevronUp,
TerminalSquareIcon,
LayoutDashboardIcon,
GitBranchIcon,
ServerIcon,
} from "lucide-react";
import { ExitIcon } from "~/assets/icons/ExitIcon";
import { GitMetadata } from "~/components/GitMetadata";
import { RuntimeIcon } from "~/components/RuntimeIcon";
@@ -73,6 +82,90 @@ type LogEntry = {
level: "info" | "error" | "warn" | "debug";
};
function getTriggeredViaDisplay(triggeredVia: string | null | undefined): {
icon: React.ReactNode;
label: string;
} | null {
if (!triggeredVia) return null;
const iconClass = "size-4 text-text-dimmed";
switch (triggeredVia) {
case "cli:manual":
return {
icon: <TerminalSquareIcon className={iconClass} />,
label: "CLI (Manual)",
};
case "cli:github_actions":
return {
icon: <GitBranchIcon className={iconClass} />,
label: "CLI (GitHub Actions)",
};
case "cli:gitlab_ci":
return {
icon: <ServerIcon className={iconClass} />,
label: "CLI (GitLab CI)",
};
case "cli:circleci":
return {
icon: <ServerIcon className={iconClass} />,
label: "CLI (CircleCI)",
};
case "cli:jenkins":
return {
icon: <ServerIcon className={iconClass} />,
label: "CLI (Jenkins)",
};
case "cli:azure_pipelines":
return {
icon: <ServerIcon className={iconClass} />,
label: "CLI (Azure Pipelines)",
};
case "cli:bitbucket_pipelines":
return {
icon: <ServerIcon className={iconClass} />,
label: "CLI (Bitbucket Pipelines)",
};
case "cli:travis_ci":
return {
icon: <ServerIcon className={iconClass} />,
label: "CLI (Travis CI)",
};
case "cli:buildkite":
return {
icon: <ServerIcon className={iconClass} />,
label: "CLI (Buildkite)",
};
case "cli:ci_other":
return {
icon: <ServerIcon className={iconClass} />,
label: "CLI (CI)",
};
case "git_integration:github":
return {
icon: <GitBranchIcon className={iconClass} />,
label: "GitHub Integration",
};
case "dashboard":
return {
icon: <LayoutDashboardIcon className={iconClass} />,
label: "Dashboard",
};
default:
// Handle any unknown values gracefully
if (triggeredVia.startsWith("cli:")) {
return {
icon: <TerminalSquareIcon className={iconClass} />,
label: `CLI (${triggeredVia.replace("cli:", "")})`,
};
}
return {
icon: <ServerIcon className={iconClass} />,
label: triggeredVia,
};
}
}
export default function Page() {
const { deployment, eventStream } = useTypedLoaderData<typeof loader>();
const organization = useOrganization();
@@ -408,6 +501,21 @@ export default function Page() {
)}
</Property.Value>
</Property.Item>
<Property.Item>
<Property.Label>Triggered via</Property.Label>
<Property.Value>
{(() => {
const display = getTriggeredViaDisplay(deployment.triggeredVia);
if (!display) return "";
return (
<span className="flex items-center gap-1.5">
{display.icon}
{display.label}
</span>
);
})()}
</Property.Value>
</Property.Item>
</Property.Table>
</div>