Skip to content

Monolith#157

Merged
Marfuen merged 12 commits into
mainfrom
mariano/org-switcher
Mar 19, 2025
Merged

Monolith#157
Marfuen merged 12 commits into
mainfrom
mariano/org-switcher

Conversation

@Marfuen
Copy link
Copy Markdown
Contributor

@Marfuen Marfuen commented Mar 19, 2025

Summary by CodeRabbit

  • New Features
    • Enhanced dashboard navigation with organization-specific routing. Now, policies, risks, tests, and people sections automatically display content based on your organization.
    • New organization switcher and updated sign-in flows deliver a streamlined onboarding experience.
    • Introduced new components for managing evidence and task assignments, improving user interaction.
  • Improvements
    • Refined loading states and dynamic table skeletons provide smoother visual feedback.
    • Overall UI adjustments improve layout consistency and accessibility.
    • Updated import paths for organization-specific hooks enhance modularity and flexibility.
  • Documentation
    • Updated documentation streamlines setup instructions and clarifies configuration details for a better user experience.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 19, 2025

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 19, 2025 8:54pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
comp-portal ⬜️ Skipped (Inspect) Mar 19, 2025 8:54pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 19, 2025

Walkthrough

This update introduces a new action to change a user’s organization and revamps many API endpoints, layouts, and UI components to incorporate dynamic organization identifiers. Routing and revalidation paths now embed the organizationId, affecting actions for API key creation, policies, risks, tests, evidence, and people. New layout components and hooks enable organization-specific navigation, while legacy layouts are removed. In addition, authentication logic and middleware are updated alongside widespread formatting, import path, and documentation improvements.

Changes

File(s) Change Summary
apps/app/src/actions/change-organization.ts, create-api-key-action.ts, create-organization-action.ts,
revoke-api-key-action.ts, create-new-policy.ts, update-policy-action.ts, update-policy-form-action.ts, update-policy-overview-action.ts, create-policy-comment.ts, create-risk-action.ts,
create-risk-comment.ts, create-task-action.ts, create-task-comment.ts, revalidate-upload.ts, update-task-action.ts,
update-inherent-risk-action.ts, update-residual-risk-action.ts, update-risk-action.ts
Introduced new changeOrganizationAction, updated revalidation paths to include organizationId, and applied formatting adjustments across many actions.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/... (Evidence, Policies, Risk, Tests, People,
Vendors, etc.)
New layout components and pages now use dynamic routing via useParams for organization-specific paths; legacy layouts are removed and replaced with updated ones supporting organization-aware navigation.
apps/app/src/auth/config.ts, apps/app/src/auth/org.ts, create-organization-form.tsx, google-sign-in.tsx Enhanced authentication flows by adding an orgName parameter for creating organizations, and updated redirection paths to reflect organization-specific contexts.
apps/app/src/components/header.tsx, main-menu.tsx, mobile-menu.tsx, organization-switcher.tsx,
tables, charts, risks
Updated UI components to include dynamic organizationIds in links and routing, with added type improvements and consistent formatting.
apps/app/src/data/getOrganizations.ts, apps/app/src/hooks/use-compliance-scores.ts Introduced a new utility function for fetching organizations and updated hook import paths for organization-specific data retrieval.
apps/app/src/middleware.ts, packages/db/docker-compose.yml, packages/docs/development.mdx Added session validation and improved redirection logic in middleware; minor formatting and documentation updates were applied.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant CA as changeOrganizationAction
    participant DB as Database
    participant Log as Logger

    U->>CA: Request organization change (orgId)
    CA->>DB: Query organization by orgId
    alt Organization exists
      DB-->>CA: Organization data
      CA->>DB: Update user's organization
      CA->>U: Return success with organization info
    else Organization not found
      DB-->>CA: Not found
      CA->>Log: Log error
      CA->>U: Return failure ("organization not found")
    end
Loading
sequenceDiagram
    participant U as User
    participant MW as Middleware/Auth
    participant RT as Router

    U->>MW: Request page/resource
    alt Authenticated & orgId present
      MW->>RT: Redirect to "/[orgId]/dashboard"
    else Unauthenticated or missing orgId
      MW->>RT: Redirect to "/auth" or "/setup"
    end
Loading

Possibly Related PRs

Poem

I’m a little bunny, hopping with delight,
Coding paths that shine so bright,
Org IDs now lead the way,
In every route, they proudly stay.
With a twitch of my nose and a happy little hop,
I celebrate these changes—nonstop!

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.
✨ 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.

Copy link
Copy Markdown

@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: 9

🧹 Nitpick comments (47)
packages/docs/development.mdx (1)

19-21: Code Block Language Annotation
The npm installation code block now uses the language specifier "bash npm". Although this might be an intentional styling choice, consider standardizing the language annotation (e.g., using just "bash" or "shell") unless there is a specific requirement for highlighting.

apps/app/src/components/forms/create-test-comment-form.tsx (3)

36-44: Naming Inconsistency: Action Variable
The variable createPolicyComment is assigned the value from createTestCommentAction. Since the component and the imported action refer to test comments, consider renaming createPolicyComment to createTestComment for clarity and consistency.

Example diff suggestion:

