| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- 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: <ResourceWarningsTab /> }]
- : []
- const FeatureFlagProviderWithOrgContext = ({
- children,
- ...props
- }: ComponentProps<typeof FeatureFlagProvider>) => {
- const { data: selectedOrganization } = useSelectedOrganizationQuery({ enabled: IS_PLATFORM })
- const cloudProvider = useDefaultProvider()
- const getConfigCatFlags = useCallback(
- (userEmail?: string) => {
- const customAttributes: Record<string, string> = {}
- if (cloudProvider) customAttributes.cloud_provider = cloudProvider
- if (selectedOrganization?.plan?.id) customAttributes.plan = selectedOrganization.plan.id
- return getFlags(userEmail, customAttributes)
- },
- [cloudProvider, selectedOrganization?.plan?.id]
- )
- return (
- <FeatureFlagProvider
- {...props}
- getConfigCatFlags={getConfigCatFlags}
- organizationSlug={selectedOrganization?.slug ?? undefined}
- >
- {children}
- </FeatureFlagProvider>
- )
- }
- const TimestampInfoTimezoneBridge = ({ children }: { children: React.ReactNode }) => {
- const { timezone } = useTimezone()
- return <TimestampInfoProvider timezone={timezone}>{children}</TimestampInfoProvider>
- }
- 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 (
- <QueryClientProvider client={queryClient}>
- <ErrorBoundary FallbackComponent={GlobalErrorBoundaryState} onError={errorBoundaryHandler}>
- <NuqsAdapter>
- <HydrationBoundary state={pageProps.dehydratedState}>
- <AuthProvider>
- <FeatureFlagProviderWithOrgContext API_URL={API_URL} enabled={IS_PLATFORM}>
- <ProfileProvider>
- <TimezoneProvider>
- <TimestampInfoTimezoneBridge>
- <Head>
- <title>{appTitle ?? 'Briven'}</title>
- <meta name="viewport" content="initial-scale=1.0, width=device-width" />
- <meta property="og:image" content={`${BASE_PATH}/img/briven-logo.png`} />
- <meta name="googlebot" content="notranslate" />
- {/* [Alaister]: This has to be an inline style tag here and not a separate component due to next/font */}
- <style
- dangerouslySetInnerHTML={{
- __html: `:root{--font-custom:${customFont.style.fontFamily};--font-source-code-pro:${sourceCodePro.style.fontFamily};}`,
- }}
- />
- {/* Speed up initial API loading times by pre-connecting to the API domain */}
- {IS_PLATFORM && (
- <link
- rel="preconnect"
- href={new URL(API_URL).origin}
- crossOrigin="use-credentials"
- />
- )}
- </Head>
- <MetaFaviconsPagesRouter
- includeManifest
- applicationName="Briven Studio"
- route={isNonProdEnv ? '/favicon/staging' : '/favicon'}
- />
- <TooltipProvider delayDuration={0}>
- <RouteValidationWrapper>
- <ThemeProvider>
- <DevToolbarProvider apiUrl={API_URL}>
- <AiAssistantStateContextProvider>
- <CommandProvider>
- <BannerStackProvider>
- <FeaturePreviewContextProvider>
- <MainScrollContainerProvider>
- {getLayout(<Component {...pageProps} />)}
- </MainScrollContainerProvider>
- <GlobalShortcuts />
- <StudioCommandMenu />
- <FeaturePreviewModal />
- </FeaturePreviewContextProvider>
- </BannerStackProvider>
- <Toaster />
- <MonacoThemeProvider />
- </CommandProvider>
- </AiAssistantStateContextProvider>
- <DevToolbar extraTabs={devToolbarExtraTabs} />
- <DevToolbarTrigger />
- </DevToolbarProvider>
- </ThemeProvider>
- </RouteValidationWrapper>
- </TooltipProvider>
- <Telemetry />
- {!isTestEnv && (
- <ReactQueryDevtools initialIsOpen={false} buttonPosition="bottom-left" />
- )}
- </TimestampInfoTimezoneBridge>
- </TimezoneProvider>
- </ProfileProvider>
- </FeatureFlagProviderWithOrgContext>
- </AuthProvider>
- </HydrationBoundary>
- </NuqsAdapter>
- <TelemetryTagManager />
- </ErrorBoundary>
- </QueryClientProvider>
- )
- }
- export default CustomApp
|