diff --git a/.github/workflows/studio-knip.yml b/.github/workflows/studio-knip.yml new file mode 100644 index 00000000000..4c77a22d797 --- /dev/null +++ b/.github/workflows/studio-knip.yml @@ -0,0 +1,65 @@ +name: Studio Dead Code (knip) + +on: + push: + branches: + - master + paths: + - 'apps/studio/**' + - 'knip.jsonc' + - 'package.json' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + - '.github/workflows/studio-knip.yml' + # No `branches` filter: stacked PRs target a sibling branch, not master, and + # the gate should still run on them. + pull_request: + paths: + - 'apps/studio/**' + - 'knip.jsonc' + - 'package.json' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + - '.github/workflows/studio-knip.yml' + +# Cancel old builds on new commit for same workflow + branch/PR +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + knip: + # Uses larger hosted runner as it significantly decreases build times + runs-on: blacksmith-4vcpu-ubuntu-2404 + env: + NODE_OPTIONS: --max-old-space-size=6144 + + steps: + # No sparse-checkout: knip resolves the whole pnpm workspace graph, so it + # needs every workspace's package.json present even when scoped to studio. + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + name: Install pnpm + with: + run_install: false + + - name: Use Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version-file: '.nvmrc' + cache: 'pnpm' + + - name: Install deps + run: pnpm install --frozen-lockfile + + # `symbols` keeps the readable table in the job log, `github-actions` adds + # the same findings as inline PR annotations. + - name: Run knip + run: pnpm knip --workspace apps/studio --no-progress --reporter symbols --reporter github-actions diff --git a/apps/docs/content/guides/deployment/branching.mdx b/apps/docs/content/guides/deployment/branching.mdx index 23342dd4c89..d4f3ed3ca11 100644 --- a/apps/docs/content/guides/deployment/branching.mdx +++ b/apps/docs/content/guides/deployment/branching.mdx @@ -15,7 +15,8 @@ Supabase branches create separate environments that spin off from your main proj - **Preview Branches**: Preview branches are ephemeral and best suited for focused testing. They are automatically deleted when a PR is merged or closed. - **Persistent Branches**: Persistent branches are long-lived and recommended for environments like staging, QA, or development. They aren't automatically paused or deleted due to inactivity or when a PR is merged or closed. - **Managing Branches**: You can create, review, and merge branches either automatically via our [GitHub integration](/docs/guides/deployment/branching/github-integration) or directly [through the dashboard](/docs/guides/deployment/branching/dashboard) (currently in beta). All branches show up in the branches page in the dashboard, regardless of how they were created. -- **Data-less**: New branches do not start with any data from your main project. This is meant to better protect your sensitive production data. To start your branches with data, you can use a [seed file](/docs/guides/deployment/branching/github-integration#seeding) if using the GitHub integration. +- **Cloned from your main project**: Each new branch is created as a clone of your main project. It starts with that project's Edge Functions deployed and the configuration set. +- **Data-less by default**: By default, new branches do not start with any data or storage objects from your main project. This is meant to better protect your sensitive production data. To start your branches with data, you can use a [seed file](/docs/guides/deployment/branching/github-integration#seeding) if using the GitHub integration, or the [Include data](/docs/guides/deployment/branching/dashboard#include-production-data) option if you create the branch from the dashboard. ## Deploying to production diff --git a/apps/docs/content/guides/deployment/branching/dashboard.mdx b/apps/docs/content/guides/deployment/branching/dashboard.mdx index ad1ae7021c8..e10efb1c2ce 100644 --- a/apps/docs/content/guides/deployment/branching/dashboard.mdx +++ b/apps/docs/content/guides/deployment/branching/dashboard.mdx @@ -41,6 +41,24 @@ Once you've enabled the feature, you can create a new branch: 1. Click the arrows next to the branch name in the top menu bar. (The top menu bar has the format `YOUR_ORGANIZATION / YOUR_PROJECT / CURRENT_BRANCH_NAME`.) 2. Click `Create branch`. +The new branch is a clone of your base project. It starts with the project's schema, Edge Functions, and the configuration set. + +### Include production data + +By default, a branch starts without any of your production data or storage objects. If your project has the Point-in-Time Recovery add-on, you can turn on **Include data** when you create the branch to copy your production data into it. + + + +A branch created with **Include data** holds a copy of your production data, treat it with the same care as production. + + + + + +A branch uses a larger disk and matches the compute size of your project, which increases its cost. + + + ## Making changes to a branch Use the branch selector in the top bar to change to your branch. Any changes you make (including SQL run in the SQL editor, table editor changes, and configuration changes) are now made against the currently selected branch. diff --git a/apps/docs/content/guides/deployment/branching/github-integration.mdx b/apps/docs/content/guides/deployment/branching/github-integration.mdx index c04cb14f4fe..cb81e3bff72 100644 --- a/apps/docs/content/guides/deployment/branching/github-integration.mdx +++ b/apps/docs/content/guides/deployment/branching/github-integration.mdx @@ -83,19 +83,25 @@ Enable the **Automatic branching** option in your GitHub Integration configurati When a new branch is created in GitHub, a corresponding branch is created in Supabase. (You can enable the **Supabase changes only** option to only create Supabase branches when Supabase files change.) +Every Supabase branch, preview or persistent, is created as a clone of your base project. The new branch starts with the Edge Functions and configuration of that project. Its database schema is not cloned. Instead, it is built from the migrations you commit to your repository. + ### Configuration You can test configuration changes on your Preview Branch by configuring the `config.toml` file in your Supabase directory. See the [Configuration docs](/docs/guides/deployment/branching/configuration) for more information. +Your branch starts with the configuration of your base project. The settings in your `config.toml` file are applied on top of that clone. + A comment is added to your PR with the deployment status of your preview branch. ### Migrations -The migrations in the `migrations` subdirectory of your Supabase directory are automatically run. +The migrations in the `migrations` subdirectory of your Supabase directory are automatically run when the branch is created. Each later commit runs only the migrations that haven't been applied yet. + +If you want to rerun existing migrations, reset the branch from the Supabase dashboard to start from scratch. Note that existing data on your branch will also be dropped by a reset. ### Seeding -No production data is copied to your Preview branch. This is meant to protect your sensitive production data. +Cloning your base project copies its Edge Functions and configuration, but not its data or storage objects. This is meant to protect your sensitive production data. Your branch starts with the tables your migrations create, and the only rows in them are the ones your seed files add. You can seed your Preview Branch with sample data using the `seed.sql` file in your Supabase directory. See the [Seeding docs](/docs/guides/local-development/seeding-your-database) for more information. diff --git a/apps/docs/content/guides/deployment/branching/troubleshooting.mdx b/apps/docs/content/guides/deployment/branching/troubleshooting.mdx index 6e77b2c1768..1fd9194c40c 100644 --- a/apps/docs/content/guides/deployment/branching/troubleshooting.mdx +++ b/apps/docs/content/guides/deployment/branching/troubleshooting.mdx @@ -27,7 +27,9 @@ You might want to roll back changes you've made in an earlier migration change. To fix this, push the latest changes, then delete the preview branch in Supabase and reopen it. -The new preview branch is reseeded from the `./supabase/seed.sql` file by default. Any additional data changes made on the old preview branch are lost. This is equivalent to running `supabase db reset` locally. All migrations are rerun in sequential order. +The new preview branch is a fresh clone of your base project and is reseeded from the `./supabase/seed.sql` file by default. Any additional data changes made on the old preview branch are lost. + +To rerun migrations that your base project has already applied, reset the branch from the Supabase dashboard instead. A reset reruns all migrations in sequential order and drops existing data on the branch. ### Deployment failures diff --git a/apps/docs/content/guides/deployment/branching/working-with-branches.mdx b/apps/docs/content/guides/deployment/branching/working-with-branches.mdx index ecdceb08658..c007f17cf5f 100644 --- a/apps/docs/content/guides/deployment/branching/working-with-branches.mdx +++ b/apps/docs/content/guides/deployment/branching/working-with-branches.mdx @@ -181,7 +181,7 @@ After completing the steps above, you should receive a Slack message whenever an Migrations are run in sequential order. Each migration builds upon the previous one. -The preview branch has a record of which migrations have been applied, and only applies new migrations for each commit. This can create an issue when rolling back migrations. +The preview branch inherits the migration history of your base project, so it only applies migrations that haven't been run yet. This can create an issue when rolling back migrations. ### Using ORM or custom seed scripts @@ -237,7 +237,9 @@ You might want to roll back changes you've made in an earlier migration change. To fix this, push the latest changes, then delete the preview branch in Supabase and reopen it. -The new preview branch is reseeded from the `./supabase/seed.sql` file by default. Any additional data changes made on the old preview branch are lost. This is equivalent to running `supabase db reset` locally. All migrations are rerun in sequential order. +The new preview branch is a fresh clone of your base project and is reseeded from the `./supabase/seed.sql` file by default. Any additional data changes made on the old preview branch are lost. + +To rerun migrations that your base project has already applied, reset the branch from the Supabase dashboard instead. A reset reruns all migrations in sequential order and drops existing data on the branch. ### Seeding behavior diff --git a/apps/studio/CLAUDE.md b/apps/studio/CLAUDE.md index 5d4790ba751..f1f084c3192 100644 --- a/apps/studio/CLAUDE.md +++ b/apps/studio/CLAUDE.md @@ -75,6 +75,7 @@ Older Studio code predates some of these conventions. For new or modified code, ## Defaults that differ here - **ESLint warnings are ratcheted in CI**: the per-rule occurrence count must not increase, so a new `any`, unresolved `exhaustive-deps` warning, or default export fails the build even though it's "only a warning". Check locally with `pnpm --filter studio run lint:ratchet`. +- **Dead files and deps are gated in CI** by knip (`pnpm knip --workspace apps/studio` locally). Framework-convention files nothing imports (routes, Vercel functions, TanStack Start files) belong in `knip.jsonc` under `workspaces["apps/studio"].entry`, not `ignore` — an ignored file's imports aren't traced, so anything only it uses gets reported as dead. There's no inline `knip-ignore` comment; the only per-file opt-out is config. In a PR stack, a file whose first consumer lands in a later PR fails the gate on the earlier one — either add it in the same PR as its first use, or add it to `workspaces["apps/studio"].ignore` with a `used from #NNN` comment and remove it in that PR. - **Clipboard**: `copyToClipboard` from `'ui'`, and never `await` anything before calling it (Safari requires the write inside the user gesture; lint-enforced) — pass a Promise as the argument instead. - **`useParams()` comes from `'common'`**, not `next/navigation` — it camelCases keys and returns `string | undefined`. - **Permissions**: `useAsyncCheckPermissions` from `hooks/misc/useCheckPermissions` (returns `can: true` when self-hosted). diff --git a/apps/studio/TANSTACK_MIGRATION.md b/apps/studio/TANSTACK_MIGRATION.md index 6c46f6e67b3..a120561fce4 100644 --- a/apps/studio/TANSTACK_MIGRATION.md +++ b/apps/studio/TANSTACK_MIGRATION.md @@ -232,6 +232,7 @@ These are the layout-only TanStack files. Most hold a single product layout comp ### Project shell — `/workers/*` - [x] A `routes/project/$ref/workers/index.tsx` ← `pages/project/[ref]/workers/index.tsx` +- [x] A `routes/project/$ref/workers/$name.tsx` ← `pages/project/[ref]/workers/[name].tsx` ### Project shell — `/functions/*` diff --git a/apps/studio/components/interfaces/Billing/Usage/UsageWarningAlerts/CPUWarnings.tsx b/apps/studio/components/interfaces/Billing/Usage/UsageWarningAlerts/CPUWarnings.tsx deleted file mode 100644 index 55355b89259..00000000000 --- a/apps/studio/components/interfaces/Billing/Usage/UsageWarningAlerts/CPUWarnings.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { AlertTitle } from '@ui/components/shadcn/ui/alert' -import { AlertCircle } from 'lucide-react' -import Link from 'next/link' -import { Alert, AlertDescription, Button } from 'ui' - -import { DOCS_URL } from '@/lib/constants' - -interface CPUWarningsProps { - hasAccessToComputeSizes: boolean - upgradeUrl: string - severity?: 'warning' | 'critical' | null -} - -export const CPUWarnings = ({ - hasAccessToComputeSizes, - upgradeUrl, - severity, -}: CPUWarningsProps) => { - if (severity === 'warning') { - return ( - - - Your max CPU usage has exceeded 80% - - High CPU usage could result in slower queries, disruption of daily back up routines, and - in rare cases, your instance may become unresponsive. If you need more resources, consider - upgrading to a larger compute add-on. - -
- - -
-
- ) - } - - if (severity === 'critical') { - return ( - - - Your max CPU usage has reached 100% - - High CPU usage could result in slower queries, disruption of daily back up routines, and - in rare cases, your instance may become unresponsive. If you need more resources, consider - upgrading to a larger compute add-on. - -
- - -
-
- ) - } - - return null -} diff --git a/apps/studio/components/interfaces/Billing/Usage/UsageWarningAlerts/DiskIOBandwidthWarnings.tsx b/apps/studio/components/interfaces/Billing/Usage/UsageWarningAlerts/DiskIOBandwidthWarnings.tsx deleted file mode 100644 index 21a1d5428c3..00000000000 --- a/apps/studio/components/interfaces/Billing/Usage/UsageWarningAlerts/DiskIOBandwidthWarnings.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import Link from 'next/link' -import { Button } from 'ui' -import { Admonition } from 'ui-patterns/Admonition' - -// [Joshen] In the future, conditionals should be from resource exhaustion endpoint as single source of truth -interface DiskIOBandwidthWarningsProps { - hasAccessToComputeSizes: boolean - hasLatest: boolean - upgradeUrl: string - currentBillingCycleSelected: boolean - latestIoBudgetConsumption: number - highestIoBudgetConsumption: number -} - -export const DiskIOBandwidthWarnings = ({ - hasAccessToComputeSizes, - hasLatest, - currentBillingCycleSelected, - upgradeUrl, - latestIoBudgetConsumption, - highestIoBudgetConsumption, -}: DiskIOBandwidthWarningsProps) => { - if (hasLatest && latestIoBudgetConsumption >= 100) { - return ( - -

