-
Notifications
You must be signed in to change notification settings - Fork 11
feat: resource deployments UI #616
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
Conversation
|
Caution Review failedThe pull request is closed. WalkthroughThis update introduces a new deployment management UI and backend for release targets. It adds granular version pinning, force deploy, and job status features, replaces the release history table with a tile-based deployments overview, and implements new API endpoints for listing, pinning, unpinning, and forcibly deploying versions. Several new React components and backend procedures support these capabilities. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant WebApp
participant API
participant DB
participant Queue
User->>WebApp: Navigate to Deployments page
WebApp->>API: Fetch release targets
API->>DB: Query releaseTarget (with joins)
DB-->>API: Release target data
API-->>WebApp: Release target data
WebApp->>API: Fetch versions and jobs for release target
API->>DB: Query deploymentVersion, job tables
DB-->>API: Version/job data
API-->>WebApp: Version/job data
User->>WebApp: Click "Pin Version" or "Force Deploy"
WebApp->>API: Call pinVersion/forceDeployVersion
API->>DB: Update or insert pin/force deploy records
API->>Queue: Enqueue evaluation or deploy job
Queue-->>API: Ack
API-->>WebApp: Success response
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: .coderabbit.yaml 📒 Files selected for processing (3)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (4)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (2)
14-15: Consider adding content or semantic meaning to empty table cells.The component has empty
TableCellelements that might indicate missing functionality or create accessibility issues. Consider adding appropriate content, using proper table headers, or adding semantic attributes if these cells are intentionally empty.Also applies to: 25-25
13-13: Fixed height may cause layout issues with varying content.The fixed height of
49pxmight cause content overflow or layout inconsistencies if job data varies significantly. Consider using flexible sizing or ensuring content constraints.packages/api/src/router/release-target-version/utils.ts (1)
5-9: Consider consolidating duplicate type definitions.The
ReleaseTargettype is defined both here and inapps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts. Consider moving this to a shared location or importing from a common types file to maintain consistency and avoid duplication.apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/ForceDeployVersion.tsx (1)
21-48: Consider using async/await for cleaner error handling.The promise chaining works but could be more readable with async/await pattern.
- const onSubmit = () => - forceDeploy - .mutateAsync({ releaseTargetId, versionId }) - .then(() => setOpen(false)) - .then(() => router.refresh()) - .then(() => invalidate()) - .then(() => - toast.success(`Force deployed ${releaseTarget.resource.name}`), - ) - .catch(() => - toast.error(`Failed to force deploy ${releaseTarget.resource.name}`), - ); + const onSubmit = async () => { + try { + await forceDeploy.mutateAsync({ releaseTargetId, versionId }); + setOpen(false); + router.refresh(); + await invalidate(); + toast.success(`Force deployed ${releaseTarget.resource.name}`); + } catch { + toast.error(`Failed to force deploy ${releaseTarget.resource.name}`); + } + };
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (29)
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/EnvironmentTableRow.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx(3 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/ReleaseTargetRow.tsx(8 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/_components/job/JobLinks.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/ForceDeployVersion.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/HeaderRow.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionDropdown.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionPinning.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/layout.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/page.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/useVersionSearch.ts(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseHistoryTable.tsx(0 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx(1 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/page.tsx(2 hunks)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/layout.tsx(2 hunks)apps/webservice/src/app/[workspaceSlug]/sidebars.ts(1 hunks)apps/webservice/src/app/urls.ts(1 hunks)packages/api/src/router/release-target-version/force-deploy-version.ts(1 hunks)packages/api/src/router/release-target-version/in-progress-version.ts(1 hunks)packages/api/src/router/release-target-version/latest-version.ts(1 hunks)packages/api/src/router/release-target-version/list-deployable-versions.ts(1 hunks)packages/api/src/router/release-target-version/router.ts(1 hunks)packages/api/src/router/release-target-version/utils.ts(1 hunks)packages/api/src/router/release-target-version/version-pinning.ts(1 hunks)packages/api/src/router/release-target.ts(1 hunks)
💤 Files with no reviewable changes (1)
- apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseHistoryTable.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- CLAUDE.md
⚙️ CodeRabbit Configuration File
**/*.{js,jsx,ts,tsx}
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- CLAUDE.md
**/*.{js,jsx,ts,tsx,json,css,md,yml,yaml}
Instructions used from:
Sources:
📄 CodeRabbit Inference Engine
- CLAUDE.md
🧠 Learnings (29)
📓 Common learnings
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: e2e/tests/api/policies/retry-policy.spec.ts:23-24
Timestamp: 2025-06-24T23:52:50.732Z
Learning: The user adityachoudhari26 prefers not to add null safety checks or defensive programming in test code, particularly in e2e tests, as they prioritize simplicity and focus on the main functionality being tested rather than comprehensive error handling within the test itself.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: e2e/tests/api/policies/retry-policy.spec.ts:117-130
Timestamp: 2025-06-24T23:53:25.398Z
Learning: User adityachoudhari26 prefers to keep non-null assertions in e2e test code without extensive null safety checks, reasoning that test failures serve the same purpose of catching issues and the extra validation doesn't add much value in test contexts.
apps/webservice/src/app/[workspaceSlug]/sidebars.ts (2)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/auth/src/utils/rbac.ts:102-118
Timestamp: 2024-10-29T02:05:46.185Z
Learning: The `releaseChannel` scope type is included in the `scopeType` enum in `packages/db/src/schema/rbac.ts`.
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/EnvironmentTableRow.tsx (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/EnvironmentDrawer.tsx:139-154
Timestamp: 2024-11-01T02:36:23.101Z
Learning: In `EnvironmentDrawer.tsx`, for the `EnvironmentDrawer` component, when there are only a few `TabButton` instances (e.g., 3), it's acceptable to define them individually without extracting them into a configuration to reduce repetition.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#287
File: packages/validators/src/jobs/conditions/status-condition.ts:4-4
Timestamp: 2025-01-21T19:52:22.838Z
Learning: In apps/webservice/src/app/api/github/webhook/workflow/handler.ts, the external "completed" status is intentionally mapped to JobStatus.Successful to handle GitHub workflow status conversions.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/layout.tsx (2)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
packages/api/src/router/release-target-version/router.ts (3)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/page.tsx (5)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, dynamic route parameters (params) return Promises instead of direct values in async contexts. When accessing properties like `params.deploymentId` in an async function, use `(await params).deploymentId` to avoid the "params should be awaited before using its properties" error. This applies to API routes, page components, and other async contexts.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, params in dynamic routes must be awaited before accessing their properties in async contexts. For example, `params.deploymentId` should be accessed as `(await params).deploymentId` in async functions.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
packages/api/src/router/release-target-version/in-progress-version.ts (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#604
File: packages/rule-engine/src/manager/version-manager.ts:124-139
Timestamp: 2025-06-30T21:19:43.866Z
Learning: In packages/rule-engine/src/manager/version-manager.ts, the findDesiredVersion method should use takeFirst (not takeFirstOrNull) because if a desiredVersionId is set but the query fails to find exactly one matching version, it indicates a data integrity or configuration issue that should fail loudly rather than be handled silently.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#500
File: packages/db/src/schema/job.ts:117-120
Timestamp: 2025-04-21T18:34:54.764Z
Learning: In the system's job schema, the relationship between job and releaseJob is a true one-to-one relationship - a release job should only ever point to one job and vice versa. The implementation uses `one(releaseJob, ...)` in the jobRelations to reflect this business rule.
apps/webservice/src/app/[workspaceSlug]/(app)/_components/job/JobLinks.tsx (3)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (11)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/auth/src/utils/rbac.ts:102-118
Timestamp: 2024-10-29T02:05:46.185Z
Learning: The `releaseChannel` scope type is included in the `scopeType` enum in `packages/db/src/schema/rbac.ts`.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: CR
PR: ctrlplanedev/ctrlplane#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-30T21:36:42.935Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript with explicit types (prefer interfaces for public APIs)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
Learnt from: CR
PR: ctrlplanedev/ctrlplane#0
File: CLAUDE.md:0-0
Timestamp: 2025-06-30T21:36:42.935Z
Learning: Applies to **/*.{ts,tsx} : Consistent type imports: `import type { Type } from "module"`
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#363
File: apps/webservice/tsconfig.json:14-15
Timestamp: 2025-03-09T08:56:53.603Z
Learning: In the ctrlplane project, they use Next.js standalone output mode, which means they intentionally exclude `.next/types` in their tsconfig.json despite including `.next/types/**/*.ts` in their include pattern.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#579
File: packages/db/src/schema/rules/concurrency.ts:0-0
Timestamp: 2025-06-01T19:10:11.535Z
Learning: In the ctrlplane codebase, when defining database schemas with Drizzle ORM, it's an intentional pattern to spread base fields (like `basePolicyRuleFields`) and then redefine specific fields to add additional constraints (like unique constraints or foreign key references). The TypeScript field overwriting behavior is deliberately used to override base field definitions with more specific requirements.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#500
File: packages/db/src/schema/job.ts:117-120
Timestamp: 2025-04-21T18:34:54.764Z
Learning: In the system's job schema, the relationship between job and releaseJob is a true one-to-one relationship - a release job should only ever point to one job and vice versa. The implementation uses `one(releaseJob, ...)` in the jobRelations to reflect this business rule.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/useVersionSearch.ts (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, dynamic route parameters (params) return Promises instead of direct values in async contexts. When accessing properties like `params.deploymentId` in an async function, use `(await params).deploymentId` to avoid the "params should be awaited before using its properties" error. This applies to API routes, page components, and other async contexts.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, params in dynamic routes must be awaited before accessing their properties in async contexts. For example, `params.deploymentId` should be accessed as `(await params).deploymentId` in async functions.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
packages/api/src/router/release-target-version/utils.ts (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/auth/src/utils/rbac.ts:102-118
Timestamp: 2024-10-29T02:05:46.185Z
Learning: The `releaseChannel` scope type is included in the `scopeType` enum in `packages/db/src/schema/rbac.ts`.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#395
File: packages/api/src/router/environment-page/resources/router.ts:40-45
Timestamp: 2025-03-24T18:46:38.894Z
Learning: The `takeFirst` utility function in the codebase (from `@ctrlplane/db`) throws an Error with message "Found non unique or inexistent value" if the result array doesn't contain exactly one element, making additional null/undefined checks unnecessary after its use.
apps/webservice/src/app/urls.ts (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:382-390
Timestamp: 2024-11-27T23:18:59.456Z
Learning: In the codebase, releases are not scoped to a specific resource.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#236
File: packages/api/src/router/workspace-integrations.ts:222-231
Timestamp: 2024-12-02T01:47:59.631Z
Learning: In `packages/api/src/router/workspace-integrations.ts`, when creating IAM policies for roles that need to assume customer-provided roles with unknown ARNs, it's acceptable to keep `Resource` as `"*"` in the policy document, while limiting the `Action` to `"sts:AssumeRole"`, since ARNs are not known in advance.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/page.tsx (8)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
packages/api/src/router/release-target-version/latest-version.ts (3)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#604
File: packages/rule-engine/src/manager/version-manager.ts:124-139
Timestamp: 2025-06-30T21:19:43.866Z
Learning: In packages/rule-engine/src/manager/version-manager.ts, the findDesiredVersion method should use takeFirst (not takeFirstOrNull) because if a desiredVersionId is set but the query fails to find exactly one matching version, it indicates a data integrity or configuration issue that should fail loudly rather than be handled silently.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionDropdown.tsx (6)
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#183
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx:46-57
Timestamp: 2024-10-30T00:03:57.878Z
Learning: Accessibility and validation feedback improvements are not desired for form fields in the `Overview` component within `apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx`.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/EnvironmentDrawer.tsx:139-154
Timestamp: 2024-11-01T02:36:23.101Z
Learning: In `EnvironmentDrawer.tsx`, for the `EnvironmentDrawer` component, when there are only a few `TabButton` instances (e.g., 3), it's acceptable to define them individually without extracting them into a configuration to reduce repetition.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/HeaderRow.tsx (3)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/ForceDeployVersion.tsx (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
packages/api/src/router/release-target-version/version-pinning.ts (2)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/layout.tsx (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, dynamic route parameters (params) return Promises instead of direct values in async contexts. When accessing properties like `params.deploymentId` in an async function, use `(await params).deploymentId` to avoid the "params should be awaited before using its properties" error. This applies to API routes, page components, and other async contexts.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#382
File: apps/webservice/src/app/api/v1/deployments/[deploymentId]/route.ts:82-88
Timestamp: 2025-03-16T19:41:44.129Z
Learning: In Next.js 15, params in dynamic routes must be awaited before accessing their properties in async contexts. For example, `params.deploymentId` should be accessed as `(await params).deploymentId` in async functions.
packages/api/src/router/release-target-version/list-deployable-versions.ts (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#604
File: packages/rule-engine/src/manager/version-manager.ts:124-139
Timestamp: 2025-06-30T21:19:43.866Z
Learning: In packages/rule-engine/src/manager/version-manager.ts, the findDesiredVersion method should use takeFirst (not takeFirstOrNull) because if a desiredVersionId is set but the query fails to find exactly one matching version, it indicates a data integrity or configuration issue that should fail loudly rather than be handled silently.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
packages/api/src/router/release-target-version/force-deploy-version.ts (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#604
File: packages/rule-engine/src/manager/version-manager.ts:124-139
Timestamp: 2025-06-30T21:19:43.866Z
Learning: In packages/rule-engine/src/manager/version-manager.ts, the findDesiredVersion method should use takeFirst (not takeFirstOrNull) because if a desiredVersionId is set but the query fails to find exactly one matching version, it indicates a data integrity or configuration issue that should fail loudly rather than be handled silently.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#500
File: packages/db/src/schema/job.ts:117-120
Timestamp: 2025-04-21T18:34:54.764Z
Learning: In the system's job schema, the relationship between job and releaseJob is a true one-to-one relationship - a release job should only ever point to one job and vice versa. The implementation uses `one(releaseJob, ...)` in the jobRelations to reflect this business rule.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#579
File: packages/rule-engine/src/rules/concurrency-rule.ts:8-11
Timestamp: 2025-06-01T19:10:47.122Z
Learning: In packages/rule-engine/src/rules/concurrency-rule.ts, the ConcurrencyRule should remain simple without additional validation since database and Zod schemas already handle concurrency validation. The user prefers this rule to be "dumb" and just perform the comparison check rather than duplicating validation logic.
packages/api/src/router/release-target.ts (5)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: packages/api/src/router/job.ts:362-365
Timestamp: 2024-11-27T23:18:42.055Z
Learning: In the file `packages/api/src/router/job.ts`, the function `releaseMatchesCondition` returns undefined if the `filter` parameter is null. This behavior ensures that when constructing the query with `and(...)`, the condition is omitted, allowing the query to function correctly even if there is no release channel associated with the environment.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: packages/api/src/router/deployment.ts:144-161
Timestamp: 2024-11-01T02:37:25.510Z
Learning: In `packages/api/src/router/deployment.ts`, when using Drizzle ORM, there is a limitation when referencing the same table twice in a relational builder query (rbq), requiring separate queries to avoid issues.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/auth/src/utils/rbac.ts:102-118
Timestamp: 2024-10-29T02:05:46.185Z
Learning: The `releaseChannel` scope type is included in the `scopeType` enum in `packages/db/src/schema/rbac.ts`.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#515
File: apps/webservice/src/app/api/v1/release-targets/[releaseTargetId]/releases/route.ts:103-108
Timestamp: 2025-04-28T18:41:58.813Z
Learning: In this project, full records from the `deployment` and `deployment_version` tables are considered safe for public API consumption, and there's no need to create restricted DTOs for them.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/ReleaseTargetRow.tsx (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#578
File: apps/webservice/src/app/[workspaceSlug]/(app)/resources/(sidebar)/providers/integrations/github/GithubDialog.tsx:58-58
Timestamp: 2025-05-30T21:48:48.868Z
Learning: In the ctrlplane codebase, the shadcn form UI version allows initializing forms with `useForm({ schema: formSchema })` directly, without needing to import and use `zodResolver` from '@hookform/resolvers/zod'. This is different from standard react-hook-form usage.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/EnvironmentDrawer.tsx:139-154
Timestamp: 2024-11-01T02:36:23.101Z
Learning: In `EnvironmentDrawer.tsx`, for the `EnvironmentDrawer` component, when there are only a few `TabButton` instances (e.g., 3), it's acceptable to define them individually without extracting them into a configuration to reduce repetition.
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#183
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx:28-34
Timestamp: 2024-10-30T00:03:58.927Z
Learning: In the Ctrlplane project, error handling for API mutations in React components is not required unless specified by the user.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#363
File: apps/webservice/tsconfig.json:14-15
Timestamp: 2025-03-09T08:56:53.603Z
Learning: In the ctrlplane project, they use Next.js standalone output mode, which means they intentionally exclude `.next/types` in their tsconfig.json despite including `.next/types/**/*.ts` in their include pattern.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionPinning.tsx (4)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx (6)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#287
File: packages/validators/src/jobs/conditions/status-condition.ts:4-4
Timestamp: 2025-01-21T19:52:22.838Z
Learning: In apps/webservice/src/app/api/github/webhook/workflow/handler.ts, the external "completed" status is intentionally mapped to JobStatus.Successful to handle GitHub workflow status conversions.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#183
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx:46-57
Timestamp: 2024-10-30T00:03:57.878Z
Learning: Accessibility and validation feedback improvements are not desired for form fields in the `Overview` component within `apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/Overview.tsx`.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx (8)
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx:42-44
Timestamp: 2024-11-01T02:35:07.352Z
Learning: In `apps/webservice/src/app/[workspaceSlug]/_components/release-channel-drawer/Usage.tsx`, within the `Usage` component, the arrays used for filtering inherited environments are expected to remain small. Therefore, performance optimizations for this filtering logic are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#237
File: apps/webservice/src/app/[workspaceSlug]/(app)/_components/deployment-resource-drawer/DeploymentResourceDrawer.tsx:43-50
Timestamp: 2024-11-27T23:16:35.580Z
Learning: In `DeploymentResourceDrawer.tsx`, the `isOpen` variable already checks whether `deploymentId`, `environmentId`, and `resourceId` are non-null, so additional null checks in query `enabled` conditions are not necessary.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#181
File: packages/api/src/router/deployment.ts:116-131
Timestamp: 2024-10-29T02:04:50.312Z
Learning: In `packages/api/src/router/deployment.ts`, the `list.byDeploymentId` procedure requires multiple database queries due to limitations of the `releaseMatchesCondition` function.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: zacharyblasczyk
PR: ctrlplanedev/ctrlplane#408
File: apps/webservice/src/components/form/job-agent/JobAgentJenkinsPipelineConfig.tsx:26-31
Timestamp: 2025-04-12T22:08:13.790Z
Learning: For Jenkins job configuration, two approaches are needed: (1) a simple URL input form for airgapped environments (current focus) and (2) a dropdown selection interface for non-airgapped environments where the Jenkins server is accessible. A component similar to DeploymentJobAgentGithubConfig.tsx is preferred.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#187
File: apps/jobs/src/ephemeral-env-checker/index.ts:57-0
Timestamp: 2024-10-30T23:10:58.869Z
Learning: In the codebase, deployments are decoupled from environments. When deleting environments (e.g., in `apps/jobs/src/ephemeral-env-checker/index.ts`), associated deployments should not be deleted.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#188
File: apps/webservice/src/app/[workspaceSlug]/_components/environment-drawer/EnvironmentDrawer.tsx:139-154
Timestamp: 2024-11-01T02:36:23.101Z
Learning: In `EnvironmentDrawer.tsx`, for the `EnvironmentDrawer` component, when there are only a few `TabButton` instances (e.g., 3), it's acceptable to define them individually without extracting them into a configuration to reduce repetition.
Learnt from: adityachoudhari26
PR: ctrlplanedev/ctrlplane#601
File: packages/job-dispatch/src/job-update.ts:264-270
Timestamp: 2025-06-24T23:56:54.799Z
Learning: In this codebase, the `Tx` type is just an alias for the database client type (`Omit<typeof db, "$client">`) and does not necessarily indicate an active transaction context. Functions like `createReleaseJob` need to be called within a transaction, which is why they are wrapped with `db.transaction()` even when the parameter is typed as `Tx`. Drizzle supports nested transactions via breakpoints, so additional transaction wrappers are safe even if already within a transaction.
🧬 Code Graph Analysis (14)
packages/api/src/router/release-target-version/router.ts (6)
packages/api/src/trpc.ts (1)
createTRPCRouter(55-55)packages/api/src/router/release-target-version/in-progress-version.ts (1)
inProgressVersion(10-50)packages/api/src/router/release-target-version/latest-version.ts (1)
latestVersion(10-46)packages/api/src/router/release-target-version/list-deployable-versions.ts (1)
listDeployableVersions(107-154)packages/api/src/router/release-target-version/version-pinning.ts (2)
pinVersion(11-45)unpinVersion(47-71)packages/api/src/router/release-target-version/force-deploy-version.ts (1)
forceDeployVersion(94-123)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/page.tsx (2)
packages/db/src/schema/release.ts (1)
releaseTarget(21-47)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx (1)
ReleaseTargetVersionsTable(86-118)
packages/api/src/router/release-target-version/in-progress-version.ts (3)
packages/api/src/trpc.ts (1)
protectedProcedure(173-173)packages/db/src/schema/job.ts (1)
JobStatus(149-149)packages/db/src/common.ts (1)
takeFirstOrNull(15-20)
apps/webservice/src/app/[workspaceSlug]/(app)/_components/job/JobLinks.tsx (1)
packages/ui/src/button.tsx (1)
buttonVariants(80-80)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (3)
packages/ui/src/table.tsx (2)
TableRow(117-117)TableCell(118-118)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx (1)
JobStatusCell(9-25)packages/db/src/schema/job.ts (1)
job(75-108)
packages/api/src/router/release-target-version/utils.ts (3)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (1)
ReleaseTarget(3-7)packages/db/src/client.ts (1)
db(15-15)packages/db/src/common.ts (1)
takeFirst(9-13)
apps/webservice/src/app/urls.ts (2)
packages/db/src/schema/release.ts (1)
releaseTarget(21-47)packages/db/src/schema/resource.ts (1)
resource(58-86)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/page.tsx (1)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx (1)
ReleaseTargetTile(121-159)
packages/api/src/router/release-target-version/latest-version.ts (3)
packages/api/src/trpc.ts (1)
protectedProcedure(173-173)packages/db/src/schema/job.ts (1)
JobStatus(149-149)packages/db/src/common.ts (1)
takeFirstOrNull(15-20)
packages/api/src/router/release-target-version/force-deploy-version.ts (9)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (1)
ReleaseTarget(3-7)packages/api/src/router/release-target-version/utils.ts (2)
ReleaseTarget(5-9)getReleaseTarget(11-36)packages/db/src/client.ts (1)
db(15-15)packages/db/src/common.ts (2)
takeFirstOrNull(15-20)takeFirst(9-13)packages/rule-engine/src/manager/version-manager.ts (1)
VersionReleaseManager(35-233)packages/rule-engine/src/manager/variable-manager.ts (1)
VariableReleaseManager(17-148)packages/api/src/trpc.ts (1)
protectedProcedure(173-173)packages/db/src/queries/create-release-job.ts (1)
createReleaseJob(19-95)packages/events/src/index.ts (1)
getQueue(28-34)
packages/api/src/router/release-target.ts (3)
packages/api/src/trpc.ts (2)
createTRPCRouter(55-55)protectedProcedure(173-173)packages/api/src/router/release-target-version/router.ts (1)
releaseTargetVersionRouter(8-15)packages/db/src/common.ts (1)
takeFirstOrNull(15-20)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx (9)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (2)
Version(10-10)ReleaseTarget(3-7)apps/webservice/src/app/[workspaceSlug]/(app)/_components/CollapsibleRow.tsx (1)
CollapsibleRow(7-24)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/HeaderRow.tsx (1)
HeaderRow(74-104)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionDropdown.tsx (1)
VersionDropdown(24-93)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (1)
JobRow(8-26)packages/ui/src/skeleton.tsx (1)
Skeleton(15-15)packages/ui/src/table.tsx (5)
TableHeader(113-113)TableRow(117-117)TableHead(116-116)Table(112-112)TableBody(114-114)apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/useVersionSearch.ts (1)
useVersionSearch(4-18)apps/webservice/src/app/[workspaceSlug]/(app)/_components/CollapsibleSearchInput.tsx (1)
CollapsibleSearchInput(9-48)
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx (2)
packages/ui/src/tooltip.tsx (4)
TooltipProvider(30-30)Tooltip(30-30)TooltipTrigger(30-30)TooltipContent(30-30)packages/ui/src/skeleton.tsx (1)
Skeleton(15-15)
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx (3)
packages/db/src/schema/job.ts (1)
JobStatus(149-149)packages/ui/src/table.tsx (1)
TableCell(118-118)apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx (1)
PolicyEvaluationTooltip(161-215)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Typecheck
- GitHub Check: Lint
- GitHub Check: build (linux/amd64)
🔇 Additional comments (44)
apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/PolicyEvaluationTooltip.tsx (3)
123-152: LGTM - Well-structured policy evaluation logic.The
getIsPassingAllRuleshelper function correctly centralizes the logic for determining if all policy rules pass. The implementation properly handles:
- Null safety with early return
- Approval rule validation across different types
- Version selector rule checking
- Rollout time validation using proper date comparison
The logic flow is clear and the function serves its purpose well.
154-159: LGTM - Consistent blocked policy UI.The
PolicyBlockCellcomponent provides a clean, consistent UI element for indicating blocked policy states. The shield icon and text are appropriate for this use case.
161-215: LGTM - Proper tooltip implementation with good UX.The tooltip refactoring from HoverCard to Tooltip pattern is well-implemented:
- Proper loading states with Skeleton component
- Conditional rendering based on policy evaluation results
- Appropriate tooltip positioning and styling
- Good user experience with policy evaluation details
The component correctly integrates the new helper function and provides comprehensive policy information.
apps/webservice/src/app/[workspaceSlug]/sidebars.ts (1)
12-12: LGTM - Clean enum addition.The addition of
ReleaseTarget = "release-target"follows the existing naming convention and properly supports the new release target functionality introduced in this PR.apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/layout.tsx (2)
7-7: LGTM - Updated import for new deployment UI.The icon change from
IconHistorytoIconRocketaligns with the shift from release history to deployments view.
98-102: LGTM - Consistent sidebar link update.The sidebar link updates are well-aligned with the new deployment management UI:
- Updated URL to use
baseUrl()method- Changed icon from history to rocket
- Updated label from "Release History" to "Deployments"
These changes properly reflect the functionality shift described in the PR objectives.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/page.tsx (2)
2-2: LGTM - Updated import for new tile-based UI.The import change from
ReleaseHistoryTabletoReleaseTargetTilealigns with the PR's objective of replacing the release history table with a tile-based deployments overview.
14-19: LGTM - Well-implemented tile-based grid layout.The refactoring from a single table component to a grid of tile components is well-executed:
- Proper mapping over
releaseTargetswith correct key usage- Clean 3-column grid layout with appropriate spacing
- Each tile receives the complete
releaseTargetobject as expected by the componentThis implementation successfully replaces the previous release history table with the new tile-based deployments overview as described in the PR objectives.
packages/api/src/router/release-target-version/router.ts (1)
1-15: LGTM! Clean router structure.The router properly aggregates all release target version procedures into a cohesive API surface. The import organization and endpoint naming are consistent with the project's conventions.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/useVersionSearch.ts (1)
1-18: LGTM! Well-structured search parameter management.The hook properly manages URL search parameters using Next.js navigation APIs. The conditional logic for setting/removing parameters is correct, and using
router.replaceappropriately updates the URL without adding history entries.apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobStatusCell.tsx (1)
1-25: LGTM! Well-structured status cell component.The component is properly typed, follows React patterns, and integrates well with the PolicyEvaluationTooltip for enhanced UX. The implementation is clean and focused on its single responsibility.
apps/webservice/src/app/[workspaceSlug]/(app)/_components/job/JobLinks.tsx (1)
1-30: LGTM! Secure and well-styled link component.The component properly handles external links with appropriate security attributes (
target="_blank"andrel="noopener noreferrer"), provides good empty state handling, and uses consistent styling withbuttonVariants.apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/page.tsx (1)
1-18: LGTM! Proper Next.js 15 async page implementation.The page correctly awaits params before accessing properties, handles the not found case appropriately, and follows Next.js server component patterns. The implementation is clean and focused.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/JobRow.tsx (1)
8-12: Component structure and type usage look good.The component properly uses TypeScript with explicit types, follows React best practices, and correctly integrates with the JobStatusCell component. The date formatting using
formatDistanceToNowStrictis appropriate for displaying relative job creation times.Also applies to: 16-26
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/types.ts (1)
1-11: Well-structured type definitions with proper TypeScript usage.The type definitions follow TypeScript best practices:
- Proper use of
import typefor type-only imports- Clean intersection types that extend base schema types with related entities
- Consistent naming conventions and structure
- Appropriate use of generic types like
Record<string, string>for the links propertyThis provides a solid foundation for type safety across the deployment management UI.
packages/api/src/router/release-target-version/utils.ts (1)
11-36: Database query implementation is correct and well-structured.The
getReleaseTargetfunction:
- Uses proper inner joins to fetch related data
- Correctly applies the
takeFirstutility for single result handling- Returns a well-typed result matching the ReleaseTarget interface
- Follows established database query patterns in the codebase
The query structure ensures data integrity by requiring all related entities to exist.
packages/api/src/router/release-target-version/in-progress-version.ts (2)
10-18: Authorization check is properly implemented.The procedure correctly uses
ReleaseTargetGetpermission and validates access to the specific release target ID. This follows the established authorization patterns in the codebase.
19-50: Database query logic is correct for finding in-progress versions.The query implementation:
- Properly joins all necessary tables to get version and job data
- Correctly filters for non-successful job statuses using
ne(schema.job.status, JobStatus.Successful)- Orders by job creation time descending to get the most recent
- Uses
takeFirstOrNullappropriately since there might not be any in-progress versions- Transforms the result into a clean format with version and job properties
The complex join structure is necessary to traverse the relationships between release targets, versions, and jobs.
packages/api/src/router/release-target.ts (1)
17-20: Good integration of version management functionality.The addition of the
releaseTargetVersionRouteras a nested router properly organizes the version-related endpoints under the release target namespace. This follows good API design practices.apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/layout.tsx (2)
23-31: LGTM! Proper Next.js 15 async params handling and metadata generation.The implementation correctly uses
await paramsas required for Next.js 15 and properly handles the case where release target is not found withnotFound().
59-74: LGTM! Clean layout component structure.The layout component properly fetches data, handles error cases, and provides a clean structure with the header and children. The destructuring of release target properties is efficient.
packages/api/src/router/release-target-version/latest-version.ts (2)
10-18: LGTM! Proper authorization implementation.The authorization check correctly uses
Permission.ReleaseTargetGetand validates against the release target ID.
19-46: LGTM! Well-structured database query with proper result handling.The query correctly joins the necessary tables to find the latest successful deployment version. The use of
takeFirstOrNullaligns with the established pattern and the final extraction ofdeployment_versionis appropriate.apps/webservice/src/app/urls.ts (2)
125-151: LGTM! Well-structured URL builders following established patterns.The new
releaseTargetandresourceDeploymentsfunctions maintain consistency with the existing URL building patterns and provide good nesting structure for the new deployment UI features.
156-156: LGTM! Proper integration with existing resource URL builder.The update to use the new
resourceDeploymentsfunction maintains backward compatibility while enabling the new nested URL structure.apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/ReleaseTargetVersionsTable.tsx (3)
23-59: LGTM! Well-structured VersionRow component with proper destructuring.The component correctly destructures the latest job and other jobs, and uses the CollapsibleRow pattern effectively with HeaderRow and JobRow components.
61-71: LGTM! Effective loading state with visual feedback.The loading state provides good visual feedback with skeleton components and opacity fade effect to indicate loading progress.
86-118: LGTM! Clean table component with proper state management.The component properly integrates search functionality, loading states, and data fetching. The 5-second refetch interval is appropriate for deployment status updates.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/ForceDeployVersion.tsx (1)
49-78: LGTM! Well-structured dialog with proper loading states.The dialog component properly handles loading states, user feedback, and follows established UI patterns with appropriate button variants.
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionDropdown.tsx (1)
24-93: Well-structured dropdown component with proper state management.The component correctly handles version pinning states and cache invalidation. Good use of conditional rendering and proper event handling with
preventDefault()andstopPropagation().apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/HeaderRow.tsx (1)
20-104: Clean component structure with good separation of concerns.The component effectively breaks down the row into logical sub-components. The
TruncatedTextTooltippattern is a nice touch for handling overflow text.apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx (1)
29-159: Good implementation of loading states and data fetching patterns.The component properly handles loading states with skeletons and implements a sensible refetch interval for in-progress deployments. The tooltip patterns provide good UX for displaying additional metadata.
packages/api/src/router/release-target-version/version-pinning.ts (1)
11-71: Well-implemented version pinning procedures with proper authorization.Both procedures follow the established patterns with appropriate authorization checks and event dispatching. The use of
takeFirstfor version retrieval ensures data integrity by failing loudly on unexpected results.apps/webservice/src/app/[workspaceSlug]/(app)/(deploy)/(raw)/systems/[systemSlug]/(raw)/deployments/[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/ReleaseTargetRow.tsx (3)
113-126: LGTM! Good integration with PolicyEvaluationTooltip.The JobStatusCell component now properly wraps its content with PolicyEvaluationTooltip and accepts the required props for policy evaluation context.
143-146: LGTM! Good refactoring to use JobLinks component.The LinksCell component has been properly refactored to delegate link rendering to the JobLinks component, which promotes consistency and reusability.
214-219: LGTM! Consistent PolicyEvaluationTooltip usage.The PolicyEvaluationTooltip is properly applied to the "No jobs" case, providing consistent policy evaluation feedback across all job status scenarios.
packages/api/src/router/release-target-version/list-deployable-versions.ts (4)
16-30: LGTM! Good separation of policy-based version selection logic.The
getVersionSelectorSqlfunction properly retrieves applicable policies, sorts them by priority, and generates SQL conditions for deployment version selection.
88-102: LGTM! Efficient job data aggregation with proper metadata handling.The lodash chain properly groups job rows by job ID and extracts job metadata (especially links) correctly. The JSON parsing of links metadata is handled safely.
142-151: LGTM! Well-designed sorting logic for deployment versions.The comparator function properly prioritizes the desired version first, then sorts by latest job creation date, and finally by deployment version creation date as fallback.
107-154: LGTM! Comprehensive API procedure with proper authorization and data flow.The procedure correctly implements:
- Input validation with Zod schema
- Authorization checks using Permission.ReleaseTargetGet
- Proper database querying with filtering and pagination
- Efficient data enrichment with job information
- Consistent error handling patterns
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/[releaseTargetId]/_components/VersionPinning.tsx (4)
34-51: LGTM! Proper async mutation handling with comprehensive error handling.The
onSubmitfunction correctly chains the mutation, state updates, cache invalidation, router refresh, and toast notifications. Error handling is properly implemented with catch block.
53-79: LGTM! Well-structured dialog with proper loading states.The dialog implementation correctly:
- Uses controlled state with
openandsetOpen- Provides clear user feedback with loading states
- Implements proper button states (disabled during pending)
- Uses consistent UI components from the design system
94-105: LGTM! Consistent error handling and mutation pattern.The
UnpinVersionDialogfollows the same excellent pattern asPinVersionDialogwith proper async handling, cache invalidation, and user feedback.
107-131: LGTM! Consistent dialog structure and user experience.The UnpinVersionDialog maintains the same high-quality patterns as the PinVersionDialog, ensuring consistent user experience across both pin and unpin operations.
...eploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/EnvironmentTableRow.tsx
Outdated
Show resolved
Hide resolved
| byId: protectedProcedure | ||
| .input(z.string().uuid()) | ||
| .meta({ | ||
| authorizationCheck: ({ canUser, input }) => | ||
| canUser.perform(Permission.ReleaseTargetGet).on({ | ||
| type: "releaseTarget", | ||
| id: input, | ||
| }), | ||
| }) | ||
| .query(async ({ ctx, input }) => | ||
| ctx.db | ||
| .select() | ||
| .from(schema.releaseTarget) | ||
| .innerJoin( | ||
| schema.resource, | ||
| eq(schema.releaseTarget.resourceId, schema.resource.id), | ||
| ) | ||
| .innerJoin( | ||
| schema.environment, | ||
| eq(schema.releaseTarget.environmentId, schema.environment.id), | ||
| ) | ||
| .innerJoin( | ||
| schema.deployment, | ||
| eq(schema.releaseTarget.deploymentId, schema.deployment.id), | ||
| ) | ||
| .where(eq(schema.releaseTarget.id, input)) | ||
| .then(takeFirstOrNull) | ||
| .then((dbResult) => { | ||
| if (dbResult == null) return null; | ||
| const { release_target, resource, environment, deployment } = | ||
| dbResult; | ||
| return { ...release_target, resource, environment, deployment }; | ||
| }), | ||
| ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Eliminate code duplication by using the getReleaseTarget utility.
The byId procedure duplicates the exact same query logic that's already implemented in the getReleaseTarget utility function from packages/api/src/router/release-target-version/utils.ts. This creates maintenance overhead and potential inconsistencies.
Replace the inline query with the utility function:
-import {
- and,
- count,
- eq,
- notInArray,
- takeFirst,
- takeFirstOrNull,
-} from "@ctrlplane/db";
+import { and, count, eq, notInArray, takeFirst } from "@ctrlplane/db";
+import { getReleaseTarget } from "./release-target-version/utils";- .query(async ({ ctx, input }) =>
- ctx.db
- .select()
- .from(schema.releaseTarget)
- .innerJoin(
- schema.resource,
- eq(schema.releaseTarget.resourceId, schema.resource.id),
- )
- .innerJoin(
- schema.environment,
- eq(schema.releaseTarget.environmentId, schema.environment.id),
- )
- .innerJoin(
- schema.deployment,
- eq(schema.releaseTarget.deploymentId, schema.deployment.id),
- )
- .where(eq(schema.releaseTarget.id, input))
- .then(takeFirstOrNull)
- .then((dbResult) => {
- if (dbResult == null) return null;
- const { release_target, resource, environment, deployment } =
- dbResult;
- return { ...release_target, resource, environment, deployment };
- }),
- ),
+ .query(async ({ input }) => {
+ try {
+ return await getReleaseTarget(input);
+ } catch {
+ return null;
+ }
+ }),Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/api/src/router/release-target.ts lines 22 to 55, the byId procedure
duplicates the query logic already implemented in the getReleaseTarget utility
function from packages/api/src/router/release-target-version/utils.ts. To fix
this, import the getReleaseTarget function and replace the inline query inside
the byId procedure with a call to getReleaseTarget, passing the necessary
context and input parameters. This will eliminate code duplication and ensure
consistency.
| <Button variant="outline" size="sm"> | ||
| Lock | ||
| </Button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lock button is missing onClick handler.
The Lock button doesn't have an onClick handler, making it non-functional. If this is intentional (placeholder for future functionality), consider disabling it or adding a tooltip to indicate it's not yet implemented.
🤖 Prompt for AI Agents
In
apps/webservice/src/app/[workspaceSlug]/(app)/resources/(raw)/[resourceId]/deployments/_components/ReleaseTargetTile.tsx
around lines 145 to 147, the Lock button lacks an onClick handler, rendering it
non-functional. To fix this, either add a proper onClick handler to implement
the intended locking functionality or, if it's a placeholder, disable the button
and/or add a tooltip explaining that the feature is not yet implemented.
| const getVersionRelease = async ( | ||
| releaseTarget: ReleaseTarget, | ||
| versionId: string, | ||
| ) => { | ||
| const existingVersionRelease = await db | ||
| .select() | ||
| .from(schema.versionRelease) | ||
| .where( | ||
| and( | ||
| eq(schema.versionRelease.releaseTargetId, releaseTarget.id), | ||
| eq(schema.versionRelease.versionId, versionId), | ||
| ), | ||
| ) | ||
| .then(takeFirstOrNull); | ||
|
|
||
| if (existingVersionRelease != null) return existingVersionRelease; | ||
|
|
||
| const { workspaceId } = releaseTarget.resource; | ||
| const vrm = new VersionReleaseManager(db, { | ||
| ...releaseTarget, | ||
| workspaceId, | ||
| }); | ||
| const { release: versionRelease } = await vrm.upsertRelease(versionId); | ||
|
|
||
| return versionRelease; | ||
| }; | ||
|
|
||
| const getVariableSetRelease = async (releaseTarget: ReleaseTarget) => { | ||
| const releaseTargetId = releaseTarget.id; | ||
| const existingVariableSetRelease = await db | ||
| .select() | ||
| .from(schema.variableSetRelease) | ||
| .where(eq(schema.variableSetRelease.releaseTargetId, releaseTargetId)) | ||
| .then(takeFirstOrNull); | ||
|
|
||
| if (existingVariableSetRelease != null) return existingVariableSetRelease; | ||
|
|
||
| const { workspaceId } = releaseTarget.resource; | ||
|
|
||
| const varrm = new VariableReleaseManager(db, { | ||
| ...releaseTarget, | ||
| workspaceId, | ||
| }); | ||
|
|
||
| const { chosenCandidate: variableValues } = await varrm.evaluate(); | ||
|
|
||
| const { release: variableRelease } = | ||
| await varrm.upsertRelease(variableValues); | ||
|
|
||
| return variableRelease; | ||
| }; | ||
|
|
||
| const getRelease = async ( | ||
| versionReleaseId: string, | ||
| variableReleaseId: string, | ||
| ) => { | ||
| const existingRelease = await db | ||
| .select() | ||
| .from(schema.release) | ||
| .where( | ||
| and( | ||
| eq(schema.release.versionReleaseId, versionReleaseId), | ||
| eq(schema.release.variableReleaseId, variableReleaseId), | ||
| ), | ||
| ) | ||
| .then(takeFirstOrNull); | ||
|
|
||
| if (existingRelease != null) return existingRelease; | ||
|
|
||
| return db | ||
| .insert(schema.release) | ||
| .values({ versionReleaseId, variableReleaseId }) | ||
| .returning() | ||
| .then(takeFirst); | ||
| }; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Helper functions should accept database client parameter for transaction support.
The helper functions use db directly, making them inflexible for transaction contexts. Consider refactoring them to accept a database client parameter:
const getVersionRelease = async (
+ db: typeof ctx.db,
releaseTarget: ReleaseTarget,
versionId: string,
) => {This would allow these functions to participate in transactions when needed.
📝 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.
| const getVersionRelease = async ( | |
| releaseTarget: ReleaseTarget, | |
| versionId: string, | |
| ) => { | |
| const existingVersionRelease = await db | |
| .select() | |
| .from(schema.versionRelease) | |
| .where( | |
| and( | |
| eq(schema.versionRelease.releaseTargetId, releaseTarget.id), | |
| eq(schema.versionRelease.versionId, versionId), | |
| ), | |
| ) | |
| .then(takeFirstOrNull); | |
| if (existingVersionRelease != null) return existingVersionRelease; | |
| const { workspaceId } = releaseTarget.resource; | |
| const vrm = new VersionReleaseManager(db, { | |
| ...releaseTarget, | |
| workspaceId, | |
| }); | |
| const { release: versionRelease } = await vrm.upsertRelease(versionId); | |
| return versionRelease; | |
| }; | |
| const getVariableSetRelease = async (releaseTarget: ReleaseTarget) => { | |
| const releaseTargetId = releaseTarget.id; | |
| const existingVariableSetRelease = await db | |
| .select() | |
| .from(schema.variableSetRelease) | |
| .where(eq(schema.variableSetRelease.releaseTargetId, releaseTargetId)) | |
| .then(takeFirstOrNull); | |
| if (existingVariableSetRelease != null) return existingVariableSetRelease; | |
| const { workspaceId } = releaseTarget.resource; | |
| const varrm = new VariableReleaseManager(db, { | |
| ...releaseTarget, | |
| workspaceId, | |
| }); | |
| const { chosenCandidate: variableValues } = await varrm.evaluate(); | |
| const { release: variableRelease } = | |
| await varrm.upsertRelease(variableValues); | |
| return variableRelease; | |
| }; | |
| const getRelease = async ( | |
| versionReleaseId: string, | |
| variableReleaseId: string, | |
| ) => { | |
| const existingRelease = await db | |
| .select() | |
| .from(schema.release) | |
| .where( | |
| and( | |
| eq(schema.release.versionReleaseId, versionReleaseId), | |
| eq(schema.release.variableReleaseId, variableReleaseId), | |
| ), | |
| ) | |
| .then(takeFirstOrNull); | |
| if (existingRelease != null) return existingRelease; | |
| return db | |
| .insert(schema.release) | |
| .values({ versionReleaseId, variableReleaseId }) | |
| .returning() | |
| .then(takeFirst); | |
| }; | |
| const getVersionRelease = async ( | |
| db: typeof ctx.db, | |
| releaseTarget: ReleaseTarget, | |
| versionId: string, | |
| ) => { | |
| const existingVersionRelease = await db | |
| .select() | |
| .from(schema.versionRelease) | |
| .where( | |
| and( | |
| eq(schema.versionRelease.releaseTargetId, releaseTarget.id), | |
| eq(schema.versionRelease.versionId, versionId), | |
| ), | |
| ) | |
| .then(takeFirstOrNull); | |
| if (existingVersionRelease != null) return existingVersionRelease; | |
| const { workspaceId } = releaseTarget.resource; | |
| const vrm = new VersionReleaseManager(db, { | |
| ...releaseTarget, | |
| workspaceId, | |
| }); | |
| const { release: versionRelease } = await vrm.upsertRelease(versionId); | |
| return versionRelease; | |
| }; |
🤖 Prompt for AI Agents
In packages/api/src/router/release-target-version/force-deploy-version.ts from
lines 18 to 93, the helper functions getVersionRelease, getVariableSetRelease,
and getRelease currently use the global db client directly, which prevents them
from participating in transactions. Refactor these functions to accept a
database client parameter and use that client for all database operations
instead of the global db. This change will allow callers to pass a transactional
database client when needed, enabling proper transaction support.
| .mutation(async ({ ctx, input }) => { | ||
| const { releaseTargetId, versionId } = input; | ||
| const releaseTarget = await getReleaseTarget(releaseTargetId); | ||
| const [versionRelease, variableRelease] = await Promise.all([ | ||
| getVersionRelease(releaseTarget, versionId), | ||
| getVariableSetRelease(releaseTarget), | ||
| ]); | ||
| const release = await getRelease(versionRelease.id, variableRelease.id); | ||
| const releaseJob = await createReleaseJob(ctx.db, release); | ||
|
|
||
| getQueue(Channel.DispatchJob).add(releaseJob.id, { | ||
| jobId: releaseJob.id, | ||
| }); | ||
|
|
||
| return releaseJob; | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider wrapping database operations in a transaction.
The mutation performs multiple database operations that should be atomic. While createReleaseJob is called with ctx.db, consider wrapping all operations in an explicit transaction to ensure consistency if any operation fails.
.mutation(async ({ ctx, input }) => {
+ return ctx.db.transaction(async (tx) => {
const { releaseTargetId, versionId } = input;
const releaseTarget = await getReleaseTarget(releaseTargetId);
const [versionRelease, variableRelease] = await Promise.all([
getVersionRelease(releaseTarget, versionId),
getVariableSetRelease(releaseTarget),
]);
const release = await getRelease(versionRelease.id, variableRelease.id);
- const releaseJob = await createReleaseJob(ctx.db, release);
+ const releaseJob = await createReleaseJob(tx, release);
getQueue(Channel.DispatchJob).add(releaseJob.id, {
jobId: releaseJob.id,
});
return releaseJob;
+ });
});📝 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.
| .mutation(async ({ ctx, input }) => { | |
| const { releaseTargetId, versionId } = input; | |
| const releaseTarget = await getReleaseTarget(releaseTargetId); | |
| const [versionRelease, variableRelease] = await Promise.all([ | |
| getVersionRelease(releaseTarget, versionId), | |
| getVariableSetRelease(releaseTarget), | |
| ]); | |
| const release = await getRelease(versionRelease.id, variableRelease.id); | |
| const releaseJob = await createReleaseJob(ctx.db, release); | |
| getQueue(Channel.DispatchJob).add(releaseJob.id, { | |
| jobId: releaseJob.id, | |
| }); | |
| return releaseJob; | |
| }); | |
| .mutation(async ({ ctx, input }) => { | |
| return ctx.db.transaction(async (tx) => { | |
| const { releaseTargetId, versionId } = input; | |
| const releaseTarget = await getReleaseTarget(releaseTargetId); | |
| const [versionRelease, variableRelease] = await Promise.all([ | |
| getVersionRelease(releaseTarget, versionId), | |
| getVariableSetRelease(releaseTarget), | |
| ]); | |
| const release = await getRelease(versionRelease.id, variableRelease.id); | |
| const releaseJob = await createReleaseJob(tx, release); | |
| getQueue(Channel.DispatchJob).add(releaseJob.id, { | |
| jobId: releaseJob.id, | |
| }); | |
| return releaseJob; | |
| }); | |
| }); |
🤖 Prompt for AI Agents
In packages/api/src/router/release-target-version/force-deploy-version.ts around
lines 108 to 123, the mutation performs multiple database operations that should
be atomic but currently are not wrapped in a transaction. To fix this, wrap all
database calls including getReleaseTarget, getVersionRelease,
getVariableSetRelease, getRelease, and createReleaseJob inside a single explicit
transaction using ctx.db.transaction or equivalent. This ensures that if any
operation fails, all changes are rolled back to maintain data consistency.
.../[deploymentSlug]/(raw)/releases/[releaseId]/(sidebar)/jobs/_components/ReleaseTargetRow.tsx
Outdated
Show resolved
Hide resolved
This reverts commit 7964685.
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Chores