Skip to content

Overview fully SSR#175

Merged
Marfuen merged 3 commits into
mainfrom
mariano/portal
Mar 21, 2025
Merged

Overview fully SSR#175
Marfuen merged 3 commits into
mainfrom
mariano/portal

Conversation

@Marfuen

@Marfuen Marfuen commented Mar 21, 2025

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Introduced new functions for fetching framework categories and framework data, enhancing data retrieval capabilities.
    • Added organization control progress tracking to improve user insights on compliance metrics.
  • Bug Fixes

    • Improved error handling and redirection for unauthenticated users, ensuring a secure user experience.
  • Refactor

    • Streamlined data handling by transitioning to direct prop-based data flows for framework and control details.
    • Consolidated progress tracking and status computations for a more responsive and consistent user experience.
  • Chores

    • Removed obsolete server-side actions and hooks related to organization control data fetching, simplifying the codebase.

@vercel

vercel Bot commented Mar 21, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
app ✅ Ready (Inspect) Visit Preview 💬 Add feedback Mar 21, 2025 10:51pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
comp-portal ⬜️ Skipped (Inspect) Mar 21, 2025 10:51pm

@coderabbitai

coderabbitai Bot commented Mar 21, 2025

Copy link
Copy Markdown

Walkthrough

This pull request refactors data retrieval and component interfacing for the dashboard. Server-side actions and custom React hooks for fetching framework categories, organization controls, and progress are removed. In their place, new asynchronous functions and utility methods are introduced to fetch frameworks, control data, and compute control statuses. Component props and type definitions are updated to pass pre-fetched data, eliminating redundant hooks. Additionally, the page components have been enhanced with authentication and organization checks, ensuring that only valid sessions proceed. Error handling and redirection logic have also been improved.

Changes

File(s) Change Summary
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/actions/getFrameworkCategoriesAction.ts Removed server-side action for fetching framework categories with authentication and DB query.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/actions/{getOrganizationControl.ts, getOrganizationControlProgress.ts, getOrganizationControlRequirements.ts} Deleted server-side actions for retrieving organization control data, progress, and requirements.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/hooks/{useOrganizationControl.ts, useOrganizationControlProgress.ts, useOrganizationControlRequirements.ts} Removed custom React hooks for organization control data and progress, shifting to a prop-driven data flow.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/{FrameworkControls.tsx, FrameworkOverview.tsx, FrameworkControlsTableColumns.tsx} Updated component props and type definitions; removed redundant hooks; externalized control status logic to a utility module.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/{getFramework.ts, getFrameworkCategories.ts} Added new asynchronous functions for fetching framework and framework category data using organization context.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/data/getControl.ts Introduced a new getControl function with enhanced session validation and comprehensive data query for organization control details.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/lib/utils.ts Added a getControlStatus utility function to compute control requirement statuses based on completion criteria.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/page.tsx Modified the page component to include authentication checks, redirection logic, and passing fetched data as props to child components.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/page.tsx Updated the control page to simplify control fetching and progress handling with improved error management.

Sequence Diagram(s)

sequenceDiagram
  participant U as User
  participant FP as FrameworkPage
  participant Auth as auth()
  participant GF as getFramework()
  participant GFC as getFrameworkCategories()
  participant FO as FrameworkOverview

  U->>FP: Request framework page
  FP->>Auth: Retrieve session
  Auth-->>FP: Session with organizationId
  FP->>GF: Fetch framework (frameworkId, orgId)
  FP->>GFC: Fetch framework categories (frameworkId, orgId)
  FP->>FO: Render view with organizationFramework and organizationCategories
Loading
sequenceDiagram
  participant U as User
  participant CP as SingleControlPage
  participant Auth as auth()
  participant GC as getControl()
  participant GCP as getOrganizationControlProgress()
  participant SC as SingleControl

  U->>CP: Request control page
  CP->>Auth: Retrieve session
  Auth-->>CP: Session info
  CP->>GC: Fetch control data (id)
  GC-->>CP: Organization control details
  CP->>GCP: Fetch progress data
  GCP-->>CP: Control progress metrics
  CP->>SC: Render SingleControl with control data & progress info
Loading

Possibly related PRs

  • Mariano/stuff #55: The changes in the main PR, which involve the removal of the getFrameworkCategoriesAction function that retrieves framework categories, are related to the retrieved PR, which introduces a new function getOrganizationCategories for fetching organization categories associated with a framework, as both deal with category retrieval based on framework IDs.
  • Add statuses and keep track of policies across controls #64: The changes in the main PR, which involve the removal of the getFrameworkCategoriesAction function that retrieves framework categories, are related to the retrieved PR, as both involve handling organization control requirements and their statuses, specifically through the introduction of new functions and modifications that affect how control requirements are managed and retrieved.

