{activeTab === "deployments" && (
@@ -212,9 +205,6 @@ export const TargetDrawer: React.FC = () => {
{activeTab === "overview" && (
)}
- {activeTab === "relationships" && (
-
- )}
{activeTab === "jobs" &&
}
{activeTab === "variables" && (
= ({ target }) => {
- return (
-
- );
-};
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/relationships/RelationshipsDiagram.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/relationships/RelationshipsDiagram.tsx
deleted file mode 100644
index 684a6148..00000000
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/relationships/RelationshipsDiagram.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-"use client";
-
-import type * as schema from "@ctrlplane/db/schema";
-import type { EdgeTypes, NodeTypes, ReactFlowInstance } from "reactflow";
-import { useCallback, useEffect, useState } from "react";
-import ReactFlow, {
- MarkerType,
- ReactFlowProvider,
- useEdgesState,
- useNodesState,
- useReactFlow,
-} from "reactflow";
-import colors from "tailwindcss/colors";
-
-import { getLayoutedElementsDagre } from "~/app/[workspaceSlug]/(app)/_components/reactflow/layout";
-import { DepEdge } from "~/app/[workspaceSlug]/(app)/_components/relationships/DepEdge";
-import { TargetNode } from "~/app/[workspaceSlug]/(app)/_components/relationships/TargetNode";
-import { api } from "~/trpc/react";
-
-const nodeTypes: NodeTypes = { target: TargetNode };
-const edgeTypes: EdgeTypes = { default: DepEdge };
-
-const useOnLayout = () => {
- const { getNodes, fitView, setNodes, setEdges, getEdges } = useReactFlow();
- return useCallback(() => {
- const layouted = getLayoutedElementsDagre(
- getNodes(),
- getEdges(),
- "BT",
- 0,
- 50,
- );
- setNodes([...layouted.nodes]);
- setEdges([...layouted.edges]);
-
- fitView({ padding: 0.12, maxZoom: 1 });
- }, [getNodes, getEdges, setNodes, setEdges, fitView]);
-};
-
-const TargetDiagram: React.FC<{
- relationships: Array;
- targets: Array;
- targetId: string;
-}> = ({ relationships, targets, targetId }) => {
- const [nodes, _, onNodesChange] = useNodesState(
- targets.map((t) => ({
- id: t.identifier,
- type: "target",
- position: { x: 100, y: 100 },
- data: {
- ...t,
- targetId,
- isOrphanNode: !relationships.some(
- (r) =>
- r.toIdentifier === t.identifier ||
- r.fromIdentifier === t.identifier,
- ),
- },
- })),
- );
- const [edges, __, onEdgesChange] = useEdgesState(
- relationships.map((t) => ({
- id: `${t.fromIdentifier}-${t.toIdentifier}`,
- source: t.fromIdentifier,
- target: t.toIdentifier,
- markerEnd: { type: MarkerType.Arrow, color: colors.neutral[700] },
- style: { stroke: colors.neutral[700] },
- label: t.type,
- })),
- );
- const onLayout = useOnLayout();
-
- const [reactFlowInstance, setReactFlowInstance] =
- useState(null);
- useEffect(() => {
- if (reactFlowInstance != null) onLayout();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [reactFlowInstance]);
- return (
-
- );
-};
-
-export const TargetHierarchyRelationshipsDiagram: React.FC<{
- targetId: string;
-}> = ({ targetId }) => {
- const hierarchy = api.resource.relations.hierarchy.useQuery(targetId);
-
- if (hierarchy.data == null) return null;
- const { relationships, resources } = hierarchy.data;
- return (
-
-
-
- );
-};
diff --git a/packages/api/src/router/job.ts b/packages/api/src/router/job.ts
index 5fb8d4ae..1ef5a52b 100644
--- a/packages/api/src/router/job.ts
+++ b/packages/api/src/router/job.ts
@@ -24,7 +24,6 @@ import {
countDistinct,
desc,
eq,
- inArray,
isNull,
notInArray,
sql,
@@ -44,7 +43,6 @@ import {
release,
releaseDependency,
releaseJobTrigger,
- releaseMatchesCondition,
resource,
system,
updateJob,
@@ -348,13 +346,6 @@ const releaseJobTriggerRouter = createTRPCRouter({
canUser.perform(Permission.JobGet).on({ type: "job", id: input }),
})
.query(async ({ ctx, input }) => {
- const rel = await ctx.db
- .select()
- .from(release)
- .innerJoin(deployment, eq(release.deploymentId, deployment.id))
- .innerJoin(system, eq(deployment.systemId, system.id))
- .then(takeFirst);
-
const deploymentName = ctx.db
.select({
deploymentName: deployment.name,
@@ -387,132 +378,7 @@ const releaseJobTriggerRouter = createTRPCRouter({
.then(processReleaseJobTriggerWithAdditionalDataRows)
.then(takeFirst);
- const { releaseDependencies } = data;
-
- const results = await ctx.db.execute(
- sql`
- WITH RECURSIVE reachable_relationships(id, visited, tr_id, source_id, target_id, type) AS (
- -- Base case: start with the given ID and no relationship
- SELECT
- ${data.resource.identifier}::uuid AS identifier,
- ARRAY[${data.resource.identifier}::uuid] AS visited,
- NULL::uuid AS tr_id,
- NULL::uuid AS source_identifier,
- NULL::uuid AS target_identifier,
- NULL::resource_relationship_type AS type
- UNION ALL
- -- Recursive case: find all relationships connected to the current set of IDs
- SELECT
- CASE
- WHEN tr.source_identifier = rr.identifier THEN tr.target_identifier
- ELSE tr.source_id
- END AS id,
- rr.visited || CASE
- WHEN tr.source_id = rr.id THEN tr.target_id
- ELSE tr.source_id
- END,
- tr.id AS tr_id,
- tr.source_identifier,
- tr.target_identifier,
- tr.type
- FROM reachable_relationships rr
- JOIN resource_relationship tr ON tr.source_identifier = rr.identifier OR tr.target_identifier = rr.identifier
- WHERE
- NOT CASE
- WHEN tr.source_id = rr.id THEN tr.target_id
- ELSE tr.source_id
- END = ANY(rr.visited)
- AND tr.target_identifier != ${data.resource.identifier}
- )
- SELECT DISTINCT tr_id AS id, source_identifier, target_identifier, type
- FROM reachable_relationships
- WHERE tr_id IS NOT NULL;
- `,
- );
-
- // db.execute does not return the types even if the sql`` is annotated with the type
- // so we need to cast them here
- const relationships = results.rows.map((r) => ({
- id: String(r.id),
- workspaceId: rel.system.workspaceId,
- fromIdentifier: String(r.source_identifier),
- toIdentifier: String(r.target_identifier),
- type: r.type as "associated_with" | "depends_on",
- }));
-
- const fromIdentifiers = relationships.map((r) => r.fromIdentifier);
- const toIdentifiers = relationships.map((r) => r.toIdentifier);
-
- const allIdentifiers = _.uniq([
- ...fromIdentifiers,
- ...toIdentifiers,
- data.resource.identifier,
- ]);
-
- const resources = await ctx.db
- .select()
- .from(resource)
- .where(
- and(
- inArray(resource.identifier, allIdentifiers),
- isNull(resource.deletedAt),
- ),
- );
-
- const releaseDependenciesWithResourcePromises = releaseDependencies.map(
- async (rd) => {
- const latestJobSubquery = ctx.db
- .select({
- id: releaseJobTrigger.id,
- resourceId: releaseJobTrigger.resourceId,
- releaseId: releaseJobTrigger.releaseId,
- status: job.status,
- createdAt: job.createdAt,
- rank: sql`ROW_NUMBER() OVER (
- PARTITION BY ${releaseJobTrigger.resourceId}, ${releaseJobTrigger.releaseId}
- ORDER BY ${job.createdAt} DESC
- )`.as("rank"),
- })
- .from(job)
- .innerJoin(releaseJobTrigger, eq(releaseJobTrigger.jobId, job.id))
- .as("latest_job");
-
- const resourceFulfillingDependency = await ctx.db
- .select()
- .from(release)
- .innerJoin(deployment, eq(release.deploymentId, deployment.id))
- .innerJoin(
- latestJobSubquery,
- eq(latestJobSubquery.releaseId, release.id),
- )
- .where(
- and(
- releaseMatchesCondition(ctx.db, rd.releaseFilter),
- eq(deployment.id, rd.deploymentId),
- inArray(
- latestJobSubquery.resourceId,
- resources.map((r) => r.id),
- ),
- eq(latestJobSubquery.rank, 1),
- eq(latestJobSubquery.status, JobStatus.Completed),
- ),
- );
-
- return {
- ...rd,
- resource: resourceFulfillingDependency.at(0)?.latest_job.resourceId,
- };
- },
- );
-
- return {
- ...data,
- releaseDependencies: await Promise.all(
- releaseDependenciesWithResourcePromises,
- ),
- relationships,
- relatedResources: resources,
- };
+ return data;
}),
});
diff --git a/packages/api/src/router/resources.ts b/packages/api/src/router/resources.ts
index b2931afd..060d2220 100644
--- a/packages/api/src/router/resources.ts
+++ b/packages/api/src/router/resources.ts
@@ -39,88 +39,6 @@ import { resourceProviderRouter } from "./target-provider";
const isNotDeleted = isNull(schema.resource.deletedAt);
-const resourceRelations = createTRPCRouter({
- hierarchy: protectedProcedure
- .input(z.string().uuid())
- .query(async ({ ctx, input }) => {
- const isResource = eq(schema.resource.id, input);
- const where = and(isResource, isNotDeleted);
- const r = await ctx.db.query.resource.findFirst({ where });
- if (r == null) return null;
-
- const results = await ctx.db.execute(
- sql`
- WITH RECURSIVE reachable_relationships(id, visited, tr_id, source_identifier, target_identifier, type) AS (
- -- Base case: start with the given ID and no relationship
- SELECT
- ${input}::uuid AS id,
- ARRAY[${input}::uuid] AS visited,
- NULL::uuid AS tr_id,
- NULL::uuid AS source_identifier,
- NULL::uuid AS target_identifier,
- NULL::resource_relationship_type AS type
- UNION ALL
- -- Recursive case: find all relationships connected to the current set of IDs
- SELECT
- CASE
- WHEN tr.source_identifier = rr.id THEN tr.target_identifier
- ELSE tr.source_identifier
- END AS id,
- rr.visited || CASE
- WHEN tr.source_identifier = rr.id THEN tr.target_identifier
- ELSE tr.source_identifier
- END,
- tr.id AS tr_id,
- tr.source_identifier,
- tr.target_identifier,
- tr.type
- FROM reachable_relationships rr
- JOIN resource_relationship tr ON tr.source_id = rr.id OR tr.target_id = rr.id
- WHERE
- NOT CASE
- WHEN tr.source_identifier = rr.id THEN tr.target_identifier
- ELSE tr.source_identifier
- END = ANY(rr.visited)
- )
- SELECT DISTINCT tr_id AS id, source_identifier, target_identifier, type
- FROM reachable_relationships
- WHERE tr_id IS NOT NULL;
- `,
- );
-
- // db.execute does not return the types even if the sql`` is annotated with the type
- // so we need to cast them here
- const relationships = results.rows.map((r) => ({
- id: String(r.id),
- fromIdentifier: String(r.source_identifier),
- toIdentifier: String(r.target_identifier),
- workspaceId: String(r.workspace_id),
- type: r.type as "associated_with" | "depends_on",
- }));
-
- const fromIdentifiers = relationships.map((r) => r.fromIdentifier);
- const toIdentifiers = relationships.map((r) => r.toIdentifier);
-
- const allIdentifiers = _.uniq([
- ...fromIdentifiers,
- ...toIdentifiers,
- input,
- ]);
-
- const resources = await ctx.db
- .select()
- .from(schema.resource)
- .where(
- and(
- inArray(schema.resource.identifier, allIdentifiers),
- isNotDeleted,
- ),
- );
-
- return { relationships, resources };
- }),
-});
-
type _StringStringRecord = Record;
const resourceQuery = (db: Tx, checks: Array>) =>
db
@@ -382,7 +300,6 @@ const getNodesRecursively = async (db: Tx, resourceId: string) => {
export const resourceRouter = createTRPCRouter({
metadataGroup: resourceMetadataGroupRouter,
provider: resourceProviderRouter,
- relations: resourceRelations,
view: resourceViews,
variable: resourceVariables,
@@ -508,16 +425,16 @@ export const resourceRouter = createTRPCRouter({
].filter(isPresent),
associations: {
from: fromNodes
- .filter((n) => n.node != null)
+ .filter((n) => isPresent(n.node))
.map((n) => ({
...n.resource_relationship,
- resource: n.node!,
+ resource: n.node,
})),
to: toNodes
- .filter((n) => n.node != null)
+ .filter((n) => isPresent(n.node))
.map((n) => ({
...n.resource_relationship,
- resource: n.node!,
+ resource: n.node,
})),
},
};
diff --git a/packages/job-dispatch/src/policy-checker.ts b/packages/job-dispatch/src/policy-checker.ts
index a0558f85..65824c04 100644
--- a/packages/job-dispatch/src/policy-checker.ts
+++ b/packages/job-dispatch/src/policy-checker.ts
@@ -7,7 +7,6 @@ import { isPassingLockingPolicy } from "./lock-checker.js";
import { isPassingConcurrencyPolicy } from "./policies/concurrency-policy.js";
import { isPassingJobRolloutPolicy } from "./policies/gradual-rollout.js";
import { isPassingApprovalPolicy } from "./policies/manual-approval.js";
-import { isPassingReleaseDependencyPolicy } from "./policies/release-dependency.js";
import {
isPassingNewerThanLastActiveReleasePolicy,
isPassingNoActiveJobsPolicy,
@@ -25,7 +24,6 @@ export const isPassingAllPolicies = async (
isPassingApprovalPolicy,
isPassingCriteriaPolicy,
isPassingConcurrencyPolicy,
- isPassingReleaseDependencyPolicy,
isPassingJobRolloutPolicy,
isPassingNoActiveJobsPolicy,
isPassingNewerThanLastActiveReleasePolicy,
@@ -48,7 +46,6 @@ export const isPassingAllPoliciesExceptNewerThanLastActive = async (
isPassingApprovalPolicy,
isPassingCriteriaPolicy,
isPassingConcurrencyPolicy,
- isPassingReleaseDependencyPolicy,
isPassingJobRolloutPolicy,
isPassingNoActiveJobsPolicy,
isPassingReleaseWindowPolicy,