Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Visualization diagram v2 #228

Merged
merged 8 commits into from
Nov 25, 2024
Merged

Conversation

adityachoudhari26
Copy link
Contributor

@adityachoudhari26 adityachoudhari26 commented Nov 24, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced enhanced visual feedback for job statuses in the ReleaseIcon component.
    • Added a DeploymentCard to the EnvironmentNode for displaying deployment information.
  • Improvements

    • Streamlined handling of resource IDs across various components for improved clarity.
    • Enhanced filtering capabilities in the deploymentRouter for more precise data retrieval.
  • Bug Fixes

    • Improved safety in property access using optional chaining in DeploymentContent and VariablesContent.
  • Refactor

    • Removed deprecated components and logic related to System and Deployment nodes to simplify the visualization structure.

Copy link
Contributor

coderabbitai bot commented Nov 24, 2024

Walkthrough

The pull request introduces significant enhancements to the ReleaseCell.tsx file, specifically the ReleaseIcon component, by adding new job status cases and corresponding visual representations. Additionally, it modifies various components to replace targetId with resourceId for clarity and consistency in API queries. The changes also include the removal of components and logic related to systems and deployments, streamlining the visualization logic. New relationships between jobs and resources are established through database schema changes, reflecting a shift in focus from deployments to jobs.

Changes

File Change Summary
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/ReleaseCell.tsx Enhanced ReleaseIcon component with new job statuses and visual representations; exported the ReleaseIcon component.
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/page.tsx Updated targetId to resourceId in DeploymentsTable and TargetPage components for improved clarity in API queries.
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/variables/page.tsx Changed query execution for fetching deployments and variables to use resourceId instead of targetId.
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/ResourceVisualizationDiagram.tsx Removed System and Deployment node types; simplified logic to focus on resources and environments.
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/edges.ts Removed functions and types related to systems and deployments; retained only resource-related edge creation functions.
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/DeploymentNode.tsx Deleted the DeploymentNode component.
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/EnvironmentNode.tsx Updated EnvironmentNode to be a client component; added new types and a DeploymentCard for displaying deployment information.
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/ProviderNode.tsx Repositioned Handle components within the ProviderNode component.
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/ResourceNode.tsx Repositioned Handle components within the ResourceNode component.
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/SystemNode.tsx Deleted the SystemNode component.
apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/DeploymentContent.tsx Refactored to use resourceId instead of targetId and added optional chaining for safer property access.
apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/VariablesContent.tsx Updated to use resourceId instead of targetId in queries for deployments and variables.
apps/webservice/src/app/api/v1/relationship/deployment-to-resource/route.ts Deleted the API endpoint related to the relationship between deployments and resources.
packages/api/src/router/deployment.ts Enhanced byTargetId method to include environment.id for filtering; refined handling of releaseJobTrigger and added a result limit of 500.
packages/api/src/router/resources.ts Added new activeReleases router with byResourceAndEnvironmentId procedure; updated existing procedures for better clarity and performance.
packages/db/drizzle/meta/_journal.json Added a new entry to the JSON structure.
packages/db/src/schema/resource.ts Removed deploymentResourceRelationship table and added jobResourceRelationship table, changing the relationship context from deployment to job.
packages/job-dispatch/src/resource/delete.ts Removed logic related to deploymentResourceRelationship from the deletion function, simplifying the operation.
packages/db/drizzle/0042_absent_cerebro.sql Introduced job_resource_relationship table and dropped deployment_resource_relationship; added foreign key constraint and unique index.

Possibly related PRs

Suggested reviewers

  • jsbroks

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (16)
packages/job-dispatch/src/resource/delete.ts (1)

Line range hint 20-42: Consider enhancing error handling in parallel operations

While the parallel execution of cleanup tasks is efficient, consider adding error handling to ensure partial failures don't leave the system in an inconsistent state.

Consider this improvement:

 export const deleteResources = async (tx: Tx, resources: Resource[]) => {
+  try {
     const eventsPromises = Promise.all(
       resources.map(getEventsForResourceDeleted),
     );
     const events = await eventsPromises.then((res) => res.flat());
     await Promise.all(events.map(handleEvent));
     const resourceIds = resources.map((r) => r.id);
     const deleteAssociatedObjects = Promise.all(
       resources.map((r) => deleteObjectsAssociatedWithResource(tx, r)),
     );
     await Promise.all([
       deleteAssociatedObjects,
       tx
         .update(resource)
         .set({ deletedAt: new Date() })
         .where(inArray(resource.id, resourceIds)),
     ]);
+  } catch (error) {
+    // Log the error for debugging
+    console.error('Failed to delete resources:', error);
+    // Re-throw to allow transaction rollback
+    throw error;
+  }
 };
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/ResourceNode.tsx (1)

47-47: Consider updating diagram documentation.

The change from vertical to horizontal layout is a significant visual change that affects how the diagram is rendered and interpreted.

Consider:

  1. Adding a comment explaining the layout convention
  2. Updating any relevant documentation about the visualization diagram
  3. Adding a screenshot example in the documentation
 <Handle
   type="target"
   className={cn(
     "h-2 w-2 rounded-full border border-neutral-500 bg-neutral-800",
     isKubernetes && "border-blue-500/70",
     isTerraform && "border-purple-500/70",
     isSharedCluster && "border-blue-500/70",
   )}
+  // Horizontal layout: connections flow left-to-right
   position={Position.Left}
 />

Also applies to: 57-57

apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/ProviderNode.tsx (1)

Line range hint 1-64: Consider documenting the new visualization architecture.

Given this is part of a larger visualization refactor (v2) with significant changes including:

  • Horizontal flow direction
  • Removal of DeploymentNode
  • Changes to resource relationships

Consider adding documentation about:

  1. The new visualization architecture
  2. Node connection patterns
  3. Migration guide for existing visualizations

Would you like me to help create a documentation template for these architectural changes?

apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/variables/page.tsx (2)

37-39: Standardize API query parameter style.

