diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/ApprovalCheck.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/ApprovalCheck.tsx
deleted file mode 100644
index d04675eb5..000000000
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/ApprovalCheck.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import { Button } from "@ctrlplane/ui/button";
-
-import { ApprovalDialog } from "~/app/[workspaceSlug]/(app)/(deploy)/_components/deployment-version/ApprovalDialog";
-import { api } from "~/trpc/react";
-import { Cancelled, Failing, Loading, Passing, Waiting } from "./StatusIcons";
-
-export const ApprovalCheck: React.FC<{
- policyId: string;
- deploymentVersion: { id: string; tag: string; deploymentId: string };
-}> = ({ policyId, deploymentVersion }) => {
- const approvalStatus =
- api.environment.policy.approval.statusByVersionPolicyId.useQuery({
- policyId,
- versionId: deploymentVersion.id,
- });
-
- if (approvalStatus.isLoading)
- return (
-
- Loading approval status
-
- );
-
- if (approvalStatus.data == null)
- return (
-
- Approval skipped
-
- );
-
- const status = approvalStatus.data.status;
- return (
-
-
- {status === "approved" && (
- <>
-
Approved
- >
- )}
- {status === "rejected" && (
- <>
-
Rejected
- >
- )}
- {status === "pending" && (
- <>
-
Pending approval
- >
- )}
-
-
- {status === "pending" && (
-
-
-
- )}
-
- );
-};
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/FlowNode.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/FlowNode.tsx
deleted file mode 100644
index ac262263f..000000000
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/FlowNode.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import type * as SCHEMA from "@ctrlplane/db/schema";
-import type { NodeProps } from "reactflow";
-import React from "react";
-import { Handle, Position } from "reactflow";
-import colors from "tailwindcss/colors";
-
-import { cn } from "@ctrlplane/ui";
-import { Badge } from "@ctrlplane/ui/badge";
-import { JobStatus } from "@ctrlplane/validators/jobs";
-
-import { api } from "~/trpc/react";
-
-type EnvironmentNodeProps = NodeProps<
- SCHEMA.Environment & {
- label: string;
- deploymentVersion: SCHEMA.DeploymentVersion;
- }
->;
-
-export const EnvironmentNode: React.FC = (node) => {
- const { data } = node;
- const releaseJobTriggers = api.job.config.byDeploymentVersionId.useQuery(
- { versionId: data.deploymentVersion.id },
- { refetchInterval: 10_000 },
- );
- const environmentJobs = releaseJobTriggers.data?.filter(
- (job) => job.environmentId === data.id,
- );
- const successful = environmentJobs?.filter(
- (job) => job.job.status === JobStatus.Successful,
- );
- return (
- <>
-
- {data.label}
-
- {releaseJobTriggers.data != null && (
-
- {successful?.length} / {environmentJobs?.length}
-
- )}
-
-
-
-
- >
- );
-};
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/FlowPolicyNode.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/FlowPolicyNode.tsx
deleted file mode 100644
index 22957ff6e..000000000
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/FlowPolicyNode.tsx
+++ /dev/null
@@ -1,189 +0,0 @@
-import type * as SCHEMA from "@ctrlplane/db/schema";
-import type { NodeProps } from "reactflow";
-import { useEffect, useState } from "react";
-import { differenceInMilliseconds } from "date-fns";
-import prettyMilliseconds from "pretty-ms";
-import { Handle, Position } from "reactflow";
-import colors from "tailwindcss/colors";
-
-import { cn } from "@ctrlplane/ui";
-import { JobStatus } from "@ctrlplane/validators/jobs";
-
-import { api } from "~/trpc/react";
-import { ApprovalCheck } from "./ApprovalCheck";
-import { Cancelled, Loading, Passing, Waiting } from "./StatusIcons";
-
-type PolicyNodeProps = NodeProps<
- SCHEMA.EnvironmentPolicy & {
- deploymentVersion: SCHEMA.DeploymentVersion;
- policyDeployments: Array;
- }
->;
-
-const MinSuccessCheck: React.FC = ({
- successMinimum,
- successType,
- deploymentVersion,
- policyDeployments,
-}) => {
- const allJobs = api.job.config.byDeploymentVersionId.useQuery(
- { versionId: deploymentVersion.id },
- { refetchInterval: 10_000 },
- );
- const envIds = policyDeployments.map((p) => p.environmentId);
- const jobs = allJobs.data?.filter((j) => envIds.includes(j.environmentId));
-
- if (successType === "optional") return null;
-
- if (successType === "some") {
- const passing =
- jobs?.filter((job) => job.job.status === JobStatus.Successful).length ??
- 0;
-
- const isMinSatified = passing >= successMinimum;
- return (
-
- {isMinSatified ?
:
} ≥ {successMinimum}{" "}
- completed sucessfully
-
- );
- }
-
- const areAllSuccessful =
- jobs?.every((job) => job.job.status === JobStatus.Successful) ?? true;
-
- return (
-
- {areAllSuccessful ? (
- <>
-
All jobs successful
- >
- ) : (
- <>
-
Waiting for all jobs to complete
- >
- )}
-
- );
-};
-
-const GradualRolloutCheck: React.FC = (data) => {
- const [timeLeft, setTimeLeft] = useState(null);
-
- const { data: approvalStatus, isLoading } =
- api.environment.policy.approval.statusByVersionPolicyId.useQuery(
- { policyId: data.id, versionId: data.deploymentVersion.id },
- { enabled: data.approvalRequirement === "manual" },
- );
-
- const startDate =
- data.approvalRequirement === "manual"
- ? (approvalStatus?.approvedAt ?? data.deploymentVersion.createdAt)
- : data.deploymentVersion.createdAt;
-
- useEffect(() => {
- const calculateTimeLeft = () => {
- const timePassed = differenceInMilliseconds(new Date(), startDate);
- return Math.max(0, data.rolloutDuration - timePassed);
- };
-
- setTimeLeft(calculateTimeLeft());
-
- const interval = setInterval(() => {
- const remaining = calculateTimeLeft();
- setTimeLeft(remaining);
-
- if (remaining <= 0) clearInterval(interval);
- }, 1000);
-
- return () => clearInterval(interval);
- }, [startDate, data.rolloutDuration]);
-
- if (timeLeft == null) return null;
-
- if (isLoading)
- return (
-
- Loading rollout status
-
- );
-
- const isApprovalPending =
- approvalStatus == null || approvalStatus.status === "pending";
-
- if (data.approvalRequirement === "manual" && isApprovalPending)
- return (
-
- Rollout pending approval
-
- );
-
- if (
- data.approvalRequirement === "manual" &&
- approvalStatus?.status === "rejected"
- )
- return (
-
- Rollout skipped due to approval rejection
-
- );
-
- return (
-
- {timeLeft <= 0 ?
:
}{" "}
- {timeLeft <= 0 ? (
- "Rollout completed"
- ) : (
- <>
- Rollout completes in{" "}
- {prettyMilliseconds(timeLeft, {
- compact: true,
- keepDecimalsOnWholeSeconds: false,
- })}
- >
- )}
-
- );
-};
-
-export const PolicyNode: React.FC = ({ data }) => {
- const noMinSuccess = data.successType === "optional";
- const noRollout = data.rolloutDuration === 0;
- const noApproval = data.approvalRequirement === "automatic";
-
- return (
- <>
-
- {!noMinSuccess &&
}
- {!noRollout &&
}
- {!noApproval && (
-
- )}
-
- {noMinSuccess && noRollout && noApproval && (
-
No policy checks.
- )}
-
-
-
-
- >
- );
-};
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/Approval.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/Approval.tsx
index 67c13e27e..edb1dad8e 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/Approval.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/checks/_components/flow-diagram/checks/Approval.tsx
@@ -1,16 +1,4 @@
-import { useState } from "react";
-
-import * as SCHEMA from "@ctrlplane/db/schema";
import { Button } from "@ctrlplane/ui/button";
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTrigger,
-} from "@ctrlplane/ui/dialog";
-import { Textarea } from "@ctrlplane/ui/textarea";
import {
Tooltip,
TooltipContent,
@@ -18,76 +6,10 @@ import {
TooltipTrigger,
} from "@ctrlplane/ui/tooltip";
+import { ApprovalDialog } from "~/app/[workspaceSlug]/(app)/(deploy)/_components/deployment-version/ApprovalDialog";
import { api } from "~/trpc/react";
import { Loading, Passing, Waiting } from "../StatusIcons";
-const ApprovalDialog: React.FC<{
- versionId: string;
- versionTag: string;
- environmentId: string;
- onSubmit: () => void;
-}> = ({ versionId, versionTag, environmentId, onSubmit }) => {
- const [open, setOpen] = useState(false);
- const addRecord =
- api.deployment.version.checks.approval.addRecord.useMutation();
-
- const [reason, setReason] = useState("");
-
- const handleSubmit = (status: SCHEMA.ApprovalStatus) =>
- addRecord
- .mutateAsync({
- deploymentVersionId: versionId,
- environmentId,
- status,
- reason,
- })
- .then(() => setOpen(false))
- .then(() => onSubmit());
-
- return (
-
- );
-};
-
export const ApprovalCheck: React.FC<{
workspaceId: string;
environmentId: string;
@@ -128,7 +50,11 @@ export const ApprovalCheck: React.FC<{
Not enough approvals
-
+
+
+
@@ -149,7 +75,11 @@ export const ApprovalCheck: React.FC<{
Not enough approvals
-
+
+
+
);
};
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/jobs/release-table/EnvironmentApprovalRow.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/jobs/release-table/EnvironmentApprovalRow.tsx
index 26de8933e..63ea39f96 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/jobs/release-table/EnvironmentApprovalRow.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/jobs/release-table/EnvironmentApprovalRow.tsx
@@ -9,17 +9,20 @@ import { ApprovalDialog } from "~/app/[workspaceSlug]/(app)/(deploy)/_components
type EnvironmentApprovalRowProps = {
approval: EnvironmentPolicyApproval & { user?: User | null };
deploymentVersion: { id: string; tag: string; deploymentId: string };
+ environmentId: string;
};
export const EnvironmentApprovalRow: React.FC = ({
approval,
deploymentVersion,
+ environmentId,
}) => {
if (approval.status === "pending")
return (