Poem

Oh, I’m a rabbit with a hop so light,
Removing old hooks and actions overnight.
New functions bloom like carrots so bright,
With authentication checks to guide our flight.
Dashboard wonders leap into the view –
CodeRabbit Inc. brings magic anew! 🐰🌟

✨ 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 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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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.

@Marfuen Marfuen changed the title Mariano/portal Overview fully SSR Mar 21, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (12)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/data/getOrganizationControlProgress.ts (1)

18-88: Good implementation with robust progress calculation logic

The function correctly fetches control requirements and calculates detailed progress metrics. The approach of using a structured type for the response and systematic calculation of completed items by type is well-implemented.

Consider adding error handling for database operations to improve robustness:

export const getOrganizationControlProgress = async (controlId: string) => {
  const session = await auth();

  if (!session) {
    return {
      error: "Unauthorized",
    };
  }

+  try {
    const requirements = await db.organizationControlRequirement.findMany({
      where: {
        organizationControlId: controlId,
      },
      include: {
        organizationPolicy: true,
        organizationEvidence: true,
      },
    });

    // Rest of the function remains the same
    
    return {
      data: {
        progress,
      },
    };
+  } catch (error) {
+    console.error("Error fetching organization control progress:", error);
+    return {
+      error: "Failed to fetch control progress",
+    };
+  }
};
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/data/getControl.ts (1)

4-30: Secure implementation with good data fetching logic

The function correctly validates user session and fetches organization control data with appropriate relations. The security check ensures users can only access controls from their organization.

Similar to the progress function, consider adding error handling for database operations:

export const getControl = async (id: string) => {
  const session = await auth();

  if (!session) {
    return {
      error: "Unauthorized",
    };
  }

+  try {
    const organizationControl = await db.organizationControl.findUnique({
      where: {
        organizationId: session.user.organizationId,
        id,
      },
      include: {
        control: true,
        OrganizationControlRequirement: {
          include: {
            organizationPolicy: true,
            organizationEvidence: true,
          },
        },
      },
    });

    return organizationControl;
+  } catch (error) {
+    console.error("Error fetching organization control:", error);
+    return {
+      error: "Failed to fetch control data",
+    };
+  }
};
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/page.tsx (1)

28-39: Consider simplifying the default progress data extraction

The condition for extracting progress data is quite complex. Consider simplifying it for better readability:

-  const progressData: ControlProgressResponse = ("data" in
-    (organizationControlProgressResult || {}) &&
-    organizationControlProgressResult?.data?.progress) || {
-    total: 0,
-    completed: 0,
-    progress: 0,
-    byType: {},
-  };

+  const progressData: ControlProgressResponse = 
+    organizationControlProgressResult?.data?.progress || {
+    total: 0,
+    completed: 0,
+    progress: 0,
+    byType: {},
+  };

The simplified version works because if organizationControlProgressResult is falsy or doesn't have the expected structure, it will fall back to the default object.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFramework.ts (1)

3-21: Consider handling the case when no framework is found.

Right now, if findUnique returns null, the function simply returns null without explanation. This could propagate errors elsewhere in the application. You might want to throw or return a more descriptive error or default object to handle the scenario gracefully when a framework does not exist for the given IDs.

export const getFramework = async (
  frameworkId: string,
  organizationId: string
) => {
  const framework = await db.organizationFramework.findUnique({
    /* ... */
  });

- return framework;
+ if (!framework) {
+   throw new Error(`Framework not found for frameworkId=${frameworkId} and organizationId=${organizationId}`);
+ }
+ return framework;
};
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFrameworkCategories.ts (1)

3-36: Ensure empty result scenarios are handled.

Returning an empty array from findMany is valid, but if your downstream logic expects categories to exist, it may cause confusion. Consider verifying whether the returned array is empty and handling that case accordingly, for example by returning a default or throwing an error to make dependencies more robust.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/page.tsx (2)

19-23: Consider providing user feedback prior to redirecting.

When the session is missing, the code executes an immediate redirect("/"). Providing a brief message or an alert can help users understand why they've been redirected.


35-39: Verify the presence of required categories.

If getFrameworkCategories returns an empty array or undefined, consider how that affects your page rendering. You may want to display a helpful message on the UI instead of silently passing an empty array.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkControls.tsx (3)

3-10: Consolidate imports if they are reused in multiple files.

