From ff3f6f7a86eca849617722500205bb9f47c2803b Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 26 Aug 2025 13:10:30 -0400 Subject: [PATCH 01/10] refactor: enhance EmployeeCompletionChart with profile links - Added external profile links for employees in the EmployeeCompletionChart, allowing users to view detailed profiles. - Integrated organization ID retrieval using useParams for dynamic linking. - Improved layout of employee details for better visual presentation. --- .../components/EmployeeCompletionChart.tsx | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/app/src/app/(app)/[orgId]/people/dashboard/components/EmployeeCompletionChart.tsx b/apps/app/src/app/(app)/[orgId]/people/dashboard/components/EmployeeCompletionChart.tsx index 55ff38f56..a2c820684 100644 --- a/apps/app/src/app/(app)/[orgId]/people/dashboard/components/EmployeeCompletionChart.tsx +++ b/apps/app/src/app/(app)/[orgId]/people/dashboard/components/EmployeeCompletionChart.tsx @@ -2,7 +2,9 @@ import { Card, CardContent, CardHeader, CardTitle } from '@comp/ui/card'; import { Input } from '@comp/ui/input'; -import { Search } from 'lucide-react'; +import { ExternalLink, Search } from 'lucide-react'; +import Link from 'next/link'; +import { useParams } from 'next/navigation'; import type { CSSProperties } from 'react'; import * as React from 'react'; @@ -47,6 +49,8 @@ export function EmployeeCompletionChart({ trainingVideos, showAll = false, }: EmployeeCompletionChartProps) { + const params = useParams(); + const orgId = params.orgId as string; const [searchTerm, setSearchTerm] = React.useState(''); const [displayedItems, setDisplayedItems] = React.useState(showAll ? 20 : 5); const [isLoading, setIsLoading] = React.useState(false); @@ -209,8 +213,19 @@ export function EmployeeCompletionChart({ {sortedStats.map((stat) => (
-
-

{stat.name}

+
+
+

{stat.name}

+ + View Profile + + +

{stat.email}

From 8a81f42b22da29a7a39e2b4698e94421a6a329fd Mon Sep 17 00:00:00 2001 From: Dhanus Date: Wed, 27 Aug 2025 00:11:24 +0530 Subject: [PATCH 02/10] fix: Enforce role-based access control in app --- apps/app/src/app/(app)/layout.tsx | 27 +++++++++++++++++++++++++++ apps/app/src/app/page.tsx | 4 ---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/apps/app/src/app/(app)/layout.tsx b/apps/app/src/app/(app)/layout.tsx index 8fd5117a1..30379b8bf 100644 --- a/apps/app/src/app/(app)/layout.tsx +++ b/apps/app/src/app/(app)/layout.tsx @@ -30,5 +30,32 @@ export default async function Layout({ children }: { children: React.ReactNode } } } + const { activeOrganizationId } = session.session; + const { id: userId } = session.user; + + if (activeOrganizationId) { + const currentUserMember = await db.member.findFirst({ + where: { + organizationId: activeOrganizationId, + userId: userId, + }, + select: { + role: true, + }, + }); + + const isAuthorized = + currentUserMember && + (currentUserMember.role.includes('admin') || currentUserMember.role.includes('owner')); + + if (!isAuthorized) { + const currentPath = hdrs.get('x-pathname') || ''; + + if (currentPath !== '/no-access') { + return redirect('/no-access'); + } + } + } + return <>{children}; } diff --git a/apps/app/src/app/page.tsx b/apps/app/src/app/page.tsx index 61552c2c6..c83d58de7 100644 --- a/apps/app/src/app/page.tsx +++ b/apps/app/src/app/page.tsx @@ -72,10 +72,6 @@ export default async function RootPage({ }, }); - if (member?.role === 'employee') { - return redirect(await buildUrlWithParams('/no-access')); - } - if (!member) { return redirect(await buildUrlWithParams('/setup')); } From a9957cd3daf9d15430d1c47c45ae4e6139e47b92 Mon Sep 17 00:00:00 2001 From: Dhanus Date: Wed, 27 Aug 2025 00:21:14 +0530 Subject: [PATCH 03/10] fix: Prisma seed command in `packages/db` --- packages/db/package.json | 2 +- .../db/prisma/seed/frameworkEditorSchemas.js | 136 --------------- packages/db/prisma/seed/seed.js | 160 ------------------ 3 files changed, 1 insertion(+), 297 deletions(-) delete mode 100644 packages/db/prisma/seed/frameworkEditorSchemas.js delete mode 100644 packages/db/prisma/seed/seed.js diff --git a/packages/db/package.json b/packages/db/package.json index 993261b7a..9ed8a996f 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -34,7 +34,7 @@ "db:generate": "prisma generate", "db:migrate": "prisma migrate dev", "db:push": "prisma db push", - "db:seed": "prisma db seed", + "db:seed": "bun prisma/seed/seed.ts", "db:studio": "prisma studio", "docker:clean": "docker compose down -v", "docker:down": "docker compose down", diff --git a/packages/db/prisma/seed/frameworkEditorSchemas.js b/packages/db/prisma/seed/frameworkEditorSchemas.js deleted file mode 100644 index 28709b66b..000000000 --- a/packages/db/prisma/seed/frameworkEditorSchemas.js +++ /dev/null @@ -1,136 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.frameworkEditorModelSchemas = exports.FrameworkEditorControlTemplateSchema = exports.FrameworkEditorTaskTemplateSchema = exports.FrameworkEditorPolicyTemplateSchema = exports.FrameworkEditorRequirementSchema = exports.FrameworkEditorFrameworkSchema = exports.FrameworkEditorVideoSchema = void 0; -const zod_1 = require("zod"); -// Assuming Frequency and Departments enums are defined elsewhere and imported -// For now, we'll use z.string() as a placeholder if their definitions aren't available. -// import { Frequency, Departments } from './path-to-shared-enums'; // Example import -const datePreprocess = (arg) => { - if (typeof arg === 'string' && /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}$/.test(arg)) { - return arg.replace(' ', 'T') + 'Z'; - } - return arg; -}; -exports.FrameworkEditorVideoSchema = zod_1.z.object({ - id: zod_1.z.string().optional(), // @id @default - title: zod_1.z.string(), - description: zod_1.z.string(), - youtubeId: zod_1.z.string(), - url: zod_1.z.string(), - createdAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for createdAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) - updatedAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for updatedAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) @updatedAt -}); -exports.FrameworkEditorFrameworkSchema = zod_1.z.object({ - id: zod_1.z.string().optional(), // @id @default - name: zod_1.z.string(), - version: zod_1.z.string(), - description: zod_1.z.string(), - visible: zod_1.z.boolean().optional(), // @default(true) - // requirements: FrameworkEditorRequirement[] - relational, omitted - // frameworkInstances: FrameworkInstance[] - relational, omitted - createdAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for createdAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) - updatedAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for updatedAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) @updatedAt -}); -exports.FrameworkEditorRequirementSchema = zod_1.z.object({ - id: zod_1.z.string().optional(), // @id @default - frameworkId: zod_1.z.string(), - // framework: FrameworkEditorFramework - relational, omitted - name: zod_1.z.string(), - identifier: zod_1.z.string().optional(), // @default("") - description: zod_1.z.string(), - // controlTemplates: FrameworkEditorControlTemplate[] - relational, omitted - // requirementMaps: RequirementMap[] - relational, omitted - createdAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for createdAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) - updatedAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for updatedAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) @updatedAt -}); -exports.FrameworkEditorPolicyTemplateSchema = zod_1.z.object({ - id: zod_1.z.string().optional(), // @id @default - name: zod_1.z.string(), - description: zod_1.z.string(), - frequency: zod_1.z.string(), // Placeholder for Frequency enum - department: zod_1.z.string(), // Placeholder for Departments enum - content: zod_1.z.any(), // Json - // controlTemplates: FrameworkEditorControlTemplate[] - relational, omitted - createdAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for createdAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) - updatedAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for updatedAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) @updatedAt - // policies: Policy[] - relational, omitted -}); -exports.FrameworkEditorTaskTemplateSchema = zod_1.z.object({ - id: zod_1.z.string().optional(), // @id @default - name: zod_1.z.string(), - description: zod_1.z.string(), - frequency: zod_1.z.string(), // Placeholder for Frequency enum - department: zod_1.z.string(), // Placeholder for Departments enum - // controlTemplates: FrameworkEditorControlTemplate[] - relational, omitted - createdAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for createdAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) - updatedAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for updatedAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) @updatedAt - // tasks: Task[] - relational, omitted -}); -exports.FrameworkEditorControlTemplateSchema = zod_1.z.object({ - id: zod_1.z.string().optional(), // @id @default - name: zod_1.z.string(), - description: zod_1.z.string(), - // policyTemplates: FrameworkEditorPolicyTemplate[] - relational, omitted - // requirements: FrameworkEditorRequirement[] - relational, omitted - // taskTemplates: FrameworkEditorTaskTemplate[] - relational, omitted - createdAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for createdAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) - updatedAt: zod_1.z - .preprocess(datePreprocess, zod_1.z.string().datetime({ - message: 'Invalid datetime string for updatedAt. Expected ISO 8601 format.', - })) - .optional(), // @default(now()) @updatedAt - // controls: Control[] - relational, omitted -}); -// For use in seed script validation -exports.frameworkEditorModelSchemas = { - FrameworkEditorVideo: exports.FrameworkEditorVideoSchema, - FrameworkEditorFramework: exports.FrameworkEditorFrameworkSchema, - FrameworkEditorRequirement: exports.FrameworkEditorRequirementSchema, - FrameworkEditorPolicyTemplate: exports.FrameworkEditorPolicyTemplateSchema, - FrameworkEditorTaskTemplate: exports.FrameworkEditorTaskTemplateSchema, - FrameworkEditorControlTemplate: exports.FrameworkEditorControlTemplateSchema, -}; diff --git a/packages/db/prisma/seed/seed.js b/packages/db/prisma/seed/seed.js deleted file mode 100644 index 4836087ad..000000000 --- a/packages/db/prisma/seed/seed.js +++ /dev/null @@ -1,160 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const client_1 = require("@prisma/client"); -const promises_1 = __importDefault(require("node:fs/promises")); -const node_path_1 = __importDefault(require("node:path")); -const frameworkEditorSchemas_1 = require("./frameworkEditorSchemas"); -const prisma = new client_1.PrismaClient(); -async function seedJsonFiles(subDirectory) { - const directoryPath = node_path_1.default.join(__dirname, subDirectory); - console.log(`Starting to seed files from: ${directoryPath}`); - const files = await promises_1.default.readdir(directoryPath); - const jsonFiles = files.filter((file) => file.endsWith('.json')); - for (const jsonFile of jsonFiles) { - try { - const filePath = node_path_1.default.join(directoryPath, jsonFile); - const jsonContent = await promises_1.default.readFile(filePath, 'utf-8'); - const jsonData = JSON.parse(jsonContent); - if (!Array.isArray(jsonData) || jsonData.length === 0) { - console.log(`Skipping empty or invalid JSON file: ${jsonFile}`); - continue; - } - if (subDirectory === 'primitives') { - const modelNameForPrisma = jsonFile.replace('.json', ''); - const prismaModelKey = modelNameForPrisma.charAt(0).toLowerCase() + modelNameForPrisma.slice(1); - const zodModelKey = modelNameForPrisma; - const prismaAny = prisma; - if (!prismaAny[prismaModelKey] || - typeof prismaAny[prismaModelKey].createMany !== 'function') { - console.warn(`Model ${prismaModelKey} not found on Prisma client or does not support createMany. Skipping ${jsonFile}.`); - continue; - } - const zodSchema = frameworkEditorSchemas_1.frameworkEditorModelSchemas[zodModelKey]; - if (!zodSchema) { - console.warn(`Zod schema not found for model ${String(zodModelKey)}. Skipping validation for ${jsonFile}.`); - } - else { - console.log(`Validating ${jsonData.length} records from ${jsonFile} against ${String(zodModelKey)} schema...`); - for (const item of jsonData) { - try { - zodSchema.parse(item); - } - catch (validationError) { - console.error(`Validation failed for an item in ${jsonFile} for model ${String(zodModelKey)}:`, item); - console.error('Validation errors:', validationError); - throw new Error(`Data validation failed for ${jsonFile}.`); - } - } - console.log(`Validation successful for ${jsonFile}.`); - } - const processedData = jsonData.map((item) => { - const newItem = { ...item }; - if (newItem.createdAt && typeof newItem.createdAt === 'string') { - newItem.createdAt = new Date(newItem.createdAt); - } - if (newItem.updatedAt && typeof newItem.updatedAt === 'string') { - newItem.updatedAt = new Date(newItem.updatedAt); - } - return newItem; - }); - console.log(`Seeding ${processedData.length} records from ${jsonFile} into ${prismaModelKey}...`); - // Use upsert to update existing records instead of skipping them - for (const record of processedData) { - await prismaAny[prismaModelKey].upsert({ - where: { id: record.id }, - create: record, - update: record, - }); - } - console.log(`Finished seeding ${jsonFile} from primitives.`); - } - else if (subDirectory === 'relations') { - // Expected filename format: _ModelAToModelB.json - if (!jsonFile.startsWith('_') || !jsonFile.includes('To')) { - console.warn(`Skipping relation file with unexpected format: ${jsonFile}`); - continue; - } - const modelNamesPart = jsonFile.substring(1, jsonFile.indexOf('.json')); - const [modelANamePascal, modelBNamePascal] = modelNamesPart.split('To'); - if (!modelANamePascal || !modelBNamePascal) { - console.warn(`Could not parse model names from relation file: ${jsonFile}`); - continue; - } - const prismaModelAName = modelANamePascal.charAt(0).toLowerCase() + modelANamePascal.slice(1); - // Infer relation field name on ModelA: pluralized, camelCased ModelB name - // e.g., if ModelB is FrameworkEditorPolicyTemplate, relation field is frameworkEditorPolicyTemplates - // This is a common convention, but might need adjustment based on actual schema - let relationFieldNameOnModelA = modelBNamePascal.charAt(0).toLowerCase() + modelBNamePascal.slice(1); - if (!relationFieldNameOnModelA.endsWith('s')) { - // basic pluralization - relationFieldNameOnModelA += 's'; - } - // Special handling for 'Requirement' -> 'requirements' (already plural) - // and other specific cases if 's' isn't the right pluralization. - // For now, using a direct map for known cases from the user's file names. - if (modelBNamePascal === 'FrameworkEditorPolicyTemplate') { - relationFieldNameOnModelA = 'policyTemplates'; - } - else if (modelBNamePascal === 'FrameworkEditorRequirement') { - relationFieldNameOnModelA = 'requirements'; - } - else if (modelBNamePascal === 'FrameworkEditorTaskTemplate') { - relationFieldNameOnModelA = 'taskTemplates'; - } - const prismaAny = prisma; - if (!prismaAny[prismaModelAName] || - typeof prismaAny[prismaModelAName].update !== 'function') { - console.warn(`Model ${prismaModelAName} not found on Prisma client or does not support update. Skipping ${jsonFile}.`); - continue; - } - console.log(`Processing relations from ${jsonFile} for ${prismaModelAName} to connect via ${relationFieldNameOnModelA}...`); - let connectionsMade = 0; - for (const relationItem of jsonData) { - if (!relationItem.A || !relationItem.B) { - console.warn(`Skipping invalid relation item in ${jsonFile}:`, relationItem); - continue; - } - const idA = relationItem.A; - const idB = relationItem.B; - try { - await prismaAny[prismaModelAName].update({ - where: { id: idA }, - data: { - [relationFieldNameOnModelA]: { - connect: { id: idB }, - }, - }, - }); - connectionsMade++; - } - catch (error) { - console.error(`Failed to connect ${prismaModelAName} (${idA}) with ${modelBNamePascal} (${idB}) from ${jsonFile}:`, error); - // Decide if one error should stop the whole process for this file or continue - } - } - console.log(`Finished processing ${jsonFile}. Made ${connectionsMade} connections.`); - } - } - catch (error) { - console.error(`Error processing ${jsonFile}:`, error); - throw error; - } - } -} -async function main() { - try { - await seedJsonFiles('primitives'); - await seedJsonFiles('relations'); - await prisma.$disconnect(); - console.log('Seeding completed successfully for primitives and relations.'); - } - catch (error) { - console.error('Seeding failed:', error); - await prisma.$disconnect(); - process.exit(1); - } -} -main(); From a4056bf4d904baf450fd07c4e7ce0f83100e3504 Mon Sep 17 00:00:00 2001 From: Dhanus Date: Wed, 27 Aug 2025 23:52:54 +0530 Subject: [PATCH 04/10] fix: Move role checks on org level --- apps/app/src/app/(app)/[orgId]/layout.tsx | 7 ++++++ apps/app/src/app/(app)/layout.tsx | 27 ----------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/apps/app/src/app/(app)/[orgId]/layout.tsx b/apps/app/src/app/(app)/[orgId]/layout.tsx index 6bc8fb313..9a80ba8e6 100644 --- a/apps/app/src/app/(app)/[orgId]/layout.tsx +++ b/apps/app/src/app/(app)/[orgId]/layout.tsx @@ -63,6 +63,13 @@ export default async function Layout({ return redirect('/auth/unauthorized'); } + const isAuthorized = member.role.includes('admin') || member.role.includes('owner'); + + // If user is not authorized, redirect to no-access page + if (!isAuthorized) { + return redirect('/no-access'); + } + // If this org is not accessible on current plan, redirect to upgrade if (!organization.hasAccess) { return redirect(`/upgrade/${organization.id}`); diff --git a/apps/app/src/app/(app)/layout.tsx b/apps/app/src/app/(app)/layout.tsx index 30379b8bf..8fd5117a1 100644 --- a/apps/app/src/app/(app)/layout.tsx +++ b/apps/app/src/app/(app)/layout.tsx @@ -30,32 +30,5 @@ export default async function Layout({ children }: { children: React.ReactNode } } } - const { activeOrganizationId } = session.session; - const { id: userId } = session.user; - - if (activeOrganizationId) { - const currentUserMember = await db.member.findFirst({ - where: { - organizationId: activeOrganizationId, - userId: userId, - }, - select: { - role: true, - }, - }); - - const isAuthorized = - currentUserMember && - (currentUserMember.role.includes('admin') || currentUserMember.role.includes('owner')); - - if (!isAuthorized) { - const currentPath = hdrs.get('x-pathname') || ''; - - if (currentPath !== '/no-access') { - return redirect('/no-access'); - } - } - } - return <>{children}; } From 155340017c62a09dcfd03709011e25df89a85863 Mon Sep 17 00:00:00 2001 From: Dhanus Date: Thu, 28 Aug 2025 00:08:12 +0530 Subject: [PATCH 05/10] fix: Allow access to auditor role --- apps/app/src/app/(app)/[orgId]/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app/src/app/(app)/[orgId]/layout.tsx b/apps/app/src/app/(app)/[orgId]/layout.tsx index 9a80ba8e6..ed0f92674 100644 --- a/apps/app/src/app/(app)/[orgId]/layout.tsx +++ b/apps/app/src/app/(app)/[orgId]/layout.tsx @@ -63,7 +63,7 @@ export default async function Layout({ return redirect('/auth/unauthorized'); } - const isAuthorized = member.role.includes('admin') || member.role.includes('owner'); + const isAuthorized = ['admin', 'owner', 'auditor'].includes(member.role); // If user is not authorized, redirect to no-access page if (!isAuthorized) { From bfa18f00b0dfe77026ec37aa6a771adea425f3d5 Mon Sep 17 00:00:00 2001 From: Dhanus Date: Thu, 28 Aug 2025 00:13:32 +0530 Subject: [PATCH 06/10] chore: Just restrict access to employee role --- apps/app/src/app/(app)/[orgId]/layout.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/app/src/app/(app)/[orgId]/layout.tsx b/apps/app/src/app/(app)/[orgId]/layout.tsx index ed0f92674..3bb85b700 100644 --- a/apps/app/src/app/(app)/[orgId]/layout.tsx +++ b/apps/app/src/app/(app)/[orgId]/layout.tsx @@ -63,10 +63,7 @@ export default async function Layout({ return redirect('/auth/unauthorized'); } - const isAuthorized = ['admin', 'owner', 'auditor'].includes(member.role); - - // If user is not authorized, redirect to no-access page - if (!isAuthorized) { + if (member.role === 'employee') { return redirect('/no-access'); } From f16ad2f9d9d1a30b041f3fae5df570e149f12e2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 11:22:38 -0400 Subject: [PATCH 07/10] chore(deps): bump @tiptap/extension-highlight from 2.22.3 to 3.3.0 (#1404) Bumps [@tiptap/extension-highlight](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/extension-highlight) from 2.22.3 to 3.3.0. - [Release notes](https://github.com/ueberdosis/tiptap/releases) - [Changelog](https://github.com/ueberdosis/tiptap/blob/develop/packages/extension-highlight/CHANGELOG.md) - [Commits](https://github.com/ueberdosis/tiptap/commits/v3.3.0/packages/extension-highlight) --- updated-dependencies: - dependency-name: "@tiptap/extension-highlight" dependency-version: 3.3.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/package.json b/packages/ui/package.json index e943c125a..b3e487ea6 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -39,7 +39,7 @@ "@tiptap/extension-bold": "2.14.0", "@tiptap/extension-character-count": "2.14.0", "@tiptap/extension-code-block-lowlight": "2.14.0", - "@tiptap/extension-highlight": "2.22.3", + "@tiptap/extension-highlight": "3.3.0", "@tiptap/extension-image": "2.14.0", "@tiptap/extension-link": "2.14.0", "@tiptap/extension-placeholder": "2.14.0", From ee901ab8fdd0c6c4ff344bf762cc1efabe1451af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 11:23:24 -0400 Subject: [PATCH 08/10] chore(deps): bump dub from 0.63.7 to 0.66.1 (#1399) Bumps [dub](https://github.com/dubinc/dub-ts) from 0.63.7 to 0.66.1. - [Release notes](https://github.com/dubinc/dub-ts/releases) - [Changelog](https://github.com/dubinc/dub-ts/blob/main/RELEASES.md) - [Commits](https://github.com/dubinc/dub-ts/compare/v0.63.7...v0.66.1) --- updated-dependencies: - dependency-name: dub dependency-version: 0.66.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mariano Fuentes --- apps/app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app/package.json b/apps/app/package.json index 0f9e14891..983cf85f9 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -57,7 +57,7 @@ "better-auth": "^1.2.8", "canvas-confetti": "^1.9.3", "d3": "^7.9.0", - "dub": "^0.63.6", + "dub": "^0.66.1", "framer-motion": "^12.18.1", "geist": "^1.3.1", "lucide-react": "^0.534.0", From 0740452faa8f3d51b38176cf69deba6f0c6f3b18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 11:24:52 -0400 Subject: [PATCH 09/10] chore(deps): bump @dub/embed-react from 0.0.15 to 0.0.16 (#1337) Bumps [@dub/embed-react](https://github.com/dubinc/dub) from 0.0.15 to 0.0.16. - [Commits](https://github.com/dubinc/dub/commits) --- updated-dependencies: - dependency-name: "@dub/embed-react" dependency-version: 0.0.16 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mariano Fuentes --- apps/app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app/package.json b/apps/app/package.json index 983cf85f9..79c6b02ff 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -22,7 +22,7 @@ "@dnd-kit/utilities": "^3.2.2", "@dub/analytics": "^0.0.27", "@dub/better-auth": "^0.0.3", - "@dub/embed-react": "^0.0.15", + "@dub/embed-react": "^0.0.16", "@hookform/resolvers": "^5.1.1", "@mendable/firecrawl-js": "^1.24.0", "@nangohq/frontend": "^0.53.2", From dd928ad8ed3ef6401ec1e7d0d13772d580d987e3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 11:41:49 -0400 Subject: [PATCH 10/10] chore: update Header component and enhance NoAccess page layout (#1425) - Added Header component to NoAccess page for better organization context. - Adjusted layout of NoAccess page to improve user experience and visual structure. - Updated Header component to conditionally render AssistantButton based on hideChat prop. Dependencies updated in bun.lock for @dub/embed-react, dub, and @tiptap/extension-highlight. Co-authored-by: Mariano Fuentes --- apps/app/src/app/(app)/no-access/page.tsx | 32 +++++++++++++---------- apps/app/src/components/header.tsx | 10 +++++-- bun.lock | 24 ++++++++--------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/apps/app/src/app/(app)/no-access/page.tsx b/apps/app/src/app/(app)/no-access/page.tsx index 392b34cb7..1369d4706 100644 --- a/apps/app/src/app/(app)/no-access/page.tsx +++ b/apps/app/src/app/(app)/no-access/page.tsx @@ -1,3 +1,4 @@ +import { Header } from '@/components/header'; import { OrganizationSwitcher } from '@/components/organization-switcher'; import { auth } from '@/utils/auth'; import { db } from '@db'; @@ -31,20 +32,23 @@ export default async function NoAccess() { }); return ( -
-

Access Denied

-
-

- Employees don't have access to app.trycomp.ai, did you mean to go to{' '} - - portal.trycomp.ai - - ? -

-

Please select another organization or contact your organization administrator.

-
-
- +
+
+
+

Access Denied

+
+

+ Employees don't have access to app.trycomp.ai, did you mean to go to{' '} + + portal.trycomp.ai + + ? +

+

Please select another organization or contact your organization administrator.

+
+
+ +
); diff --git a/apps/app/src/components/header.tsx b/apps/app/src/components/header.tsx index 004266a07..65e4d9185 100644 --- a/apps/app/src/components/header.tsx +++ b/apps/app/src/components/header.tsx @@ -5,14 +5,20 @@ import { Suspense } from 'react'; import { AssistantButton } from './ai/chat-button'; import { MobileMenu } from './mobile-menu'; -export async function Header({ organizationId }: { organizationId?: string }) { +export async function Header({ + organizationId, + hideChat = false, +}: { + organizationId?: string; + hideChat?: boolean; +}) { const { organizations } = await getOrganizations(); return (
- + {!hideChat && }
}> diff --git a/bun.lock b/bun.lock index 0bfebbbc4..a5cb1cf90 100644 --- a/bun.lock +++ b/bun.lock @@ -125,7 +125,7 @@ "@dnd-kit/utilities": "^3.2.2", "@dub/analytics": "^0.0.27", "@dub/better-auth": "^0.0.3", - "@dub/embed-react": "^0.0.15", + "@dub/embed-react": "^0.0.16", "@hookform/resolvers": "^5.1.1", "@mendable/firecrawl-js": "^1.24.0", "@nangohq/frontend": "^0.53.2", @@ -160,7 +160,7 @@ "better-auth": "^1.2.8", "canvas-confetti": "^1.9.3", "d3": "^7.9.0", - "dub": "^0.63.6", + "dub": "^0.66.1", "framer-motion": "^12.18.1", "geist": "^1.3.1", "lucide-react": "^0.534.0", @@ -383,7 +383,7 @@ "@tiptap/extension-bold": "2.14.0", "@tiptap/extension-character-count": "2.14.0", "@tiptap/extension-code-block-lowlight": "2.14.0", - "@tiptap/extension-highlight": "2.22.3", + "@tiptap/extension-highlight": "3.3.0", "@tiptap/extension-image": "2.14.0", "@tiptap/extension-link": "2.14.0", "@tiptap/extension-placeholder": "2.14.0", @@ -767,9 +767,9 @@ "@dub/better-auth": ["@dub/better-auth@0.0.3", "", { "dependencies": { "zod": "^3.24.4" } }, "sha512-5haJGPt8Xab1L4De6naqEwC8k2KJrxI2iAfs5t9u6iNob3DNBTsbSZGb2godIigg9ZsS2J+joKKG5hDK6jT0UQ=="], - "@dub/embed-core": ["@dub/embed-core@0.0.15", "", { "dependencies": { "@floating-ui/dom": "^1.6.12" } }, "sha512-0hfWesBfUBpzw29FbCEUSxakNCCebTcyoVXHanE45HSj0Atmx3ANpilpa25lR5g62MwLg9kcX4dR6jpTfLeQ8g=="], + "@dub/embed-core": ["@dub/embed-core@0.0.16", "", { "dependencies": { "@floating-ui/dom": "^1.6.12" } }, "sha512-CsPVxvC2E8OcgwVUA5zIwy+x+XGP4IaE4LLlMz4GoK24ACn6Hcy7Pn/2vb4HFMSPay8fzd47cEQk/2MXsFQXPQ=="], - "@dub/embed-react": ["@dub/embed-react@0.0.15", "", { "dependencies": { "@dub/embed-core": "^0.0.15", "class-variance-authority": "^0.7.0", "vite": "5.2.9" }, "peerDependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" } }, "sha512-GLLAMGpn6WLXbM8q4n0lPOrjsYkmI0W3LvAAMFbb+FeQ6OwFvz390xwWW2ygfUo74wvWLSYVEOoHymiuoSrb7Q=="], + "@dub/embed-react": ["@dub/embed-react@0.0.16", "", { "dependencies": { "@dub/embed-core": "^0.0.16", "class-variance-authority": "^0.7.0", "vite": "5.2.9" }, "peerDependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" } }, "sha512-HVo20cEKEX5nRxJsUq6XiUsv2HnmZec2iQbGruWf+Z//OyiUboquaGqOUnNNOmLPdmWONzaYxXYhvAmEjKU1XQ=="], "@effect/platform": ["@effect/platform@0.90.3", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.33.0", "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.17.7" } }, "sha512-XvQ37yzWQKih4Du2CYladd1i/MzqtgkTPNCaN6Ku6No4CK83hDtXIV/rP03nEoBg2R3Pqgz6gGWmE2id2G81HA=="], @@ -1707,7 +1707,7 @@ "@tiptap/extension-heading": ["@tiptap/extension-heading@2.26.1", "", { "peerDependencies": { "@tiptap/core": "^2.7.0" } }, "sha512-KSzL8WZV3pjJG9ke4RaU70+B5UlYR2S6olNt5UCAawM+fi11mobVztiBoC19xtpSVqIXC1AmXOqUgnuSvmE4ZA=="], - "@tiptap/extension-highlight": ["@tiptap/extension-highlight@2.22.3", "", { "peerDependencies": { "@tiptap/core": "^2.7.0" } }, "sha512-cdPSeQ3QcThhJdzkjK9a1871uPQjwmOf0WzTGW33lJyJDQHypWIRNUus56c3pGA7BgV9P59QW7Fm8rDnM8XkbA=="], + "@tiptap/extension-highlight": ["@tiptap/extension-highlight@3.3.0", "", { "peerDependencies": { "@tiptap/core": "^3.3.0" } }, "sha512-G+mHVXkoQ4uG97JRFN56qL42iJVKbSeWgDGssmnjNZN/W4Nsc40LuNryNbQUOM9CJbEMIT5NGAwvc/RG0OpGGQ=="], "@tiptap/extension-history": ["@tiptap/extension-history@2.26.1", "", { "peerDependencies": { "@tiptap/core": "^2.7.0", "@tiptap/pm": "^2.7.0" } }, "sha512-m6YR1gkkauIDo3PRl0gP+7Oc4n5OqDzcjVh6LvWREmZP8nmi94hfseYbqOXUb6RPHIc0JKF02eiRifT4MSd2nw=="], @@ -2755,7 +2755,7 @@ "draco3d": ["draco3d@1.5.7", "", {}, "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ=="], - "dub": ["dub@0.63.7", "", { "peerDependencies": { "@modelcontextprotocol/sdk": ">=1.5.0 <1.10.0", "zod": ">= 3" }, "optionalPeers": ["@modelcontextprotocol/sdk"], "bin": { "mcp": "bin/mcp-server.js" } }, "sha512-DhMF4ceWIPjMGA4ZU8L1pySJFtwdXRjcwchRLLWReN5t3C/MZohrLvrqbeJOBfdOE4VKGtqI8uYD3kBT+4nMSQ=="], + "dub": ["dub@0.66.1", "", { "dependencies": { "zod": "^3.20.0" } }, "sha512-a3XlK1R7Pnfj33sB7Hpcl0lidrX3Rq46ZTQN48eCoMj+2QIumWoOZsEnAIP6qfEtvGuNCaDfCzfMh0Im2zyo5g=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], @@ -4309,7 +4309,7 @@ "saxes": ["saxes@6.0.0", "", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA=="], - "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], + "scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="], "schema-utils": ["schema-utils@3.3.0", "", { "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } }, "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg=="], @@ -5111,8 +5111,6 @@ "@react-email/components/@react-email/render": ["@react-email/render@1.1.2", "", { "dependencies": { "html-to-text": "^9.0.5", "prettier": "^3.5.3", "react-promise-suspense": "^0.3.4" }, "peerDependencies": { "react": "^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RnRehYN3v9gVlNMehHPHhyp2RQo7+pSkHDtXPvg3s0GbzM9SQMW4Qrf8GRNvtpLC4gsI+Wt0VatNRUFqjvevbw=="], - "@react-three/fiber/scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="], - "@react-three/postprocessing/maath": ["maath@0.6.0", "", { "peerDependencies": { "@types/three": ">=0.144.0", "three": ">=0.144.0" } }, "sha512-dSb2xQuP7vDnaYqfoKzlApeRcR2xtN8/f7WV/TMAkBC8552TwTLtOO0JTcSygkYMjNDPoo6V01jTw/aPi4JrMw=="], "@semantic-release/github/@semantic-release/error": ["@semantic-release/error@4.0.0", "", {}, "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ=="], @@ -5247,6 +5245,8 @@ "dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + "dub/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "duplexer2/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "ecdsa-sig-formatter/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], @@ -5821,14 +5821,14 @@ "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + "react-dom/scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], + "react-dropzone/file-selector": ["file-selector@2.1.2", "", { "dependencies": { "tslib": "^2.7.0" } }, "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig=="], "react-email/chalk": ["chalk@5.6.0", "", {}, "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ=="], "react-promise-suspense/fast-deep-equal": ["fast-deep-equal@2.0.1", "", {}, "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w=="], - "react-reconciler/scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="], - "read-cache/pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], "read-pkg/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="],