mirror of
https://github.com/supabase/supabase.git
synced 2026-10-17 23:29:08 +03:00
Merge branch 'master' into chore/user-management-v2-part-3
This commit is contained in:
commit
7d17e73bd3
122 files changed
+6939
-740
No files matched your search
@@ -163,7 +163,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i
|
||||
<td>Kotlin</td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt" target="_blank" rel="noopener noreferrer">supabase-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt/tree/master/Postgrest" target="_blank" rel="noopener noreferrer">postgrest-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt/tree/master/GoTrue" target="_blank" rel="noopener noreferrer">gotrue-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt/tree/master/Auth" target="_blank" rel="noopener noreferrer">auth-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt/tree/master/Realtime" target="_blank" rel="noopener noreferrer">realtime-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt/tree/master/Storage" target="_blank" rel="noopener noreferrer">storage-kt</a></td>
|
||||
<td><a href="https://github.com/supabase-community/supabase-kt/tree/master/Functions" target="_blank" rel="noopener noreferrer">functions-kt</a></td>
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { DialogProps } from '@radix-ui/react-alert-dialog'
|
||||
import { CircleIcon, LaptopIcon, MoonIcon, SunIcon } from 'lucide-react'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import * as React from 'react'
|
||||
|
||||
import { docsConfig } from '@/config/docs'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button } from 'ui'
|
||||
import {
|
||||
Button,
|
||||
CommandDialog,
|
||||
CommandEmpty_Shadcn_,
|
||||
CommandGroup_Shadcn_,
|
||||
@@ -17,6 +16,7 @@ import {
|
||||
CommandItem_Shadcn_,
|
||||
CommandList_Shadcn_,
|
||||
CommandSeparator_Shadcn_,
|
||||
DialogProps,
|
||||
} from 'ui'
|
||||
|
||||
export function CommandMenu({ ...props }: DialogProps) {
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import { DropdownMenuTriggerProps } from '@radix-ui/react-dropdown-menu'
|
||||
|
||||
// import { NpmCommands } from 'types/unist'
|
||||
|
||||
// import { Event, trackEvent } from '@/lib/events'
|
||||
import { cn } from 'ui'
|
||||
import { Button } from 'ui'
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from 'ui'
|
||||
import { Check, Copy } from 'lucide-react'
|
||||
import {
|
||||
Button,
|
||||
cn,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuTriggerProps,
|
||||
} from 'ui'
|
||||
|
||||
interface CopyButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
value: string
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import * as React from 'react'
|
||||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { cn as uiCN } from 'ui'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
export const cn = uiCN
|
||||
|
||||
export function formatDate(input: string | number): string {
|
||||
const date = new Date(input)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"typecheck": "contentlayer2 build && tsc --noEmit -p tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@radix-ui/react-alert-dialog": "^1.0.5",
|
||||
"contentlayer2": "0.4.6",
|
||||
"eslint-config-supabase": "*",
|
||||
@@ -23,20 +24,26 @@
|
||||
"markdown-wasm": "^1.2.0",
|
||||
"next": "^14.2.10",
|
||||
"next-contentlayer2": "0.4.6",
|
||||
"next-themes": "^0.3.0",
|
||||
"react": "^18.2.0",
|
||||
"react-docgen": "^7.0.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-inlinesvg": "^4.0.4",
|
||||
"react-wrap-balancer": "^1.1.0",
|
||||
"recharts": "^2.12.7",
|
||||
"rehype-autolink-headings": "^7.1.0",
|
||||
"rehype-pretty-code": "^0.6.0",
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark": "^14.0.3",
|
||||
"remark-code-import": "^1.2.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"sonner": "^1.5.0",
|
||||
"ts-morph": "^22.0.0",
|
||||
"ui": "*",
|
||||
"unist-util-visit": "^5.0.0"
|
||||
"ui-patterns": "*",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@shikijs/compat": "^1.1.7",
|
||||
@@ -52,7 +59,7 @@
|
||||
"shiki": "^1.1.7",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"tsconfig": "*",
|
||||
"typescript": "^5.5.0",
|
||||
"typescript": "~5.5.0",
|
||||
"unist-builder": "3.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import { DropdownMenuCheckboxItemProps } from '@radix-ui/react-dropdown-menu'
|
||||
|
||||
import { Button } from 'ui'
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuCheckboxItemProps,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { REGEXP_ONLY_DIGITS_AND_CHARS } from 'input-otp'
|
||||
|
||||
import { InputOTP, InputOTPGroup, InputOTPSlot } from 'ui'
|
||||
import { InputOTP, InputOTPGroup, InputOTPSlot, REGEXP_ONLY_DIGITS_AND_CHARS } from 'ui'
|
||||
|
||||
export default function InputOTPPattern() {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { TreeView, TreeViewItem } from 'ui'
|
||||
import { flattenTree } from 'react-accessible-treeview'
|
||||
import { TreeView, TreeViewItem, flattenTree } from 'ui'
|
||||
|
||||
export default function TreeViewDemo() {
|
||||
const data = {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { TreeView, TreeViewItem } from 'ui'
|
||||
import { flattenTree } from 'react-accessible-treeview'
|
||||
import { TreeView, TreeViewItem, flattenTree } from 'ui'
|
||||
|
||||
export default function TreeViewDemo() {
|
||||
const data = {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useState } from 'react'
|
||||
import { TreeView, TreeViewItem } from 'ui'
|
||||
import { flattenTree } from 'react-accessible-treeview'
|
||||
import {
|
||||
ContextMenu_Shadcn_,
|
||||
ContextMenuContent_Shadcn_,
|
||||
ContextMenuItem_Shadcn_,
|
||||
ContextMenuSeparator_Shadcn_,
|
||||
ContextMenuTrigger_Shadcn_,
|
||||
flattenTree,
|
||||
TreeView,
|
||||
TreeViewItem,
|
||||
} from 'ui'
|
||||
|
||||
const data = {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { useState } from 'react'
|
||||
import { TreeView, TreeViewItem } from 'ui'
|
||||
import { flattenTree } from 'react-accessible-treeview'
|
||||
import {
|
||||
ContextMenu_Shadcn_,
|
||||
ContextMenuContent_Shadcn_,
|
||||
ContextMenuItem_Shadcn_,
|
||||
ContextMenuSeparator_Shadcn_,
|
||||
ContextMenuTrigger_Shadcn_,
|
||||
flattenTree,
|
||||
TreeView,
|
||||
TreeViewItem,
|
||||
} from 'ui'
|
||||
|
||||
const data = {
|
||||
|
||||
@@ -1188,7 +1188,7 @@ export const functions: NavMenuConstant = {
|
||||
},
|
||||
{
|
||||
name: 'Integrating with Log Drains',
|
||||
url: '/guides/functions/log-drains',
|
||||
url: '/guides/platform/log-drains',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -2260,6 +2260,17 @@ export const reference_kotlin_v2 = {
|
||||
},
|
||||
}
|
||||
|
||||
export const reference_kotlin_v3 = {
|
||||
icon: 'reference-kotlin',
|
||||
title: 'kotlin',
|
||||
url: 'guides/reference/kotlin',
|
||||
parent: '/reference',
|
||||
pkg: {
|
||||
name: '@supabase-community/supabase-kt',
|
||||
repo: 'https://github.com/supabase-community/supabase-kt',
|
||||
},
|
||||
}
|
||||
|
||||
export const reference_cli = {
|
||||
icon: 'reference-cli',
|
||||
title: 'Supabase CLI',
|
||||
@@ -2352,7 +2363,7 @@ export const references = [
|
||||
},
|
||||
{
|
||||
label: 'supabase-kt',
|
||||
versions: ['v2', 'v1'],
|
||||
versions: ['v3', 'v2', 'v1'],
|
||||
description: 'something about the reference',
|
||||
icon: '/docs/img/icons/kotlin-icon.svg',
|
||||
url: '/reference/kotlin/start',
|
||||
|
||||
@@ -30,6 +30,7 @@ enum MenuId {
|
||||
RefSwiftV2 = 'reference_swift_v2',
|
||||
RefKotlinV1 = 'reference_kotlin_v1',
|
||||
RefKotlinV2 = 'reference_kotlin_v2',
|
||||
RefKotlinV3 = 'reference_kotlin_v3',
|
||||
RefCli = 'reference_cli',
|
||||
RefApi = 'reference_api',
|
||||
SelfHostingAuth = 'reference_self_hosting_auth',
|
||||
@@ -166,6 +167,11 @@ const menus: Menu[] = [
|
||||
{
|
||||
id: MenuId.RefKotlinV2,
|
||||
type: 'reference',
|
||||
path: '/reference/kotlin/v2',
|
||||
},
|
||||
{
|
||||
id: MenuId.RefKotlinV3,
|
||||
type: 'reference',
|
||||
path: '/reference/kotlin',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
// Basic UI things
|
||||
import Link from 'next/link'
|
||||
import { Accordion, Admonition, Alert, Button, CodeBlock, Image, markdownComponents } from 'ui'
|
||||
import { Accordion, Alert, Button, CodeBlock, Image, markdownComponents } from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import { GlassPanel } from 'ui-patterns/GlassPanel'
|
||||
import { IconPanel } from 'ui-patterns/IconPanel'
|
||||
import { TabPanel, Tabs } from '~/features/ui/Tabs'
|
||||
|
||||
@@ -162,6 +162,14 @@ You'll notice that this token is quite a bit longer, since it contains informati
|
||||
}
|
||||
```
|
||||
|
||||
If using the service role key, you'll need to pass it into both the `apikey` and `authorization` headers (again, only do this from a secure environment such as your own server):
|
||||
|
||||
```bash
|
||||
curl "$YOUR_PROJECT_URL/rest/v1/colors?select=name" \
|
||||
-H "apikey: $YOUR_SERVICE_ROLE_KEY" \
|
||||
-H "authorization: Bearer $YOUR_SERVICE_ROLE_KEY"
|
||||
```
|
||||
|
||||
Now that you understand what JWTs are and where they're used in Supabase, you can explore how to use them in combination with Row Level Security to start restricting access to certain tables, rows, and columns in your Postgres database.
|
||||
|
||||
## Resources
|
||||
|
||||
@@ -80,7 +80,7 @@ In the `build.gradle` (app) file, add these dependencies then press "Sync now."
|
||||
```kotlin
|
||||
implementation "io.github.jan-tennert.supabase:postgrest-kt:$supabase_version"
|
||||
implementation "io.github.jan-tennert.supabase:storage-kt:$supabase_version"
|
||||
implementation "io.github.jan-tennert.supabase:gotrue-kt:$supabase_version"
|
||||
implementation "io.github.jan-tennert.supabase:auth-kt:$supabase_version"
|
||||
implementation "io.ktor:ktor-client-android:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-core:$ktor_version"
|
||||
implementation "io.ktor:ktor-utils:$ktor_version"
|
||||
|
||||
@@ -65,6 +65,12 @@ Exchange the authorization code for an access and refresh token by calling [`POS
|
||||
- `redirect_uri`: This must be exactly the same URL used in the first step.
|
||||
- (Recommended) `code_verifier`: If you used the PKCE flow in the first step, include the code verifier as `code_verifier`.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
If your application need to support dynamically generated Redirect URLs, check out [Handling Dynamic Redirect URLs](#handling-dynamic-redirect-urls) section below.
|
||||
|
||||
</Admonition>
|
||||
|
||||
As per OAuth2 spec, provide the client id and client secret as basic auth header:
|
||||
|
||||
- `client_id`: The unique client ID identifying your OAuth App.
|
||||
@@ -151,6 +157,11 @@ When creating a new project, you can either ask the user to provide a database p
|
||||
|
||||
You can configure the user's [custom SMTP settings](https://supabase.com/docs/guides/auth/auth-smtp) using the [`/config/auth` endpoint](https://api.supabase.com/api/v1#/projects%20config/updateV1AuthConfig).
|
||||
|
||||
### Handling Dynamic Redirect URLs
|
||||
|
||||
To handle multiple, dynamically generated redirect URLs within the same OAuth app, you can leverage the `state` query parameter. When starting the OAuth process, include the desired, encoded redirect URL in the `state` parameter.
|
||||
Once authorization is complete, we will sends the `state` value back to your app. You can then verify its integrity and extract the correct redirect URL, decoding it and redirecting the user to the correct URL.
|
||||
|
||||
## Current limitations
|
||||
|
||||
Only some features are available until we roll out fine-grained access control. If you need full database access, you will need to prompt the user for their database password.
|
||||
@@ -213,13 +213,17 @@ let data = try await supabase.storage.from("bucket")
|
||||
|
||||
```kotlin
|
||||
val data = supabase.storage.from("bucket").downloadAuthenticated("image.jpg") {
|
||||
size(800, 300)
|
||||
transform {
|
||||
size(800, 300)
|
||||
}
|
||||
}
|
||||
|
||||
//Or on JVM stream directly to a file
|
||||
val file = File("image.jpg")
|
||||
supabase.storage.from("bucket").downloadAuthenticatedTo("image.jpg", file) {
|
||||
size(800, 300)
|
||||
transform {
|
||||
size(800, 300)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -308,15 +312,19 @@ let data = try await supabase.storage.from("bucket")
|
||||
|
||||
```kotlin
|
||||
val data = supabase.storage.from("bucket").downloadAuthenticated("image.jpg") {
|
||||
size(200, 200)
|
||||
format = "origin"
|
||||
transform {
|
||||
size(200, 200)
|
||||
format = ImageTransformation.Format.ORIGIN
|
||||
}
|
||||
}
|
||||
|
||||
//Or on JVM stream directly to a file
|
||||
val file = File("image.jpg")
|
||||
supabase.storage.from("bucket").downloadAuthenticatedTo("image.jpg", file) {
|
||||
size(200, 200)
|
||||
format = "origin"
|
||||
transform {
|
||||
size(200, 200)
|
||||
format = ImageTransformation.Format.ORIGIN
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -431,13 +439,17 @@ let data = try await supabase.storage.from("bucket")
|
||||
|
||||
```kotlin
|
||||
val data = supabase.storage["bucket"].downloadAuthenticated("image.jpg") {
|
||||
quality = 50
|
||||
transform {
|
||||
quality = 50
|
||||
}
|
||||
}
|
||||
|
||||
//Or on JVM stream directly to a file
|
||||
val file = File("image.jpg")
|
||||
supabase.storage["bucket"].downloadAuthenticatedTo("image.jpg", file) {
|
||||
quality = 50
|
||||
transform {
|
||||
quality = 50
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -529,15 +541,19 @@ let data = try await supabase.storage.from("bucket")
|
||||
|
||||
```kotlin
|
||||
val data = supabase.storage.from("bucket").downloadAuthenticated("image.jpg") {
|
||||
size(800, 300)
|
||||
resize = ImageTransformation.Resize.CONTAIN
|
||||
transform {
|
||||
size(800, 300)
|
||||
resize = ImageTransformation.Resize.CONTAIN
|
||||
}
|
||||
}
|
||||
|
||||
//Or on JVM stream directly to a file
|
||||
val file = File("image.jpg")
|
||||
supabase.storage.from("bucket").downloadAuthenticatedTo("image.jpg", file) {
|
||||
size(800, 300)
|
||||
resize = ImageTransformation.Resize.CONTAIN
|
||||
transform {
|
||||
size(800, 300)
|
||||
resize = ImageTransformation.Resize.CONTAIN
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -70,18 +70,10 @@ try await supabase.storage.from("bucket_name").upload(path: "file_path", file: f
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
install(Storage)
|
||||
}
|
||||
|
||||
suspend fun uploadData(bytes: ByteArray) {
|
||||
supabase.storage.from("bucket_name").upload("file_path", bytes)
|
||||
}
|
||||
supabase.storage.from("bucket_name").upload("file_path", bytes)
|
||||
|
||||
//Or on JVM/Android: (This will stream the data from the file to supabase)
|
||||
suspend fun uploadFile(file: File) {
|
||||
supabase.storage.from("bucket_name").upload("file_path", file)
|
||||
}
|
||||
supabase.storage.from("bucket_name").upload("file_path", file)
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -147,6 +139,15 @@ try await supabase.storage.from("bucket_name")
|
||||
)
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.storage.from("bucket_name").upload("file_path", bytes) {
|
||||
upsert = true
|
||||
}
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="python" label="Python">
|
||||
|
||||
@@ -214,6 +215,15 @@ try await supabase.storage.from("bucket_name")
|
||||
)
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.storage.from("bucket_name").upload("file_path", bytes) {
|
||||
contentType = ContentType.Image.JPEG
|
||||
}
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="python" label="Python">
|
||||
|
||||
|
||||
@@ -77,9 +77,13 @@ export const REFERENCES = {
|
||||
name: 'Kotlin',
|
||||
library: 'supabase-kt',
|
||||
libPath: 'kotlin',
|
||||
versions: ['v2', 'v1'],
|
||||
versions: ['v3', 'v2', 'v1'],
|
||||
icon: 'reference-kotlin',
|
||||
meta: {
|
||||
v3: {
|
||||
libId: 'reference_kotlin_v3',
|
||||
specFile: 'supabase_kt_v3',
|
||||
},
|
||||
v2: {
|
||||
libId: 'reference_kotlin_v2',
|
||||
specFile: 'supabase_kt_v2',
|
||||
|
||||
@@ -21,13 +21,15 @@ custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supab
|
||||
Add dependency to your build file using the BOM.
|
||||
|
||||
The available modules are:
|
||||
- [**gotrue-kt**](https://github.com/supabase-community/supabase-kt/tree/master/GoTrue)
|
||||
- [**auth-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Auth)
|
||||
- [**realtime-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Realtime)
|
||||
- [**storage-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Storage)
|
||||
- [**functions-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Functions)
|
||||
- [**postgrest-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Postgrest)
|
||||
- Other plugins also available [here](https://github.com/supabase-community/supabase-kt/tree/master/plugins)
|
||||
|
||||
Checkout the different READMEs for information about supported Kotlin targets.
|
||||
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
<Tabs
|
||||
@@ -41,7 +43,7 @@ custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supab
|
||||
```kotlin
|
||||
implementation(platform("io.github.jan-tennert.supabase:bom:VERSION"))
|
||||
implementation("io.github.jan-tennert.supabase:postgrest-kt")
|
||||
implementation("io.github.jan-tennert.supabase:gotrue-kt")
|
||||
implementation("io.github.jan-tennert.supabase:auth-kt")
|
||||
implementation("io.github.jan-tennert.supabase:realtime-kt")
|
||||
```
|
||||
|
||||
@@ -51,7 +53,7 @@ custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supab
|
||||
```groovy
|
||||
implementation platform("io.github.jan-tennert.supabase:bom:VERSION")
|
||||
implementation 'io.github.jan-tennert.supabase:postgrest-kt'
|
||||
implementation 'io.github.jan-tennert.supabase:gotrue-kt'
|
||||
implementation 'io.github.jan-tennert.supabase:auth-kt'
|
||||
implementation 'io.github.jan-tennert.supabase:realtime-kt'
|
||||
```
|
||||
|
||||
@@ -72,7 +74,7 @@ custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supab
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.jan-tennert.supabase</groupId>
|
||||
<artifactId>gotrue-kt</artifactId>
|
||||
<artifactId>auth-kt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.jan-tennert.supabase</groupId>
|
||||
@@ -92,7 +94,8 @@ custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supab
|
||||
<RefSubLayout.Details>
|
||||
|
||||
You can find a list of engines [here](https://ktor.io/docs/http-client-engines.html)
|
||||
Note that not all Ktor engines support Websockets. So if you plan to use the Realtime module, make sure to use an engine that supports Websockets. Checkout the [engine limitations](https://ktor.io/docs/client-engines.html#limitations) for more information.
|
||||
- Note that not all Ktor engines support Websockets. So if you plan to use the Realtime module, make sure to use an engine that supports Websockets. Checkout the [engine limitations](https://ktor.io/docs/client-engines.html#limitations) for more information.
|
||||
- If using `supabase-kt` 3.0.0 and above, you need to use Ktor version 3.0.0-rc-1 or later.
|
||||
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
|
||||
@@ -2,7 +2,7 @@ This reference documents every object and method available in Supabase's Kotlin
|
||||
|
||||
To see supported Kotlin targets, check the corresponding module README on [GitHub](https://github.com/supabase-community/supabase-kt).
|
||||
|
||||
To migrate from version 1.4.X to 2.0.0, see the [migration guide](https://github.com/supabase-community/supabase-kt/blob/master/MIGRATION.md)
|
||||
To migrate from version 2.X to 3.0.0, see the [migration guide](https://github.com/supabase-community/supabase-kt/blob/master/MIGRATION.md)
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
---
|
||||
id: installing
|
||||
title: 'Installing & Initialization'
|
||||
slug: installing
|
||||
custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supabase.yml
|
||||
---
|
||||
|
||||
### Add one or more modules to your project
|
||||
|
||||
<RefSubLayout.EducationRow>
|
||||
<RefSubLayout.Details>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
|
||||
<a href="https://github.com/supabase-community/supabase-kt/releases" style={{ marginRight: '8px' }}>
|
||||
<img src="https://img.shields.io/github/release/supabase-community/supabase-kt?label=stable" alt="latest stable supabase-kt version"/>
|
||||
</a>
|
||||
<a href="https://github.com/supabase-community/supabase-kt/releases">
|
||||
<img src="https://img.shields.io/maven-central/v/io.github.jan-tennert.supabase/supabase-kt?label=experimental" alt="latest supabase-kt version"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Add dependency to your build file using the BOM.
|
||||
|
||||
The available modules are:
|
||||
- [**gotrue-kt**](https://github.com/supabase-community/supabase-kt/tree/master/GoTrue)
|
||||
- [**realtime-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Realtime)
|
||||
- [**storage-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Storage)
|
||||
- [**functions-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Functions)
|
||||
- [**postgrest-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Postgrest)
|
||||
- Other plugins also available [here](https://github.com/supabase-community/supabase-kt/tree/master/plugins)
|
||||
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
<Tabs
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="kotlin"
|
||||
queryGroup="build-file"
|
||||
>
|
||||
<TabPanel id="kotlin" label="build.gradle.kts">
|
||||
|
||||
```kotlin
|
||||
implementation(platform("io.github.jan-tennert.supabase:bom:VERSION"))
|
||||
implementation("io.github.jan-tennert.supabase:postgrest-kt")
|
||||
implementation("io.github.jan-tennert.supabase:gotrue-kt")
|
||||
implementation("io.github.jan-tennert.supabase:realtime-kt")
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="groovy" label="build.gradle">
|
||||
|
||||
```groovy
|
||||
implementation platform("io.github.jan-tennert.supabase:bom:VERSION")
|
||||
implementation 'io.github.jan-tennert.supabase:postgrest-kt'
|
||||
implementation 'io.github.jan-tennert.supabase:gotrue-kt'
|
||||
implementation 'io.github.jan-tennert.supabase:realtime-kt'
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="xml" label="pom.xml">
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.github.jan-tennert.supabase</groupId>
|
||||
<artifactId>bom</artifactId>
|
||||
<version>VERSION</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.jan-tennert.supabase</groupId>
|
||||
<artifactId>postgrest-kt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.jan-tennert.supabase</groupId>
|
||||
<artifactId>gotrue-kt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.jan-tennert.supabase</groupId>
|
||||
<artifactId>realtime-kt</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</RefSubLayout.Examples>
|
||||
|
||||
</RefSubLayout.EducationRow>
|
||||
|
||||
### Add Ktor Client Engine to each of your Kotlin targets (required)
|
||||
|
||||
<RefSubLayout.EducationRow>
|
||||
<RefSubLayout.Details>
|
||||
|
||||
You can find a list of engines [here](https://ktor.io/docs/http-client-engines.html)
|
||||
Note that not all Ktor engines support Websockets. So if you plan to use the Realtime module, make sure to use an engine that supports Websockets. Checkout the [engine limitations](https://ktor.io/docs/client-engines.html#limitations) for more information.
|
||||
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
<Tabs
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="kotlin"
|
||||
queryGroup="build-file"
|
||||
>
|
||||
<TabPanel id="kotlin" label="build.gradle.kts">
|
||||
|
||||
```kotlin
|
||||
implementation("io.ktor:ktor-client-[engine]:KTOR_VERSION")
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="groovy" label="build.gradle">
|
||||
|
||||
```groovy
|
||||
implementation 'io.ktor:ktor-client-[engine]:KTOR_VERSION'
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="xml" label="pom.xml">
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.ktor</groupId>
|
||||
<artifactId>ktor-client-[engine]</artifactId>
|
||||
<version>KTOR_VERSION</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
</RefSubLayout.Examples>
|
||||
|
||||
<RefSubLayout.Details>
|
||||
|
||||
Multiplatform example:
|
||||
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
|
||||
<Tabs
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="kotlin"
|
||||
queryGroup="build-file"
|
||||
>
|
||||
<TabPanel id="kotlin" label="build.gradle.kts">
|
||||
|
||||
```kotlin
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
//supabase modules
|
||||
}
|
||||
}
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
implementation("io.ktor:ktor-client-cio:KTOR_VERSION")
|
||||
}
|
||||
}
|
||||
val androidMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
}
|
||||
val jsMain by getting {
|
||||
dependencies {
|
||||
implementation("io.ktor:ktor-client-js:KTOR_VERSION")
|
||||
}
|
||||
}
|
||||
val iosMain by getting {
|
||||
dependencies {
|
||||
implementation("io.ktor:ktor-client-darwin:KTOR_VERSION")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
</RefSubLayout.Examples>
|
||||
|
||||
</RefSubLayout.EducationRow>
|
||||
|
||||
### Serialization
|
||||
|
||||
supabase-kt provides several different ways to encode and decode your custom objects.
|
||||
By default, [KotlinX Serialization](https://github.com/Kotlin/kotlinx.serialization) is used.
|
||||
|
||||
<RefSubLayout.EducationRow>
|
||||
<RefSubLayout.Details>
|
||||
|
||||
Use [KotlinX Serialization](https://github.com/Kotlin/kotlinx.serialization).
|
||||
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
|
||||
<Tabs
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="kotlin"
|
||||
queryGroup="build-file"
|
||||
>
|
||||
<TabPanel id="kotlin" label="build.gradle.kts">
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
kotlin("plugin.serialization") version "KOTLIN_VERSION"
|
||||
}
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="groovy" label="build.gradle">
|
||||
|
||||
```groovy
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.plugin.serialization' version 'KOTLIN_VERSION'
|
||||
}
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="xml" label="pom.xml">
|
||||
|
||||
```xml
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<compilerPlugins>
|
||||
<plugin>kotlinx-serialization</plugin>
|
||||
</compilerPlugins>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-serialization</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
```kotlin
|
||||
val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
//Already the default serializer, but you can provide a custom Json instance (optional):
|
||||
defaultSerializer = KotlinXSerializer(Json {
|
||||
//apply your custom config
|
||||
})
|
||||
}
|
||||
```
|
||||
</RefSubLayout.Examples>
|
||||
|
||||
</RefSubLayout.EducationRow>
|
||||
<RefSubLayout.EducationRow>
|
||||
<RefSubLayout.Details>
|
||||
|
||||
Use [Moshi](https://github.com/square/moshi).
|
||||
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
|
||||
<Tabs
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="kotlin"
|
||||
queryGroup="build-file"
|
||||
>
|
||||
<TabPanel id="kotlin" label="build.gradle.kts">
|
||||
|
||||
```kotlin
|
||||
implementation("io.github.jan-tennert.supabase:serializer-moshi:VERSION")
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="groovy" label="build.gradle">
|
||||
|
||||
```groovy
|
||||
implementation 'io.github.jan-tennert.supabase:serializer-moshi:VERSION'
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="xml" label="pom.xml">
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.github.jan-tennert.supabase</groupId>
|
||||
<artifactId>serializer-moshi</artifactId>
|
||||
<version>VERSION</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
```kotlin
|
||||
val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
defaultSerializer = MoshiSerializer()
|
||||
}
|
||||
```
|
||||
|
||||
</RefSubLayout.Examples>
|
||||
|
||||
</RefSubLayout.EducationRow>
|
||||
<RefSubLayout.EducationRow>
|
||||
<RefSubLayout.Details>
|
||||
|
||||
Use [Jackson](https://github.com/FasterXML/jackson-module-kotlin).
|
||||
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
|
||||
<Tabs
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="kotlin"
|
||||
queryGroup="build-file"
|
||||
>
|
||||
<TabPanel id="kotlin" label="build.gradle.kts">
|
||||
|
||||
```kotlin
|
||||
implementation("io.github.jan-tennert.supabase:serializer-jackson:VERSION")
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="groovy" label="build.gradle">
|
||||
|
||||
```groovy
|
||||
implementation 'io.github.jan-tennert.supabase:serializer-jackson:VERSION'
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="xml" label="pom.xml">
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>io.github.jan-tennert.supabase</groupId>
|
||||
<artifactId>serializer-jackson</artifactId>
|
||||
<version>VERSION</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
```kotlin
|
||||
val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
defaultSerializer = JacksonSerializer()
|
||||
}
|
||||
```
|
||||
|
||||
</RefSubLayout.Examples>
|
||||
|
||||
</RefSubLayout.EducationRow>
|
||||
<RefSubLayout.EducationRow>
|
||||
<RefSubLayout.Details>
|
||||
|
||||
Use custom serializer.
|
||||
|
||||
</RefSubLayout.Details>
|
||||
<RefSubLayout.Examples>
|
||||
|
||||
```kotlin
|
||||
class CustomSerializer: SupabaseSerializer {
|
||||
|
||||
override fun <T : Any> encode(type: KType, value: T): String {
|
||||
//encode value to string
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(type: KType, value: String): T {
|
||||
//decode value
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
```kotlin
|
||||
val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
defaultSerializer = CustomSerializer()
|
||||
}
|
||||
```
|
||||
|
||||
</RefSubLayout.Examples>
|
||||
|
||||
</RefSubLayout.EducationRow>
|
||||
@@ -0,0 +1,13 @@
|
||||
This reference documents every object and method available in Supabase's Kotlin Multiplatform library, [supabase-kt](https://github.com/supabase-community/supabase-kt). You can use supabase-kt to interact with your Postgres database, listen to database changes, invoke Deno Edge Functions, build login and user management functionality, and manage large files.
|
||||
|
||||
To see supported Kotlin targets, check the corresponding module README on [GitHub](https://github.com/supabase-community/supabase-kt).
|
||||
|
||||
To migrate from version 1.4.X to 2.0.0, see the [migration guide](https://github.com/supabase-community/supabase-kt/blob/master/MIGRATION.md)
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
The Kotlin client library is created and maintained by the Supabase community, and is not an official library. Please be tolerant of areas where the library is still being developed, and — as with all the libraries — feel free to contribute wherever you find issues.
|
||||
|
||||
Huge thanks to official maintainer, [jan-tennert](https://github.com/jan-tennert).
|
||||
|
||||
</Admonition>
|
||||
@@ -1,9 +1,10 @@
|
||||
import { ArrowDown, Check, X } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { Button, Image } from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import { GlassPanel } from 'ui-patterns/GlassPanel'
|
||||
import { IconPanel } from 'ui-patterns/IconPanel'
|
||||
import SqlToRest from 'ui-patterns/SqlToRest'
|
||||
import { Admonition, Button, Image } from 'ui'
|
||||
import { Heading } from 'ui/src/components/CustomHTMLElements'
|
||||
import { AppleSecretGenerator } from '~/components/AppleSecretGenerator'
|
||||
import AuthProviders from '~/components/AuthProviders'
|
||||
@@ -21,8 +22,8 @@ import {
|
||||
HuggingFaceDeployment,
|
||||
KotlinProjectSetup,
|
||||
MigrationWarnings,
|
||||
ProjectSetup,
|
||||
OAuthPkceFlow,
|
||||
ProjectSetup,
|
||||
QuickstartDbSetup,
|
||||
QuickstartIntro,
|
||||
SocialProviderSettingsSupabase,
|
||||
@@ -37,7 +38,7 @@ import StepHikeCompact from '~/components/StepHikeCompact'
|
||||
import { CodeSampleWrapper } from '~/features/directives/CodeSample.client'
|
||||
import { Accordion, AccordionItem } from '~/features/ui/Accordion'
|
||||
import * as CH from '~/features/ui/CodeHike'
|
||||
import { Tabs, TabPanel } from '~/features/ui/Tabs'
|
||||
import { TabPanel, Tabs } from '~/features/ui/Tabs'
|
||||
|
||||
const components = {
|
||||
Accordion,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import { MDXProvider } from '@mdx-js/react'
|
||||
import { type PropsWithChildren } from 'react'
|
||||
|
||||
import { Admonition } from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
|
||||
const components = { Admonition }
|
||||
|
||||
|
||||
@@ -123,6 +123,10 @@ const levelsData = {
|
||||
icon: 'reference-kotlin',
|
||||
name: 'Kotlin Reference v2.0',
|
||||
},
|
||||
reference_kotlin_v3: {
|
||||
icon: 'reference-kotlin',
|
||||
name: 'Kotlin Reference v3.0',
|
||||
},
|
||||
reference_cli: {
|
||||
icon: 'reference-cli',
|
||||
name: 'CLI Reference',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Content, Paragraph, Root } from 'mdast'
|
||||
import type { MdxJsxFlowElement } from 'mdast-util-mdx'
|
||||
import type { AdmonitionProps } from 'ui'
|
||||
import type { AdmonitionProps } from 'ui-patterns/admonition'
|
||||
import type { Node } from 'unist'
|
||||
import { visit } from 'unist-util-visit'
|
||||
|
||||
|
||||
Vendored
+1
@@ -1,5 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
/// <reference types="next/navigation-types/compat/navigation" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
+15
-2
@@ -36,12 +36,14 @@
|
||||
"@octokit/graphql": "^7.0.2",
|
||||
"@octokit/plugin-paginate-graphql": "^4.0.0",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"@supabase/auth-helpers-react": "^0.4.2",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tanstack/react-query": "^5.13.4",
|
||||
"acorn": "^8.11.3",
|
||||
"acorn-typescript": "^1.4.13",
|
||||
"ai-commands": "*",
|
||||
"common": "*",
|
||||
"common-tags": "^1.8.2",
|
||||
"config": "*",
|
||||
@@ -50,8 +52,10 @@
|
||||
"github-slugger": "^2.0.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"hast-util-has-property": "^2.0.1",
|
||||
"hast-util-to-html": "^9.0.0",
|
||||
"icons": "*",
|
||||
"isbot": "^5.1.2",
|
||||
"js-yaml": "^3.14.1",
|
||||
"jsrsasign": "^11.0.0",
|
||||
"katex": "^0.16.10",
|
||||
"lodash": "^4.17.21",
|
||||
@@ -61,6 +65,8 @@
|
||||
"mdast-util-from-markdown": "^1.2.0",
|
||||
"mdast-util-gfm": "^2.0.2",
|
||||
"mdast-util-mdx": "^2.0.0",
|
||||
"mdast-util-mdx-jsx": "^2.0.0",
|
||||
"mdast-util-to-hast": "^12.3.0",
|
||||
"mdast-util-to-markdown": "^1.5.0",
|
||||
"mdast-util-to-string": "^3.1.1",
|
||||
"micromark-extension-gfm": "^2.0.3",
|
||||
@@ -73,10 +79,12 @@
|
||||
"openai": "^4.20.1",
|
||||
"openapi-fetch": "^0.8.2",
|
||||
"react": "^18.2.0",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.12",
|
||||
"react-intersection-observer": "^9.5.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-use": "^17.5.0",
|
||||
"rehype-katex": "^7.0.0",
|
||||
"rehype-slug": "^5.1.0",
|
||||
"remark": "^14.0.2",
|
||||
@@ -91,16 +99,21 @@
|
||||
"unist-builder": "^3.0.1",
|
||||
"unist-util-filter": "^4.0.1",
|
||||
"unist-util-visit": "^4.1.2",
|
||||
"unist-util-visit-parents": "^5.0.0",
|
||||
"uuid": "^9.0.1",
|
||||
"valtio": "^1.12.0",
|
||||
"yaml": "^2.4.5"
|
||||
"yaml": "^2.4.5",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aws-sdk/client-secrets-manager": "^3.410.0",
|
||||
"@types/estree": "1.0.5",
|
||||
"@types/hast": "^2.3.4",
|
||||
"@types/jsrsasign": "^10.5.12",
|
||||
"@types/mdast": "^3.0.0",
|
||||
"@types/node": "^20.11.16",
|
||||
"@types/react": "^18.2.24",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
"@types/unist": "^2.0.6",
|
||||
"api-types": "*",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
@@ -115,7 +128,7 @@
|
||||
"slugify": "^1.6.6",
|
||||
"tsconfig": "*",
|
||||
"tsx": "^4.6.2",
|
||||
"typescript": "^5.5.0",
|
||||
"typescript": "~5.5.0",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"vitest": "^2.0.2"
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
"reference_swift_v1",
|
||||
"reference_swift_v2",
|
||||
"reference_kotlin_v1",
|
||||
"reference_kotlin_v2"
|
||||
"reference_kotlin_v2",
|
||||
"reference_kotlin_v3"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -50,7 +51,8 @@
|
||||
"reference_swift_v1",
|
||||
"reference_swift_v2",
|
||||
"reference_kotlin_v1",
|
||||
"reference_kotlin_v2"
|
||||
"reference_kotlin_v2",
|
||||
"reference_kotlin_v3"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -989,7 +991,8 @@
|
||||
"reference_kotlin_v2",
|
||||
"reference_python_v2",
|
||||
"reference_swift_v1",
|
||||
"reference_swift_v2"
|
||||
"reference_swift_v2",
|
||||
"reference_kotlin_v3"
|
||||
],
|
||||
"items": [
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
// types/mdx.d.ts
|
||||
declare module '*.mdx' {
|
||||
let MDXComponent: (props) => JSX.Element
|
||||
export default MDXComponent
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, test, expect } from 'vitest'
|
||||
import { formatEstimatedCount } from './Pagination.utils'
|
||||
|
||||
describe('formatEstimatedCount', () => {
|
||||
|
||||
@@ -184,7 +184,7 @@ const ProviderForm = ({ config, provider }: ProviderFormProps) => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (urlProvider === provider.title.toLowerCase()) {
|
||||
if (urlProvider?.toLowerCase() === provider.title.toLowerCase()) {
|
||||
setOpen(true)
|
||||
ref.current?.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}
|
||||
|
||||
@@ -1383,7 +1383,7 @@ const PROVIDER_SAML = {
|
||||
$schema: JSON_SCHEMA_VERSION,
|
||||
type: 'object',
|
||||
title: 'SAML 2.0',
|
||||
link: 'https://supabase.com/docs/guides/auth/enterprise-sso',
|
||||
link: 'https://supabase.com/docs/guides/auth/enterprise-sso/auth-sso-saml',
|
||||
properties: {
|
||||
SAML_ENABLED: {
|
||||
title: 'Enable SAML 2.0 Single Sign-on',
|
||||
|
||||
@@ -20,7 +20,8 @@ import { useProjectApiQuery } from 'data/config/project-api-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { timeout } from 'lib/helpers'
|
||||
import { Admonition, Button, cn, Separator } from 'ui'
|
||||
import { Button, cn, Separator } from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { PROVIDERS_SCHEMAS } from '../AuthProvidersFormValidation'
|
||||
import { BanUserModal } from './BanUserModal'
|
||||
@@ -45,9 +46,9 @@ export const UserOverview = ({ user, onDeleteSuccess }: UserOverviewProps) => {
|
||||
const isPhoneAuth = user.phone !== null
|
||||
const isBanned = user.banned_until !== null
|
||||
|
||||
const providers = (user.raw_app_meta_data?.providers ?? []).map((provider) => {
|
||||
const providers = (user.raw_app_meta_data?.providers ?? []).map((provider: string) => {
|
||||
return {
|
||||
name: provider,
|
||||
name: provider.startsWith('sso') ? 'SAML' : provider,
|
||||
icon:
|
||||
provider === 'email'
|
||||
? `${BASE_PATH}/img/icons/email-icon2.svg`
|
||||
@@ -235,10 +236,13 @@ export const UserOverview = ({ user, onDeleteSuccess }: UserOverviewProps) => {
|
||||
<div className="flex-grow mt-0.5">
|
||||
<p className="capitalize">{provider.name}</p>
|
||||
<p className="text-xs text-foreground-light">
|
||||
Signed in with a {providerName} account via OAuth
|
||||
Signed in with a {providerName} account via{' '}
|
||||
{providerName === 'SAML' ? 'SSO' : 'OAuth'}
|
||||
</p>
|
||||
<Button asChild type="default" className="mt-2">
|
||||
<Link href={`/project/${projectRef}/auth/providers?provider=${provider.name}`}>
|
||||
<Link
|
||||
href={`/project/${projectRef}/auth/providers?provider=${provider.name === 'SAML' ? 'SAML 2.0' : provider.name}`}
|
||||
>
|
||||
Configure {providerName} provider
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
@@ -21,7 +21,10 @@ export const isAtBottom = ({ currentTarget }: UIEvent<HTMLDivElement>): boolean
|
||||
export const formatUsersData = (users: User[]) => {
|
||||
return users.map((user) => {
|
||||
const provider: string = user.raw_app_meta_data?.provider ?? ''
|
||||
const providers: string[] = user.raw_app_meta_data?.providers ?? []
|
||||
const providers: string[] = (user.raw_app_meta_data?.providers ?? []).map((x: string) => {
|
||||
if (x.startsWith('sso')) return 'SAML'
|
||||
return x
|
||||
})
|
||||
|
||||
return {
|
||||
id: user.id,
|
||||
@@ -34,9 +37,11 @@ export const formatUsersData = (users: User[]) => {
|
||||
.map((p) => {
|
||||
return p === 'email'
|
||||
? `${BASE_PATH}/img/icons/email-icon2.svg`
|
||||
: providerIconMap[p]
|
||||
? `${BASE_PATH}/img/icons/${providerIconMap[p]}.svg`
|
||||
: undefined
|
||||
: p === 'SAML'
|
||||
? `${BASE_PATH}/img/icons/saml-icon.svg`
|
||||
: providerIconMap[p]
|
||||
? `${BASE_PATH}/img/icons/${providerIconMap[p]}.svg`
|
||||
: undefined
|
||||
})
|
||||
.filter(Boolean),
|
||||
// I think it's alright to just check via the main provider since email and phone should be mutually exclusive
|
||||
@@ -207,7 +212,7 @@ export const formatUserColumns = ({
|
||||
: Array.isArray(value)
|
||||
? value.join(', ')
|
||||
: value
|
||||
const isConfirmed = user?.email_confirmed_at || user?.phone_confirmed_at
|
||||
const isConfirmed = !!user?.confirmed_at
|
||||
|
||||
if (col.id === 'img') {
|
||||
return (
|
||||
|
||||
@@ -93,6 +93,7 @@ export const UsersV2 = () => {
|
||||
const {
|
||||
data,
|
||||
error,
|
||||
isSuccess,
|
||||
isLoading,
|
||||
isRefetching,
|
||||
isError,
|
||||
@@ -123,7 +124,7 @@ export const UsersV2 = () => {
|
||||
})
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const totalUsers = useMemo(() => countData?.result[0].count, [countData?.result[0].count])
|
||||
const totalUsers = useMemo(() => countData?.result[0].count ?? 0, [countData?.result[0].count])
|
||||
const users = useMemo(() => data?.pages.flatMap((page) => page.result), [data?.pages])
|
||||
|
||||
const handleScroll = (event: UIEvent<HTMLDivElement>) => {
|
||||
@@ -171,8 +172,9 @@ export const UsersV2 = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
isSuccessStorage ||
|
||||
(isErrorStorage && (errorStorage as Error).message.includes('data is undefined'))
|
||||
!isRefetching &&
|
||||
(isSuccessStorage ||
|
||||
(isErrorStorage && (errorStorage as Error).message.includes('data is undefined')))
|
||||
) {
|
||||
const columns = formatUserColumns({
|
||||
config: columnConfiguration ?? [],
|
||||
@@ -186,7 +188,7 @@ export const UsersV2 = () => {
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isSuccessStorage, isErrorStorage, errorStorage])
|
||||
}, [isSuccess, isRefetching, isSuccessStorage, isErrorStorage, errorStorage])
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col">
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { Info, PlusIcon } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { FormMessage } from '@ui/components/shadcn/ui/form'
|
||||
import { Input } from '@ui/components/shadcn/ui/input'
|
||||
import { useParams } from 'common'
|
||||
import { useCreateCollection } from 'data/analytics/warehouse-collections-create-mutation'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useCurrentOrgPlan } from 'hooks/misc/useCurrentOrgPlan'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import {
|
||||
Admonition,
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
Alert_Shadcn_,
|
||||
Button,
|
||||
FormControl_Shadcn_,
|
||||
FormField_Shadcn_,
|
||||
FormMessage_Shadcn_,
|
||||
Form_Shadcn_,
|
||||
Input_Shadcn_,
|
||||
Modal,
|
||||
WarningIcon,
|
||||
} from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { useCurrentOrgPlan } from 'hooks/misc/useCurrentOrgPlan'
|
||||
import { Alert } from '@ui/components/shadcn/ui/alert'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
|
||||
export const CreateWarehouseCollectionModal = ({
|
||||
open,
|
||||
@@ -133,7 +125,7 @@ export const CreateWarehouseCollectionModal = ({
|
||||
render={({ field }) => (
|
||||
<FormItemLayout label="Collection name" layout="horizontal">
|
||||
<FormControl_Shadcn_>
|
||||
<Input autoFocus placeholder="Events" {...field} />
|
||||
<Input_Shadcn_ autoFocus placeholder="Events" {...field} />
|
||||
</FormControl_Shadcn_>
|
||||
</FormItemLayout>
|
||||
)}
|
||||
@@ -149,7 +141,7 @@ export const CreateWarehouseCollectionModal = ({
|
||||
>
|
||||
<FormControl_Shadcn_>
|
||||
<div className="relative flex items-center gap-2">
|
||||
<Input type="number" {...field} />
|
||||
<Input_Shadcn_ type="number" {...field} />
|
||||
<span className="absolute right-3 text-foreground-lighter text-sm pointer-events-none">
|
||||
days
|
||||
</span>
|
||||
@@ -159,7 +151,7 @@ export const CreateWarehouseCollectionModal = ({
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<FormMessage />
|
||||
<FormMessage_Shadcn_ />
|
||||
</Modal.Content>
|
||||
|
||||
{plan?.id === 'free' && (
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { describe, test, expect } from 'vitest'
|
||||
import { DiskType } from './DiskManagement.constants'
|
||||
import {
|
||||
calculateDiskSizePrice,
|
||||
calculateIOPSPrice,
|
||||
calculateThroughputPrice,
|
||||
} from './DiskManagement.utils'
|
||||
import { DiskType } from './DiskManagement.constants'
|
||||
|
||||
describe('DiskManagement.utils.ts:calculateDiskSizePrice', () => {
|
||||
test('GP3 with 8GB to GP3 with 10GB for pro plan', () => {
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
import { describe, test, expect } from 'vitest'
|
||||
import { deriveRoleChangeActions } from './UpdateRolesPanel.utils'
|
||||
|
||||
// [Joshen] This is specifically testing the project scope changes
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
isUpdateWithoutWhere,
|
||||
suffixWithLimit,
|
||||
} from './SQLEditor.utils'
|
||||
import { describe, test, expect, it } from 'vitest'
|
||||
|
||||
describe('SQLEditor.utils.ts:checkIfAppendLimitRequired', () => {
|
||||
test('Should return false if limit passed is <= 0', () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { indexOf } from 'lodash'
|
||||
import { ExternalLink, Lock } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
@@ -21,9 +22,7 @@ import { useProjectPostgrestConfigUpdateMutation } from 'data/config/project-pos
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { ExternalLink, Lock } from 'lucide-react'
|
||||
import {
|
||||
Admonition,
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
Alert_Shadcn_,
|
||||
@@ -40,6 +39,7 @@ import {
|
||||
Switch,
|
||||
WarningIcon,
|
||||
} from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import {
|
||||
MultiSelector,
|
||||
|
||||
+2
-1
@@ -33,8 +33,9 @@ import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { INSTANCE_MICRO_SPECS, INSTANCE_NANO_SPECS } from 'lib/constants'
|
||||
import { TIME_PERIODS_BILLING, TIME_PERIODS_REPORTS } from 'lib/constants/metrics'
|
||||
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
||||
import { Button } from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import { INFRA_ACTIVITY_METRICS } from './Infrastructure.constants'
|
||||
import { Admonition, Button } from 'ui'
|
||||
|
||||
const NON_DEDICATED_IO_RESOURCES = [
|
||||
'ci_micro',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { formatTableRowsToSQL } from './TableEntity.utils'
|
||||
|
||||
describe('TableEntity.utils: formatTableRowsToSQL', () => {
|
||||
|
||||
@@ -192,25 +192,27 @@ export function LogsSidebarMenuV2() {
|
||||
Create query
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<DropdownMenuItem className="gap-x-2" asChild>
|
||||
<button
|
||||
onClick={() => setCreateCollectionOpen(true)}
|
||||
className="w-full flex items-center text-xs px-2 py-1"
|
||||
disabled={!canCreateCollection}
|
||||
>
|
||||
<Plus size={14} />
|
||||
Create collection
|
||||
</button>
|
||||
</DropdownMenuItem>
|
||||
</TooltipTrigger>
|
||||
{!canCreateCollection && (
|
||||
<TooltipContent>
|
||||
You need additional permissions to create a collection
|
||||
</TooltipContent>
|
||||
)}
|
||||
</Tooltip>
|
||||
{warehouseEnabled && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<DropdownMenuItem className="gap-x-2" asChild>
|
||||
<button
|
||||
onClick={() => setCreateCollectionOpen(true)}
|
||||
className="w-full flex items-center text-xs px-2 py-1"
|
||||
disabled={!canCreateCollection}
|
||||
>
|
||||
<Plus size={14} />
|
||||
Create collection
|
||||
</button>
|
||||
</DropdownMenuItem>
|
||||
</TooltipTrigger>
|
||||
{!canCreateCollection && (
|
||||
<TooltipContent>
|
||||
You need additional permissions to create a collection
|
||||
</TooltipContent>
|
||||
)}
|
||||
</Tooltip>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<CreateWarehouseCollectionModal
|
||||
@@ -247,7 +249,7 @@ export function LogsSidebarMenuV2() {
|
||||
label={collection?.name ?? ''}
|
||||
/>
|
||||
))}
|
||||
{whCollectionsLoading ? (
|
||||
{whCollectionsLoading && warehouseEnabled ? (
|
||||
<div className="p-4">
|
||||
<GenericSkeletonLoader />
|
||||
</div>
|
||||
|
||||
@@ -194,21 +194,6 @@ const ReportsMenu = () => {
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* [Joshen] Temp notice while we shift some pages on 040424 - can probably remove in 3 months perhaps */}
|
||||
<Alert_Shadcn_>
|
||||
<AlertTitle_Shadcn_ className="text-sm">
|
||||
Query Performance and Project Linter reports have been shifted
|
||||
</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_ className="text-xs">
|
||||
<p className="mb-2">They can now be found in the menu under the database section.</p>
|
||||
<Button asChild type="default" size="tiny">
|
||||
<Link href={`/project/${ref}/database/query-performance`}>
|
||||
Head over to Database
|
||||
</Link>
|
||||
</Button>
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
|
||||
<UpdateCustomReportModal
|
||||
onCancel={() => setSelectedReportToUpdate(undefined)}
|
||||
selectedReport={selectedReportToUpdate}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
function FormsContainer(props: { children: React.ReactNode; header?: string }) {
|
||||
import { cn } from 'ui'
|
||||
|
||||
function FormsContainer(props: { children: React.ReactNode; header?: string; className?: string }) {
|
||||
return (
|
||||
<div className="mx-auto max-w-4xl px-5 pt-12 pb-20">
|
||||
<div className={cn('mx-auto max-w-4xl px-5 pt-12 pb-20', props.className)}>
|
||||
{props.header && <h1 className="text-foreground mb-8 text-3xl">{props.header}</h1>}
|
||||
<div className="space-y-20">{props.children}</div>
|
||||
</div>
|
||||
|
||||
@@ -41,9 +41,17 @@ const getUsersCountSQl = ({
|
||||
}
|
||||
|
||||
if (providers && providers.length > 0) {
|
||||
conditions.push(
|
||||
`(raw_app_meta_data->>'providers')::jsonb ?| array[${providers.map((p) => `'${p}'`).join(', ')}]`
|
||||
)
|
||||
// [Joshen] This is arguarbly not fully optimized, but at the same time not commonly used
|
||||
// JFYI in case we do eventually run into performance issues here when filtering for SAML provider
|
||||
if (providers.includes('saml 2.0')) {
|
||||
conditions.push(
|
||||
`(select jsonb_agg(case when value ~ '^sso' then 'sso' else value end) from jsonb_array_elements_text((raw_app_meta_data ->> 'providers')::jsonb)) ?| array[${providers.map((p) => (p === 'saml 2.0' ? `'sso'` : `'${p}'`)).join(', ')}]`.trim()
|
||||
)
|
||||
} else {
|
||||
conditions.push(
|
||||
`(raw_app_meta_data->>'providers')::jsonb ?| array[${providers.map((p) => `'${p}'`).join(', ')}]`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const combinedConditions = conditions.map((x) => `(${x})`).join(' and ')
|
||||
|
||||
@@ -43,7 +43,7 @@ const getUsersSQL = ({
|
||||
|
||||
if (hasValidKeywords) {
|
||||
conditions.push(
|
||||
`id::text ilike '%${keywords}%' or email ilike '%${keywords}%' or phone ilike '%${keywords}%`
|
||||
`id::text ilike '%${keywords}%' or email ilike '%${keywords}%' or phone ilike '%${keywords}%'`
|
||||
)
|
||||
}
|
||||
|
||||
@@ -56,9 +56,17 @@ const getUsersSQL = ({
|
||||
}
|
||||
|
||||
if (providers && providers.length > 0) {
|
||||
conditions.push(
|
||||
`(raw_app_meta_data->>'providers')::jsonb ?| array[${providers.map((p) => `'${p}'`).join(', ')}]`
|
||||
)
|
||||
// [Joshen] This is arguarbly not fully optimized, but at the same time not commonly used
|
||||
// JFYI in case we do eventually run into performance issues here when filtering for SAML provider
|
||||
if (providers.includes('saml 2.0')) {
|
||||
conditions.push(
|
||||
`(select jsonb_agg(case when value ~ '^sso' then 'sso' else value end) from jsonb_array_elements_text((raw_app_meta_data ->> 'providers')::jsonb)) ?| array[${providers.map((p) => (p === 'saml 2.0' ? `'sso'` : `'${p}'`)).join(', ')}]`.trim()
|
||||
)
|
||||
} else {
|
||||
conditions.push(
|
||||
`(raw_app_meta_data->>'providers')::jsonb ?| array[${providers.map((p) => `'${p}'`).join(', ')}]`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const combinedConditions = conditions.map((x) => `(${x})`).join(' and ')
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"@hcaptcha/react-hcaptcha": "^1.8.1",
|
||||
"@headlessui/react": "^1.7.17",
|
||||
"@heroicons/react": "^2.1.3",
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@next/bundle-analyzer": "^14.2.3",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
@@ -36,7 +37,9 @@
|
||||
"@stripe/react-stripe-js": "^2.5.0",
|
||||
"@stripe/stripe-js": "^3.0.5",
|
||||
"@supabase/auth-helpers-react": "^0.4.2",
|
||||
"@supabase/auth-js": "2.64.2",
|
||||
"@supabase/pg-meta": "*",
|
||||
"@supabase/realtime-js": "2.10.2",
|
||||
"@supabase/shared-types": "0.1.70",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tanstack/react-query": "4.35.7",
|
||||
@@ -53,6 +56,7 @@
|
||||
"config": "*",
|
||||
"configcat-js": "^7.0.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"dnd-core": "^16.0.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"framer-motion": "^11.0.3",
|
||||
"generate-password-browser": "^1.1.0",
|
||||
@@ -64,6 +68,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.436.0",
|
||||
"markdown-table": "^3.0.3",
|
||||
"memoize-one": "^5.0.1",
|
||||
"mime-db": "^1.53.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
@@ -81,6 +86,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-contexify": "^5.0.0",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-csv": "^2.0.3",
|
||||
"react-data-grid": "7.0.0-beta.41",
|
||||
"react-datepicker": "^4.18.0",
|
||||
@@ -89,18 +95,22 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.13",
|
||||
"react-grid-layout": "^1.4.2",
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-inlinesvg": "^4.0.4",
|
||||
"react-intersection-observer": "^9.5.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-simple-maps": "4.0.0-beta.6",
|
||||
"react-tracked": "^1.7.11",
|
||||
"react-use": "^17.5.0",
|
||||
"react-virtualized-auto-sizer": "^1.0.20",
|
||||
"react-window": "^1.8.6",
|
||||
"react-window-infinite-loader": "^1.0.7",
|
||||
"reactflow": "^11.10.1",
|
||||
"recharts": "^2.8.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"semver": "^6.3.1",
|
||||
"shared-data": "*",
|
||||
"sonner": "^1.5.0",
|
||||
"sql-formatter": "^13.1.0",
|
||||
"sqlstring": "^2.3.2",
|
||||
"tus-js-client": "^4.1.0",
|
||||
@@ -112,6 +122,7 @@
|
||||
"vitest": "^1.6.0",
|
||||
"yup": "^1.4.0",
|
||||
"yup-password": "^0.3.0",
|
||||
"zod": "^3.22.4",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -134,6 +145,7 @@
|
||||
"@types/randombytes": "^2.0.3",
|
||||
"@types/react": "^18.2.24",
|
||||
"@types/react-beautiful-dnd": "^13.1.2",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
"@types/react-csv": "^1.1.2",
|
||||
"@types/react-datepicker": "^4.3.4",
|
||||
"@types/react-dom": "^18.2.8",
|
||||
@@ -160,6 +172,6 @@
|
||||
"prettier": "^4.0.0-alpha.8",
|
||||
"storybook-dark-mode": "^3.0.1",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,6 @@ import passwordStrength from 'lib/password-strength'
|
||||
import type { CloudProvider } from 'shared-data'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
import {
|
||||
Admonition,
|
||||
Badge,
|
||||
Button,
|
||||
CollapsibleContent_Shadcn_,
|
||||
@@ -76,6 +75,7 @@ import {
|
||||
TableRow,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import { Input } from 'ui-patterns/DataInputs/Input'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { InfoTooltip } from 'ui-patterns/info-tooltip'
|
||||
|
||||
@@ -15,7 +15,7 @@ const PageLayout: NextPageWithLayout = () => {
|
||||
return <NoPermission isFullPage resourceText="access your project's auth provider settings" />
|
||||
} else {
|
||||
return (
|
||||
<FormsContainer>
|
||||
<FormsContainer className="w-full">
|
||||
<AuthProvidersForm />
|
||||
</FormsContainer>
|
||||
)
|
||||
|
||||
@@ -214,7 +214,10 @@ const DatabaseUsage = () => {
|
||||
renderer={(props) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="col-span-4 inline-grid grid-cols-12 gap-12 w-full">
|
||||
<p className="text-sm -mt-4 text-foreground-lighter">
|
||||
The data refreshes every 24 hours.
|
||||
</p>
|
||||
<div className="col-span-4 inline-grid grid-cols-12 gap-12 w-full mt-5">
|
||||
<div className="grid gap-2 col-span-2">
|
||||
<h5 className="text-sm">Space used</h5>
|
||||
<span className="text-lg">{formatBytes(databaseSizeBytes, 2, 'GB')}</span>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { sanitizeTaxIdValue } from 'components/interfaces/Organization/BillingSettings/TaxID/TaxID.utils'
|
||||
import { describe, test, expect } from 'vitest'
|
||||
|
||||
/**
|
||||
* We're sanitizing EU tax ids. Stripe expects a prefixed tax id (ATU12345678),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { vi } from 'vitest'
|
||||
import { expect, test, vi } from 'vitest'
|
||||
|
||||
import { screen } from '@testing-library/dom'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { removeJSONTrailingComma } from 'lib/helpers'
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
describe('removeJSONTrailingComma', () => {
|
||||
it('should handle an empty object', () => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { vi } from 'vitest'
|
||||
import { RowField } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.types'
|
||||
import {
|
||||
generateRowObjectFromFields,
|
||||
parseValue,
|
||||
} from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils'
|
||||
import { RowField } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.types'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
describe('parseValue', () => {
|
||||
it('should return null when originalValue is null', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { inferColumnType } from 'components/interfaces/TableGridEditor/SidePanelEditor/SpreadsheetImport/SpreadsheetImport.utils'
|
||||
import { describe, test, expect } from 'vitest'
|
||||
|
||||
describe('SpreadsheedImport.utils: inferColumnType', () => {
|
||||
test('should default column type to text if no rows to infer from', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { formatFilterURLParams, formatSortURLParams } from 'components/grid/SupabaseGrid.utils'
|
||||
import { describe, test, expect } from 'vitest'
|
||||
|
||||
// Sort URL syntax: `column:order`
|
||||
describe('SupabaseGrid.utils: formatSortURLParams', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { sanitizeRoute } from 'components/layouts/AppLayout/ProjectDropdown'
|
||||
import { test, expect } from 'vitest'
|
||||
|
||||
test('Should sanitize project routes correctly when switching projects by removing project specific parameters', () => {
|
||||
expect(sanitizeRoute('/project/[ref]', { ref: 'abc' })).toBe('/project/[ref]')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { screen } from '@testing-library/react'
|
||||
import ReportWidget from 'components/interfaces/Reports/ReportWidget'
|
||||
import { test } from 'vitest'
|
||||
import { render } from '../../helpers'
|
||||
|
||||
test('static elements', async () => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
convertFromBytes,
|
||||
convertToBytes,
|
||||
} from 'components/to-be-cleaned/Storage/StorageSettings/StorageSettings.utils'
|
||||
import { describe, test, expect } from 'vitest'
|
||||
|
||||
describe('StorageSettings.utils: convertFromBytes', () => {
|
||||
test('should convert 1024 to 1KB', () => {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { renderHook } from '@testing-library/react'
|
||||
import {
|
||||
isFloat,
|
||||
numberFormatter,
|
||||
precisionFormatter,
|
||||
useStacked,
|
||||
} from 'components/ui/Charts/Charts.utils'
|
||||
import { renderHook } from '@testing-library/react'
|
||||
import { test, expect } from 'vitest'
|
||||
|
||||
test('isFloat', () => {
|
||||
expect(isFloat(123)).toBe(false)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { API_URL } from 'lib/constants'
|
||||
import { test, expect } from 'vitest'
|
||||
|
||||
test('MSW works as expected', async () => {
|
||||
const res = await fetch(`${API_URL}/msw/test`)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import { RouterComponent } from './router'
|
||||
import { expect, suite, vi } from 'vitest'
|
||||
import { routerMock } from 'tests/mocks/router'
|
||||
import { expect, suite, test } from 'vitest'
|
||||
import { RouterComponent } from './router'
|
||||
|
||||
suite('Router Mock', () => {
|
||||
test('Router mock works as expected', async () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { vi } from 'vitest'
|
||||
import { afterEach, beforeEach, test, vi } from 'vitest'
|
||||
|
||||
import LogEventChart from 'components/interfaces/Settings/Logs/LogEventChart'
|
||||
import { screen } from '@testing-library/react'
|
||||
import LogEventChart from 'components/interfaces/Settings/Logs/LogEventChart'
|
||||
import { render } from '../../helpers'
|
||||
|
||||
const { ResizeObserver } = window
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { describe, vi, test } from 'vitest'
|
||||
import LogTable from 'components/interfaces/Settings/Logs/LogTable'
|
||||
import { waitFor, screen, prettyDOM } from '@testing-library/react'
|
||||
import { prettyDOM, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import LogTable from 'components/interfaces/Settings/Logs/LogTable'
|
||||
import dayjs from 'dayjs'
|
||||
import { beforeAll, expect, test, vi } from 'vitest'
|
||||
import { render } from '../../helpers'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
|
||||
@@ -5,7 +5,7 @@ import { PREVIEWER_DATEPICKER_HELPERS } from 'components/interfaces/Settings/Log
|
||||
import dayjs from 'dayjs'
|
||||
import timezone from 'dayjs/plugin/timezone'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
import { vi } from 'vitest'
|
||||
import { expect, test, vi } from 'vitest'
|
||||
import { render } from '../../helpers'
|
||||
|
||||
dayjs.extend(timezone)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {
|
||||
checkForWithClause,
|
||||
checkForILIKEClause,
|
||||
checkForWildcard,
|
||||
checkForWithClause,
|
||||
} from 'components/interfaces/Settings/Logs/Logs.utils'
|
||||
import { describe, test, expect } from 'vitest'
|
||||
|
||||
describe('checkForWithClause', () => {
|
||||
test('basic queries', () => {
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
import { vi } from 'vitest'
|
||||
import { act, findByRole, findByText, fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import { wait } from '@testing-library/user-event/dist/utils'
|
||||
import { findByText, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import dayjs from 'dayjs'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
import { useRouter } from 'next/router'
|
||||
import { expect, test, vi } from 'vitest'
|
||||
|
||||
dayjs.extend(utc)
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LogsTableName } from 'components/interfaces/Settings/Logs/Logs.constants'
|
||||
import LogsPreviewer from 'components/interfaces/Settings/Logs/LogsPreviewer'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { logDataFixture } from '../../fixtures'
|
||||
import { render } from '../../helpers'
|
||||
|
||||
// [Joshen] There's gotta be a much better way to mock these things so that it applies for ALL tests
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { vi } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import { expect, test, vi } from 'vitest'
|
||||
|
||||
import { render } from 'tests/helpers'
|
||||
import LogsQueryPanel from 'components/interfaces/Settings/Logs/LogsQueryPanel'
|
||||
import { render } from 'tests/helpers'
|
||||
|
||||
test('run and clear', async () => {
|
||||
const mockRun = vi.fn()
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { vi } from 'vitest'
|
||||
import { screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
|
||||
import PreviewFilterPanel from 'components/interfaces/Settings/Logs/PreviewFilterPanel'
|
||||
import { render } from '../../helpers'
|
||||
import { clickDropdown } from 'tests/helpers'
|
||||
import { expect, test, vi } from 'vitest'
|
||||
|
||||
test.skip('filter input change and submit', async () => {
|
||||
const mockFn = vi.fn()
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// mock the fetch function
|
||||
import { get } from 'lib/common/fetch'
|
||||
import { LogsSavedPage } from 'pages/project/[ref]/logs/explorer/saved'
|
||||
import { render } from 'tests/helpers'
|
||||
import { test } from 'vitest'
|
||||
|
||||
test('on load, refresh user content', async () => {
|
||||
// get.mockResolvedValue({})
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { vi } from 'vitest'
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import dayjs from 'dayjs'
|
||||
import { LogsExplorerPage } from 'pages/project/[ref]/logs/explorer/index'
|
||||
import { clickDropdown, render } from 'tests/helpers'
|
||||
import { routerMock } from 'tests/mocks/router'
|
||||
import { beforeAll, describe, expect, test, vi } from 'vitest'
|
||||
|
||||
// [Joshen] Am temporarily commenting out the breaking tests due to:
|
||||
// "TypeError: _fetch.get.mockReset is not a function" error from Jest
|
||||
@@ -21,7 +21,7 @@ beforeAll(() => {
|
||||
...mod,
|
||||
IS_PLATFORM: true,
|
||||
useIsLoggedIn: vi.fn(),
|
||||
useParams: jest.fn(() => ({ ref: 'projectRef' })),
|
||||
useParams: vi.fn(() => ({ ref: 'projectRef' })),
|
||||
}
|
||||
})
|
||||
vi.mock('lib/gotrue', () => ({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { prettyDOM, screen } from '@testing-library/react'
|
||||
import { screen } from '@testing-library/react'
|
||||
import { test } from 'vitest'
|
||||
|
||||
import { ApiReport } from 'pages/project/[ref]/reports/api-overview'
|
||||
import { render } from '../../../helpers'
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { screen } from '@testing-library/react'
|
||||
import { test } from 'vitest'
|
||||
|
||||
import { render } from '../../../helpers'
|
||||
import { StorageReport } from 'pages/project/[ref]/reports/storage'
|
||||
import { render } from '../../../helpers'
|
||||
|
||||
// [Joshen] Mock data for ApiReport is in __mocks__/hooks/useStorageReport
|
||||
// I don't think this is an ideal set up as the mock data is not clear in this file itself
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getReturnToPath } from 'lib/gotrue'
|
||||
import { describe, it, expect } from 'vitest'
|
||||
|
||||
describe(`getReturnToPath`, () => {
|
||||
it(`returns to /projects when no fallback is provided`, () => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { beforeAll, vi } from 'vitest'
|
||||
import { setupServer } from 'msw/node'
|
||||
import { createDynamicRouteParser } from 'next-router-mock/dist/dynamic-routes'
|
||||
import { afterAll, afterEach, beforeAll, vi } from 'vitest'
|
||||
import { APIMock } from './mocks/api'
|
||||
import { routerMock } from './mocks/router'
|
||||
import { createDynamicRouteParser } from 'next-router-mock/dist/dynamic-routes'
|
||||
|
||||
export const mswServer = setupServer(...APIMock)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"company": [
|
||||
{
|
||||
"number": "85+",
|
||||
"number": "90+",
|
||||
"text": "team members\n\nin 25+ countries"
|
||||
},
|
||||
{
|
||||
@@ -9,7 +9,7 @@
|
||||
"text": "languages spoken"
|
||||
},
|
||||
{
|
||||
"number": "$116M",
|
||||
"number": "$196M",
|
||||
"text": "in funding"
|
||||
},
|
||||
{
|
||||
@@ -17,7 +17,7 @@
|
||||
"text": "community members"
|
||||
},
|
||||
{
|
||||
"number": "5000+",
|
||||
"number": "5,000+",
|
||||
"text": "memes posted\n\n(and counting)"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
export interface JobItemProps {
|
||||
id: string
|
||||
title: string
|
||||
location: any
|
||||
team: string
|
||||
employment: string
|
||||
descriptionHtml: string
|
||||
jobUrl: string
|
||||
}
|
||||
|
||||
export const PLACEHOLDER_JOB_ID = '64d76968-1fe1-458c-8c6d-8859168c3fb7'
|
||||
export const filterGenericJob = (job: JobItemProps) => job.id === PLACEHOLDER_JOB_ID
|
||||
export const groupJobsByTeam = (jobs: JobItemProps[]) => {
|
||||
return jobs.reduce(
|
||||
(acc, job) => {
|
||||
if (!acc[job.team]) {
|
||||
acc[job.team] = []
|
||||
}
|
||||
acc[job.team].push(job)
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, JobItemProps[]>
|
||||
)
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import { PropsWithChildren } from 'react'
|
||||
import { CH } from '@code-hike/mdx/components'
|
||||
import { ArrowUpRight, Triangle } from 'lucide-react'
|
||||
import {
|
||||
Admonition,
|
||||
Badge,
|
||||
cn,
|
||||
Collapsible_Shadcn_,
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
Heading,
|
||||
Image,
|
||||
} from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import { type ImageProps } from 'ui/src/components/Image/Image'
|
||||
import Avatar from '~/components/Avatar'
|
||||
import Chart from '~/components/Charts/PGCharts'
|
||||
|
||||
@@ -25,15 +25,19 @@
|
||||
"@octokit/graphql": "^7.0.2",
|
||||
"@octokit/plugin-paginate-graphql": "^4.0.0",
|
||||
"@octokit/rest": "^20.0.2",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@react-three/fiber": "^7.0.29",
|
||||
"@supabase/auth-helpers-react": "^0.4.2",
|
||||
"@supabase/auth-ui-react": "^0.4.5",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@vercel/og": "^0.6.2",
|
||||
"ai-commands": "*",
|
||||
"animejs": "^3.2.2",
|
||||
"classnames": "^2.3.1",
|
||||
"clsx": "^1.2.1",
|
||||
"cobe": "^0.6.2",
|
||||
"common": "*",
|
||||
"common-tags": "^1.8.2",
|
||||
"config": "*",
|
||||
"contentlayer2": "0.4.6",
|
||||
"dat.gui": "^0.7.9",
|
||||
@@ -43,6 +47,7 @@
|
||||
"globby": "^13.2.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
"icons": "*",
|
||||
"lodash": "^4.0.0",
|
||||
"lucide-react": "*",
|
||||
"markdown-toc": "^1.2.0",
|
||||
"next": "^14.2.10",
|
||||
@@ -50,6 +55,7 @@
|
||||
"next-mdx-remote": "^4.4.1",
|
||||
"next-seo": "^6.5.0",
|
||||
"next-themes": "^0.3.0",
|
||||
"openai": "^4.20.1",
|
||||
"parse-numeric-range": "^1.3.0",
|
||||
"react": "^18.2.0",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
@@ -69,7 +75,7 @@
|
||||
"swiper": "^11.0.7",
|
||||
"three": "^0.136.0",
|
||||
"typed.js": "^2.0.16",
|
||||
"typescript": "^5.5.0",
|
||||
"typescript": "~5.5.0",
|
||||
"ui": "*",
|
||||
"ui-patterns": "*",
|
||||
"use-debounce": "^7.0.1",
|
||||
@@ -79,9 +85,11 @@
|
||||
"devDependencies": {
|
||||
"@types/animejs": "^3.1.12",
|
||||
"@types/classnames": "^2.3.1",
|
||||
"@types/common-tags": "^1.8.4",
|
||||
"@types/dat.gui": "^0.7.10",
|
||||
"@types/mdx-js__react": "^1.5.6",
|
||||
"@types/node": "^20.11.16",
|
||||
"@types/lodash": "^4.0.0",
|
||||
"@types/parse-numeric-range": "^0.0.1",
|
||||
"@types/react": "^18.2.24",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
|
||||
+383
-384
@@ -1,22 +1,26 @@
|
||||
import { GlobeAltIcon } from '@heroicons/react/outline'
|
||||
import { Check } from 'lucide-react'
|
||||
import { NextPage } from 'next'
|
||||
import { NextSeo } from 'next-seo'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import { NextSeo } from 'next-seo'
|
||||
import { GlobeAltIcon } from '@heroicons/react/outline'
|
||||
import { Check } from 'lucide-react'
|
||||
import { Badge, Button, Separator, buttonVariants, cn } from 'ui'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import Styles from '~/styles/career.module.css'
|
||||
|
||||
import Globe from '~/components/Globe'
|
||||
import DefaultLayout from '~/components/Layouts/Default'
|
||||
import SectionContainer from '~/components/Layouts/SectionContainer'
|
||||
|
||||
import { groupJobsByTeam, filterGenericJob, JobItemProps, PLACEHOLDER_JOB_ID } from '~/lib/careers'
|
||||
import career from '~/data/career.json'
|
||||
import Styles from '~/styles/career.module.css'
|
||||
|
||||
export async function getStaticProps() {
|
||||
const job_res = await fetch('https://boards-api.greenhouse.io/v1/boards/supabase/jobs')
|
||||
|
||||
const job_res = await fetch('https://api.ashbyhq.com/posting-api/job-board/supabase')
|
||||
const job_data = await job_res.json()
|
||||
const jobs = groupJobsByTeam(job_data.jobs.filter((job: JobItemProps) => !filterGenericJob(job)))
|
||||
const placeholderJob = job_data.jobs.find(filterGenericJob)
|
||||
|
||||
const contributor_res = await fetch(
|
||||
'https://api.github.com/repos/supabase/supabase/contributors?per_page=100'
|
||||
@@ -70,13 +74,20 @@ export async function getStaticProps() {
|
||||
|
||||
return {
|
||||
props: {
|
||||
jobs: job_data.jobs,
|
||||
jobs,
|
||||
placeholderJob,
|
||||
contributors: contributors,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const CareerPage: NextPage = ({ jobs, contributors }: any) => {
|
||||
interface CareersPageProps {
|
||||
jobs: Record<string, JobItemProps[]>
|
||||
placeholderJob: JobItemProps
|
||||
contributors: { login: string; avatar_url: string; html_url: string }[]
|
||||
}
|
||||
|
||||
const CareerPage: NextPage<CareersPageProps> = ({ jobs, placeholderJob, contributors }) => {
|
||||
const { basePath } = useRouter()
|
||||
|
||||
const meta_title = 'Careers | Supabase'
|
||||
@@ -99,412 +110,400 @@ const CareerPage: NextPage = ({ jobs, contributors }: any) => {
|
||||
}}
|
||||
/>
|
||||
<DefaultLayout>
|
||||
<div className="text-foreground">
|
||||
<div className="container relative mx-auto px-6 py-10 lg:pt-12 lg:px-16 xl:px-20 text-center space-y-4">
|
||||
<h1 className="text-sm text-brand md:text-base">
|
||||
<span className="sr-only">Supabase </span>Careers
|
||||
</h1>
|
||||
<h2 className="text-3xl md:text-4xl xl:text-5xl lg:max-w-2xl xl:max-w-3xl lg:mx-auto tracking-[-1.5px]">
|
||||
We're on a mission to build the best developer platform
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-foreground-lighter max-w-sm sm:max-w-md md:max-w-lg mx-auto">
|
||||
Explore remote possibilities and join our team to help us achieve it.
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<a href="#positions">
|
||||
<Button type="primary">Open positions</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<header className="container relative mx-auto px-6 pt-12 pb-8 lg:pt-24 lg:px-16 xl:px-20 text-center space-y-4">
|
||||
<h1 className="text-sm text-brand md:text-base">
|
||||
<span className="sr-only">Supabase </span>Careers
|
||||
</h1>
|
||||
<h2 className="text-3xl md:text-4xl xl:text-5xl lg:max-w-2xl xl:max-w-3xl lg:mx-auto tracking-[-1.5px]">
|
||||
We're on a mission to build the best developer platform
|
||||
</h2>
|
||||
<p className="text-sm md:text-base text-foreground-lighter max-w-sm sm:max-w-md md:max-w-lg mx-auto">
|
||||
Explore remote possibilities and join our team to help us achieve it.
|
||||
</p>
|
||||
<Button asChild type="primary" className="mt-4">
|
||||
<Link href="#positions">Open positions</Link>
|
||||
</Button>
|
||||
</header>
|
||||
|
||||
<SectionContainer>
|
||||
<div className="flex flex-wrap md:flex-nowrap -mt-6 md:mt-0 w-fit md:w-full mx-auto md:flex md:items-start justify-around lg:w-full lg:max-w-5xl">
|
||||
{career.company.map((company: { number: string; text: string }, i: number) => {
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className="border-t-[1px] mt-6 mx-2 md:mx-2 md:mt-0 md:border-0 border-brand w-[134px] md:max-w-none"
|
||||
>
|
||||
<div className="hidden md:block border-t-[1px] lg:border-t-2 border-brand w-[60px] lg:w-[100px]"></div>
|
||||
<h2 className="text-3xl lg:text-4xl pt-3 tracking-[-1.5px]">
|
||||
{company.number}
|
||||
</h2>
|
||||
<ReactMarkdown className="text-foreground-light text-sm lg:text-base">
|
||||
{company.text}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
<div className="py-[1.25px] bg-gradient-to-r from-background via-border to-background">
|
||||
<div className="bg-alternative overflow-clip">
|
||||
<SectionContainer className="md:!pt-16 md:grid md:max-h-[500px] grid-cols-1 md:grid-cols-5 md:gap-8">
|
||||
<SectionContainer className="!pt-8">
|
||||
<div className="flex flex-wrap md:flex-nowrap -mt-6 md:mt-0 w-fit md:w-full mx-auto md:flex md:items-start justify-around lg:w-full lg:max-w-5xl">
|
||||
{career.company.map((company: { number: string; text: string }, i: number) => {
|
||||
return (
|
||||
<div
|
||||
className="
|
||||
key={i}
|
||||
className="border-t-[1px] mt-6 mx-2 md:mx-2 md:mt-0 md:border-0 border-brand w-[134px] md:max-w-none"
|
||||
>
|
||||
<div className="hidden md:block border-t-[1px] lg:border-t-2 border-brand w-[60px] lg:w-[100px]"></div>
|
||||
<h2 className="text-3xl lg:text-4xl pt-3 tracking-[-1.5px]">{company.number}</h2>
|
||||
<ReactMarkdown className="text-foreground-light text-sm lg:text-base">
|
||||
{company.text}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
<div className="py-[1.25px] bg-gradient-to-r from-background via-border to-background">
|
||||
<div className="bg-alternative overflow-clip">
|
||||
<SectionContainer className="md:!pt-16 md:grid md:max-h-[500px] grid-cols-1 md:grid-cols-5 md:gap-8">
|
||||
<div
|
||||
className="
|
||||
relative md:col-span-2 aspect-square
|
||||
w-[calc(100%+100px)] md:w-[calc(100%+450px)] xl:w-[calc(100%+200px)]
|
||||
-mb-[160px] md:mb-0
|
||||
-top-[160px] md:-top-[200px] xl:-top-[210px]
|
||||
-left-[100px] md:-left-[450px] xl:-left-[200px]
|
||||
"
|
||||
>
|
||||
<Globe />
|
||||
</div>
|
||||
<div className="relative md:col-span-3">
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl max-w-[300px] md:max-w-xs tracking-[-1.5px]">
|
||||
We work together, wherever we are
|
||||
</h2>
|
||||
<p className="text-foreground-light mt-4 text-xs sm:text-sm md:text-base md:w-full">
|
||||
Working in a globally distributed team is rewarding but has its challenges. We
|
||||
are across many different timezones, so we use tools like Notion, Slack, and
|
||||
Discord to stay connected to our team, and our community.
|
||||
</p>
|
||||
<div className="max-w-[300px] sm:max-w-md md:max-w-md mt-20">
|
||||
<div className="border-t-2 border-brand w-4/12"></div>
|
||||
<h2 className="text-2xl sm:text-3xl md:text-4xl pt-2 tracking-[-1.5px]">
|
||||
We deeply believe in the efficacy of collaborative open source
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
<SectionContainer className="-mt-16 md:mt-16">
|
||||
<div className="md:flex md:gap-6">
|
||||
<div className="md:w-1/2">
|
||||
<div>
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl tracking-[-1.5px]">
|
||||
What is Supabase
|
||||
</h2>
|
||||
<p className="text-foreground-light text-xs sm:text-sm lg:text-base pt-2 sm:max-w-md xl:max-w-lg">
|
||||
Supabase is an open source Firebase alternative, built by developers for
|
||||
developers. Supabase adds auth, realtime, storage, restful APIs, and edge
|
||||
functions to Postgres without a single line of code. Supabase was
|
||||
born-remote. Having a globally distributed, open source company is our
|
||||
secret weapon to hiring top-tier talent.
|
||||
</p>
|
||||
</div>
|
||||
<div className="md:w-full rounded-md mt-10 md:mt-36 lg:mt-40">
|
||||
<div className="relative w-full aspect-[148/125]">
|
||||
<Image
|
||||
src="/images/career/1.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid justify-items-end">
|
||||
<div className="w-full md:w-5/6 rounded-md mt-6">
|
||||
<div className="relative w-full aspect-[29/22]">
|
||||
<Image
|
||||
src="/images/career/2.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 md:mt-0 w-full md:w-1/2">
|
||||
<div className="w-full rounded-md">
|
||||
<div className="relative w-full aspect-[137/110]">
|
||||
<Image
|
||||
src="/images/career/3.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-6 mt-6">
|
||||
<div className="w-full rounded-md">
|
||||
<div className="relative w-full aspect-[142/189]">
|
||||
<Image
|
||||
src="/images/career/4.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full rounded-md">
|
||||
<div className="relative w-full aspect-[142/189]">
|
||||
<Image
|
||||
src="/images/career/5.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full rounded-md mt-6">
|
||||
<div className="relative w-full aspect-[16/9]">
|
||||
<Image
|
||||
src="/images/career/6.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
<SectionContainer>
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl tracking-[-1.5px]">
|
||||
Human powered
|
||||
>
|
||||
<Globe />
|
||||
</div>
|
||||
<div className="relative md:col-span-3">
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl max-w-[300px] md:max-w-xs tracking-[-1.5px]">
|
||||
We work together, wherever we are
|
||||
</h2>
|
||||
<p className="text-foreground-lighter text-xs sm:text-sm lg:text-base pt-3 sm:w-3/5 lg:max-w-sm">
|
||||
As a completely remote and asynchronous team, we focus on these five traits to
|
||||
keep our team effective:
|
||||
<p className="text-foreground-light mt-4 text-xs sm:text-sm md:text-base md:w-full">
|
||||
Working in a globally distributed team is rewarding but has its challenges. We are
|
||||
across many different timezones, so we use tools like Notion, Slack, and Discord
|
||||
to stay connected to our team, and our community.
|
||||
</p>
|
||||
<div className="grid pt-10 gap-8 grid-cols-2 md:grid-cols-3 lg:gap-16 lg:grid-cols-5">
|
||||
{career.humanPowered.map(
|
||||
(human: { icon: string; title: string; text: string }, i: number) => {
|
||||
return (
|
||||
<div key={i} className="flex flex-col gap-3">
|
||||
<div>
|
||||
<h2 className="text-base">{human.title}</h2>
|
||||
<p className="text-foreground-light text-xs lg:text-sm">{human.text}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
<SectionContainer className="!pb-0">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl max-w-[300px] xl:max-w-none mx-auto tracking-[-1.5px]">
|
||||
1,000 + Contributors building Supabase
|
||||
<div className="max-w-[300px] sm:max-w-md md:max-w-md mt-20">
|
||||
<div className="border-t-2 border-brand w-4/12"></div>
|
||||
<h2 className="text-2xl sm:text-3xl md:text-4xl pt-2 tracking-[-1.5px]">
|
||||
We deeply believe in the efficacy of collaborative open source
|
||||
</h2>
|
||||
<p className="text-foreground-light text-xs sm:text-sm lg:text-base sm:max-w-lg lg:max-w-2xl mx-auto pt-3">
|
||||
We're building a community of communities, bringing together developers from
|
||||
many different backgrounds, as well as new developers looking to get involved
|
||||
with open source. We love celebrating everyone who contributes their time to the
|
||||
Supabase mission.
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-[1080px] h-[370px] mx-auto sm:mt-10 md:mt-16 lg:mt-28 2xl:mt-60">
|
||||
{contributors.map((contributor: any, i: number) => {
|
||||
return (
|
||||
<div
|
||||
className={`${
|
||||
Styles[`contributors-${i}`]
|
||||
} absolute w-12 h-12 md:w-14 md:h-14 lg:w-16 lg:h-16 rounded-full border-[1.5px] border-default z-10
|
||||
transition-all hover:scale-105 drop-shadow-sm hover:drop-shadow-md
|
||||
`}
|
||||
key={i}
|
||||
>
|
||||
<Link href={contributor.html_url} target="_blank">
|
||||
<div className="relative w-full h-full">
|
||||
<Image
|
||||
src={contributor.avatar_url}
|
||||
alt={`${contributor.login} github avatar`}
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-full object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<div
|
||||
className={`${Styles['contributors-bg-circle']} w-[100%] lg:w-[80%] left-[0%] lg:left-[10%] -bottom-[30%] xs:-bottom-[36%] sm:-bottom-[52%] md:-bottom-[64%] lg:-bottom-[80%] xl:-bottom-[100%]`}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full bg-alternative rounded-full p-4"></div>
|
||||
</div>
|
||||
<div
|
||||
className={`${Styles['contributors-bg-circle']} w-[80%] lg:w-[60%] left-[10%] lg:left-[20%] -bottom-[25%] xs:-bottom-[30%] sm:-bottom-[44%] md:-bottom-[54%] lg:-bottom-[60%] xl:-bottom-[75%]`}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full bg-alternative rounded-full p-4"></div>
|
||||
</div>
|
||||
<div
|
||||
className={`${Styles['contributors-bg-circle']} w-[60%] lg:w-[40%] left-[20%] lg:left-[30%] -bottom-[20%] xs:-bottom-[25%] sm:-bottom-[38%] md:-bottom-[44%] lg:-bottom-[40%] xl:-bottom-[50%]`}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full bg-alternative rounded-full p-4"></div>
|
||||
</div>
|
||||
<div
|
||||
className={`${Styles['contributors-bg-circle']} w-[40%] lg:w-[20%] left-[30%] lg:left-[40%] -bottom-[15%] xs:-bottom-[19%] sm:-bottom-[30%] md:-bottom-[34%] lg:-bottom-[20%] xl:-bottom-[25%]`}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full bg-alternative rounded-full p-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionContainer>
|
||||
<div className="xl:flex lg:items-start xl:gap-10 justify-between">
|
||||
<div className="xl:min-w-[300px] xl:max-w-[400px]">
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl max-w-[280px] sm:max-w-xs xl:max-w-none tracking-[-1.5px]">
|
||||
Great people deserve great benefits
|
||||
</h2>
|
||||
</div>
|
||||
<div className="mt-12 xl:mt-0 space-y-6 lg:space-y-0 sm:w-fit sm:mx-auto lg:grid lg:grid-cols-2 lg:gap-16">
|
||||
{career.benefits.map(
|
||||
(benefits: { icon: string; title: string; text: string }, i: number) => {
|
||||
return (
|
||||
<div className="h-full flex items-start space-x-6 w-full" key={i}>
|
||||
<div className="h-fit text-sm lg:text-base">
|
||||
<h2 className="text-sm">{benefits.title}</h2>
|
||||
<ReactMarkdown className="prose pt-1 text-sm">
|
||||
{benefits.text}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
</SectionContainer>
|
||||
|
||||
<SectionContainer>
|
||||
<div className="text-center sm:max-w-md md:w-3/4 lg:max-w-lg xl:max-w-2xl mx-auto">
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl tracking-[-1.5px]">How we hire</h2>
|
||||
<p className="text-xs sm:text-sm lg:text-base text-foreground-light pt-3">
|
||||
The entire process is fully remote and all communication happens over email or via
|
||||
video chat in Google Meet. The calls are all 1:1 and usually take between 20-45
|
||||
minutes. We know you are interviewing us too, so please ask questions. We are happy
|
||||
to answer.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-16 md:ml-36 lg:flex lg:items-start lg:w-fit lg:mx-auto">
|
||||
{career.hiring.map((hiring: { title: string; text: string }, i: number) => {
|
||||
return (
|
||||
<div
|
||||
key={i + 1}
|
||||
className="flex lg:block items-start space-x-6 lg:space-x-0 lg:w-full"
|
||||
>
|
||||
<div className="lg:flex items-center">
|
||||
<h3 className="bg-brand-400 border-[1px] border-brand-300 text-brand-600 text-md text-center w-[44px] px-2 py-1.5 rounded-md">
|
||||
{i + 1}
|
||||
</h3>
|
||||
<div className="h-[100px] w-[1px] sm:h-[100px] mx-auto lg:h-[1px] lg:w-full bg-brand-500 lg:pr-6"></div>
|
||||
</div>
|
||||
<div className="lg:mt-6">
|
||||
<h2 className="sm:text-lg max-w-[75%] xl:max-w-none xl:w-11/12 lg:max-w-none">
|
||||
{hiring.title}
|
||||
</h2>
|
||||
<p className="text-foreground-light text-xs sm:text-sm mt-1 md:w-3/4 lg:w-11/12">
|
||||
{hiring.text}
|
||||
</p>
|
||||
<SectionContainer className="-mt-16 md:mt-16">
|
||||
<div className="md:flex md:gap-6">
|
||||
<div className="md:w-1/2">
|
||||
<div>
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl tracking-[-1.5px]">
|
||||
What is Supabase
|
||||
</h2>
|
||||
<p className="text-foreground-light text-xs sm:text-sm lg:text-base pt-2 sm:max-w-md xl:max-w-lg">
|
||||
Supabase is an open source Firebase alternative, built by developers for
|
||||
developers. Supabase adds auth, realtime, storage, restful APIs, and edge
|
||||
functions to Postgres without a single line of code. Supabase was born-remote.
|
||||
Having a globally distributed, open source company is our secret weapon to
|
||||
hiring top-tier talent.
|
||||
</p>
|
||||
</div>
|
||||
<div className="md:w-full rounded-md mt-10 md:mt-36 lg:mt-40">
|
||||
<div className="relative w-full aspect-[148/125]">
|
||||
<Image
|
||||
src="/images/career/1.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<h3 className="bg-brand-400 border-[1px] border-brand-300 text-brand-600 text-xl w-[44px] lg:min-w-[40px] min-h-[40px] px-2 py-1 rounded-md grid justify-items-center items-center">
|
||||
<Check />
|
||||
</h3>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
<div className="grid justify-items-end">
|
||||
<div className="w-full md:w-5/6 rounded-md mt-6">
|
||||
<div className="relative w-full aspect-[29/22]">
|
||||
<Image
|
||||
src="/images/career/2.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 md:mt-0 w-full md:w-1/2">
|
||||
<div className="w-full rounded-md">
|
||||
<div className="relative w-full aspect-[137/110]">
|
||||
<Image
|
||||
src="/images/career/3.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-6 mt-6">
|
||||
<div className="w-full rounded-md">
|
||||
<div className="relative w-full aspect-[142/189]">
|
||||
<Image
|
||||
src="/images/career/4.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full rounded-md">
|
||||
<div className="relative w-full aspect-[142/189]">
|
||||
<Image
|
||||
src="/images/career/5.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full rounded-md mt-6">
|
||||
<div className="relative w-full aspect-[16/9]">
|
||||
<Image
|
||||
src="/images/career/6.jpg"
|
||||
alt="team photo"
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-md object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div id="positions" className="max-w-6xl mx-auto">
|
||||
<SectionContainer>
|
||||
<h2 className="text-xl sm:text-3xl xl:text-3xl tracking-[-1.5px] mb-3">
|
||||
Open positions
|
||||
</h2>
|
||||
<p className="max-w-xl text-foreground-lighter">
|
||||
Want to build the best developer platform?
|
||||
<br /> We’d love to talk to you.
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl tracking-[-1.5px]">Human powered</h2>
|
||||
<p className="text-foreground-lighter text-xs sm:text-sm lg:text-base pt-3 sm:w-3/5 lg:max-w-sm">
|
||||
As a completely remote and asynchronous team, we focus on these five traits to keep
|
||||
our team effective:
|
||||
</p>
|
||||
<div className="mt-10 -space-y-px">
|
||||
{jobs.map(
|
||||
(
|
||||
job: {
|
||||
title: string
|
||||
location: any
|
||||
employment: string
|
||||
description: string
|
||||
absolute_url: string
|
||||
},
|
||||
i: number
|
||||
) => {
|
||||
<div className="grid pt-10 gap-8 grid-cols-2 md:grid-cols-3 lg:gap-16 lg:grid-cols-5">
|
||||
{career.humanPowered.map(
|
||||
(human: { icon: string; title: string; text: string }, i: number) => {
|
||||
return (
|
||||
<Link
|
||||
href={job.absolute_url}
|
||||
key={i}
|
||||
className="
|
||||
first-of-type:rounded-t-md last-of-type:rounded-b-md
|
||||
cursor-pointer md:cursor-default bg-surface-75 border border-muted drop-shadow-sm p-4 px-7
|
||||
flex flex-col md:flex-row
|
||||
md:items-center
|
||||
transition hover:bg-surface-100
|
||||
hover:cursor-pointer"
|
||||
>
|
||||
<h2 className="text-base min-w-[240px] lg:min-w-[316px] sm:truncate mr-6">
|
||||
{job.title}
|
||||
</h2>
|
||||
<div className="flex justify-between justify-[normal] pt-2 md:pt-0 w-full items-center">
|
||||
<div className="flex items-center space-x-4">
|
||||
<Badge
|
||||
className="bg-surface-200 bg-opacity-100 border-muted"
|
||||
variant={'default'}
|
||||
>
|
||||
<GlobeAltIcon className="w-3 h-3" />
|
||||
|
||||
<span className="ml-1">{job.location.name}</span>
|
||||
</Badge>
|
||||
<span className="hidden md:block">{job.employment}</span>
|
||||
</div>
|
||||
<p className="hidden lg:block lg:text-sm">{job.description}</p>
|
||||
<div
|
||||
className={cn(
|
||||
buttonVariants({ type: 'default', size: 'tiny' }),
|
||||
'rounded-full'
|
||||
)}
|
||||
>
|
||||
Apply for position
|
||||
</div>
|
||||
<div key={i} className="flex flex-col gap-3">
|
||||
<div>
|
||||
<h2 className="text-base">{human.title}</h2>
|
||||
<p className="text-foreground-light text-xs lg:text-sm">{human.text}</p>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
<SectionContainer className="!pb-0">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl max-w-[300px] xl:max-w-none mx-auto tracking-[-1.5px]">
|
||||
1,000 + Contributors building Supabase
|
||||
</h2>
|
||||
<p className="text-foreground-light text-xs sm:text-sm lg:text-base sm:max-w-lg lg:max-w-2xl mx-auto pt-3">
|
||||
We're building a community of communities, bringing together developers from many
|
||||
different backgrounds, as well as new developers looking to get involved with open
|
||||
source. We love celebrating everyone who contributes their time to the Supabase
|
||||
mission.
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-[1080px] h-[370px] mx-auto sm:mt-10 md:mt-16 lg:mt-28 2xl:mt-60">
|
||||
{contributors.map((contributor: any, i: number) => {
|
||||
return (
|
||||
<div
|
||||
className={`${
|
||||
Styles[`contributors-${i}`]
|
||||
} absolute w-12 h-12 md:w-14 md:h-14 lg:w-16 lg:h-16 rounded-full border-[1.5px] border-default z-10
|
||||
transition-all hover:scale-105 drop-shadow-sm hover:drop-shadow-md
|
||||
`}
|
||||
key={i}
|
||||
>
|
||||
<Link href={contributor.html_url} target="_blank">
|
||||
<div className="relative w-full h-full">
|
||||
<Image
|
||||
src={contributor.avatar_url}
|
||||
alt={`${contributor.login} github avatar`}
|
||||
fill
|
||||
sizes="(min-width: 767px) 45vw, 100vw"
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
className="rounded-full object-cover"
|
||||
draggable={false}
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<div
|
||||
className={`${Styles['contributors-bg-circle']} w-[100%] lg:w-[80%] left-[0%] lg:left-[10%] -bottom-[30%] xs:-bottom-[36%] sm:-bottom-[52%] md:-bottom-[64%] lg:-bottom-[80%] xl:-bottom-[100%]`}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full bg-alternative rounded-full p-4"></div>
|
||||
</div>
|
||||
<div
|
||||
className={`${Styles['contributors-bg-circle']} w-[80%] lg:w-[60%] left-[10%] lg:left-[20%] -bottom-[25%] xs:-bottom-[30%] sm:-bottom-[44%] md:-bottom-[54%] lg:-bottom-[60%] xl:-bottom-[75%]`}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full bg-alternative rounded-full p-4"></div>
|
||||
</div>
|
||||
<div
|
||||
className={`${Styles['contributors-bg-circle']} w-[60%] lg:w-[40%] left-[20%] lg:left-[30%] -bottom-[20%] xs:-bottom-[25%] sm:-bottom-[38%] md:-bottom-[44%] lg:-bottom-[40%] xl:-bottom-[50%]`}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full bg-alternative rounded-full p-4"></div>
|
||||
</div>
|
||||
<div
|
||||
className={`${Styles['contributors-bg-circle']} w-[40%] lg:w-[20%] left-[30%] lg:left-[40%] -bottom-[15%] xs:-bottom-[19%] sm:-bottom-[30%] md:-bottom-[34%] lg:-bottom-[20%] xl:-bottom-[25%]`}
|
||||
>
|
||||
<div className="flex flex-col justify-between h-full bg-alternative rounded-full p-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionContainer>
|
||||
<div className="xl:flex lg:items-start xl:gap-10 justify-between">
|
||||
<div className="xl:min-w-[300px] xl:max-w-[400px]">
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl max-w-[280px] sm:max-w-xs xl:max-w-none tracking-[-1.5px]">
|
||||
Great people deserve great benefits
|
||||
</h2>
|
||||
</div>
|
||||
<div className="mt-12 xl:mt-0 space-y-6 lg:space-y-0 sm:w-fit sm:mx-auto lg:grid lg:grid-cols-2 lg:gap-16">
|
||||
{career.benefits.map(
|
||||
(benefits: { icon: string; title: string; text: string }, i: number) => {
|
||||
return (
|
||||
<div className="h-full flex items-start space-x-6 w-full" key={i}>
|
||||
<div className="h-fit text-sm lg:text-base">
|
||||
<h2 className="text-sm">{benefits.title}</h2>
|
||||
<ReactMarkdown className="prose pt-1 text-sm">
|
||||
{benefits.text}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
<SectionContainer>
|
||||
<div className="text-center sm:max-w-md md:w-3/4 lg:max-w-lg xl:max-w-2xl mx-auto">
|
||||
<h2 className="text-2xl sm:text-3xl xl:text-4xl tracking-[-1.5px]">How we hire</h2>
|
||||
<p className="text-xs sm:text-sm lg:text-base text-foreground-light pt-3">
|
||||
The entire process is fully remote and all communication happens over email or via
|
||||
video chat in Google Meet. The calls are all 1:1 and usually take between 20-45
|
||||
minutes. We know you are interviewing us too, so please ask questions. We are happy to
|
||||
answer.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-16 md:ml-36 lg:flex lg:items-start lg:w-fit lg:mx-auto">
|
||||
{career.hiring.map((hiring: { title: string; text: string }, i: number) => {
|
||||
return (
|
||||
<div
|
||||
key={i + 1}
|
||||
className="flex lg:block items-start space-x-6 lg:space-x-0 lg:w-full"
|
||||
>
|
||||
<div className="lg:flex items-center">
|
||||
<h3 className="bg-brand-400 border-[1px] border-brand-300 text-brand-600 text-md text-center w-[44px] px-2 py-1.5 rounded-md">
|
||||
{i + 1}
|
||||
</h3>
|
||||
<div className="h-[100px] w-[1px] sm:h-[100px] mx-auto lg:h-[1px] lg:w-full bg-brand-500 lg:pr-6"></div>
|
||||
</div>
|
||||
<div className="lg:mt-6">
|
||||
<h2 className="sm:text-lg max-w-[75%] xl:max-w-none xl:w-11/12 lg:max-w-none">
|
||||
{hiring.title}
|
||||
</h2>
|
||||
<p className="text-foreground-light text-xs sm:text-sm mt-1 md:w-3/4 lg:w-11/12">
|
||||
{hiring.text}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<h3 className="bg-brand-400 border-[1px] border-brand-300 text-brand-600 text-xl w-[44px] lg:min-w-[40px] min-h-[40px] px-2 py-1 rounded-md grid justify-items-center items-center">
|
||||
<Check />
|
||||
</h3>
|
||||
</div>
|
||||
</SectionContainer>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div id="positions" className="max-w-6xl mx-auto">
|
||||
<SectionContainer>
|
||||
<h2 className="text-xl sm:text-3xl xl:text-3xl tracking-[-1.5px] mb-3">
|
||||
Open positions
|
||||
</h2>
|
||||
<p className="max-w-xl text-foreground-lighter">
|
||||
Want to build the best developer platform?
|
||||
<br /> We’d love to talk to you.
|
||||
</p>
|
||||
<div className="mt-10 flex flex-col gap-4">
|
||||
{Object.entries(jobs).map(([team, teamJobs]) => (
|
||||
<div key={team}>
|
||||
<h4 className="text-foreground-lighter text-sm">{team}</h4>
|
||||
<div className="mt-2 -space-y-px">
|
||||
{(teamJobs as JobItemProps[])
|
||||
.filter((job: any) => !filterGenericJob(job))
|
||||
.map((job: JobItemProps) => (
|
||||
<JobItem job={job} key={job.id} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="pt-4 mt-4 border-t border-muted -space-y-px">
|
||||
{placeholderJob && <JobItem job={placeholderJob} />}
|
||||
</div>
|
||||
</SectionContainer>
|
||||
</div>
|
||||
</DefaultLayout>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const JobItem: React.FC<{ job: JobItemProps }> = ({ job }) => {
|
||||
const isPlaceholderJob = job.id === PLACEHOLDER_JOB_ID
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={job.jobUrl}
|
||||
className="
|
||||
first-of-type:rounded-t-md last-of-type:rounded-b-md
|
||||
cursor-pointer md:cursor-default bg-surface-75 border border-muted drop-shadow-sm p-4 px-7
|
||||
flex flex-col md:flex-row
|
||||
md:items-center
|
||||
transition hover:bg-surface-100
|
||||
hover:cursor-pointer
|
||||
"
|
||||
target="_blank"
|
||||
>
|
||||
<h2 className="text-base min-w-[240px] lg:min-w-[316px] sm:truncate mr-6">{job.title}</h2>
|
||||
<div className="flex justify-between justify-[normal] pt-2 md:pt-0 w-full items-center">
|
||||
<div className="flex items-center gap-4">
|
||||
<Badge>
|
||||
<GlobeAltIcon className="w-3 h-3" />
|
||||
<span className="ml-1">{job.location}</span>
|
||||
</Badge>
|
||||
<span className="hidden md:block">{job.employment}</span>
|
||||
</div>
|
||||
<div className={cn(buttonVariants({ type: 'default', size: 'tiny' }), 'rounded-full')}>
|
||||
{isPlaceholderJob ? 'Submit resume' : 'Apply for position'}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default CareerPage
|
||||
@@ -2,19 +2,20 @@ import { type CodeHikeConfig, remarkCodeHike } from '@code-hike/mdx'
|
||||
import { CH } from '@code-hike/mdx/components'
|
||||
import { ChevronLeft, ExternalLink } from 'lucide-react'
|
||||
import { type GetStaticPaths, type GetStaticProps } from 'next'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { MDXRemote, type MDXRemoteSerializeResult } from 'next-mdx-remote'
|
||||
import { serialize } from 'next-mdx-remote/serialize'
|
||||
import { NextSeo } from 'next-seo'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { type Dispatch, type SetStateAction, useState } from 'react'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||
import 'swiper/css'
|
||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||
|
||||
import { useBreakpoint } from 'common'
|
||||
import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' }
|
||||
import { Admonition, Button } from 'ui'
|
||||
import { Button } from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
import { ExpandableVideo } from 'ui-patterns/ExpandableVideo'
|
||||
|
||||
import ImageModal from '~/components/ImageModal'
|
||||
|
||||
Generated
+74
-13
@@ -31,6 +31,7 @@
|
||||
"apps/design-system": {
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@radix-ui/react-alert-dialog": "^1.0.5",
|
||||
"contentlayer2": "0.4.6",
|
||||
"eslint-config-supabase": "*",
|
||||
@@ -41,20 +42,26 @@
|
||||
"markdown-wasm": "^1.2.0",
|
||||
"next": "^14.2.10",
|
||||
"next-contentlayer2": "0.4.6",
|
||||
"next-themes": "^0.3.0",
|
||||
"react": "^18.2.0",
|
||||
"react-docgen": "^7.0.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-inlinesvg": "^4.0.4",
|
||||
"react-wrap-balancer": "^1.1.0",
|
||||
"recharts": "^2.12.7",
|
||||
"rehype-autolink-headings": "^7.1.0",
|
||||
"rehype-pretty-code": "^0.6.0",
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark": "^14.0.3",
|
||||
"remark-code-import": "^1.2.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"sonner": "^1.5.0",
|
||||
"ts-morph": "^22.0.0",
|
||||
"ui": "*",
|
||||
"unist-util-visit": "^5.0.0"
|
||||
"ui-patterns": "*",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@shikijs/compat": "^1.1.7",
|
||||
@@ -70,7 +77,7 @@
|
||||
"shiki": "^1.1.7",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"tsconfig": "*",
|
||||
"typescript": "^5.5.0",
|
||||
"typescript": "~5.5.0",
|
||||
"unist-builder": "3.0.0"
|
||||
}
|
||||
},
|
||||
@@ -860,12 +867,14 @@
|
||||
"@octokit/graphql": "^7.0.2",
|
||||
"@octokit/plugin-paginate-graphql": "^4.0.0",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"@supabase/auth-helpers-react": "^0.4.2",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tanstack/react-query": "^5.13.4",
|
||||
"acorn": "^8.11.3",
|
||||
"acorn-typescript": "^1.4.13",
|
||||
"ai-commands": "*",
|
||||
"common": "*",
|
||||
"common-tags": "^1.8.2",
|
||||
"config": "*",
|
||||
@@ -874,8 +883,10 @@
|
||||
"github-slugger": "^2.0.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"hast-util-has-property": "^2.0.1",
|
||||
"hast-util-to-html": "^9.0.0",
|
||||
"icons": "*",
|
||||
"isbot": "^5.1.2",
|
||||
"js-yaml": "^3.14.1",
|
||||
"jsrsasign": "^11.0.0",
|
||||
"katex": "^0.16.10",
|
||||
"lodash": "^4.17.21",
|
||||
@@ -885,6 +896,8 @@
|
||||
"mdast-util-from-markdown": "^1.2.0",
|
||||
"mdast-util-gfm": "^2.0.2",
|
||||
"mdast-util-mdx": "^2.0.0",
|
||||
"mdast-util-mdx-jsx": "^2.0.0",
|
||||
"mdast-util-to-hast": "^12.3.0",
|
||||
"mdast-util-to-markdown": "^1.5.0",
|
||||
"mdast-util-to-string": "^3.1.1",
|
||||
"micromark-extension-gfm": "^2.0.3",
|
||||
@@ -897,10 +910,12 @@
|
||||
"openai": "^4.20.1",
|
||||
"openapi-fetch": "^0.8.2",
|
||||
"react": "^18.2.0",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.12",
|
||||
"react-intersection-observer": "^9.5.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-use": "^17.5.0",
|
||||
"rehype-katex": "^7.0.0",
|
||||
"rehype-slug": "^5.1.0",
|
||||
"remark": "^14.0.2",
|
||||
@@ -915,16 +930,21 @@
|
||||
"unist-builder": "^3.0.1",
|
||||
"unist-util-filter": "^4.0.1",
|
||||
"unist-util-visit": "^4.1.2",
|
||||
"unist-util-visit-parents": "^5.0.0",
|
||||
"uuid": "^9.0.1",
|
||||
"valtio": "^1.12.0",
|
||||
"yaml": "^2.4.5"
|
||||
"yaml": "^2.4.5",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aws-sdk/client-secrets-manager": "^3.410.0",
|
||||
"@types/estree": "1.0.5",
|
||||
"@types/hast": "^2.3.4",
|
||||
"@types/jsrsasign": "^10.5.12",
|
||||
"@types/mdast": "^3.0.0",
|
||||
"@types/node": "^20.11.16",
|
||||
"@types/react": "^18.2.24",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
"@types/unist": "^2.0.6",
|
||||
"api-types": "*",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
@@ -939,7 +959,7 @@
|
||||
"slugify": "^1.6.6",
|
||||
"tsconfig": "*",
|
||||
"tsx": "^4.6.2",
|
||||
"typescript": "^5.5.0",
|
||||
"typescript": "~5.5.0",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
"vitest": "^2.0.2"
|
||||
}
|
||||
@@ -1793,6 +1813,7 @@
|
||||
"@hcaptcha/react-hcaptcha": "^1.8.1",
|
||||
"@headlessui/react": "^1.7.17",
|
||||
"@heroicons/react": "^2.1.3",
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@next/bundle-analyzer": "^14.2.3",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
@@ -1801,7 +1822,9 @@
|
||||
"@stripe/react-stripe-js": "^2.5.0",
|
||||
"@stripe/stripe-js": "^3.0.5",
|
||||
"@supabase/auth-helpers-react": "^0.4.2",
|
||||
"@supabase/auth-js": "2.64.2",
|
||||
"@supabase/pg-meta": "*",
|
||||
"@supabase/realtime-js": "2.10.2",
|
||||
"@supabase/shared-types": "0.1.70",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@tanstack/react-query": "4.35.7",
|
||||
@@ -1818,6 +1841,7 @@
|
||||
"config": "*",
|
||||
"configcat-js": "^7.0.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"dnd-core": "^16.0.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"framer-motion": "^11.0.3",
|
||||
"generate-password-browser": "^1.1.0",
|
||||
@@ -1829,6 +1853,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.436.0",
|
||||
"markdown-table": "^3.0.3",
|
||||
"memoize-one": "^5.0.1",
|
||||
"mime-db": "^1.53.0",
|
||||
"mobx": "^6.10.2",
|
||||
"mobx-react-lite": "^4.0.5",
|
||||
@@ -1846,6 +1871,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-contexify": "^5.0.0",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
"react-csv": "^2.0.3",
|
||||
"react-data-grid": "7.0.0-beta.41",
|
||||
"react-datepicker": "^4.18.0",
|
||||
@@ -1854,18 +1880,22 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.13",
|
||||
"react-grid-layout": "^1.4.2",
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-inlinesvg": "^4.0.4",
|
||||
"react-intersection-observer": "^9.5.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-simple-maps": "4.0.0-beta.6",
|
||||
"react-tracked": "^1.7.11",
|
||||
"react-use": "^17.5.0",
|
||||
"react-virtualized-auto-sizer": "^1.0.20",
|
||||
"react-window": "^1.8.6",
|
||||
"react-window-infinite-loader": "^1.0.7",
|
||||
"reactflow": "^11.10.1",
|
||||
"recharts": "^2.8.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"semver": "^6.3.1",
|
||||
"shared-data": "*",
|
||||
"sonner": "^1.5.0",
|
||||
"sql-formatter": "^13.1.0",
|
||||
"sqlstring": "^2.3.2",
|
||||
"tus-js-client": "^4.1.0",
|
||||
@@ -1877,6 +1907,7 @@
|
||||
"vitest": "^1.6.0",
|
||||
"yup": "^1.4.0",
|
||||
"yup-password": "^0.3.0",
|
||||
"zod": "^3.22.4",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -1899,6 +1930,7 @@
|
||||
"@types/randombytes": "^2.0.3",
|
||||
"@types/react": "^18.2.24",
|
||||
"@types/react-beautiful-dnd": "^13.1.2",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
"@types/react-csv": "^1.1.2",
|
||||
"@types/react-datepicker": "^4.3.4",
|
||||
"@types/react-dom": "^18.2.8",
|
||||
@@ -1925,7 +1957,7 @@
|
||||
"prettier": "^4.0.0-alpha.8",
|
||||
"storybook-dark-mode": "^3.0.1",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
}
|
||||
},
|
||||
"apps/studio/node_modules/@heroicons/react": {
|
||||
@@ -2971,15 +3003,19 @@
|
||||
"@octokit/graphql": "^7.0.2",
|
||||
"@octokit/plugin-paginate-graphql": "^4.0.0",
|
||||
"@octokit/rest": "^20.0.2",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@react-three/fiber": "^7.0.29",
|
||||
"@supabase/auth-helpers-react": "^0.4.2",
|
||||
"@supabase/auth-ui-react": "^0.4.5",
|
||||
"@supabase/supabase-js": "^2.44.3",
|
||||
"@vercel/og": "^0.6.2",
|
||||
"ai-commands": "*",
|
||||
"animejs": "^3.2.2",
|
||||
"classnames": "^2.3.1",
|
||||
"clsx": "^1.2.1",
|
||||
"cobe": "^0.6.2",
|
||||
"common": "*",
|
||||
"common-tags": "^1.8.2",
|
||||
"config": "*",
|
||||
"contentlayer2": "0.4.6",
|
||||
"dat.gui": "^0.7.9",
|
||||
@@ -2989,6 +3025,7 @@
|
||||
"globby": "^13.2.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
"icons": "*",
|
||||
"lodash": "^4.0.0",
|
||||
"lucide-react": "*",
|
||||
"markdown-toc": "^1.2.0",
|
||||
"next": "^14.2.10",
|
||||
@@ -2996,6 +3033,7 @@
|
||||
"next-mdx-remote": "^4.4.1",
|
||||
"next-seo": "^6.5.0",
|
||||
"next-themes": "^0.3.0",
|
||||
"openai": "^4.20.1",
|
||||
"parse-numeric-range": "^1.3.0",
|
||||
"react": "^18.2.0",
|
||||
"react-copy-to-clipboard": "^5.1.0",
|
||||
@@ -3015,7 +3053,7 @@
|
||||
"swiper": "^11.0.7",
|
||||
"three": "^0.136.0",
|
||||
"typed.js": "^2.0.16",
|
||||
"typescript": "^5.5.0",
|
||||
"typescript": "~5.5.0",
|
||||
"ui": "*",
|
||||
"ui-patterns": "*",
|
||||
"use-debounce": "^7.0.1",
|
||||
@@ -3025,7 +3063,9 @@
|
||||
"devDependencies": {
|
||||
"@types/animejs": "^3.1.12",
|
||||
"@types/classnames": "^2.3.1",
|
||||
"@types/common-tags": "^1.8.4",
|
||||
"@types/dat.gui": "^0.7.10",
|
||||
"@types/lodash": "^4.0.0",
|
||||
"@types/mdx-js__react": "^1.5.6",
|
||||
"@types/node": "^20.11.16",
|
||||
"@types/parse-numeric-range": "^0.0.1",
|
||||
@@ -43303,7 +43343,7 @@
|
||||
"sql-formatter": "^15.0.2",
|
||||
"ts-jest": "^29.1.1",
|
||||
"tsconfig": "*",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
}
|
||||
},
|
||||
"packages/ai-commands/node_modules/argparse": {
|
||||
@@ -43408,10 +43448,11 @@
|
||||
"react-use": "^17.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "4.17.5",
|
||||
"@types/react": "^18.2.24",
|
||||
"@types/react-dom": "^18.2.8",
|
||||
"tsconfig": "*",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@supabase/auth-js": "^2.63.0",
|
||||
@@ -43464,7 +43505,13 @@
|
||||
"packages/icons": {
|
||||
"dependencies": {
|
||||
"@supabase/build-icons": "*",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.24"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"packages/pg-meta": {
|
||||
@@ -43475,7 +43522,7 @@
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
}
|
||||
},
|
||||
"packages/shared-data": {
|
||||
@@ -43498,6 +43545,7 @@
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"@radix-ui/react-context": "^1.0.1",
|
||||
"@radix-ui/react-context-menu": "^2.1.5",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||
@@ -43577,6 +43625,7 @@
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@tokens-studio/sd-transforms": "^0.8.5",
|
||||
"@types/common-tags": "^1.8.1",
|
||||
"@types/lodash": "4.17.5",
|
||||
"@types/react": "^18.2.24",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
"@types/react-dom": "^18.2.8",
|
||||
@@ -43592,7 +43641,8 @@
|
||||
"ts-jest": "^29.1.1",
|
||||
"tsconfig": "*",
|
||||
"tsconfig-paths-webpack-plugin": "^4.0.1",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "*",
|
||||
@@ -43603,8 +43653,11 @@
|
||||
"packages/ui-patterns": {
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@supabase/sql-to-rest": "^0.1.6",
|
||||
"class-variance-authority": "^0.6.0",
|
||||
"clsx": "^1.2.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"common": "*",
|
||||
"common-tags": "^1.8.2",
|
||||
@@ -43614,18 +43667,24 @@
|
||||
"lucide-react": "*",
|
||||
"monaco-editor": "*",
|
||||
"next-themes": "*",
|
||||
"openai": "^4.20.1",
|
||||
"prism-react-renderer": "^2.3.1",
|
||||
"react-error-boundary": "^4.0.12",
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-intersection-observer": "^9.8.2",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-tooltip": "*",
|
||||
"react-use": "^17.5.0",
|
||||
"reactflow": "*",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"sonner": "^1.5.0",
|
||||
"sql-formatter": "^15.3.1",
|
||||
"sse.js": "^2.2.0",
|
||||
"tsconfig": "*",
|
||||
"ui": "*",
|
||||
"valtio": "*"
|
||||
"valtio": "*",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@supabase/auth-helpers-react": "^0.4.2",
|
||||
@@ -43639,6 +43698,8 @@
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"api-types": "*",
|
||||
"next-router-mock": "^0.9.13",
|
||||
"typescript": "~5.5.0",
|
||||
"vite": "^5.2.14",
|
||||
"vitest": "^2.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -44755,7 +44816,7 @@
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"postgres": "^3.0.5",
|
||||
"ts-jest": "^29.1.1",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
}
|
||||
},
|
||||
"tests/node_modules/@testdeck/core": {
|
||||
|
||||
@@ -34,6 +34,6 @@
|
||||
"sql-formatter": "^15.0.2",
|
||||
"ts-jest": "^29.1.1",
|
||||
"tsconfig": "*",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
}
|
||||
}
|
||||
@@ -136,8 +136,8 @@ export const CLIENT_LIBRARIES = [
|
||||
url: 'https://github.com/supabase-community/supabase-kt/tree/master/Postgrest',
|
||||
},
|
||||
{
|
||||
name: 'gotrue-kt',
|
||||
url: 'https://github.com/supabase-community/supabase-kt/tree/master/GoTrue',
|
||||
name: 'auth-kt',
|
||||
url: 'https://github.com/supabase-community/supabase-kt/tree/master/Auth',
|
||||
},
|
||||
{
|
||||
name: 'storage-kt',
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
"react-use": "^17.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "4.17.5",
|
||||
"@types/react": "^18.2.24",
|
||||
"@types/react-dom": "^18.2.8",
|
||||
"tsconfig": "*",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@supabase/supabase-js": "*",
|
||||
|
||||
@@ -5,7 +5,13 @@
|
||||
"build:icons": "build-icons --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --iconFileExtension=.ts --exportFileName=index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"typescript": "^5.5.0",
|
||||
"typescript": "~5.5.0",
|
||||
"@supabase/build-icons": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.24"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,6 @@
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
import { hover } from '@testing-library/user-event/dist/hover'
|
||||
import { drop } from 'lodash'
|
||||
import Image from 'next/image'
|
||||
import xl from 'react-syntax-highlighter/dist/esm/languages/hljs/xl'
|
||||
import { cn } from 'ui/src/lib/utils'
|
||||
|
||||
interface TweetCard {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { cva } from 'class-variance-authority'
|
||||
import React, { forwardRef } from 'react'
|
||||
import { cn } from 'ui/src/lib/utils/cn'
|
||||
import { Alert, AlertDescription, AlertTitle } from 'ui/src/components/shadcn/ui/alert'
|
||||
import { forwardRef } from 'react'
|
||||
import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, cn } from 'ui'
|
||||
|
||||
export interface AdmonitionProps {
|
||||
type:
|
||||
@@ -18,8 +17,8 @@ export interface AdmonitionProps {
|
||||
description?: string | React.ReactNode
|
||||
showIcon?: boolean
|
||||
childProps?: {
|
||||
title?: React.ComponentProps<typeof AlertTitle>
|
||||
description?: React.ComponentProps<typeof AlertDescription>
|
||||
title?: React.ComponentProps<typeof AlertTitle_Shadcn_>
|
||||
description?: React.ComponentProps<typeof AlertDescription_Shadcn_>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +87,8 @@ const admonitionBase = cva('', {
|
||||
})
|
||||
|
||||
export const Admonition = forwardRef<
|
||||
React.ElementRef<typeof Alert>,
|
||||
React.ComponentPropsWithoutRef<typeof Alert> & AdmonitionProps
|
||||
React.ElementRef<typeof Alert_Shadcn_>,
|
||||
React.ComponentPropsWithoutRef<typeof Alert_Shadcn_> & AdmonitionProps
|
||||
>(
|
||||
(
|
||||
{ type = 'note', variant, showIcon = true, label, title, description, children, ...props },
|
||||
@@ -98,7 +97,7 @@ export const Admonition = forwardRef<
|
||||
const typeMapped = variant ? admonitionToAlertMapping[variant] : admonitionToAlertMapping[type]
|
||||
|
||||
return (
|
||||
<Alert
|
||||
<Alert_Shadcn_
|
||||
ref={ref}
|
||||
variant={typeMapped}
|
||||
{...props}
|
||||
@@ -116,7 +115,7 @@ export const Admonition = forwardRef<
|
||||
)}
|
||||
{label || title ? (
|
||||
<>
|
||||
<AlertTitle
|
||||
<AlertTitle_Shadcn_
|
||||
{...props.childProps?.title}
|
||||
className={cn(
|
||||
'text mt-0.5 flex gap-3 text-sm [&_p]:mb-1.5 [&_p]:mt-0',
|
||||
@@ -125,15 +124,15 @@ export const Admonition = forwardRef<
|
||||
)}
|
||||
>
|
||||
{label || title}
|
||||
</AlertTitle>
|
||||
</AlertTitle_Shadcn_>
|
||||
{description && (
|
||||
<AlertDescription className={props.childProps?.description?.className}>
|
||||
<AlertDescription_Shadcn_ className={props.childProps?.description?.className}>
|
||||
{description}
|
||||
</AlertDescription>
|
||||
</AlertDescription_Shadcn_>
|
||||
)}
|
||||
{/* // children is to handle Docs and MDX issues with children and <p> elements */}
|
||||
{children && (
|
||||
<AlertDescription
|
||||
<AlertDescription_Shadcn_
|
||||
{...props.childProps?.description}
|
||||
className={cn(
|
||||
'mt-3 [&_p]:mb-1.5 [&_p]:mt-0',
|
||||
@@ -141,7 +140,7 @@ export const Admonition = forwardRef<
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</AlertDescription>
|
||||
</AlertDescription_Shadcn_>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
@@ -149,7 +148,7 @@ export const Admonition = forwardRef<
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</Alert>
|
||||
</Alert_Shadcn_>
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -1,4 +1,5 @@
|
||||
import { cva } from 'class-variance-authority'
|
||||
import { motion } from 'framer-motion'
|
||||
import React from 'react'
|
||||
import {
|
||||
FormDescription_Shadcn_,
|
||||
@@ -8,7 +9,6 @@ import {
|
||||
cn,
|
||||
} from 'ui'
|
||||
import { SIZE } from 'ui/src/lib/constants'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
|
||||
type Props = {
|
||||
align?: 'left' | 'right'
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@supabase/sql-to-rest": "^0.1.6",
|
||||
"class-variance-authority": "^0.6.0",
|
||||
"clsx": "^1.2.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"common": "*",
|
||||
"common-tags": "^1.8.2",
|
||||
@@ -21,17 +24,23 @@
|
||||
"monaco-editor": "*",
|
||||
"next-themes": "*",
|
||||
"prism-react-renderer": "^2.3.1",
|
||||
"openai": "^4.20.1",
|
||||
"react-error-boundary": "^4.0.12",
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-intersection-observer": "^9.8.2",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-tooltip": "*",
|
||||
"react-use": "^17.5.0",
|
||||
"reactflow": "*",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"sonner": "^1.5.0",
|
||||
"sql-formatter": "^15.3.1",
|
||||
"sse.js": "^2.2.0",
|
||||
"tsconfig": "*",
|
||||
"ui": "*",
|
||||
"valtio": "*"
|
||||
"valtio": "*",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@supabase/auth-helpers-react": "^0.4.2",
|
||||
@@ -45,6 +54,8 @@
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"api-types": "*",
|
||||
"next-router-mock": "^0.9.13",
|
||||
"typescript": "~5.5.0",
|
||||
"vite": "^5.2.14",
|
||||
"vitest": "^2.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -4,7 +4,6 @@ export * from './src/lib/Markdown'
|
||||
|
||||
// GENERAL
|
||||
|
||||
export * from 'ui-patterns/admonition'
|
||||
export * from './src/components/Button'
|
||||
export * from './src/components/Icon'
|
||||
export * from './src/components/Icon/IconContext'
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import type { Config } from '@jest/types'
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
preset: 'ts-jest',
|
||||
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
|
||||
testEnvironment: 'jsdom',
|
||||
// Restricting test file pattern to just tsx files since the js files need a babel preset to run
|
||||
// and most likely won't pass now anyway - the tests were ported from the UI repo and are out of date
|
||||
testRegex: '(.*\\.test.tsx$)',
|
||||
moduleNameMapper: {
|
||||
'^@ui/(.*)$': '<rootDir>/src/$1',
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -1 +0,0 @@
|
||||
import '@testing-library/jest-dom'
|
||||
@@ -12,7 +12,7 @@
|
||||
"transform-tokens": "node ./transformTokens.js",
|
||||
"extract-design-tokens": "node internals/tokens/extract-design-tokens.js",
|
||||
"generate-styles": "npm run extract-design-tokens && npm run transform-tokens && npm run cleanse-css-for-tailwind && npm run generate-demo-tailwind-classes",
|
||||
"test": "jest"
|
||||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.7.17",
|
||||
@@ -24,6 +24,7 @@
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-collapsible": "^1.0.3",
|
||||
"@radix-ui/react-context": "^1.0.1",
|
||||
"@radix-ui/react-context-menu": "^2.1.5",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||
@@ -98,11 +99,11 @@
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.4",
|
||||
"@ctrl/tinycolor": "^3.4.0",
|
||||
"@jest/types": "^29.6.0",
|
||||
"@testing-library/jest-dom": "^6.1.3",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@tokens-studio/sd-transforms": "^0.8.5",
|
||||
"@types/common-tags": "^1.8.1",
|
||||
"@types/lodash": "4.17.5",
|
||||
"@types/react": "^18.2.24",
|
||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||
"@types/react-dom": "^18.2.8",
|
||||
@@ -111,14 +112,12 @@
|
||||
"config": "*",
|
||||
"copyfiles": "^2.4.1",
|
||||
"glob": "^8.1.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"next": "*",
|
||||
"sql-formatter": "^12.2.0",
|
||||
"style-dictionary": "^3.7.1",
|
||||
"ts-jest": "^29.1.1",
|
||||
"tsconfig": "*",
|
||||
"tsconfig-paths-webpack-plugin": "^4.0.1",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "~5.5.0",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "*",
|
||||
|
||||
Loaded 100 of 122 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user