Merge branch 'dnywh/chore/polish-database-settings' into dnywh/temp/jit-prototype
No files matched your search
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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).*)',
|
||||
],
|
||||
}
|
||||
|
Before Width: | Height: | Size: 366 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 499 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 676 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 50 KiB |
|
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',
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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">
|
||||
|
||||