Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix: Init deny calendar ui v2 #456

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

fix: Init deny calendar ui v2 #456

wants to merge 6 commits into from

Conversation

adityachoudhari26
Copy link
Contributor

@adityachoudhari26 adityachoudhari26 commented Apr 6, 2025

Summary by CodeRabbit

  • New Features

    • Introduced an interactive calendar allowing users to manage deny windows with intuitive drag-and-drop, resizing, and editing.
    • Added a streamlined dialog interface for creating and configuring deny rules.
  • Style

    • Enhanced visual design and responsive styling for a consistent and user-friendly experience across devices.

Copy link
Contributor

coderabbitai bot commented Apr 6, 2025

Walkthrough

This pull request introduces calendar functionalities by adding new dependencies and React components for managing deny windows using a calendar interface. It adds corresponding CSS for styling and a new context for state management. On the backend, new TRPC endpoints for creating, updating, and deleting deny window entries are added, while obsolete endpoints are removed. Additionally, a new dependency is introduced in the API package and a method is added in the rule-engine package for computing denied time ranges.

Changes

File(s) Change Summary
apps/webservice/package.json Added dependencies: react-big-calendar (^1.18.0) and @types/react-big-calendar (^1.16.1)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.css New CSS file added for styling deny rule creation components, including responsive and state-specific styles
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx New React component with multiple sub-components (e.g., CreateDenyRuleDialog, EventComponent) to manage deny windows with drag-and-drop support
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/page.tsx Updated page to fetch workspace details, handle 404 cases, and render the CreateDenyRuleDialog with updated Card styling
packages/api/package.json Added dependency: "@ctrlplane/rule-engine": "workspace:*"
packages/api/src/root.ts Updated import path for policyRouter to specify "./router/policy/router"
packages/api/src/router/policy/deny-window.ts Introduced a new TRPC router with procedures: list, create, createInCalendar, resize, drag, update, and delete for deny windows
packages/api/src/router/policy/router.ts Removed individual deny window endpoints and added a new denyWindow endpoint referencing the new router
packages/rule-engine/src/rules/deployment-deny-rule.ts Added method getWindowsInRange to compute denied time windows based on a date range, and modified the rrule import
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/DenyWindowContext.tsx New React context (with provider and hook) for managing the open event ID in deny window components

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant Page as DenyWindowsPage
    participant API as Workspace API
    Browser->>Page: Load page with workspaceSlug
    Page->>API: Fetch workspace details by slug
    API-->>Page: Return workspace details (or null)
    alt Workspace exists
       Page->>Browser: Render page with CreateDenyRuleDialog
    else Workspace missing
       Page->>Browser: Trigger 404 response
    end
Loading
sequenceDiagram
    participant User
    participant UI as CreateDenyRuleDialog
    participant API as DenyWindowRouter
    participant DB as Database
    User->>UI: Select a time slot on calendar
    UI->>API: Send create request for a deny window
    API->>DB: Insert deny window record
    DB-->>API: Confirm record inserted
    API-->>UI: Return deny window details
    UI->>User: Display new deny window on calendar
Loading

Suggested reviewers

  • jsbroks

Poem

I'm a rabbit with code so spry,
Hopping through changes beneath the sky.
Calendars bloom where rules are made,
Deny windows flourish in every cascade.
With a twitch and a hop, I'm filled with cheer—
CodeRabbit’s magic is finally here!
🐇💻

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

Documentation and Community

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (8)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (4)

57-58: Remove console.log statements before production.

There's a console.log statement that should be removed before deploying to production.

-          onClick={(e) => {
-            e.stopPropagation();
-            console.log("clicked!", event);
-          }}
+          onClick={(e) => {
+            e.stopPropagation();
+          }}

43-72: Add proper typing for the event prop in EventComponent.

Using any type for the event prop reduces type safety. Consider creating a proper type definition.

