Commit Graph
28 Commits
Author SHA1 Message Date
Joshen Lim 1baaded0bb Consolidate execute-sql-query into execute-sql-mutation (#46944)
## Context

Just some clean up as I was going through stuff
- `useExecuteSqlQuery` is deprecated and not used at all
- As such `execute-sql-query` is technically irrelevant, the more
relevant file is `execute-sql-mutation`
- Hence opting to consolidate `execute-sql-query` into
`execute-sql-mutation`
- Also removing `ExecuteSqlError` since its just re-exporting the
`ResponseError` type

There's a lot of file changes but its essentially just updating the
importing statements across the files
2026-06-16 00:07:16 +08:00
Joshen LimandAli Waseem 4691372093 Joshen/fe 3610 projectneedssecuring to avoid fetching all table privileges (#46929)
## Context

The dashboard has an RQ hook that fetches all table privileges in the
database `useTablePrivilegesQuery`
[here](https://github.com/supabase/supabase/blob/master/apps/studio/data/privileges/table-privileges-query.ts#L21)
which can potentially be a resource heavy query on the database,
especially if the database has a large number of relations.

A recent UI that was added `ProjectNeedsSecuring` uses that query, and
has become a common entry point for all projects as it's rendered when
the user lands on the project's home page, and the project has tables
with RLS issues, in which case if the project has a large number of
tables, the database will face run into resource issues, resulting in
statement timeouts.

## Changes involved

Opting to pass in `includedSchemas` parameter wherever we're calling
`useTablePrivilegesQuery`, which includes:
- `ProjectNeedsSecuring`
- `QueueSettings`
- `column-privileges`
In which we'll hence only fetch the table privileges for the provided
schemas only (rather than the whole DB)

Also did a similar fix for `useColumnPrivilegesQuery` as well as it
likely runs into the same problem

## To test
- [ ] Verify that those 3 UIs are still working as expected (should not
have any visual changes)
- [ ] Verify in the network tab that table / column privileges are now
filtered to the schema provided, rather than fetching for all schemas in
the DB

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved permission-save failure messaging by generating clearer toast
errors from unexpected failures.
* Prevented privilege-related UI from loading until required
configuration is successfully retrieved.
* **Performance**
* Faster, more targeted privilege loading by scoping both table and
column privilege queries to the selected/relevant schema(s), reducing
unnecessary client-side filtering.
* Switched privilege retrieval to schema-aware database metadata queries
for more efficient results.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Ali Waseem <waseema393@gmail.com>
2026-06-15 08:10:34 -06:00
Alaister YoungandAlaister Young ea695fdfa9 [FE-3496] feat(studio): hide unexposed tables from Data API docs (#46508)
The autogenerated Data API docs listed every table and database function
from the PostgREST OpenAPI spec, even ones that aren't actually
accessible via the Data API (i.e. with grants revoked). This filters the
docs down to only the entities that are exposed, and surfaces a count of
the excluded ones with a link to enable them.

This applies to **both** autogenerated docs surfaces:
- the **API Docs side panel** (the slide-over opened from the API docs
button), and
- the **full-page Data API docs** at `/integrations/data_api/docs`.

<img width="259" height="272" alt="Screenshot 2026-06-01 at 5 48 21 PM"
src="https://github.com/user-attachments/assets/d2af86f2-5436-4e94-8295-83ecc74a77d9"
/>

**Changed:**
- Both docs UIs now only list tables and functions that have Data API
access (any `anon`/`authenticated`/`service_role` grant). Fully-revoked
entities are hidden.
- Side panel: both the sidebar list and the drilled-in resource picker
are filtered.
- Full page: the menu's Tables/Functions groups are filtered, with a
footer note under each.

**Added:**
- A footer under each list — "N table(s)/function(s) not exposed via
**Data API**" — linking to Data API settings
(`/integrations/data_api/settings`) so the entity can be granted access.
- One-shot `useExposedTablesQuery` / `useExposedFunctionsQuery` hooks
reusing the same granted/custom/revoked SQL as the Data API settings
page (no new SQL).
- Pure, unit-tested `partitionExposedDocsEntities()` helper (fails open
if grant status hasn't loaded / errors, so docs are never blanked).
- Optional `footer` slot on `ProductMenuGroup` (rendered by `DocsMenu`)
so the full-page menu can show the not-exposed note under a group.

**Note on the "all" queries:** the new `useExposedTablesQuery` /
`useExposedFunctionsQuery` fetch the full grant-status list in a single
request (rather than paginating like the Data API settings page does).
This is deliberate — the docs sections aren't paginated and render every
entity from the OpenAPI spec at once, so we need the complete status set
to cross-reference against. Ideally we'd refactor the docs to be
paginated in future, at which point these queries should move to a
paginated approach too; until then, the one-shot "all" fetch is what
matches the current (unpaginated) docs behavior.

## To test

- On a project, revoke a `public` table's Data API access (Data API
settings → uncheck it)
- Open the **full-page** docs at `/integrations/data_api/docs`: the
table should no longer appear under Tables and Views, and you should see
"1 table not exposed via Data API" under that menu group
- Open the **API Docs side panel** and expand Tables and Views: same
behavior
- Click the "Data API" link → goes to Data API settings (closes the side
panel if open)
- Same for a database function under Functions
- Tables/functions that are still granted (or have custom/partial
grants) should remain visible

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Data API docs now reflect actual exposure: tables/functions not
exposed by permissions are hidden and counted.
* Sections display footer indicators with counts of hidden entities and
links to Data API settings.
* Navigation lists and docs menu updated to show only exposed entities
and the new "not exposed" cues.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-06-02 23:36:14 +10:00
Charis 2d4e87f579 studio: SafeSql for reports, query performance, privileges (4/7) (#45998)
## Summary

Part 4 of the SafeSql migration stack
([#45897](https://github.com/supabase/supabase/pull/45897),
[#45903](https://github.com/supabase/supabase/pull/45903),
[#45990](https://github.com/supabase/supabase/pull/45990), this PR, …).

Converts the remaining reports, query performance, observability, index
advisor, and privileges call sites of `executeSql` to produce
`SafeSqlFragment` values. The `ReportQuery.sql` field flips from
`string` to `SafeSqlFragment`, which cascades into every consumer —
landed here atomically so each branch typechecks cleanly.

Touched areas:

- `interfaces/Reports/*` — `ReportQuery.sql: SafeSqlFragment`, plus all
report definitions/utilities updated
- `interfaces/QueryPerformance/useQueryPerformanceQuery.ts`
- `interfaces/Database/IndexAdvisor/*` and
`data/database/{table-index-advisor,retrieve-index-advisor-result}-query.ts`
-
`data/privileges/{table-api-access,update-exposed-entities}-mutation.ts`
- `interfaces/Storage/StoragePolicies/StoragePolicies.tsx`
- `hooks/analytics/useDbQuery.tsx`
- `Observability/useSlowQueriesCount.ts` +
`useQueryInsightsIssues.utils.test.ts`

## Test plan

- [x] `pnpm typecheck` passes
- [x] `useQueryInsightsIssues.utils.test.ts` passes
- [x] Dev-server smoke test: reports pages, query performance, index
advisor, storage policies

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Reworked SQL construction and typings across reporting, query
performance, index advisor, and privilege features to use safer SQL
fragments, improving reliability and preventing query composition
issues.
* **Types**
* Reporting query types were split to distinguish database vs. logs
queries, enabling correct handling and validation.
* **Docs/Utils**
  * Added a helper to consistently generate logs SQL for report hooks.
* **Tests**
  * Updated tests to exercise the new SQL-building API.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45998)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-15 14:50:38 -04:00
Alaister YoungandAlaister Young d272c15d8d [FE-2792] feat(studio): unify table exposure check on RLS policies page (#45041)
Fixes the RLS policies page showing self-contradictory or wrong
admonitions for tables with partial grants. Classifies each table using
the same `granted / custom / revoked` semantics used by the Data API
settings page so the two views agree on what counts as "exposed".

**Changed:**
- `PolicyTableRow` now uses `useTableApiAccessQuery` (shared cache with
the Table Editor sidebar) instead of a bespoke
`tables-roles-access-query`
- Boolean soup collapsed into a single `TableDataApiStatus`
discriminated union (`schema-not-exposed | no-grants | custom-grants |
publicly-readable | locked-by-rls | secured`) via a pure helper
- Admonition copy for `no-grants` and `locked-by-rls` updated; a table
with no policies but full grants now reads "No data will be returned via
the Data API as no RLS policies exist on this table." instead of the
earlier self-contradictory "can be accessed but no data will be
returned"
- `table-api-access-query.ts` now exposes a `grantStatus: 'granted' |
'custom'` on `access` entries — `granted` = all 3 API roles × all 4 CRUD
privileges (matches `getTableGrantsCTEs` in pg-meta)

**Added:**
- New `custom-grants` admonition: "This table has custom Data API
permissions — access may be restricted for some roles or operations."
- Unit tests for `getTableDataApiStatus`, `getTableAdmonitionMessage`,
and `isFullyGranted`

**Removed:**
- `data/tables/tables-roles-access-query.ts` and the `rolesAccess` key —
no more callers

## To test

On a project with the `public` schema exposed, for each scenario check
the admonition shown on `/project/{ref}/auth/policies`:

1. Table with full standard grants, RLS on, no policies → "No data will
be returned via the Data API as no RLS policies exist on this table."
2. Table with full standard grants, RLS off → yellow warning "can be
accessed by anyone"
3. Table with partial grants (e.g. only `GRANT SELECT ON t TO anon`) →
new "custom Data API permissions" admonition regardless of RLS state
4. Table with no anon/authenticated/service_role grants → "cannot be
accessed via the Data API"
5. Schema not in the exposed list → "schema not exposed" admonition with
link

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Added unit tests covering table Data API/RLS status classification and
API grant validation.

* **Refactor**
* Introduced a unified per-table API/RLS status model and reusable
utilities to derive display status and admonitions.
* Simplified UI logic to drive access indicators and warnings from the
new status.

* **Chores**
  * Removed legacy role-based access query and its related keying logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-04-20 22:35:51 +08:00
Charis 3b7052b5a9 cleanup: fix import order and prefixes for studio/data (#44501) 2026-04-03 09:15:57 +02:00
49ad1eb325 [FE-2479] chore(studio): revoke default grants in public on project creation (#43704)
When the `tableEditorApiAccessToggle` feature flag is enabled, project
creation now appends SQL to revoke default privileges for `anon`,
`authenticated`, and `service_role` on the `public` schema. This runs
after the base image init script's default grants. This is temporary
while we're still using a feature flag. Eventually it'll be moved into
the base image.

Applies to both the main project creation flow and the Vercel deploy
button flow.

Part of the "Secure by Default" initiative – new projects created under
this flag won't automatically expose tables/functions/sequences to the
Data API via default privileges. Users can still opt in at a table
level.

## Notes

Reusing the existing `useDataApiGrantTogglesEnabled()` flag here rather
than creating a new one – it's the same feature surface area and avoids
unnecessary flag proliferation.

## To test

1. **With flag enabled:**
- Enable the `tableEditorApiAccessToggle` flag in PostHog for your user
   - Create a new project via the dashboard
   - Create a new table
- Confirm in `/project/_/integrations/data_api/settings` that the new
table is not exposed by default

2. **With flag disabled:**
   - Disable the flag (or use a different user without it)
   - Create a new project
- Verify default privileges are intact and tables are accessible via the
Data API as usual

3. **With RLS event trigger enabled too:**
- Enable both the feature flag and the "enable RLS event trigger"
checkbox during project creation
   - Verify both SQL statements run correctly on the new project

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-03-18 12:22:42 +08:00
Joshen Lim 241f7bb721 Chore/shift manual queries into pg meta (#43692)
## Context

Related to FE-2557

Part of shifting manually written dashboard queries into
packages/pg-meta where
- pg-meta can be code owners of
- we can write tests for the queries 

This PR just shifts all the `.sql.ts` files that we previously created
into packages/pg-meta

There's still other areas where we need to shift over as well which I'll
address in subsequent PRs

## Notable changes

- `getTableRowsCountSql` -> Opted to shift `formatFilterValue` logic out
before calling this method (ref `table-rows-count-query`)
- `getDeleteOldCronJobRunDetailsByCtidSql` -> Opted to shift
`validatePageNumber` logic out before calling this method (ref
`CronJobsTab.useCleanupActions`)
2026-03-16 16:14:48 +07:00
Alaister Young 9652e8c4d3 [SEC-385] feat(studio): Add default privileges for new entities toggle (#43583)
Adds a new toggle in:
<img width="1161" height="356" alt="Screenshot 2026-03-10 at 17 17 06"
src="https://github.com/user-attachments/assets/b09ac1aa-a8f5-4fb4-8771-f113b140eac8"
/>

Other changes:
- form submissions with no table/function changes were failing because
an empty string got passed to executeSql. Added an early return when
there's nothing to execute

To test:
- Ensure the form is still in working order
- Create some tables and functions with the toggle on add off and make
sure your selected default applies
2026-03-12 09:38:03 +00:00
Ali Waseem 585724daea fix(studio): skip empty SQL execution when saving Data API settings (#43605)
When saving Data API settings with only max rows changes (no
table/function privilege changes), updateExposedEntities sent an empty
string to pg-meta/query which failed server-side validation with 'String
must contain at least 1 character(s)'. Early return when there are no
SQL parts to execute.
2026-03-10 17:44:04 +00:00
Alaister Young 3eb0022264 [FE-2158] (part 2) – feat(studio): Add exposed functions config to Postgrest settings (#43478)
**Changes:**
- Add function exposure controls to Data API settings
- Adds a per-function GRANT/REVOKE UI to the Data API settings page,
alongside the existing table selector.
- Empty state: shows "No tables/functions available" instead of "0 of 0
X exposed" when there's nothing to show
- Renamed update-exposed-tables-mutation →
update-exposed-entities-mutation to handle both tables and functions in
one save
**Decisions of note:**
- Functions are grouped by schema.name across overloads — toggling one
entry grants/revokes `EXECUTE` on all overloads
- Only normal and window functions are shown (`prokind in ('f', 'w')`) —
triggers and aggregates are excluded

---

**To test:**

- Table and schema selectors still works end-to-end
- Toggling a function and saving updates the count label and applies the
grant (check via SQL Editor: select * from
information_schema.role_routine_grants where routine_schema = 'public')
- Functions in unexposed schemas are dimmed and unclickable
- With no functions in the selected schemas, the selector label reads
"No functions available" and the dropdown shows the same
2026-03-10 22:11:59 +08:00
Alaister YoungandNick Babadzhanian 5894e37b40 [FE-2158] – feat(studio): Add exposed tables config to Postgrest settings (#43280)
Adds a feature flagged exposed tables config to postgrest settings:
<img width="1158" height="589" alt="Screenshot 2026-03-02 at 17 04 13"
src="https://github.com/user-attachments/assets/8fa8ab81-0bfa-4781-83bc-80ac52e180f8"
/>

To test:
- make sure the existing (feature flag off) settings work as expected
- make sure exposing and removing schemas works in the new mode
- make sure exposing and removing tables works in the new mode
- ideally try with a lot of tables to check search and infinite scroll
work as expected
- try exposing a schema without any tables (like `graphql_public`) and
make sure it doesn't get removed randomly when editing tables
- try with a table with custom permissions (for example `REVOKE SELECT
ON public.posts FROM anon;`) and make sure the user is informed with the
tooltip

---------

Co-authored-by: Nick Babadzhanian <33933459+pgnickb@users.noreply.github.com>
2026-03-06 20:51:37 +08:00
Saxon FletcherandCharis Lam 0dab4d93fe Enable or disable Data API access per table (#41218)
* feat(studio): add mutation to update table access privileges

Adds a mutation to update table grants for `anon` and `authenticated`
roles.

* feat(studio): add data api toggles

Add toggles to the Table Editor, allowing fine-grained grants to the
anon and authenticated roles.

* fix(studio): don't show rls policies warning if table not exposed

RLS policies warning was showing in Table Editor side panel even if
table was not exposed due to no grants to anon/authenticated.

* fixup! feat(studio): add data api toggles

* fixup! feat(studio): add data api toggles

* fix(studio): revalidate rls lints when table grants are toggled

---------

Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
2026-01-07 12:12:15 -05:00
CharisandJoshen Lim 1d49e9e954 feat(studio): show icon on tables exposed by data api (#41416)
* feat(studio): show icon on tables exposed by data api

Show an icon in the Table Editor for tables that are exposed via the
Data API.

* refactor(studio): move table api access query up to parent

* fix(studio): invalidate table privileges query on table create

* fix(studio): make RLS disabled warning on table editor more obvious

Change from warning -> danger

* Only show add foreign key in side panel if isSuccess

* chore(studio): put data api exposed badge behind feature flag

Only show badge for now if flag `dataApiExposedBadge` is enabled.

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2025-12-18 16:50:26 +00:00
Ivan Vasilov 4da5d019ae chore: Migrate some stray queryKeys to the RQ 5 syntax (#40086)
Fix some stray queryKeys.
2025-11-04 09:33:49 +01:00
Ivan Vasilov 8b657165b5 chore: Migrate to use custom type for ReactQuery queries and mutations (#40073)
* Add custom types for queries, mutations and infinite queries.

* Migrate all queries to use the new type.

* Migrate all infinite queries to useCustomInfiniteQueryOptions.

* Migrate all mutations to use useCustomMutationOptions.

* Add type to all imports in `types` folder.
2025-11-03 13:18:13 +01:00
Ivan Vasilov da4a40e308 chore: Migrate RQ functions to use object syntax style (#39895)
* Migrate all uses of invalidateQueries to use object syntax.

* Migrate the remainder of useInfiniteQuery.

* Migrate all setQueriesData.

* Migrate all fetchQuery uses.

* Migrate some leftover functions from RQ.

* Fix issues found by Charis.
2025-10-28 10:43:14 +01:00
Stojan DimitrovskiandJoshen Lim 1af6b84790 types are broken (#39866)
* types are broken

* Fix TS issues

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2025-10-28 10:38:07 +08:00
Alaister YoungandJoshen Lim 8855d05803 chore(studio): swap react-query to object syntax (#39842)
* chore(studio): swap react-query to object syntax

* Fix small issues found

* Fix realtime settings

* Nit

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2025-10-27 09:38:27 +01:00
Andrew Valleteau 4bd28eecb8 fix(api): set x-pg-application-name for dashboard (#37048)
chore(api): set x-pg-application-name for dashboard
2025-07-21 10:39:46 +02:00
Julien GouxandQiao Han 8b45671ff6 fix: move column privileges to query route (#35560)
* fix: move column privileges to query route

* add query keys

* chore: reverts read query for column privileges

---------

Co-authored-by: Qiao Han <qiao@supabase.io>
2025-05-13 12:56:21 +08:00
Andrew Valleteau 31aad403de fix(studio): early fail query when x-connection-encrypted is invalid (#35331)
* fix(studio): early fail query when x-connection-encrypted is invalid

* fix(studio): uniformize readDatabase and projectDetails connString handling

* chore: update api types

* chore: add connectionString null option

* fix: only enforce x-connection-encrypted on platform

* chore: refactor connString check in a single point

* chore: fix guard logic

* chore: fix pgMetaGuard

* chore: fix types
2025-05-08 12:11:03 +02:00
Kevin Grüneberg 4532286e04 fix: align with API types (#34821)
* fix: align with API types

* Update new-project.constants.ts
2025-04-08 17:17:35 +08:00
Bobbie Soedirgo f5c0a4c899 fix: only use MAINTAIN for table privileges if PG17+ (#30998)
* chore: use @supabase/pg-meta for table privileges queries

* fix: only use MAINTAIN for table privileges if PG17+

* chore: run prettier
2024-12-08 18:58:29 +01:00
df52ea7ee0 feat: Replace all toasts with sonner (#28250)
* Update the design of the sonner toasts. Add the close button by default.

* Migrate studio and www apps to use the SonnerToaster.

* Migrate all toasts from studio.

* Migrate all leftover toasts in studio.

* Add a new toast component with progress. Use it in studio.

* Migrate the design-system app.

* Refactor the consent toast to use sonner.

* Switch docs to use the new sonner toasts.

* Remove toast examples from the design-system app.

* Remove all toast-related components and old code.

* Fix the progress bar in the toast progress component. Also make the bottom components vertically centered.

* Fix the width of the toast progress.

* Use text-foreground-lighter instead of muted for ToastProgress text

* Rename ToastProgress to SonnerProgress.

* Shorten the text in sonner progress.

* Use the correct classes for the close button. Add a const var for the default toast duration. Remove the custom width class from sonner.

* Set the position for all progress toasts to bottom right. Set the duration for all toasts to the default (when reusing a toast id from loading/progress toast, the duration is set to infinity).

* Fix the playwright tests.

* Refactor imports to use ui instead of @ui.

* Change all imports of react-hot-toast with sonner. These components were merged since the last commit to this branch.

* Remove react-hot-toast lib.

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Jonathan Summers-Muir <MildTomato@users.noreply.github.com>
2024-08-31 07:50:51 +08:00
Joshen LimandIvan Vasilov bb6349f34f Second round of wrapping RQ errors with handleError (#26428)
* First round of wrapping RQ errors with handleError

* Remove the throw before the handleError usage.

* Make the handling of an API error more versatile. Add logging in Sentry if the error is of unknown type.

* Remove throwing of the handleError function.

* Add return type to the handleError function to be never so that we're sure it always throws.

* Second round of wrapping RQ errors with handleError

* Temp fix in delete credential mutation, and fix loading state

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
2024-05-21 15:51:11 +08:00
Kevin Grüneberg f9a55935f5 chore: use type imports for types/interfaces (#21738) 2024-03-04 20:48:22 +08:00
6d121f1546 feat(dashboard): Add column-level privileges management (#13745)
* add privileges page

* fix

* fix: could have both global and column-specific privileges + is global per privilege

* Trigger Build

* load permissions data for current table only

* fix style for light theme

* add a guide to Privileges

* Update apps/docs/pages/guides/auth/column-level-security.mdx

Co-authored-by: Greg Richardson <greg.nmr@gmail.com>

* Update apps/docs/pages/guides/auth/column-level-security.mdx

Co-authored-by: Greg Richardson <greg.nmr@gmail.com>

* Update doc

* Update docs

* progress moving privileges to pg-meta

* split up column privileges and table privileges

* adds loading state to toggles

* Add feature flag, move from auth section to database section

* Cleanup

* Update meta store table lists, add header warnings, update docs

* Add alert if any columns have privilages

* Spelling

* fix api.d.ts

* fix link

* move to auth pages

* only show editable schemas

* limit roles

* auto select first table

* remove roles meta store

* inline toggling

* apply privileges all at once

* add preview and use new switch component

* fix spelling

* handle long column names

* warn users about losing changes when changing schemas/tables

* remove strange docs link

* fix feature preview after reload

* use shadcn select

* Update select.tsx

* Minor UX fixes

* Update toast

* Update feature preview image for cls

* update cls warnings

* update warnings

* fix toast message

* Add migration alert to preview page

* Add link to CLS from feature preview, and add empty state on CLS page if feature preview is not enabled

* Shift local storage keys hard code to lib/constants

---------

Co-authored-by: Copple <10214025+kiwicopple@users.noreply.github.com>
Co-authored-by: Greg Richardson <greg.nmr@gmail.com>
Co-authored-by: Terry Sutton <saltcod@gmail.com>
Co-authored-by: Alaister Young <a@alaisteryoung.com>
Co-authored-by: Jonathan Summers-Muir <MildTomato@users.noreply.github.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2024-01-10 17:39:03 +11:00