From 6f9929b79ca4dd6de31189d6a49bbdd2e9674e17 Mon Sep 17 00:00:00 2001 From: Aditya Choudhari Date: Wed, 12 Mar 2025 11:21:35 -0700 Subject: [PATCH] fix: Optimize job fetching in release cell --- .../(sidebar)/DeploymentPageContent.tsx | 2 +- .../environment-cell/ReleaseInfo.tsx | 75 +++++++------------ packages/api/src/router/job.ts | 40 ++++++++++ 3 files changed, 70 insertions(+), 47 deletions(-) diff --git a/apps/webservice/src/app/[workspaceSlug]/(appv2)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(sidebar)/DeploymentPageContent.tsx b/apps/webservice/src/app/[workspaceSlug]/(appv2)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(sidebar)/DeploymentPageContent.tsx index 28a09cb91..a436d18ad 100644 --- a/apps/webservice/src/app/[workspaceSlug]/(appv2)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(sidebar)/DeploymentPageContent.tsx +++ b/apps/webservice/src/app/[workspaceSlug]/(appv2)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(sidebar)/DeploymentPageContent.tsx @@ -341,7 +341,7 @@ export const DeploymentPageContent: React.FC = ({ {environments.map((env) => ( e.stopPropagation()} key={env.id} > diff --git a/apps/webservice/src/app/[workspaceSlug]/(appv2)/(deploy)/_components/deployments/environment-cell/ReleaseInfo.tsx b/apps/webservice/src/app/[workspaceSlug]/(appv2)/(deploy)/_components/deployments/environment-cell/ReleaseInfo.tsx index 525b63580..a8c23e1dd 100644 --- a/apps/webservice/src/app/[workspaceSlug]/(appv2)/(deploy)/_components/deployments/environment-cell/ReleaseInfo.tsx +++ b/apps/webservice/src/app/[workspaceSlug]/(appv2)/(deploy)/_components/deployments/environment-cell/ReleaseInfo.tsx @@ -1,4 +1,5 @@ -import type { JobCondition, JobStatusType } from "@ctrlplane/validators/jobs"; +import type * as SCHEMA from "@ctrlplane/db/schema"; +import type { JobStatusType } from "@ctrlplane/validators/jobs"; import Link from "next/link"; import { IconCircle, IconLoader2 } from "@tabler/icons-react"; import { capitalCase } from "change-case"; @@ -12,18 +13,14 @@ import { HoverCardContent, HoverCardTrigger, } from "@ctrlplane/ui/hover-card"; +import { Skeleton } from "@ctrlplane/ui/skeleton"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@ctrlplane/ui/tooltip"; -import { - ColumnOperator, - ComparisonOperator, - FilterType, -} from "@ctrlplane/validators/conditions"; -import { activeStatusType, JobFilterType } from "@ctrlplane/validators/jobs"; +import { activeStatusType } from "@ctrlplane/validators/jobs"; import { DeploymentBarChart } from "~/app/[workspaceSlug]/(appv2)/(deploy)/_components/deployments/charts/DeploymentBarChart"; import { ReleaseDropdownMenu } from "~/app/[workspaceSlug]/(appv2)/(deploy)/_components/release/ReleaseDropdownMenu"; @@ -34,6 +31,26 @@ import { import { api } from "~/trpc/react"; import { StatusIcon } from "./StatusIcon"; +const Message: React.FC<{ + trigger: SCHEMA.ReleaseJobTrigger & { job: SCHEMA.Job }; +}> = ({ trigger }) => { + const { data, isLoading } = api.resource.byId.useQuery(trigger.resourceId); + + return ( +
+
+ + {isLoading ? : data?.name} +
+ {trigger.job.message != null && trigger.job.message !== "" && ( +
+ {capitalCase(trigger.job.status)} — {trigger.job.message} +
+ )} +
+ ); +}; + export const Release: React.FC<{ name: string; version: string; @@ -57,35 +74,14 @@ export const Release: React.FC<{ statuses, } = props; - const isSameRelease: JobCondition = { - type: JobFilterType.Release, - operator: ColumnOperator.Equals, - value: releaseId, - }; - - const isSameEnvironment: JobCondition = { - type: JobFilterType.Environment, - operator: ColumnOperator.Equals, - value: environment.id, - }; - - const filter: JobCondition = { - type: FilterType.Comparison, - operator: ComparisonOperator.And, - conditions: [isSameRelease, isSameEnvironment], - }; - - const workspaceId = api.workspace.bySlug.useQuery(workspaceSlug); - - const releaseJobTriggersQ = api.job.config.byWorkspaceId.list.useQuery( - { workspaceId: workspaceId.data?.id ?? "", filter }, - { enabled: isPresent(workspaceId.data?.id) }, + const releaseJobTriggersQ = api.job.config.byReleaseAndEnvironmentId.useQuery( + { releaseId, environmentId: environment.id }, ); const releaseJobTriggers = releaseJobTriggersQ.data ?? []; const latestJobsByResource = _.chain(releaseJobTriggers) - .groupBy((r) => r.resource.id) + .groupBy((r) => r.resourceId) .mapValues((triggers) => _.maxBy(triggers, (t) => new Date(t.job.createdAt)), ) @@ -103,7 +99,7 @@ export const Release: React.FC<{ .value(); const configuredWithMessages = releaseJobTriggers.filter((d) => - [d.job, d.resource, d.job.message].every(isPresent), + isPresent(d.job.message), ); return ( @@ -148,20 +144,7 @@ export const Release: React.FC<{ {configuredWithMessages.length > 0 && ( {configuredWithMessages.map((d) => ( -
-
- - {d.resource.name} -
- {d.job.message != null && d.job.message !== "" && ( -
- {capitalCase(d.job.status)} — {d.job.message} -
- )} -
+ ))}
)} diff --git a/packages/api/src/router/job.ts b/packages/api/src/router/job.ts index a04ba1997..96ae58462 100644 --- a/packages/api/src/router/job.ts +++ b/packages/api/src/router/job.ts @@ -432,6 +432,46 @@ const releaseJobTriggerRouter = createTRPCRouter({ .then(processReleaseJobTriggerWithAdditionalDataRows), ), + byReleaseAndEnvironmentId: protectedProcedure + .input( + z.object({ + releaseId: z.string().uuid(), + environmentId: z.string().uuid(), + limit: z.number().int().nonnegative().max(1000).default(500), + offset: z.number().int().nonnegative().default(0), + }), + ) + .meta({ + authorizationCheck: ({ canUser, input }) => + canUser + .perform(Permission.JobList) + .on({ type: "environment", id: input.environmentId }), + }) + .query(({ ctx, input }) => + ctx.db + .select() + .from(schema.releaseJobTrigger) + .innerJoin( + schema.job, + eq(schema.releaseJobTrigger.jobId, schema.job.id), + ) + .where( + and( + eq(schema.releaseJobTrigger.releaseId, input.releaseId), + eq(schema.releaseJobTrigger.environmentId, input.environmentId), + ), + ) + .orderBy(desc(schema.job.createdAt)) + .limit(input.limit) + .offset(input.offset) + .then((rows) => + rows.map((row) => ({ + ...row.release_job_trigger, + job: row.job, + })), + ), + ), + byId: protectedProcedure .input(z.string().uuid()) .meta({