mirror of
https://github.com/supabase/supabase.git
synced 2026-10-16 06:39:09 +03:00
start moving to tanstack router
This commit is contained in:
1 parent
ca1c1cd81a
commit
523ecb9d6e
14 files changed
+834
-907
No files matched your search
@@ -8,11 +8,9 @@
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# react-router
|
||||
/.react-router/
|
||||
|
||||
# production
|
||||
/build
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useQuery, UseQueryOptions } from '@tanstack/react-query'
|
||||
|
||||
import { useIsLoggedIn } from 'common'
|
||||
import { get, handleError } from 'data/fetchers'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import type { Permission, ResponseError } from 'types'
|
||||
import { permissionKeys } from './keys'
|
||||
|
||||
@@ -23,14 +23,14 @@ export const usePermissionsQuery = <TData = PermissionsData>({
|
||||
enabled = true,
|
||||
...options
|
||||
}: UseQueryOptions<PermissionsData, PermissionsError, TData> = {}) => {
|
||||
const { profile } = useProfile()
|
||||
const isSignedIn = useIsLoggedIn()
|
||||
|
||||
return useQuery<PermissionsData, PermissionsError, TData>(
|
||||
permissionKeys.list(),
|
||||
({ signal }) => getPermissions(signal),
|
||||
{
|
||||
...options,
|
||||
enabled: IS_PLATFORM && enabled && profile !== undefined,
|
||||
enabled: IS_PLATFORM && enabled && isSignedIn,
|
||||
staleTime: 30 * 60 * 1000,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Supabase</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Link as RemixLink } from 'react-router'
|
||||
import { Link as TanstackRouterLink } from '@tanstack/react-router'
|
||||
|
||||
export default function Link({
|
||||
children,
|
||||
@@ -11,8 +11,8 @@ export default function Link({
|
||||
passHref?: boolean
|
||||
}) {
|
||||
return (
|
||||
<RemixLink to={href} {...props}>
|
||||
<TanstackRouterLink to={href} {...props}>
|
||||
{children}
|
||||
</RemixLink>
|
||||
</TanstackRouterLink>
|
||||
)
|
||||
}
|
||||
@@ -1,26 +1,17 @@
|
||||
import { useLocation, useParams, useSearchParams, useNavigate } from 'react-router'
|
||||
import { useLocation, useParams, useSearch, useNavigate } from '@tanstack/react-router'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { NextRouter } from 'next/router'
|
||||
import { parse } from 'querystring'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
export function useRouter(): NextRouter {
|
||||
const params = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const params = useParams({ strict: false })
|
||||
const searchParams = useSearch({ strict: false })
|
||||
const location = useLocation()
|
||||
const navigate = useNavigate()
|
||||
|
||||
const query = useMemo(() => {
|
||||
let q: { [key: string]: string | string[] | undefined } = Object.fromEntries(
|
||||
Array.from(new Set(searchParams.keys())).map((key) => {
|
||||
const values = searchParams.getAll(key)
|
||||
return [key, values.length > 1 ? values : values[0]]
|
||||
})
|
||||
)
|
||||
|
||||
q = { ...q, ...params }
|
||||
|
||||
return q
|
||||
return { ...params, ...searchParams }
|
||||
}, [params, searchParams])
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { StrictMode } from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import { RouterProvider, createRouter } from '@tanstack/react-router'
|
||||
import { routeTree } from './routeTree.gen'
|
||||
|
||||
const router = createRouter({ routeTree })
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface Register {
|
||||
router: typeof router
|
||||
}
|
||||
}
|
||||
|
||||
const rootElement = document.getElementById('root')!
|
||||
if (!rootElement.innerHTML) {
|
||||
const root = ReactDOM.createRoot(rootElement)
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<RouterProvider router={router} />
|
||||
</StrictMode>
|
||||
)
|
||||
}
|
||||
@@ -5,9 +5,9 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"dev": "next dev --turbopack -p 8082",
|
||||
"dev": "vite",
|
||||
"dev:secrets:pull": "AWS_PROFILE=supabase-dev node ../../scripts/getSecrets.js -n local/studio",
|
||||
"build": "next build && ./../../scripts/upload-static-assets.sh",
|
||||
"build": "vite build && ./../../scripts/upload-static-assets.sh",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"clean": "rimraf node_modules tsconfig.tsbuildinfo .next .turbo",
|
||||
@@ -18,7 +18,7 @@
|
||||
"test:ci": "vitest --run --coverage",
|
||||
"test:report": "open coverage/lcov-report/index.html",
|
||||
"deploy:staging": "VERCEL_ORG_ID=team_E6KJ1W561hMTjon1QSwOh0WO VERCEL_PROJECT_ID=QmcmhbiAtCMFTAHCuGgQscNbke4TzgWULECctNcKmxWCoT vercel --prod -A .vercel/staging.json",
|
||||
"typecheck": "react-router typegen && tsc --noEmit",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"prettier:check": "prettier --check .",
|
||||
"prettier:write": "prettier --write .",
|
||||
"build:deno-types": "tsx scripts/deno-types.ts"
|
||||
@@ -39,9 +39,7 @@
|
||||
"@heroicons/react": "^2.1.3",
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@next/bundle-analyzer": "15.3.1",
|
||||
"@number-flow/react": "^0.3.2",
|
||||
"@sentry/nextjs": "^8.52.1",
|
||||
"@std/path": "npm:@jsr/std__path@^1.0.8",
|
||||
"@stripe/react-stripe-js": "^3.1.1",
|
||||
"@stripe/stripe-js": "^5.5.0",
|
||||
@@ -53,9 +51,10 @@
|
||||
"@supabase/supabase-js": "catalog:",
|
||||
"@tanstack/react-query": "4.35.7",
|
||||
"@tanstack/react-query-devtools": "4.35.7",
|
||||
"@tanstack/react-router": "^1.114.27",
|
||||
"@tanstack/react-router-devtools": "^1.120.11",
|
||||
"@uidotdev/usehooks": "^2.4.1",
|
||||
"@vercel/flags": "^2.6.0",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@zip.js/zip.js": "^2.7.29",
|
||||
"ai": "^3.4.33",
|
||||
"ai-commands": "workspace:*",
|
||||
@@ -133,10 +132,11 @@
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
||||
"@radix-ui/react-use-escape-keydown": "^1.0.3",
|
||||
"@react-router/dev": "^7.1.1",
|
||||
"@supabase/postgres-meta": "^0.64.4",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tanstack/router-plugin": "^1.120.11",
|
||||
"@testing-library/dom": "^10.0.0",
|
||||
"@testing-library/jest-dom": "^6.6.0",
|
||||
"@testing-library/react": "^16.0.0",
|
||||
@@ -164,6 +164,7 @@
|
||||
"@types/sqlstring": "^2.3.0",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/zxcvbn": "^4.4.1",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@vitest/coverage-v8": "^3.0.9",
|
||||
"@vitest/ui": "^3.0.0",
|
||||
"api-types": "workspace:*",
|
||||
@@ -181,10 +182,13 @@
|
||||
"prettier": "3.2.4",
|
||||
"raw-loader": "^4.0.2",
|
||||
"require-in-the-middle": "^7.5.2",
|
||||
"rollup-plugin-node-polyfills": "^0.2.1",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"tsx": "^4.19.3",
|
||||
"typescript": "~5.5.0",
|
||||
"vite": "^6.2.6",
|
||||
"vite": "^6.3.5",
|
||||
"vite-plugin-circular-dependency": "^0.5.0",
|
||||
"vite-plugin-cjs-interop": "^2.2.0",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"vitest": "^3.0.5"
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import type { Config } from '@react-router/dev/config'
|
||||
|
||||
export default {
|
||||
basename: process.env.NEXT_PUBLIC_BASE_PATH ?? '/',
|
||||
ssr: false,
|
||||
} satisfies Config
|
||||
@@ -0,0 +1,88 @@
|
||||
/* eslint-disable */
|
||||
|
||||
// @ts-nocheck
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
// This file was automatically generated by TanStack Router.
|
||||
// You should NOT make any changes in this file as it will be overwritten.
|
||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||
|
||||
// Import Routes
|
||||
|
||||
import { Route as rootRoute } from './routes/__root'
|
||||
import { Route as IndexImport } from './routes/index'
|
||||
|
||||
// Create/Update Routes
|
||||
|
||||
const IndexRoute = IndexImport.update({
|
||||
id: '/',
|
||||
path: '/',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
// Populate the FileRoutesByPath interface
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface FileRoutesByPath {
|
||||
'/': {
|
||||
id: '/'
|
||||
path: '/'
|
||||
fullPath: '/'
|
||||
preLoaderRoute: typeof IndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create and export the route tree
|
||||
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesById {
|
||||
__root__: typeof rootRoute
|
||||
'/': typeof IndexRoute
|
||||
}
|
||||
|
||||
export interface FileRouteTypes {
|
||||
fileRoutesByFullPath: FileRoutesByFullPath
|
||||
fullPaths: '/'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to: '/'
|
||||
id: '__root__' | '/'
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
|
||||
export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
}
|
||||
|
||||
const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
}
|
||||
|
||||
export const routeTree = rootRoute
|
||||
._addFileChildren(rootRouteChildren)
|
||||
._addFileTypes<FileRouteTypes>()
|
||||
|
||||
/* ROUTE_MANIFEST_START
|
||||
{
|
||||
"routes": {
|
||||
"__root__": {
|
||||
"filePath": "__root.tsx",
|
||||
"children": [
|
||||
"/"
|
||||
]
|
||||
},
|
||||
"/": {
|
||||
"filePath": "index.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
ROUTE_MANIFEST_END */
|
||||
@@ -0,0 +1,161 @@
|
||||
import { createRootRoute, Outlet } from '@tanstack/react-router'
|
||||
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
|
||||
import 'react-data-grid/lib/styles.css'
|
||||
import 'styles/code.scss'
|
||||
import 'styles/contextMenu.scss'
|
||||
import 'styles/date-picker.scss'
|
||||
import 'styles/editor.scss'
|
||||
import 'styles/graphiql-base.scss'
|
||||
import 'styles/grid.scss'
|
||||
import 'styles/main.scss'
|
||||
import 'styles/markdown-preview.scss'
|
||||
import 'styles/monaco.scss'
|
||||
import 'styles/react-data-grid-logs.scss'
|
||||
import 'styles/reactflow.scss'
|
||||
import 'styles/storage.scss'
|
||||
import 'styles/stripe.scss'
|
||||
import 'styles/toast.scss'
|
||||
import 'styles/ui.scss'
|
||||
import 'ui/build/css/themes/dark.css'
|
||||
import 'ui/build/css/themes/light.css'
|
||||
|
||||
import { loader } from '@monaco-editor/react'
|
||||
import * as Sentry from '@sentry/nextjs'
|
||||
import { Hydrate, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
||||
import dayjs from 'dayjs'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import timezone from 'dayjs/plugin/timezone'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
import Head from 'next/head'
|
||||
import { NuqsAdapter } from 'nuqs/adapters/next/pages'
|
||||
import { ErrorInfo } from 'react'
|
||||
import { ErrorBoundary } from 'react-error-boundary'
|
||||
|
||||
import { FeatureFlagProvider, ThemeProvider, useThemeSandbox } from 'common'
|
||||
import MetaFaviconsPagesRouter from 'common/MetaFavicons/pages-router'
|
||||
import { RouteValidationWrapper } from 'components/interfaces/App'
|
||||
import { AppBannerContextProvider } from 'components/interfaces/App/AppBannerWrapperContext'
|
||||
import { StudioCommandMenu } from 'components/interfaces/App/CommandMenu'
|
||||
import { FeaturePreviewContextProvider } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import FeaturePreviewModal from 'components/interfaces/App/FeaturePreview/FeaturePreviewModal'
|
||||
import { MonacoThemeProvider } from 'components/interfaces/App/MonacoThemeProvider'
|
||||
import { GenerateSql } from 'components/interfaces/SqlGenerator/SqlGenerator'
|
||||
import { ErrorBoundaryState } from 'components/ui/ErrorBoundaryState'
|
||||
import { useRootQueryClient } from 'data/query-client'
|
||||
// import { customFont, sourceCodePro } from 'fonts'
|
||||
import { AuthProvider } from 'lib/auth'
|
||||
import { getFlags as getConfigCatFlags } from 'lib/configcat'
|
||||
import { API_URL, BASE_PATH, IS_PLATFORM } from 'lib/constants'
|
||||
import { ProfileProvider } from 'lib/profile'
|
||||
import { Telemetry } from 'lib/telemetry'
|
||||
import HCaptchaLoadedStore from 'stores/hcaptcha-loaded-store'
|
||||
import { AppPropsWithLayout } from 'types'
|
||||
import { SonnerToaster, TooltipProvider } from 'ui'
|
||||
import { CommandProvider } from 'ui-patterns/CommandMenu'
|
||||
|
||||
dayjs.extend(customParseFormat)
|
||||
dayjs.extend(utc)
|
||||
dayjs.extend(timezone)
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
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() {
|
||||
const queryClient = useRootQueryClient()
|
||||
|
||||
const errorBoundaryHandler = (error: Error, info: ErrorInfo) => {
|
||||
Sentry.withScope(function (scope) {
|
||||
scope.setTag('globalErrorBoundary', true)
|
||||
Sentry.captureException(error)
|
||||
})
|
||||
|
||||
console.error(error.stack)
|
||||
}
|
||||
|
||||
useThemeSandbox()
|
||||
|
||||
const isTestEnv = process.env.NEXT_PUBLIC_NODE_ENV === 'test'
|
||||
|
||||
return (
|
||||
<ErrorBoundary FallbackComponent={ErrorBoundaryState} onError={errorBoundaryHandler}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<NuqsAdapter>
|
||||
<AuthProvider>
|
||||
<FeatureFlagProvider
|
||||
API_URL={API_URL}
|
||||
enabled={IS_PLATFORM}
|
||||
getConfigCatFlags={getConfigCatFlags}
|
||||
>
|
||||
<ProfileProvider>
|
||||
<Head>
|
||||
<title>Supabase</title>
|
||||
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
|
||||
{/* [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};}`,
|
||||
}}
|
||||
/> */}
|
||||
</Head>
|
||||
<MetaFaviconsPagesRouter applicationName="Supabase Studio" />
|
||||
<TooltipProvider delayDuration={0}>
|
||||
<RouteValidationWrapper>
|
||||
<ThemeProvider
|
||||
defaultTheme="system"
|
||||
themes={['dark', 'light', 'classic-dark']}
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<AppBannerContextProvider>
|
||||
<CommandProvider>
|
||||
<FeaturePreviewContextProvider>
|
||||
<Outlet />
|
||||
<StudioCommandMenu />
|
||||
<GenerateSql />
|
||||
<FeaturePreviewModal />
|
||||
</FeaturePreviewContextProvider>
|
||||
<SonnerToaster position="top-right" />
|
||||
<MonacoThemeProvider />
|
||||
</CommandProvider>
|
||||
</AppBannerContextProvider>
|
||||
</ThemeProvider>
|
||||
</RouteValidationWrapper>
|
||||
</TooltipProvider>
|
||||
<Telemetry />
|
||||
{!isTestEnv && (
|
||||
<>
|
||||
<HCaptchaLoadedStore />
|
||||
<TanStackRouterDevtools />
|
||||
<ReactQueryDevtools initialIsOpen={false} position="bottom-right" />
|
||||
</>
|
||||
)}
|
||||
</ProfileProvider>
|
||||
</FeatureFlagProvider>
|
||||
</AuthProvider>
|
||||
</NuqsAdapter>
|
||||
</QueryClientProvider>
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
export const Route = createRootRoute({
|
||||
component: CustomApp,
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createFileRoute('/')({
|
||||
component: Index,
|
||||
})
|
||||
|
||||
function Index() {
|
||||
return (
|
||||
<div className="p-2">
|
||||
<h3>Welcome Home!</h3>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"rootDirs": [".", "./.react-router/types"],
|
||||
"rootDirs": ["."],
|
||||
"baseUrl": ".",
|
||||
"downlevelIteration": true,
|
||||
"incremental": true,
|
||||
@@ -23,13 +23,6 @@
|
||||
"useDefineForClassFields": true,
|
||||
"types": ["node", "vite/client"]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.js",
|
||||
"**/*.jsx",
|
||||
"./../../packages/ui/src/**/*.d.ts",
|
||||
".react-router/types/**/*"
|
||||
],
|
||||
"include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "./../../packages/ui/src/**/*.d.ts"],
|
||||
"exclude": ["node_modules", "public/deno/*.ts"]
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill'
|
||||
import { reactRouter } from '@react-router/dev/vite'
|
||||
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import path from 'path'
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import circleDependency from 'vite-plugin-circular-dependency'
|
||||
@@ -70,7 +71,13 @@ export default defineConfig(({ mode }) => {
|
||||
'react-copy-to-clipboard',
|
||||
],
|
||||
}),
|
||||
reactRouter(),
|
||||
TanStackRouterVite({
|
||||
target: 'react',
|
||||
autoCodeSplitting: true,
|
||||
routesDirectory: './routes',
|
||||
generatedRouteTree: './routeTree.gen.ts',
|
||||
}),
|
||||
react(),
|
||||
],
|
||||
optimizeDeps: {
|
||||
esbuildOptions: {
|
||||
|
||||
Generated
+504
-860
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user