Skip to content

Commit

Permalink
fix: Optimize release list query and use lazy loading for release cel…
Browse files Browse the repository at this point in the history
…ls (#269)
  • Loading branch information
adityachoudhari26 authored Dec 21, 2024
1 parent cc5ef4b commit d242177
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 350 deletions.
1 change: 1 addition & 0 deletions apps/webservice/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"react-dom": "catalog:react18",
"react-grid-layout": "^1.4.4",
"react-hook-form": "^7.51.4",
"react-intersection-observer": "^9.14.0",
"react-use": "^17.5.0",
"react-use-websocket": "^4.10.1",
"reactflow": "^11.11.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { RouterOutputs } from "@ctrlplane/api";
import type * as SCHEMA from "@ctrlplane/db/schema";
import type { JobStatus } from "@ctrlplane/validators/jobs";
import type { JobCondition, JobStatus } from "@ctrlplane/validators/jobs";
import { useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { IconChevronRight, IconDots } from "@tabler/icons-react";
Expand All @@ -14,9 +14,15 @@ import {
CollapsibleTrigger,
} from "@ctrlplane/ui/collapsible";
import { TableCell, TableRow } from "@ctrlplane/ui/table";
import { ReservedMetadataKey } from "@ctrlplane/validators/conditions";
import { JobStatusReadable } from "@ctrlplane/validators/jobs";
import {
ColumnOperator,
ComparisonOperator,
FilterType,
ReservedMetadataKey,
} from "@ctrlplane/validators/conditions";
import { JobFilterType, JobStatusReadable } from "@ctrlplane/validators/jobs";

import { api } from "~/trpc/react";
import { JobDropdownMenu } from "../../systems/[systemSlug]/deployments/[deploymentSlug]/releases/[versionId]/JobDropdownMenu";
import { DeployButton } from "../../systems/[systemSlug]/deployments/DeployButton";
import { JobLinksCell } from "../job-table/JobLinksCell";
Expand Down Expand Up @@ -258,9 +264,43 @@ export const ReleaseRows: React.FC<ReleaseRowsProps> = ({
deployment,
resource,
}) => {
const { workspaceSlug } = useParams<{ workspaceSlug: string }>();
const { data: workspace } = api.workspace.bySlug.useQuery(workspaceSlug);

const [open, setOpen] = useState(false);
const { releaseJobTriggers } = release;
const hasOtherReleaseJobTriggers = releaseJobTriggers.length > 1;

const isSameRelease: JobCondition = {
type: JobFilterType.Release,
operator: ColumnOperator.Equals,
value: release.id,
};

const isSameResource: JobCondition = {
type: JobFilterType.JobResource,
operator: ColumnOperator.Equals,
value: resource.id,
};

const isSameEnvironment: JobCondition = {
type: JobFilterType.Environment,
operator: ColumnOperator.Equals,
value: environment.id,
};

const filter: JobCondition = {
type: FilterType.Comparison,
operator: ComparisonOperator.And,
conditions: [isSameRelease, isSameResource, isSameEnvironment],
};

const { data: releaseJobTriggers } =
api.job.config.byWorkspaceId.list.useQuery(
{ workspaceId: workspace?.id ?? "", filter },
{ enabled: workspace != null },
);

const hasOtherReleaseJobTriggers =
releaseJobTriggers != null && releaseJobTriggers.length > 1;

return (
<Collapsible asChild open={open} onOpenChange={setOpen}>
Expand All @@ -270,14 +310,14 @@ export const ReleaseRows: React.FC<ReleaseRowsProps> = ({
environment={environment}
deployment={deployment}
resource={resource}
releaseJobTrigger={releaseJobTriggers[0]}
releaseJobTrigger={releaseJobTriggers?.[0]}
isExpandable={hasOtherReleaseJobTriggers}
isExpanded={open}
key={releaseJobTriggers[0]?.id ?? `${release.id}-parent`}
key={releaseJobTriggers?.[0]?.id ?? `${release.id}-parent`}
/>
<CollapsibleContent asChild>
<>
{releaseJobTriggers.map((trigger, idx) => {
{releaseJobTriggers?.map((trigger, idx) => {
if (idx === 0) return null;
return (
<ReleaseJobTriggerChildRow
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"use client";

import type { RouterOutputs } from "@ctrlplane/api";
import { useParams } from "next/navigation";
import { useInView } from "react-intersection-observer";

import { Button } from "@ctrlplane/ui/button";

import { useReleaseChannelDrawer } from "~/app/[workspaceSlug]/(app)/_components/release-channel-drawer/useReleaseChannelDrawer";
import { api } from "~/trpc/react";
import { DeployButton } from "./DeployButton";
import { Release } from "./TableCells";

type Environment = RouterOutputs["environment"]["bySystemId"][number];
type BlockedEnv = RouterOutputs["release"]["blocked"][number];

type ReleaseEnvironmentCellProps = {
environment: Environment;
deployment: { slug: string; jobAgentId: string | null };
release: { id: string; version: string; createdAt: Date };
blockedEnv?: BlockedEnv;
};

const ReleaseEnvironmentCell: React.FC<ReleaseEnvironmentCellProps> = ({
environment,
deployment,
release,
blockedEnv,
}) => {
const { workspaceSlug, systemSlug } = useParams<{
workspaceSlug: string;
systemSlug: string;
}>();

const { data: statuses, isLoading } =
api.release.status.byEnvironmentId.useQuery(
{ releaseId: release.id, environmentId: environment.id },
{ refetchInterval: 2_000 },
);

const { setReleaseChannelId } = useReleaseChannelDrawer();

if (isLoading)
return <p className="text-xs text-muted-foreground">Loading...</p>;

const hasResources = environment.resources.length > 0;
const isAlreadyDeployed = statuses != null && statuses.length > 0;

const hasJobAgent = deployment.jobAgentId != null;
const isBlockedByReleaseChannel = blockedEnv != null;

const showRelease = isAlreadyDeployed;
const showDeployButton =
!isAlreadyDeployed &&
hasJobAgent &&
hasResources &&
!isBlockedByReleaseChannel;

return (
<>
{showRelease && (
<Release
workspaceSlug={workspaceSlug}
systemSlug={systemSlug}
deploymentSlug={deployment.slug}
releaseId={release.id}
version={release.version}
environment={environment}
name={release.version}
deployedAt={release.createdAt}
statuses={statuses.map((s) => s.job.status)}
/>
)}

{showDeployButton && (
<DeployButton releaseId={release.id} environmentId={environment.id} />
)}

{!isAlreadyDeployed && (
<div className="text-center text-xs text-muted-foreground/70">
{isBlockedByReleaseChannel && (
<>
Blocked by{" "}
<Button
variant="link"
size="sm"
onClick={() =>
setReleaseChannelId(blockedEnv.releaseChannelId ?? null)
}
className="px-0 text-muted-foreground/70"
>
release channel
</Button>
</>
)}
{!isBlockedByReleaseChannel && !hasJobAgent && "No job agent"}
{!isBlockedByReleaseChannel &&
hasJobAgent &&
!hasResources &&
"No resources"}
</div>
)}
</>
);
};

export const LazyReleaseEnvironmentCell: React.FC<
ReleaseEnvironmentCellProps
> = (props) => {
const { ref, inView } = useInView();

return (
<div className="flex w-full items-center justify-center" ref={ref}>
{!inView && <p className="text-xs text-muted-foreground">Loading...</p>}
{inView && <ReleaseEnvironmentCell {...props} />}
</div>
);
};
Loading

0 comments on commit d242177

Please sign in to comment.