refactor: add icon support for deployments and services in UI components

This commit is contained in:
Mauricio Siu
2026-08-11 02:01:21 -06:00
parent 1617d07fbd
commit c6c259f926
3 changed files with 35 additions and 11 deletions
@@ -14,10 +14,11 @@ import {
import type { inferRouterOutputs } from "@trpc/server";
import {
ArrowUpDown,
Boxes,
ChevronLeft,
ChevronRight,
CircuitBoard,
ExternalLink,
GlobeIcon,
Loader2,
Rocket,
Server,
@@ -71,6 +72,7 @@ function getServiceInfo(d: DeploymentRow) {
return {
type: "Application" as const,
name: app.name,
icon: app.icon,
projectId: app.environment.project.projectId,
environmentId: app.environment.environmentId,
projectName: app.environment.project.name,
@@ -83,6 +85,7 @@ function getServiceInfo(d: DeploymentRow) {
return {
type: "Compose" as const,
name: comp.name,
icon: comp.icon,
projectId: comp.environment.project.projectId,
environmentId: comp.environment.environmentId,
projectName: comp.environment.project.name,
@@ -175,10 +178,16 @@ export function ShowDeploymentsTable() {
if (!info) return <span className="text-muted-foreground">—</span>;
return (
<div className="flex items-center gap-2">
{info.type === "Application" ? (
<Rocket className="size-4 text-muted-foreground shrink-0" />
{info.icon ? (
<img
src={info.icon}
alt={info.name}
className="size-4 object-contain shrink-0"
/>
) : info.type === "Application" ? (
<GlobeIcon className="size-4 text-muted-foreground shrink-0" />
) : (
<Boxes className="size-4 text-muted-foreground shrink-0" />
<CircuitBoard className="size-4 text-muted-foreground shrink-0" />
)}
<div className="flex flex-col min-w-0">
<span className="font-medium truncate">{info.name}</span>
@@ -45,10 +45,12 @@ type ServiceItem = {
id: string;
name: string;
type: ServiceType;
icon: string | null;
};
type NamedService = {
name: string;
icon?: string | null;
};
type EnvironmentServiceCollections = {
@@ -116,8 +118,20 @@ const getStringQueryParam = (value: string | string[] | undefined) =>
const includesSearch = (value: string | null | undefined, search: string) =>
value?.toLowerCase().includes(search.toLowerCase()) ?? false;
const getServiceIcon = (type: ServiceType, className = "size-4") => {
const Icon = SERVICE_ICONS[type];
const getServiceIcon = (
service: Pick<ServiceItem, "type" | "icon">,
className = "size-4",
) => {
if (service.icon) {
return (
<img
src={service.icon}
alt=""
className={`${className} object-contain shrink-0`}
/>
);
}
const Icon = SERVICE_ICONS[service.type];
return <Icon className={className} />;
};
@@ -127,7 +141,7 @@ const countEnvironmentServices = (environment: ServiceCollections): number =>
0,
);
const mapServices = <T extends { name: string }>(
const mapServices = <T extends NamedService>(
items: readonly T[],
getId: (item: T) => string,
type: ServiceType,
@@ -136,6 +150,7 @@ const mapServices = <T extends { name: string }>(
id: getId(item),
name: item.name,
type,
icon: item.icon ?? null,
}));
const extractServicesFromEnvironment = (
@@ -550,7 +565,7 @@ export const AdvanceBreadcrumb = () => {
aria-expanded={serviceOpen}
className="h-auto px-2 py-1.5 hover:bg-accent gap-2"
>
{getServiceIcon(currentService.type)}
{getServiceIcon(currentService)}
<span className="font-medium max-w-[50px] md:max-w-[150px] truncate">
{currentService.name}
</span>
@@ -589,7 +604,7 @@ export const AdvanceBreadcrumb = () => {
>
<div className="flex items-center gap-3">
<div className="flex items-center justify-center size-8 rounded-md bg-muted">
{getServiceIcon(service.type)}
{getServiceIcon(service)}
</div>
<div className="flex flex-col">
<span className="font-medium">
+2 -2
View File
@@ -802,7 +802,7 @@ export const findAllDeploymentsByComposeId = async (composeId: string) => {
const centralizedDeploymentsWith = {
application: {
columns: { applicationId: true, name: true, appName: true },
columns: { applicationId: true, name: true, appName: true, icon: true },
with: {
environment: {
columns: { environmentId: true, name: true },
@@ -821,7 +821,7 @@ const centralizedDeploymentsWith = {
},
},
compose: {
columns: { composeId: true, name: true, appName: true },
columns: { composeId: true, name: true, appName: true, icon: true },
with: {
environment: {
columns: { environmentId: true, name: true },