While the refactoring to resourceId is good, there's an inconsistency in how parameters are passed to the queries:

  • Line 38 uses object style: { resourceId }
  • Line 39 uses direct parameter style: resourceId

This inconsistency could lead to confusion. Consider standardizing to the object parameter style for both queries.

  const resourceId = params.targetId;
  const deployments = api.deployment.byTargetId.useQuery({ resourceId });
- const variables = api.deployment.variable.byTargetId.useQuery(resourceId);
+ const variables = api.deployment.variable.byTargetId.useQuery({ resourceId });

37-39: Add explicit loading and error handling states.

The component could benefit from explicit handling of loading and error states from the queries for better user experience.

  const resourceId = params.targetId;
  const deployments = api.deployment.byTargetId.useQuery({ resourceId });
  const variables = api.deployment.variable.byTargetId.useQuery(resourceId);
+ 
+ if (deployments.isLoading || variables.isLoading) {
+   return <div>Loading...</div>;
+ }
+ 
+ if (deployments.error || variables.error) {
+   return <div>Error loading data</div>;
+ }
apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/DeploymentContent.tsx (2)

42-46: Simplify status styling logic

The current className conditional logic is hard to maintain and has redundant classes. Consider using a status-to-style mapping for better maintainability.

Consider refactoring to:

+ const statusStyles = {
+   null: "bg-neutral-800 text-muted-foreground",
+   completed: "bg-green-500/30 text-green-400 text-muted-foreground",
+ };
+ 
  <div
    className={cn(
-     deployment.releaseJobTrigger?.job == null &&
-       "bg-neutral-800 text-muted-foreground",
-     deployment.releaseJobTrigger?.job.status === "completed" &&
-       "bg-green-500/30 text-green-400 text-muted-foreground",
+     statusStyles[deployment.releaseJobTrigger?.job?.status ?? null]
    )}
  >

48-50: Clarify the fallback message

The message "No deployments" is misleading since we're already inside a deployment mapping. This suggests the version is missing, not that there are no deployments.

Consider updating the fallback message:

- {deployment.releaseJobTrigger?.release.version ?? "No deployments"}
+ {deployment.releaseJobTrigger?.release.version ?? "No version"}
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/ReleaseCell.tsx (1)

47-77: Consider refactoring for better maintainability

While the new status handlers are functionally correct, consider these improvements:

  1. Extract repeated styling classes into a constant or utility class
  2. Centralize the status-to-color mapping in a constant/enum
  3. Add unit tests for the new states

Example refactor:

const STATUS_STYLES = {
  [JobStatus.Cancelled]: {
    bgColor: 'bg-neutral-400',
    icon: IconCircleX,
  },
  [JobStatus.Failure]: {
    bgColor: 'bg-red-400',
    icon: IconCircleX,
  },
  // ... other statuses
} as const;

const baseStyles = 'rounded-full p-1 dark:text-black';

export const ReleaseIcon: React.FC<{ job?: Job }> = ({ job }) => {
  if (!job?.status || !(job.status in STATUS_STYLES)) return null;
  
  const { bgColor, icon: Icon } = STATUS_STYLES[job.status];
  return (
    <div className={`${baseStyles} ${bgColor}`}>
      <Icon strokeWidth={2} />
    </div>
  );
};
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/ResourceVisualizationDiagram.tsx (1)

Line range hint 1-114: Consider documenting the architectural decisions.

The significant simplification of the visualization architecture (removing System and Deployment nodes) improves maintainability. However, consider:

  1. Documenting these architectural decisions for future reference
  2. Adding comments explaining the new data structure and relationship model
  3. Updating any related documentation or diagrams

Consider creating an Architecture Decision Record (ADR) to document the rationale behind removing the System and Deployment nodes and how this affects the overall system visualization strategy.

apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/VariablesContent.tsx (1)

107-107: Remove redundant variable assignment

The resourceId variable assignment is redundant as it's just renaming targetId without any transformation.

Consider using targetId directly or remove the assignment:

- const resourceId = targetId;
  const deployments = api.deployment.byTargetId.useQuery({ resourceId: targetId });
  const variables = api.deployment.variable.byTargetId.useQuery({ resourceId: targetId });
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/page.tsx (1)

28-30: Consider updating component interface and API consistency.

A few suggestions to improve the code:

  1. Update the component props to use resourceId instead of targetId for consistency with the internal usage.
  2. Standardize the API query parameters - byResourceId uses a direct string parameter while byTargetId uses an object parameter.
