import '@/styles/code.css' import '@/styles/editor.css' import '@/styles/focus.css' import '@/styles/globals.css' import '@/styles/graphiql-base.css' import '@/styles/grid.css' import '@/styles/markdown-preview.css' import '@/styles/monaco.css' import '@/styles/react-data-grid-logs.css' import '@/styles/reactflow.css' import '@/styles/storage.css' import '@/styles/stripe.css' import '@/styles/ui.css' import 'react-data-grid/lib/styles.css' import 'ui-patterns/ShimmeringLoader/index.css' import { loader } from '@monaco-editor/react' import * as Sentry from '@sentry/nextjs' import { HydrationBoundary, QueryClientProvider } from '@tanstack/react-query' import { ReactQueryDevtools } from '@tanstack/react-query-devtools' import { FeatureFlagProvider, getFlags, TelemetryTagManager, ThemeProvider, useThemeSandbox, } from 'common' import MetaFaviconsPagesRouter from 'common/MetaFavicons/pages-router' import dayjs from 'dayjs' import customParseFormat from 'dayjs/plugin/customParseFormat' import duration from 'dayjs/plugin/duration' import relativeTime from 'dayjs/plugin/relativeTime' import timezone from 'dayjs/plugin/timezone' import utc from 'dayjs/plugin/utc' import { DevToolbar, DevToolbarProvider, DevToolbarTrigger, type ExtraTab } from 'dev-tools' import dynamic from 'next/dynamic' import Head from 'next/head' import { NuqsAdapter } from 'nuqs/adapters/next/pages' import { ErrorInfo, useCallback, useEffect, useState, type ComponentProps } from 'react' import { ErrorBoundary } from 'react-error-boundary' import { TooltipProvider } from 'ui' import { TimestampInfoProvider } from 'ui-patterns' import { StudioCommandMenu } from '@/components/interfaces/App/CommandMenu' import { StudioCommandProvider as CommandProvider } from '@/components/interfaces/App/CommandMenu/StudioCommandProvider' import { FeaturePreviewContextProvider } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { FeaturePreviewModal } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewModal' import { MonacoThemeProvider } from '@/components/interfaces/App/MonacoThemeProvider' import { RouteValidationWrapper } from '@/components/interfaces/App/RouteValidationWrapper' import { MainScrollContainerProvider } from '@/components/layouts/MainScrollContainerContext' import { BannerStackProvider } from '@/components/ui/BannerStack/BannerStackProvider' import { GlobalErrorBoundaryState } from '@/components/ui/ErrorBoundary/GlobalErrorBoundaryState' import { GlobalShortcuts } from '@/components/ui/GlobalShortcuts/GlobalShortcuts' import { getCLIReleaseVersion } from '@/data/misc/cli-release-version-query' import { useRootQueryClient } from '@/data/query-client' import { customFont, sourceCodePro } from '@/fonts' import { useCustomContent } from '@/hooks/custom-content/useCustomContent' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { AuthProvider } from '@/lib/auth' import { API_URL, BASE_PATH, IS_PLATFORM, useDefaultProvider } from '@/lib/constants' import { TimezoneProvider, useTimezone } from '@/lib/datetime' import { ProfileProvider } from '@/lib/profile' import { Telemetry } from '@/lib/telemetry' import { Toaster } from '@/lib/toaster' import { AiAssistantStateContextProvider } from '@/state/ai-assistant-state' import type { AppPropsWithLayout } from '@/types' dayjs.extend(customParseFormat) dayjs.extend(utc) dayjs.extend(timezone) dayjs.extend(relativeTime) dayjs.extend(duration) // Keep dev-only components out of the production bundle const env = process.env.NEXT_PUBLIC_ENVIRONMENT const IS_DEV_TOOLBAR_ENABLED = env === 'local' || env === 'staging' const ResourceWarningsTab = IS_DEV_TOOLBAR_ENABLED ? dynamic(() => import('@/components/ui/DevToolbar/ResourceWarningsTab').then((m) => m.ResourceWarningsTab) ) : () => null const devToolbarExtraTabs: ExtraTab[] = IS_DEV_TOOLBAR_ENABLED ? [{ id: 'warnings', label: 'Warnings', content: }] : [] const FeatureFlagProviderWithOrgContext = ({ children, ...props }: ComponentProps) => { const { data: selectedOrganization } = useSelectedOrganizationQuery({ enabled: IS_PLATFORM }) const cloudProvider = useDefaultProvider() const getConfigCatFlags = useCallback( (userEmail?: string) => { const customAttributes: Record = {} if (cloudProvider) customAttributes.cloud_provider = cloudProvider if (selectedOrganization?.plan?.id) customAttributes.plan = selectedOrganization.plan.id return getFlags(userEmail, customAttributes) }, [cloudProvider, selectedOrganization?.plan?.id] ) return ( {children} ) } const TimestampInfoTimezoneBridge = ({ children }: { children: React.ReactNode }) => { const { timezone } = useTimezone() return {children} } loader.config({ // [Joshen] Attempt for offline support/bypass ISP issues is to store the assets required for monaco // locally. We're however, only storing the assets which we need (based on what the network tab loads // while using monaco). If we end up facing more effort trying to maintain this, probably to either // use cloudflare or find some way to pull all the files from a CDN via a CLI, rather than tracking individual files // The alternative was to import * as monaco from 'monaco-editor' but i couldn't get it working paths: { vs: IS_PLATFORM ? 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs' : `${BASE_PATH}/monaco-editor`, }, }) // [Joshen TODO] Once we settle on the new nav layout - we'll need a lot of clean up in terms of our layout components // a lot of them are unnecessary and introduce way too many cluttered CSS especially with the height styles that make // debugging way too difficult. Ideal scenario is we just have one AppLayout to control the height and scroll areas of // the dashboard, all other layout components should not be doing that function CustomApp({ Component, pageProps }: AppPropsWithLayout) { const queryClient = useRootQueryClient() const { appTitle } = useCustomContent(['app:title']) const [isCLI, setIsCLI] = useState(false) const getLayout = Component.getLayout ?? ((page) => page) const errorBoundaryHandler = (error: Error, _info: ErrorInfo) => { Sentry.withScope(function (scope) { scope.setTag('globalErrorBoundary', true) const eventId = Sentry.captureException(error) // Attach the Sentry event ID to the error object so it can be accessed by the error boundary if (eventId && error && typeof error === 'object') { ;(error as any).sentryId = eventId } }) console.error(error.stack) } useThemeSandbox() const isTestEnv = process.env.NEXT_PUBLIC_NODE_ENV === 'test' // [Joshen] Should target hosted staging, local dev, and local CLI only const isNonProdEnv = (IS_PLATFORM && process.env.NEXT_PUBLIC_ENVIRONMENT !== 'prod') || isCLI const checkCliEnvironment = async () => { const data = await getCLIReleaseVersion() if (!!data.current) setIsCLI(true) } useEffect(() => { if (!IS_PLATFORM) checkCliEnvironment() }, []) return ( {appTitle ?? 'Briven'} {/* [Alaister]: This has to be an inline style tag here and not a separate component due to next/font */}