-  const createPolicyComment = useAction(createTestCommentAction, {
+  const createTestComment = useAction(createTestCommentAction, {

54-56: Submission Handler Relies on Action Variable
The onSubmit function correctly calls the execution method on the action. If you decide to rename the variable as suggested above, remember to update its reference here as well.


58-107: JSX Structure and Accordion Usage
The JSX returned by the component is well-structured. One point to consider: the Accordion is configured with a default value of ["policy"], which might be a leftover from previous naming conventions. If the intent is strictly to create test comments, you may want to review if this value should be updated to something more descriptive (e.g., "test-comment").

apps/app/src/components/tables/risk-register/empty-states.tsx (1)

53-69: NoRisks component is missing organization context.

Unlike the NoResults component, NoRisks doesn't utilize the organization ID when opening the create risk sheet. Consider updating the CreateRiskSheet component usage to pass the organization ID context.

-			<CreateRiskSheet />
+			<CreateRiskSheet orgId={orgId} />

This would require:

  1. Updating the component to extract the orgId:
const { orgId } = useParams<{ orgId: string }>();
  1. Ensuring the CreateRiskSheet component accepts an orgId prop.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/layout.tsx (3)

1-7: Unused import detected

The Title component is imported on line 2 but never used in this file.

-import { Title } from "@/components/title";

53-65: Enhance cache key for better performance

The cache key "risk-cache" is too generic and might not effectively distinguish between different risk IDs and organizations, leading to potential cache collisions.

const getRisk = unstable_cache(
	async (riskId: string, organizationId: string) => {
		const risk = await db.risk.findUnique({
			where: {
				id: riskId,
				organizationId: organizationId,
			},
		});

		return risk;
	},
-	["risk-cache"],
+	["risk-cache", (riskId: string, organizationId: string) => `${organizationId}-${riskId}`],
);

54-63: Add error handling for database operations

The database query lacks error handling. If the query fails, it will throw an uncaught exception.

async (riskId: string, organizationId: string) => {
+	try {
		const risk = await db.risk.findUnique({
			where: {
				id: riskId,
				organizationId: organizationId,
			},
		});

		return risk;
+	} catch (error) {
+		console.error("Error fetching risk:", error);
+		return null;
+	}
},
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/layout.tsx (2)

10-13: Consider adding fallback for potentially undefined orgId.

The code retrieves the organization ID but doesn't include a fallback if user or user.organizationId is undefined. This could lead to invalid routes like /undefined/vendors.

 const session = await auth();
 const user = session?.user;
 const orgId = user?.organizationId;
+const safeOrgId = orgId || ""; // Fallback to empty string or redirect if no orgId

If no organization ID should be available, consider redirecting the user:

if (!orgId) {
  redirect("/select-organization"); // Redirect to appropriate page
}

18-24: Commented-out menu items.

I notice there are commented-out menu items for a "vendors register" section. If this is planned for future implementation, consider adding a TODO comment explaining when these will be uncommented, or remove them if they're not intended to be used.

items={[
  { path: `/${orgId}/vendors`, label: t("vendors.dashboard.title") },
  // TODO: Uncomment when vendors register feature is implemented in ticket #XYZ
  // {
  // 	path: `/${orgId}/vendors/register`,
  // 	label: t("vendors.register.title"),
  // },
]}
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/layout.tsx (1)

1-14: Add fallback handling for missing organizationId.

The component correctly retrieves the organization ID from the user session, but there's no fallback handling if the session or organization ID is missing.

 	const t = await getI18n();
 	const session = await auth();
 	const user = session?.user;
 	const orgId = user?.organizationId;
+
+	if (!orgId) {
+		// Consider redirecting to an error page or a page where the user can select an organization
+		// or provide a reasonable fallback behavior
+	}
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/layout.tsx (1)

1-12: Add fallback handling for missing organizationId.

The component correctly retrieves the organization ID, but there's no fallback handling if the session or organization ID is missing.

 import { auth } from "@/auth";
 import { getI18n } from "@/locales/server";
 import { SecondaryMenu } from "@bubba/ui/secondary-menu";

 export default async function Layout({
 	children,
 }: {
 	children: React.ReactNode;
 }) {
 	const t = await getI18n();
 	const session = await auth();
 	const organizationId = session?.user?.organizationId;
+
+	if (!organizationId) {
+		// Consider redirecting to an error page or a page where the user can select an organization
+		// or provide a reasonable fallback behavior
+	}
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/layout.tsx (1)

1-27: Well-structured layout implementation with organization-specific routing.

The layout follows the established pattern seen in other similar layout files, properly retrieving i18n translations and authentication data to construct organization-specific navigation paths.

Consider adding error handling for cases where the user is not authenticated or the organization ID is missing, similar to what's implemented in the risk/[riskId]/layout.tsx file:

export default async function Layout({
	children,
}: {
	children: React.ReactNode;
}) {
	const t = await getI18n();
	const session = await auth();
	const user = session?.user;
	const orgId = user?.organizationId;
+
+	if (!session || !orgId) {
+		redirect("/");
+	}

	return (
		<div className="max-w-[1200px] m-auto">
			<SecondaryMenu
				items={[
					{ path: `/${orgId}/risk`, label: t("risk.dashboard.title") },
					{ path: `/${orgId}/risk/register`, label: t("risk.register.title") },
				]}
			/>

			<main className="mt-8">{children}</main>
		</div>
	);
}
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/layout.tsx (1)

1-26: Good implementation of evidence detail layout with proper organization context.

The layout correctly implements the PathProvider for evidence-specific navigation and passes the organization ID with proper null handling. The component follows the established pattern seen in other layout files.

Consider adding error handling for cases where the user is not authenticated or the organization ID is missing:

export default async function Layout({
	children,
}: {
	children: React.ReactNode;
}) {
	const t = await getI18n();
	const session = await auth();
	const user = session?.user;
	const organizationId = user?.organizationId;
+
+	if (!session || !organizationId) {
+		redirect("/");
+	}

	return (
		<div className="max-w-[1200px] m-auto">
			<PathProvider
				organizationId={organizationId ?? ""}
				translationBackButton={t("evidence.dashboard.layout_back_button")}
				translationOverview={t("evidence.overview")}
				translationEdit={t("evidence.edit")}
			/>
			<main className="py-4">{children}</main>
		</div>
	);
}
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/layout.tsx (2)

1-4: Add a newline after imports for consistency.

Missing a newline after the import statements, which is inconsistent with other similar layout files.

import { getI18n } from "@/locales/server";
import { SecondaryMenu } from "@bubba/ui/secondary-menu";
import { auth } from "@/auth";
+
export default async function Layout({

4-32: Well-structured tests layout with organization-specific routing.

The layout correctly implements the SecondaryMenu with proper organization-specific paths. The component follows the established pattern seen in other layout files.

Consider adding error handling for cases where the user is not authenticated or the organization ID is missing:

export default async function Layout({
	children,
}: {
	children: React.ReactNode;
}) {
	const t = await getI18n();
	const session = await auth();
	const user = session?.user;
	const organizationId = user?.organizationId;
+
+	if (!session || !organizationId) {
+		redirect("/");
+	}

	return (
		<div className="max-w-[1200px] m-auto">
			<SecondaryMenu
				items={[
					{
						path: `/${organizationId}/tests`,
						label: t("tests.dashboard.overview"),
					},
					{
						path: `/${organizationId}/tests/all`,
						label: t("tests.dashboard.all"),
					},
				]}
			/>

			<main className="mt-8">{children}</main>
		</div>
	);
}
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/layout.tsx (2)

9-14: Clarify dynamic import strategy

The HotKeys component is loaded dynamically but has ssr: true. This seems contradictory as dynamic imports are typically used to reduce the initial bundle size by deferring loading until client-side. If SSR is needed, consider explaining the reason in a comment or possibly use a regular import instead.


23-24: Add error handling for Promise resolution

The code awaits params without any error handling. If the Promise rejection occurs, it could cause unhandled rejection errors. Consider adding try/catch for proper error handling:

-	const session = await auth();
-	const orgId = (await params).orgId;
+	const session = await auth();
+	let orgId;
+	try {
+		orgId = (await params).orgId;
+	} catch (error) {
+		console.error("Failed to resolve params:", error);
+		redirect("/");
+	}
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/components/table/ControlRequirementsTable.tsx (1)

39-43: Remove console.log in production code

There's a console.log statement in the onRowClick function which should be removed before deploying to production:

 const onRowClick = (requirement: RequirementTableData) => {
-	console.log({
-		requirement,
-	});
 	switch (requirement.type) {
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/layout.tsx (1)

17-19: Consider more flexible menu items implementation

The menu items array has been hardcoded to a single item. If there were multiple items before, or if you anticipate adding more in the future, consider a more flexible approach:

 	<SecondaryMenu
-		items={[{ path: `/${orgId}/people`, label: t("people.title") }]}
+		items={[
+			{ path: `/${orgId}/people`, label: t("people.title") },
+			// Additional items can be added here
+		]}
 	/>
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/components/table/RiskRegisterColumns.tsx (1)

8-10: Consider adding a brief documentation comment

Consider adding a brief JSDoc comment to explain the purpose of this function and the parameter:

+/**
+ * Creates column definitions for the risk register table with organization-specific links
+ * @param orgId - The organization ID used in navigation links
+ * @returns Column definitions for the risk register table
+ */
 export const columns = (
 	orgId: string,
 ): ColumnDef<Risk & { owner: User | null }>[] => [
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/layout.tsx (1)

12-14: Consider adding error handling for missing session.

While the code correctly retrieves the session and extracts the organization ID, there's no error handling for cases where the session or user might be undefined.

 const session = await auth();
 const user = session?.user;
 const orgId = user?.organizationId;
+if (!orgId) {
+  // Handle missing organization ID case
+  // Could redirect to an error page or default organization
+}
apps/app/src/actions/change-organization.ts (1)

16-18: Consider renaming event to match the action name.
The metadata.track.event is "create-employee", which might be misleading for a changeOrganizationAction.

Here's a diff illustrating a revised event name:

-      event: "create-employee",
+      event: "change-organization",
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/(overview)/components/table/PoliciesTable.tsx (2)

34-34: Confirm usage of router.replace.
Using router.replace removes the previous entry from the history stack. If you need to preserve it, consider router.push.


82-86: Remove or restore commented-out CTA code.
The CTA for creating a policy is fully commented out, which can lead to confusion. Remove it if it's deprecated or reintroduce it if still needed.

apps/app/src/app/[locale]/(app)/setup/page.tsx (1)

17-21: Query is simple and efficient.
Sorting frameworks by name in ascending order is a standard approach. If this grows large in the future, consider adding an index on the database.

apps/app/src/components/sidebar.tsx (1)

18-23: Cookie retrieval is handled safely.
Falling back to null if the cookie is missing prevents runtime errors. Consider catching JSON parse errors if the cookie is corrupted.

  const cookieStore = await cookies();
  const initialItems = cookieStore.has(Cookies.MenuConfig)
-    ? JSON.parse(cookieStore.get(Cookies.MenuConfig)?.value ?? "")
-    : null;
+    ? safeParseJSON(cookieStore.get(Cookies.MenuConfig)?.value)
+    : null;
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/editor/components/PolicyDetails.tsx (3)

42-42: Redirect to all policies page is inconsistent

You're redirecting to /${orgId}/policies if a policy isn't found, but based on your file structure, it seems like the "all policies" page would be at /${orgId}/policies/all.

- if (!policy) return redirect(`/${orgId}/policies`);
+ if (!policy) return redirect(`/${orgId}/policies/all`);

44-48: Complex policy content formatting could be refactored

The content formatting logic handles multiple data structures but is somewhat complex and could benefit from a cleaner approach.

- const formattedContent = Array.isArray(policy.content)
-   ? policy.content
-   : typeof policy.content === "object" && policy.content !== null
-     ? [policy.content as JSONContent]
-     : [];

+ const formattedContent = (() => {
+   if (Array.isArray(policy.content)) return policy.content;
+   if (typeof policy.content === "object" && policy.content !== null) return [policy.content as JSONContent];
+   return [];
+ })();

50-62: Error handling in handleSavePolicy could be improved

The function logs and rethrows errors, which is good for debugging but doesn't provide user feedback.

Consider using a toast notification or error state to inform users:

+ const [saveError, setSaveError] = useState<string | null>(null);

  const handleSavePolicy = async (content: JSONContent[]): Promise<void> => {
    if (!policy) return;
+   setSaveError(null);

    try {
      await updatePolicy({
        ...policy,
        content,
      });
    } catch (error) {
      console.error("Error saving policy:", error);
+     setSaveError("Failed to save policy. Please try again.");
      throw error;
    }
  };

Then display the error in your UI if saveError is not null.

apps/app/src/middleware.ts (1)

46-50: Matcher configuration could be more maintainable

The current matcher uses a negative lookahead regex which can be hard to maintain. Consider using an array of paths for better readability.

export const config = {
-  matcher: [
-    // Skip auth-related routes
-    "/((?!api|_next/static|_next/image|favicon.ico|monitoring|ingest|auth/callback|auth/signin|auth/signout).*)",
-  ],
+  matcher: [
+    // Match all paths
+    "/(.*)",
+    // Exclude specific paths
+    "/(api|_next/static|_next/image|favicon.ico|monitoring|ingest)/:path*",
+    "/(auth/callback|auth/signin|auth/signout)/:path*",
+  ],
};
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/editor/page.tsx (2)

6-15: Function signature could include orgId parameter

The PolicyEditor function accepts locale and policyId but doesn't include orgId in its params type, despite the route path including an [orgId] parameter.

export default async function PolicyEditor({
  params,
}: {
-  params: Promise<{ locale: string; policyId: string }>;
+  params: Promise<{ locale: string; policyId: string; orgId: string }>;
}) {
-  const { locale, policyId } = await params;
+  const { locale, policyId, orgId } = await params;
  setStaticParamsLocale(locale);

  return <PolicyDetails policyId={policyId} />;
}

You might need to pass orgId to PolicyDetails if it doesn't already retrieve it via useParams().


17-30: The same issue exists in generateMetadata function

Similar to the PolicyEditor function, generateMetadata is missing the orgId parameter.

export async function generateMetadata({
  params,
}: {
-  params: Promise<{ locale: string; policyId: string }>;
+  params: Promise<{ locale: string; policyId: string; orgId: string }>;
}): Promise<Metadata> {
  const { locale } = await params;

  setStaticParamsLocale(locale);
  const t = await getI18n();

  return {
    title: t("sub_pages.policies.policy_details"),
  };
}
apps/app/src/actions/organization/create-organization-action.ts (1)

22-25: Consider removing redundant validation

The manual check for !name || !website seems redundant since you're already using Zod schema validation with organizationSchema, which should catch these validation errors before this point.

-  if (!name || !website) {
-    console.log("Invalid input detected:", { name, website });
-    throw new Error("Invalid user input");
-  }
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/PathProvider.tsx (1)

23-35: Add defensive checks for parsing the evidence ID

The current implementation assumes a specific URL structure. Consider adding more defensive checks to handle unexpected path formats.

 useEffect(() => {
   const pathParts = pathname.split("/");
   const evidenceIndex = pathParts.findIndex((part) => part === "evidence");
   const id =
     evidenceIndex >= 0 && pathParts.length > evidenceIndex + 1
       ? pathParts[evidenceIndex + 1]
       : "";

+  // Reset evidenceId if we navigate away from evidence pages
+  if (!pathname.includes("/evidence/") || pathname.endsWith("/evidence/list")) {
+    setEvidenceId("");
+    return;
+  }
+
   // Only update if we've got a valid ID
   if (id && id !== "list") {
     setEvidenceId(id);
   }
 }, [pathname]);
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/components/FrameworkProgress.tsx (1)

17-18: Remove unused auth import

The auth import from "@/auth" is not being used in this component.

-import { auth } from "@/auth";
apps/app/src/components/organization-switcher.tsx (3)

27-36: Simplify success condition in useAction callback

The condition if (result.data?.success) is redundant because the onSuccess callback is only called when the action succeeds. You can simplify this code.

const { execute } = useAction(changeOrganizationAction, {
  onSuccess: (result) => {
-   if (result.data?.success) {
-     router.push(`/${result.data.data?.id}`);
-   }
+   router.push(`/${result.data.data?.id}`);
  },
  onError: (error) => {
    console.error(error);
  },
});

51-53: Add fallback for organization name

There's no fallback text when currentOrganization is undefined, which might happen if the provided organizationId doesn't match any organization in the list.

<span className="hidden md:inline-block">
-  {currentOrganization?.name}
+  {currentOrganization?.name || "Select Organization"}
</span>

73-74: Internationalize "Create new org" text

The text "Create new org" is hardcoded, unlike other parts of the application that use internationalization. Consider using the translation system for consistency.

<Plus className="h-4 w-4" />
-<span>Create new org</span>
+<span>{t("organization.switcher.create_new")}</span>

Don't forget to add the useI18n hook:

+import { useI18n } from "@/locales/client";

export function OrganizationSwitcher({
  organizations,
  organizationId,
}: OrganizationSwitcherProps) {
  const router = useRouter();
+  const t = useI18n();
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/page.tsx (1)

45-60: Caching approach is fine; consider adding minimal error handling.
It's generally good to handle or propagate errors when performing database transactions, even though a try/catch might be placed upstream.

apps/app/src/components/risks/charts/risks-by-assignee.tsx (2)

29-49: Retrieving user stats and building local objects.
Implementation is clear. Sorting in memory is fine for small sets but could move to DB-level sorting if performance needs expand.


50-168: UI layout for risk progress bars is well-structured.
Utilizing color-coded segments for different statuses improves clarity. Consider providing a fallback name or clarifying label for "Unknown User" for completeness.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/page.tsx (1)

19-30: Consider optimizing the repeated organizationId reference.

The organizationId is fetched from session.user twice. Consider storing it in a variable before line 25 to avoid duplicate property access.

 const session = await auth();

 if (!session?.user?.organizationId) {
   redirect("/onboarding");
 }

+const organizationId = session.user.organizationId;
-const overview = await getTestsOverview(session.user.organizationId);
-const organizationId = session.user.organizationId;
+const overview = await getTestsOverview(organizationId);

 if (overview?.totalTests === 0) {
   redirect(`/${organizationId}/tests/all`);
 }
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/page.tsx (1)

28-28: Consider storing organizationId in a variable to avoid repetition.

Similar to the tests overview page, consider extracting the organizationId into a variable before using it multiple times.

 if (!session?.user?.organizationId) {
   redirect("/onboarding");
 }

+const organizationId = session.user.organizationId;
-const overview = await getPoliciesOverview(session.user.organizationId);
+const overview = await getPoliciesOverview(organizationId);

 if (overview?.totalPolicies === 0) {
-  redirect(`/${session.user.organizationId}/policies/all`);
+  redirect(`/${organizationId}/policies/all`);
 }
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/page.tsx (1)

59-70: Consider caching the users data for improved performance.

While getPolicy is correctly cached, getUsers isn't. Since organization members don't change frequently during a session, consider applying similar caching to getUsers for better performance.

-const getUsers = async (organizationId: string) => {
+const getUsers = cache(async (organizationId: string) => {
   const orgMembers = await db.organizationMember.findMany({
     where: { organizationId: organizationId },
     include: {
       user: true,
     },
   });

   const users = orgMembers.map((member) => member.user);

   return users;
-};
+});
apps/app/src/components/main-menu.tsx (2)

33-43: Fix typo in menuIcons mapping

There's a typo in the menuIcons mapping for the 'people' icon.

- people: Icons.Peolple,
+ people: Icons.People,

183-247: Consistent typo in people icon usage

The same typo from the menuIcons mapping appears in the defaultItems array.

- icon: Icons.Peolple,
+ icon: Icons.People,
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 339eaac and fc3048c.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (103)
  • apps/app/src/actions/change-organization.ts (1 hunks)
  • apps/app/src/actions/organization/create-api-key-action.ts (1 hunks)
  • apps/app/src/actions/organization/create-organization-action.ts (1 hunks)
  • apps/app/src/actions/organization/revoke-api-key-action.ts (1 hunks)
  • apps/app/src/actions/policies/create-new-policy.ts (1 hunks)
  • apps/app/src/actions/policies/update-policy-action.ts (2 hunks)
  • apps/app/src/actions/policies/update-policy-form-action.ts (3 hunks)
  • apps/app/src/actions/policies/update-policy-overview-action.ts (1 hunks)
  • apps/app/src/actions/policy/create-policy-comment.ts (1 hunks)
  • apps/app/src/actions/risk/create-risk-action.ts (1 hunks)
  • apps/app/src/actions/risk/create-risk-comment.ts (1 hunks)
  • apps/app/src/actions/risk/task/create-task-action.ts (1 hunks)
  • apps/app/src/actions/risk/task/create-task-comment.ts (1 hunks)
  • apps/app/src/actions/risk/task/revalidate-upload.ts (1 hunks)
  • apps/app/src/actions/risk/task/update-task-action.ts (1 hunks)
  • apps/app/src/actions/risk/update-inherent-risk-action.ts (1 hunks)
  • apps/app/src/actions/risk/update-residual-risk-action.ts (1 hunks)
  • apps/app/src/actions/risk/update-risk-action.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/(home)/components/FrameworkProgress.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/components/FrameworkProgress.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/components/table/ControlRequirementsTable.tsx (3 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/PathProvider.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/components/table/EvidenceListTable.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/loading.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/overview/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/[employeeId]/actions/update-department.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/[employeeId]/components/EmployeeDetails.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/components/table/EmployeesTable.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/layout.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/page.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/(overview)/components/table/PoliciesTable.tsx (4 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/(overview)/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/editor/components/PolicyDetails.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/editor/page.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/page.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/page.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/RiskRegisterTable.tsx (3 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/components/table/RiskRegisterColumns.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/layout.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/members/loading.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/page.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/hooks/useTest.ts (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/layout.tsx (2 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/layout.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/list/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/overview/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/people/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/(overview)/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/(overview)/page.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/(overview)/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/[policyId]/editor/components/PolicyDetails.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/[policyId]/editor/page.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/[policyId]/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/[policyId]/page.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/risk/(overview)/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/risk/(overview)/page.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/risk/[riskId]/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/risk/register/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/settings/members/loading.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/tests/(overview)/layout.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/tests/(overview)/page.tsx (0 hunks)
  • apps/app/src/app/[locale]/(app)/setup/page.tsx (1 hunks)
  • apps/app/src/app/page.tsx (1 hunks)
  • apps/app/src/auth/config.ts (1 hunks)
  • apps/app/src/auth/org.ts (1 hunks)
  • apps/app/src/components/forms/create-organization-form.tsx (2 hunks)
  • apps/app/src/components/forms/create-test-comment-form.tsx (2 hunks)
  • apps/app/src/components/forms/risks/create-risk-form.tsx (1 hunks)
  • apps/app/src/components/google-sign-in.tsx (1 hunks)
  • apps/app/src/components/header.tsx (1 hunks)
  • apps/app/src/components/main-menu.tsx (12 hunks)
  • apps/app/src/components/mobile-menu.tsx (1 hunks)
  • apps/app/src/components/organization-switcher.tsx (1 hunks)
  • apps/app/src/components/policies/charts/policies-by-framework.tsx (1 hunks)
  • apps/app/src/components/risks/charts/risks-by-assignee.tsx (2 hunks)
  • apps/app/src/components/sheets/invite-user-sheet.tsx (1 hunks)
  • apps/app/src/components/sheets/test-comment-sheet.tsx (1 hunks)
  • apps/app/src/components/sidebar.tsx (1 hunks)
  • apps/app/src/components/tables/people/data-table.tsx (4 hunks)
  • apps/app/src/components/tables/people/empty-states.tsx (3 hunks)
  • apps/app/src/components/tables/policies/columns.tsx (1 hunks)
  • apps/app/src/components/tables/policies/empty-states.tsx (1 hunks)
  • apps/app/src/components/tables/risk-register/empty-states.tsx (1 hunks)
  • apps/app/src/components/tables/tests/data-table.tsx (1 hunks)
  • apps/app/src/components/tables/tests/filter-toolbar.tsx (1 hunks)
  • apps/app/src/components/ui/data-table/DataTable.tsx (1 hunks)
  • apps/app/src/components/ui/data-table/DataTableSkeleton.tsx (1 hunks)
  • apps/app/src/data/getOrganizations.ts (1 hunks)
  • apps/app/src/hooks/use-compliance-scores.ts (1 hunks)
  • apps/app/src/middleware.ts (1 hunks)
  • packages/db/docker-compose.yml (1 hunks)
  • packages/docs/development.mdx (5 hunks)
💤 Files with no reviewable changes (20)
  • apps/app/src/app/[locale]/(app)/(dashboard)/risk/register/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/[id]/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/risk/(overview)/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/(home)/components/FrameworkProgress.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/people/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/list/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/evidence/overview/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/tests/(overview)/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/(overview)/page.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/(overview)/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/[policyId]/editor/components/PolicyDetails.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/[policyId]/editor/page.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/[policyId]/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/[policyId]/page.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/tests/(overview)/page.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/policies/all/(overview)/layout.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/settings/members/loading.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/risk/(overview)/page.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/risk/[riskId]/layout.tsx
🧰 Additional context used
🧬 Code Definitions (27)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/loading.tsx (1)
apps/app/src/components/ui/data-table/DataTableSkeleton.tsx (1) (1)
  • DataTableSkeleton (21-79)
apps/app/src/actions/policies/create-new-policy.ts (1)
apps/app/src/actions/schema.ts (1) (1)
  • createPolicySchema (275-280)
apps/app/src/components/mobile-menu.tsx (1)
apps/app/src/components/main-menu.tsx (1) (1)
  • MainMenu (180-402)
apps/app/src/actions/organization/create-organization-action.ts (3)
apps/app/src/actions/schema.ts (1) (1)
  • organizationSchema (13-20)
apps/app/src/auth/org.ts (1) (1)
  • createOrganizationAndConnectUser (25-78)
apps/app/src/jobs/tasks/organization/create-organization.ts (1) (1)
  • createOrganizationTask (8-105)
apps/app/src/components/header.tsx (3)
apps/app/src/data/getOrganizations.ts (1) (1)
  • getOrganizations (4-28)
apps/app/src/components/mobile-menu.tsx (1) (1)
  • MobileMenu (9-36)
apps/app/src/components/organization-switcher.tsx (1) (1)
  • OrganizationSwitcher (21-79)
apps/app/src/components/sidebar.tsx (1)
apps/app/src/components/main-menu.tsx (1) (1)
  • MainMenu (180-402)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/layout.tsx (5)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/overview/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/(overview)/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/layout.tsx (1) (1)
  • Layout (4-32)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/layout.tsx (1) (1)
  • Layout (5-31)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/editor/components/PolicyDetails.tsx (2)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/page.tsx (1) (1)
  • PolicyDetails (10-31)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/editor/page.tsx (1) (1)
  • PolicyEditor (6-15)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/(overview)/layout.tsx (6)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/overview/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/layout.tsx (1) (1)
  • Layout (13-50)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/layout.tsx (1) (1)
  • Layout (4-32)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/layout.tsx (1) (1)
  • Layout (5-31)
apps/app/src/app/[locale]/(app)/setup/page.tsx (1)
apps/app/src/components/forms/create-organization-form.tsx (1) (1)
  • Onboarding (293-295)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/layout.tsx (5)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/overview/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/(overview)/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/layout.tsx (1) (1)
  • Layout (5-31)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/layout.tsx (6)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/layout.tsx (1) (1)
  • Layout (5-26)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/layout.tsx (1) (1)
  • Layout (5-24)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/layout.tsx (1) (1)
  • Layout (14-51)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/layout.tsx (1) (1)
  • Layout (5-27)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/layout.tsx (1) (1)
  • Layout (6-42)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/layout.tsx (1) (1)
  • Layout (5-30)
apps/app/src/components/tables/risk-register/empty-states.tsx (1)
apps/app/src/components/tables/people/empty-states.tsx (1) (1)
  • NoResults (15-46)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/layout.tsx (4)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/layout.tsx (1) (1)
  • Layout (5-24)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/layout.tsx (1) (1)
  • Layout (5-27)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/layout.tsx (1) (1)
  • Layout (6-42)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/layout.tsx (1) (1)
  • Layout (5-30)
apps/app/src/auth/org.ts (1)
apps/app/src/auth/stripe.ts (1) (1)
  • stripe (13-15)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/overview/layout.tsx (5)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/(overview)/layout.tsx (1) (1)
  • Layout (5-33)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/layout.tsx (1) (1)
  • Layout (4-32)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/layout.tsx (1) (1)
  • Layout (5-31)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/layout.tsx (4)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/layout.tsx (1) (1)
  • Layout (5-24)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/layout.tsx (1) (1)
  • Layout (5-27)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/layout.tsx (1) (1)
  • Layout (5-27)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/layout.tsx (1) (1)
  • Layout (6-42)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/layout.tsx (6)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/layout.tsx (1) (1)
  • Layout (5-26)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/layout.tsx (1) (1)
  • Layout (5-24)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/layout.tsx (1) (1)
  • Layout (5-27)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/layout.tsx (1) (1)
  • Layout (5-27)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/layout.tsx (1) (1)
  • Layout (6-42)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/layout.tsx (1) (1)
  • Layout (5-30)
apps/app/src/auth/config.ts (1)
apps/app/src/auth/org.ts (1) (1)
  • createOrganizationAndConnectUser (25-78)
apps/app/src/components/sheets/test-comment-sheet.tsx (1)
apps/app/src/components/forms/create-test-comment-form.tsx (1) (1)
  • CreateTestCommentForm (31-108)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/layout.tsx (6)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/layout.tsx (1) (1)
  • Layout (5-24)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/layout.tsx (1) (1)
  • Layout (5-27)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/layout.tsx (1) (1)
  • Layout (5-27)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/layout.tsx (1) (1)
  • Layout (6-42)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/layout.tsx (1) (1)
  • Layout (5-30)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/PathProvider.tsx (1) (1)
  • PathProvider (14-62)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/page.tsx (4)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/editor/components/PolicyDetails.tsx (1) (1)
  • PolicyDetails (15-69)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/(overview)/page.tsx (1) (1)
  • generateMetadata (99-111)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/editor/page.tsx (1) (1)
  • generateMetadata (17-30)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/page.tsx (1) (1)
  • generateMetadata (101-113)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/RiskRegisterTable.tsx (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/components/table/RiskRegisterColumns.tsx (1) (1)
  • columns (8-60)
apps/app/src/components/organization-switcher.tsx (1)
apps/app/src/actions/change-organization.ts (1) (1)
  • changeOrganizationAction (7-59)
apps/app/src/components/main-menu.tsx (1)
packages/ui/src/components/icons.tsx (1) (1)
  • Icons (143-736)
apps/app/src/components/ui/data-table/DataTableSkeleton.tsx (2)
apps/app/src/components/ui/data-table/index.ts (1) (1)
  • DataTableSkeleton (3-3)
apps/app/src/components/tables/policies/columns.tsx (1) (1)
  • columns (23-76)
apps/app/src/components/forms/create-organization-form.tsx (2)
apps/app/src/actions/organization/create-organization-action.ts (1) (1)
  • createOrganizationAction (9-56)
apps/app/src/actions/schema.ts (1) (1)
  • organizationSchema (13-20)
🔇 Additional comments (182)
apps/app/src/components/sheets/invite-user-sheet.tsx (1)

3-3: Path update aligned with organization-specific structure.

This import path change adds [orgId] to the path, properly aligning with the organization-scoped architecture being implemented across the application. The component functionality remains unchanged, and the useEmployees hook is now correctly located in an organization-specific context.

apps/app/src/actions/risk/update-residual-risk-action.ts (1)

37-39: Organization-specific path revalidation looks good.

The path revalidation has been correctly updated to include the user's organization ID, which aligns with the PR's objective of making routes organization-specific. The changes ensure that cached data is properly refreshed within the correct organizational context after a risk update.

apps/app/src/actions/policy/create-policy-comment.ts (1)

34-34: LGTM: Updated revalidation path with organization context

The path has been correctly updated to include the organization ID, which aligns with the PR's objective of incorporating dynamic organization identifiers in routing paths. This change ensures that cache revalidation is properly scoped to the specific organization.

apps/app/src/actions/risk/update-inherent-risk-action.ts (1)

37-39: Organization-specific path revalidation improves security

The changes to include the user's organization ID in revalidation paths properly align with the multi-tenant architecture being implemented in this PR. This ensures that only organization-specific pages are revalidated, which is both more efficient and more secure.

apps/app/src/components/policies/charts/policies-by-framework.tsx (1)

3-3: Import path updated to include organization ID.

The import path for usePolicies now includes a dynamic [orgId] segment, which aligns with the PR's goal of incorporating organization identifiers into routing paths. This change enables organization-specific policy retrieval without modifying the component's functionality.

apps/app/src/components/tables/tests/data-table.tsx (7)

20-20: Import updated to include useParams hook

The import statement has been updated to include the useParams hook from next/navigation, which is necessary for accessing the organization ID from the URL parameters.


153-153: Organization ID extraction added

The component now extracts the organization ID from URL parameters, aligning with the project's move toward organization-specific routing.


182-185: Updated route to include organization ID

The navigation path now correctly includes the organization ID when redirecting to a test's detail page, changing from /tests/all/${test.id} to /${orgId}/tests/all/${test.id}.


3-19: Code formatting improvements

The import statements have been reformatted with consistent indentation using tabs, improving code readability.


26-38: Interface formatting improved

The DataTableProps interface has been reformatted with consistent indentation, maintaining the same structure and requirements.


40-145: Column definition formatting improved

The getColumns function has been reformatted with consistent indentation while preserving the same functionality for generating table columns.


147-217: DataTable function formatting improved

The main DataTable function has been reformatted with consistent indentation while preserving the core table rendering functionality.

apps/app/src/components/forms/risks/create-risk-form.tsx (2)

5-6: Appropriate update to use dynamic organization paths

The import paths have been correctly updated to use dynamic [orgId] placeholders instead of static organization identifiers. This change aligns with the overall PR objective of implementing dynamic organization routing throughout the application.


12-15: Consistent formatting changes

The indentation has been updated from spaces to tabs across multiple import statements, maintaining consistent formatting throughout the file.

Also applies to: 19-24, 28-33

apps/app/src/components/tables/tests/filter-toolbar.tsx (3)

13-13: Path updated to include organizational context

The import path for refreshTestsAction has been correctly updated to include the [orgId] parameter, aligning with the broader changes in this PR to incorporate organization-specific routing.


18-18: Indentation style changed

The indentation for the isEmpty property has been changed from spaces to tabs. While this doesn't affect functionality, ensure this matches the project's code style guidelines.


21-119: Implementation remains functionally unchanged

The component's functionality remains intact despite the numerous line annotations. The component correctly uses the updated refreshTestsAction with its new path that includes the organization context. The filter toolbar continues to provide search capabilities, clear functionality, and test refresh actions as before.

apps/app/src/components/tables/people/data-table.tsx (4)

14-14: Added useParams import to support organization-specific routing.

The addition of useParams from Next.js navigation is necessary to extract the organization ID from the URL for dynamic routing purposes.


49-49: Good implementation of organization-specific context.

Extracting the organization ID from URL parameters allows for dynamic routing and maintains organization context throughout the user navigation experience. The type definition ensures type safety.


67-67: Updated link path to include organization ID.

The link to individual people pages now correctly includes the organization ID in the URL path, maintaining the organizational context during navigation.


109-109: Modified visibility behavior for department badge.

Removed the hidden class from the department badge container, making it visible on all screen sizes while maintaining the flex layout on medium screens and larger. Verify if this change was intentional as it changes the component's responsive behavior.

Was removing the hidden class intentional? Previously, the department badge was hidden on small screens and only visible on medium screens and larger. The new behavior makes it visible on all screen sizes.

packages/docs/development.mdx (5)

2-3: Metadata Update: Double Quotes for Title & Description
The metadata now uses double quotes for both the title and description, which enhances consistency and clarity across documentation.


7-10: Info Block Formatting Enhanced
The <Info> block has been reformatted with clear line breaks and updated inline code markers. This improves readability and clearly emphasizes the prerequisite steps.


48-49: Updated Port Conflict Message
The port conflict message now states "Port 3000 is already in use. Trying 3002 instead." This update correctly reflects the new fallback port behavior and improves clarity for the reader.


78-80: Tip Block Content Update
The <Tip> block now clearly communicates that unlimited editors are available under the Pro Plan and above, with adjusted formatting for improved legibility.


85-86: Image Tag Style Consistency
The style attribute within the <img> tag has been updated to use double quotes, ensuring consistency with the overall document formatting.

apps/app/src/components/forms/create-test-comment-form.tsx (3)

3-4: Update Import Paths for Organization-Specific Modules
The import paths for createTestCommentAction and createTestCommentSchema have been updated to include [orgId] in the directory, which is in line with the new organization-specific structure.


7-10: Consistent Formatting for UI Component Imports
The formatting for importing Accordion components is now standardized. No functional changes here, but the update improves consistency and clarity.


32-34: Initialization and Hook Usage
The use of hooks (useI18n, useQueryState, and useParams) is clear and concise. The variables are initialized properly; using _ for the unused state value is acceptable.

apps/app/src/components/sheets/test-comment-sheet.tsx (6)

9-14: Formatting Update for Sheet Component Imports
The import block for the Sheet UI components has been reformatted. These changes improve readability without altering functionality.


19-19: Updated Import Path for Test Type
The import for the Test type now includes the [orgId] segment in its path, ensuring consistency with the new organizational structure.


22-26: Component Parameter Handling
The TestCommentSheet component receives a test parameter (of type Test) appropriately. The destructuring and type assignment are clear and adhere to current TypeScript best practices.


27-35: Responsive Behavior Setup
The hooks for internationalization, media query, and query state are being used correctly to manage the responsive behavior and open/close state for the sheet/drawer. The helper function handleOpenChange cleanly updates the state.


37-63: Desktop Rendering with Sheet Component
The desktop layout properly uses the Sheet component and provides a clear UI for creating a test comment. The close button functionality and the organization of header and content components appear well implemented.


66-73: Mobile/Alternate Rendering with Drawer Component
The fallback to the Drawer component for non-desktop screens is correctly handled. The component remains consistent with accessibility practices (e.g., hidden title) and maintains a similar interface to the desktop version.

apps/app/src/components/tables/risk-register/empty-states.tsx (5)

8-8: Added imports to support organization-aware routing.

Adding useParams along with the existing useRouter import correctly supports the dynamic routing pattern being implemented across the application.


12-12: Good improvement to component flexibility.

Making hasFilters optional with the ? modifier improves the component's flexibility, allowing it to be used in contexts where filters may not be present.


16-18: Properly implemented organization context.

The component now correctly extracts the organization ID from the URL parameters using the Next.js useParams hook, following the pattern used in other components like the people tables.


38-38: Successfully updated routing to be organization-aware.

The button's click handler now correctly includes the organization ID in the navigation path, changing from a static path to a dynamic one that includes the organization context.


51-51:

Details

❓ Verification inconclusive

Check query parameter state update implementation.

Using useQueryState for managing the modal state is good practice, but verify that the create-risk-sheet parameter is properly handled when navigating between pages with different organization IDs.


🏁 Script executed:

#!/bin/bash
# Check how create-risk-sheet query parameter is handled across the app
rg -A 3 -B 3 "create-risk-sheet" --glob "*.{ts,tsx}" --no-heading

Length of output: 5442


Ensure correct behavior of the create-risk-sheet query parameter across organization pages

  • Verify that when navigating between different organization IDs (e.g., in pages like RiskRegisterTable), the modal state managed by useQueryState("create-risk-sheet") is properly reset so that a modal open state from one organization does not unintentionally persist in a different context.
  • Check that the implementation in components such as empty-states.tsx, filter-toolbar.tsx, and create-risk-sheet.tsx correctly updates the query parameter based on the current organization’s context.
  • Confirm that proper routing or state-reset logic is in place to avoid side effects when the active organization changes.
apps/app/src/components/tables/people/empty-states.tsx (4)

6-6: Good addition of useParams import.

Adding the useParams hook from Next.js navigation is appropriate for extracting organization ID from the URL path parameters.


18-18: Good implementation of organization context.

Extracting the organization ID from URL parameters with proper TypeScript typing ensures the component is organization-aware.


36-39: Correctly updated navigation to use dynamic organization path.

The Button's onClick handler now properly uses the organization ID in the navigation path, making it context-sensitive to the current organization.


48-71:

Details

❓ Verification inconclusive

Consider updating NoEmployees component for organization awareness.

While you've updated the NoResults component to use organization context, the NoEmployees component still lacks organization awareness. Consider extracting the orgId in this component as well, especially if the EmployeeInviteSheet component needs organization context.


🏁 Script executed:

#!/bin/bash
# Check if EmployeeInviteSheet uses organization context
rg -A 5 "function EmployeeInviteSheet" --type tsx
rg "useParams.*orgId" --type tsx --files-with-matches -- "components/sheets/invite-user-sheet"

Length of output: 202


🏁 Script executed:

#!/bin/bash
# Re-run search for EmployeeInviteSheet definition without specifying file type
rg -A 5 "function EmployeeInviteSheet" components/sheets/invite-user-sheet

# Re-run search for organization context usage (e.g., useParams with orgId) in the invite sheet file
rg "useParams.*orgId" components/sheets/invite-user-sheet

Length of output: 288


Action Required: Verify Organization Context for EmployeeInviteSheet

Automated searches did not reveal any usage of organization context (e.g., extracting an orgId) in the EmployeeInviteSheet component. As you updated the NoResults component to incorporate organization data, please confirm whether EmployeeInviteSheet requires organization context. If it does, consider updating the NoEmployees component to extract and pass along the orgId accordingly.

  • Please verify the implementation of EmployeeInviteSheet to see if it depends on organization context (for example, by checking for hooks like useParams or similar patterns).
  • If the component requires organization data, modify NoEmployees (located in apps/app/src/components/tables/people/empty-states.tsx) to extract the orgId and pass it to EmployeeInviteSheet.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/[riskId]/layout.tsx (3)

38-39: Consistent usage of organization ID

Good job using the organization ID consistently in navigation paths, which aligns with the overall PR objective of incorporating dynamic organization identifiers.


14-51: Overall layout implementation is well-structured

The layout component follows the same pattern as other layout components in the application, with proper authentication checks, organization-specific routing, and a clear component structure. This aligns well with the PR's goal of revamping components to incorporate dynamic organization identifiers.


6-6:

Details

✅ Verification successful

Consider the stability of unstable_cache

You're using unstable_cache which is marked as unstable in the Next.js API. While it works, be aware that its behavior might change in future Next.js versions.


🌐 Web query:

Is unstable_cache still marked as unstable in the latest Next.js version?

💡 Result:

As of the latest information available up to October 2024, unstable_cache remains marked as experimental in Next.js. Here's a breakdown of its status:

  1. Current Stability:

    • The API retains the unstable_ prefix in Next.js documentation[1][9], indicating it hasn't transitioned to stability.
    • Multiple unresolved GitHub issues persist, including problems with stale data[3], revalidation intervals[6], and nested caching behavior[13].
  2. Planned Replacement:

    • Next.js is actively developing use cache as a more ergonomic replacement[8][9], which:
      • Supports caching of any serializable data (not just JSON)[9]
      • Integrates with React Suspense[8]
      • Offers simplified configuration via cacheLife and cacheTag APIs[8][9]
    • The transition path includes migration guides and codemods once stabilized[1].
  3. Key Limitations of unstable_cache:

    • Only caches JSON-compatible data[9]
    • Requires manual management of cache keys/tags[1]
    • Known issues with date deserialization[5] and persistent revalidation bugs[6]

For production use, the Next.js team recommends:

  • Using unstable_cache cautiously with awareness of potential breaking changes
  • Monitoring GitHub issues for updates on critical bugs
  • Considering alternative caching strategies (e.g., ISR with revalidateTag[2][7]) for mission-critical features

The experimental use cache API can be tested in Next.js canary builds, but isn't production-ready yet[8][9].

Citations:


Notice: unstable_cache Remains Experimental
We’ve confirmed that as of the latest documentation (October 2024), unstable_cache is still marked as experimental in Next.js. Its current functionality is valid, but be cautious of potential changes in future releases—review its usage periodically and consider alternatives for mission-critical features if necessary.

packages/db/docker-compose.yml (1)

28-29: Good addition of alternative command.

Adding this comment helps users troubleshoot if they're using a Docker version that doesn't support the hyphenated command syntax. This improves documentation and user experience.

apps/app/src/components/tables/policies/empty-states.tsx (3)

8-8: Good addition of useParams import.

The import of useParams is necessary for retrieving the organization ID from the URL parameters, which aligns with the PR's objective of incorporating dynamic organization identifiers into routing paths.


11-12: Organization ID extraction looks good.

Extracting the organization ID from URL parameters follows the pattern of organization-specific routing being implemented throughout the application.


24-24: Good update to incorporate dynamic organization ID in route.

The Link href is now correctly updated to include the organization ID dynamically, ensuring that policy creation happens in the context of the current organization.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/members/loading.tsx (1)

12-59: Well-structured loading component.

This loading component provides an excellent user experience by:

  • Matching the structure of the actual content it will replace
  • Using proper internationalization
  • Incorporating visual indicators of loading state through the LogoSpinner
  • Maintaining consistent styling with the rest of the application

The implementation follows best practices for creating loading states in Next.js applications.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/vendors/(overview)/layout.tsx (1)

5-30: Layout follows consistent pattern.

This layout component correctly follows the same pattern as other layout components in the application, which is good for maintaining consistency. It properly:

  • Retrieves internationalization strings
  • Gets the user's session and organization ID
  • Renders the SecondaryMenu with appropriate navigation items
  • Places children in a main element with appropriate spacing

This consistency makes the codebase more maintainable and the UI more predictable.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/hooks/useTest.ts (2)

3-7: Import path update for organization-specific routes

The import paths have been correctly updated to include the [orgId] segment, reflecting the new directory structure that supports organization-specific contexts.


12-17: Minor formatting changes in error handling

The error handling logic remains functionally the same, with some whitespace adjustments that maintain code consistency.

apps/app/src/hooks/use-compliance-scores.ts (1)

4-5: Updated import paths to support organization-specific routes

All import paths have been correctly modified to include the [orgId] dynamic segment, maintaining consistency with the organization-aware architecture being implemented across the application.

Also applies to: 11-11

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/loading.tsx (1)

1-16: Well-implemented loading component for evidence list

The new loading component effectively uses the DataTableSkeleton with appropriate configuration for columns, rows, and UI features. This provides a smooth loading experience that matches the actual data table structure.

apps/app/src/actions/risk/task/create-task-action.ts (1)

39-39: Updated revalidation path to include organization context

The path in revalidatePath now correctly includes the user's organization ID, ensuring that the correct organization-specific route is revalidated after creating a task.

apps/app/src/components/google-sign-in.tsx (2)

23-27: Redirect destination changed from "/" to "/setup"

The sign-in redirect destination has been modified to direct users to "/setup" instead of the root path when no invite code is present. This change aligns with the PR's focus on organization-specific functionality, likely directing users to a setup page for configuring organization settings after signing in.


30-46: Button implementation looks good

The implementation follows best practices with proper loading state handling and accessibility considerations.

apps/app/src/actions/risk/update-risk-action.ts (1)

44-46: Path revalidation now organization-specific

The paths in revalidatePath have been updated to include the user's organization ID, making them organization-specific. This change is consistent with the PR's objective of incorporating dynamic organization identifiers throughout the application.

apps/app/src/components/ui/data-table/DataTable.tsx (1)

257-257: Increased skeleton rows for improved loading state

The number of skeleton rows shown during loading has been increased to 10, providing a better visual representation while data is being fetched. This is a good UX improvement.

apps/app/src/actions/risk/task/update-task-action.ts (1)

56-60: Updated revalidation paths with organization context

The revalidation paths now include the user's organization ID, ensuring proper cache revalidation in the context of the specific organization. This change is consistent with the PR's focus on organization-specific routing throughout the application.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/[employeeId]/actions/update-department.ts (1)

66-67: Updated revalidation paths to include organizationId

The paths in the revalidatePath calls have been correctly updated to include the organization identifier, ensuring consistent routing throughout the application. This aligns with the broader changes in the PR that incorporate organization context into route paths.

apps/app/src/components/tables/policies/columns.tsx (3)

8-8: Added useParams import for organization-specific routing

Good addition of the useParams hook to retrieve the current organization ID from the URL.


24-24: Extracting organizationId from URL parameters

Correctly extracting the orgId parameter to use in dynamic route generation.


38-38: Updated Link to include organization ID in path

The Link component now correctly uses the organization ID in the URL path, maintaining consistency with the application's new routing structure.

apps/app/src/actions/risk/create-risk-comment.ts (1)

36-37: Updated revalidation paths with organization context

The revalidation paths have been correctly updated to include the organization ID, ensuring that cache invalidation is properly scoped to the user's organization. This change aligns with the broader effort to make all routes organization-specific.

apps/app/src/actions/risk/task/revalidate-upload.ts (1)

25-26: Correctly updated revalidation paths with organization ID

The paths in the revalidatePath calls now include the organization identifier, ensuring consistent routing and cache invalidation throughout the application. This maintains alignment with the rest of the monolithic changes being implemented.

apps/app/src/data/getOrganizations.ts (1)

4-28: Clean implementation of organization retrieval

The function clearly handles authentication checking and efficiently retrieves all organizations associated with the current user. The implementation follows good patterns for database querying with proper error handling when a user is not authenticated.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/components/table/EmployeesTable.tsx (3)

6-6: LGTM: Import updated to include useParams

The addition of useParams is appropriate for accessing the organization ID from the URL.


14-15: Good use of typed params

Using TypeScript typing with useParams<{ orgId: string }>() ensures type safety when accessing URL parameters.


30-30: Route path updated to include organization context

The navigation now correctly includes the organization ID in the URL path, maintaining organization context during navigation.

apps/app/src/actions/risk/task/create-task-comment.ts (1)

37-38: Revalidation paths updated for organization-based routing

The revalidation paths now correctly include the user's organization ID, ensuring proper cache invalidation for the new URL structure.

apps/app/src/app/page.tsx (1)

4-16: Well-structured root page with appropriate redirects

The root page implementation follows a logical flow:

  1. Checks authentication status
  2. Redirects authenticated users with an organization to their organization page
  3. Redirects other authenticated users to setup
  4. Redirects unauthenticated users to auth

This clean implementation ensures users are properly directed based on their session state.

apps/app/src/components/mobile-menu.tsx (2)

9-9: Good implementation of organization-specific context.

The MobileMenu component now correctly accepts the organizationId prop, aligning with the PR's objective to incorporate organization identifiers throughout the application.


29-32: Properly passing organizationId to MainMenu.

The organizationId is now correctly forwarded to the MainMenu component, which will use this to generate organization-aware navigation links.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/layout.tsx (1)

15-26: Layout structure is consistent with application patterns.

The implementation follows the established pattern used in other layout components throughout the application, maintaining a consistent user experience.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/layout.tsx (1)

17-25: Good implementation of dynamic navigation paths.

The SecondaryMenu items now correctly use dynamic paths with the organization ID, aligning with the PR's objective to make routing organization-aware.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/people/[employeeId]/components/EmployeeDetails.tsx (3)

3-3: Updated import to include useParams.

The import statement is correctly updated to include the useParams hook from next/navigation.


22-22: Effective use of useParams hook.

The component now correctly extracts the organization ID from the URL using the useParams hook, making it organization-aware.


26-26: Dynamic redirect path implementation.

The redirect path now correctly includes the organization ID, ensuring that navigation remains within the context of the current organization.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/components/table/EvidenceListTable.tsx (1)

6-6: Clean implementation of organization-specific routing.

The changes correctly implement organization-specific routing by extracting the orgId from URL parameters and using it to construct the evidence detail page URL. This aligns well with the broader effort to support organization context throughout the application.

Also applies to: 12-13, 42-42

apps/app/src/actions/policies/create-new-policy.ts (2)

4-4: Verify import usage.

The Departments and Frequency imports are properly used in the policy creation logic at lines 53-54, which is good.


58-58: Good update for organization-specific routing.

Updating the revalidation path to include the organization ID (/${user.organizationId}/policies) aligns with the organization-specific routing approach being implemented across the application, ensuring that the cache invalidation is correctly scoped to the specific organization.

apps/app/src/actions/organization/create-api-key-action.ts (1)

69-69: Good adaptation for organization-specific routing.

The revalidation path now correctly includes the organization ID, making it organization-specific. This change is consistent with the overall pattern in this PR to incorporate organization context in routing.

apps/app/src/actions/risk/create-risk-action.ts (1)

41-42: Properly updated revalidation paths.

The revalidation paths now include the user's organization ID, maintaining consistency with the organization-specific routing approach implemented throughout the application. This ensures that cached data is properly invalidated for the specific organization context.

apps/app/src/actions/policies/update-policy-form-action.ts (4)

14-14: Good default parameter value for date calculation.

Adding a default value for the baseDate parameter improves the function's usability and prevents potential undefined errors if the parameter is omitted.


46-54: Improved readability with structured destructuring.

Restructuring the variable destructuring improves code readability by clearly showing each parameter on its own line, making the code easier to maintain.


123-124: Properly updated revalidation paths for organization context.

The revalidation paths now correctly include the user's organization ID, maintaining consistency with the organization-specific routing approach implemented throughout the application.


117-117:

Details

✅ Verification successful

Check for potential type safety issues.

While the code works, using as any for the isRequiredToSign field update bypasses TypeScript's type checking. Consider updating your Prisma schema and regenerating types to properly include this field.

Run this script to check if the Prisma schema already includes this field:


🏁 Script executed:

#!/bin/bash
# Check if isRequiredToSign is defined in the Prisma schema
rg "isRequiredToSign" -A 3 -B 3 --glob "*.prisma"

Length of output: 687


Enhance Type Safety for isRequiredToSign Field

The verification confirms that the Prisma schema (in packages/db/prisma/schema/policy.prisma) already defines isRequiredToSign as a Boolean. Since the code correctly converts the incoming value with isRequiredToSign === "required", there's no longer a need for any as any type assertions on this field. Please remove any remaining as any casts related to this update and, if needed, regenerate the Prisma client to ensure the generated types are fully leveraged.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/layout.tsx (2)

20-21: Unusual typing for route parameters

The params prop is typed as a Promise, which is unusual for Next.js route parameters. Typically, these would be directly available as plain objects. Consider changing the type to params: { orgId: string } unless there's a specific reason for handling it as a Promise.


34-45: Layout component structure looks good

The layout structure with Sidebar, Header, and main content is well-organized and follows good practices for responsive design with appropriate margin adjustments for different screen sizes.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/overview/frameworks/controls/[id]/components/table/ControlRequirementsTable.tsx (3)

31-31: Organization-aware routing implementation looks good

Good job implementing organization-aware routing by extracting the orgId parameter from the URL using the typed useParams hook.


46-48: Dynamic navigation paths correctly implemented

The dynamic navigation paths that include the organization ID are well-implemented and consistent with the application's new routing structure.


53-55: Evidence navigation path correctly updated

The evidence navigation path correctly includes the organization ID parameter, maintaining consistency with the updated routing approach.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/components/table/RiskRegisterColumns.tsx (2)

8-10: Good refactoring to support organization-aware routing

Good job converting the static columns array to a function that accepts the organization ID. This is a clean approach to make the table links organization-aware.


16-18: Dynamic risk link implementation looks good

The Link's href now correctly includes the organization ID, maintaining consistency with the application's updated routing structure.

apps/app/src/actions/policies/update-policy-overview-action.ts (2)

54-56: Improved formatting of isRequiredToSign logic.

The reformatting of the conditional expression enhances code readability while maintaining the same functionality.


62-64: Properly updated revalidation paths with organization context.

The revalidation paths now correctly include the user's organization ID, ensuring proper cache invalidation specific to the organization context. This change aligns with the application's shift toward organization-specific routing.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/settings/layout.tsx (2)

1-1: Added auth import for organization context.

The import of the auth module is necessary for accessing the user's session and organization information.


21-32: Updated menu paths with organization context.

The menu item paths now correctly incorporate the organization ID, enabling proper organization-specific navigation.

apps/app/src/actions/organization/revoke-api-key-action.ts (3)

9-10: Improved code formatting.

The formatting changes enhance code readability while maintaining the same functionality.


12-55: Improved indentation and formatting.

The consistent indentation and formatting throughout the action definition improves code readability.


42-42: Updated revalidation path with organization context.

The revalidation path now correctly includes the organization ID from the context, ensuring proper cache invalidation specific to the organization.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/RiskRegisterTable.tsx (3)

8-8: Added useParams import for organization context.

The import of the useParams hook is necessary for extracting the organization ID from the URL parameters.


20-21: Added organization ID extraction from URL parameters.

The component now correctly extracts the organization ID from the URL parameters, enabling organization-specific functionality.


98-98: Updated columns prop to include organization context.

The columns function is now correctly called with the organization ID, enabling the creation of organization-specific links in the data table.

apps/app/src/actions/change-organization.ts (2)

1-2: No functional issues observed for the initial boilerplate.
The imports and setup look straightforward and correct.


24-59:

Details

❓ Verification inconclusive

Verify authorization checks for organization changes.
While this action updates the user's organization, it doesn't appear to verify whether the user is authorized to make changes for the specified organization. Confirm that authActionClient or other logic ensures the user has the right permissions, particularly in multi-tenant scenarios.

Please run a search in the codebase to confirm that authActionClient properly restricts or validates user permissions:


🏁 Script executed:

#!/bin/bash
# Searching references to authActionClient usage to confirm permission checks
rg -A 8 'authActionClient'

Length of output: 65579


Attention: Revisit Organization Authorization Validation

The change organization action uses the authActionClient, which confirms that the user is authenticated by verifying the session. However, while this check prevents unauthenticated access, it does not specifically validate whether the authenticated user is actually permitted to change to the provided organization. In a multi-tenant scenario, this could allow a user to switch to an organization without verifying proper membership or permission.

  • Confirm that additional authorization logic (such as a membership or role check) is implemented—either within authActionClient or as extra validation in this action—to ensure that the user can legitimately change to the specified organization.
  • If the current implementation relies solely on session verification, consider extending the authorization checks to explicitly validate the user's right to join or modify the organization.
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/(overview)/components/table/PoliciesTable.tsx (2)

4-4: Importing hooks for dynamic routing is appropriate.
The addition of useParams and useRouter aligns with Next.js best practices for route-based data.


13-13: Handle missing orgId gracefully.
If orgId is undefined for any reason, router.replace might fail. Consider verifying the presence of orgId or providing a fallback route.

apps/app/src/components/header.tsx (4)

11-14: New imports support multi-organization flows.
Including OrganizationSwitcher, getOrganizations, auth, and redirect is consistent with introducing organization-specific navigation.


17-19: Internationalization and organization fetch.
Using getI18n and getOrganizations on the server is well-structured, ensuring localized strings and org data are fetched in one place.


20-26: Ensure fallback path covers user intentions.
Redirecting to "/" if currentOrganizationId is missing might prevent users from creating or switching organizations if they have none. Verify that this flow is intentional.


28-65: Header structure and layout appear consistent.
The UI elements (mobile menu, organization switcher, feedback form, notifications, etc.) integrate nicely, and using Suspense for asynchronous data is appropriate.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/(overview)/layout.tsx (3)

1-4: Imports look appropriate.
No issues with the imported modules. They are all used correctly within the file.


5-9: Async layout function is well structured.
Defining the prop type inline with children: React.ReactNode is a clean approach.


15-32: SecondaryMenu usage and layout structure appear consistent.
Menu items correctly reference the organizationId and the translation labels. The styling with max-w-[1200px] and m-auto consistently matches other layout files.

apps/app/src/app/[locale]/(app)/setup/page.tsx (2)

7-7: Title update is appropriate.
Renaming the page title to “Organization Setup | Comp AI” promotes clarity.


11-13: Straightforward data fetching and rendering.
Fetching frameworks and directly passing them into <Onboarding> is a clear and concise flow. Ensure the component handles empty or null data gracefully.

Please confirm that the Onboarding component gracefully handles an empty frameworks array with no runtime errors.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/list/layout.tsx (3)

1-4: Imports are appropriate.
No unnecessary imports. All are utilized.


5-9: Layout function signature is consistent with the pattern.
This matches the design of other layout files in the codebase.


15-32: Menu items and layout usage are consistent.
Basic structure aligns with other files; the SecondaryMenu items have correct translation keys. The py-8 main container ensures good spacing.

apps/app/src/components/sidebar.tsx (4)

6-7: Auth and redirect imports are needed for user-based sidebar rendering.
Import statements look correct given the new approach.


10-13: Session handling is correct.
Destructuring user?.organizationId is succinct.


14-16: Redirect prevents sidebar usage without organization context.
Redirecting to / if organizationId is missing ensures you avoid broken sidebar links.


24-37: Sidebar rendering with dynamic organization link is logical.
Attaching the organizationId to paths is consistent with the new dynamic approach. Layout styling is straightforward.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/overview/layout.tsx (1)

1-33: Layout component follows best practices with proper organization context

The layout component is well-structured with proper authentication, internationalization support, and organization context handling. The component correctly extracts the organization ID from the authenticated user session and uses it to build dynamic navigation paths.

This approach is consistent with similar layout components in the application (like those in policies and tests sections) and ensures proper organization-scoped navigation.

apps/app/src/auth/config.ts (3)

74-78: Organization name is now properly defined during creation

The addition of the orgName parameter when calling createOrganizationAndConnectUser enables proper organization naming during user onboarding. This aligns with the function signature in org.ts which expects this parameter.


10-25: Code formatting improved for better readability

The indentation changes to the User and Session interfaces improve code consistency and readability.


29-82: Consistent indentation applied to auth configuration

The formatting changes to the authConfig object provide consistent indentation throughout the file, making it easier to read and maintain.

apps/app/src/actions/policies/update-policy-action.ts (2)

98-99: Organization-scoped path revalidation implemented

The revalidation paths now include the user's organization ID, ensuring that cache invalidation is properly scoped to the organization context. This change aligns with the organization-specific routing approach implemented across the application.


90-91: Properly type-casted content processing

The content processing logic correctly type-casts the content as ContentNode before processing.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/layout.tsx (3)

8-11: Well-defined props interface with proper typing

The LayoutProps interface properly defines the expected props with appropriate types, including the Promise-wrapped params object containing policyId and orgId.


13-50: Comprehensive layout implementation with proper authentication and redirection

The Layout component effectively:

  1. Authenticates the user and extracts organization context
  2. Redirects appropriately when authentication or policy lookup fails
  3. Provides organization-scoped navigation through SecondaryMenu
  4. Includes a back button for improved user experience

The component follows the established pattern for layout components in the application.


52-64: Efficient policy retrieval with proper caching

The getPolicy function is properly implemented with React's cache function to optimize performance for repeated policy lookups. It correctly queries by both policyId and organizationId for proper data isolation between organizations.

apps/app/src/actions/organization/create-organization-action.ts (2)

27-31: LGTM! Direct organization creation approach

The simplified approach of directly calling createOrganizationAndConnectUser with the provided user information makes the code cleaner and more straightforward.


45-50: Good addition of organization details in the response

Including the newOrganization object in the response is helpful as it provides immediate context to the client about the newly created organization without requiring another request.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/PathProvider.tsx (2)

46-61: LGTM! Well-structured menu component

The SecondaryMenu implementation is clean and provides good navigation options with appropriate back button handling.


41-43:

Details

❓ Verification inconclusive

Consider adding locale to paths

The constructed paths don't include the locale segment that appears in the URL pattern shown in the file path ([locale]/(app)/(dashboard)/[orgId]). This might cause issues with path matching.


🏁 Script executed:

#!/bin/bash
# Check how locale is handled in similar components
rg -A 3 "const \w+Path = .*\/\$\{organizationId\}" --type ts

Length of output: 185


Below is a new shell script using a corrected regex pattern. This should help us check how other components construct their paths and whether they include the locale segment:

Please run this and share the output so we can determine whether similar components incorporate the locale in their path constructions.


🏁 Script executed:

#!/bin/bash
# Corrected regex search: looking for similar definitions of path variables using "organizationId"
rg -A 3 "const \\w+Path = .*\\/\\$\\{organizationId\\}" --type ts

Length of output: 309


Attention: Potential Missing Locale in URL Paths

In apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/PathProvider.tsx, the URL constructions:

// Format paths exactly as they would appear in the URL to ensure matching works correctly
const overviewPath = `/${organizationId}/evidence/${evidenceId}`;
const editPath = `/${organizationId}/evidence/${evidenceId}/edit`;

omit the locale segment present in the file route ([locale]/(app)/(dashboard)/[orgId]). It’s unclear if this omission is intentional or if the locale should be explicitly included (e.g., /${locale}/${organizationId}/evidence/${evidenceId}). Given that our automated searches for similar implementations returned no conclusive evidence, please review the overall routing configuration and confirm whether the locale segment is expected to be part of the constructed paths.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/(home)/components/FrameworkProgress.tsx (2)

39-84: LGTM! Well-designed CircleProgress component

The CircleProgress component is well-designed, reusable, and includes good visual feedback with appropriate SVG elements for displaying progress.


153-177: Good responsive design for labels

The component handles responsive design well by showing shorter labels on mobile screens while providing more detailed labels on larger screens.

apps/app/src/components/organization-switcher.tsx (1)

46-77: LGTM! Well-structured dropdown menu

The dropdown implementation is clean, with good structure and clear organization selection functionality.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/(overview)/page.tsx (7)

1-10: All imports appear to be in order.
No concerns detected with the usage of unstable_cache, redirect, and other imported modules.


11-16: Confirm usage of Promise-based params.
Typing params as Promise<{ locale: string }> is somewhat unusual. Please verify that this is intended and that all call sites properly handle the promise nature of the parameter.


17-17: Locale configuration logic is correct.
setStaticParamsLocale(locale) effectively sets the locale for further processing.


19-23: Organization check is well-handled.
Redirecting users without an organizationId to onboarding ensures that only valid organizations can access this page.


25-30: Redirect logic for empty risk data is appropriate.
Invoking redirect when overview?.risks === 0 correctly handles the no-risk scenario.


32-43: UI rendering logic looks good.
No issues found; both RiskOverview and RisksAssignee are properly grouped within responsive layouts.


62-74: Metadata generation is straightforward.
Title generation relies on translations. This is a succinct and clear approach.

apps/app/src/auth/org.ts (12)

5-7: Parameter definitions look good.
These fields are appropriately typed for creating a Stripe customer.


9-16: Sufficient error handling within the try block.
Logging and rethrowing is acceptable to ensure errors aren’t silently swallowed.


18-19: Returning Stripe customer ID.
Returning the ID to the caller is clear and consistent with typical usage.


20-22: Catch block logs the error.
No new concerns; this provides enough insight into failures.


25-29: Revised function signature is appropriate.
Accepting orgName clarifies the calling context and aligns with dynamic naming requirements.


30-47: Organization creation transaction is logically sound.
Creating an organization entry with membership and selected fields in a single transaction is a valid approach.


48-55: Setting the user’s role to 'admin'.
No issues with this role assignment; ensures ownership after org creation.


57-61: Dynamic Stripe customer creation.
Making the Stripe call after the org transaction ensures we only create a customer if the org exists.


63-65: Warn and proceed if Stripe customer ID is absent.
Graceful handling with a warning allows the flow to continue.


67-70: Updates Stripe customer ID on the organization record.
Straightforward approach ensures data consistency.


72-75: Assigning user’s organization ID.
Ties the user to the newly created organization—makes sense for multi-tenant logic.


77-77: Returning the organization details.
Returning the entire organization object is beneficial for post-creation usage.

apps/app/src/components/risks/charts/risks-by-assignee.tsx (4)

1-1: Auth import noted but appears unused.
No further action is needed unless a future requirement uses auth.


13-13: Added organizationId prop is correct.
Ensuring that we track an organization’s ID fosters proper scoping of risk data.


17-26: User interface definition.
Fields align well with a typical user profile plus risk metrics.


172-193: Caching DB queries is efficient.
Leveraging unstable_cache with tags keeps the data fresh while reducing repeated DB loads.

apps/app/src/components/ui/data-table/DataTableSkeleton.tsx (3)

16-18: Well-defined optional props for enhanced flexibility.

These new props provide good customization options for the skeleton component, allowing for more tailored loading states depending on the context.


30-46: Clean implementation of conditional rendering for search and filter skeletons.

The layout structure correctly handles responsive design with the flex-col md:flex-row class combination, ensuring proper stacking on mobile and horizontal alignment on larger screens.


71-76: Consistent pagination skeleton implementation.

The pagination skeleton follows the same design pattern as the other conditional elements, maintaining consistency throughout the component.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/(overview)/page.tsx (1)

48-99: Effective use of caching for database queries.

The unstable_cache implementation for database queries is a good optimization for this dashboard page. The transaction with parallel Promise.all queries is well-structured to efficiently fetch all the required statistics in a single database round trip.

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

25-29: Consistent redirect pattern for empty data scenarios.

Good practice to redirect users to a relevant page when there's no data to display in the overview.


46-97: Well-structured database transaction with parallel queries.

The implementation effectively uses Promise.all with multiple count queries to retrieve all policy statistics in a single transaction, which is efficient and follows best practices.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/policies/all/[policyId]/page.tsx (1)

10-31: Proper parameter extraction and error handling with redirect.

The component correctly extracts required parameters and handles the case when a policy is not found with an appropriate redirect.

apps/app/src/components/forms/create-organization-form.tsx (5)

33-41: Update to pass organization data to RealtimeStatus

The RealtimeStatus component now accepts a newOrganization parameter with organization ID and name, enabling proper redirection after organization creation.


55-59: Improved navigation flow with organization ID

The useEffect properly redirects users to their new organization's page after successful creation, using the organization ID in the path.


85-87: Good use of useRef for organization data

Using useRef to store the new organization details prevents unnecessary re-renders while maintaining access to the data for redirection purposes.


89-94: Complete success handler implementation

The onSuccess callback now properly stores the newly created organization in the ref, making it available for redirection.


119-123: Correctly passing organization data to RealtimeStatus

The component passes the organization reference to RealtimeStatus, enabling proper navigation flow after organization creation.

apps/app/src/components/main-menu.tsx (3)

23-30: Well-structured MenuItem type definition

The new MenuItem type properly encapsulates all necessary properties including the icon component type, improving type safety throughout the component.


70-74: Proper path transformation for organization context

The code now correctly transforms menu item paths by replacing the :organizationId placeholder with the actual organization ID.


292-321: Robust path matching logic

The new isPathActive function properly handles different path patterns, including special case handling for the root organization path. This ensures menu items are correctly highlighted based on current navigation.

Comment on lines +25 to +27
if (!risk) {
redirect("/risk");
}
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

Improve redirect path

When a risk isn't found, the code redirects to /risk, but this path doesn't include the organization ID which appears to be a pattern throughout the application.

	if (!risk) {
-		redirect("/risk");
+		redirect(`/${session.user.organizationId}/risk`);
	}
📝 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
if (!risk) {
redirect("/risk");
}
if (!risk) {
redirect(`/${session.user.organizationId}/risk`);
}

Comment on lines +9 to +12
interface LayoutProps {
children: React.ReactNode;
params: Promise<{ riskId: string }>;
}
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

The params type doesn't match actual usage

The params prop is typed as a Promise, but it's awaited directly on line 22. This suggests a mismatch between the expected type and actual implementation.

interface LayoutProps {
	children: React.ReactNode;
-	params: Promise<{ riskId: string }>;
+	params: { riskId: string };
}
📝 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
interface LayoutProps {
children: React.ReactNode;
params: Promise<{ riskId: string }>;
}
interface LayoutProps {
children: React.ReactNode;
params: { riskId: string };
}

Comment on lines +22 to +23
const riskId = await params;
const risk = await getRisk(riskId.riskId, session.user.organizationId);
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

Confusing Promise handling

Line 22 awaits params which is already typed as a Promise, but then you're accessing riskId.riskId, suggesting the Promise is already resolved. This makes the code hard to understand.

-	const riskId = await params;
-	const risk = await getRisk(riskId.riskId, session.user.organizationId);
+	const risk = await getRisk(params.riskId, session.user.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 riskId = await params;
const risk = await getRisk(riskId.riskId, session.user.organizationId);
const risk = await getRisk(params.riskId, session.user.organizationId);

Comment on lines +11 to +13
const session = await auth();
const user = session?.user;
const orgId = user?.organizationId;
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 fallback for missing organizationId

The code assumes user?.organizationId will be available, but there's no fallback if it's undefined. Consider adding a fallback or redirect to handle this case:

 	const session = await auth();
 	const user = session?.user;
 	const orgId = user?.organizationId;
+
+	if (!orgId) {
+		// Either redirect or use a default value
+		redirect("/");
+	}
📝 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 session = await auth();
const user = session?.user;
const orgId = user?.organizationId;
const session = await auth();
const user = session?.user;
const orgId = user?.organizationId;
if (!orgId) {
// Either redirect or use a default value
redirect("/");
}

Comment on lines +10 to +13
const t = await getI18n();
const session = await auth();
const user = session?.user;
const organizationId = user?.organizationId;
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

Consider handling missing organization information.
If organizationId happens to be null or undefined, you may end up with invalid links or partially rendered UI. Consider redirecting or showing an error message in such cases.

  const session = await auth();
  const user = session?.user;
  const organizationId = user?.organizationId;

+ if (!organizationId) {
+   // You might redirect or display an error here
+   redirect("/");
+ }
📝 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 t = await getI18n();
const session = await auth();
const user = session?.user;
const organizationId = user?.organizationId;
const t = await getI18n();
const session = await auth();
const user = session?.user;
const organizationId = user?.organizationId;
if (!organizationId) {
// You might redirect or display an error here
redirect("/");
}

Comment on lines +10 to +13
const t = await getI18n();
const session = await auth();
const user = session?.user;
const organizationId = user?.organizationId;
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

Potential missing redirect if organizationId is undefined.
Similar to other layouts, consider handling null or missing IDs to avoid broken routes.

  const session = await auth();
  const user = session?.user;
  const organizationId = user?.organizationId;

+ if (!organizationId) {
+   // Possibly redirect or show a fallback
+   redirect("/");
+ }
📝 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 t = await getI18n();
const session = await auth();
const user = session?.user;
const organizationId = user?.organizationId;
const t = await getI18n();
const session = await auth();
const user = session?.user;
const organizationId = user?.organizationId;
if (!organizationId) {
// Possibly redirect or show a fallback
redirect("/");
}

Comment on lines +15 to +32
return (
<div className="max-w-[1200px] m-auto">
<SecondaryMenu
items={[
{
path: `/${organizationId}/policies`,
label: t("policies.dashboard.title"),
},
{
path: `/${organizationId}/policies/all`,
label: t("policies.dashboard.all"),
},
]}
/>

<main className="mt-8">{children}</main>
</div>
);
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

The layout renders correctly but lacks null check for organizationId

The component uses organizationId directly in the navigation paths without checking if it's null or undefined. This could lead to invalid routes like /undefined/policies if the auth session doesn't have a user or the user doesn't have an organizationId.

Consider adding a fallback or validation:

- <SecondaryMenu
-   items={[
-     {
-       path: `/${organizationId}/policies`,
-       label: t("policies.dashboard.title"),
-     },
-     {
-       path: `/${organizationId}/policies/all`,
-       label: t("policies.dashboard.all"),
-     },
-   ]}
- />

+ <SecondaryMenu
+   items={[
+     {
+       path: organizationId ? `/${organizationId}/policies` : "/policies",
+       label: t("policies.dashboard.title"),
+     },
+     {
+       path: organizationId ? `/${organizationId}/policies/all` : "/policies/all",
+       label: t("policies.dashboard.all"),
+     },
+   ]}
+ />
📝 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
return (
<div className="max-w-[1200px] m-auto">
<SecondaryMenu
items={[
{
path: `/${organizationId}/policies`,
label: t("policies.dashboard.title"),
},
{
path: `/${organizationId}/policies/all`,
label: t("policies.dashboard.all"),
},
]}
/>
<main className="mt-8">{children}</main>
</div>
);
return (
<div className="max-w-[1200px] m-auto">
<SecondaryMenu
items={[
{
path: organizationId ? `/${organizationId}/policies` : "/policies",
label: t("policies.dashboard.title"),
},
{
path: organizationId ? `/${organizationId}/policies/all` : "/policies/all",
label: t("policies.dashboard.all"),
},
]}
/>
<main className="mt-8">{children}</main>
</div>
);

Comment on lines 11 to 18
export async function middleware(request: NextRequest) {
const response = await I18nMiddleware(request);
const nextUrl = request.nextUrl;
const hasSession = request.cookies.has("authjs.session-token");

const pathnameLocale = nextUrl.pathname.split("/", 2)?.[1];
// If the user is not authenticated, redirect to the auth page.
if (!hasSession && request.nextUrl.pathname !== "/auth") {
return NextResponse.redirect(new URL("/auth", request.url));
}

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

Authentication check doesn't handle API routes correctly

The middleware redirects any non-authenticated request to /auth, but doesn't appear to have special handling for API routes which should return 401 status instead of redirects.

Add special handling for API routes:

  // If the user is not authenticated, redirect to the auth page.
  if (!hasSession && request.nextUrl.pathname !== "/auth") {
+   // For API routes, return 401 instead of redirecting
+   if (request.nextUrl.pathname.startsWith("/api/")) {
+     return NextResponse.json(
+       { error: "Unauthorized" },
+       { status: 401 }
+     );
+   }
    return NextResponse.redirect(new URL("/auth", request.url));
  }
📝 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
export async function middleware(request: NextRequest) {
const response = await I18nMiddleware(request);
const nextUrl = request.nextUrl;
const hasSession = request.cookies.has("authjs.session-token");
const pathnameLocale = nextUrl.pathname.split("/", 2)?.[1];
// If the user is not authenticated, redirect to the auth page.
if (!hasSession && request.nextUrl.pathname !== "/auth") {
return NextResponse.redirect(new URL("/auth", request.url));
}
export async function middleware(request: NextRequest) {
const hasSession = request.cookies.has("authjs.session-token");
// If the user is not authenticated, redirect to the auth page.
if (!hasSession && request.nextUrl.pathname !== "/auth") {
// For API routes, return 401 instead of redirecting
if (request.nextUrl.pathname.startsWith("/api/")) {
return NextResponse.json(
{ error: "Unauthorized" },
{ status: 401 }
);
}
return NextResponse.redirect(new URL("/auth", request.url));
}
}

Comment on lines +109 to +111
<Link href="/overview/frameworks">
{t("frameworks.overview.progress.empty.action")}
</Link>
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

Update framework link to include organization ID

The link to "/overview/frameworks" doesn't include the organization ID, unlike other links in the component that use /${orgId}/.... This could lead to routing inconsistencies.

-<Link href="/overview/frameworks">
+<Link href={`/${orgId}/frameworks`}>
   {t("frameworks.overview.progress.empty.action")}
</Link>
📝 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
<Link href="/overview/frameworks">
{t("frameworks.overview.progress.empty.action")}
</Link>
<Link href={`/${orgId}/frameworks`}>
{t("frameworks.overview.progress.empty.action")}
</Link>

@vercel vercel Bot temporarily deployed to Preview – comp-portal March 19, 2025 20:51 Inactive
Copy link
Copy Markdown

@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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between fc3048c and d536a97.

📒 Files selected for processing (12)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/components/AssigneeSection.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/hooks/useOrganizationAdmins.ts (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/RiskRegisterTable.tsx (3 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/components/table/RiskRegisterFilters.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/[testId]/components/AssigneeSection.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/vendors/components/create-risk-form.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/vendors/components/create-vendor-sheet.tsx (1 hunks)
  • apps/app/src/app/[locale]/(app)/(dashboard)/vendors/register/VendorRegisterTable.tsx (1 hunks)
  • apps/app/src/app/layout.tsx (1 hunks)
  • apps/app/src/components/forms/risks/create-risk-form.tsx (1 hunks)
  • apps/app/src/components/risks/tasks/task-attachments.tsx (1 hunks)
  • apps/app/src/components/tables/tests/filter-toolbar.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/hooks/useOrganizationAdmins.ts
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/components/table/RiskRegisterFilters.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/vendors/components/create-vendor-sheet.tsx
  • apps/app/src/components/risks/tasks/task-attachments.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/app/src/components/forms/risks/create-risk-form.tsx
  • apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/risk/register/RiskRegisterTable.tsx
  • apps/app/src/components/tables/tests/filter-toolbar.tsx
🧰 Additional context used
🧬 Code Definitions (1)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/[testId]/components/AssigneeSection.tsx (2)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/components/AssigneeSection.tsx (1) (1)
  • AssigneeSection (24-136)
apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/hooks/useOrganizationAdmins.ts (2) (2)
  • useOrganizationAdmins (33-38)
  • Admin (6-12)
🔇 Additional comments (14)
apps/app/src/app/layout.tsx (1)

1-3: Clean and well-structured Next.js layout component.

The implementation follows React and Next.js best practices with:

  • Proper TypeScript typing for the children prop
  • Efficient use of React fragments to avoid unnecessary DOM elements
  • Adherence to Next.js App Router layout patterns

This minimal root layout component provides a solid foundation for the application's UI structure.

apps/app/src/app/[locale]/(app)/(dashboard)/vendors/components/create-risk-form.tsx (2)

5-6: Import paths updated to use dynamic organization identifier

The import paths for both hooks have been updated to include [orgId] as part of the path, which aligns with the PR objective of making components organization-aware. This update ensures the risk form correctly uses the context of the current organization.


12-16: Improved formatting of import statements

The indentation of import statements has been standardized, making the code more readable and consistent with the project's style guidelines.

Also applies to: 19-25, 28-33

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[id]/components/AssigneeSection.tsx (5)

1-17: New component for evidence assignment with correct imports

This new component imports all necessary dependencies and defines a clear interface for the props. The component will help manage the assignment of evidence to organization administrators.


18-22: Well-defined props interface

The AssigneeSectionProps interface clearly defines the required props with appropriate types. The interface includes evidenceId, currentAssigneeId (which can be nullable), and an async callback for success handling.


24-70: Well-structured component with robust state management

The component handles state management correctly with proper effect hooks to sync the selected assignee with props and data. The assignment logic in handleAssigneeChange correctly handles the "none" case and updates both local state and the server.


72-78: Good loading and error state handling

The component provides appropriate visual feedback during loading and clear error messaging when the admin data fails to load, enhancing the user experience.


80-134: Well-designed UI with accessible selection interface

The selection interface includes avatars and names for better visual recognition, properly handles the "None" option, and provides appropriate styling for the dropdown. The component is also responsive to execution states, disabling the interface during updates.

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/tests/all/[testId]/components/AssigneeSection.tsx (3)

15-18: Proper import of the Admin type and useOrganizationAdmins hook

The import uses an absolute path with the @/ prefix, which is consistent with the project's import pattern for organization-specific hooks. Importing the Admin type directly alongside the hook improves code readability.


20-73: Component logic for test assignment

The component correctly handles the assignment of tests to administrators, maintaining consistent state management patterns with the evidence assignment component. The use of useEffect hooks ensures proper synchronization between props and state.


75-137: Consistent UI pattern across assignment components

The UI implementation maintains consistency with the evidence assignment component, providing the same user experience across different parts of the application. This consistency is important for usability and maintainability.

apps/app/src/app/[locale]/(app)/(dashboard)/vendors/register/VendorRegisterTable.tsx (3)

9-9: Import path update aligns with organization-centric architecture.

The import path change from a relative path to an absolute path using the organization-specific folder structure ([orgId]) aligns well with the PR objective of incorporating dynamic organization identifiers throughout the application.


15-17: Code formatting improvement enhances readability.

The function signature reformatting with the parameter on a new line and the addition of a trailing comma follows modern TypeScript formatting conventions and improves readability.


71-81:

Details

❓ Verification inconclusive

Consider uncommenting or removing the filtering functionality.

There are commented-out sections related to filtering functionality that use the admins data fetched from useOrganizationAdmins. If these features are meant to be implemented later, consider adding a TODO comment with more context. If they're no longer needed, it might be cleaner to remove them entirely.

Also applies to: 103-109


🏁 Script executed:

#!/bin/bash
# Check if RiskRegisterFilters component exists and is used elsewhere
rg -l "RiskRegisterFilters" --type tsx

Length of output: 66


RiskRegisterFilters Usage Verification

The initial command failed because --type tsx isn’t recognized. Please run the above script to verify whether the RiskRegisterFilters token exists elsewhere in the codebase. If it isn’t used anywhere outside the commented-out section in the file:

  • Remove the commented filtering code if the feature is no longer needed.
  • Or add a TODO comment with more context if you plan to reintroduce this functionality later.

🏁 Script executed:

#!/bin/bash
# Re-run search for the "RiskRegisterFilters" token in the repository using the "typescript" file type,
# which should cover both .ts and .tsx files.
rg -l "RiskRegisterFilters" --type typescript

Length of output: 80


Action Required: Address the commented filtering functionality

It appears that the RiskRegisterFilters functionality isn’t referenced elsewhere in the codebase based on our search attempts. Please manually verify this before making the change. If you confirm that the filtering feature is no longer needed, remove the commented-out code in both the 71–81 and the 103–109 sections of apps/app/src/app/[locale]/(app)/(dashboard)/vendors/register/VendorRegisterTable.tsx. Alternatively, if you plan to reintroduce this functionality later, add a TODO comment with clear context and a timeline for when it should be re-enabled.

Comment on lines +42 to +45
onError: (error) => {
console.log("error", error);
toast.error("Failed to update Assignee");
},
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

Remove console.log statement

There's a console.log statement in the error handler that should be removed before deploying to production. While useful during development, debugging logs should not remain in production code.

-		onError: (error) => {
-			console.log("error", error);
-			toast.error("Failed to update Assignee");
-		},
+		onError: () => {
+			toast.error("Failed to update Assignee");
+		},
📝 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
onError: (error) => {
console.log("error", error);
toast.error("Failed to update Assignee");
},
onError: () => {
toast.error("Failed to update Assignee");
},

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