All of these types come from @bubba/db/types. Although this is acceptable, ensure no duplication exists in other files. If these imports are heavily reused, consider a dedicated types file to streamline imports.


15-23: Consider isolating FrameworkCategory in a shared module.

This new type extension is clean; however, it’s referenced in multiple components. To prevent drift or duplication, you might centralize the definition in a shared types file.


30-36: Avoid forcing a cast to OrganizationControlType[].

The .flatMap() call is strongly typed, but this manual casting can mask potential shape mismatches. Consider letting TypeScript infer the correct return type or refining the type to match the actual shape.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkOverview.tsx (2)

15-37: Be mindful of duplicated logic to check requirement completion.

You repeat the same “published” checks in multiple places. If feasible, centralize the requirement-completion check in a shared utility to prevent maintenance headaches down the line.


45-57: Consider reusing shared logic for control compliance.

Similar to checking requirement completion, consider factoring out the repeated logic into a helper function to avoid duplication and reduce the risk of divergences.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0956dde and c16b567.

📒 Files selected for processing (19)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/actions/getFrameworkCategoriesAction.ts (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkControls.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkOverview.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/table/FrameworkControlsTableColumns.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFramework.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFrameworkCategories.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/lib/utils.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/page.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/actions/getOrganizationControl.ts (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/actions/getOrganizationControlProgress.ts (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/actions/getOrganizationControlRequirements.ts (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/components/SingleControl.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/components/table/ControlRequirementsTable.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/data/getControl.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/data/getOrganizationControlProgress.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/hooks/useOrganizationControl.ts (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/hooks/useOrganizationControlProgress.ts (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/hooks/useOrganizationControlRequirements.ts (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/page.tsx (2 hunks)
💤 Files with no reviewable changes (8)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/components/table/ControlRequirementsTable.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/actions/getFrameworkCategoriesAction.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/hooks/useOrganizationControlRequirements.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/actions/getOrganizationControl.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/actions/getOrganizationControlRequirements.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/hooks/useOrganizationControlProgress.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/actions/getOrganizationControlProgress.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/hooks/useOrganizationControl.ts
🧰 Additional context used
🧬 Code Definitions (5)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/lib/utils.ts (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/table/FrameworkControlsTableColumns.tsx (1) (1)
  • OrganizationControlType (22-38)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/page.tsx (4)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFrameworkCategories.ts (1) (1)
  • getFrameworkCategories (3-36)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFramework.ts (1) (1)
  • getFramework (3-21)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkOverview.tsx (1) (1)
  • FrameworkOverview (15-133)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkControls.tsx (1) (1)
  • FrameworkControls (30-59)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/page.tsx (2)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/data/getControl.ts (1) (1)
  • getControl (4-30)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/data/getOrganizationControlProgress.ts (2) (2)
  • getOrganizationControlProgress (18-88)
  • ControlProgressResponse (6-16)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/components/SingleControl.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/data/getOrganizationControlProgress.ts (1) (1)
  • ControlProgressResponse (6-16)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkOverview.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkControls.tsx (1) (1)
  • FrameworkCategory (15-23)
🔇 Additional comments (18)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/data/getOrganizationControlProgress.ts (1)

6-16: Well-structured interface for progress data

The ControlProgressResponse interface provides a clear contract for the progress data structure, making it easier to understand and work with the progress metrics throughout the application.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/page.tsx (2)

21-26: Good refactoring of error handling logic

The updated code properly handles both null results and error objects, ensuring users are redirected when data isn't available.


41-46: Props-based data passing is a good improvement

Passing pre-fetched data as props to the SingleControl component simplifies the component hierarchy and removes the need for redundant hooks. This is a good architectural improvement.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/components/SingleControl.tsx (4)

13-13: Good type import for strong typing

Importing the ControlProgressResponse type provides proper type safety for the component props.


25-25: Props interface update aligns with new data flow pattern

Adding the organizationControlProgress property to the interface properly documents the component's requirements and ensures type safety.


28-41: Clean refactoring from hooks to props-based data

The component now uses the passed progress data directly instead of fetching it with a hook. The progressStatus calculation logic is clear and handles all possible states.


43-43: Loading state check includes both required props

The loading check now ensures both organizationControl and organizationControlProgress are available before rendering, which prevents potential null reference errors.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/lib/utils.ts (1)

11-21: Confirm that file URL usage and published fields align with the actual data model.

fileUrl and the published property are accessed directly, but they aren't explicitly visible in the provided type definition for OrganizationControlRequirement. Verify that these fields are indeed part of your schema. If they aren't guaranteed to exist, this may cause runtime errors or unexpected undefined behavior.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/page.tsx (3)

25-25: Check for multi-organization scenarios.

Storing organizationId in the session is fine for single-org contexts. If a user can belong to multiple organizations, ensure the correct organizationId is selected or validated here.


40-44: Ensure consistent not-found handling.

You're correctly redirecting if organizationFramework is not found. Confirm that all calls to getFramework in the codebase follow a similar pattern so that users don't remain on a page that expects valid framework data.


48-55: Commendable prop-based data flow.

Passing organizationCategories and organizationFramework as props to FrameworkOverview and FrameworkControls fosters clarity and reusability. Good job on removing redundant data-fetching hooks in the child components.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/table/FrameworkControlsTableColumns.tsx (1)

21-21: Make sure the new import aligns with all call sites.

By removing the local getControlStatus and importing it instead, you centralize the logic. Verify that the newly imported utility function retains the same signature, and ensure unit tests are added/updated to cover the new code location.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkControls.tsx (1)

25-28: Prop typing approach looks good.

Passing organizationCategories and frameworkId as explicit props directly is more flexible than hooking into internal data fetching. This reduces hidden dependencies and clarifies the contract of this component.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkOverview.tsx (5)

3-3: New typed imports are correct.

Importing Framework and OrganizationFramework plus FrameworkCategory from the local file is consistent. Just confirm those references are valid throughout your application.

Also applies to: 9-9


11-12: Props interface now ensures required data is available.

Providing organizationCategories and organizationFramework explicitly makes it clear what data the component needs. This is a solid improvement over potentially implicit data fetching.


40-43: Clean compliance metric calculation.

Calculating compliancePercentage is straightforward with the ratio of completed vs. total. This approach is maintainable and easy to debug.


76-76: UI reads framework details directly from props.

Displaying the framework’s name, description, and version from organizationFramework clarifies data flow. This is consistent with the new props-based refactor.

Also applies to: 80-80, 84-84


114-115: Dates are formatted locally; verify the user’s timezone needs.

Using format(…, "MMM d, yyyy") is good for readability. If user-specific timezones are required, consider adding locale/timezone support or clarifying that these are UTC dates.

Also applies to: 123-124

@vercel vercel Bot temporarily deployed to Preview – comp-portal March 21, 2025 22:49 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (5)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFrameworkCategories.ts (2)

15-15: Avoid using any type for status

The status property is typed as any with a comment indicating it should be a ComplianceStatus enum. Using any bypasses TypeScript's type checking benefits.

-    status: any; // ComplianceStatus enum
+    status: ComplianceStatus; // Import this enum from wherever it's defined

24-49: Consider adding explicit return type to the function

The function doesn't explicitly specify its return type, which would improve type safety and documentation.

export const getFrameworkCategories = async (
  frameworkId: string,
  organizationId: string
-) => {
+): Promise<FrameworkCategories> => {
  const organizationCategories = await db.organizationCategory.findMany({
    // ...
  });

  return organizationCategories;
};
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkControls.tsx (1)

34-36: Consider adding loading state

The component returns null if organizationCategories is not provided, but it might be better to show a loading state or skeleton UI to improve user experience.

  if (!organizationCategories) {
-    return null;
+    return <div className="flex justify-center p-4">Loading framework controls...</div>;
  }
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkOverview.tsx (2)

52-70: Code duplication in requirement status checking

The logic to determine if a requirement is completed (lines 56-67) duplicates the logic used earlier (lines 26-37). Consider extracting this into a utility function.

+ const isRequirementCompleted = (req) => {
+   switch (req.type) {
+     case "policy":
+       return req.organizationPolicy?.status === "published";
+     case "file":
+       return !!req.fileUrl;
+     case "evidence":
+       return req.organizationEvidence?.published === true;
+     default:
+       return req.published;
+   }
+ };

  const totalRequirements = requirements.length;
- const completedRequirements = requirements.filter((req) => {
-   switch (req.type) {
-     case "policy":
-       return req.organizationPolicy?.status === "published";
-     case "file":
-       return !!req.fileUrl;
-     case "evidence":
-       return req.organizationEvidence?.published === true;
-     default:
-       return req.published;
-   }
- }).length;
+ const completedRequirements = requirements.filter(isRequirementCompleted).length;

  // ...

  const compliantControls = allControls.filter((control) => {
    const controlRequirements = control.OrganizationControlRequirement;
    if (controlRequirements.length === 0) return false;

-   const completedControlRequirements = controlRequirements.filter((req) => {
-     switch (req.type) {
-       case "policy":
-         return req.organizationPolicy?.status === "published";
-       case "file":
-         return !!req.fileUrl;
-       case "evidence":
-         return req.organizationEvidence?.published === true;
-       default:
-         return req.published;
-     }
-   }).length;
+   const completedControlRequirements = controlRequirements.filter(isRequirementCompleted).length;

    return completedControlRequirements === controlRequirements.length;
  }).length;

76-80: Consider adding fallback for optional chaining

The component uses optional chaining for organizationFramework properties, but doesn't provide fallback text if these properties are undefined.

- <CardTitle>{organizationFramework?.framework.name}</CardTitle>
+ <CardTitle>{organizationFramework?.framework.name || 'Unnamed Framework'}</CardTitle>

<p className="text-sm text-muted-foreground">
- {organizationFramework?.framework.description}
+ {organizationFramework?.framework.description || 'No description available'}
</p>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c16b567 and 9a9eeab.

📒 Files selected for processing (3)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkControls.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkOverview.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFrameworkCategories.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkControls.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFrameworkCategories.ts (1) (1)
  • FrameworkCategories (11-22)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkOverview.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/data/getFrameworkCategories.ts (1) (1)
  • FrameworkCategories (11-22)
🔇 Additional comments (8)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkControls.tsx (3)

8-11: Good use of strongly typed props

The component now correctly uses the imported FrameworkCategories type for the props, making the component more type-safe.


13-16: Props refactoring improves component architecture

The component now accepts pre-fetched data as props rather than fetching it internally, which is a best practice for separation of concerns and improves testability.


20-31: Improved naming clarity with orgControl

Renaming the variable from control to orgControl makes the code more readable by avoiding confusion between the organization control object and the nested control property.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/[frameworkId]/components/FrameworkOverview.tsx (5)

10-13: Props typing improved with detailed types

The props interface now clearly specifies the expected data structure with proper typing, enhancing type safety and making the component's dependencies explicit.


15-18: Component now receives pre-fetched data

Refactoring to accept pre-fetched data as props follows best practices for separation of concerns and improves testability.


19-38: Well-structured compliance calculation logic

The calculation of compliance metrics is well-organized and handles different requirement types appropriately. Good use of flatMap to process nested arrays.


39-43: Prevent division by zero with guard clause

Good defensive programming by checking if totalRequirements is greater than zero before calculating the percentage.


114-116: Good handling of date formatting with fallbacks

The component correctly handles potential undefined dates by providing fallback text when dates are not available.

Also applies to: 123-125

Comment on lines +28 to +46
const organizationCategories = await db.organizationCategory.findMany({
where: {
organizationId,
frameworkId,
},
include: {
organizationControl: {
include: {
control: true,
OrganizationControlRequirement: {
include: {
organizationPolicy: true,
organizationEvidence: true,
},
},
},
},
},
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for database query

The database query lacks error handling. If the query fails, the error will propagate up the call stack without any context about what operation failed.

export const getFrameworkCategories = async (
  frameworkId: string,
  organizationId: string
) => {
+  try {
    const organizationCategories = await db.organizationCategory.findMany({
      where: {
        organizationId,
        frameworkId,
      },
      include: {
        organizationControl: {
          include: {
            control: true,
            OrganizationControlRequirement: {
              include: {
                organizationPolicy: true,
                organizationEvidence: true,
              },
            },
          },
        },
      },
    });

    return organizationCategories;
+  } catch (error) {
+    console.error(`Failed to fetch framework categories: ${error}`);
+    throw new Error(`Failed to fetch framework categories for framework ${frameworkId} and organization ${organizationId}`);
+  }
};
📝 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 organizationCategories = await db.organizationCategory.findMany({
where: {
organizationId,
frameworkId,
},
include: {
organizationControl: {
include: {
control: true,
OrganizationControlRequirement: {
include: {
organizationPolicy: true,
organizationEvidence: true,
},
},
},
},
},
});
export const getFrameworkCategories = async (
frameworkId: string,
organizationId: string
) => {
try {
const organizationCategories = await db.organizationCategory.findMany({
where: {
organizationId,
frameworkId,
},
include: {
organizationControl: {
include: {
control: true,
OrganizationControlRequirement: {
include: {
organizationPolicy: true,
organizationEvidence: true,
},
},
},
},
},
});
return organizationCategories;
} catch (error) {
console.error(`Failed to fetch framework categories: ${error}`);
throw new Error(
`Failed to fetch framework categories for framework ${frameworkId} and organization ${organizationId}`
);
}
};

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.

1 participant