Merge branch 'dnywh/chore/polish-database-settings' into dnywh/temp/jit-prototype

This commit is contained in:
Danny White committed 2026-02-24 18:11:22 +11:00
commit 3908486d39
268 files changed
+21426 -4356

No files matched your search

+11
View File
@@ -93,6 +93,17 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"admonition-responsive": {
name: "admonition-responsive",
type: "components:example",
registryDependencies: ["admonition"],
component: React.lazy(() => import("@/registry/default/example/admonition-responsive")),
source: "",
files: ["registry/default/example/admonition-responsive.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"admonition-button": {
name: "admonition-button",
type: "components:example",
@@ -49,6 +49,18 @@ Only ever use the `primary` (green) button `type` on a `default` Admonition. Eve
className="[&_.preview>[data-orientation=vertical]]:sm:max-w-[70%]"
/>
## Responsive
{' '}
<ComponentPreview
name="admonition-responsive"
className="[&_.preview>[data-orientation=vertical]]:sm:max-w-[70%]"
/>
Reize your browser to see the button(s) change `layout` based on the Admonition’s width.
When `layout="responsive"`, the Alert root gets `@container` so the Admonition is the container-query context. The Admonition stays `vertical` when it’s narrow and switches to `horizontal` when its own width reaches the `@md` container breakpoint, independent of page width.
### Warning
<ComponentPreview
@@ -0,0 +1,14 @@
import { Button } from 'ui'
import { Admonition } from 'ui-patterns/admonition'
export default function AdmonitionDemo() {
return (
<Admonition
type="default"
layout="responsive"
title="Disk management has moved"
description="Disk management is now handled alongside Project Compute on the Compute and Disk page."
actions={<Button type="default">Go to Compute and Disk</Button>}
/>
)
}
@@ -2,22 +2,22 @@ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from 'ui'
export default function ResizableDemo() {
return (
<ResizablePanelGroup direction="horizontal" className="max-w-md rounded-lg border">
<ResizablePanel defaultSize={50}>
<ResizablePanelGroup orientation="horizontal" className="max-w-md rounded-lg border">
<ResizablePanel defaultSize="50">
<div className="flex h-[200px] items-center justify-center p-6">
<span className="font-semibold">One</span>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={50}>
<ResizablePanelGroup direction="vertical">
<ResizablePanel defaultSize={25}>
<ResizablePanel defaultSize="50">
<ResizablePanelGroup orientation="vertical">
<ResizablePanel defaultSize="25">
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Two</span>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={75}>
<ResizablePanel defaultSize="75">
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Three</span>
</div>
@@ -2,22 +2,22 @@ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from 'ui'
export default function ResizableDemo() {
return (
<ResizablePanelGroup direction="horizontal" className="max-w-md rounded-lg border">
<ResizablePanel defaultSize={50}>
<ResizablePanelGroup orientation="horizontal" className="max-w-md rounded-lg border">
<ResizablePanel defaultSize="50">
<div className="flex h-[200px] items-center justify-center p-6">
<span className="font-semibold">One</span>
</div>
</ResizablePanel>
<ResizableHandle />
<ResizablePanel defaultSize={50}>
<ResizablePanelGroup direction="vertical">
<ResizablePanel defaultSize={25}>
<ResizablePanel defaultSize="50">
<ResizablePanelGroup orientation="vertical">
<ResizablePanel defaultSize="25">
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Two</span>
</div>
</ResizablePanel>
<ResizableHandle />
<ResizablePanel defaultSize={75}>
<ResizablePanel defaultSize="75">
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Three</span>
</div>
@@ -3,16 +3,16 @@ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from 'ui'
export default function ResizableDemo() {
return (
<ResizablePanelGroup
direction="horizontal"
orientation="horizontal"
className="min-h-[200px] max-w-md rounded-lg border"
>
<ResizablePanel defaultSize={25}>
<ResizablePanel defaultSize="25">
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Sidebar</span>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={75}>
<ResizablePanel defaultSize="75">
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Content</span>
</div>
@@ -2,14 +2,17 @@ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from 'ui'
export default function ResizableDemo() {
return (
<ResizablePanelGroup direction="vertical" className="min-h-[200px] max-w-md rounded-lg border">
<ResizablePanel defaultSize={25}>
<ResizablePanelGroup
orientation="vertical"
className="min-h-[200px] max-w-md rounded-lg border"
>
<ResizablePanel defaultSize="25">
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Header</span>
</div>
</ResizablePanel>
<ResizableHandle />
<ResizablePanel defaultSize={75}>
<ResizablePanel defaultSize="75">
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Content</span>
</div>
+6
View File
@@ -13,6 +13,12 @@ export const examples: Registry = [
registryDependencies: ['admonition'],
files: ['example/admonition-demo.tsx'],
},
{
name: 'admonition-responsive',
type: 'components:example',
registryDependencies: ['admonition'],
files: ['example/admonition-responsive.tsx'],
},
{
name: 'admonition-button',
type: 'components:example',
+6 -2
View File
@@ -335,7 +335,9 @@ If your image has alternate light and dark versions, or you want to make it zoom
dark: '/docs/img/supabase-architecture.svg',
light: '/docs/img/supabase-architecture--light.svg',
}}
zoomable
width={1600}
height={767}
/>
```
@@ -345,7 +347,9 @@ If your image has alternate light and dark versions, or you want to make it zoom
dark: '/docs/img/supabase-architecture.svg',
light: '/docs/img/supabase-architecture--light.svg',
}}
zoomable
width={1600}
height={767}
/>
### Project Variables
+64
View File
@@ -0,0 +1,64 @@
'use client'
import { useTheme } from 'next-themes'
import NextImage, { ImageProps as NextImageProps } from 'next/image'
interface StaticImageData {
src: string
height: number
width: number
blurDataURL?: string
blurWidth?: number
blurHeight?: number
}
interface StaticRequire {
default: StaticImageData
}
type StaticImport = StaticRequire | StaticImageData
type SourceType =
| string
| {
dark: string | StaticImport
light: string | StaticImport
}
export interface ImageProps extends Omit<NextImageProps, 'src'> {
src: SourceType
caption?: string
containerClassName?: string
}
/**
*
* This is a shrunk version of the `ui` package Image component. Because of
* Cumulative Layout Shift caused by problems stated in this PR
* https://github.com/supabase/supabase/pull/43026/ that's affecting hash
* navigation, and the need to support captions and light/dark image versions.
*
* Ideally we should solve these issues in that component and re-use it again,
* making sure it doesn't affect other projects consuming the component.
*
*/
const Image = ({ src, alt = '', ...props }: ImageProps) => {
const { resolvedTheme } = useTheme()
const source =
typeof src === 'string' ? src : resolvedTheme?.includes('dark') ? src.dark : src.light
return (
<figure className={props.containerClassName}>
<NextImage
key={resolvedTheme}
alt={alt}
src={source}
className={props.className}
style={props.style}
{...props}
/>
{props.caption && <figcaption className="text-center">{props.caption}</figcaption>}
</figure>
)
}
export default Image
@@ -126,7 +126,9 @@ It is possible to upload more vectors to a single table if Memory allows it (for
light: '/docs/img/ai/instance-type/hnsw-dims--light.png',
dark: '/docs/img/ai/instance-type/hnsw-dims--dark.png',
}}
zoomable
width={1427}
height={862}
/>
## IVFFlat
@@ -260,7 +262,9 @@ For 1,000,000 vectors 40 probes results to accuracy of 0.98. Note that exact val
light: '/docs/img/ai/going-prod/size-to-rps--light.png',
dark: '/docs/img/ai/going-prod/size-to-rps--dark.png',
}}
zoomable
width={1427}
height={862}
/>
<Admonition type="note">
@@ -296,7 +300,9 @@ You can increase the Requests per Second by increasing `m` and `ef_construction`
light: '/docs/img/ai/going-prod/dbpedia-hnsw-build-parameters--light.png',
dark: '/docs/img/ai/going-prod/dbpedia-hnsw-build-parameters--dark.png',
}}
zoomable
width={1052}
height={796}
/>
</TabPanel>
@@ -308,7 +314,9 @@ You can increase the Requests per Second by increasing `m` and `ef_construction`
light: '/docs/img/ai/instance-type/lists-for-1m--light.png',
dark: '/docs/img/ai/instance-type/lists-for-1m--dark.png',
}}
zoomable
width={1032}
height={796}
/>
</TabPanel>
@@ -327,7 +335,9 @@ We follow techniques outlined in the [ANN Benchmarks](https://github.com/erikber
dark: '/docs/img/ai/instance-type/vecs-benchmark--dark.png',
}}
className="max-h-[650px]"
zoomable
width={1196}
height={1194}
/>
Each test is run for a minimum of 30-40 minutes. They include a series of experiments executed at different concurrency levels to measure the engine's performance under different load types. The results are then averaged.
@@ -20,7 +20,9 @@ If you've used [Vecs](/docs/guides/ai/vecs-python-client) to create 3 different
light: '/docs/img/ai/scaling/engineering-for-scale--single-database--light.png',
dark: '/docs/img/ai/scaling/engineering-for-scale--single-database--dark.png',
}}
zoomable
width={1600}
height={1145}
/>
For example, with 3 collections, called `docs`, `posts`, and `images`, we could expose the "docs" inside the public schema like this:
@@ -55,7 +57,9 @@ As you move into production, we recommend splitting your collections into separa
light: '/docs/img/ai/scaling/engineering-for-scale--with-secondaries--light.png',
dark: '/docs/img/ai/scaling/engineering-for-scale--with-secondaries--dark.png',
}}
zoomable
width={1600}
height={1641}
/>
You can use as many secondary databases as you need to manage your collections. With this architecture, you have 2 options for accessing collections within your application:
@@ -138,5 +142,7 @@ This diagram provides an example architecture that allows you to access the coll
light: '/docs/img/ai/scaling/engineering-for-scale--multi-database--light.png',
dark: '/docs/img/ai/scaling/engineering-for-scale--multi-database--dark.png',
}}
zoomable
width={1600}
height={1754}
/>
@@ -37,7 +37,9 @@ We'll be saving the Postgres documentation in Postgres, and ChatGPT will be retr
light: '/docs/img/ai/chatgpt-plugins/chatgpt-plugin-scheme--light.png',
dark: '/docs/img/ai/chatgpt-plugins/chatgpt-plugin-scheme--dark.png',
}}
zoomable
width={1196}
height={1194}
/>
### Step 1: Fork the ChatGPT Retrieval Plugin repository
+12 -4
View File
@@ -34,7 +34,9 @@ On the other hand, if you need to scale your application, you will need to [crea
light: '/docs/img/ai/going-prod/dbpedia-ivfflat-vs-hnsw-4xl--light.png',
dark: '/docs/img/ai/going-prod/dbpedia-ivfflat-vs-hnsw-4xl--dark.png',
}}
zoomable
width={1052}
height={796}
/>
## HNSW, understanding `ef_construction`, `ef_search`, and `m`
@@ -55,7 +57,9 @@ Search parameters:
light: '/docs/img/ai/going-prod/dbpedia-hnsw-build-parameters--light.png',
dark: '/docs/img/ai/going-prod/dbpedia-hnsw-build-parameters--dark.png',
}}
zoomable
width={1052}
height={796}
/>
## IVFFlat, understanding `probes` and `lists`
@@ -76,7 +80,9 @@ You can find more examples of how `lists` and `probes` constants affect accuracy
light: '/docs/img/ai/going-prod/lists-count--light.png',
dark: '/docs/img/ai/going-prod/lists-count--dark.png',
}}
zoomable
width={1467}
height={808}
/>
## Performance tips when using indexes
@@ -117,5 +123,7 @@ Or take a look at our [pgvector 0.5.0 performance](/blog/increase-performance-pg
light: '/docs/img/ai/going-prod/size-to-rps--light.png',
dark: '/docs/img/ai/going-prod/size-to-rps--dark.png',
}}
zoomable
width={1427}
height={862}
/>
@@ -81,6 +81,8 @@ Skip lists are multi-layer linked lists. The bottom layer is a regular linked li
light: '/docs/img/ai/vector-indexes/hnsw-indexes/skip-list--light.png',
dark: '/docs/img/ai/vector-indexes/hnsw-indexes/skip-list--dark.png',
}}
width={1400}
height={700}
/>
When searching for an element, the algorithm begins at the top layer and traverses its linked list horizontally. If the target element is found, the algorithm stops and returns it. Otherwise if the next element in the list is greater than the target (or `NULL`), the algorithm drops down to the next layer below. Since each layer below is less sparse than the layer above (with the bottom layer connecting all elements), the target will eventually be found. Skip lists offer O(log n) average complexity for both search and insertion/deletion.
@@ -93,7 +95,9 @@ A navigable small world (NSW) is a special type of proximity graph that also inc
alt="visual of an example navigable small world graph"
src="/docs/img/ai/vector-indexes/hnsw-indexes/nsw.png"
className="max-h-[600px] mx-auto"
zoomable
width={1016}
height={759}
/>
The “navigable” part of NSW specifically refers to the ability to logarithmically scale the greedy search algorithm on the graph, an algorithm that attempts to make only the locally optimal choice at each hop. Without this property, the graph may still be considered a small world with short paths between far-away nodes, but the greedy algorithm tends to miss them. Greedy search is ideal for NSW because it is quick to navigate and has low computational costs.
@@ -16,6 +16,8 @@ There are four major layers to Supabase Auth:
dark: '/docs/img/supabase-architecture.svg',
light: '/docs/img/supabase-architecture--light.svg',
}}
width={1600}
height={767}
/>
## Client layer
@@ -19,6 +19,8 @@ Below is a flow chart illustrating how the Enrollment and Verify APIs work in th
dark: '/docs/img/guides/auth-mfa/auth-mfa-phone-flow.svg',
}}
containerClassName="max-w-[700px]"
width={93}
height={150}
/>
### Add enrollment flow
@@ -19,6 +19,8 @@ Below is a flow chart illustrating how the Enrollment, Challenge, and Verify API
dark: '/docs/img/guides/auth-mfa/auth-mfa-flow.svg',
}}
containerClassName="max-w-[700px]"
width={111}
height={150}
/>
[TOTP MFA API](/docs/reference/javascript/auth-mfa-api) is free to use and is enabled on all Supabase projects by default.
File diff suppressed because it is too large. Load diff
@@ -83,6 +83,8 @@ Key rotation and revocation are one of the most important processes for maintain
dark: '/docs/img/guides/auth-signing-keys/states.svg',
}}
containerClassName="max-w-[300px] min-w-[180px]"
width={336}
height={766}
/>
<div>
+2
View File
@@ -13,6 +13,8 @@ Cron Jobs can be created via SQL or the [Integrations -> Cron](/dashboard/projec
dark: '/docs/img/guides/cron/cron.jpg',
light: '/docs/img/guides/cron/cron--light.jpg',
}}
width={2072}
height={1457}
/>
Every Job can run SQL snippets or database functions with zero network latency or make an HTTP request, such as invoking a Supabase Edge Function, with ease.
@@ -150,8 +150,10 @@ Serverside-poolers, such as Supabase's [Supavisor](https://github.com/supabase/s
light:
'/docs/img/guides/database/connecting-to-postgres/how-connection-pooling-works--light.png',
}}
width={1851}
height={907}
caption="Connecting to the database directly vs using a Connection Pooler"
zoomable
/>
They maintain hot connections with the database and intelligently share them with clients only when needed, maximizing the amount of queries a single connection can service. They're best used to manage queries from auto-scaling systems, such as edge and serverless functions.
@@ -304,5 +306,7 @@ You can follow the decision flow in the connection method diagram to quickly cho
light: '/docs/img/guides/database/connecting-to-postgres/connection-decision-tree-light.svg',
}}
caption="Choosing between direct Postgres connections and connection pooling"
zoomable
width={291}
height={150}
/>
@@ -27,11 +27,13 @@ These numbers are generalizations and depends on other Supabase products that yo
<Image
alt="Database client connections chart"
zoomable
src={{
dark: '/docs/img/database/reports/db-connections-chart-dark.png',
light: '/docs/img/database/reports/db-connections-chart-light.png',
}}
width={2062}
height={608}
/>
For Teams and Enterprise plans, Supabase provides Advanced Telemetry charts directly within the Dashboard. The `Database client connections` chart displays historical connection data broken down by connection type:
@@ -15,11 +15,13 @@ Wrappers introduce some new terminology and different workflows.
<Image
alt="Foreign Data Wrappers (FDW)"
zoomable
src={{
dark: '/docs/img/database/foreign-data-wrappers/extracting-data.png',
light: '/docs/img/database/foreign-data-wrappers/extracting-data--light.png',
}}
width={1600}
height={929}
/>
### Remote servers
@@ -114,11 +116,13 @@ select cron.schedule(
<Image
alt="FDW with pg_cron"
zoomable
src={{
dark: '/docs/img/database/foreign-data-wrappers/extracting-data-pgcron.png',
light: '/docs/img/database/foreign-data-wrappers/extracting-data-pgcron--light.png',
}}
width={1600}
height={929}
/>
This process can be taxing on your database if you are moving large amounts of data. Often, it's better to use an external tool for batch ETL, such as [Fivetran](https://fivetran.com/) or [Airbyte](https://airbyte.io/).
@@ -12,7 +12,9 @@ OrioleDB addresses PostgreSQL's scalability limitations by removing bottlenecks
alt="TPC-C (warehouses = 500)"
src="/docs/img/database/orioledb-tpc-c-500-warehouse.png"
className="max-w-[550px] !mx-auto border rounded-md"
zoomable
width={1000}
height={609}
/>
<Admonition type="note">
@@ -53,7 +55,9 @@ To get started with OrioleDB you need to [create a new Supabase project](/dashbo
dark: '/docs/img/database/orioledb-creating-project.png',
}}
className="max-w-[550px] !mx-auto border rounded-md"
zoomable
width={1376}
height={2034}
/>
### Creating tables
@@ -13,6 +13,8 @@ Table partitioning is a technique that allows you to divide a large table into s
dark: '/docs/img/database/partitions-dark.png',
}}
className="max-h-[400px] !mx-auto"
width={1600}
height={1075}
/>
Each partition contains a subset of the data based on a specified criteria, such as a range of values or a specific condition. Partitioning can significantly improve query performance and simplify data management for large datasets.
@@ -30,6 +30,8 @@ hideToc: true
light:
'/docs/img/guides/database/connecting-to-postgres/pgadmin/register-server-pgAdmin--light.png',
}}
width={1851}
height={1190}
/>
</StepHikeCompact.Code>
@@ -71,11 +71,13 @@ Here is a simplified diagram of the index we just created (note that in practice
<Image
alt="B-Tree index example in Postgres"
zoomable
src={{
dark: '/docs/img/database/managing-indexes/creating-indexes.png',
light: '/docs/img/database/managing-indexes/creating-indexes--light.png',
}}
width={1600}
height={1091}
/>
You can see that in any large data set, traversing the index to locate a given value can be done in much less operations (O(log n)) than compared to scanning the table one value at a time from top to bottom (O(n)).
@@ -25,7 +25,9 @@ To monitor your replication pipelines:
<Image
alt="Destinations List"
src="/docs/img/database/replication/replication-destinations-list.png"
zoomable
width={3560}
height={2146}
/>
#### Pipeline states
@@ -47,7 +49,9 @@ For detailed information about a specific pipeline, click **View status** on the
<Image
alt="Pipeline Status View"
src="/docs/img/database/replication/replication-view-status.png"
zoomable
width={3560}
height={2146}
/>
#### Replication lag metrics
@@ -77,7 +81,9 @@ Table errors occur during the copy phase and affect individual tables. These err
<Image
alt="Table Error Details"
src="/docs/img/database/replication/replication-pipeline-table-error.png"
zoomable
width={3560}
height={2146}
/>
**Viewing table error details:**
@@ -103,7 +109,9 @@ When a pipeline error occurs, you'll receive an email notification immediately.
<Image
alt="Pipeline Error Details"
src="/docs/img/database/replication/replication-pipeline-error.png"
zoomable
width={3560}
height={2146}
/>
**Viewing pipeline error details:**
@@ -128,7 +136,12 @@ To see detailed logs for all your replication pipelines:
2. Select **Replication** from the log source filter
3. You'll see all logs from your replication pipelines
<Image alt="Replication Logs" src="/docs/img/database/replication/replication-logs.png" zoomable />
<Image
alt="Replication Logs"
src="/docs/img/database/replication/replication-logs.png"
width={3560}
height={2146}
/>
<Admonition type="note">
@@ -106,7 +106,9 @@ Before adding destinations, you need to enable replication for your project:
<Image
alt="Enable Replication"
src="/docs/img/database/replication/replication-enable-replication.png"
zoomable
width={3560}
height={2146}
/>
### Step 3: Add a destination
@@ -140,7 +142,9 @@ First, create an analytics bucket to store your replicated data:
<Image
alt="Create new analytics bucket"
src="/docs/img/database/replication/replication-iceberg-new-bucket.png"
zoomable
width={3560}
height={2146}
/>
3. Fill in the bucket details:
@@ -148,7 +152,9 @@ First, create an analytics bucket to store your replicated data:
<Image
alt="Analytics bucket details"
src="/docs/img/database/replication/replication-iceberg-details.png"
zoomable
width={3560}
height={2146}
/>
- **Name**: A unique name for your bucket (e.g., `analytics_warehouse`)
@@ -169,7 +175,9 @@ First, create an analytics bucket to store your replicated data:
<Image
alt="Add Destination"
src="/docs/img/database/replication/replication-add-destination.png"
zoomable
width={3560}
height={2146}
/>
3. Configure the general settings:
@@ -263,7 +271,9 @@ Before configuring BigQuery as a destination, set up the following in Google Clo
<Image
alt="BigQuery Configuration Settings"
src="/docs/img/database/replication/replication-bigquery-details.png"
zoomable
width={3560}
height={2146}
/>
3. Configure the general settings:
@@ -330,7 +340,9 @@ After creating a destination, the replication pipeline will start and appear in
<Image
alt="Replication Destinations List"
src="/docs/img/database/replication/replication-destinations-list.png"
zoomable
width={3560}
height={2146}
/>
For comprehensive monitoring instructions including pipeline states, metrics, and logs, see the [Replication Monitoring guide](/docs/guides/database/replication/replication-monitoring).
@@ -342,7 +354,9 @@ You can manage your pipeline from the destinations list using the actions menu.
<Image
alt="Pipeline Actions"
src="/docs/img/database/replication/replication-pipeline-actions.png"
zoomable
width={3560}
height={2146}
/>
Available actions:
+9 -3
View File
@@ -29,11 +29,13 @@ When creating a table, it's best practice to add columns at the same time.
<Image
alt="Tables and columns"
zoomable
src={{
dark: '/docs/img/database/managing-tables/creating-tables.png',
light: '/docs/img/database/managing-tables/creating-tables--light.png',
}}
width={1600}
height={1145}
/>
You must define the "data type" of each column when it is created. You can add and remove columns at any time after creating a table.
@@ -343,11 +345,13 @@ Tables can be "joined" together using Foreign Keys.
<Image
alt="Foreign Keys"
zoomable
src={{
dark: '/docs/img/database/managing-tables/joining-tables.png',
light: '/docs/img/database/managing-tables/joining-tables--light.png',
}}
width={1600}
height={1145}
/>
This is where the "Relational" naming comes from, as data typically forms some sort of relationship.
@@ -421,11 +425,13 @@ Tables belong to `schemas`. Schemas are a way of organizing your tables, often f
<Image
alt="Schemas and tables"
zoomable
src={{
dark: '/docs/img/database/managing-tables/schemas.png',
light: '/docs/img/database/managing-tables/schemas--light.png',
}}
width={1600}
height={1145}
/>
If you don't explicitly pass a schema when creating a table, Postgres will assume that you want to create the table in the `public` schema.
@@ -112,11 +112,13 @@ All other configurations, including API, Auth, and seed files, are ignored by de
We highly recommend turning on a 'required check' for the Supabase integration. You can do this from your GitHub repository settings. This prevents PRs from being merged when migration checks fail, and stops invalid migrations from being merged into your production branch.
<Image
zoomable
className="max-w-[700px] !mx-auto"
alt='Check the "Require status checks to pass before merging" option.'
caption='Check the "Require status checks to pass before merging" option.'
src="/docs/img/guides/platform/branching/github-required-check.jpg?v=1"
width={1140}
height={979}
/>
### Email notifications
@@ -15,7 +15,9 @@ This guide shows you how to set up your local Supabase development environment t
light: '/docs/img/local-dev-environment--light.svg',
dark: '/docs/img/local-dev-environment.svg',
}}
zoomable
width={1600}
height={933}
/>
## Set up a local environment
@@ -164,6 +166,8 @@ In a production environment, we recommend using a CI/CD pipeline to deploy new m
light: '/docs/img/local-dev-environment--light.svg',
dark: '/docs/img/local-dev-environment.svg',
}}
width={1600}
height={933}
/>
This example uses two Supabase projects, one for production and one for staging.
@@ -12,7 +12,9 @@ Running databases is a shared responsibility between you and Supabase. There are
light: '/docs/img/platform/shared-responsibility-model--light.png',
dark: '/docs/img/platform/shared-responsibility-model--dark.png',
}}
zoomable
width={1674}
height={1405}
/>
To summarize, you are always responsible for:
@@ -45,7 +45,10 @@ Click the **"Deploy a new function"** button and select **"Via Editor"** to crea
light: '/docs/img/guides/functions/dashboard/create-edge-function--light.png',
dark: '/docs/img/guides/functions/dashboard/create-edge-function--dark.png',
}}
zoomable
width={2338}
height={926}
/>
<Admonition type="note" label="Pre-built templates">
@@ -68,7 +71,10 @@ The dashboard will load your chosen template in the code editor. Here's what the
light: '/docs/img/guides/functions/dashboard/edge-function-template--light.png',
dark: '/docs/img/guides/functions/dashboard/edge-function-template--dark.png',
}}
zoomable
width={2430}
height={1248}
/>
If needed, you can modify this code directly in the browser editor. The function accepts a JSON payload with a `name` field and returns a greeting message.
@@ -109,7 +115,10 @@ Click **"Send Request"** to test your function.
light: '/docs/img/guides/functions/dashboard/edge-function-test--light.png',
dark: '/docs/img/guides/functions/dashboard/edge-function-test--dark.png',
}}
zoomable
width={2430}
height={1350}
/>
In this example, we successfully tested our Hello World function by sending a JSON payload with a name field, and received the expected greeting message back.
@@ -202,7 +211,10 @@ Go to your project > **Deploy a new function** > **Via AI Assistant**.
light: '/docs/img/guides/functions/dashboard/create-ai-edge-function--light.png',
dark: '/docs/img/guides/functions/dashboard/create-ai-edge-function--dark.png',
}}
zoomable
width={2604}
height={926}
/>
Describe what you want your function to do in the prompt
@@ -213,7 +225,10 @@ Describe what you want your function to do in the prompt
light: '/docs/img/guides/functions/dashboard/ai-edge-function--light.png',
dark: '/docs/img/guides/functions/dashboard/ai-edge-function--dark.png',
}}
zoomable
width={2768}
height={1836}
/>
Click **Deploy** and the Assistant will create and deploy the function for you.
@@ -104,6 +104,9 @@ You will also need to set secrets for your production Edge Functions. You can do
light: '/docs/img/edge-functions-secrets--light.jpg',
dark: '/docs/img/edge-functions-secrets.jpg',
}}
width={3757}
height={1525}
/>
Note that you can paste multiple secrets at a time.
@@ -25,6 +25,9 @@ Each Supabase project consists of several tools:
dark: '/docs/img/supabase-architecture.svg',
light: '/docs/img/supabase-architecture--light.svg',
}}
width={1600}
height={767}
/>
### Postgres (database)
@@ -173,7 +173,10 @@ The Supabase CLI uses Docker containers to manage the local development stack. F
dark: '/docs/img/guides/cli/docker-mac.png',
light: '/docs/img/guides/cli/docker-mac-light.png',
}}
zoomable
width={2880}
height={1800}
/>
</TabPanel>
@@ -185,7 +188,10 @@ The Supabase CLI uses Docker containers to manage the local development stack. F
dark: '/docs/img/guides/cli/docker-win.png',
light: '/docs/img/guides/cli/docker-win-light.png',
}}
zoomable
width={2560}
height={1520}
/>
</TabPanel>
@@ -16,9 +16,12 @@ If you want to restore your backup to a hosted Supabase project, follow the [Mig
First, download your project's backup file from dashboard and identify its backup image version (following the `PG:` prefix):
<Image
zoomable
alt="Project Paused: 90 Days Remaining"
src="/docs/img/guides/platform/paused-dl-image-version.png"
width={628}
height={389}
/>
## Restoring your backup
@@ -13,7 +13,10 @@ An AWS Marketplace subscription is linked to exactly one Supabase organization.
dark: '/docs/img/guides/platform/aws-marketplace-onboarding-page-extended--dark.png',
light: '/docs/img/guides/platform/aws-marketplace-onboarding-page-extended--light.png',
}}
zoomable
width={3040}
height={1312}
/>
## Implications of linking a Supabase organization to a marketplace subscription
@@ -28,8 +28,11 @@ For more details on completing the setup and what it means to link an organizati
<Image
alt="Supabase product overview on the AWS Marketplace"
src="/docs/img/guides/platform/aws-marketplace-listing-overview.png"
zoomable
/>
width={2222}
height={2414}
/>
</StepHikeCompact.Details>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={2}>
@@ -47,8 +50,11 @@ For more details on completing the setup and what it means to link an organizati
<Image
alt="Supabase purchase options on the AWS Marketplace"
src="/docs/img/guides/platform/aws-marketplace-listing-purchase-options.png"
zoomable
/>
width={2334}
height={2418}
/>
</StepHikeCompact.Details>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={3}>
@@ -57,8 +63,11 @@ For more details on completing the setup and what it means to link an organizati
<Image
alt="Supabase product subscribe"
src="/docs/img/guides/platform/aws-marketplace-listing-subscribe.png"
zoomable
/>
width={2270}
height={632}
/>
</StepHikeCompact.Details>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={4}>
@@ -67,8 +76,11 @@ For more details on completing the setup and what it means to link an organizati
<Image
alt="Supabase product subscribe"
src="/docs/img/guides/platform/aws-marketplace-listing-success.png"
zoomable
/>
width={1944}
height={1254}
/>
</StepHikeCompact.Details>
</StepHikeCompact.Step>
<StepHikeCompact.Step step={5}>
@@ -80,8 +92,11 @@ For more details on completing the setup and what it means to link an organizati
dark: '/docs/img/guides/platform/aws-marketplace-onboarding-page--dark.png',
light: '/docs/img/guides/platform/aws-marketplace-onboarding-page--light.png',
}}
zoomable
/>
width={3048}
height={1058}
/>
</StepHikeCompact.Details>
</StepHikeCompact.Step>
@@ -10,7 +10,10 @@ You can view your invoices in the [AWS Billing and Cost Management console](http
<Image
alt="Subscription upgrade modal"
src="/docs/img/guides/platform/aws-marketplace-invoices.png"
zoomable
width={4544}
height={1714}
/>
## What invoices you get from AWS
@@ -21,7 +21,10 @@ You can upgrade your plan at any time. The new plan will be active immediately,
light: '/docs/img/guides/platform/aws-marketplace-change-plan.png',
dark: '/docs/img/guides/platform/aws-marketplace-change-plan.png',
}}
zoomable
width={2088}
height={2276}
/>
### Downgrade
@@ -44,7 +47,10 @@ If the downgrade causes you to exceed the [free projects limit](/docs/guides/pla
light: '/docs/img/guides/platform/aws-marketplace-configure-auto-renewal.png',
dark: '/docs/img/guides/platform/aws-marketplace-configure-auto-renewal.png',
}}
zoomable
width={2080}
height={2074}
/>
#### Downgrade to a paid plan
@@ -29,8 +29,11 @@ Different plans cannot be mixed within a single organization. For example, you c
dark: '/docs/img/guides/platform/billing-overview.png',
}}
className="max-w-[600px] inline-block"
zoomable
/>
width={1600}
height={1475}
/>
</div>
## Costs
@@ -43,8 +43,11 @@ Compute sizes can be changed by first selecting your project in the dashboard [h
light: '/docs/img/guides/platform/compute-size-selection--light.png',
dark: '/docs/img/guides/platform/compute-size-selection--dark.png',
}}
zoomable
className="max-w-[500px]"
width={2122}
height={1302}
/>
We charge hourly for additional compute based on your usage. Read more about [usage-based billing for compute](/docs/guides/platform/manage-your-usage/compute).
@@ -13,7 +13,10 @@ Each organization has a credit balance. Credits are applied to future invoices t
light: '/docs/img/guides/platform/credit-balance--light.png',
dark: '/docs/img/guides/platform/credit-balance--dark.png',
}}
zoomable
width={2034}
height={388}
/>
You can find the credit balance on the [organization's billing page](/dashboard/org/_/billing).
@@ -50,8 +53,11 @@ If you are interested in larger (> <Price price="2000" />) credit packages, [rea
light: '/docs/img/guides/platform/credit-top-up--light.png',
dark: '/docs/img/guides/platform/credit-top-up--dark.png',
}}
zoomable
className="max-w-[500px]"
width={1014}
height={758}
/>
## Credit FAQ
@@ -23,7 +23,10 @@ Upgrades take effect immediately. During the process, you are informed of the as
dark: '/docs/img/guides/platform/upgrade-to-pro-plan-modal--dark.png',
}}
className="max-w-[577px]"
zoomable
width={1536}
height={1116}
/>
If you still have credits in your account, we will use the credits first before charging your card.
@@ -39,7 +42,10 @@ Downgrades take effect immediately. During the process, you are informed of the
dark: '/docs/img/guides/platform/downgrade-to-free-plan-modal--dark.png',
}}
className="max-w-[577px]"
zoomable
width={2096}
height={1649}
/>
#### Credits upon downgrade
@@ -55,7 +55,10 @@ You can view Branching usage on the [organization's usage page](/dashboard/org/_
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Usage Summary section, you can see how many hours your Preview branches existed during the selected time period. Hover over "Branching Compute Hours" for a detailed breakdown.
@@ -66,7 +69,10 @@ In the Usage Summary section, you can see how many hours your Preview branches e
light: '/docs/img/guides/platform/usage-summary-branch-hours--light.png',
dark: '/docs/img/guides/platform/usage-summary-branch-hours--dark.png',
}}
zoomable
width={2258}
height={1360}
/>
## Optimize usage
@@ -134,7 +134,10 @@ You can view Compute usage on the [organization's usage page](/dashboard/org/_/u
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Compute Hours section, you can see how many hours of a specific Compute size your projects have used during the selected time period. Hover over a specific date for a daily breakdown.
@@ -145,7 +148,10 @@ In the Compute Hours section, you can see how many hours of a specific Compute s
light: '/docs/img/guides/platform/usage-compute--light.png',
dark: '/docs/img/guides/platform/usage-compute--dark.png',
}}
zoomable
width={2050}
height={810}
/>
## Optimize usage
@@ -109,7 +109,10 @@ You can view Disk size usage on the [organization's usage page](/dashboard/org/_
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Disk size section, you can see how much disk size your projects have provisioned.
@@ -120,7 +123,10 @@ In the Disk size section, you can see how much disk size your projects have prov
light: '/docs/img/guides/platform/usage-disk-size--light.png',
dark: '/docs/img/guides/platform/usage-disk-size--dark.png',
}}
zoomable
width={2010}
height={670}
/>
### Disk size distribution
@@ -68,7 +68,10 @@ You can view Edge Function Invocations usage on the [organization's usage page](
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Edge Function Invocations section, you can see how many invocations your projects have had during the selected time period.
@@ -79,7 +82,10 @@ In the Edge Function Invocations section, you can see how many invocations your
light: '/docs/img/guides/platform/usage-function-invocations--light.png',
dark: '/docs/img/guides/platform/usage-function-invocations--dark.png',
}}
zoomable
width={2008}
height={734}
/>
## Exceeding Quotas
@@ -121,7 +121,10 @@ You can view Egress usage on the [organization's usage page](/dashboard/org/_/us
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Total Egress section, you can see the usage for the selected time period. Hover over a specific date to view a breakdown by service. Note that this includes the cached egress.
@@ -132,6 +135,9 @@ In the Total Egress section, you can see the usage for the selected time period.
light: '/docs/img/guides/platform/unified-egress--light.png',
dark: '/docs/img/guides/platform/unified-egress.png',
}}
width={803}
height={460}
/>
Separately, you can see the cached egress right below:
@@ -142,6 +148,9 @@ Separately, you can see the cached egress right below:
light: '/docs/img/guides/platform/cached-egress--light.png',
dark: '/docs/img/guides/platform/cached-egress.png',
}}
width={1422}
height={586}
/>
### Custom report
@@ -155,7 +164,10 @@ Separately, you can see the cached egress right below:
light: '/docs/img/guides/platform/egress-report--light.png',
dark: '/docs/img/guides/platform/egress-report--dark.png',
}}
zoomable
width={2884}
height={948}
/>
## Debug usage
@@ -172,7 +184,10 @@ On the Advisors [Query performance view](/dashboard/project/_/database/query-per
light: '/docs/img/guides/platform/advisor-most-frequent-queries--light.png',
dark: '/docs/img/guides/platform/advisor-most-frequent-queries--dark.png',
}}
zoomable
width={5006}
height={510}
/>
### Most requested API endpoints
@@ -185,7 +200,10 @@ In the [Logs Explorer](/dashboard/project/_/logs/explorer) you can access Edge L
light: '/docs/img/guides/platform/logs-top-paths--light.png',
dark: '/docs/img/guides/platform/logs-top-paths--dark.png',
}}
zoomable
width={4492}
height={1166}
/>
## Optimize usage
@@ -112,4 +112,7 @@ You can view Log Drain Events usage on the [organization's usage page](/dashboar
light: '/docs/img/guides/platform/usage-logdrain-events--light.png',
dark: '/docs/img/guides/platform/usage-logdrain-events--dark.png',
}}
width={2092}
height={762}
/>
@@ -124,7 +124,10 @@ You can view Monthly Active SSO Users usage on the [organization's usage page](/
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Monthly Active SSO Users section, you can see the usage for the selected time period.
@@ -135,6 +138,9 @@ In the Monthly Active SSO Users section, you can see the usage for the selected
light: '/docs/img/guides/platform/usage-mau-sso--light.png',
dark: '/docs/img/guides/platform/usage-mau-sso--dark.png',
}}
width={2034}
height={884}
/>
## Exceeding Quotas
@@ -25,8 +25,11 @@ Your billing cycle runs from January 1 to January 31. Although User-1 was signed
dark: '/docs/img/guides/platform/third-party-mau-auth0-login-screen.png',
}}
className="max-h-[190px]"
zoomable
/>
width={1098}
height={1970}
/>
</StepHikeCompact.Code>
</StepHikeCompact.Step>
@@ -48,8 +51,11 @@ Your billing cycle runs from January 1 to January 31. Although User-1 was signed
dark: '/docs/img/guides/platform/third-party-mau-auth0-login-screen.png',
}}
className="max-h-[190px]"
zoomable
/>
width={1098}
height={1970}
/>
</StepHikeCompact.Code>
</StepHikeCompact.Step>
</StepHikeCompact>
@@ -117,6 +123,9 @@ You can view Monthly Active Third-Party Users usage on the [organization's usage
light: '/docs/img/guides/platform/usage-mau-third-party--light.png',
dark: '/docs/img/guides/platform/usage-mau-third-party--dark.png',
}}
width={2040}
height={1040}
/>
## Exceeding Quotas
@@ -112,7 +112,10 @@ You can view Monthly Active Users usage on the [organization's usage page](/dash
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Monthly Active Users section, you can see the usage for the selected time period.
@@ -123,6 +126,9 @@ In the Monthly Active Users section, you can see the usage for the selected time
light: '/docs/img/guides/platform/usage-mau--light.png',
dark: '/docs/img/guides/platform/usage-mau--dark.png',
}}
width={2040}
height={878}
/>
## Exceeding Quotas
@@ -74,7 +74,10 @@ You can view Realtime Messages usage on the [organization's usage page](/dashboa
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Realtime Messages section, you can see the usage for the selected time period.
@@ -85,7 +88,10 @@ In the Realtime Messages section, you can see the usage for the selected time pe
light: '/docs/img/guides/platform/usage-realtime-messages--light.png',
dark: '/docs/img/guides/platform/usage-realtime-messages--dark.png',
}}
zoomable
width={2036}
height={760}
/>
## Exceeding Quotas
@@ -79,7 +79,10 @@ You can view Realtime Peak Connections usage on the [organization's usage page](
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Realtime Peak Connections section, you can see the usage for the selected time period.
@@ -90,7 +93,10 @@ In the Realtime Peak Connections section, you can see the usage for the selected
light: '/docs/img/guides/platform/usage-realtime-peak-connections--light.png',
dark: '/docs/img/guides/platform/usage-realtime-peak-connections--dark.png',
}}
zoomable
width={2046}
height={752}
/>
## Exceeding Quotas
@@ -106,7 +106,10 @@ You can view Storage Image Transformations usage on the [organization's usage pa
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Storage Image Transformations section, you can see how many origin images were transformed during the selected time period.
@@ -117,7 +120,10 @@ In the Storage Image Transformations section, you can see how many origin images
light: '/docs/img/guides/platform/usage-image-transformations--light.png',
dark: '/docs/img/guides/platform/usage-image-transformations--dark.png',
}}
zoomable
width={2032}
height={848}
/>
## Optimize usage
@@ -60,7 +60,10 @@ You can view Storage size usage on the [organization's usage page](/dashboard/or
light: '/docs/img/guides/platform/usage-navbar--light.png',
dark: '/docs/img/guides/platform/usage-navbar--dark.png',
}}
zoomable
width={1546}
height={208}
/>
In the Storage size section, you can see how much storage your projects have used during the selected time period.
@@ -71,7 +74,10 @@ In the Storage size section, you can see how much storage your projects have use
light: '/docs/img/guides/platform/usage-storage-size--light.png',
dark: '/docs/img/guides/platform/usage-storage-size--dark.png',
}}
zoomable
width={2028}
height={882}
/>
### SQL Editor
@@ -13,7 +13,10 @@ You can freely transfer projects between different organizations. Head to your [
dark: '/docs/img/guides/platform/project-transfer-overview.png',
}}
className="max-w-[600px] !mx-auto border rounded-md"
zoomable
width={677}
height={224}
/>
<Image
@@ -23,7 +26,10 @@ You can freely transfer projects between different organizations. Head to your [
dark: '/docs/img/guides/platform/project-transfer-modal.png',
}}
className="max-w-[600px] !mx-auto"
zoomable
width={773}
height={581}
/>
Source organization - the organization the project currently belongs to
@@ -14,7 +14,9 @@ Read Replicas are additional databases kept in sync with your Primary database.
alt="Map view of all project databases."
src="/docs/img/guides/platform/read-replicas/map-view.png?v=1"
containerClassName="max-w-[700px] !mx-auto"
zoomable
width={2000}
height={830}
/>
## About Read Replicas
@@ -46,7 +48,6 @@ You can only read data from a Read Replica. This is in contrast to a Primary dat
<Image
src="/docs/img/guides/platform/read-replicas/read-replicas-flow.svg"
zoomable
alt="Read Replicas decision flowchart"
/>
@@ -128,7 +129,9 @@ In the SQL editor, you can choose if you want to run the query on a particular R
alt="SQL editor view."
src="/docs/img/guides/platform/read-replicas/sql-editor.png?v=1"
containerClassName="max-w-[700px]"
zoomable
width={2024}
height={1048}
/>
### Logging
@@ -80,8 +80,10 @@ The 90-day window allows Supabase to introduce platform changes that may not be
During the 90-day restore window a paused project can be restored to the platform with a single button click from [Studio's dashboard page](/dashboard/projects).
<Image
zoomable
alt="Project Paused: 90 Days Remaining"
width={962}
height={386}
src="/docs/img/guides/platform/paused-90-day.png"
/>
@@ -91,17 +93,21 @@ After the 90-day restore window, you can download your project's backup file, an
- [Restore a backup locally](/docs/guides/local-development/restoring-downloaded-backup)
<Image
zoomable
alt="Project Paused: 90 Days Remaining"
src="/docs/img/guides/platform/paused-dl-backup.png"
width={495}
height={306}
/>
If you upgrade to a paid plan while your project is paused within the 90-day restore window, any expired one-click restore options are reenabled. Since the backup was taken outside the backwards compatibility window, it may fail to restore. If you have a problem restoring your backup after upgrading, contact [Support](/support).
<Image
zoomable
alt="Project Paused: 90 Days Remaining"
src="/docs/img/guides/platform/paused-paid-tier.png"
width={962}
height={385}
/>
### Disk sizing
@@ -37,7 +37,10 @@ The following invoice was issued on January 6, 2025 with the previous billing cy
light: '/docs/img/guides/platform/example-invoice.png',
dark: '/docs/img/guides/platform/example-invoice.png',
}}
zoomable
width={1690}
height={2192}
/>
1. The final amount due
+19 -1
View File
@@ -43,6 +43,9 @@ To get started, navigate to the [Supabase Queues](/dashboard/project/_/integrati
dark: '/docs/img/queues-quickstart-install.png',
light: '/docs/img/queues-quickstart-install.png',
}}
width={2064}
height={1720}
/>
On the [Queues page](/dashboard/project/_/integrations/queues/queues):
@@ -71,8 +74,11 @@ Queue names can only be lowercase and hyphens and underscores are permitted.
dark: '/docs/img/queues-quickstart-create.png',
light: '/docs/img/queues-quickstart-create.png',
}}
zoomable
className="max-w-lg !mx-auto"
width={1456}
height={1420}
/>
### What happens when you create a queue?
@@ -99,6 +105,9 @@ To get started, navigate to the Queues [Settings page](/dashboard/project/_/inte
dark: '/docs/img/queues-quickstart-settings.png',
light: '/docs/img/queues-quickstart-settings.png',
}}
width={2140}
height={1642}
/>
### Enable RLS on your tables in `pgmq` schema
@@ -113,6 +122,9 @@ You’ll want to create RLS policies for any Queues you want your client-side co
dark: '/docs/img/queues-quickstart-rls.png',
light: '/docs/img/queues-quickstart-rls.png',
}}
width={2130}
height={1508}
/>
### Grant permissions to `pgmq_public` database functions
@@ -135,6 +147,9 @@ To manage your queue permissions, click on the Queue Settings button.
dark: '/docs/img/queues-quickstart-queue-settings.png',
light: '/docs/img/queues-quickstart-queue-settings.png',
}}
width={2150}
height={1192}
/>
Then enable the required roles permissions.
@@ -145,6 +160,9 @@ Then enable the required roles permissions.
dark: '/docs/img/queues-quickstart-roles.png',
light: '/docs/img/queues-quickstart-roles-light.png',
}}
width={1271}
height={1315}
/>
<Admonition type="note">
@@ -15,6 +15,9 @@ Realtime is written in [Elixir](https://elixir-lang.org/), which compiles to [Er
light: '/docs/img/guides/platform/realtime/architecture--light.png',
dark: '/docs/img/guides/platform/realtime/architecture--dark.png',
}}
width={1990}
height={2226}
/>
## Elixir & Phoenix
+48 -12
View File
@@ -45,11 +45,14 @@ The report displays the total number of connected Realtime clients, showing how
<Image
alt="Connected Clients chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/connected-clients-chart-dark.png',
light: '/docs/img/guides/platform/realtime/reports/connected-clients-chart-light.png',
}}
width={2343}
height={625}
/>
### Actions you can take
@@ -72,11 +75,14 @@ The report displays the total number of broadcast events sent by clients, showin
<Image
alt="Broadcast Events chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/broadcast-events-chart-dark.png',
light: '/docs/img/guides/platform/realtime/reports/broadcast-events-chart-light.png',
}}
width={2343}
height={625}
/>
### Actions you can take
@@ -98,11 +104,14 @@ The report displays the total number of presence events sent by clients, showing
<Image
alt="Presence Events chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/presence-events-chart-dark.png',
light: '/docs/img/guides/platform/realtime/reports/presence-events-chart-light.png',
}}
width={2343}
height={625}
/>
### Actions you can take
@@ -124,11 +133,14 @@ The report displays the total number of Postgres change events received by clien
<Image
alt="Postgres Changes Events chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/postgres-changes-events-chart-dark.png',
light: '/docs/img/guides/platform/realtime/reports/postgres-changes-events-chart-light.png',
}}
width={2343}
height={625}
/>
### Actions you can take
@@ -151,11 +163,14 @@ The report displays the rate of channel joins per second, showing how frequently
<Image
alt="Rate of Channel Joins chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/rate-of-channel-joins-chart-dark.png',
light: '/docs/img/guides/platform/realtime/reports/rate-of-channel-joins-chart-light.png',
}}
width={2343}
height={625}
/>
### Actions you can take
@@ -176,11 +191,14 @@ The report displays the median payload size in bytes, showing how message sizes
<Image
alt="Message Payload Size chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/message-payload-size-chart-dark.png',
light: '/docs/img/guides/platform/realtime/reports/message-payload-size-chart-light.png',
}}
width={2343}
height={625}
/>
### Actions you can take
@@ -203,12 +221,15 @@ The report displays the median replication lag in milliseconds, showing the dela
<Image
alt="Broadcast from Database Replication Lag chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/broadcast-from-database-replication-lag-chart-dark.png',
light:
'/docs/img/guides/platform/realtime/reports/broadcast-from-database-replication-lag-chart-light.png',
}}
width={2343}
height={625}
/>
### Actions you can take
@@ -232,12 +253,15 @@ The report displays the median RLS execution time in milliseconds, showing how l
<Image
alt="(Read) Private Channel Subscription RLS Execution Time chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/read-private-channel-subscription-rls-execution-time-chart-dark.png',
light:
'/docs/img/guides/platform/realtime/reports/read-private-channel-subscription-rls-execution-time-chart-light.png',
}}
width={2343}
height={625}
/>
### Actions you can take
@@ -262,12 +286,15 @@ The report displays the median RLS execution time in milliseconds, showing how l
<Image
alt="(Write) Private Channel Subscription RLS Execution Time chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/write-private-channel-subscription-rls-execution-time-chart-dark.png',
light:
'/docs/img/guides/platform/realtime/reports/write-private-channel-subscription-rls-execution-time-chart-light.png',
}}
width={2343}
height={625}
/>
### Actions you can take
@@ -292,11 +319,14 @@ The report displays the total number of HTTP requests made to the Realtime servi
<Image
alt="Total Requests chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/total-requests-chart-dark.png',
light: '/docs/img/guides/platform/realtime/reports/total-requests-chart-light.png',
}}
width={4721}
height={834}
/>
### Actions you can take
@@ -318,11 +348,14 @@ The report displays the total number of response errors from the Realtime API, s
<Image
alt="Response Errors chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/response-errors-chart-dark.png',
light: '/docs/img/guides/platform/realtime/reports/response-errors-chart-light.png',
}}
width={4721}
height={645}
/>
### Actions you can take
@@ -348,11 +381,14 @@ The report displays the average response time in milliseconds, showing how quick
<Image
alt="Response Speed chart"
zoomable
src={{
dark: '/docs/img/guides/platform/realtime/reports/response-speed-chart-dark.png',
light: '/docs/img/guides/platform/realtime/reports/response-speed-chart-light.png',
}}
width={4721}
height={834}
/>
### Actions you can take
@@ -18,7 +18,10 @@ All changes made in this screen will disconnect all your connected clients to en
light: '/docs/img/guides/platform/realtime/realtime-settings--light.png',
dark: '/docs/img/guides/platform/realtime/realtime-settings--dark.png',
}}
zoomable
width={4600}
height={2600}
/>
You can set the following settings using the Realtime Settings screen in your Dashboard:
@@ -23,7 +23,10 @@ Platform Audit Logs can be found under your [organization's audit logs](/dashboa
light: '/docs/img/guides/security/platform-audit-logs--light.png',
dark: '/docs/img/guides/security/platform-audit-logs--dark.png',
}}
zoomable
width={2414}
height={958}
/>
For each audit log, you can see additional details by clicking on the log entry:
@@ -358,6 +358,9 @@ If the tools and communities already exist, with an MIT, Apache 2, or equivalent
dark: "/docs/img/supabase-architecture.svg",
light: "/docs/img/supabase-architecture--light.svg",
}}
width={1600}
height={767}
/>
- **[Studio](https://github.com/supabase/supabase/tree/master/apps/studio)** - A dashboard for managing your self-hosted Supabase project
@@ -24,6 +24,9 @@ The dashboard provides the easiest setup experience:
<Image
alt="Query with PostgreSQL button on analytics bucket page"
src="/docs/img/storage/query-analytics-with-postgres.png"
width={1860}
height={332}
/>
3. Enter the **Postgres schema** where you want to create the foreign tables.
@@ -31,6 +34,9 @@ The dashboard provides the easiest setup experience:
<Image
alt="Select destination PostgreSQL schema"
src="/docs/img/storage/query-analytics-schema-name.png"
width={525}
height={297}
/>
4. Click **Connect**. The wrapper is now configured.
@@ -32,7 +32,10 @@ First, create a new analytics bucket to store your replicated data:
<Image
alt="Creating a new analytics bucket"
src="/docs/img/database/replication/replication-iceberg-new-bucket.png"
zoomable
width={3560}
height={2146}
/>
### Step 2: Create a publication
@@ -61,7 +64,10 @@ Now set up the pipeline to sync data to your analytics bucket:
<Image
alt="Replication pipeline configuration"
src="/docs/img/database/replication/replication-iceberg-details.png"
zoomable
width={3560}
height={2146}
/>
## Monitoring your pipeline
+20 -5
View File
@@ -58,11 +58,14 @@ The following charts provide a more advanced and detailed view of your database
<Image
alt="Memory usage chart"
zoomable
src={{
dark: '/docs/img/database/reports/memory-usage-chart-dark.png',
light: '/docs/img/database/reports/memory-usage-chart-light.png',
}}
width={2148}
height={650}
/>
| Component | Description |
@@ -92,11 +95,14 @@ Actions you can take:
<Image
alt="CPU usage chart"
zoomable
src={{
dark: '/docs/img/database/reports/cpu-usage-chart-dark.png',
light: '/docs/img/database/reports/cpu-usage-chart-light.png',
}}
width={2152}
height={654}
/>
| Category | Description |
@@ -128,11 +134,14 @@ Actions you can take:
<Image
alt="Disk IOPS chart"
zoomable
src={{
dark: '/docs/img/database/reports/disk-iops-chart-dark.png',
light: '/docs/img/database/reports/disk-iops-chart-light.png',
}}
width={2146}
height={650}
/>
This chart displays read and write IOPS with a reference line showing your compute size's maximum IOPS capacity.
@@ -180,11 +189,14 @@ Actions you can take:
<Image
alt="Disk Size chart"
zoomable
src={{
dark: '/docs/img/database/reports/disk-size-chart-dark.png',
light: '/docs/img/database/reports/disk-size-chart-light.png',
}}
width={2148}
height={654}
/>
| Component | Description |
@@ -214,11 +226,14 @@ Actions you can take:
<Image
alt="Database connections chart"
zoomable
src={{
dark: '/docs/img/database/reports/db-connections-chart-dark.png',
light: '/docs/img/database/reports/db-connections-chart-light.png',
}}
width={2066}
height={608}
/>
| Connection Type | Description |
+3 -2
View File
@@ -1,6 +1,6 @@
import { ArrowDown, Check, X } from 'lucide-react'
import Link from 'next/link'
import { Badge, Button, Image } from 'ui'
import { Badge, Button } from 'ui'
import { Admonition, type AdmonitionProps } from 'ui-patterns/admonition'
import { GlassPanel } from 'ui-patterns/GlassPanel'
import { IconPanel } from 'ui-patterns/IconPanel'
@@ -13,6 +13,7 @@ import { AuthSmsProviderConfig } from '~/components/AuthSmsProviderConfig'
import { CostWarning } from '~/components/AuthSmsProviderConfig/AuthSmsProviderConfig.Warnings'
import ButtonCard from '~/components/ButtonCard'
import { Extensions } from '~/components/Extensions'
import Image, { type ImageProps } from '~/components/Image'
import { JwtGenerator, JwtGeneratorSimple } from '~/components/JwtGenerator'
import { MetricsStackCards } from '~/components/MetricsStackCards'
import { NavData } from '~/components/NavData'
@@ -60,7 +61,7 @@ const components = {
IconCheck: Check,
IconPanel,
IconX: X,
Image: (props: any) => <Image fill alt="" className="object-contain" {...props} />,
Image: (props: ImageProps) => <Image className="rounded-md w-full" {...props} />,
JwtGenerator,
JwtGeneratorSimple,
Link,
+33 -11
View File
@@ -1,17 +1,23 @@
import { isbot } from 'isbot'
import { NextResponse, type NextRequest } from 'next/server'
import { clientSdkIds } from '~/content/navigation.references'
import { BASE_PATH } from '~/lib/constants'
import { stampFirstReferrerCookie } from 'common/first-referrer-cookie'
import { isbot } from 'isbot'
import { NextResponse, type NextRequest } from 'next/server'
const REFERENCE_PATH = `${BASE_PATH ?? ''}/reference`
export function middleware(request: NextRequest) {
const url = new URL(request.url)
// Non-reference paths: just handle the first-referrer cookie and pass through
if (!url.pathname.startsWith(REFERENCE_PATH)) {
return NextResponse.next()
const response = NextResponse.next()
stampFirstReferrerCookie(request, response)
return response
}
// Reference paths: existing rewrite logic with cookie stamping on every response
if (isbot(request.headers.get('user-agent'))) {
let [, lib, maybeVersion, ...slug] = url.pathname.replace(REFERENCE_PATH, '').split('/')
@@ -24,7 +30,9 @@ export function middleware(request: NextRequest) {
if (slug.length > 0) {
const rewriteUrl = new URL(url)
rewriteUrl.pathname = (BASE_PATH ?? '') + '/api/crawlers'
return NextResponse.rewrite(rewriteUrl)
const response = NextResponse.rewrite(rewriteUrl)
stampFirstReferrerCookie(request, response)
return response
}
}
}
@@ -33,28 +41,42 @@ export function middleware(request: NextRequest) {
if (lib === 'cli') {
const rewritePath = [REFERENCE_PATH, 'cli'].join('/')
return NextResponse.rewrite(new URL(rewritePath, request.url))
const response = NextResponse.rewrite(new URL(rewritePath, request.url))
stampFirstReferrerCookie(request, response)
return response
}
if (lib === 'api') {
const rewritePath = [REFERENCE_PATH, 'api'].join('/')
return NextResponse.rewrite(new URL(rewritePath, request.url))
const response = NextResponse.rewrite(new URL(rewritePath, request.url))
stampFirstReferrerCookie(request, response)
return response
}
if (lib?.startsWith('self-hosting-')) {
const rewritePath = [REFERENCE_PATH, lib].join('/')
return NextResponse.rewrite(new URL(rewritePath, request.url))
const response = NextResponse.rewrite(new URL(rewritePath, request.url))
stampFirstReferrerCookie(request, response)
return response
}
if (clientSdkIds.includes(lib)) {
const version = /v\d+/.test(maybeVersion) ? maybeVersion : null
const rewritePath = [REFERENCE_PATH, lib, version].filter(Boolean).join('/')
return NextResponse.rewrite(new URL(rewritePath, request.url))
const response = NextResponse.rewrite(new URL(rewritePath, request.url))
stampFirstReferrerCookie(request, response)
return response
}
return NextResponse.next()
const response = NextResponse.next()
stampFirstReferrerCookie(request, response)
return response
}
export const config = {
matcher: '/reference/:path*',
matcher: [
// Broadened from `/reference/:path*` to stamp first-referrer cookies on all
// docs pages, not just reference paths. Excludes Next.js internals and static files.
'/((?!api|_next/static|_next/image|favicon.ico|__nextjs).*)',
],
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 676 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 45 KiB

@@ -128,7 +128,7 @@ function createModelFromMatch({
} else {
return null
}
case 'github-discussions':
case 'troubleshooting':
return new TroubleshootingModel({
title: page_title,
href,
@@ -446,9 +446,6 @@ async function generateEmbeddings() {
}
requireEnvOrThrow([
'DOCS_GITHUB_APP_ID',
'DOCS_GITHUB_APP_INSTALLATION_ID',
'DOCS_GITHUB_APP_PRIVATE_KEY',
'NEXT_PUBLIC_MISC_ANON_KEY',
'NEXT_PUBLIC_MISC_URL',
'NEXT_PUBLIC_SUPABASE_URL',
+11 -21
View File
@@ -1,10 +1,5 @@
import { type GuideModel } from '../../../resources/guide/guideModel.js'
import { GuideModelLoader } from '../../../resources/guide/guideModelLoader.js'
import {
GitHubDiscussionLoader,
type GitHubDiscussionSource,
fetchDiscussions,
} from './github-discussion.js'
import { LintWarningsGuideLoader, type LintWarningsGuideSource } from './lint-warnings-guide.js'
import { MarkdownLoader, type MarkdownSource } from './markdown.js'
import { IntegrationLoader, type IntegrationSource, fetchPartners } from './partner-integrations.js'
@@ -16,13 +11,14 @@ import {
OpenApiReferenceLoader,
type OpenApiReferenceSource,
} from './reference-doc.js'
import { fetchTroubleshootingSources, type TroubleshootingSource } from './troubleshooting.js'
export type SearchSource =
| MarkdownSource
| OpenApiReferenceSource
| ClientLibReferenceSource
| CliReferenceSource
| GitHubDiscussionSource
| TroubleshootingSource
| IntegrationSource
| LintWarningsGuideSource
@@ -150,21 +146,15 @@ export async function fetchAllSources(fullIndex: boolean) {
.then((data) => data.flat())
: []
const githubDiscussionSources = fetchDiscussions(
'supabase',
'supabase',
'DIC_kwDODMpXOc4CUvEr' // 'Troubleshooting' category
)
.then((discussions) =>
Promise.all(
discussions.map((discussion) =>
new GitHubDiscussionLoader('supabase/supabase', discussion).load()
)
)
)
// Load troubleshooting articles from local MDX files
const troubleshootingSources = fetchTroubleshootingSources()
.then((loaders) => Promise.all(loaders.map((loader) => loader.load())))
.then((data) => data.flat())
const sources: SearchSource[] = (
// Type assertion required because ReferenceLoader.load() returns Promise<BaseSource[]>
// which widens the inferred union type. All concrete sources in this array are valid
// SearchSource types (MarkdownSource, OpenApiReferenceSource, etc.).
const sources = (
await Promise.all([
guideSources,
lintWarningsGuideSources,
@@ -177,9 +167,9 @@ export async function fetchAllSources(fullIndex: boolean) {
ktLibReferenceSource,
cliReferenceSource,
partnerIntegrationSources,
githubDiscussionSources,
troubleshootingSources,
])
).flat()
).flat() as SearchSource[]
return sources
}
@@ -0,0 +1,101 @@
import { createHash } from 'node:crypto'
import { BaseLoader, BaseSource } from './base.js'
import {
getAllTroubleshootingEntriesInternal,
getArticleSlug,
} from '../../../features/docs/Troubleshooting.utils.common.mjs'
import type { ITroubleshootingEntry } from '../../../features/docs/Troubleshooting.utils.js'
/**
* Loader for troubleshooting articles from local MDX files.
*
* The path format is `/guides/troubleshooting/{slug}` where slug is derived
* from the filename (e.g., `auth-error-handling.mdx` → `auth-error-handling`).
*/
export class TroubleshootingLoader extends BaseLoader {
type = 'troubleshooting' as const
constructor(
source: string,
public entry: ITroubleshootingEntry
) {
const slug = getArticleSlug(entry)
super(source, `/guides/troubleshooting/${slug}`)
}
async load(): Promise<TroubleshootingSource[]> {
return [new TroubleshootingSource(this.source, this.path, this.entry)]
}
}
/**
* Search source for a single troubleshooting article.
*
* Each article becomes one indexed page with a single section containing
* the full content. This differs from guide pages which may have multiple
* sections based on headings.
*/
export class TroubleshootingSource extends BaseSource {
type = 'troubleshooting' as const
constructor(
source: string,
path: string,
public entry: ITroubleshootingEntry
) {
super(source, path)
}
async process() {
const { title, topics, keywords } = this.entry.data
const content = this.entry.contentWithoutJsx
// Include title and metadata in checksum so any changes trigger re-indexing.
// This ensures updates to title, topics, or keywords are picked up even if
// the main content hasn't changed.
const checksum = createHash('sha256')
.update(JSON.stringify({ title, topics, keywords, content }))
.digest('base64')
const meta = { title, topics, keywords }
// Troubleshooting articles are single-section pages (no sub-headings indexed).
// We explicitly set slug to undefined so the database's `get_full_content_url`
// function returns the page URL without a fragment (e.g., no trailing `#slug`).
// This is handled in SQL: `CASE WHEN slug IS NULL THEN '' ELSE concat('#', slug) END`
const sections = [
{
heading: title,
slug: undefined as string | undefined,
content: `# ${title}\n${content}`,
},
]
this.checksum = checksum
this.meta = meta
this.sections = sections
return { checksum, meta, sections }
}
/**
* Returns the full article content formatted for full-text search indexing.
* The title is included as a heading to boost its relevance in search results.
*/
extractIndexedContent(): string {
return `# ${this.entry.data.title}\n\n${this.entry.contentWithoutJsx}`
}
}
/**
* Loads all troubleshooting articles from `content/troubleshooting/` directory.
*
* Each MDX file is parsed, validated, and converted to a TroubleshootingLoader.
* Hidden files (prefixed with `_`) are excluded.
*
* @returns Array of loaders, one per troubleshooting article
*/
export async function fetchTroubleshootingSources(): Promise<TroubleshootingLoader[]> {
const entries = (await getAllTroubleshootingEntriesInternal()) as ITroubleshootingEntry[]
return entries.map((entry) => new TroubleshootingLoader('troubleshooting', entry))
}
+6 -12
View File
@@ -1,11 +1,11 @@
{
"rules": {
"react-hooks/exhaustive-deps": 209,
"react-hooks/exhaustive-deps": 208,
"import/no-anonymous-default-export": 57,
"@tanstack/query/exhaustive-deps": 13,
"@typescript-eslint/no-explicit-any": 1215,
"@typescript-eslint/no-explicit-any": 1214,
"no-restricted-imports": 59,
"no-restricted-exports": 300,
"no-restricted-exports": 297,
"react/no-unstable-nested-components": 69
},
"ruleFiles": {
@@ -56,7 +56,6 @@
"components/interfaces/Integrations/Queues/SingleQueue/QueueSettings.tsx": 1,
"components/interfaces/Integrations/Queues/SingleQueue/SendMessageModal.tsx": 1,
"components/interfaces/Integrations/Wrappers/WrapperDynamicColumns.tsx": 1,
"components/interfaces/Integrations/templates/StripeSyncEngine/InstallationOverview.tsx": 1,
"components/interfaces/Observability/DatabaseInfrastructureSection.tsx": 1,
"components/interfaces/Observability/useSlowQueriesCount.ts": 1,
"components/interfaces/Organization/BillingSettings/BillingCustomerData/useBillingCustomerDataForm.ts": 1,
@@ -302,7 +301,6 @@
"components/interfaces/Database/Backups/PITR/PITR.utils.ts": 1,
"components/interfaces/Database/Backups/RestoreToNewProject/BackupsList.tsx": 1,
"components/interfaces/Database/EnumeratedTypes/CreateEnumeratedTypeSidePanel.tsx": 2,
"components/interfaces/Database/EnumeratedTypes/DeleteEnumeratedTypeModal.tsx": 1,
"components/interfaces/Database/EnumeratedTypes/EditEnumeratedTypeSidePanel.tsx": 2,
"components/interfaces/Database/EnumeratedTypes/EnumeratedTypeValueRow.tsx": 1,
"components/interfaces/Database/Functions/CreateFunction/FunctionEditor.tsx": 1,
@@ -318,7 +316,6 @@
"components/interfaces/Database/Replication/UpdateVersionModal.tsx": 2,
"components/interfaces/Database/RestoreToNewProject/RestoreToNewProject.tsx": 1,
"components/interfaces/Database/Roles/RoleRow.tsx": 4,
"components/interfaces/Database/Roles/RolesList.tsx": 1,
"components/interfaces/Database/Schemas/SchemaGraph.tsx": 1,
"components/interfaces/Database/Tables/ColumnList.tsx": 2,
"components/interfaces/Docs/Description.tsx": 2,
@@ -446,7 +443,6 @@
"components/interfaces/Settings/Logs/PreviewFilterPanel.tsx": 1,
"components/interfaces/Settings/Logs/PreviewFilterPanelWithUniversal.tsx": 2,
"components/interfaces/Settings/Logs/SidebarV2/SidebarItem.tsx": 1,
"components/interfaces/Sidebar.tsx": 2,
"components/interfaces/SignIn/SignInForm.tsx": 1,
"components/interfaces/SignIn/SignInWithCustom.tsx": 1,
"components/interfaces/SignIn/SignInWithGitHub.tsx": 1,
@@ -485,7 +481,7 @@
"components/interfaces/Support/LinkSupportTicketForm.tsx": 6,
"components/interfaces/TableGridEditor/SidePanelEditor/ActionBar.tsx": 1,
"components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnDefaultValue.tsx": 2,
"components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx": 5,
"components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx": 6,
"components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.utils.ts": 2,
"components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx": 1,
"components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/InputWithSuggestions.tsx": 2,
@@ -494,7 +490,7 @@
"components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/DrilldownViewer/DrilldownPane.tsx": 1,
"components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/DrilldownViewer/DrilldownViewer.tsx": 3,
"components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/index.tsx": 3,
"components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.tsx": 9,
"components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.tsx": 10,
"components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.types.ts": 1,
"components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils.ts": 9,
"components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/TextEditor.tsx": 2,
@@ -620,6 +616,7 @@
"data/documents/dpa-request-mutation.ts": 1,
"data/edge-functions/edge-function-test-mutation.ts": 1,
"data/edge-functions/edge-functions-deploy-mutation.ts": 2,
"data/entitlements/entitlements-query.ts": 1,
"data/fdw/fdw-create-mutation.ts": 1,
"data/fdw/fdw-update-mutation.ts": 1,
"data/fetchers.ts": 12,
@@ -805,7 +802,6 @@
"components/grid/components/header/sort/SortRow.tsx": 1,
"components/interfaces/Account/TOTPFactors/DeleteFactorModal.tsx": 1,
"components/interfaces/App/CommandMenu/CommandMenu.tsx": 1,
"components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx": 1,
"components/interfaces/Auth/AuthProvidersForm/FormField.tsx": 1,
"components/interfaces/Auth/Policies/PolicyEditor/PolicyAllowedOperation.tsx": 1,
"components/interfaces/Auth/Policies/PolicyEditor/PolicyDefinition.tsx": 1,
@@ -836,12 +832,10 @@
"components/interfaces/Database/Backups/PITR/PITRStatus.tsx": 1,
"components/interfaces/Database/Backups/PITR/TimeInput.tsx": 1,
"components/interfaces/Database/EnumeratedTypes/CreateEnumeratedTypeSidePanel.tsx": 1,
"components/interfaces/Database/EnumeratedTypes/DeleteEnumeratedTypeModal.tsx": 1,
"components/interfaces/Database/EnumeratedTypes/EditEnumeratedTypeSidePanel.tsx": 1,
"components/interfaces/Database/EnumeratedTypes/EnumeratedTypeValueRow.tsx": 1,
"components/interfaces/Database/Extensions/ExtensionCardSkeleton.tsx": 1,
"components/interfaces/Database/Functions/FunctionsList/FunctionList.tsx": 1,
"components/interfaces/Database/Functions/FunctionsList/FunctionsList.tsx": 1,
"components/interfaces/Database/Indexes/Indexes.tsx": 1,
"components/interfaces/Database/Migrations/Migrations.tsx": 1,
"components/interfaces/Database/Privileges/PrivilegesHead.tsx": 1,
@@ -1,13 +1,13 @@
import type { Sort } from 'components/grid/types'
import { ArrowDown, ArrowUp, ChevronDown, Edit, Lock, Trash, Unlock } from 'lucide-react'
import type { CalculatedColumn } from 'react-data-grid'
import { useTableSort } from 'components/grid/hooks/useTableSort'
import type { Sort } from 'components/grid/types'
import { ArrowDown, ArrowUp, ChevronDown, Copy, Edit, Lock, Trash, Unlock } from 'lucide-react'
import type { CalculatedColumn } from 'react-data-grid'
import { useTableEditorStateSnapshot } from 'state/table-editor'
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
import {
Button,
cn,
copyToClipboard,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -93,9 +93,19 @@ export const ColumnMenu = ({ column, isEncrypted }: ColumnMenuProps) => {
<ArrowDown size={14} strokeWidth={currentSort && !currentSort.ascending ? 3 : 1.5} />
<span>Sort Descending</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
className="space-x-2"
onClick={(e) => {
e.stopPropagation()
copyToClipboard(columnName)
}}
>
<Copy size={12} />
<span>Copy name</span>
</DropdownMenuItem>
{snap.editable && (
<>
<DropdownMenuSeparator />
<Tooltip>
<TooltipTrigger asChild className={`${isEncrypted ? 'opacity-50' : ''}`}>
<DropdownMenuItem
@@ -57,7 +57,7 @@ export const UserPanel = () => {
return (
<>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={30} maxSize={45} minSize={30} className="bg-studio border-t">
<ResizablePanel defaultSize="30" maxSize="45" minSize="30" className="bg-studio border-t">
<Button
type="text"
className="absolute top-3 right-3 px-1"
@@ -751,11 +751,11 @@ export const UsersV2 = () => {
</div>
<LoadingLine loading={isLoading || isRefetching || isFetchingNextPage} />
<ResizablePanelGroup
direction="horizontal"
orientation="horizontal"
className="relative flex flex-grow bg-alternative min-h-0"
autoSaveId="query-performance-layout-v1"
>
<ResizablePanel defaultSize={1}>
<ResizablePanel>
<div className="flex flex-col w-full h-full">
<DataGrid
ref={gridRef}
@@ -3,7 +3,6 @@ import Link from 'next/link'
import { useParams } from 'common'
import { DOCS_URL } from 'lib/constants'
import { Button } from 'ui'
import { Admonition } from 'ui-patterns/admonition'
import {
PageSection,
PageSectionContent,
@@ -12,6 +11,7 @@ import {
PageSectionTitle,
} from 'ui-patterns'
import { DocsButton } from '../../ui/DocsButton'
import { Admonition } from 'ui-patterns/admonition'
// [Joshen] Only used for non AWS projects
export function DiskManagementPanelForm() {
@@ -28,8 +28,9 @@ export function DiskManagementPanelForm() {
<PageSectionContent>
<Admonition
type="default"
title="Disk management has moved"
description="Disk management is now handled alongside Project Compute on the Compute and Disk page."
layout="responsive"
title="Disk Management has moved"
description="Disk configuration is now managed alongside Project Compute on the new Compute and Disk page."
actions={
<Button type="default" asChild>
<Link href={`/project/${projectRef}/settings/compute-and-disk`}>
@@ -1,10 +1,5 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { Loader2, Plus, Send, X } from 'lucide-react'
import { useState } from 'react'
import { useFieldArray, useForm } from 'react-hook-form'
import * as z from 'zod'
import { useParams } from 'common'
import { RoleImpersonationPopover } from 'components/interfaces/RoleImpersonationSelector/RoleImpersonationPopover'
import { getKeys, useAPIKeysQuery } from 'data/api-keys/api-keys-query'
@@ -18,6 +13,9 @@ import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization
import { IS_PLATFORM } from 'lib/constants'
import { prettifyJSON } from 'lib/helpers'
import { getRoleImpersonationJWT } from 'lib/role-impersonation'
import { Loader2, Plus, Send, X } from 'lucide-react'
import { useState } from 'react'
import { useFieldArray, useForm } from 'react-hook-form'
import {
RoleImpersonationStateContextProvider,
useGetImpersonatedRoleState,
@@ -51,6 +49,8 @@ import {
TextArea_Shadcn_ as Textarea,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import * as z from 'zod'
import { HTTP_METHODS } from './EdgeFunctionDetails.constants'
import { ErrorWithStatus, ResponseData } from './EdgeFunctionDetails.types'
@@ -289,7 +289,28 @@ export const EdgeFunctionTesterSheet = ({ visible, onClose }: EdgeFunctionTester
return (
<Sheet open={visible} onOpenChange={onClose}>
<SheetContent size="default" className="flex flex-col gap-0 p-0">
<SheetContent
size="default"
className="flex flex-col gap-0 p-0"
onPointerDownOutside={(e) => {
// react-resizable-panels v4 registers document-level capture-phase pointer
// handlers that can interfere with Radix Dialog's outside-interaction detection.
// Prevent the sheet from closing when interacting with the resize handle.
const target = (e as CustomEvent<{ originalEvent: PointerEvent }>).detail?.originalEvent
?.target as HTMLElement | null
if (target?.closest?.('[data-separator]')) {
e.preventDefault()
}
}}
onFocusOutside={(e) => {
// The v4 Separator explicitly calls .focus() on itself during pointerdown,
// which can trigger Radix Dialog's focus-outside detection.
const target = e.target as HTMLElement | null
if (target?.closest?.('[data-separator]')) {
e.preventDefault()
}
}}
>
<SheetHeader>
<SheetTitle>Test {functionSlug}</SheetTitle>
</SheetHeader>
@@ -299,7 +320,7 @@ export const EdgeFunctionTesterSheet = ({ visible, onClose }: EdgeFunctionTester
onSubmit={form.handleSubmit(onSubmit)}
className="flex-1 overflow-y-auto flex flex-col"
>
<ResizablePanelGroup direction="vertical">
<ResizablePanelGroup orientation="vertical">
<ResizablePanel>
<div className="flex flex-col gap-y-4 p-5 h-full overflow-y-auto">
<FormField_Shadcn_
@@ -353,7 +374,7 @@ export const EdgeFunctionTesterSheet = ({ visible, onClose }: EdgeFunctionTester
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={41} minSize={41} maxSize={83}>
<ResizablePanel defaultSize="41" minSize="41" maxSize="83">
<div className="h-full bg-surface-100 border-t flex-1 flex flex-col overflow-hidden">
{response ? (
<div className="h-full bg-surface-100 flex flex-col overflow-hidden">
@@ -1,13 +1,13 @@
import { useDebounce, useIntersectionObserver } from '@uidotdev/usehooks'
import { Plus } from 'lucide-react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { ReactNode, useEffect, useMemo, useRef, useState } from 'react'
import { keepPreviousData } from '@tanstack/react-query'
import { useDebounce, useIntersectionObserver } from '@uidotdev/usehooks'
import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import { useContentInfiniteQuery } from 'data/content/content-infinite-query'
import type { Content } from 'data/content/content-query'
import { SNIPPET_PAGE_LIMIT } from 'data/content/sql-folders-query'
import { Plus } from 'lucide-react'
import { ReactNode, useEffect, useMemo, useRef, useState } from 'react'
import { editorPanelState } from 'state/editor-panel-state'
import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state'
import {
Command_Shadcn_,
CommandGroup_Shadcn_,
@@ -42,7 +42,7 @@ export const SnippetDropdown = ({
autoFocus = false,
onSelect,
}: SnippetDropdownProps) => {
const router = useRouter()
const { openSidebar } = useSidebarManagerSnapshot()
const scrollRootRef = useRef<HTMLDivElement | null>(null)
const [open, setOpen] = useState(false)
@@ -133,20 +133,14 @@ export const SnippetDropdown = ({
className="cursor-pointer w-full"
onSelect={() => {
setOpen(false)
router.push(`/project/${projectRef}/sql/new`)
editorPanelState.openAsNew()
openSidebar(SIDEBAR_KEYS.EDITOR_PANEL)
}}
onClick={() => setOpen(false)}
>
<Link
href={`/project/${projectRef}/sql/new`}
onClick={() => {
setOpen(false)
}}
className="w-full flex items-center gap-2"
>
<div className="w-full flex items-center gap-2">
<Plus size={14} strokeWidth={1.5} />
<p>Create a report block with SQL</p>
</Link>
<p>Create snippet</p>
</div>
</CommandItem_Shadcn_>
</CommandGroup_Shadcn_>
</CommandList_Shadcn_>
@@ -77,11 +77,15 @@ export const MessageDetailsPanel = ({
return (
<ResizablePanel
defaultSize={30}
maxSize={45}
minSize={30}
defaultSize="30"
maxSize="45"
minSize="30"
collapsible
onCollapse={() => setSelectedMessage(null)}
onResize={(panelSize) => {
if (panelSize.asPercentage === 0) {
setSelectedMessage(null)
}
}}
className="bg-studio border-t pointer-events-auto"
>
<Button
@@ -4,13 +4,13 @@ import { useRouter } from 'next/router'
import { parseAsInteger, useQueryState } from 'nuqs'
import { UIEvent, useMemo, useRef } from 'react'
import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid'
import AlertError from 'components/ui/AlertError'
import { PostgresQueueMessage } from 'data/database-queues/database-queue-messages-infinite-query'
import type { ResponseError } from 'types'
import { Badge, Button, ResizableHandle, ResizablePanel, ResizablePanelGroup, cn } from 'ui'
import { Badge, Button, cn, ResizableHandle, ResizablePanel, ResizablePanelGroup } from 'ui'
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
import { DATE_FORMAT, MessageDetailsPanel } from './MessageDetailsPanel'
import AlertError from '@/components/ui/AlertError'
import { PostgresQueueMessage } from '@/data/database-queues/database-queue-messages-infinite-query'
import type { ResponseError } from '@/types'
interface QueueDataGridProps {
error?: ResponseError | null
@@ -179,8 +179,6 @@ export const QueueMessagesDataGrid = ({
if (typeof idx === 'number' && idx >= 0) {
setSelectedMessageId(props.row.msg_id)
gridRef.current?.scrollToCell({ idx: 0, rowIdx: idx })
const { messageId, ...rest } = router.query
router.push({ ...router, query: { ...rest, messageId: props.row.msg_id } })
}
}}
/>
@@ -211,11 +209,11 @@ export const QueueMessagesDataGrid = ({
}}
/>
<ResizablePanelGroup
direction="horizontal"
orientation="horizontal"
className="absolute inset-0 z-10 pointer-events-none"
autoSaveId="queue-messages-layout-v1"
>
<ResizablePanel defaultSize={1} />
<ResizablePanel />
{selectedMessage && (
<>
<ResizableHandle withHandle className="pointer-events-auto" />
@@ -1,9 +1,11 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { useStripeSyncInstallMutation } from 'data/database-integrations/stripe/stripe-sync-install-mutation'
import { useStripeSyncUninstallMutation } from 'data/database-integrations/stripe/stripe-sync-uninstall-mutation'
import { useSchemasQuery } from 'data/database/schemas-query'
import { formatRelative } from 'date-fns'
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { useTrack } from 'lib/telemetry/track'
import { AlertCircle, BadgeCheck, Check, ExternalLink, RefreshCwIcon } from 'lucide-react'
@@ -73,6 +75,12 @@ export const StripeSyncInstallationPage = () => {
connectionString: project?.connectionString,
})
// Check permissions for managing function secrets
const { can: canManageSecrets } = useAsyncCheckPermissions(
PermissionAction.FUNCTIONS_SECRET_WRITE,
'*'
)
const isSyncing = isSyncRunning(syncState)
const installed = isInstalled(installationStatus)
@@ -328,12 +336,14 @@ export const StripeSyncInstallationPage = () => {
<ButtonTooltip
type="primary"
onClick={() => setShouldShowInstallSheet(true)}
disabled={!canInstall}
disabled={!canInstall || !canManageSecrets}
tooltip={{
content: {
text: !canInstall
? 'Your database already uses a schema named "stripe"'
: undefined,
: !canManageSecrets
? 'You need additional permissions to install the Stripe Sync Engine.'
: undefined,
},
}}
>
@@ -343,9 +353,20 @@ export const StripeSyncInstallationPage = () => {
</>
) : installed && !uninstalling ? (
<div className="flex justify-end mt-4">
<Button type="default" onClick={() => setShowUninstallModal(true)}>
<ButtonTooltip
type="default"
onClick={() => setShowUninstallModal(true)}
disabled={!canManageSecrets}
tooltip={{
content: {
text: !canManageSecrets
? 'You need additional permissions to uninstall the Stripe Sync Engine.'
: undefined,
},
}}
>
Uninstall integration
</Button>
</ButtonTooltip>
</div>
) : null
}
@@ -1,23 +1,23 @@
import { X } from 'lucide-react'
import { useRef } from 'react'
import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid'
import ReactMarkdown from 'react-markdown'
import { useParams } from 'common'
import { LINTER_LEVELS } from 'components/interfaces/Linter/Linter.constants'
import {
LintCategoryBadge,
LintEntity,
NoIssuesFound,
lintInfoMap,
NoIssuesFound,
} from 'components/interfaces/Linter/Linter.utils'
import { Lint } from 'data/lint/lint-query'
import { useRouter } from 'next/router'
import { useTrack } from 'lib/telemetry/track'
import { Button, ResizableHandle, ResizablePanel, ResizablePanelGroup, cn } from 'ui'
import { X } from 'lucide-react'
import { useRouter } from 'next/router'
import { useRef } from 'react'
import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid'
import ReactMarkdown from 'react-markdown'
import { Button, cn, ResizableHandle, ResizablePanel, ResizablePanelGroup } from 'ui'
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
import { EntityTypeIcon } from './Linter.utils'
import LintDetail from './LintDetail'
import { EntityTypeIcon } from './Linter.utils'
interface LinterDataGridProps {
isLoading: boolean
@@ -117,11 +117,11 @@ const LinterDataGrid = ({
return (
<ResizablePanelGroup
direction="horizontal"
orientation="horizontal"
className="relative flex flex-grow bg-alternative min-h-0"
autoSaveId="linter-layout-v1"
>
<ResizablePanel defaultSize={1}>
<ResizablePanel>
<DataGrid
ref={gridRef}
style={{ height: '100%' }}
@@ -177,9 +177,9 @@ const LinterDataGrid = ({
<>
<ResizableHandle withHandle />
<ResizablePanel
defaultSize={30}
maxSize={45}
minSize={30}
defaultSize="30"
maxSize="45"
minSize="30"
className="bg-studio border-t flex flex-col h-full"
>
<div className="flex items-center justify-between w-full border-b py-3 px-6">
@@ -1,17 +1,18 @@
import { useDebounce } from '@uidotdev/usehooks'
import { Home } from 'lucide-react'
import { useState } from 'react'
import { useParams } from 'common'
import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import { useContentQuery } from 'data/content/content-query'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
import { Metric, METRIC_CATEGORIES, METRICS } from 'lib/constants/metrics'
import { Home, Plus } from 'lucide-react'
import { useState } from 'react'
import { editorPanelState } from 'state/editor-panel-state'
import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state'
import type { Dashboards } from 'types'
import {
Command_Shadcn_,
CommandEmpty_Shadcn_,
CommandGroup_Shadcn_,
CommandInput_Shadcn_,
CommandItem_Shadcn_,
@@ -24,6 +25,7 @@ import {
SQL_ICON,
} from 'ui'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import { DEPRECATED_REPORTS } from './Reports.constants'
interface MetricOptionsProps {
@@ -40,6 +42,7 @@ interface MetricOptionsProps {
export const MetricOptions = ({ config, handleChartSelection }: MetricOptionsProps) => {
const { ref: projectRef } = useParams()
const { data: selectedOrganization } = useSelectedOrganizationQuery()
const { openSidebar } = useSidebarManagerSnapshot()
const [search, setSearch] = useState('')
const { projectAuthAll: authEnabled, projectStorageAll: storageEnabled } = useIsFeatureEnabled([
@@ -56,7 +59,11 @@ export const MetricOptions = ({ config, handleChartSelection }: MetricOptionsPro
const { mutate: sendEvent } = useSendEventMutation()
const debouncedSearch = useDebounce(search, 300)
const { data, isPending: isLoading } = useContentQuery({
const {
data,
isPending: isLoading,
refetch,
} = useContentQuery({
projectRef,
type: 'sql',
name: debouncedSearch.length === 0 ? undefined : debouncedSearch,
@@ -96,7 +103,11 @@ export const MetricOptions = ({ config, handleChartSelection }: MetricOptionsPro
</DropdownMenuSub>
)
})}
<DropdownMenuSub>
<DropdownMenuSub
onOpenChange={(open) => {
if (open) refetch()
}}
>
<DropdownMenuSubTrigger className="space-x-2">
<SQL_ICON
size={14}
@@ -120,9 +131,11 @@ export const MetricOptions = ({ config, handleChartSelection }: MetricOptionsPro
<ShimmeringLoader />
<ShimmeringLoader className="w-3/4" />
</div>
) : (
<CommandEmpty_Shadcn_>No snippets found</CommandEmpty_Shadcn_>
)}
) : !snippets?.length ? (
<p className="text-xs text-center text-foreground-lighter py-3">
No snippets found
</p>
) : null}
<CommandGroup_Shadcn_>
{snippets?.map((snippet) => (
<CommandItem_Shadcn_
@@ -154,6 +167,23 @@ export const MetricOptions = ({ config, handleChartSelection }: MetricOptionsPro
))}
</CommandGroup_Shadcn_>
</CommandList_Shadcn_>
<div className="h-px bg-border-overlay -mx-1" />
<CommandGroup_Shadcn_>
<CommandItem_Shadcn_
className="cursor-pointer w-full"
onSelect={() => {
editorPanelState.openAsNew()
openSidebar(SIDEBAR_KEYS.EDITOR_PANEL)
}}
>
<div className="w-full flex items-center gap-2">
<Plus size={14} strokeWidth={1.5} />
<p>Create snippet</p>
</div>
</CommandItem_Shadcn_>
</CommandGroup_Shadcn_>
</Command_Shadcn_>
</DropdownMenuSubContent>
</DropdownMenuPortal>
@@ -1,12 +1,5 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useQueryClient } from '@tanstack/react-query'
import dayjs from 'dayjs'
import { groupBy, isEqual, isNull } from 'lodash'
import { ArrowRight, Plus, RefreshCw, Save } from 'lucide-react'
import { useRouter } from 'next/router'
import { DragEvent, useEffect, useState } from 'react'
import { toast } from 'sonner'
import { useParams } from 'common'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { DatabaseSelector } from 'components/ui/DatabaseSelector'
@@ -21,6 +14,7 @@ import {
useContentUpsertMutation,
} from 'data/content/content-upsert-mutation'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
import dayjs from 'dayjs'
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
@@ -28,10 +22,16 @@ import { BASE_PATH } from 'lib/constants'
import { Metric, TIME_PERIODS_REPORTS } from 'lib/constants/metrics'
import { uuidv4 } from 'lib/helpers'
import { useProfile } from 'lib/profile'
import { groupBy, isEqual, isNull } from 'lodash'
import { Plus, RefreshCw, Save } from 'lucide-react'
import { useRouter } from 'next/router'
import { DragEvent, useEffect, useState } from 'react'
import { toast } from 'sonner'
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
import type { Dashboards } from 'types'
import { Button, cn, DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, LogoLoader } from 'ui'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { createSqlSnippetSkeletonV2 } from '../SQLEditor/SQLEditor.utils'
import { ChartConfig } from '../SQLEditor/UtilityPanel/ChartConfig'
import { GridResize } from './GridResize'
@@ -450,20 +450,6 @@ const Reports = () => {
</div>
}
/>
{startDate && endDate && (
<div className="hidden items-center space-x-1 lg:flex ">
<span className="text-sm text-foreground-light">
{dayjs(startDate).format('MMM D, YYYY')}
</span>
<span className="text-foreground-lighter">
<ArrowRight size={12} />
</span>
<span className="text-sm text-foreground-light">
{dayjs(endDate).format('MMM D, YYYY')}
</span>
</div>
)}
</div>
</div>
@@ -784,10 +784,10 @@ export const SQLEditor = () => {
<div className="flex h-full">
<ResizablePanelGroup
className="relative"
direction="vertical"
orientation="vertical"
autoSaveId={LOCAL_STORAGE_KEYS.SQL_EDITOR_SPLIT_SIZE}
>
<ResizablePanel defaultSize={50} maxSize={70}>
<ResizablePanel defaultSize="50" maxSize="70">
<div className="flex-grow overflow-y-auto border-b h-full">
{isLoading ? (
<div className="flex h-full w-full items-center justify-center">
@@ -898,7 +898,7 @@ export const SQLEditor = () => {
<ResizableHandle withHandle />
<ResizablePanel defaultSize={50} maxSize={70}>
<ResizablePanel defaultSize="50" maxSize="70">
{isLoading ? (
<div className="flex h-full w-full items-center justify-center">
<Loader2 className="animate-spin text-brand" />
@@ -132,10 +132,10 @@ export const ChartConfig = ({
}
return (
<ResizablePanelGroup direction="horizontal" className="flex-grow h-full">
<ResizablePanel className="p-4 h-full" defaultSize={75}>
<ResizablePanelGroup orientation="horizontal" className="flex-grow h-full">
<ResizablePanel className="p-4 h-full" defaultSize="75">
{!hasConfig ? (
<ResizablePanel className="p-4 h-full" defaultSize={75}>
<ResizablePanel className="p-4 h-full" defaultSize="75">
<NoDataPlaceholder
size="normal"
title="Configure your chart"
@@ -173,8 +173,8 @@ export const ChartConfig = ({
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel
defaultSize={25}
minSize={15}
defaultSize="25"
minSize="15"
className="px-3 py-3 space-y-4 !overflow-y-auto"
>
<div className="flex justify-between items-center h-5">
Loaded 100 of 268 files, more files were not shown because too many files have changed in this diff. Show more