-const DeploymentsTable: React.FC<{ targetId: string }> = ({ targetId }) => {
-  const resourceId = targetId;
+const DeploymentsTable: React.FC<{ resourceId: string }> = ({ resourceId }) => {
   const jobs = api.job.byResourceId.useQuery(resourceId);
-  const deployments = api.deployment.byTargetId.useQuery({ resourceId });
+  const deployments = api.deployment.byTargetId.useQuery(resourceId);
packages/api/src/router/resources.ts (1)

397-397: Consider adding defensive programming for the google provider access.

While the current implementation works, it might be more robust to handle the case where the google array itself is undefined:

-              google: resource.provider.google[0] ?? null,
+              google: resource.provider.google?.[0] ?? null,

This change would prevent potential runtime errors if the google property is undefined.

apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/EnvironmentNode.tsx (3)

93-99: Simplify opacity calculation in the Skeleton component

The opacity calculation in the style prop can be simplified by removing the unnecessary multiplication by 1.

Apply this diff to simplify the code:

-{ opacity: 1 * (1 - i / 3) }
+{ opacity: 1 - i / 3 }

68-75: Handle additional job statuses for robustness

The status checks for isInProgress, isPending, and isCompleted consider specific job statuses. To make the component more robust against future status additions or changes, consider handling other possible statuses or using a default case.

For example, you could define a function to determine the status color:

const getStatusBorderColor = (): string => {
  if (isInProgress) return "border-blue-500";
  if (isPending) return "border-neutral-500";
  if (isCompleted) return "border-green-500";
  return "border-default";
};

And then use it in your className:

 className={cn(
   "relative flex min-w-[250px] flex-col gap-2 rounded-md border px-4 py-3",
-  isInProgress && "border-blue-500",
-  isPending && "border-neutral-500",
-  isCompleted && "border-green-500",
+  getStatusBorderColor(),
 )}

80-85: Avoid redundant border classes in className

The base class includes border border-neutral-800, but conditional classes also apply border colors. This could lead to redundant or conflicting styles. Consider removing the base border color or adjusting the conditional classes.

Apply this diff to remove the redundant base border style:

 className={cn(
-  "relative flex min-w-[250px] flex-col gap-2 rounded-md border border-neutral-800 bg-neutral-900/30 px-4 py-3",
+  "relative flex min-w-[250px] flex-col gap-2 rounded-md bg-neutral-900/30 px-4 py-3",
   isInProgress && "border-blue-500",
   isPending && "border-neutral-500",
   isCompleted && "border-green-500",
 )}
packages/api/src/router/deployment.ts (1)

618-622: Add Validation to Prevent Non-positive 'jobsPerDeployment' Values

The jobsPerDeployment parameter could potentially be zero or negative, leading to unexpected behavior in the query. Consider adding a .min(1) constraint to ensure it is at least 1.

Apply this change to the input schema:

 .input(
   z.object({
     resourceId: z.string().uuid(),
     environmentIds: z.array(z.string().uuid()).optional(),
     deploymentIds: z.array(z.string().uuid()).optional(),
-    jobsPerDeployment: z.number().optional().default(30),
+    jobsPerDeployment: z.number().min(1).optional().default(30),
     showAllStatuses: z.boolean().optional().default(false),
   }),
 )
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a672da8 and 9d79f40.

📒 Files selected for processing (19)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/ReleaseCell.tsx (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/page.tsx (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/variables/page.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/ResourceVisualizationDiagram.tsx (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/edges.ts (0 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/DeploymentNode.tsx (0 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/EnvironmentNode.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/ProviderNode.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/ResourceNode.tsx (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/SystemNode.tsx (0 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/DeploymentContent.tsx (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/VariablesContent.tsx (1 hunks)
  • apps/webservice/src/app/api/v1/relationship/deployment-to-resource/route.ts (0 hunks)
  • packages/api/src/router/deployment.ts (7 hunks)
  • packages/api/src/router/resources.ts (1 hunks)
  • packages/db/drizzle/0042_lonely_warstar.sql (1 hunks)
  • packages/db/drizzle/meta/_journal.json (1 hunks)
  • packages/db/src/schema/resource.ts (0 hunks)
  • packages/job-dispatch/src/resource/delete.ts (1 hunks)
💤 Files with no reviewable changes (5)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/edges.ts
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/DeploymentNode.tsx
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/SystemNode.tsx
  • apps/webservice/src/app/api/v1/relationship/deployment-to-resource/route.ts
  • packages/db/src/schema/resource.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/db/drizzle/0042_lonely_warstar.sql
🧰 Additional context used
📓 Learnings (1)
packages/api/src/router/deployment.ts (1)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-11-12T09:55:38.456Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
🔇 Additional comments (14)
packages/job-dispatch/src/resource/delete.ts (2)

6-6: LGTM: Import changes align with schema updates

The removal of the deploymentResourceRelationship import aligns with the broader refactoring effort to simplify the resource relationship model.


10-18: Verify the impact of removing deployment relationship cleanup

The simplified relationship cleanup looks correct, but let's verify there are no remaining references to these resources in other tables.

✅ Verification successful

Let me check the SQL files to understand the nature of these references.


The deployment relationship cleanup is properly handled

The SQL migrations show that the deployment_resource_relationship table has been explicitly dropped (in migration 0042), and all other resource relationships are properly handled with CASCADE delete constraints. The current implementation correctly focuses on cleaning up resource_relationship table entries, while other related tables (resource_session, resource_metadata, resource_variable, etc.) are automatically handled through their CASCADE delete constraints.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to resources in deployment-related tables
# This helps ensure we haven't missed any cleanup requirements after removing deployment_resource_relationship

# Search for any deployment-resource relationship references in SQL files
echo "Checking for deployment-resource references in SQL files..."
rg -l "deployment.*resource|resource.*deployment" --type sql

# Search for any deployment-resource relationship references in TypeScript files
echo "Checking for deployment-resource references in TypeScript code..."
ast-grep --pattern 'deployment$_resource' --lang ts

Length of output: 473


Script:

#!/bin/bash
# Check the content of the SQL files that have references
echo "Content of 0039_hard_joystick.sql:"
cat packages/db/drizzle/0039_hard_joystick.sql

echo -e "\nContent of 0042_lonely_warstar.sql:"
cat packages/db/drizzle/0042_lonely_warstar.sql

# Let's also check if there are any other tables referencing resource.id
echo -e "\nChecking for other foreign key references to resource.id:"
rg "REFERENCES.*resource.*id" --type sql

Length of output: 4530

apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/ProviderNode.tsx (1)

55-55: LGTM! Verify the impact of handle position changes.

The change from vertical (Top/Bottom) to horizontal (Left/Right) flow makes sense and follows common visualization patterns. The changes are consistent with similar modifications in ResourceNode.tsx.

Let's verify the handle positions across all node types and check for any affected connections:

Also applies to: 63-63

✅ Verification successful

Handle positions are consistently updated across all node components

The verification shows that all node components (ProviderNode, EnvironmentNode, and ResourceNode) consistently use Left/Right positions for their handles, confirming a systematic change to horizontal flow layout.

  • ProviderNode: Left/Right positions ✓
  • EnvironmentNode: Left/Right positions ✓
  • ResourceNode: Left/Right positions ✓
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in handle positions across node components
# and identify any potentially affected connections

# Check for other node components using Handle positions
rg -A 2 "position={Position\." "apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize"

# Look for any connection configurations that might need updates
rg "Position\.(Top|Bottom|Left|Right)" "apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize"

Length of output: 1215

apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/DeploymentContent.tsx (1)

12-12: Verify consistent usage of resourceId

Let's verify that the transition from targetId to resourceId is consistent across the codebase.

✅ Verification successful

Consistent usage of resourceId confirmed

The change from targetId to resourceId in DeploymentContent.tsx is part of a consistent pattern across the codebase. The search results show that resourceId is the standardized identifier used throughout the application, particularly in:

  • Database schemas and queries
  • API routes and endpoints
  • Job dispatch and deployment logic
  • Resource management components

The change aligns with the codebase's conventions and maintains consistency.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining instances of targetId that might need updating

# Search for targetId usage in TypeScript/JavaScript files
echo "Checking for targetId usage in TS/JS files:"
rg -t typescript -t javascript 'targetId' -A 2

# Search for resourceId usage to verify the new pattern
echo -e "\nVerifying resourceId usage:"
rg -t typescript -t javascript 'resourceId' -A 2

Length of output: 333


Script:

#!/bin/bash
# Let's try with correct file extensions
echo "Checking for targetId usage:"
rg "targetId" --type-add 'ts:*.{ts,tsx}' --type-add 'js:*.{js,jsx}' -t ts -t js -A 2

echo -e "\nVerifying resourceId usage:"
rg "resourceId" --type-add 'ts:*.{ts,tsx}' --type-add 'js:*.{js,jsx}' -t ts -t js -A 2

Length of output: 84754

apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/ReleaseCell.tsx (2)

11-18: LGTM! Icon imports are well-organized

The new icon imports are properly organized and align with the new job status handlers.


23-23: LGTM! Component export enhances reusability

The ReleaseIcon component is now properly exported, allowing it to be reused across the application.

apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/ResourceVisualizationDiagram.tsx (3)

90-90: LGTM! Explicit layout direction improves visualization.

The left-to-right layout is a good choice for relationship diagrams, making the flow of dependencies more intuitive.


87-87: Verify all necessary relationships are represented in the simplified edge structure.

The edge creation has been simplified to only include resource-to-environment and provider-to-resource relationships.

✅ Verification successful

Edge relationships are correctly represented for the resource visualization context

The simplified edge structure is complete and appropriate for this visualization context. The code shows two essential relationships:

  1. Resource-to-Environment edges showing where resources are deployed ("in" relationship)
  2. Provider-to-Resource edges showing resource discovery ("discovered" relationship)

These relationships align with the component's purpose of visualizing resource relationships, and no other edge types are necessary for this specific diagram.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any other relationship types that might need edges
rg -A 5 "createEdgesFrom.*To.*" --type typescript

Length of output: 86


Script:

#!/bin/bash
# Search for edge creation patterns in the codebase
rg -l "createEdge|Edge.*From|.*ToEdge" 

# Get the content of the current file to understand the context better
cat "apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/ResourceVisualizationDiagram.tsx"

Length of output: 4017


Script:

#!/bin/bash
# Let's check the edges.ts file to understand all edge creation functions
cat "apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/edges.ts"

Length of output: 1118


60-67: Consider performance and validation implications of the new data structure.

While consolidating deployments into environment data simplifies the visualization, please consider:

  1. Performance impact when handling environments with many deployments
  2. Validation of system and environment names in the label to handle special characters

Consider implementing pagination or virtualization if environments can contain a large number of deployments.

packages/db/drizzle/meta/_journal.json (1)

298-307: LGTM! Verify the associated migration file.

The new migration entry follows the established pattern and maintains consistency with existing entries.

Let's verify the associated migration file exists and contains the expected schema changes:

✅ Verification successful

Migration file verified and matches expected changes

The migration file 0042_lonely_warstar.sql exists and correctly implements the removal of the deployment_resource_relationship table as expected.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the migration file exists and contains expected changes

# Check if the migration file exists
fd "0042_lonely_warstar.sql" packages/db/drizzle

# Display the migration file contents to verify the removal of deployment_resource_relationship table
fd "0042_lonely_warstar.sql" packages/db/drizzle --exec cat {}

Length of output: 204

packages/api/src/router/resources.ts (1)

397-397: LGTM! Clean simplification of the google provider handling.

The use of the nullish coalescing operator (??) is a more concise and idiomatic way to handle the default case.

apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/EnvironmentNode.tsx (1)

54-63: Verify the parameter name in api.deployment.byTargetId.useQuery

The useQuery hook is calling api.deployment.byTargetId with a resourceId instead of a targetId. Please confirm that this is intentional and that the byTargetId method accepts resourceId as a parameter.

Run the following script to check the method definition:

✅ Verification successful

The parameter name resourceId is correct in the byTargetId query

Looking at the implementation in packages/api/src/router/deployment.ts, the byTargetId procedure accepts an input object that explicitly includes resourceId as a parameter. The procedure is correctly typed and the parameter name matches the API contract.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify if `byTargetId` method accepts `resourceId` or `targetId`.

# Search for the definition of `byTargetId` and inspect its parameters.
fd --type f --extension ts --extension tsx | xargs grep -nE 'byTargetId\('

Length of output: 76


Script:

#!/bin/bash
# Let's try a more comprehensive search using ripgrep to find the API definition
rg -l "deployment.*byTargetId" --type ts --type tsx

# Also search for the router definition since it's likely a tRPC API
rg "deployment.*router" --type ts

Length of output: 395


Script:

#!/bin/bash
# Let's check the deployment router implementation
cat packages/api/src/router/deployment.ts

# Also search with ast-grep to find the procedure definition
ast-grep --pattern 'procedure($$$).query($$$byTargetId$$$)'

Length of output: 23123

packages/api/src/router/deployment.ts (2)

713-713: Confirm Correct Usage of 'lte' Function in Query

Verify that the lte function is correctly used in the condition:

lte(rankSubquery.rank, jobsPerDeployment),

Ensure that rankSubquery.rank and jobsPerDeployment are of compatible types and that this condition effectively limits the number of jobs per deployment as intended.


659-669: Review the Implementation of 'rankSubquery'

The rankSubquery calculates the rank of releases per deployment. Confirm that it integrates correctly with the main query and that the ranking behaves as expected, especially when limiting jobs per deployment.

@@ -44,7 +44,7 @@ export const ResourceNode: React.FC<ResourceNodeProps> = (node) => {
isTerraform && "border-purple-500/70",
isSharedCluster && "border-blue-500/70",
)}
position={Position.Top}
position={Position.Left}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Found inconsistent handle positions in the visualization nodes

The search reveals that while most nodes use the new horizontal layout (Left/Right positions), there are still some nodes using vertical positions (Top/Bottom). Specifically:

  • Position.Top and Position.Bottom are still present in some components
  • Most nodes have been updated to use Position.Left and Position.Right

To maintain consistency across the visualization:

  • Update remaining Top/Bottom positions to match the new Left/Right convention
  • Check if the Top/Bottom positions in other nodes are intentional or were missed in this update
🔗 Analysis chain

LGTM! Verify handle position consistency across all node types.

The change from vertical (Top/Bottom) to horizontal (Left/Right) handle positions makes sense for infrastructure diagrams. This layout is more intuitive for visualizing resource relationships.

Let's verify that all node types follow this new convention:

Also applies to: 57-57

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent handle positions across all node components
# Look for any remaining Top/Bottom handle positions that might have been missed

# Search for Position.Top or Position.Bottom in node components
rg -l "Position\.(Top|Bottom)" --type typescript | grep -i "node\.tsx$"

# Search for all node components to ensure we haven't missed any
fd -e tsx$ -e ts$ | grep -i "node\.tsx$"

Length of output: 155


Script:

#!/bin/bash
# Let's try a different approach to find node components and their handle positions

# First, find all Node.tsx files
fd "Node\.tsx$"

# Then search for Position enum usage in these files
echo "=== Handle Positions ==="
rg "Position\." -A 1 -B 1 --no-filename $(fd "Node\.tsx$")

Length of output: 3345

Comment on lines 12 to 14
const resourceId = targetId;
const deployments = api.deployment.byTargetId.useQuery({ resourceId });
const targetValues = api.deployment.variable.byTargetId.useQuery(resourceId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Standardize query parameter passing

The query parameter passing is inconsistent between the two queries. While deployment.byTargetId uses an object parameter, deployment.variable.byTargetId uses a direct string parameter.

Apply this diff to standardize the approach:

  const resourceId = targetId;
  const deployments = api.deployment.byTargetId.useQuery({ resourceId });
- const targetValues = api.deployment.variable.byTargetId.useQuery(resourceId);
+ const targetValues = api.deployment.variable.byTargetId.useQuery({ resourceId });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const resourceId = targetId;
const deployments = api.deployment.byTargetId.useQuery({ resourceId });
const targetValues = api.deployment.variable.byTargetId.useQuery(resourceId);
const resourceId = targetId;
const deployments = api.deployment.byTargetId.useQuery({ resourceId });
const targetValues = api.deployment.variable.byTargetId.useQuery({ resourceId });

Comment on lines 108 to 109
const deployments = api.deployment.byTargetId.useQuery({ resourceId });
const variables = api.deployment.variable.byTargetId.useQuery(resourceId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Maintain consistency in API call patterns

The deployment query uses an object parameter { resourceId } while the variables query uses the resourceId directly. This inconsistency could lead to maintenance issues.

Consider using the same parameter structure for both queries:

  const deployments = api.deployment.byTargetId.useQuery({ resourceId });
- const variables = api.deployment.variable.byTargetId.useQuery(resourceId);
+ const variables = api.deployment.variable.byTargetId.useQuery({ resourceId });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const deployments = api.deployment.byTargetId.useQuery({ resourceId });
const variables = api.deployment.variable.byTargetId.useQuery(resourceId);
const deployments = api.deployment.byTargetId.useQuery({ resourceId });
const variables = api.deployment.variable.byTargetId.useQuery({ resourceId });

Comment on lines 110 to 113
const resourceId = params.targetId;
const target = api.resource.byId.useQuery(resourceId);
const jobs = api.job.byResourceId.useQuery(resourceId);
const deployments = api.deployment.byTargetId.useQuery({ resourceId });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix error handling and standardize API parameters.

Two issues to address:

  1. The target query result is used in the notFound() check before confirming loading is complete.
  2. The API queries show inconsistent parameter passing patterns.
   const resourceId = params.targetId;
   const target = api.resource.byId.useQuery(resourceId);
   const jobs = api.job.byResourceId.useQuery(resourceId);
-  const deployments = api.deployment.byTargetId.useQuery({ resourceId });
+  const deployments = api.deployment.byTargetId.useQuery(resourceId);

   const unlockTarget = api.resource.unlock.useMutation();
   const lockTarget = api.resource.lock.useMutation();

   const utils = api.useUtils();

   const isLoading = target.isLoading || jobs.isLoading || deployments.isLoading;

-  if (!target.isLoading && target.data == null) notFound();
-  if (isLoading)
+  if (isLoading) {
     return (
       <div className="flex h-full w-full items-center justify-center">
         <IconLoader2 className="h-8 w-8 animate-spin" />
       </div>
     );
+  }
+  
+  if (target.data == null) {
+    notFound();
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const resourceId = params.targetId;
const target = api.resource.byId.useQuery(resourceId);
const jobs = api.job.byResourceId.useQuery(resourceId);
const deployments = api.deployment.byTargetId.useQuery({ resourceId });
const resourceId = params.targetId;
const target = api.resource.byId.useQuery(resourceId);
const jobs = api.job.byResourceId.useQuery(resourceId);
const deployments = api.deployment.byTargetId.useQuery(resourceId);
const unlockTarget = api.resource.unlock.useMutation();
const lockTarget = api.resource.lock.useMutation();
const utils = api.useUtils();
const isLoading = target.isLoading || jobs.isLoading || deployments.isLoading;
if (isLoading) {
return (
<div className="flex h-full w-full items-center justify-center">
<IconLoader2 className="h-8 w-8 animate-spin" />
</div>
);
}
if (target.data == null) {
notFound();
}

Comment on lines 28 to 30
const resourceId = targetId;
const jobs = api.job.byResourceId.useQuery(resourceId);
const deployments = api.deployment.byTargetId.useQuery({ resourceId });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Inconsistent parameter passing detected in API calls

There are inconsistencies in how resourceId is being passed to API queries:

  • api.job.byResourceId.useQuery() takes resourceId directly
  • api.deployment.byTargetId.useQuery() takes { resourceId } as an object
  • api.deployment.variable.byTargetId.useQuery() takes resourceId directly

Additionally, there's one instance in JobsContent.tsx still using targetId instead of resourceId:

const jobs = api.job.byResourceId.useQuery(targetId);
🔗 Analysis chain

Verify consistent usage of resourceId across the codebase.

Let's ensure the refactoring from targetId to resourceId is consistently applied across all components and API calls.

Also applies to: 110-113

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining instances of targetId in API calls and verify resourceId usage

# Check for remaining targetId usage in API calls
echo "Checking for targetId in API calls..."
rg -A 2 "api\.[a-zA-Z]+\.byTargetId\.useQuery" 

# Check for resourceId usage pattern
echo "Checking resourceId usage pattern..."
rg -A 2 "api\.[a-zA-Z]+\.byResourceId\.useQuery"

# Check for potential inconsistencies in parameter passing
echo "Checking parameter passing patterns..."
rg "\.useQuery\(\{.*resourceId" 

Length of output: 4944

const tg = await ctx.db
.select()
.from(resource)
.where(and(eq(resource.id, input), isNull(resource.deletedAt)))
.where(and(eq(resource.id, resourceId), isNull(resource.deletedAt)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Check for Existence of Resource Before Proceeding

After fetching the resource with resourceId, ensure that it exists (tg is not null) before using it. This prevents potential null reference errors if an invalid resourceId is provided.

Consider adding a check:

if (!tg) {
  throw new Error("Resource not found");
}

Comment on lines 710 to 712
deploymentIds != null
? inArray(deployment.id, deploymentIds)
: undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle Empty 'deploymentIds' Array in Filter Condition

Similarly, if deploymentIds is an empty array, the inArray condition will exclude all deployments. Ensure a length check is in place to prevent unintended filtering.

Modify the condition like this:

-                    deploymentIds != null
+                    deploymentIds != null && deploymentIds.length > 0
                       ? inArray(deployment.id, deploymentIds)
                       : undefined,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
deploymentIds != null
? inArray(deployment.id, deploymentIds)
: undefined,
deploymentIds != null && deploymentIds.length > 0
? inArray(deployment.id, deploymentIds)
: undefined,

Comment on lines 653 to 655
environmentIds != null
? inArray(environment.id, environmentIds)
: undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle Empty 'environmentIds' Array in Filter Condition

If environmentIds is provided as an empty array, the inArray condition will result in no environments being matched, which might not be the intended behavior. Add a length check to ensure the condition is only applied when environmentIds is not empty.

Update the filter condition as follows:

-                environmentIds != null
+                environmentIds != null && environmentIds.length > 0
                   ? inArray(environment.id, environmentIds)
                   : undefined,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
environmentIds != null
? inArray(environment.id, environmentIds)
: undefined,
environmentIds != null && environmentIds.length > 0
? inArray(environment.id, environmentIds)
: undefined,

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/ResourceVisualizationDiagram.tsx (1)

57-68: Consider performance and maintainability implications of nested data structure

The new structure embeds deployment data within environment nodes, which:

  1. Could impact performance if there are many deployments per environment
  2. Increases nesting level, potentially making debugging more challenging
  3. Might cause unnecessary re-renders if deployments change frequently

Consider extracting deployments to a separate state if they need frequent updates.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9d79f40 and f7583f4.

📒 Files selected for processing (1)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/ResourceVisualizationDiagram.tsx (3 hunks)
🔇 Additional comments (3)
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/ResourceVisualizationDiagram.tsx (3)

88-88: LGTM! Edge creation logic has been simplified

The edge creation has been streamlined to focus only on resource-to-environment and provider-to-resource relationships, making the visualization clearer and more maintainable.


91-91: Verify layout direction with various node configurations

The enforced left-to-right layout direction might affect readability with:

  • Large number of nodes
  • Deep hierarchies
  • Wide resource-to-environment relationships

Please test the visualization with different data sets to ensure the layout remains clear and usable.

Consider making the direction configurable based on:

-  const setReactFlowInstance = useLayoutAndFitView(nodes, { direction: "LR" });
+  const setReactFlowInstance = useLayoutAndFitView(nodes, { 
+    direction: window.innerWidth > window.innerHeight ? "LR" : "TB"
+  });

25-25: Verify if System type definition should be retained

The System type definition appears to be retained while the AI summary indicates that system concepts have been removed from the visualization logic. This might indicate an incomplete refactoring.

Let's verify the usage of System type in the codebase:

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/EnvironmentNode.tsx (3)

27-49: Consider enhancing accessibility for job status indicators.

While the component is well-structured, consider adding ARIA labels or role attributes to improve accessibility for users relying on screen readers, especially for the job status indicators.

-      <div className="flex items-center gap-2">
+      <div 
+        className="flex items-center gap-2"
+        role="status"
+        aria-label={`Job status: ${JobStatusReadable[job.status]}`}
+      >

77-82: Enhance status visualization beyond just border colors.

Using only border colors for status indication may not be sufficient for accessibility and UX. Consider adding icons or badges to make the status more prominent.

   className={cn(
     "relative flex min-w-[250px] flex-col gap-2 rounded-md border border-neutral-800 bg-neutral-900/30 px-4 py-3",
-    isInProgress && "border-blue-500",
-    isPending && "border-neutral-500",
-    isCompleted && "border-green-500",
+    isInProgress && "border-blue-500 before:content-['In_Progress'] before:absolute before:-top-2 before:left-2 before:text-xs before:bg-blue-500/10 before:px-2 before:rounded",
+    isPending && "border-neutral-500 before:content-['Pending'] before:absolute before:-top-2 before:left-2 before:text-xs before:bg-neutral-500/10 before:px-2 before:rounded",
+    isCompleted && "border-green-500 before:content-['Completed'] before:absolute before:-top-2 before:left-2 before:text-xs before:bg-green-500/10 before:px-2 before:rounded",
   )}

98-113: Optimize rendering performance.

The mapping operation inside the render function could benefit from memoization to prevent unnecessary re-renders.

+  const memoizedDeployments = React.useMemo(
+    () =>
+      data.environment.deployments.map((deployment) => {
+        const latestActiveRelease = latestActiveReleases.find(
+          (r) => r.releaseJobTrigger.release.deploymentId === deployment.id,
+        );
+        return (
+          <DeploymentCard
+            key={deployment.id}
+            deploymentName={deployment.name}
+            job={latestActiveRelease?.releaseJobTrigger.job}
+            releaseVersion={
+              latestActiveRelease?.releaseJobTrigger.release.version ?? ""
+            }
+          />
+        );
+      }),
+    [data.environment.deployments, latestActiveReleases]
+  );

   {!latestActiveReleasesQ.isLoading &&
-    data.environment.deployments.map((deployment) => {
-      const latestActiveRelease = latestActiveReleases.find(
-        (r) =>
-          r.releaseJobTrigger.release.deploymentId === deployment.id,
-      );
-      return (
-        <DeploymentCard
-          key={deployment.id}
-          deploymentName={deployment.name}
-          job={latestActiveRelease?.releaseJobTrigger.job}
-          releaseVersion={
-            latestActiveRelease?.releaseJobTrigger.release.version ?? ""
-          }
-        />
-      );
-    })}
+    memoizedDeployments}
packages/db/src/schema/resource.ts (1)

275-286: Consider adding foreign key constraint and audit fields.

While the basic table structure is good, consider these improvements:

  1. Add a foreign key constraint on resourceIdentifier to maintain referential integrity with resources
  2. Add created_at and updated_at timestamps for auditing purposes
 export const jobResourceRelationship = pgTable(
   "job_resource_relationship",
   {
     id: uuid("id").primaryKey().defaultRandom(),
     jobId: uuid("job_id")
       .references(() => job.id, { onDelete: "cascade" })
       .notNull(),
-    resourceIdentifier: text("resource_identifier").notNull(),
+    resourceIdentifier: text("resource_identifier")
+      .references(() => resource.identifier)
+      .notNull(),
+    createdAt: timestamp("created_at", { withTimezone: true })
+      .notNull()
+      .defaultNow(),
+    updatedAt: timestamp("updated_at", { withTimezone: true })
+      .$onUpdate(() => new Date()),
   },
   (t) => ({
     uniq: uniqueIndex().on(t.jobId, t.resourceIdentifier),
   }),
 );
packages/api/src/router/deployment.ts (2)

674-674: Consider implementing pagination

While adding a limit of 500 records helps prevent excessive data retrieval, consider implementing proper pagination using cursor-based or offset-based pagination for better scalability and user experience.

Example implementation:

-.limit(500)
+.offset(input.offset ?? 0)
+.limit(input.limit ?? 50)

And update the input type:

.input(z.object({
  id: z.string().uuid(),
  offset: z.number().min(0).optional(),
  limit: z.number().min(1).max(100).optional()
}))

Based on the search results, I can now generate the final response since I have found all the job statuses defined in the codebase:

Consider including Failed and Cancelled statuses in the job status filter

The current job status filtering includes Completed, Pending, and InProgress, but it's missing important operational statuses that are defined and used in the codebase:

  • Failure - Used to track failed jobs
  • Cancelled - Used to track cancelled jobs
  • Skipped - Used to track skipped jobs

Including these additional statuses would provide a more complete operational view of the deployment status.

🔗 Analysis chain

Line range hint 664-673: Consider handling additional job statuses

The current job status filtering includes Completed, Pending, and InProgress, but consider whether other statuses like Failed or Cancelled should be included for a complete operational view.

Let's check if there are any other job statuses in use:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for JobStatus enum usage across the codebase
ast-grep --pattern 'JobStatus.$_'

Length of output: 42989

packages/api/src/router/resources.ts (1)

362-449: LGTM! Authorization and input validation are properly implemented.

The implementation correctly handles permissions, validates input, and uses proper SQL query builder patterns to prevent SQL injection.

Consider adding an index on (deployment_id, created_at) to optimize the rank calculation in the subquery, as this operation could be expensive for large datasets. The query uses this combination frequently in the window function:

ROW_NUMBER() OVER (PARTITION BY release.deployment_id ORDER BY release.created_at DESC)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7905c34 and 47c2446.

📒 Files selected for processing (10)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/page.tsx (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/variables/page.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/EnvironmentNode.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/DeploymentContent.tsx (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/VariablesContent.tsx (1 hunks)
  • packages/api/src/router/deployment.ts (3 hunks)
  • packages/api/src/router/resources.ts (2 hunks)
  • packages/db/drizzle/0042_absent_cerebro.sql (1 hunks)
  • packages/db/drizzle/meta/_journal.json (1 hunks)
  • packages/db/src/schema/resource.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/page.tsx
  • apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/variables/page.tsx
  • apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/DeploymentContent.tsx
  • apps/webservice/src/app/[workspaceSlug]/(app)/_components/target-drawer/VariablesContent.tsx
  • packages/db/drizzle/meta/_journal.json
🔇 Additional comments (10)
packages/db/drizzle/0042_absent_cerebro.sql (3)

8-12: LGTM! Foreign key constraint with appropriate cascade behavior.

The constraint is well-defined with proper cascade behavior and includes idempotency handling.


1-5: LGTM! Verify cascade behavior for resource deletion.

The table schema is well-structured with appropriate data types and constraints.

Let's verify if resources have cascade delete behavior to prevent orphaned relationships:

✅ Verification successful

Cascade delete behavior is properly configured

The migration correctly sets up cascade delete behavior with ON DELETE cascade in the foreign key constraint job_resource_relationship_job_id_job_id_fk. This ensures that when a job is deleted, its associated resource relationships will be automatically removed, preventing orphaned records.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if resources table has cascade delete behavior
rg -A 10 'CREATE TABLE.*resource.*' 

Length of output: 3139


Script:

#!/bin/bash
# Let's check if there's a foreign key constraint with cascade delete in the job table
rg -A 10 'CREATE TABLE.*job"' 

Length of output: 908


14-14: LGTM! Verify index usage in application queries.

The unique composite index is well-designed and will prevent duplicate relationships while optimizing queries.

Let's verify the application code uses this index effectively:

✅ Verification successful

Index design is appropriate for the schema definition

The unique index on job_resource_relationship(job_id, resource_identifier) aligns well with the table schema and its usage patterns:

  • The table definition shows these columns are marked as notNull and have a composite unique constraint
  • The index matches the foreign key relationship with the job table
  • The schema suggests lookups will be primarily by job_id, making it an efficient leading column
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if queries in the codebase will utilize this index
# Look for queries involving job_id and resource_identifier
rg -A 5 'job.*resource.*identifier|resource.*job.*id' --type typescript

Length of output: 108


Script:

#!/bin/bash
# Search for SQL queries or database operations involving job_resource_relationship table
rg -l "job_resource_relationship"

# Then examine the specific files for query patterns
rg -A 5 "FROM.*job_resource_relationship|JOIN.*job_resource_relationship|INSERT.*job_resource_relationship|SELECT.*job_resource_relationship" 

Length of output: 300


Script:

#!/bin/bash
# Let's examine the schema definition and any query builders in the resource.ts file
cat packages/db/src/schema/resource.ts

Length of output: 9500

apps/webservice/src/app/[workspaceSlug]/(app)/(targets)/targets/[targetId]/visualize/nodes/EnvironmentNode.tsx (2)

1-16: LGTM! Imports and setup are well-organized.

The imports are properly structured and the "use client" directive is correctly placed.


17-25: LGTM! Types are well-defined and provide good type safety.

The Environment and EnvironmentNodeProps types correctly model the relationships and required data.

packages/db/src/schema/resource.ts (2)

34-34: LGTM!

The import of the job schema is correctly added to support the new job-resource relationship.


275-286: Verify data migration from deploymentResourceRelationship.

Since this table replaces deploymentResourceRelationship, ensure there's a proper data migration strategy in place.

✅ Verification successful

The previous search didn't yield results, so I'm broadening the search to look for recent migrations, references to the new table, and recent changes to understand the context better. This will help determine if this is a new table addition or a replacement of an existing one.


Migration is properly handled - no action needed

The migration files show a clear transition strategy:

  1. Creation of new job_resource_relationship table
  2. Explicit dropping of old deployment_resource_relationship table
  3. Proper foreign key constraints and indexes are set up
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for migration files and verify table existence

# Check for migration files that handle the table transition
echo "Checking for relevant migration files..."
fd --type f ".*deployment.*resource.*relationship.*" packages/db/drizzle/

# Verify if old table still exists in schema
echo "Checking for old table definition..."
rg "deploymentResourceRelationship" packages/db/src/schema/

# Check for any remaining references to the old table
echo "Checking for remaining references to old table..."
rg "deployment.*resource.*relationship" --type ts

Length of output: 470


Script:

#!/bin/bash
# Let's check for any recent migrations that might be related to this change
echo "Checking recent migration files..."
fd --type f "\.sql$" packages/db/drizzle/ --exec head -n 20 {}

# Let's also check for any references to job_resource_relationship
echo "Checking references to new table..."
rg "job.*resource.*relationship" --type ts -A 3

# Let's check git history for recent changes related to this
echo "Checking recent changes..."
git log --oneline -n 5 -- packages/db/

Length of output: 18346

packages/api/src/router/deployment.ts (2)

373-373: LGTM: Addition of resourceId to query projection

The addition of resourceId to the select statement enhances the query's data retrieval capabilities and aligns with the schema requirements.


680-688: LGTM: Proper null handling for releaseJobTrigger

The implementation correctly handles the nullable release_job_trigger with proper type assertions. The non-null assertions are safe here due to the where clause conditions.

packages/api/src/router/resources.ts (1)

482-486: LGTM! Function parameters are correctly ordered.

The environmentHasResource function call maintains proper parameter ordering and type safety.

"resource_identifier" text NOT NULL
);
--> statement-breakpoint
DROP TABLE "deployment_resource_relationship";--> statement-breakpoint
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider data migration before dropping the table.

This is a breaking change that will permanently delete all deployment-resource relationships. Consider adding a data migration step to preserve existing relationships by converting them to job-resource relationships if applicable.

Example migration approach:

  1. Create new table (done)
  2. Migrate relevant data from deployment relationships to job relationships
  3. Verify data consistency
  4. Then drop the old table

Comment on lines +54 to +60
const resourceId = data.environment.resource.id;
const environmentId = data.environment.id;
const latestActiveReleasesQ =
api.resource.activeReleases.byResourceAndEnvironmentId.useQuery(
{ resourceId, environmentId },
{ refetchInterval: 5_000 },
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for the TRPC query.

The query lacks error handling which could lead to a poor user experience if the API request fails.

   const latestActiveReleasesQ =
     api.resource.activeReleases.byResourceAndEnvironmentId.useQuery(
       { resourceId, environmentId },
-      { refetchInterval: 5_000 },
+      { 
+        refetchInterval: 5_000,
+        retry: 3,
+        onError: (error) => {
+          console.error('Failed to fetch active releases:', error);
+          // Add error notification/handling here
+        }
+      },
     );

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +680 to 689
releaseJobTrigger:
row.release_job_trigger != null
? {
...row.release_job_trigger,
job: row.job!,
release: row.release!,
resourceId: row.resource.id,
}
: null,
})),
Copy link
Member

@jsbroks jsbroks Nov 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we convert this to with query builder?

@adityachoudhari26 adityachoudhari26 merged commit 5e07f60 into main Nov 25, 2024
9 of 10 checks passed
@adityachoudhari26 adityachoudhari26 deleted the visualization-diagram-v2 branch November 25, 2024 02:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants