Skip to content

feat: suggest bounded expirations for policy skips in ui#1170

Merged
adityachoudhari26 merged 2 commits into
mainfrom
ui-skip-expiry-gating
Jun 10, 2026
Merged

feat: suggest bounded expirations for policy skips in ui#1170
adityachoudhari26 merged 2 commits into
mainfrom
ui-skip-expiry-gating

Conversation

@adityachoudhari26

@adityachoudhari26 adityachoudhari26 commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Intelligent expiry options for deployment skips computed from deployment evaluations.
    • New dropdown expiry selector with preset relative options and a "No expiration" choice.
  • UI/UX Improvements

    • Simplified "Skip" flow with streamlined add behavior and automatic reset after creation.
    • Clearer expiration status display including a warning when no expiration is set.

Copilot AI review requested due to automatic review settings June 10, 2026 04:00
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors the deployment skip expiry workflow by extracting shared logic into utilities and components. A new skip-expiry module computes selectable expiry times from rule evaluations, a new ExpirySelect component handles option selection with status messaging, and both CreateSkipForm and PolicySkipActions are updated to use this consolidated approach instead of managing expiry inline.

Changes

Deployment Skip Expiry Selection Flow

Layer / File(s) Summary
Expiry option computation and detection
apps/web/app/routes/ws/deployments/_components/release-targets/skip-expiry.ts
New module that normalizes dates, detects gradual rollouts and other rule-based timings, selects the latest candidate across evaluations, and builds selectable expiry options (rule-based when available, plus 6h/12h/24h and no-expiration).
ExpirySelect UI component
apps/web/app/routes/ws/deployments/_components/release-targets/ExpirySelect.tsx
New reusable select component that renders expiry options and shows either a relative "Expires in…" time or a highlighted warning for permanent (no-expiration) skips.
CreateSkipForm refactor to state-driven UI
apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/policy-skip/CreateSkipForm.tsx
Replaced react-hook-form/zod form with local state: selects rule, queries evaluations, computes expiry options, renders ExpirySelect, and imperatively calls the TRPC create skip mutation with computed expiresAt.
PolicySkipActions popover refactor
apps/web/app/routes/ws/deployments/_components/release-targets/PolicySkipActions.tsx
Replaces inline DateTimePicker and manual expiresAt state with a SkipExpiryForm that computes expiry options and submits expiresAt to the parent createSkip mutation; form unmounts on popover close.

Sequence Diagram

sequenceDiagram
  participant User
  participant CreateSkipForm
  participant Evaluations API
  participant Skip Mutation
  User->>CreateSkipForm: Select rule
  CreateSkipForm->>Evaluations API: Query deploymentVersions.evaluate
  Evaluations API-->>CreateSkipForm: Return rule evaluations
  CreateSkipForm->>CreateSkipForm: expiryOptionsForRule(evaluations)
  CreateSkipForm->>User: Render ExpirySelect with computed options
  User->>CreateSkipForm: Select expiry option
  User->>CreateSkipForm: Click "Add skip"
  CreateSkipForm->>Skip Mutation: policySkips.createForEnvAndVersion
  Skip Mutation-->>CreateSkipForm: Success
  CreateSkipForm->>CreateSkipForm: Reset state, invalidate cache
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

  • ctrlplanedev/ctrlplane#1154: Both PRs modify the release-target policy-skip creation UI flow to support an optional expiry (expiresAt) when calling the TRPC create mutation, with overlapping changes to expiry selection and skip UI.

Poem

🐰 I nibbled at code and found a way,
To make expiry choices clear as day.
Rollouts whisper times that I compute,
Select and skip — the flow's more cute.
Hooray for shared logic — hop, let's play!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: adding UI suggestions for expiration times when users create policy skips, which is reflected throughout the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ui-skip-expiry-gating

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the deployments UI skip flows to encourage bounded (time-limited) policy skips by replacing free-form datetime selection with a small set of suggested expirations, including rule-derived “until X completes/opens/ends/passes” options when available.

Changes:

  • Added shared logic to derive skip expiration options from policy evaluation details (plus fixed-duration fallbacks).
  • Introduced a reusable ExpirySelect UI component to present those options and warn about permanent skips.
  • Updated both release-target skip actions and env+version skip creation to use the new expiry selector instead of a datetime picker.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
