mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Merge branch 'master' of github.com:supabase/supabase
This commit is contained in:
commit
a847b5e2c1
99 files changed
+2153
-511
No files matched your search
@@ -0,0 +1,20 @@
|
||||
name: reviewdog
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
|
||||
jobs:
|
||||
misspell:
|
||||
name: runner / misspell
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code.
|
||||
uses: actions/checkout@v1
|
||||
- name: misspell
|
||||
uses: reviewdog/action-misspell@v1
|
||||
with:
|
||||
github_token: ${{ secrets.github_token }}
|
||||
locale: "US"
|
||||
reporter: github-pr-review
|
||||
level: error
|
||||
exclude: "*.css"
|
||||
@@ -0,0 +1,108 @@
|
||||
If you upload additional profile photos, they'll accumulate
|
||||
in the `avatars` bucket because of their random names with only the latest being referenced
|
||||
from `public.profiles` and the older versions getting orphaned.
|
||||
|
||||
To automatically remove obsolete storage objects, extend the database
|
||||
triggers. Note that it is not sufficient to delete the objects from the
|
||||
`storage.objects` table because that would orphan and leak the actual storage objects in
|
||||
the S3 backend. Instead, invoke the storage API within Postgres via the `http` extension.
|
||||
|
||||
Enable the [http extension for the `extensions` schema](https://app.supabase.com/project/_/database/extensions) in the Dashboard.
|
||||
Then, define the following SQL functions in the SQL Editor to delete
|
||||
storage objects via the API:
|
||||
|
||||
```SQL
|
||||
create or replace function delete_storage_object(bucket text, object text, out status int, out content varchar)
|
||||
returns record
|
||||
language 'plpgsql'
|
||||
security definer
|
||||
as $$
|
||||
declare
|
||||
project_url varchar := '<YOURPROJECTURL>';
|
||||
service_role_key varchar := '<YOURSERVICEROLEKEY>'; -- full access needed
|
||||
url varchar := project_url||'/storage/v1/object/'||bucket||'/'||object;
|
||||
begin
|
||||
select
|
||||
into status, content
|
||||
result.status::int, result.content::varchar
|
||||
FROM extensions.http((
|
||||
'DELETE',
|
||||
url,
|
||||
ARRAY[extensions.http_header('authorization','Bearer '||service_role_key)],
|
||||
NULL,
|
||||
NULL)::extensions.http_request) as result;
|
||||
end;
|
||||
$$;
|
||||
|
||||
create or replace function delete_avatar(avatar_url text, out status int, out content varchar)
|
||||
returns record
|
||||
language 'plpgsql'
|
||||
security definer
|
||||
as $$
|
||||
begin
|
||||
select
|
||||
into status, content
|
||||
result.status, result.content
|
||||
from public.delete_storage_object('avatars', avatar_url) as result;
|
||||
end;
|
||||
$$;
|
||||
|
||||
```
|
||||
|
||||
Next, add a trigger that removes any obsolete avatar whenever the
|
||||
profile is updated or deleted:
|
||||
|
||||
```SQL
|
||||
create or replace function delete_old_avatar()
|
||||
returns trigger
|
||||
language 'plpgsql'
|
||||
security definer
|
||||
as $$
|
||||
declare
|
||||
status int;
|
||||
content varchar;
|
||||
begin
|
||||
if coalesce(old.avatar_url, '') <> ''
|
||||
and (tg_op = 'DELETE' or (old.avatar_url <> new.avatar_url)) then
|
||||
select
|
||||
into status, content
|
||||
result.status, result.content
|
||||
from public.delete_avatar(old.avatar_url) as result;
|
||||
if status <> 200 then
|
||||
raise warning 'Could not delete avatar: % %', status, content;
|
||||
end if;
|
||||
end if;
|
||||
if tg_op = 'DELETE' then
|
||||
return old;
|
||||
end if;
|
||||
return new;
|
||||
end;
|
||||
$$;
|
||||
|
||||
create trigger before_profile_changes
|
||||
before update of avatar_url or delete on public.profiles
|
||||
for each row execute function public.delete_old_avatar();
|
||||
|
||||
```
|
||||
|
||||
Finally, delete the `public.profile` row before a user is deleted.
|
||||
If this step is omitted, you won't be able to delete users without
|
||||
first manually deleting their avatar image.
|
||||
|
||||
```SQL
|
||||
create or replace function delete_old_profile()
|
||||
returns trigger
|
||||
language 'plpgsql'
|
||||
security definer
|
||||
as $$
|
||||
begin
|
||||
delete from public.profiles where id = old.id;
|
||||
return old;
|
||||
end;
|
||||
$$;
|
||||
|
||||
create trigger before_delete_user
|
||||
before delete on auth.users
|
||||
for each row execute function public.delete_old_profile();
|
||||
|
||||
```
|
||||
@@ -20,6 +20,7 @@ import QuickstartIntro from './MDX/quickstart_intro.mdx'
|
||||
import ProjectSetup from './MDX/project_setup.mdx'
|
||||
import SocialProviderSetup from './MDX/social_provider_setup.mdx'
|
||||
import SocialProviderSettingsSupabase from './MDX/social_provider_settings_supabase.mdx'
|
||||
import StorageManagement from './MDX/storage_management.mdx'
|
||||
import { Mermaid } from 'mdx-mermaid/lib/Mermaid'
|
||||
import InlineCodeTag from './CustomHTMLElements/InlineCode'
|
||||
import React from 'react'
|
||||
@@ -49,6 +50,7 @@ const components = {
|
||||
ProjectSetup,
|
||||
SocialProviderSetup,
|
||||
SocialProviderSettingsSupabase,
|
||||
StorageManagement,
|
||||
Mermaid,
|
||||
Extensions,
|
||||
Alert: (props: any) => (
|
||||
|
||||
@@ -468,6 +468,13 @@
|
||||
"installed_version": "1.1",
|
||||
"comment": "generate universally unique identifiers (UUIDs)"
|
||||
},
|
||||
{
|
||||
"name": "vector",
|
||||
"schema": "extensions",
|
||||
"default_version": "0.4.0",
|
||||
"installed_version": null,
|
||||
"comment": "vector data type with similarity search"
|
||||
},
|
||||
{
|
||||
"name": "xml2",
|
||||
"schema": null,
|
||||
|
||||
@@ -217,7 +217,7 @@ import { createClient, useQuery } from 'urql'
|
||||
// Prepare API key and Authorization header
|
||||
const headers = {
|
||||
apikey: <SUPABASE_ANON_KEY>,
|
||||
authorization: `Bearer ${<SUPABASE_ANON_KEY}`>
|
||||
authorization: `Bearer ${<SUPABASE_ANON_KEY>}`,
|
||||
}
|
||||
|
||||
// Create GraphQL client
|
||||
|
||||
@@ -6,6 +6,15 @@ export const meta = {
|
||||
description: 'Using Import Maps.',
|
||||
}
|
||||
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/ILr3cneZuFk"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
Since [Supabase CLI](https://supabase.com/docs/guides/resources/supabase-cli) version `1.33.0` [import maps](https://deno.land/manual@v1.29.2/node/import_maps) can be used with Supabase Edge Functions.
|
||||
|
||||
[Import maps](https://github.com/WICG/import-maps#the-import-map) is a web-platform standard that allows you to use bare specifiers with Deno without having to install the Node.js package locally.
|
||||
|
||||
@@ -25,7 +25,7 @@ By default, Edge Functions have access to these secrets:
|
||||
|
||||
Let's create a local file for storing our secrets, and inside it we can store a secret `MY_NAME`:
|
||||
|
||||
```jsx
|
||||
```bash
|
||||
echo "MY_NAME=Yoda" >> ./supabase/.env.local
|
||||
```
|
||||
|
||||
|
||||
@@ -530,6 +530,10 @@ export class AccountComponent implements OnInit {
|
||||
}
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -500,6 +500,10 @@ Now you will need to run the prebuild command to get the application working on
|
||||
expo prebuild
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -793,6 +793,10 @@ class _AccountPageState extends State<AccountPage> {
|
||||
}
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
Congratulations, that is it! You have now built a fully functional user management app using Flutter and Supabase!
|
||||
|
||||
## See also
|
||||
|
||||
@@ -522,6 +522,10 @@ template: `
|
||||
`
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -495,6 +495,10 @@ return (
|
||||
<Avatar url={profile.avatar_url} onUpload={updateProfile}></Avatar>
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -555,6 +555,10 @@ export default defineComponent({
|
||||
</script>
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -718,6 +718,10 @@ return (
|
||||
)
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -420,6 +420,10 @@ And then we can add the widget to the Account page:
|
||||
|
||||
That is it! You should now be able to upload a profile photo to Supabase Storage.
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -397,6 +397,10 @@ return (
|
||||
)
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -771,6 +771,10 @@ return (
|
||||
)
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -415,6 +415,10 @@ return (
|
||||
)
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -368,6 +368,10 @@ And then we can add the widget to the Account page:
|
||||
</form>
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -434,6 +434,10 @@ And then we can add the widget to the Account page:
|
||||
</form>
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -379,6 +379,10 @@ And then we can add the widget to the Account page:
|
||||
</template>
|
||||
```
|
||||
|
||||
### Storage management
|
||||
|
||||
<StorageManagement />
|
||||
|
||||
## Next steps
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
|
||||
@@ -6,6 +6,8 @@ image: launch-week-6/crdt/og-pg-crdt.png
|
||||
thumb: launch-week-6/crdt/og-pg-crdt.png
|
||||
tags:
|
||||
- launch-week
|
||||
- postgres
|
||||
- planetpg
|
||||
date: '2022-12-10'
|
||||
toc_depth: 2
|
||||
---
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"next-seo": "^4.20.0",
|
||||
"next-transpile-modules": "^9.0.0",
|
||||
"nodemailer": "^6.7.3",
|
||||
"octokit": "^2.0.10",
|
||||
"octokit": "^2.0.14",
|
||||
"parse-numeric-range": "^1.3.0",
|
||||
"react": "^17.0.2",
|
||||
"react-copy-to-clipboard": "^5.0.2",
|
||||
|
||||
@@ -9,7 +9,7 @@ version: "3.8"
|
||||
services:
|
||||
studio:
|
||||
container_name: supabase-studio
|
||||
image: supabase/studio:20221214-4eecc99
|
||||
image: supabase/studio:20230127-123d704
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: [ "CMD", "node", "-e", "require('http').get('http://localhost:3000/api/profile', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})" ]
|
||||
@@ -27,8 +27,6 @@ services:
|
||||
|
||||
SUPABASE_URL: http://kong:8000
|
||||
SUPABASE_PUBLIC_URL: ${SUPABASE_PUBLIC_URL}
|
||||
# Kept for backwards compatibility with studio:0.22.08
|
||||
SUPABASE_REST_URL: ${API_EXTERNAL_URL}/rest/v1/
|
||||
SUPABASE_ANON_KEY: ${ANON_KEY}
|
||||
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ router
|
||||
.get('/oak-server', (context) => {
|
||||
context.response.body = 'This is an example Oak server running on Edge Functions!'
|
||||
})
|
||||
.post('/oak-server/greet', (context) => {
|
||||
.post('/oak-server/greet', async (context) => {
|
||||
// Note: request body will be streamed to the function as chunks, set limit to 0 to fully read it.
|
||||
const result = context.request.body({ type: 'json', limit: 0 })
|
||||
const body = await result.value
|
||||
|
||||
Generated
+1766
-302
File diff suppressed because it is too large.
Load diff
@@ -62,5 +62,8 @@
|
||||
"mdx-mermaid": "^1.3.2",
|
||||
"mermaid": "^9.2.2",
|
||||
"mini-svg-data-uri": "^1.4.4"
|
||||
},
|
||||
"overrides": {
|
||||
"pgsql-parser": "13.4.0"
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ info:
|
||||
|
||||
functions:
|
||||
- id: initializing
|
||||
$ref: '@supabase/supabase-js.index.SupabaseClient.constructor'
|
||||
description: |
|
||||
You can initialize a new Supabase client using the `create_client()` method.
|
||||
|
||||
@@ -50,7 +49,6 @@ functions:
|
||||
|
||||
- id: sign-up
|
||||
title: 'sign_up()'
|
||||
$ref: '@supabase/gotrue-js.GoTrueClient.signUp'
|
||||
notes: |
|
||||
- By default, the user needs to verify their email address before logging in. To turn this off, disable **Confirm email** in [your project](https://app.supabase.com/project/_/auth/providers).
|
||||
- **Confirm email** determines if users need to confirm their email address after signing up.
|
||||
@@ -88,7 +86,6 @@ functions:
|
||||
```
|
||||
- id: sign-out
|
||||
title: 'sign_out()'
|
||||
$ref: '@supabase/gotrue-js.GoTrueClient.signOut'
|
||||
notes: |
|
||||
- In order to use the `signOut()` method, the user needs to be signed in first.
|
||||
examples:
|
||||
@@ -100,7 +97,6 @@ functions:
|
||||
```
|
||||
- id: verify-otp
|
||||
title: 'verify_otp()'
|
||||
$ref: '@supabase/gotrue-js.GoTrueClient.verifyOtp'
|
||||
notes: |
|
||||
- The `verifyOtp` method takes in different verification types. If a phone number is used, the type can either be `sms` or `phone_change`. If an email address is used, the type can be one of the following: `signup`, `magiclink`, `recovery`, `invite` or `email_change`.
|
||||
- The verification type used should be determined based on the corresponding auth method called before `verifyOtp` to sign up / sign-in a user.
|
||||
@@ -114,7 +110,6 @@ functions:
|
||||
|
||||
- id: get-session
|
||||
title: 'get_session_from_url'
|
||||
$ref: '@supabase/gotrue-js.GoTrueClient.getSession'
|
||||
examples:
|
||||
- id: get-session
|
||||
name: Get the session data from URL
|
||||
@@ -125,7 +120,6 @@ functions:
|
||||
|
||||
- id: set-session
|
||||
title: 'set_session()'
|
||||
$ref: '@supabase/gotrue-js.GoTrueClient.setSession'
|
||||
notes: |
|
||||
- `setSession()` takes in a refresh token and uses it to get a new session.
|
||||
- The refresh token can only be used once to obtain a new session.
|
||||
@@ -142,7 +136,6 @@ functions:
|
||||
```
|
||||
- id: refresh-session
|
||||
title: 'refresh_ession()'
|
||||
$ref: '@supabase/gotrue-js.GoTrueClient.refreshSession'
|
||||
notes: |
|
||||
- This method will refresh the session whether the current one is expired or not.
|
||||
- Both examples destructure `user` and `session` from `data`. This is not required; so `const { data, error } =` is also valid.
|
||||
@@ -155,7 +148,6 @@ functions:
|
||||
```
|
||||
- id: select
|
||||
title: 'Fetch data: select()'
|
||||
$ref: '@supabase/postgrest-js.PostgrestQueryBuilder.select'
|
||||
notes: |
|
||||
- By default, Supabase projects return a maximum of 1,000 rows. This setting can be changed in your project's [API settings](https://app.supabase.com/project/_/settings/api). It's recommended that you keep it low to limit the payload size of accidental or malicious requests.
|
||||
- `apikey` is a reserved keyword if you're using the [Supabase Platform](/docs/guides/platform) and [should be avoided as a column name](https://github.com/supabase/supabase/issues/5465).
|
||||
@@ -181,7 +173,6 @@ functions:
|
||||
title: 'invoke()'
|
||||
description: |
|
||||
Invoke a Supabase Function.
|
||||
$ref: '@supabase/functions-js.F'
|
||||
notes: |
|
||||
- Requires an Authorization header.
|
||||
- When you pass in a body to your function, we automatically attach the Content-Type header for `Blob`, `ArrayBuffer`, `File`, `FormData` and `String`. If it doesn't match any of these types we assume the payload is `json`, serialise it and attach the `Content-Type` header as `application/json`. You can override this behaviour by passing in a `Content-Type` header of your own.
|
||||
@@ -204,7 +195,6 @@ functions:
|
||||
|
||||
- id: list-buckets
|
||||
title: 'list_buckets()'
|
||||
$ref: '@supabase/storage-js.packages/StorageBucketApi.default.listBuckets'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: `select`
|
||||
@@ -220,7 +210,6 @@ functions:
|
||||
|
||||
- id: get-bucket
|
||||
title: 'get_bucket()'
|
||||
$ref: '@supabase/storage-js.packages/StorageBucketApi.default.getBucket'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: `select`
|
||||
@@ -236,7 +225,6 @@ functions:
|
||||
|
||||
- id: create-bucket
|
||||
title: 'create_bucket()'
|
||||
$ref: '@supabase/storage-js.packages/StorageBucketApi.default.createBucket'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: `insert`
|
||||
@@ -252,7 +240,6 @@ functions:
|
||||
|
||||
- id: empty-bucket
|
||||
title: 'empty_bucket()'
|
||||
$ref: '@supabase/storage-js.packages/StorageBucketApi.default.emptyBucket'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: `select`
|
||||
@@ -267,7 +254,6 @@ functions:
|
||||
```
|
||||
- id: delete-bucket
|
||||
title: 'delete_bucket()'
|
||||
$ref: '@supabase/storage-js.packages/StorageBucketApi.default.deleteBucket'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: `select` and `delete`
|
||||
@@ -283,7 +269,6 @@ functions:
|
||||
|
||||
- id: from-upload
|
||||
title: 'from_.upload()'
|
||||
$ref: '@supabase/storage-js.packages/StorageFileApi.default.upload'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: none
|
||||
@@ -299,7 +284,6 @@ functions:
|
||||
```
|
||||
- id: from-move
|
||||
title: 'from_.move()'
|
||||
$ref: '@supabase/storage-js.packages/StorageFileApi.default.move'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: none
|
||||
@@ -315,7 +299,6 @@ functions:
|
||||
|
||||
- id: from-create-signed-url
|
||||
title: 'from_.create_signed_url()'
|
||||
$ref: '@supabase/storage-js.packages/StorageFileApi.default.createSignedUrl'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: none
|
||||
@@ -331,7 +314,6 @@ functions:
|
||||
|
||||
- id: from-get-public-url
|
||||
title: 'from_.get_public_url()'
|
||||
$ref: '@supabase/storage-js.packages/StorageFileApi.default.getPublicUrl'
|
||||
notes: |
|
||||
- The bucket needs to be set to public, either via [updateBucket()](/docs/reference/javascript/storage-updatebucket) or by going to Storage on [app.supabase.com](https://app.supabase.com), clicking the overflow menu on a bucket and choosing "Make public"
|
||||
- RLS policy permissions required:
|
||||
@@ -348,7 +330,6 @@ functions:
|
||||
|
||||
- id: from-download
|
||||
title: 'from_.download()'
|
||||
$ref: '@supabase/storage-js.packages/StorageFileApi.default.download'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: none
|
||||
@@ -366,7 +347,6 @@ functions:
|
||||
|
||||
- id: from-remove
|
||||
title: 'from_.remove()'
|
||||
$ref: '@supabase/storage-js.packages/StorageFileApi.default.remove'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: none
|
||||
@@ -381,7 +361,6 @@ functions:
|
||||
```
|
||||
- id: from-list
|
||||
title: 'from_.list()'
|
||||
$ref: '@supabase/storage-js.packages/StorageFileApi.default.list'
|
||||
notes: |
|
||||
- RLS policy permissions required:
|
||||
- `buckets` table permissions: none
|
||||
@@ -396,6 +375,5 @@ functions:
|
||||
```
|
||||
- id: subscribe
|
||||
title: on().subscribe()
|
||||
$ref: '@supabase/realtime-js.RealtimeChannel.on'
|
||||
notes: |
|
||||
- We are implementing this feature at the moment. If you have queries feel free to open an issue on the [realtime-py](https://github.com/supabase-community) repository.
|
||||
+1
-3
@@ -6,13 +6,11 @@ DEFAULT_PROJECT_NAME=Default Project
|
||||
|
||||
SUPABASE_URL=http://localhost:8000
|
||||
SUPABASE_PUBLIC_URL=http://localhost:8000
|
||||
NEXT_PUBLIC_SUPABASE_URL=$SUPABASE_URL
|
||||
NEXT_PUBLIC_SUPABASE_PUBLIC_URL=$SUPABASE_PUBLIC_URL
|
||||
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
|
||||
SUPABASE_SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
|
||||
|
||||
# TODO: evaluate these variables at runtime instead
|
||||
# https://nextjs.org/docs/basic-features/environment-variables#loading-environment-variables
|
||||
NEXT_PUBLIC_SITE_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_GOTRUE_URL=$NEXT_PUBLIC_SUPABASE_PUBLIC_URL/auth/v1
|
||||
NEXT_PUBLIC_GOTRUE_URL=$SUPABASE_PUBLIC_URL/auth/v1
|
||||
NEXT_PUBLIC_HCAPTCHA_SITE_KEY=10000000-ffff-ffff-ffff-000000000001
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Tabs } from 'ui'
|
||||
import { Button, IconExternalLink, Tabs } from 'ui'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
|
||||
import { TEMPLATES_SCHEMAS } from 'stores/authConfig/schema'
|
||||
@@ -8,10 +8,20 @@ import TemplateEditor from './TemplateEditor'
|
||||
const EmailTemplates = observer(() => {
|
||||
return (
|
||||
<div>
|
||||
<FormHeader
|
||||
title="Email Templates"
|
||||
description="Customize the emails that will be sent out to your users."
|
||||
/>
|
||||
<div className='flex justify-between items-center'>
|
||||
<FormHeader
|
||||
title="Email Templates"
|
||||
description="Customize the emails that will be sent out to your users."
|
||||
/>
|
||||
<Button type="link" icon={<IconExternalLink size={14} strokeWidth={1.5} />}>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://supabase.com/docs/guides/auth/auth-email-templates"
|
||||
>
|
||||
Email Templates Documentation
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
<FormPanel>
|
||||
<Tabs
|
||||
scrollable
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useRouter } from 'next/router'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useParams, useStore } from 'hooks'
|
||||
import { PolicyEditorModal, PolicyTableRow } from 'components/interfaces/Auth/Policies'
|
||||
import { PostgresRole, PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresRole, PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog'
|
||||
import NoSearchResults from 'components/to-be-cleaned/NoSearchResults'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PostgresPolicy } from '@supabase/postgres-meta'
|
||||
import type { PostgresPolicy } from '@supabase/postgres-meta'
|
||||
import { has, isEmpty, isEqual } from 'lodash'
|
||||
import {
|
||||
PolicyFormField,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FC } from 'react'
|
||||
import { PostgresRole } from '@supabase/postgres-meta'
|
||||
import type { PostgresRole } from '@supabase/postgres-meta'
|
||||
|
||||
import MultiSelect from 'components/ui/MultiSelect'
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import PolicyDefinition from './PolicyDefinition'
|
||||
import PolicyAllowedOperation from './PolicyAllowedOperation'
|
||||
import PolicyRoles from './PolicyRoles'
|
||||
import PolicyEditorFooter from './PolicyEditorFooter'
|
||||
import { PostgresRole } from '@supabase/postgres-meta'
|
||||
import type { PostgresRole } from '@supabase/postgres-meta'
|
||||
|
||||
// Exposed for StoragePoliciesEditor.js
|
||||
export { PolicyName, PolicyRoles }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Modal } from 'ui'
|
||||
import { FC, useState, useEffect } from 'react'
|
||||
import { isEmpty } from 'lodash'
|
||||
import { PostgresRole } from '@supabase/postgres-meta'
|
||||
import type { PostgresRole } from '@supabase/postgres-meta'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import PolicyEditorModalTitle from './PolicyEditorModalTitle'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FC } from 'react'
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { Button, Dropdown, IconEdit, IconTrash, IconMoreVertical } from 'ui'
|
||||
import { PostgresPolicy } from '@supabase/postgres-meta'
|
||||
import type { PostgresPolicy } from '@supabase/postgres-meta'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { checkPermissions } from 'hooks'
|
||||
|
||||
@@ -3,7 +3,7 @@ import { FC } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { Badge, Button } from 'ui'
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { checkPermissions } from 'hooks'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FC } from 'react'
|
||||
import { PostgresTable, PostgresPolicy } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable, PostgresPolicy } from '@supabase/postgres-meta'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useStore } from 'hooks'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import { Button, Input, Form, Modal, Listbox, IconPlus, IconDatabase } from 'ui'
|
||||
import { PostgresExtension, PostgresSchema } from '@supabase/postgres-meta'
|
||||
import type { PostgresExtension, PostgresSchema } from '@supabase/postgres-meta'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FC, useState } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { Badge, Toggle } from 'ui'
|
||||
import { PostgresPublication, PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresPublication, PostgresTable } from '@supabase/postgres-meta'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { checkPermissions, useStore } from 'hooks'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FC, useState } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { Button, Input, IconChevronLeft, IconSearch, IconAlertCircle } from 'ui'
|
||||
import { PostgresPublication } from '@supabase/postgres-meta'
|
||||
import type { PostgresPublication } from '@supabase/postgres-meta'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { checkPermissions, useStore } from 'hooks'
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Input, Button, IconSearch, IconPlus, IconChevronLeft, IconEdit3, IconTr
|
||||
import { useStore } from 'hooks'
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import NoSearchResults from 'components/to-be-cleaned/NoSearchResults'
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
interface Props {
|
||||
selectedTable: PostgresTable
|
||||
@@ -25,11 +25,11 @@ const ColumnList: FC<Props> = ({
|
||||
const { meta } = useStore()
|
||||
const [filterString, setFilterString] = useState<string>('')
|
||||
const columns =
|
||||
filterString.length === 0
|
||||
(filterString.length === 0
|
||||
? selectedTable.columns
|
||||
: selectedTable.columns.filter((column: any) => column.name.includes(filterString))
|
||||
: selectedTable.columns?.filter((column: any) => column.name.includes(filterString))) ?? []
|
||||
|
||||
const isLocked = meta.excludedSchemas.includes(selectedTable?.schema ?? '')
|
||||
const isLocked = meta.excludedSchemas.includes(selectedTable.schema ?? '')
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -18,7 +18,7 @@ import { partition } from 'lodash'
|
||||
import { useStore } from 'hooks'
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import NoSearchResults from 'components/to-be-cleaned/NoSearchResults'
|
||||
import { PostgresTable, PostgresSchema } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable, PostgresSchema } from '@supabase/postgres-meta'
|
||||
|
||||
interface Props {
|
||||
selectedSchema: string
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { Button, IconTerminal, IconMaximize2, IconMinimize2, IconBookOpen, IconCode } from 'ui'
|
||||
import { useProjectSettings } from 'hooks'
|
||||
import { useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
import { useAccessTokens } from 'hooks/queries/useAccessTokens'
|
||||
import { Commands } from './Functions.types'
|
||||
import CommandRender from 'components/interfaces/Functions/CommandRender'
|
||||
@@ -18,17 +18,17 @@ const TerminalInstructions: FC<Props> = ({ closable = false }) => {
|
||||
const { ui } = useStore()
|
||||
|
||||
const { tokens } = useAccessTokens()
|
||||
const { services } = useProjectSettings(ref as string | undefined)
|
||||
const { data: settings } = useProjectSettingsQuery({ projectRef: ref as string })
|
||||
|
||||
const [showInstructions, setShowInstructions] = useState(!closable)
|
||||
|
||||
// Get the API service
|
||||
const API_SERVICE_ID = 1
|
||||
const apiService = (services ?? []).find((x: any) => x.app.id == API_SERVICE_ID)
|
||||
const apiKeys = apiService?.service_api_keys ?? []
|
||||
const anonKey = apiKeys.find((x: any) => x.name === 'anon key')?.api_key
|
||||
const apiService = settings?.autoApiService
|
||||
const anonKey = apiService?.service_api_keys.find((x: any) => x.name === 'anon key')
|
||||
? apiService.defaultApiKey
|
||||
: undefined
|
||||
|
||||
const endpoint = apiService?.app_config.endpoint ?? ''
|
||||
const endpoint = apiService?.endpoint ?? ''
|
||||
const endpointSections = endpoint.split('.')
|
||||
const functionsEndpoint = [
|
||||
...endpointSections.slice(0, 1),
|
||||
|
||||
@@ -5,9 +5,8 @@ import { Input, IconLoader, IconAlertCircle } from 'ui'
|
||||
import { JwtSecretUpdateStatus } from '@supabase/shared-types/out/events'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { checkPermissions, useJwtSecretUpdateStatus, useProjectSettings } from 'hooks'
|
||||
import { DEFAULT_PROJECT_API_SERVICE_ID, IS_PLATFORM } from 'lib/constants'
|
||||
import { PROJECT_ENDPOINT_PROTOCOL } from 'pages/api/constants'
|
||||
import { useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
import { checkPermissions, useJwtSecretUpdateStatus } from 'hooks'
|
||||
import Snippets from 'components/to-be-cleaned/Docs/Snippets'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import SimpleCodeBlock from 'components/to-be-cleaned/SimpleCodeBlock'
|
||||
@@ -23,10 +22,10 @@ const APIKeys = () => {
|
||||
const [selectedLanguage, setSelectedLanguage] = useState(availableLanguages[0])
|
||||
|
||||
const {
|
||||
services,
|
||||
data: settings,
|
||||
isError: isProjectSettingsError,
|
||||
isLoading: isProjectSettingsLoading,
|
||||
} = useProjectSettings(ref as string | undefined)
|
||||
} = useProjectSettingsQuery({ projectRef: ref as string })
|
||||
|
||||
const {
|
||||
jwtSecretUpdateStatus,
|
||||
@@ -37,8 +36,7 @@ const APIKeys = () => {
|
||||
const canReadAPIKeys = checkPermissions(PermissionAction.READ, 'service_api_keys')
|
||||
|
||||
// Get the API service
|
||||
const apiService = (services ?? []).find((x: any) => x.app.id == DEFAULT_PROJECT_API_SERVICE_ID)
|
||||
const apiConfig = apiService?.app_config ?? {}
|
||||
const apiService = settings?.autoApiService
|
||||
const apiKeys = apiService?.service_api_keys ?? []
|
||||
|
||||
// API keys should not be empty. However it can be populated with a delay on project creation
|
||||
@@ -46,7 +44,7 @@ const APIKeys = () => {
|
||||
const isNotUpdatingJwtSecret =
|
||||
jwtSecretUpdateStatus === undefined || jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updated
|
||||
|
||||
const apiUrl = `${IS_PLATFORM ? 'https' : PROJECT_ENDPOINT_PROTOCOL}://${apiConfig.endpoint}`
|
||||
const apiUrl = `${apiService?.protocol ?? 'https'}://${apiService?.endpoint ?? '-'}`
|
||||
const anonKey = apiKeys.find((key: any) => key.tags === 'anon')
|
||||
|
||||
const clientInitSnippet: any = Snippets.init(apiUrl)
|
||||
@@ -111,7 +109,7 @@ const APIKeys = () => {
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm">API Key</p>
|
||||
<div className="flex items-center space-x-1 -ml-1">
|
||||
{anonKey.tags?.split(',').map((x: any, i: number) => (
|
||||
{anonKey?.tags?.split(',').map((x: any, i: number) => (
|
||||
<code key={`${x}${i}`} className="text-xs">
|
||||
{x}
|
||||
</code>
|
||||
@@ -121,7 +119,7 @@ const APIKeys = () => {
|
||||
</div>
|
||||
}
|
||||
copy={canReadAPIKeys && isNotUpdatingJwtSecret}
|
||||
reveal={anonKey.tags !== 'anon' && canReadAPIKeys && isNotUpdatingJwtSecret}
|
||||
reveal={anonKey?.tags !== 'anon' && canReadAPIKeys && isNotUpdatingJwtSecret}
|
||||
value={
|
||||
!canReadAPIKeys
|
||||
? 'You need additional permissions to view API keys'
|
||||
@@ -129,7 +127,7 @@ const APIKeys = () => {
|
||||
? 'JWT secret update failed, new API key may have issues'
|
||||
: jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updating
|
||||
? 'Updating JWT secret...'
|
||||
: anonKey.api_key
|
||||
: apiService?.defaultApiKey
|
||||
}
|
||||
onChange={() => {}}
|
||||
descriptionText={
|
||||
|
||||
@@ -3,18 +3,15 @@ import { useRouter } from 'next/router'
|
||||
import { JwtSecretUpdateError, JwtSecretUpdateStatus } from '@supabase/shared-types/out/events'
|
||||
import { IconAlertCircle, Input } from 'ui'
|
||||
|
||||
import {
|
||||
useStore,
|
||||
useProjectSettings,
|
||||
useProjectPostgrestConfig,
|
||||
useJwtSecretUpdateStatus,
|
||||
} from 'hooks'
|
||||
import { configKeys } from 'data/config/keys'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
import { useStore, useProjectPostgrestConfig, useJwtSecretUpdateStatus } from 'hooks'
|
||||
|
||||
import Panel from 'components/ui/Panel'
|
||||
import PostgrestConfig from './PostgrestConfig'
|
||||
import { DisplayApiSettings } from 'components/ui/ProjectSettings'
|
||||
import { JWT_SECRET_UPDATE_ERROR_MESSAGES } from './API.constants'
|
||||
import { PROJECT_ENDPOINT_PROTOCOL } from 'pages/api/constants'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import JWTSettings from './JWTSettings'
|
||||
|
||||
@@ -26,8 +23,9 @@ const ServiceList: FC<Props> = ({ projectRef }) => {
|
||||
const { ui } = useStore()
|
||||
const router = useRouter()
|
||||
const { ref } = router.query
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const { services, isError, mutateSettings } = useProjectSettings(ref as string | undefined)
|
||||
const { data: settings, isError } = useProjectSettingsQuery({ projectRef: ref as string })
|
||||
const { mutateConfig } = useProjectPostgrestConfig(ref as string | undefined)
|
||||
const { jwtSecretUpdateError, jwtSecretUpdateStatus }: any = useJwtSecretUpdateStatus(ref)
|
||||
|
||||
@@ -41,7 +39,7 @@ const ServiceList: FC<Props> = ({ projectRef }) => {
|
||||
switch (jwtSecretUpdateStatus) {
|
||||
case Updated:
|
||||
mutateConfig()
|
||||
mutateSettings()
|
||||
queryClient.invalidateQueries({ queryKey: configKeys.settings(projectRef) })
|
||||
ui.setNotification({ category: 'success', message: 'Successfully updated JWT secret' })
|
||||
break
|
||||
case Failed:
|
||||
@@ -57,9 +55,8 @@ const ServiceList: FC<Props> = ({ projectRef }) => {
|
||||
}, [jwtSecretUpdateStatus])
|
||||
|
||||
// Get the API service
|
||||
const API_SERVICE_ID = 1
|
||||
const apiService = services ? services.find((x: any) => x.app.id == API_SERVICE_ID) : {}
|
||||
const apiConfig = apiService?.app_config
|
||||
const apiService = settings?.autoApiService
|
||||
const apiUrl = `${apiService?.protocol ?? 'https'}://${apiService?.endpoint ?? '-'}`
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -79,9 +76,7 @@ const ServiceList: FC<Props> = ({ projectRef }) => {
|
||||
readOnly
|
||||
disabled
|
||||
className="input-mono"
|
||||
value={`${IS_PLATFORM ? 'https' : PROJECT_ENDPOINT_PROTOCOL}://${
|
||||
apiConfig?.endpoint ?? '-'
|
||||
}`}
|
||||
value={apiUrl}
|
||||
descriptionText="A RESTful endpoint for querying and managing your database."
|
||||
layout="horizontal"
|
||||
/>
|
||||
|
||||
+1
-1
@@ -134,7 +134,7 @@ const CustomDomainVerify = ({ projectRef, customDomain, settings }: CustomDomain
|
||||
<DNSRecord
|
||||
type="CNAME"
|
||||
name={customDomain.hostname}
|
||||
value={settings?.autoApiService.app_config.endpoint ?? 'Loading...'}
|
||||
value={settings?.autoApiService.endpoint ?? 'Loading...'}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ const CustomDomainsConfigureHostname = () => {
|
||||
const { data: settings } = useProjectSettingsQuery({ projectRef: ref })
|
||||
|
||||
const FORM_ID = 'custom-domains-form'
|
||||
const endpoint = settings?.autoApiService.app_config.endpoint ?? undefined
|
||||
const endpoint = settings?.autoApiService.endpoint
|
||||
const canConfigureCustomDomain = checkPermissions(PermissionAction.UPDATE, 'projects')
|
||||
|
||||
const verifyCNAME = async (domain: string): Promise<boolean> => {
|
||||
@@ -123,7 +123,7 @@ const CustomDomainsConfigureHostname = () => {
|
||||
'your custom domain'
|
||||
)}
|
||||
, resolving to{' '}
|
||||
{endpoint !== undefined ? (
|
||||
{endpoint ? (
|
||||
<code className="text-xs">{endpoint}</code>
|
||||
) : (
|
||||
"your project's API URL"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FC } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { checkPermissions, useStore } from 'hooks'
|
||||
import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FC } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { Button, IconAlertCircle, IconLock } from 'ui'
|
||||
import { PostgresPolicy, PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresPolicy, PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import React, { FC } from 'react'
|
||||
import { isNil } from 'lodash'
|
||||
import { Select } from 'ui'
|
||||
import { PostgresType } from '@supabase/postgres-meta'
|
||||
import type { PostgresType } from '@supabase/postgres-meta'
|
||||
|
||||
import InputWithSuggestions from './InputWithSuggestions'
|
||||
import { POSTGRES_DATA_TYPES } from '../SidePanelEditor.constants'
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { FC, useEffect, useState } from 'react'
|
||||
import { isUndefined, isEmpty } from 'lodash'
|
||||
import { Dictionary } from 'components/grid'
|
||||
import { Checkbox, SidePanel, Input, Button, IconExternalLink, Toggle } from 'ui'
|
||||
import {
|
||||
import type {
|
||||
PostgresColumn,
|
||||
PostgresExtension,
|
||||
PostgresRelationship,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { find, isUndefined, isEqual, isNull } from 'lodash'
|
||||
import { Dictionary } from 'components/grid'
|
||||
import {
|
||||
import type {
|
||||
PostgresColumn,
|
||||
PostgresRelationship,
|
||||
PostgresTable,
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { Button, IconArrowRight } from 'ui'
|
||||
import { ColumnField } from '../SidePanelEditor.types'
|
||||
import InformationBox from 'components/ui/InformationBox'
|
||||
import { getForeignKeyUIState } from './ColumnEditor.utils'
|
||||
import { PostgresRelationship } from '@supabase/postgres-meta'
|
||||
import type { PostgresRelationship } from '@supabase/postgres-meta'
|
||||
|
||||
interface Props {
|
||||
column: ColumnField
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import React, { FC, ReactNode } from 'react'
|
||||
import { IconCalendar, IconType, IconHash, Listbox, IconToggleRight, Input } from 'ui'
|
||||
import { PostgresType } from '@supabase/postgres-meta'
|
||||
import type { PostgresType } from '@supabase/postgres-meta'
|
||||
import { POSTGRES_DATA_TYPES, POSTGRES_DATA_TYPE_OPTIONS } from '../SidePanelEditor.constants'
|
||||
import { PostgresDataTypeOption } from '../SidePanelEditor.types'
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { PostgresTable, PostgresColumn } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable, PostgresColumn } from '@supabase/postgres-meta'
|
||||
|
||||
interface Props {
|
||||
table: PostgresTable
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import React, { FC, useEffect, useState } from 'react'
|
||||
import { get, find, isEmpty, sortBy } from 'lodash'
|
||||
import { Dictionary } from 'components/grid'
|
||||
import { SidePanel, Input, Listbox, IconHelpCircle } from 'ui'
|
||||
import { PostgresTable, PostgresColumn } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable, PostgresColumn } from '@supabase/postgres-meta'
|
||||
|
||||
import ActionBar from '../ActionBar'
|
||||
import { ForeignKey } from './ForeignKeySelector.types'
|
||||
@@ -71,7 +71,7 @@ const ForeignKeySelector: FC<Props> = ({
|
||||
setSelectedForeignKey({
|
||||
schema: table.schema,
|
||||
table: table.name,
|
||||
column: table.columns.length > 0 ? table.columns[0].name : undefined,
|
||||
column: table.columns?.length ? table.columns[0].name : undefined,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import React, { FC, useEffect, useState } from 'react'
|
||||
import { SidePanel, IconLoader, IconXCircle } from 'ui'
|
||||
import { PostgresRelationship } from '@supabase/postgres-meta'
|
||||
import type { PostgresRelationship } from '@supabase/postgres-meta'
|
||||
|
||||
import ActionBar from '../ActionBar'
|
||||
import InputField from './InputField'
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { isUndefined, partition, isEmpty } from 'lodash'
|
||||
import { SidePanel } from 'ui'
|
||||
import { Dictionary } from 'components/grid'
|
||||
import { Query } from 'components/grid/query/Query'
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import ActionBar from '../ActionBar'
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { PostgresRelationship } from '@supabase/postgres-meta'
|
||||
import type { PostgresRelationship } from '@supabase/postgres-meta'
|
||||
|
||||
export interface JsonEditValue {
|
||||
column: string
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import dayjs from 'dayjs'
|
||||
import { find, isUndefined, compact, isEqual, omitBy, isNull, isString } from 'lodash'
|
||||
import { Dictionary } from 'components/grid'
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
import { uuidv4, minifyJSON, tryParseJson } from 'lib/helpers'
|
||||
import { RowField } from './RowEditor.types'
|
||||
@@ -15,7 +15,7 @@ export const generateRowFields = (
|
||||
// @ts-ignore
|
||||
const primaryKeyColumns = primary_keys.map((key) => key.name)
|
||||
|
||||
return table.columns.map((column) => {
|
||||
return table.columns!.map((column) => {
|
||||
const value = isUndefined(row)
|
||||
? ''
|
||||
: DATETIME_TYPES.includes(column.format)
|
||||
|
||||
@@ -2,7 +2,7 @@ import { FC, useState } from 'react'
|
||||
import { find, isEmpty, isUndefined } from 'lodash'
|
||||
import { Query, Dictionary } from 'components/grid'
|
||||
import { Modal } from 'ui'
|
||||
import { PostgresRelationship, PostgresTable, PostgresColumn } from '@supabase/postgres-meta'
|
||||
import type { PostgresRelationship, PostgresTable, PostgresColumn } from '@supabase/postgres-meta'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import { RowEditor, ColumnEditor, TableEditor } from '.'
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { PostgresRelationship } from '@supabase/postgres-meta'
|
||||
import type { PostgresRelationship } from '@supabase/postgres-meta'
|
||||
|
||||
export interface CreateColumnPayload {
|
||||
tableId: number
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FC } from 'react'
|
||||
import { isUndefined } from 'lodash'
|
||||
import { Checkbox, Input, IconX, IconMenu, Popover, IconLink, IconSettings, Button } from 'ui'
|
||||
import { PostgresType } from '@supabase/postgres-meta'
|
||||
import type { PostgresType } from '@supabase/postgres-meta'
|
||||
|
||||
import { ColumnField } from '../SidePanelEditor.types'
|
||||
import ColumnType from '../ColumnEditor/ColumnType'
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import React, { FC, useState } from 'react'
|
||||
import { partition, isEmpty, isUndefined } from 'lodash'
|
||||
import { Alert, Button, IconEdit, IconHelpCircle, IconKey, IconTrash, IconExternalLink } from 'ui'
|
||||
|
||||
import {
|
||||
import type {
|
||||
PostgresTable,
|
||||
PostgresColumn,
|
||||
PostgresRelationship,
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { FC } from 'react'
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
interface Props {
|
||||
schema: string
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { FC, useEffect, useState } from 'react'
|
||||
import { isUndefined, isEmpty } from 'lodash'
|
||||
import { Badge, Checkbox, SidePanel, Input, Alert } from 'ui'
|
||||
import { PostgresTable, PostgresType } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable, PostgresType } from '@supabase/postgres-meta'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import ActionBar from '../ActionBar'
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { some } from 'lodash'
|
||||
import { PostgresColumn, PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresColumn, PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
import { ImportContent, TableField } from './TableEditor.types'
|
||||
import { DEFAULT_COLUMNS } from './TableEditor.constants'
|
||||
|
||||
@@ -2,7 +2,7 @@ import { FC, useRef, useEffect, useState } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRouter } from 'next/router'
|
||||
import { find, isUndefined } from 'lodash'
|
||||
import { PostgresColumn, PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresColumn, PostgresTable } from '@supabase/postgres-meta'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { SchemaView } from 'types'
|
||||
@@ -92,7 +92,7 @@ const TableGridEditor: FC<Props> = ({
|
||||
? parseSupaTable(
|
||||
{
|
||||
table: selectedTable as PostgresTable,
|
||||
columns: (selectedTable as PostgresTable).columns,
|
||||
columns: (selectedTable as PostgresTable).columns ?? [],
|
||||
primaryKeys: (selectedTable as PostgresTable).primary_keys,
|
||||
relationships: (selectedTable as PostgresTable).relationships,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Project } from 'types'
|
||||
import { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types'
|
||||
import { useFlag } from 'hooks'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
|
||||
export const generateDatabaseMenu = (project?: Project): ProductMenuGroup[] => {
|
||||
const ref = project?.ref ?? 'default'
|
||||
@@ -62,12 +63,16 @@ export const generateDatabaseMenu = (project?: Project): ProductMenuGroup[] => {
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
name: 'Backups',
|
||||
key: 'backups',
|
||||
url: `/project/${ref}/database/backups/scheduled`,
|
||||
items: [],
|
||||
},
|
||||
...(IS_PLATFORM
|
||||
? [
|
||||
{
|
||||
name: 'Backups',
|
||||
key: 'backups',
|
||||
url: `/project/${ref}/database/backups/scheduled`,
|
||||
items: [],
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -3,7 +3,8 @@ import { useRouter } from 'next/router'
|
||||
import { find, filter, get as _get } from 'lodash'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
|
||||
import { useProjectSettings, useStore, withAuth } from 'hooks'
|
||||
import { AutoApiService, useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
import { useStore, withAuth } from 'hooks'
|
||||
import BaseLayout from 'components/layouts'
|
||||
import ProjectLayout from '../ProjectLayout/ProjectLayout'
|
||||
import StorageMenu from './StorageMenu'
|
||||
@@ -39,20 +40,24 @@ const StorageLayout: FC<Props> = ({ title, children }) => {
|
||||
buckets,
|
||||
} = storageExplorerStore || {}
|
||||
|
||||
const { services, isLoading } = useProjectSettings(ref as string | undefined)
|
||||
const apiService = find(services ?? [], (service) => service.app.id === 1)
|
||||
const projectUrl = apiService?.app_config?.endpoint ?? ''
|
||||
const { data: settings, isLoading } = useProjectSettingsQuery({ projectRef: ref as string })
|
||||
const apiService = settings?.autoApiService
|
||||
const serviceKey = find(apiService?.service_api_keys ?? [], (key) => key.tags === 'service_role')
|
||||
const canAccessStorage = !isLoading && services && serviceKey
|
||||
const canAccessStorage = !isLoading && apiService && serviceKey
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && services) initializeStorageStore()
|
||||
if (!isLoading && apiService) initializeStorageStore(apiService)
|
||||
}, [isLoading])
|
||||
|
||||
const initializeStorageStore = async () => {
|
||||
if (projectUrl) {
|
||||
const initializeStorageStore = async (apiService: AutoApiService) => {
|
||||
if (apiService.endpoint) {
|
||||
if (serviceKey) {
|
||||
storageExplorerStore.initStore(ref, projectUrl, serviceKey.api_key)
|
||||
storageExplorerStore.initStore(
|
||||
ref,
|
||||
apiService.endpoint,
|
||||
apiService.serviceApiKey,
|
||||
apiService.protocol
|
||||
)
|
||||
await storageExplorerStore.fetchBuckets()
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { FC, ReactNode, useState, useEffect } from 'react'
|
||||
import { isUndefined } from 'lodash'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { checkPermissions, useParams, useStore } from 'hooks'
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
} from 'ui'
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { PostgresSchema, PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresSchema, PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
import { SchemaView } from 'types'
|
||||
import { checkPermissions, useStore, useParams } from 'hooks'
|
||||
|
||||
@@ -26,7 +26,7 @@ const FileExplorer = ({
|
||||
const fileExplorerRef = useRef(null)
|
||||
const storageExplorerStore = useStorageStore()
|
||||
|
||||
const { setSelectedItemToRename } = storageExplorerStore
|
||||
const { setSelectedItemToRename, setSelectedItemsToDelete } = storageExplorerStore
|
||||
|
||||
useEffect(() => {
|
||||
if (fileExplorerRef) {
|
||||
|
||||
@@ -3,8 +3,8 @@ import { IconAlertCircle, IconLoader, Input } from 'ui'
|
||||
import { JwtSecretUpdateStatus } from '@supabase/shared-types/out/events'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { checkPermissions, useJwtSecretUpdateStatus, useProjectSettings } from 'hooks'
|
||||
import { DEFAULT_PROJECT_API_SERVICE_ID } from 'lib/constants'
|
||||
import { useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
import { checkPermissions, useJwtSecretUpdateStatus } from 'hooks'
|
||||
import Panel from 'components/ui/Panel'
|
||||
|
||||
const DisplayApiSettings = () => {
|
||||
@@ -12,11 +12,10 @@ const DisplayApiSettings = () => {
|
||||
const { ref } = router.query
|
||||
|
||||
const {
|
||||
services,
|
||||
error: projectSettingsError,
|
||||
data: settings,
|
||||
isError: isProjectSettingsError,
|
||||
isLoading: isProjectSettingsLoading,
|
||||
} = useProjectSettings(ref as string | undefined)
|
||||
} = useProjectSettingsQuery({ projectRef: ref as string })
|
||||
const {
|
||||
jwtSecretUpdateStatus,
|
||||
isError: isJwtSecretUpdateStatusError,
|
||||
@@ -28,8 +27,7 @@ const DisplayApiSettings = () => {
|
||||
const isNotUpdatingJwtSecret =
|
||||
jwtSecretUpdateStatus === undefined || jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updated
|
||||
// Get the API service
|
||||
const apiService = (services ?? []).find((x: any) => x.app.id == DEFAULT_PROJECT_API_SERVICE_ID)
|
||||
const apiKeys = apiService?.service_api_keys ?? []
|
||||
const apiKeys = settings?.autoApiService.service_api_keys ?? []
|
||||
// api keys should not be empty. However it can be populated with a delay on project creation
|
||||
const isApiKeysEmpty = apiKeys.length === 0
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ import { useRouter } from 'next/router'
|
||||
import { Input, IconAlertCircle, IconLoader } from 'ui'
|
||||
import { JwtSecretUpdateStatus } from '@supabase/shared-types/out/events'
|
||||
import { useJwtSecretUpdateStatus, useProjectSettings } from 'hooks'
|
||||
import { DEFAULT_PROJECT_API_SERVICE_ID, IS_PLATFORM } from 'lib/constants'
|
||||
import { PROJECT_ENDPOINT_PROTOCOL } from 'pages/api/constants'
|
||||
import { DEFAULT_PROJECT_API_SERVICE_ID } from 'lib/constants'
|
||||
import Panel from 'components/ui/Panel'
|
||||
|
||||
const DisplayConfigSettings = () => {
|
||||
@@ -28,6 +27,7 @@ const DisplayConfigSettings = () => {
|
||||
const jwtSecret = project?.jwt_secret ?? ''
|
||||
const apiService = (services ?? []).find((x: any) => x.app.id == DEFAULT_PROJECT_API_SERVICE_ID)
|
||||
const apiConfig = apiService?.app_config ?? {}
|
||||
const apiUrl = `${apiConfig.protocol ?? 'https'}://${apiConfig.endpoint ?? '-'}`
|
||||
|
||||
return (
|
||||
<ConfigContentWrapper>
|
||||
@@ -56,7 +56,7 @@ const DisplayConfigSettings = () => {
|
||||
copy
|
||||
disabled
|
||||
className="input-mono"
|
||||
value={`${IS_PLATFORM ? 'https' : PROJECT_ENDPOINT_PROTOCOL}://${apiConfig.endpoint}`}
|
||||
value={apiUrl}
|
||||
descriptionText="A RESTful endpoint for querying and managing your database."
|
||||
layout="horizontal"
|
||||
/>
|
||||
|
||||
@@ -48,6 +48,7 @@ export type ServiceApiKey = {
|
||||
}
|
||||
|
||||
export type AutoApiService = Service & {
|
||||
protocol: 'https' | 'http'
|
||||
endpoint: string
|
||||
restUrl: string
|
||||
project: Project
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { v4 as _uuidV4 } from 'uuid'
|
||||
import { PostgresColumn } from '@supabase/postgres-meta'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { PASSWORD_STRENGTH, DEFAULT_MINIMUM_PASSWORD_STRENGTH, API_URL } from 'lib/constants'
|
||||
|
||||
|
||||
@@ -97,17 +97,16 @@ class StorageExplorerStore {
|
||||
}
|
||||
}
|
||||
|
||||
initStore(projectRef, url, serviceKey) {
|
||||
initStore(projectRef, url, serviceKey, protocol = PROJECT_ENDPOINT_PROTOCOL) {
|
||||
this.projectRef = projectRef
|
||||
this.initializeSupabaseClient(serviceKey, url)
|
||||
this.initializeSupabaseClient(serviceKey, url, protocol)
|
||||
}
|
||||
|
||||
/* Methods which are commonly used + For better readability */
|
||||
|
||||
initializeSupabaseClient = (serviceKey, serviceEndpoint) => {
|
||||
console.debug(serviceEndpoint)
|
||||
initializeSupabaseClient = (serviceKey, serviceEndpoint, protocol) => {
|
||||
this.supabaseClient = createClient(
|
||||
`${IS_PLATFORM ? 'https' : PROJECT_ENDPOINT_PROTOCOL}://${serviceEndpoint}`,
|
||||
`${IS_PLATFORM ? 'https' : protocol}://${serviceEndpoint}`,
|
||||
serviceKey,
|
||||
{
|
||||
auth: {
|
||||
|
||||
@@ -131,6 +131,19 @@ const nextConfig = {
|
||||
key: 'X-Frame-Options',
|
||||
value: 'DENY',
|
||||
},
|
||||
{
|
||||
key: 'X-Content-Type-Options',
|
||||
value: 'no-sniff',
|
||||
},
|
||||
{
|
||||
key: 'Content-Security-Policy',
|
||||
value: `
|
||||
frame-ancestors 'none';
|
||||
upgrade-insecure-requests;
|
||||
`
|
||||
.replace(/\s{2,}/g, ' ')
|
||||
.trim(),
|
||||
},
|
||||
{
|
||||
key: 'Referrer-Policy',
|
||||
value: 'strict-origin-when-cross-origin',
|
||||
|
||||
+1
-1
@@ -26,7 +26,6 @@
|
||||
"@sentry/nextjs": "^6.17.4",
|
||||
"@stripe/react-stripe-js": "^1.7.0",
|
||||
"@stripe/stripe-js": "^1.25.0",
|
||||
"@supabase/postgres-meta": "^0.26.1",
|
||||
"@supabase/react-data-grid": "^7.1.0-beta.7",
|
||||
"@supabase/shared-types": "^0.1.29",
|
||||
"@supabase/supabase-js": "^2.1.1",
|
||||
@@ -102,6 +101,7 @@
|
||||
"@storybook/addon-links": "^6.4.19",
|
||||
"@storybook/react": "^6.4.19",
|
||||
"@storybook/testing-library": "^0.0.9",
|
||||
"@supabase/postgres-meta": "^0.60.2",
|
||||
"@tailwindcss/typography": "^0.5.2",
|
||||
"@testing-library/dom": "^8.19.0",
|
||||
"@testing-library/react": "^12.1.5",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const PUBLIC_URL = new URL(process.env.NEXT_PUBLIC_SUPABASE_PUBLIC_URL || 'http://localhost:8000')
|
||||
const PUBLIC_URL = new URL(process.env.SUPABASE_PUBLIC_URL || 'http://localhost:8000')
|
||||
|
||||
export const PROJECT_REST_URL = `${PUBLIC_URL.origin}/rest/v1/`
|
||||
export const PROJECT_ENDPOINT = PUBLIC_URL.host
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { method } = req
|
||||
|
||||
switch (method) {
|
||||
case 'GET':
|
||||
return handleGetAll(req, res)
|
||||
default:
|
||||
res.setHeader('Allow', ['GET'])
|
||||
res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
|
||||
}
|
||||
}
|
||||
|
||||
const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
return res.status(200).json({ tierKey: 'FREE', backups: [] })
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import apiWrapper from 'lib/api/apiWrapper'
|
||||
import { PROJECT_ENDPOINT, PROJECT_REST_URL } from 'pages/api/constants'
|
||||
import { PROJECT_ENDPOINT, PROJECT_ENDPOINT_PROTOCOL, PROJECT_REST_URL } from 'pages/api/constants'
|
||||
|
||||
export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler)
|
||||
|
||||
@@ -36,17 +36,12 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
{
|
||||
id: 1,
|
||||
name: 'Default API',
|
||||
project: { ref: 'default' },
|
||||
app: { id: 1, name: 'Auto API' },
|
||||
app_config: {
|
||||
db_schema: 'public',
|
||||
endpoint: PROJECT_ENDPOINT,
|
||||
realtime_enabled: true,
|
||||
},
|
||||
endpoint: PROJECT_ENDPOINT,
|
||||
restUrl: PROJECT_REST_URL,
|
||||
defaultApiKey: process.env.SUPABASE_ANON_KEY,
|
||||
serviceApiKey: process.env.SUPABASE_SERVICE_KEY,
|
||||
service_api_keys: [
|
||||
{
|
||||
api_key_encrypted: '-',
|
||||
@@ -72,6 +67,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
endpoint: PROJECT_ENDPOINT,
|
||||
realtime_enabled: true,
|
||||
},
|
||||
protocol: PROJECT_ENDPOINT_PROTOCOL,
|
||||
endpoint: PROJECT_ENDPOINT,
|
||||
restUrl: PROJECT_REST_URL,
|
||||
defaultApiKey: process.env.SUPABASE_ANON_KEY,
|
||||
|
||||
@@ -5,14 +5,13 @@ import { FC, createContext, useContext, useEffect, useState } from 'react'
|
||||
import { observer, useLocalObservable } from 'mobx-react-lite'
|
||||
|
||||
import { NextPageWithLayout } from 'types'
|
||||
import { API_URL, IS_PLATFORM } from 'lib/constants'
|
||||
import { PROJECT_ENDPOINT_PROTOCOL } from 'pages/api/constants'
|
||||
import { checkPermissions, useStore } from 'hooks'
|
||||
import { get } from 'lib/common/fetch'
|
||||
import { snakeToCamel } from 'lib/helpers'
|
||||
import { DocsLayout } from 'components/layouts'
|
||||
import { GeneralContent, ResourceContent, RpcContent } from 'components/interfaces/Docs'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
|
||||
const PageContext = createContext(null)
|
||||
|
||||
@@ -71,9 +70,11 @@ const DocView: FC<any> = observer(({}) => {
|
||||
const [selectedLang, setSelectedLang] = useState<any>('js')
|
||||
const [showApiKey, setShowApiKey] = useState<any>(DEFAULT_KEY)
|
||||
|
||||
const { data, error }: any = useSWR(`${API_URL}/props/project/${PageState.projectRef}/api`, get)
|
||||
const API_KEY = data?.autoApiService?.defaultApiKey
|
||||
const swaggerUrl = data?.autoApiService?.restUrl
|
||||
const { data, error } = useProjectSettingsQuery({ projectRef: PageState.projectRef as string })
|
||||
const API_KEY = data?.autoApiService.service_api_keys.find((key: any) => key.tags === 'anon')
|
||||
? data.autoApiService.defaultApiKey
|
||||
: undefined
|
||||
const swaggerUrl = data?.autoApiService.restUrl
|
||||
const headers: any = { apikey: API_KEY }
|
||||
|
||||
const canReadServiceKey = checkPermissions(
|
||||
@@ -81,7 +82,7 @@ const DocView: FC<any> = observer(({}) => {
|
||||
'service_api_keys.service_role_key'
|
||||
)
|
||||
|
||||
if (API_KEY?.length > 40) headers['Authorization'] = `Bearer ${API_KEY}`
|
||||
if (API_KEY) headers['Authorization'] = `Bearer ${API_KEY}`
|
||||
|
||||
const { data: jsonSchema, error: jsonSchemaError } = useSWR(
|
||||
() => swaggerUrl,
|
||||
@@ -117,9 +118,7 @@ const DocView: FC<any> = observer(({}) => {
|
||||
// Data Loaded
|
||||
const autoApiService = {
|
||||
...data.autoApiService,
|
||||
endpoint: IS_PLATFORM
|
||||
? `https://${data?.autoApiService?.endpoint}`
|
||||
: `${PROJECT_ENDPOINT_PROTOCOL}://${data.autoApiService.endpoint}`,
|
||||
endpoint: `${data.autoApiService.protocol ?? 'https'}://${data.autoApiService.endpoint ?? '-'}`,
|
||||
}
|
||||
|
||||
const { query } = router
|
||||
@@ -175,7 +174,7 @@ const DocView: FC<any> = observer(({}) => {
|
||||
key="anon"
|
||||
onClick={() =>
|
||||
setShowApiKey({
|
||||
key: autoApiService?.defaultApiKey,
|
||||
key: API_KEY,
|
||||
name: 'anon (public)',
|
||||
})
|
||||
}
|
||||
@@ -187,7 +186,7 @@ const DocView: FC<any> = observer(({}) => {
|
||||
key="service"
|
||||
onClick={() =>
|
||||
setShowApiKey({
|
||||
key: autoApiService?.serviceApiKey,
|
||||
key: autoApiService.serviceApiKey,
|
||||
name: 'service_role (secret)',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { isUndefined } from 'lodash'
|
||||
import { PostgresColumn, PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresColumn, PostgresTable } from '@supabase/postgres-meta'
|
||||
import { Modal } from 'ui'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useRouter } from 'next/router'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { isUndefined, isNaN } from 'lodash'
|
||||
import { Alert, Button, Checkbox, IconExternalLink, Modal } from 'ui'
|
||||
import { PostgresTable, PostgresColumn } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable, PostgresColumn } from '@supabase/postgres-meta'
|
||||
|
||||
import { useStore, withAuth, useUrlState, useParams } from 'hooks'
|
||||
import { Dictionary } from 'components/grid'
|
||||
|
||||
@@ -3,7 +3,7 @@ import { NextPage } from 'next'
|
||||
import router from 'next/router'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { isUndefined } from 'lodash'
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
import { useStore, withAuth } from 'hooks'
|
||||
import { TableEditorLayout } from 'components/layouts'
|
||||
|
||||
@@ -6,7 +6,8 @@ import { IconGlobe, IconTerminal } from 'ui'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { NextPageWithLayout } from 'types'
|
||||
import { checkPermissions, useProjectSettings, useStore } from 'hooks'
|
||||
import { useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
import { checkPermissions, useStore } from 'hooks'
|
||||
import FunctionsLayout from 'components/layouts/FunctionsLayout'
|
||||
import CommandRender from 'components/interfaces/Functions/CommandRender'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
@@ -95,16 +96,14 @@ const PageLayout: NextPageWithLayout = () => {
|
||||
},
|
||||
]
|
||||
|
||||
const { services } = useProjectSettings(ref as string | undefined)
|
||||
|
||||
const API_SERVICE_ID = 1
|
||||
|
||||
// Get the API service
|
||||
const apiService = (services ?? []).find((x: any) => x.app.id == API_SERVICE_ID)
|
||||
const apiKeys = apiService?.service_api_keys ?? []
|
||||
const anonKey = apiKeys.find((x: any) => x.name === 'anon key')?.api_key
|
||||
const { data: settings } = useProjectSettingsQuery({ projectRef: ref as string })
|
||||
const apiService = settings?.autoApiService
|
||||
const anonKey = apiService?.service_api_keys.find((x: any) => x.name === 'anon key')
|
||||
? apiService.defaultApiKey
|
||||
: undefined
|
||||
|
||||
const endpoint = apiService?.app_config.endpoint ?? ''
|
||||
const endpoint = apiService?.endpoint ?? ''
|
||||
const endpointSections = endpoint.split('.')
|
||||
const functionsEndpoint = [
|
||||
...endpointSections.slice(0, 1),
|
||||
|
||||
@@ -370,8 +370,8 @@ const ProjectLinks: FC = observer(() => {
|
||||
|
||||
// Then create env for vercel project with supabase project
|
||||
const vercelEnvs = prepareVercelEvns(defaultVercelEnvs, {
|
||||
endpoint: `${IS_PLATFORM ? 'https' : PROJECT_ENDPOINT_PROTOCOL}://${
|
||||
projectDetails.autoApiService.endpoint
|
||||
endpoint: `${projectDetails.apiService.protocol ?? 'https'}://${
|
||||
projectDetails.apiService.endpoint ?? '-'
|
||||
}`,
|
||||
anon_key: projectDetails.autoApiService.defaultApiKey,
|
||||
service_key: projectDetails.autoApiService.serviceApiKey,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PostgresMetaInterface from '../common/PostgresMetaInterface'
|
||||
import { PostgresColumn } from '@supabase/postgres-meta'
|
||||
import type { PostgresColumn } from '@supabase/postgres-meta'
|
||||
import { IRootStore } from '../RootStore'
|
||||
|
||||
export default class ColumnStore extends PostgresMetaInterface<PostgresColumn> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PostgresMetaInterface from '../common/PostgresMetaInterface'
|
||||
import { PostgresColumn } from '@supabase/postgres-meta'
|
||||
import type { PostgresColumn } from '@supabase/postgres-meta'
|
||||
import { IRootStore } from '../RootStore'
|
||||
|
||||
export default class ExtensionsStore extends PostgresMetaInterface<PostgresColumn> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
import PostgresMetaInterface from '../common/PostgresMetaInterface'
|
||||
import { IRootStore } from '../RootStore'
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { makeObservable, observable } from 'mobx'
|
||||
import { find, isUndefined, isEqual, isEmpty, chunk } from 'lodash'
|
||||
import { Query } from 'components/grid/query/Query'
|
||||
|
||||
import {
|
||||
import type {
|
||||
PostgresColumn,
|
||||
PostgresTable,
|
||||
PostgresRelationship,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PostgresSchema } from '@supabase/postgres-meta'
|
||||
import type { PostgresSchema } from '@supabase/postgres-meta'
|
||||
import PostgresMetaInterface from '../common/PostgresMetaInterface'
|
||||
import { IRootStore } from '../RootStore'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { action, makeObservable } from 'mobx'
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import type { PostgresTable } from '@supabase/postgres-meta'
|
||||
|
||||
import PostgresMetaInterface, { IPostgresMetaInterface } from '../common/PostgresMetaInterface'
|
||||
import { IRootStore } from '../RootStore'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PostgresMetaInterface from '../common/PostgresMetaInterface'
|
||||
import { PostgresType } from '@supabase/postgres-meta'
|
||||
import type { PostgresType } from '@supabase/postgres-meta'
|
||||
import { IRootStore } from '../RootStore'
|
||||
|
||||
export default class TypesStore extends PostgresMetaInterface<PostgresType> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PostgresColumn } from '@supabase/postgres-meta'
|
||||
import type { PostgresColumn } from '@supabase/postgres-meta'
|
||||
import { Query } from 'components/grid'
|
||||
import { makeAutoObservable } from 'mobx'
|
||||
import { SchemaView, VaultSecret } from 'types'
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { PostgresColumn } from '@supabase/postgres-meta'
|
||||
import type { PostgresColumn } from '@supabase/postgres-meta'
|
||||
|
||||
export interface Notification {
|
||||
category: 'info' | 'error' | 'success' | 'loading'
|
||||
|
||||
Reference in new issue
Block a user