- Your workload has used up all your Disk IO Budget and is now running at the baseline - performance. If you need consistent disk performance, consider upgrading to a larger - compute add-on. -

- - - } - /> - ) - } - - if (hasLatest && latestIoBudgetConsumption >= 80) { - return ( - -

- Your workload has consumed {latestIoBudgetConsumption}% of your Disk IO Budget. If you - use up all your Disk IO Budget, your instance will reverted to baseline performance. - If you need consistent disk performance, consider upgrading to a larger compute - add-on. -

- - - } - /> - ) - } - - if (currentBillingCycleSelected && highestIoBudgetConsumption >= 100) { - return ( - -

- Your workload has used up all your Disk IO Budget and reverted to baseline performance - at least once during this billing cycle. If you need consistent disk performance, - consider upgrading to a larger compute add-on. -

- - - } - /> - ) - } - - if (currentBillingCycleSelected && highestIoBudgetConsumption >= 80) { - return ( - -

- Your workload has consumed {highestIoBudgetConsumption}% of your Disk IO budget during - this billing cycle. If you use up all your Disk IO Budget, your instance will reverted - to baseline performance. If you need consistent disk performance, consider upgrading - to a larger compute add-on. -

- - - } - /> - ) - } - - return null -} diff --git a/apps/studio/components/interfaces/Billing/Usage/UsageWarningAlerts/RAMWarnings.tsx b/apps/studio/components/interfaces/Billing/Usage/UsageWarningAlerts/RAMWarnings.tsx deleted file mode 100644 index 4fc8c9b5e35..00000000000 --- a/apps/studio/components/interfaces/Billing/Usage/UsageWarningAlerts/RAMWarnings.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { AlertTitle } from '@ui/components/shadcn/ui/alert' -import { AlertCircle } from 'lucide-react' -import Link from 'next/link' -import { Alert, AlertDescription, Button } from 'ui' - -import { DOCS_URL } from '@/lib/constants' - -interface RAMWarningsProps { - hasAccessToComputeSizes: boolean - upgradeUrl: string - severity?: 'warning' | 'critical' | null -} - -export const RAMWarnings = ({ - hasAccessToComputeSizes, - upgradeUrl, - severity, -}: RAMWarningsProps) => { - if (severity === 'warning') { - return ( - - - Your memory usage has exceeded 80% - - High memory usage could result in overall degraded performance, and in rare cases, your - instance may become unresponsive. If you need more resources, consider upgrading to a - larger compute add-on. - -
- - -
-
- ) - } - - if (severity === 'critical') { - return ( - - - Your memory usage has reached 100% - - High memory usage could result in overall degraded performance, and in rare cases, your - instance may become unresponsive. If you need more resources, consider upgrading to a - larger compute add-on. - -
- - -
-
- ) - } - - return null -} diff --git a/apps/studio/components/interfaces/ConnectSheet/Connect.constants.ts b/apps/studio/components/interfaces/ConnectSheet/Connect.constants.ts index 86071ccaef9..a588f3320dd 100644 --- a/apps/studio/components/interfaces/ConnectSheet/Connect.constants.ts +++ b/apps/studio/components/interfaces/ConnectSheet/Connect.constants.ts @@ -386,6 +386,8 @@ export const PGBOUNCER_ENABLED_BUT_NO_IPV4_ADDON_TEXT = 'Purchase IPv4 add-on or use Shared Pooler if on a IPv4 network' export const IPV4_ADDON_TEXT = 'Connections are IPv4 proxied with IPv4 add-on' +export const CONNECTION_SOURCE_LOAD_BALANCER = 'load-balancer' + export type ConnectionStringMethod = 'direct' | 'transaction' | 'session' export const connectionStringMethodOptions: Record< diff --git a/apps/studio/components/interfaces/ConnectSheet/ConnectConfigSection.tsx b/apps/studio/components/interfaces/ConnectSheet/ConnectConfigSection.tsx index bb21ae25718..9f96b39af66 100644 --- a/apps/studio/components/interfaces/ConnectSheet/ConnectConfigSection.tsx +++ b/apps/studio/components/interfaces/ConnectSheet/ConnectConfigSection.tsx @@ -126,12 +126,14 @@ export function ConnectConfigSection({ layout="horizontal" label={field.label} description={field.description} + name={`connect-${field.id}`} >