-const EventComponent: React.FC<{
-  event: any;
-  creatingDenyWindow: boolean;
-}> = ({ event, creatingDenyWindow }) => {
+const EventComponent: React.FC<{
+  event: Event & {
+    title: string;
+    start: Date;
+    end: Date;
+  };
+  creatingDenyWindow: boolean;
+}> = ({ event, creatingDenyWindow }) => {

130-138: Extract the UUID extraction logic to a reusable function.

The UUID regex and extraction logic is duplicated in both handleEventResize and handleEventDrag. Extract it to a reusable function.

+  const extractDenyWindowId = (eventId: string) => {
+    const uuidRegex =
+      /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\d+$/i;
+    const match = uuidRegex.exec(eventId);
+    const denyWindowId = match ? match[1] : null;
+    return { 
+      denyWindowId,
+      denyWindow: denyWindowId 
+        ? denyWindows.find(window => window.id === denyWindowId) 
+        : null 
+    };
+  };

   const handleEventResize = (event: EventChange) => {
     const { start, end } = event;
     const e = event.event as {
       end: Date;
       start: Date;
       id: string;
     };

-    const uuidRegex =
-      /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\d+$/i;
-    const match = uuidRegex.exec(e.id);
-    const denyWindowId = match ? match[1] : null;
-    const denyWindow = denyWindows.find(
-      (denyWindow) => denyWindow.id === denyWindowId,
-    );
+    const { denyWindowId, denyWindow } = extractDenyWindowId(e.id);

196-240: Consider adding loading and error states in the UI.

The component doesn't handle loading or error states from the various API calls. Add visual feedback to improve user experience.

   return (
     <div onClick={() => setCreatingDenyWindow(false)}>
+      {denyWindowsQ.isLoading && (
+        <div className="flex justify-center items-center h-10 mb-2">
+          <div className="text-sm">Loading calendar data...</div>
+        </div>
+      )}
+      
+      {denyWindowsQ.isError && (
+        <div className="flex justify-center items-center h-10 mb-2 text-destructive">
+          <div className="text-sm">Error loading calendar data. Please try again.</div>
+        </div>
+      )}
+      
       <DnDCalendar
packages/rule-engine/src/rules/deployment-deny-rule.ts (1)

226-236: Consider more robust timezone offset extraction.

The current implementation for extracting timezone offset relies on string parsing of formatted dates, which could be fragile. Consider using a more robust approach.

-      const formatter = new Intl.DateTimeFormat("en-US", {
-        timeZone: this.timezone,
-        timeZoneName: "longOffset",
-      });
-
-      const offsetStr = formatter.format(windowStart).split("GMT")[1];
-      const offsetHours = parseInt(offsetStr?.split(":")[0] ?? "0", 10);
-
-      const realStartUTC = subHours(windowStart, offsetHours);
-      const realEndUTC = subHours(windowEnd, offsetHours);
+      // Get the timezone offset in minutes at the specific date
+      const localDate = new Date(windowStart);
+      const utcDate = new Date(Date.UTC(
+        localDate.getUTCFullYear(),
+        localDate.getUTCMonth(),
+        localDate.getUTCDate(),
+        localDate.getUTCHours(),
+        localDate.getUTCMinutes(),
+        localDate.getUTCSeconds()
+      ));
+      
+      // Calculate offset between UTC and the timezone
+      const tzDate = this.castTimezone(utcDate, this.timezone);
+      const offsetMinutes = (tzDate.getTime() - utcDate.getTime()) / (1000 * 60);
+      const offsetHours = offsetMinutes / 60;
+      
+      const realStartUTC = subHours(windowStart, offsetHours);
+      const realEndUTC = subHours(windowEnd, offsetHours);
packages/api/src/router/policy/deny-window.ts (3)

5-26: Consider using enums or constants for weekdays.

Your weekdayMap object works fine, but defining a TypeScript enum might provide more clarity and reduce possible mistakes. This is optional.


28-74: Potential pagination needed.

While the logic for retrieving and transforming deny windows is correct, returning all results at once may pose scalability issues for large datasets. Consider adding pagination or filters if this route could return many records.


92-112: Incomplete mutation handler.

createInCalendar logs the input but doesn't persist data to the database. If this is intentional, consider leaving a TODO comment or an explanatory note.

Do you want me to propose a complete implementation for this procedure?

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20efc63 and ccaa4ee.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • apps/webservice/package.json (2 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.css (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/page.tsx (4 hunks)
  • packages/api/package.json (1 hunks)
  • packages/api/src/root.ts (1 hunks)
  • packages/api/src/router/policy/deny-window.ts (1 hunks)
  • packages/api/src/router/policy/router.ts (2 hunks)
  • packages/db/src/schema/policy.ts (1 hunks)
  • packages/rule-engine/src/rules/deployment-deny-rule.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{ts,tsx}`: **Note on Error Handling:** Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error...

**/*.{ts,tsx}: Note on Error Handling:
Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error handling. These are acceptable as long as they maintain clarity and predictability.

  • packages/db/src/schema/policy.ts
  • packages/api/src/root.ts
  • packages/api/src/router/policy/router.ts
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx
  • packages/rule-engine/src/rules/deployment-deny-rule.ts
  • packages/api/src/router/policy/deny-window.ts
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/page.tsx
🧬 Code Definitions (2)
packages/api/src/router/policy/router.ts (1)
packages/api/src/router/policy/deny-window.ts (1)
  • denyWindowRouter (28-258)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/page.tsx (1)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (1)
  • CreateDenyRuleDialog (85-241)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: Lint
  • GitHub Check: build (linux/amd64)
  • GitHub Check: Typecheck
  • GitHub Check: Test
🔇 Additional comments (24)
packages/api/package.json (1)

32-32: New dependency looks good.

Adding the rule-engine workspace package will enable deny window functionality required for the calendar UI implementation. This is consistent with the PR's objective of building the deny calendar UI.

packages/api/src/root.ts (1)

6-6: More specific import path looks good.

This change makes the import path more precise by referencing the router file directly. This clarifies the module structure and follows good import practices.

apps/webservice/package.json (2)

78-78: New calendar dependency looks good.

The addition of react-big-calendar is appropriate for implementing the calendar UI for deny windows as described in the PR objectives.


107-107: Type definitions for the calendar library look good.

Adding the corresponding TypeScript type definitions as a dev dependency follows best practices and ensures proper type checking for the new calendar component.

packages/db/src/schema/policy.ts (1)

209-218: Exporting the schema is appropriate.

Making the deny window schema available for import from other modules is necessary for the deny window functionality being implemented. This follows good modular design practices by exposing only what's needed by other components.

apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.css (3)

1-880: The CSS file appears to be using react-big-calendar's default styles with adaptations for the design system.

The file includes comprehensive styling for the calendar components, properly using CSS variables with the format hsl(var(--variable-name)) for theming consistency.


812-834: Well-implemented cross-browser scrollbar compatibility.

The custom scrollbar implementation includes styling for both WebKit browsers (Chrome, Safari) and Firefox, ensuring a consistent user experience across different browsers.


882-947: Smooth drag and drop animations for better UX.

The transition effect on events during drag operations (line 895) and the hover effects for resize anchors improve user interaction feedback.

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

15-16: Good modularization of the deny window functionality.

Importing the denyWindowRouter from a separate file improves code organization and separation of concerns.


152-152: Refactored deny window endpoints into a dedicated router.

The integration of denyWindowRouter replaces the previous direct endpoint implementations (createDenyWindow, updateDenyWindow, deleteDenyWindow), making the code more maintainable and following the single responsibility principle.

apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (1)

182-193:

❓ Verification inconclusive

Implement or remove commented code in handleEventCreate.

The handleEventCreate function contains commented-out code that appears to be incomplete functionality. Either implement it properly or remove the commented code.

-  const handleEventCreate = (event: EventCreate) => {
-    console.log("creating deny window", event);
-    const { start, end } = event;
-    // console.log("creating deny window", start, end);
-    // createDenyWindow.mutate({
-    //   policyId: "123",
-    //   start,
-    //   end,
-    //   timeZone,
-    // });
-    // setEvents((prev) => [...prev, { id: "temp", start, end, title: "" }]);
-  };
+  const handleEventCreate = (event: EventCreate) => {
+    const { start, end } = event;
+    // This implementation needs a policy ID
+    // You might want to:
+    // 1. Get it from props or context
+    // 2. Show a dialog to select a policy
+    // 3. Create a default policy if none exists
+    setCreatingDenyWindow(true);
+    
+    // Show a temporary event until the backend confirms creation
+    const tempId = `temp-${Date.now()}`;
+    setEvents((prev) => [...prev, { 
+      id: tempId, 
+      start, 
+      end, 
+      title: "New Deny Window" 
+    }]);
+    
+    // TODO: Get the actual policy ID before uncommenting
+    // createDenyWindow.mutate({
+    //   policyId: "[POLICY_ID]",
+    //   start,
+    //   end,
+    //   timeZone,
+    // }, {
+    //   onSuccess: () => {
+    //     denyWindowsQ.refetch();
+    //     setCreatingDenyWindow(false);
+    //   },
+    //   onError: (error) => {
+    //     // Remove the temporary event on error
+    //     setEvents((prev) => prev.filter(e => e.id !== tempId));
+    //     setCreatingDenyWindow(false);
+    //     // Handle error (e.g., show an error toast)
+    //   }
+    // });
+  };

🏁 Script executed:

#!/bin/bash
# Check if there's any context about how policy IDs are obtained in other components

echo "Searching for uses of policy IDs in deny window context:"
rg "policyId.*denyWindow" --type=ts

echo "Searching for any policy selection components:"
rg "PolicySelect|SelectPolicy" --type=tsx

Length of output: 335


Below is an additional shell script that uses a broader search (avoiding the unrecognized tsx file type issue) to help verify whether there’s any established mechanism for obtaining a policy ID (or a policy selection component) elsewhere in the deny-windows context:

Please run the above script and share its output.

Based on its results we can confirm if there’s an existing approach for resolving the policy ID. If no references are found, you may consider either:

  • Removing the commented code until a clear solution for obtaining a policy ID is implemented, or
  • Implementing the new approach (e.g. fetching the policy ID from props, context, or prompting the user) as suggested in the diff.

Once you verify this context manually, please update or finalize the implementation accordingly.


🏁 Script executed:

#!/bin/bash
# Searching for any occurrence of "policyId" in files under the deny-windows folder
echo "Searching for 'policyId' usage in deny-windows components:"
rg "policyId" apps/webservice/src/app/\[workspaceSlug\]/\(app\)/policies/deny-windows/

# Searching for potential policy selection components by looking for "PolicySelect" or "SelectPolicy" in TSX or TS files
echo "Searching for PolicySelect or SelectPolicy keywords in TS/TSX files:"
find . -type f \( -name "*.tsx" -or -name "*.ts" \) -exec grep -EH "PolicySelect|SelectPolicy" {} \;

Length of output: 719


Action: Address Incomplete Policy ID Handling in Deny Window Creation

The current implementation of handleEventCreate in
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx
still contains commented-out code for invoking the mutation with a hardcoded policy ID ("123"). Our search did not reveal an existing mechanism or component (such as a "PolicySelect" or "SelectPolicy") for obtaining a valid policy ID. As a result, the placeholder code remains ambiguous and could be confusing to future maintainers.

Please choose one of the following approaches:

  • Implement a Complete Solution:
    • Retrieve the policy ID from a reliable source (e.g., via props, React context, or by presenting a policy selection UI) before calling the mutation.
    • Uncomment and adapt the mutation call accordingly, ensuring that the actual policy ID is used.

  • Remove the Placeholder Code:
    • If the proper implementation is not ready, remove the commented-out code to clean up the file and avoid any misconceptions.
    • Add a clear TODO or FIXME comment to document that policy selection/ID retrieval needs to be addressed later.

The diff snippet suggestion remains useful as it outlines a temporary approach (e.g., using a temporary ID for UI feedback) with a placeholder for the policy ID. However, without an established pattern in the codebase, it's important to either finalize this mechanism or eliminate the placeholder.

Please update the code accordingly and ensure that the component behavior is clear and maintainable.

packages/rule-engine/src/rules/deployment-deny-rule.ts (2)

9-9: Import style change from default to namespace import.

The import statement for rrule has been changed from what appears to have been a default import to a namespace import, which is a good practice for modules with multiple exports.


162-241: Well-implemented date range functionality with detailed timezone handling.

The new getWindowsInRange method provides a robust way to calculate deny windows within a date range. The code includes thorough comments explaining the complex timezone handling logic.

apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/page.tsx (5)

1-1: Looks good.

Importing notFound from next/navigation is appropriate for returning a 404 when the resource is unavailable.


24-26: No concerns.

Import statements from ~trpc/server and your local CreateDenyRule component look properly scoped and consistent with the rest of the file.


33-35: Ensure param resolution is maintained.

Using await params to destructure { workspaceSlug } and validating workspace with notFound() is logically correct. Confirm that calling code always provides a valid promise for params.


63-63: Minor UI improvement.

Adding the mb-6 class to the <Card> for spacing is a clear enhancement of the page layout.


85-85: Good integration of the deny window dialog.

Passing workspace.id ensures the dialog has the context needed to manage deny windows. The null check above prevents runtime issues.

packages/api/src/router/policy/deny-window.ts (6)

1-4: Imports are well-chosen.

Using types and utilities from rrule, date-fns, and zod is appropriate for date manipulation and input validation.


76-90: Creation logic is straightforward.

The insert operation with proper permission checks looks good. No major concerns here.


113-159: Resize functionality seems correct.

Your approach to calculating new start/end times and updating dtstart and dtend in the database is clear. Make sure to test boundary cases (e.g., negative offsets, extremely large offsets) to ensure stability.


161-209: Drag logic is well-structured.

Mapping the new weekday and adjusting offsets looks correct. Suggest verifying that multi-day drags behave as expected within the recurrence rules.


210-235: Update procedure is straightforward.

The usage of updatePolicyRuleDenyWindow provides a clean approach for partial updates. The permission check is also consistent with the rest of the file.


236-258: Deletion logic appears safe.

Ensures the user has PolicyDelete permission, then removes the record from the database. Everything is consistent and aligned with best practices.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (4)

44-44: Use a more specific type than any for event.

Currently, event is declared as any, which can mask potential type mismatches or usage issues. Consider introducing an explicit interface or a provided type (e.g., from the calendar library) to ensure clarity and type safety.


45-47: Remove or utilize the unused creatingDenyWindow prop.

The creatingDenyWindow prop is declared but never referenced in the component’s logic, leading to dead code. Either safely remove it, or consider leveraging it to manage UI state or behavior relevant to creating deny windows.


105-110: Consider adding explicit error or loading states.

While fetching deny windows, the UI does not appear to handle loading or error conditions. Providing feedback for these states would help users understand the app’s status and avoid confusion.


193-198: Clean up commented-out code.

The creation logic for deny windows is partially commented out. This can lead to confusion or unmaintained code. Remove or reintroduce it with a finalized approach for creating deny windows in the calendar.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ccaa4ee and 1d49e29.

📒 Files selected for processing (1)
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{ts,tsx}`: **Note on Error Handling:** Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error...

**/*.{ts,tsx}: Note on Error Handling:
Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error handling. These are acceptable as long as they maintain clarity and predictability.

  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Typecheck
  • GitHub Check: Lint
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/amd64)
🔇 Additional comments (1)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (1)

74-76: Replace placeholder content in PopoverContent with meaningful details.

The placeholder "TEST TEXT" is still present. Consider rendering actual event details or helpful information regarding the deny window to enhance the user experience.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (7)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (7)

44-44: Replace any type with a more specific type.

Using any type reduces TypeScript's ability to catch errors at compile time. Consider replacing it with a more specific type that matches the event structure from react-big-calendar.

-  event: any;
+  event: Event;

59-59: Remove console.log statement before production.

Console logs should be removed before merging to production. They can expose sensitive information and create noise in the browser console.

-            console.log("clicked!", event);

77-77: Replace generic object type with a more specific type.

Using object type is too generic and doesn't provide proper type checking. Consider using a more specific type that matches the event structure.

-  event: object;
+  event: {
+    end: Date;
+    start: Date;
+    id: string;
+    title: string;
+  };

111-113: Initialize state with an empty array instead of mapping over potentially undefined data.

The current approach might cause issues if denyWindowsQ.data is undefined on the initial render. It's better to initialize with an empty array and update state when data becomes available.

-  const [events, setEvents] = useState<Event[]>(
-    denyWindows.flatMap((denyWindow) => denyWindow.events),
-  );
+  const [events, setEvents] = useState<Event[]>([]);

132-135: Extract UUID regex to a constant or utility function.

The UUID regex is defined inline within the event handlers. Since it's used in multiple places, consider extracting it to a constant outside the component or to a utility function for better reusability.

+ const DENY_WINDOW_ID_REGEX = /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\d+$/i;
+
+ const extractDenyWindowId = (eventId: string): string | null => {
+   const match = DENY_WINDOW_ID_REGEX.exec(eventId);
+   return match ? match[1] : null;
+ };

// Then in the handlers:
-    const uuidRegex =
-      /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\d+$/i;
-    const match = uuidRegex.exec(e.id);
-    const denyWindowId = match ? match[1] : null;
+    const denyWindowId = extractDenyWindowId(e.id);

162-165: Duplicate UUID regex pattern - extract to a shared function.

The same UUID regex pattern is duplicated in handleEventResize and handleEventDrag. Extract it to a shared function to eliminate redundancy.

// (Same suggestion as above, but for the second occurrence)
-    const uuidRegex =
-      /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-\d+$/i;
-    const match = uuidRegex.exec(e.id);
-    const denyWindowId = match ? match[1] : null;
+    const denyWindowId = extractDenyWindowId(e.id);

223-224: Consider making drag and resize configurable.

Currently, all events are draggable and resizable. Consider making this configurable based on event properties or user permissions.

-      resizableAccessor={() => true}
-      draggableAccessor={() => true}
+      resizableAccessor={(event) => event.id !== "new"}
+      draggableAccessor={(event) => event.id !== "new"}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d49e29 and 695f8bc.

📒 Files selected for processing (1)
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{ts,tsx}`: **Note on Error Handling:** Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error...

**/*.{ts,tsx}: Note on Error Handling:
Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error handling. These are acceptable as long as they maintain clarity and predictability.

  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/amd64)
  • GitHub Check: Typecheck
  • GitHub Check: Lint
  • GitHub Check: Test
🔇 Additional comments (4)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (4)

69-71: Replace placeholder content in PopoverContent.

The "TEST TEXT" placeholder should be replaced with meaningful content about the event.

-      <PopoverContent side="right" align="center" className="p-2">
-        <div>TEST TEXT</div>
-      </PopoverContent>
+      <PopoverContent side="right" align="center" className="p-2">
+        <div className="space-y-2">
+          <div className="font-medium">{event.title}</div>
+          <div className="text-xs">
+            <span>Time: </span>
+            <span>{start} - {end}</span>
+          </div>
+        </div>
+      </PopoverContent>

90-92: LGTM: Good use of browser's timezone.

Using the browser's timezone through Intl.DateTimeFormat().resolvedOptions() is a good approach to ensure the calendar displays in the user's local timezone.


95-99: LGTM: Well-structured date range initialization.

The current range state is well-structured with proper default values using the current week. Good job!


200-219: LGTM: Thorough range change handling.

The range change handler properly handles both array and object range formats, ensuring the calendar responds correctly to user navigation.

Comment on lines +185 to +193
console.log("creating deny window", event);
const { start, end } = event;
// // console.log("creating deny window", start, end);
// // createDenyWindow.mutate({
// // policyId: "123",
// // start,
// end,
// timeZone,
// });
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Clean up commented code and implement the actual window creation.

There's commented code and a console.log that should be removed or implemented properly. The current implementation doesn't actually create a deny window in the backend.

-    console.log("creating deny window", event);
-    const { start, end } = event;
-    // // console.log("creating deny window", start, end);
-    // // createDenyWindow.mutate({
-    // //   policyId: "123",
-    // //   start,
-    //   end,
-    //   timeZone,
-    // });
+    const { start, end } = event;
+    // Set local state first for immediate UI feedback
+    setCreatingDenyWindow(true);
+    setEvents((prev) => [...prev, { id: "new", start, end, title: "New Deny Window" }]);
+    
+    // Uncomment and implement when ready to connect to backend
+    /* 
+    createDenyWindow.mutate({
+      workspaceId,
+      start,
+      end,
+      timeZone,
+    });
+    */
📝 Committable suggestion

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

Suggested change
console.log("creating deny window", event);
const { start, end } = event;
// // console.log("creating deny window", start, end);
// // createDenyWindow.mutate({
// // policyId: "123",
// // start,
// end,
// timeZone,
// });
const { start, end } = event;
// Set local state first for immediate UI feedback
setCreatingDenyWindow(true);
setEvents((prev) => [...prev, { id: "new", start, end, title: "New Deny Window" }]);
// Uncomment and implement when ready to connect to backend
/*
createDenyWindow.mutate({
workspaceId,
start,
end,
timeZone,
});
*/

Comment on lines +115 to +118
useEffect(
() => setEvents(denyWindows.flatMap((denyWindow) => denyWindow.events)),
[denyWindows],
);
Copy link
Member

Choose a reason for hiding this comment

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

If we can remove this use effect we should

id: string;
};

const uuidRegex =
Copy link
Member

Choose a reason for hiding this comment

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

use zod?

id: string;
};

const uuidRegex =
Copy link
Member

Choose a reason for hiding this comment

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

zod?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (9)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/DenyWindowContext.tsx (1)

8-10: Optional: Provide default context value.

Currently, the context is initialized as undefined, which is handled by the custom hook. For additional clarity, consider providing a default context value (e.g., null for openEventId and a no-op updater) during development or testing.

apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (3)

124-171: Optional: Provide a fallback or visual cue if denyWindow is null.

Currently, the EventComponent always renders a popover. Consider gracefully handling the case where a corresponding denyWindow is unavailable or not loaded. This is handled indirectly by returning null if denyWindow == null downstream, but you might add a quick check earlier or render a fallback UI.


173-297: Handle server-side operation failures gracefully.

In the drag, resize, and create handlers, the code updates state optimistically but does not handle potential failures. Consider adding error handling to revert changes or inform users if a backend operation fails.

+ resizeDenyWindow.mutate(
+   { windowId: id, dtstartOffset, dtendOffset },
+   {
+     onError: (err) => {
+       console.error("Resize failed", err);
+       // Possibly revert UI changes or show notification
+     },
+   },
+ );

285-295: Remove or clarify commented code for deny window creation.

The creation logic is commented out. If you plan to integrate it soon, consider adding a TODO. Otherwise, remove the commented code to avoid confusion.

packages/api/src/router/policy/deny-window.ts (5)

28-74: Watch out for large result sets.

The list procedure uses flatMap to generate potentially large event arrays. For extremely large date ranges, consider adding pagination or a limit to prevent excessive data fetching.


52-73: Consider partial or lazy evaluation of getWindowsInRange.

If the generated intervals can be large, you might want to fetch or compute them in chunks. This will help avoid performance bottlenecks if users query significantly large ranges.


176-224: Allow multi-weekday recurrences.

At line 213, you overwrite byweekday with [input.day]. If the domain requires multi-day recurrences, consider merging or appending to an existing array instead.

- byweekday: [input.day as rrule.ByWeekday],
+ const updatedByWeekday = Array.isArray(denyWindow.rrule.byweekday)
+   ? [...denyWindow.rrule.byweekday, input.day as rrule.ByWeekday]
+   : [input.day as rrule.ByWeekday];
+ byweekday: updatedByWeekday,

225-249: Checks for nonexistent records.

The update procedure relies on takeFirst. If no record is found, the code does not handle that scenario explicitly. Consider throwing an error or returning a friendly message when denyWindow is not in the DB.


251-273: Ensure a consistent user experience after deletion.

The delete procedure similarly does not indicate if no record is found. If needed, handle the case where the record is already deleted or never existed to keep the UI or calling code consistent.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 695f8bc and b26d5e4.

📒 Files selected for processing (4)
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (1 hunks)
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/DenyWindowContext.tsx (1 hunks)
  • packages/api/src/router/policy/deny-window.ts (1 hunks)
  • packages/db/src/schema/policy.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/db/src/schema/policy.ts
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{ts,tsx}`: **Note on Error Handling:** Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error...

**/*.{ts,tsx}: Note on Error Handling:
Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error handling. These are acceptable as long as they maintain clarity and predictability.

  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx
  • packages/api/src/router/policy/deny-window.ts
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/DenyWindowContext.tsx
🧬 Code Definitions (1)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (2)
packages/db/src/schema/policy.ts (2)
  • PolicyRuleDenyWindow (254-256)
  • Policy (252-252)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/DenyWindowContext.tsx (2)
  • useDenyWindow (24-29)
  • DenyWindowProvider (12-22)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Lint
  • GitHub Check: Typecheck
  • GitHub Check: build (linux/amd64)
  • GitHub Check: build (linux/amd64)
🔇 Additional comments (7)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/DenyWindowContext.tsx (3)

1-10: Great use of typed context.

Defining DenyWindowContextType and passing it to createContext ensures a strong contract, preventing accidental misuse of the context properties.


12-22: Provider usage looks good.

The DenyWindowProvider correctly manages openEventId and setOpenEventId, and exposes them to the subtree. This pattern is straightforward and encourages a clean separation of concerns.


24-29: Clear custom hook.

useDenyWindow provides an excellent developer experience and enforces usage within the provider with a descriptive error. Good job ensuring the context is never accessed unexpectedly.

apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (2)

86-122: Good separation of read vs. edit states.

DenyWindowInfo and EditDenyWindow are logically separated, improving readability and maintainability by isolating presentation from editing concerns.


298-352: Calendar usage is well integrated.

The overall approach to managing the calendar with react-big-calendar and withDragAndDrop is clear. The arrangement of onRangeChange, onSelectSlot, and onEventDrop helps keep logic centralized, improving code clarity.

packages/api/src/router/policy/deny-window.ts (2)

76-105: Good usage of typed schema.

This create procedure properly references createPolicyRuleDenyWindow for validation, helping ensure data correctness at the boundary layer.


128-174: Consider negative offset validation.

In the resize procedure, ensure negative offsets (which effectively shrink windows or move them before dtstart) are acceptable or handle them gracefully. Maintaining a minimum length or limiting the shift might be necessary in some use cases.

Would you like to confirm we have a max/min offset requirement in your domain rules? If so, we can add a zod refinement or a check before updating the window.

Comment on lines +52 to +84
const EditDenyWindow: React.FC<{
denyWindow: SCHEMA.PolicyRuleDenyWindow;
setEditing: () => void;
}> = ({ denyWindow, setEditing }) => {
const form = useForm({
schema: SCHEMA.updatePolicyRuleDenyWindow,
defaultValues: denyWindow,
});

const updateDenyWindow = api.policy.denyWindow.update.useMutation();
const onSubmit = form.handleSubmit((data) => {
console.log("data", data);
// updateDenyWindow.mutate({
// id: denyWindow.id,
// data,
// });
// setEditing();
});

return (
<Form {...form}>
<form onSubmit={onSubmit}>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<Input {...field} className="border-neutral-600" />
)}
/>
</form>
</Form>
);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider hooking up the actual update mutation.

Within EditDenyWindow, the logic for updating the deny window is commented out. This might be intentional for scaffolding, but remember to implement or remove it before going live.

-    console.log("data", data);
-    // updateDenyWindow.mutate({
-    //   id: denyWindow.id,
-    //   data,
-    // });
-    // setEditing();
+    updateDenyWindow.mutate({
+      id: denyWindow.id,
+      data,
+    });
+    setEditing();
📝 Committable suggestion

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

Suggested change
const EditDenyWindow: React.FC<{
denyWindow: SCHEMA.PolicyRuleDenyWindow;
setEditing: () => void;
}> = ({ denyWindow, setEditing }) => {
const form = useForm({
schema: SCHEMA.updatePolicyRuleDenyWindow,
defaultValues: denyWindow,
});
const updateDenyWindow = api.policy.denyWindow.update.useMutation();
const onSubmit = form.handleSubmit((data) => {
console.log("data", data);
// updateDenyWindow.mutate({
// id: denyWindow.id,
// data,
// });
// setEditing();
});
return (
<Form {...form}>
<form onSubmit={onSubmit}>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<Input {...field} className="border-neutral-600" />
)}
/>
</form>
</Form>
);
};
const EditDenyWindow: React.FC<{
denyWindow: SCHEMA.PolicyRuleDenyWindow;
setEditing: () => void;
}> = ({ denyWindow, setEditing }) => {
const form = useForm({
schema: SCHEMA.updatePolicyRuleDenyWindow,
defaultValues: denyWindow,
});
const updateDenyWindow = api.policy.denyWindow.update.useMutation();
const onSubmit = form.handleSubmit((data) => {
updateDenyWindow.mutate({
id: denyWindow.id,
data,
});
setEditing();
});
return (
<Form {...form}>
<form onSubmit={onSubmit}>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<Input {...field} className="border-neutral-600" />
)}
/>
</form>
</Form>
);
};

Comment on lines +107 to +126
createInCalendar: protectedProcedure
.meta({
authorizationCheck: ({ canUser, input }) =>
canUser
.perform(Permission.PolicyCreate)
.on({ type: "policy", id: input.policyId }),
})
.input(
z.object({
policyId: z.string().uuid(),
start: z.date(),
end: z.date(),
timeZone: z.string(),
}),
)
.mutation(({ ctx, input }) => {
console.log(input);

return;
}),
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Complete the calendar creation logic.

The createInCalendar mutation currently only logs input. Finalize its implementation or remove it if it remains unused.

- console.log(input);
- return;
+ // Example:
+ return ctx.db.insert(policyRuleDenyWindow)
+   .values({
+     policyId: input.policyId,
+     name: "Calendar-based window",
+     // Additional fields...
+   })
+   .returning()
+   .then(takeFirst);
📝 Committable suggestion

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

Suggested change
createInCalendar: protectedProcedure
.meta({
authorizationCheck: ({ canUser, input }) =>
canUser
.perform(Permission.PolicyCreate)
.on({ type: "policy", id: input.policyId }),
})
.input(
z.object({
policyId: z.string().uuid(),
start: z.date(),
end: z.date(),
timeZone: z.string(),
}),
)
.mutation(({ ctx, input }) => {
console.log(input);
return;
}),
createInCalendar: protectedProcedure
.meta({
authorizationCheck: ({ canUser, input }) =>
canUser
.perform(Permission.PolicyCreate)
.on({ type: "policy", id: input.policyId }),
})
.input(
z.object({
policyId: z.string().uuid(),
start: z.date(),
end: z.date(),
timeZone: z.string(),
}),
)
.mutation(({ ctx, input }) => {
// Example:
return ctx.db.insert(policyRuleDenyWindow)
.values({
policyId: input.policyId,
name: "Calendar-based window",
// Additional fields...
})
.returning()
.then(takeFirst);
}),

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/api/src/router/policy/deny-window.ts (1)

125-128: 🛠️ Refactor suggestion

Implement or remove the placeholder createInCalendar mutation.

The createInCalendar mutation logs the input but doesn't persist data. If you intend to allow calendar-based creation, finalize it with a proper insert statement; otherwise, remove the placeholder to avoid confusion.

 console.log(input);
 return;
+// Example implementation, adjust as needed:
+return ctx.db.insert(policyRuleDenyWindow)
+  .values({
+    policyId: input.policyId,
+    // Additional fields referencing input.start, input.end, etc.
+  })
+  .returning()
+  .then(takeFirst);
🧹 Nitpick comments (4)
apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (3)

63-69: Remove or finalize the commented-out update logic.

The update code is currently commented out, which could be confusing for future maintainers. If you intend to implement this logic soon, consider adding a TODO note or finalize the mutation call. Otherwise, remove it to keep the code clean.

     console.log("data", data);
-    // updateDenyWindow.mutate({
-    //   id: denyWindow.id,
-    //   data,
-    // });
-    // setEditing();
+    updateDenyWindow.mutate({
+      id: denyWindow.id,
+      data,
+    });
+    setEditing();

230-255: Add error handling when resizing a deny window.

When the resizeDenyWindow mutation fails, there is no feedback for the user, and the UI might become out of sync. Consider adding try/catch or using the mutation’s onError callback to revert local state.

-  resizeDenyWindow.mutate({ windowId: id, dtstartOffset, dtendOffset });
+  resizeDenyWindow.mutate(
+    { windowId: id, dtstartOffset, dtendOffset },
+    {
+      onError: (error) => {
+        console.error("Failed to resize event:", error);
+        // Optionally revert local state changes or show a notification.
+      },
+    }
+  );

326-332: Review slot selection logic to avoid unintentional creation.

Currently, clicking a slot when an event popover is open discards the “new” event, but clicking when no popover is open creates a new event immediately. This might surprise users or lead to accidental creations. Consider prompting for confirmation or at least providing a form for basic input before finalizing creation.

packages/api/src/router/policy/deny-window.ts (1)

178-219: Confirm correct weekday mapping on drag.

The code sets the byweekday based on the day index. Ensure that the user’s time zone or start-of-week preferences do not lead to unexpected results. If day boundaries cross midnight, partial offsets might shift the day incorrectly from the user’s perspective.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b26d5e4 and 6ee3aa2.

📒 Files selected for processing (2)
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx (1 hunks)
  • packages/api/src/router/policy/deny-window.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{ts,tsx}`: **Note on Error Handling:** Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error...

**/*.{ts,tsx}: Note on Error Handling:
Avoid strict enforcement of try/catch blocks. Code may use early returns, Promise chains (.then().catch()), or other patterns for error handling. These are acceptable as long as they maintain clarity and predictability.

  • packages/api/src/router/policy/deny-window.ts
  • apps/webservice/src/app/[workspaceSlug]/(app)/policies/deny-windows/_components/CreateDenyRule.tsx
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Typecheck
  • GitHub Check: Lint
  • GitHub Check: build (linux/amd64)
🔇 Additional comments (1)
packages/api/src/router/policy/deny-window.ts (1)

130-155:

❓ Verification inconclusive

Consider validating window boundaries when resizing.

Resizing a deny window might cause it to overlap with other blocks or go out of permissible ranges. If relevant, add validations or user feedback to ensure a consistent UX.

Are there rules in the codebase that prevent overlapping windows or limit resizing? If so, verify them with a script:


🏁 Script executed:

#!/bin/bash
# Search for existing constraints or checks around policyRuleDenyWindow.
rg -A 6 'constraint.*policyRuleDenyWindow'

Length of output: 44


ACTION: Verify and Add Boundary Validations for Deny Window Resizing

The search for constraints enforcing non-overlapping or boundary limits on deny windows did not yield any evidence of such validations. This might imply that resizing currently lacks these checks, which could lead to overlaps or out-of-range configurations. Please verify manually whether:

  • There are additional validations elsewhere in the codebase (or in a shared utility) that guard against overlapping windows or enforce allowed ranges.
  • Resizing operations should incorporate boundary validations and user feedback to maintain a consistent UX.

If no such validations exist, consider adding explicit checks in the logic around packages/api/src/router/policy/deny-window.ts (lines 130–155).

Comment on lines +284 to +294
const handleEventCreate = (event: EventCreate) => {
console.log("creating deny window", event);
const { start, end } = event;
// // console.log("creating deny window", start, end);
// // createDenyWindow.mutate({
// // policyId: "123",
// // start,
// end,
// timeZone,
// });
setEvents((prev) => [...prev, { id: "new", start, end, title: "" }]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Finalize or remove placeholder calendar creation code.

The createDenyWindow mutation call is fully commented out. If you plan to enable it, ensure that the request is handled correctly on the API side with an appropriate response. Otherwise, remove the commented code to reduce clutter.

-    // // createDenyWindow.mutate({
-    // //   policyId: "123",
-    // //   start,
-    // //   end,
-    // //   timeZone,
-    // // });
+    createDenyWindow.mutate({
+      policyId: "123", // or retrieve real policy ID
+      start,
+      end,
+      timeZone,
+    });
📝 Committable suggestion

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

Suggested change
const handleEventCreate = (event: EventCreate) => {
console.log("creating deny window", event);
const { start, end } = event;
// // console.log("creating deny window", start, end);
// // createDenyWindow.mutate({
// // policyId: "123",
// // start,
// end,
// timeZone,
// });
setEvents((prev) => [...prev, { id: "new", start, end, title: "" }]);
const handleEventCreate = (event: EventCreate) => {
console.log("creating deny window", event);
const { start, end } = event;
// // console.log("creating deny window", start, end);
createDenyWindow.mutate({
policyId: "123", // or retrieve real policy ID
start,
end,
timeZone,
});
setEvents((prev) => [...prev, { id: "new", start, end, title: "" }]);
};

Comment on lines +127 to +128
const [editing, setEditing] = useState<boolean>(false);
const { openEventId, setOpenEventId } = useDenyWindow();
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using the any type in event props.

Using any undermines type safety and makes the code harder to maintain in the long run. Consider defining or inferring the exact event type to ensure better readability and IDE support.

-const EventComponent: React.FC<{ event: any; denyWindow: ... }> = ({ event, ... }
+interface CalendarEvent {
+  id: string;
+  title: string;
+  start: Date;
+  end: Date;
+}
+
+const EventComponent: React.FC<{
+  event: CalendarEvent;
+  denyWindow: SCHEMA.PolicyRuleDenyWindow & { policy: SCHEMA.Policy };
+}> = ({ event, denyWindow }) => { ... }
📝 Committable suggestion

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

Suggested change
const [editing, setEditing] = useState<boolean>(false);
const { openEventId, setOpenEventId } = useDenyWindow();
interface CalendarEvent {
id: string;
title: string;
start: Date;
end: Date;
}
const EventComponent: React.FC<{
event: CalendarEvent;
denyWindow: SCHEMA.PolicyRuleDenyWindow & { policy: SCHEMA.Policy };
}> = ({ event, denyWindow }) => {
// component implementation here
};

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