Monolith#157
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
1 Skipped Deployment
|
WalkthroughThis 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
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
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
Possibly Related PRs
Poem
Tip ⚡🧪 Multi-step agentic review comment chat (experimental)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
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 variablecreatePolicyCommentis assigned the value fromcreateTestCommentAction. Since the component and the imported action refer to test comments, consider renamingcreatePolicyCommenttocreateTestCommentfor clarity and consistency.Example diff suggestion:
- const createPolicyComment = useAction(createTestCommentAction, { + const createTestComment = useAction(createTestCommentAction, {
54-56: Submission Handler Relies on Action Variable
TheonSubmitfunction 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:
- Updating the component to extract the orgId:
const { orgId } = useParams<{ orgId: string }>();
- 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 detectedThe
Titlecomponent is imported on line 2 but never used in this file.-import { Title } from "@/components/title";
53-65: Enhance cache key for better performanceThe 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 operationsThe 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
useroruser.organizationIdis 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 orgIdIf 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 strategyThe 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 resolutionThe code awaits
paramswithout 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 codeThere's a console.log statement in the
onRowClickfunction 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 implementationThe 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 commentConsider 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.
Themetadata.track.eventis"create-employee", which might be misleading for achangeOrganizationAction.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.
Usingrouter.replaceremoves the previous entry from the history stack. If you need to preserve it, considerrouter.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 inconsistentYou're redirecting to
/${orgId}/policiesif 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 refactoredThe 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 improvedThe 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
saveErroris not null.apps/app/src/middleware.ts (1)
46-50: Matcher configuration could be more maintainableThe 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 parameterThe
PolicyEditorfunction acceptslocaleandpolicyIdbut doesn't includeorgIdin 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
orgIdtoPolicyDetailsif it doesn't already retrieve it viauseParams().
17-30: The same issue exists in generateMetadata functionSimilar to the
PolicyEditorfunction,generateMetadatais missing theorgIdparameter.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 validationThe manual check for
!name || !websiteseems redundant since you're already using Zod schema validation withorganizationSchema, 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 IDThe 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 importThe
authimport 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 callbackThe condition
if (result.data?.success)is redundant because theonSuccesscallback 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 nameThere's no fallback text when
currentOrganizationis undefined, which might happen if the providedorganizationIddoesn'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" textThe 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
getPolicyis correctly cached,getUsersisn't. Since organization members don't change frequently during a session, consider applying similar caching togetUsersfor 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 mappingThere's a typo in the menuIcons mapping for the 'people' icon.
- people: Icons.Peolple, + people: Icons.People,
183-247: Consistent typo in people icon usageThe 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
⛔ Files ignored due to path filters (1)
yarn.lockis 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 contextThe 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 securityThe 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
usePoliciesnow 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 hookThe import statement has been updated to include the
useParamshook fromnext/navigation, which is necessary for accessing the organization ID from the URL parameters.
153-153: Organization ID extraction addedThe 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 IDThe 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 improvementsThe import statements have been reformatted with consistent indentation using tabs, improving code readability.
26-38: Interface formatting improvedThe
DataTablePropsinterface has been reformatted with consistent indentation, maintaining the same structure and requirements.
40-145: Column definition formatting improvedThe
getColumnsfunction has been reformatted with consistent indentation while preserving the same functionality for generating table columns.
147-217: DataTable function formatting improvedThe main
DataTablefunction 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 pathsThe 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 changesThe 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 contextThe import path for
refreshTestsActionhas 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 changedThe indentation for the
isEmptyproperty 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 unchangedThe component's functionality remains intact despite the numerous line annotations. The component correctly uses the updated
refreshTestsActionwith 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: AddeduseParamsimport to support organization-specific routing.The addition of
useParamsfrom 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
hiddenclass 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
hiddenclass 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 forcreateTestCommentActionandcreateTestCommentSchemahave 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, anduseParams) 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 theTesttype now includes the[orgId]segment in its path, ensuring consistency with the new organizational structure.
22-26: Component Parameter Handling
TheTestCommentSheetcomponent receives atestparameter (of typeTest) 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 functionhandleOpenChangecleanly updates the state.
37-63: Desktop Rendering with Sheet Component
The desktop layout properly uses theSheetcomponent 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 theDrawercomponent 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
useParamsalong with the existinguseRouterimport correctly supports the dynamic routing pattern being implemented across the application.
12-12: Good improvement to component flexibility.Making
hasFiltersoptional 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
useParamshook, 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
useQueryStatefor managing the modal state is good practice, but verify that thecreate-risk-sheetparameter 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-headingLength of output: 5442
Ensure correct behavior of the
create-risk-sheetquery parameter across organization pages
- Verify that when navigating between different organization IDs (e.g., in pages like
RiskRegisterTable), the modal state managed byuseQueryState("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, andcreate-risk-sheet.tsxcorrectly 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
useParamshook 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-sheetLength 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 IDGood 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-structuredThe 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_cacheYou're using
unstable_cachewhich 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_cacheremains marked as experimental in Next.js. Here's a breakdown of its status:
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].
Planned Replacement:
- Next.js is actively developing
use cacheas 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
cacheLifeandcacheTagAPIs[8][9]- The transition path includes migration guides and codemods once stabilized[1].
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_cachecautiously 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 featuresThe experimental
use cacheAPI can be tested in Next.js canary builds, but isn't production-ready yet[8][9].Citations:
- 1: https://nextjs.org/docs/app/api-reference/functions/unstable_cache
- 2: https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration
- 3: vercel/next.js#75462
- 4: https://blog.logrocket.com/caching-next-js-unstable-cache/
- 5: vercel/next.js#51613
- 6: vercel/next.js#67751
- 7: https://nextjs.org/docs/app/building-your-application/caching
- 8: https://nextjs.org/blog/our-journey-with-caching
- 9: https://nextjs.org/docs/app/api-reference/directives/use-cache
- 10: https://octotype.app/peibolsang/stories/12
- 11: https://nextjs.org/docs/app/building-your-application/data-fetching/fetching
- 12: vercel/next.js#73192
- 13: vercel/next.js#68677
Notice:
unstable_cacheRemains Experimental
We’ve confirmed that as of the latest documentation (October 2024),unstable_cacheis 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 routesThe 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 handlingThe 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 routesAll 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 listThe new loading component effectively uses the
DataTableSkeletonwith 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 contextThe path in
revalidatePathnow 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 goodThe 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-specificThe paths in
revalidatePathhave 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 stateThe 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 contextThe 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 organizationIdThe paths in the
revalidatePathcalls 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 routingGood addition of the
useParamshook to retrieve the current organization ID from the URL.
24-24: Extracting organizationId from URL parametersCorrectly extracting the
orgIdparameter to use in dynamic route generation.
38-38: Updated Link to include organization ID in pathThe 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 contextThe 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 IDThe paths in the
revalidatePathcalls 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 retrievalThe 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 useParamsThe addition of
useParamsis appropriate for accessing the organization ID from the URL.
14-15: Good use of typed paramsUsing TypeScript typing with
useParams<{ orgId: string }>()ensures type safety when accessing URL parameters.
30-30: Route path updated to include organization contextThe 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 routingThe 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 redirectsThe root page implementation follows a logical flow:
- Checks authentication status
- Redirects authenticated users with an organization to their organization page
- Redirects other authenticated users to setup
- 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
orgIdfrom 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
DepartmentsandFrequencyimports 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
baseDateparameter 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 anyfor theisRequiredToSignfield 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
isRequiredToSignFieldThe verification confirms that the Prisma schema (in
packages/db/prisma/schema/policy.prisma) already definesisRequiredToSignas a Boolean. Since the code correctly converts the incoming value withisRequiredToSign === "required", there's no longer a need for anyas anytype assertions on this field. Please remove any remainingas anycasts 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 parametersThe
paramsprop 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 toparams: { orgId: string }unless there's a specific reason for handling it as a Promise.
34-45: Layout component structure looks goodThe 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 goodGood job implementing organization-aware routing by extracting the
orgIdparameter from the URL using the typeduseParamshook.
46-48: Dynamic navigation paths correctly implementedThe 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 updatedThe 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 routingGood 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 goodThe 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 thatauthActionClientor other logic ensures the user has the right permissions, particularly in multi-tenant scenarios.Please run a search in the codebase to confirm that
authActionClientproperly 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
authActionClientor 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 ofuseParamsanduseRouteraligns with Next.js best practices for route-based data.
13-13: Handle missing orgId gracefully.
IforgIdis undefined for any reason,router.replacemight fail. Consider verifying the presence oforgIdor providing a fallback route.apps/app/src/components/header.tsx (4)
11-14: New imports support multi-organization flows.
IncludingOrganizationSwitcher,getOrganizations,auth, andredirectis consistent with introducing organization-specific navigation.
17-19: Internationalization and organization fetch.
UsinggetI18nandgetOrganizationson 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"/"ifcurrentOrganizationIdis 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 withchildren: React.ReactNodeis a clean approach.
15-32: SecondaryMenu usage and layout structure appear consistent.
Menu items correctly reference theorganizationIdand the translation labels. The styling withmax-w-[1200px]andm-autoconsistently 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
Onboardingcomponent gracefully handles an emptyframeworksarray 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; theSecondaryMenuitems have correct translation keys. Thepy-8main 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.
Destructuringuser?.organizationIdis succinct.
14-16: Redirect prevents sidebar usage without organization context.
Redirecting to/iforganizationIdis missing ensures you avoid broken sidebar links.
24-37: Sidebar rendering with dynamic organization link is logical.
Attaching theorganizationIdto 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 contextThe 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 creationThe addition of the
orgNameparameter when callingcreateOrganizationAndConnectUserenables proper organization naming during user onboarding. This aligns with the function signature inorg.tswhich expects this parameter.
10-25: Code formatting improved for better readabilityThe indentation changes to the User and Session interfaces improve code consistency and readability.
29-82: Consistent indentation applied to auth configurationThe 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 implementedThe 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 processingThe 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 typingThe 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 redirectionThe Layout component effectively:
- Authenticates the user and extracts organization context
- Redirects appropriately when authentication or policy lookup fails
- Provides organization-scoped navigation through SecondaryMenu
- 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 cachingThe 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 approachThe simplified approach of directly calling
createOrganizationAndConnectUserwith the provided user information makes the code cleaner and more straightforward.
45-50: Good addition of organization details in the responseIncluding the
newOrganizationobject 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 componentThe 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 tsLength 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 tsLength 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
localesegment 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 componentThe CircleProgress component is well-designed, reusable, and includes good visual feedback with appropriate SVG elements for displaying progress.
153-177: Good responsive design for labelsThe 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 menuThe 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 ofunstable_cache,redirect, and other imported modules.
11-16: Confirm usage of Promise-based params.
TypingparamsasPromise<{ 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 anorganizationIdto onboarding ensures that only valid organizations can access this page.
25-30: Redirect logic for empty risk data is appropriate.
Invokingredirectwhenoverview?.risks === 0correctly handles the no-risk scenario.
32-43: UI rendering logic looks good.
No issues found; bothRiskOverviewandRisksAssigneeare 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.
AcceptingorgNameclarifies 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 usesauth.
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.
Leveragingunstable_cachewith 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-rowclass 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_cacheimplementation 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 RealtimeStatusThe RealtimeStatus component now accepts a
newOrganizationparameter with organization ID and name, enabling proper redirection after organization creation.
55-59: Improved navigation flow with organization IDThe 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 dataUsing 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 implementationThe onSuccess callback now properly stores the newly created organization in the ref, making it available for redirection.
119-123: Correctly passing organization data to RealtimeStatusThe 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 definitionThe 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 contextThe code now correctly transforms menu item paths by replacing the
:organizationIdplaceholder with the actual organization ID.
292-321: Robust path matching logicThe 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.
| if (!risk) { | ||
| redirect("/risk"); | ||
| } |
There was a problem hiding this comment.
🛠️ 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.
| if (!risk) { | |
| redirect("/risk"); | |
| } | |
| if (!risk) { | |
| redirect(`/${session.user.organizationId}/risk`); | |
| } |
| interface LayoutProps { | ||
| children: React.ReactNode; | ||
| params: Promise<{ riskId: string }>; | ||
| } |
There was a problem hiding this comment.
🛠️ 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.
| interface LayoutProps { | |
| children: React.ReactNode; | |
| params: Promise<{ riskId: string }>; | |
| } | |
| interface LayoutProps { | |
| children: React.ReactNode; | |
| params: { riskId: string }; | |
| } |
| const riskId = await params; | ||
| const risk = await getRisk(riskId.riskId, session.user.organizationId); |
There was a problem hiding this comment.
🛠️ 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.
| const riskId = await params; | |
| const risk = await getRisk(riskId.riskId, session.user.organizationId); | |
| const risk = await getRisk(params.riskId, session.user.organizationId); |
| const session = await auth(); | ||
| const user = session?.user; | ||
| const orgId = user?.organizationId; |
There was a problem hiding this comment.
🛠️ 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.
| 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("/"); | |
| } |
| const t = await getI18n(); | ||
| const session = await auth(); | ||
| const user = session?.user; | ||
| const organizationId = user?.organizationId; |
There was a problem hiding this comment.
🛠️ 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.
| 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("/"); | |
| } |
| const t = await getI18n(); | ||
| const session = await auth(); | ||
| const user = session?.user; | ||
| const organizationId = user?.organizationId; |
There was a problem hiding this comment.
🛠️ 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.
| 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("/"); | |
| } |
| 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> | ||
| ); |
There was a problem hiding this comment.
🛠️ 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.
| 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> | |
| ); |
| 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)); | ||
| } | ||
|
|
There was a problem hiding this comment.
🛠️ 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.
| 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)); | |
| } | |
| } |
| <Link href="/overview/frameworks"> | ||
| {t("frameworks.overview.progress.empty.action")} | ||
| </Link> |
There was a problem hiding this comment.
🛠️ 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.
| <Link href="/overview/frameworks"> | |
| {t("frameworks.overview.progress.empty.action")} | |
| </Link> | |
| <Link href={`/${orgId}/frameworks`}> | |
| {t("frameworks.overview.progress.empty.action")} | |
| </Link> |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 identifierThe 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 statementsThe 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 importsThis 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 interfaceThe
AssigneeSectionPropsinterface clearly defines the required props with appropriate types. The interface includesevidenceId,currentAssigneeId(which can be nullable), and an async callback for success handling.
24-70: Well-structured component with robust state managementThe component handles state management correctly with proper effect hooks to sync the selected assignee with props and data. The assignment logic in
handleAssigneeChangecorrectly handles the "none" case and updates both local state and the server.
72-78: Good loading and error state handlingThe 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 interfaceThe 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 hookThe 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 assignmentThe component correctly handles the assignment of tests to administrators, maintaining consistent state management patterns with the evidence assignment component. The use of
useEffecthooks ensures proper synchronization between props and state.
75-137: Consistent UI pattern across assignment componentsThe 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
adminsdata fetched fromuseOrganizationAdmins. 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 tsxLength of output: 66
RiskRegisterFilters Usage Verification
The initial command failed because
--type tsxisn’t recognized. Please run the above script to verify whether theRiskRegisterFilterstoken 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 typescriptLength of output: 80
Action Required: Address the commented filtering functionality
It appears that the
RiskRegisterFiltersfunctionality 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 ofapps/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.
| onError: (error) => { | ||
| console.log("error", error); | ||
| toast.error("Failed to update Assignee"); | ||
| }, |
There was a problem hiding this comment.
🛠️ 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.
| onError: (error) => { | |
| console.log("error", error); | |
| toast.error("Failed to update Assignee"); | |
| }, | |
| onError: () => { | |
| toast.error("Failed to update Assignee"); | |
| }, |
Summary by CodeRabbit