apps/web/app/routes/ws/deployments/_components/release-targets/skip-expiry.ts New option-building utilities to suggest bounded expirations based on evaluation details.
apps/web/app/routes/ws/deployments/_components/release-targets/PolicySkipActions.tsx Replaces datetime picker with suggested expiry selector in release-target skip popover.
apps/web/app/routes/ws/deployments/_components/release-targets/ExpirySelect.tsx New select component for expiry choices + UX warning for “No expiration”.
apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/policy-skip/CreateSkipForm.tsx Refactors env+version skip creation to use suggested expiry selector and local state.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +100 to +115
export function expiryOptionsForRule(
evaluations: RuleEvaluation[],
ruleId: string | undefined,
now: Date,
): ExpiryOption[] {
const ruleEvaluations = evaluations.filter((e) => e.ruleId === ruleId);
const first = ruleEvaluations[0];
return buildExpiryOptions({
details: first.details ?? null,
nextEvaluationAt:
first.nextEvaluationAt != null ? new Date(first.nextEvaluationAt) : null,
gradualMaxTime:
ruleId != null ? maxRolloutTime(ruleEvaluations, ruleId) : null,
now,
});
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/web/app/routes/ws/deployments/_components/release-targets/skip-expiry.ts`:
- Around line 100-115: expiryOptionsForRule can dereference an undefined first
when no evaluations match ruleId; update expiryOptionsForRule to safely handle
empty ruleEvaluations by using optional chaining or guards before accessing
first.details and first.nextEvaluationAt and by passing nulls to
buildExpiryOptions when first is undefined; keep the call to
maxRolloutTime(ruleEvaluations, ruleId) only when ruleEvaluations is non-empty
(or ensure maxRolloutTime tolerates empty arrays) so that expiryOptionsForRule
(the function) never reads properties off an undefined first and
buildExpiryOptions always receives valid nullable fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f6c3c89f-ccb6-4ad3-a4f4-bb61c4a0c52c

📥 Commits

Reviewing files that changed from the base of the PR and between 935332f and 520261a.

📒 Files selected for processing (4)
  • apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/policy-skip/CreateSkipForm.tsx
  • apps/web/app/routes/ws/deployments/_components/release-targets/ExpirySelect.tsx
  • apps/web/app/routes/ws/deployments/_components/release-targets/PolicySkipActions.tsx
  • apps/web/app/routes/ws/deployments/_components/release-targets/skip-expiry.ts

Comment thread apps/web/app/routes/ws/deployments/_components/release-targets/skip-expiry.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/web/app/routes/ws/deployments/_components/release-targets/skip-expiry.ts (1)

54-56: 💤 Low value

Typo in comment perpetuates API naming issue.

The comment references evaulate which matches the existing API endpoint deploymentVersions.evaulate. While technically accurate, this perpetuates a typo that may confuse future readers. Consider adding a clarifying note that this matches an existing API name, or filing a follow-up to rename the API endpoint.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/web/app/routes/ws/deployments/_components/release-targets/skip-expiry.ts`
around lines 54 - 56, The comment contains a typo "evaulate" which mirrors the
existing API endpoint deploymentVersions.evaulate; update the comment to either
correct the spelling to "evaluate" while explicitly noting it matches the
current API name (e.g., "note: API is named deploymentVersions.evaulate with
this spelling") or add a brief clarifying sentence suggesting a follow-up task
to rename the API; reference the symbol deploymentVersions.evaulate so readers
understand the mismatch and avoid confusion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@apps/web/app/routes/ws/deployments/_components/release-targets/skip-expiry.ts`:
- Around line 54-56: The comment contains a typo "evaulate" which mirrors the
existing API endpoint deploymentVersions.evaulate; update the comment to either
correct the spelling to "evaluate" while explicitly noting it matches the
current API name (e.g., "note: API is named deploymentVersions.evaulate with
this spelling") or add a brief clarifying sentence suggesting a follow-up task
to rename the API; reference the symbol deploymentVersions.evaulate so readers
understand the mismatch and avoid confusion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: eead1526-df6f-4d20-8aa5-57670cd66062

📥 Commits

Reviewing files that changed from the base of the PR and between 520261a and 2eb664d.

📒 Files selected for processing (1)
  • apps/web/app/routes/ws/deployments/_components/release-targets/skip-expiry.ts

@adityachoudhari26 adityachoudhari26 merged commit 66e0888 into main Jun 10, 2026
9 checks passed
@adityachoudhari26 adityachoudhari26 deleted the ui-skip-expiry-gating branch June 10, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants