mirror of
https://github.com/supabase/supabase.git
synced 2026-10-15 06:09:08 +03:00
Merge branch 'master' into feat/minutely-daily-usage-charts
This commit is contained in:
commit
f140f435fe
23 files changed
+690
-361
No files matched your search
Generated
+484
-302
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -10,7 +10,7 @@
|
||||
"@docusaurus/core": "^2.0.0-alpha.63",
|
||||
"@docusaurus/preset-classic": "^2.0.0-alpha.63",
|
||||
"@kiwicopple/prism-react-renderer": "github:kiwicopple/prism-react-renderer",
|
||||
"mermaid": "^8.6.4",
|
||||
"mermaid": "^8.13.8",
|
||||
"react": "^16.8.4",
|
||||
"react-dom": "^16.8.4",
|
||||
"react-inlinesvg": "^2.0.1"
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
|
||||
POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
|
||||
JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
|
||||
ANON_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYyNzIwODU0MCwiZXhwIjoxOTc0MzYzNzQwfQ.zcaQfHd3VA7XgJmdGfmV86OLVJT9s2MTmSy-e69BpUY
|
||||
SERVICE_ROLE_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaWF0IjoxNjI3MjA4NTQwLCJleHAiOjE5NzQzNjM3NDB9.pkT3PNpO4DtO45Ac5HK_TKCx8sGLgNtV__pr_ZrRSAU
|
||||
ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
|
||||
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
|
||||
|
||||
# Auth
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ _format_version: "1.1"
|
||||
consumers:
|
||||
- username: anon
|
||||
keyauth_credentials:
|
||||
- key: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYyNzIwODU0MCwiZXhwIjoxOTc0MzYzNzQwfQ.zcaQfHd3VA7XgJmdGfmV86OLVJT9s2MTmSy-e69BpUY
|
||||
- key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
|
||||
- username: service_role
|
||||
keyauth_credentials:
|
||||
- key: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaWF0IjoxNjI3MjA4NTQwLCJleHAiOjE5NzQzNjM3NDB9.pkT3PNpO4DtO45Ac5HK_TKCx8sGLgNtV__pr_ZrRSAU
|
||||
- key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
|
||||
|
||||
###
|
||||
### Access Control List
|
||||
|
||||
+2
-2
@@ -2,5 +2,5 @@ STUDIO_PG_META_URL=http://localhost:8000/pg
|
||||
POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
|
||||
|
||||
SUPABASE_URL=http://localhost:8000
|
||||
SUPABASE_ANON_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYyNzIwODU0MCwiZXhwIjoxOTc0MzYzNzQwfQ.zcaQfHd3VA7XgJmdGfmV86OLVJT9s2MTmSy-e69BpUY
|
||||
SUPABASE_SERVICE_KEY=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaWF0IjoxNjI3MjA4NTQwLCJleHAiOjE5NzQzNjM3NDB9.pkT3PNpO4DtO45Ac5HK_TKCx8sGLgNtV__pr_ZrRSAU
|
||||
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
|
||||
SUPABASE_SERVICE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Popover,
|
||||
Typography,
|
||||
} from '@supabase/ui'
|
||||
import { useRouter } from 'next/router'
|
||||
import { FC } from 'react'
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
@@ -16,6 +17,10 @@ import SVG from 'react-inlinesvg'
|
||||
interface Props {}
|
||||
|
||||
const HelpPopover: FC<Props> = () => {
|
||||
const router = useRouter()
|
||||
const projectRef = router.query.ref
|
||||
const supportUrl = `/support/new${projectRef ? `?ref=${projectRef}` : ''}`
|
||||
|
||||
return (
|
||||
<Popover
|
||||
className="w-80"
|
||||
@@ -34,7 +39,7 @@ const HelpPopover: FC<Props> = () => {
|
||||
hosted services.
|
||||
</p>
|
||||
</Typography.Text>
|
||||
<Link href="/support/new">
|
||||
<Link href={supportUrl}>
|
||||
<Button className="sbui-default-button--dark-white" icon={<IconMail />}>
|
||||
Contact support team
|
||||
</Button>
|
||||
|
||||
@@ -16,7 +16,7 @@ export async function fetchVercelProjects({
|
||||
url = `${url}?${query}`
|
||||
}
|
||||
const response = await get(url, {
|
||||
headers: { Authorization: `Bearer ${vercelToken}` },
|
||||
headers: { vercel_authorization: `Bearer ${vercelToken}` },
|
||||
})
|
||||
if (response.error != null) {
|
||||
return { error: `Retrieve vercel projects failed. ${response.error?.message}` }
|
||||
@@ -48,7 +48,7 @@ export async function fetchVercelProject({
|
||||
url = `${url}?${query}`
|
||||
}
|
||||
const data = await get(url, {
|
||||
headers: { Authorization: `Bearer ${vercelToken}` },
|
||||
headers: { vercel_authorization: `Bearer ${vercelToken}` },
|
||||
})
|
||||
if (data.error != null) {
|
||||
return { error: `Retrieve vercel project failed. ${data.error.message}` }
|
||||
@@ -74,7 +74,7 @@ export async function fetchVercelProjectEnvs({
|
||||
url = `${url}?${query}`
|
||||
}
|
||||
const response = await get(url, {
|
||||
headers: { Authorization: `Bearer ${vercelToken}` },
|
||||
headers: { vercel_authorization: `Bearer ${vercelToken}` },
|
||||
})
|
||||
if (response.error != null) {
|
||||
return { error: `Retrieve vercel project envs failed. ${response.error?.message}` }
|
||||
@@ -114,7 +114,7 @@ export async function createVercelEnv({
|
||||
url,
|
||||
{ key, value, type, target },
|
||||
{
|
||||
headers: { Authorization: `Bearer ${vercelToken}` },
|
||||
headers: { vercel_authorization: `Bearer ${vercelToken}` },
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ function checkRedirectTo(
|
||||
redirectIfFound?: boolean
|
||||
) {
|
||||
if (loading) return false
|
||||
if (router.asPath == redirectTo) return false
|
||||
if (router.pathname == redirectTo) return false
|
||||
|
||||
// If redirectTo is set, redirect if the user was not found.
|
||||
if (redirectTo && !redirectIfFound && !profile) return true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { IconMoon, IconSun, Select, Typography } from '@supabase/ui'
|
||||
import { IconMoon, IconSun, Select, Typography, Input } from '@supabase/ui'
|
||||
|
||||
import { useProfile, useStore, withAuth } from 'hooks'
|
||||
import { post } from 'lib/common/fetch'
|
||||
@@ -32,8 +32,10 @@ export default withAuth(User)
|
||||
const ProfileCard = observer(() => {
|
||||
const { ui } = useStore()
|
||||
const { mutateProfile } = useProfile()
|
||||
|
||||
const user = ui.profile
|
||||
|
||||
console.log('User', user?.username, user?.primary_email)
|
||||
|
||||
const updateUser = async (model: any) => {
|
||||
try {
|
||||
const updatedUser = await post(`${API_URL}/profile/update`, model)
|
||||
@@ -51,6 +53,9 @@ const ProfileCard = observer(() => {
|
||||
|
||||
return (
|
||||
<article className="p-4 max-w-4xl">
|
||||
<section>
|
||||
<GithubProfile />
|
||||
</section>
|
||||
<section className="">
|
||||
{/* @ts-ignore */}
|
||||
<SchemaFormPanel
|
||||
@@ -77,6 +82,41 @@ const ProfileCard = observer(() => {
|
||||
)
|
||||
})
|
||||
|
||||
const GithubProfile = observer(() => {
|
||||
const { ui } = useStore()
|
||||
|
||||
return (
|
||||
<Panel
|
||||
title={[
|
||||
<Typography.Title key="panel-title" level={5} className="mb-0">
|
||||
Account Information
|
||||
</Typography.Title>,
|
||||
]}
|
||||
>
|
||||
<Panel.Content>
|
||||
<div className="space-y-2">
|
||||
<Input
|
||||
readOnly
|
||||
disabled
|
||||
label="Username"
|
||||
layout="horizontal"
|
||||
value=""
|
||||
placeholder={ui.profile?.username ?? ''}
|
||||
/>
|
||||
<Input
|
||||
readOnly
|
||||
disabled
|
||||
label="Email"
|
||||
layout="horizontal"
|
||||
value=""
|
||||
placeholder={ui.profile?.primary_email ?? ''}
|
||||
/>
|
||||
</div>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
)
|
||||
})
|
||||
|
||||
const ThemeSettings = observer(() => {
|
||||
const { ui } = useStore()
|
||||
|
||||
|
||||
+48
-4
@@ -1,19 +1,21 @@
|
||||
import { NextPage } from 'next'
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRouter } from 'next/router'
|
||||
import { NextRouter, useRouter } from 'next/router'
|
||||
import { isUndefined } from 'lodash'
|
||||
import { Typography } from '@supabase/ui'
|
||||
|
||||
import { Project } from 'types'
|
||||
import { useProfile, useStore, withAuth } from 'hooks'
|
||||
import { post, delete_ } from 'lib/common/fetch'
|
||||
import { API_URL, IS_PLATFORM, PROJECT_STATUS, STRIPE_PRODUCT_IDS } from 'lib/constants'
|
||||
import { API_URL, IS_PLATFORM, PROJECT_STATUS } from 'lib/constants'
|
||||
import { AccountLayout } from 'components/layouts'
|
||||
import { auth } from 'lib/gotrue'
|
||||
import Landing from 'components/interfaces/Home/Landing'
|
||||
import ProjectList from 'components/interfaces/Home/ProjectList'
|
||||
import OrganizationDropdown from 'components/to-be-cleaned/Dropdown/OrganizationDropdown'
|
||||
import TextConfirmModal from 'components/to-be-cleaned/ModalsDeprecated/TextConfirmModal'
|
||||
import Connecting from 'components/ui/Loading'
|
||||
|
||||
const Home: NextPage = () => {
|
||||
const { app, ui } = useStore()
|
||||
@@ -26,7 +28,23 @@ const Home: NextPage = () => {
|
||||
const [selectedProjectToDelete, setSelectedProjectToDelete] = useState<Project>()
|
||||
|
||||
if (!profile) {
|
||||
return <Landing />
|
||||
return <UnauthorizedLanding />
|
||||
} else {
|
||||
const isRedirect = isRedirectFromThirdPartyService(router)
|
||||
if (isRedirect) {
|
||||
const queryParams = (router.query as any) || {}
|
||||
const params = new URLSearchParams(queryParams)
|
||||
if (router.query?.next?.includes('https://vercel.com')) {
|
||||
router.push(`/vercel/integrate?${params.toString()}`)
|
||||
}
|
||||
if (router.query?.next?.includes('new-project')) {
|
||||
router.push('/new/project')
|
||||
}
|
||||
if (router.query['x-amzn-marketplace-token'] != undefined) {
|
||||
router.push(`/account/associate?${params.toString()}`)
|
||||
}
|
||||
return <Connecting />
|
||||
}
|
||||
}
|
||||
|
||||
const onSelectDeleteProject = async (project: Project) => {
|
||||
@@ -103,3 +121,29 @@ const Home: NextPage = () => {
|
||||
)
|
||||
}
|
||||
export default withAuth(observer(Home))
|
||||
|
||||
// detect for redirect from 3rd party service like vercel, aws...
|
||||
function isRedirectFromThirdPartyService(router: NextRouter) {
|
||||
return router.query.next !== undefined || router.query['x-amzn-marketplace-token'] !== undefined
|
||||
}
|
||||
|
||||
const UnauthorizedLanding = () => {
|
||||
const router = useRouter()
|
||||
const autoLogin = isRedirectFromThirdPartyService(router)
|
||||
|
||||
useEffect(() => {
|
||||
if (autoLogin) {
|
||||
const queryParams = (router.query as any) || {}
|
||||
const params = new URLSearchParams(queryParams)
|
||||
// trigger github signIn
|
||||
auth.signIn(
|
||||
{ provider: 'github' },
|
||||
{
|
||||
redirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}?${params.toString()}`,
|
||||
}
|
||||
)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return autoLogin ? <Connecting /> : <Landing />
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { Button, Typography } from '@supabase/ui'
|
||||
import Router from 'next/router'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { API_URL } from 'lib/constants'
|
||||
import { useStore, withAuth } from 'hooks'
|
||||
@@ -15,6 +15,8 @@ import Panel from 'components/to-be-cleaned/Panel'
|
||||
*/
|
||||
const Wizard = () => {
|
||||
const { ui, app } = useStore()
|
||||
const router = useRouter()
|
||||
|
||||
const [orgName, setOrgName] = useState('')
|
||||
const [newOrgLoading, setNewOrgLoading] = useState(false)
|
||||
|
||||
@@ -49,11 +51,7 @@ const Wizard = () => {
|
||||
} else {
|
||||
const org = response
|
||||
app.onOrgAdded(org)
|
||||
|
||||
// Router.push('/new/[slug]', `/new/${org.slug}`)
|
||||
// Using window.location.href for now as organization metadata needs to refresh
|
||||
// We do not get is_owner nor stripe_customer_id from the response here
|
||||
window.location.href = `/new/${org.slug}`
|
||||
router.push(`/new/${org.slug}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +68,7 @@ const Wizard = () => {
|
||||
]}
|
||||
footer={[
|
||||
<div key="panel-footer" className="flex items-center w-full justify-between">
|
||||
<Button type="default" onClick={() => Router.push('/')}>
|
||||
<Button type="default" onClick={() => router.push('/')}>
|
||||
Cancel
|
||||
</Button>
|
||||
<div className="space-x-3">
|
||||
|
||||
@@ -188,6 +188,7 @@ const ResetDbPassword: FC<any> = () => {
|
||||
} else {
|
||||
ui.setNotification({ category: 'error', message: 'Failed to reset password' })
|
||||
}
|
||||
setIsUpdatingPassword(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,9 +280,6 @@ const DownloadCertificate: FC<any> = ({ createdAt }) => {
|
||||
}
|
||||
|
||||
const GeneralSettings: FC<any> = ({ projectRef }) => {
|
||||
const { ui } = useStore()
|
||||
const isOwner = ui.selectedOrganization?.is_owner
|
||||
|
||||
const { data, error }: any = useSWR(`${API_URL}/props/project/${projectRef}/settings`, get)
|
||||
|
||||
if (data?.error || error) {
|
||||
@@ -378,7 +376,7 @@ const GeneralSettings: FC<any> = ({ projectRef }) => {
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
</section>
|
||||
{isOwner && <ResetDbPassword />}
|
||||
<ResetDbPassword />
|
||||
<DownloadCertificate createdAt={connectionInfo.inserted_at} />
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -12,11 +12,13 @@ import {
|
||||
} from '@supabase/ui'
|
||||
import SVG from 'react-inlinesvg'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { API_URL } from 'lib/constants'
|
||||
import { useStore, withAuth } from 'hooks'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { Project } from 'types'
|
||||
import { isUndefined } from 'lodash'
|
||||
|
||||
const DEFAULT = {
|
||||
category: {
|
||||
@@ -49,6 +51,9 @@ function formReducer(state: any, action: any) {
|
||||
|
||||
const SupportNew = () => {
|
||||
const { ui, app } = useStore()
|
||||
const router = useRouter()
|
||||
const projectRef = router.query.ref
|
||||
|
||||
const [formState, formDispatch] = useReducer(formReducer, DEFAULT)
|
||||
const [errors, setErrors] = useState<any>([])
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
@@ -72,7 +77,12 @@ const SupportNew = () => {
|
||||
useEffect(() => {
|
||||
// set project default
|
||||
if (sortedProjects.length > 1) {
|
||||
handleOnChange({ name: 'project', value: sortedProjects[0].ref })
|
||||
const selectedProject = sortedProjects.find((project: Project) => project.ref === projectRef)
|
||||
if (!isUndefined(selectedProject)) {
|
||||
handleOnChange({ name: 'project', value: selectedProject.ref })
|
||||
} else {
|
||||
handleOnChange({ name: 'project', value: sortedProjects[0].ref })
|
||||
}
|
||||
} else {
|
||||
// set as 'No specific project'
|
||||
handleOnChange({ name: 'project', value: projectDefaults[0].ref })
|
||||
|
||||
@@ -226,7 +226,7 @@ const Connecting = () => (
|
||||
const ProjectLinksEmptyState = () => (
|
||||
<div className="flex flex-col space-y-4">
|
||||
<Typography.Text>
|
||||
You haven’t created a Supabase project yet. Get started by creating a new Supabase project,
|
||||
You haven't created a Supabase project yet. Get started by creating a new Supabase project,
|
||||
then close this window and retry adding integration.
|
||||
</Typography.Text>
|
||||
<Typography.Link href="https://app.supabase.io">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { values } from 'mobx'
|
||||
import { Project } from 'types'
|
||||
import { Organization, Project } from 'types'
|
||||
|
||||
import { API_URL, STRIPE_PRODUCT_IDS } from 'lib/constants'
|
||||
import { IRootStore } from '../RootStore'
|
||||
@@ -71,19 +71,23 @@ export default class AppStore implements IAppStore {
|
||||
}
|
||||
}
|
||||
|
||||
onOrgUpdated(org: any) {
|
||||
if (org && org.id) {
|
||||
this.organizations.data[org.id] = { ...org }
|
||||
onOrgUpdated(updatedOrg: Organization) {
|
||||
if (updatedOrg && updatedOrg.id) {
|
||||
const originalOrg = this.organizations.data[updatedOrg.id]
|
||||
this.organizations.data[updatedOrg.id] = {
|
||||
...originalOrg,
|
||||
...updatedOrg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onOrgAdded(org: any) {
|
||||
onOrgAdded(org: Organization) {
|
||||
if (org && org.id) {
|
||||
this.organizations.data[org.id] = { ...org }
|
||||
this.organizations.data[org.id] = org
|
||||
}
|
||||
}
|
||||
|
||||
onOrgDeleted(org: any) {
|
||||
onOrgDeleted(org: Organization) {
|
||||
if (org && org.id) {
|
||||
const projects = values(this.projects.data)
|
||||
// cleanup projects saved queries
|
||||
|
||||
@@ -4,9 +4,13 @@ export interface Organization {
|
||||
name: string
|
||||
billing_email: string
|
||||
project_limit: number
|
||||
stripe_customer_id?: string
|
||||
total_free_projects?: number
|
||||
members: any[]
|
||||
projects: any[]
|
||||
is_owner?: boolean
|
||||
stripe_customer_id?: string
|
||||
stripe_customer_object?: any
|
||||
total_free_projects?: number
|
||||
total_paid_projects?: number
|
||||
}
|
||||
|
||||
export interface Project {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
process.env.SUPABASE_URL = 'http://localhost:8000'
|
||||
process.env.SUPABASE_KEY_ANON =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYyNzIwODU0MCwiZXhwIjoxOTc0MzYzNzQwfQ.zcaQfHd3VA7XgJmdGfmV86OLVJT9s2MTmSy-e69BpUY'
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE'
|
||||
process.env.SUPABASE_KEY_ADMIN =
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaWF0IjoxNjI3MjA4NTQwLCJleHAiOjE5NzQzNjM3NDB9.pkT3PNpO4DtO45Ac5HK_TKCx8sGLgNtV__pr_ZrRSAU'
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q'
|
||||
@@ -133,9 +133,7 @@ Migrating projects can be achieved using standard PostgreSQL tooling. This is pa
|
||||
|
||||
When you create a new project in Supabase we ask for a password. You can use this password to connect directly to your Postgres database.
|
||||
|
||||
If you forget your password, you can reset it from the Dashboard SQL editor:
|
||||
|
||||
For example:
|
||||
If you forget your password, you can reset it from the Dashboard under the database settings page, or through the SQL editor as such:
|
||||
|
||||
```sql
|
||||
alter user postgres
|
||||
|
||||
@@ -716,6 +716,48 @@ pages:
|
||||
console.log(event, session)
|
||||
})
|
||||
```
|
||||
- name: Listen to sign in
|
||||
js: |
|
||||
```js
|
||||
supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (event == 'SIGNED_IN') console.log('SIGNED_IN', session)
|
||||
})
|
||||
```
|
||||
- name: Listen to sign out
|
||||
js: |
|
||||
```js
|
||||
supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (event == 'SIGNED_OUT') console.log('SIGNED_OUT', session)
|
||||
})
|
||||
```
|
||||
- name: Listen to token refresh
|
||||
js: |
|
||||
```js
|
||||
supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (event == 'TOKEN_REFRESHED') console.log('TOKEN_REFRESHED', session)
|
||||
})
|
||||
```
|
||||
- name: Listen to user updates
|
||||
js: |
|
||||
```js
|
||||
supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (event == 'USER_UPDATED') console.log('USER_UPDATED', session)
|
||||
})
|
||||
```
|
||||
- name: Listen to user deleted
|
||||
js: |
|
||||
```js
|
||||
supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (event == 'USER_DELETED') console.log('USER_DELETED', session)
|
||||
})
|
||||
```
|
||||
- name: Listen to password recovery events
|
||||
js: |
|
||||
```js
|
||||
supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (event == 'PASSWORD_RECOVERY') console.log('PASSWORD_RECOVERY', session)
|
||||
})
|
||||
```
|
||||
auth.api.getUser():
|
||||
title: 'getUser()'
|
||||
$ref: '@supabase/gotrue-js.GoTrueApi.getUser'
|
||||
|
||||
+14
-10
@@ -3,21 +3,23 @@ var axios = require('axios')
|
||||
var fs = require('fs')
|
||||
|
||||
const query = `
|
||||
query BIO_QUERY($username: String!) {
|
||||
organization(login: $username) {
|
||||
query Sponsors {
|
||||
organization(login: "supabase") {
|
||||
id
|
||||
sponsorshipsAsMaintainer(first: 100) {
|
||||
totalCount
|
||||
sponsors(first: 100) {
|
||||
nodes {
|
||||
createdAt
|
||||
privacyLevel
|
||||
tier {
|
||||
name
|
||||
... on Organization {
|
||||
id
|
||||
createdAt
|
||||
name : login
|
||||
}
|
||||
sponsor {
|
||||
... on User {
|
||||
id
|
||||
createdAt
|
||||
login
|
||||
}
|
||||
}
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,10 +41,11 @@ const fetchAllSponsors = async () => {
|
||||
},
|
||||
}
|
||||
)
|
||||
return data.data.organization.sponsorshipsAsMaintainer
|
||||
return data.data.organization.sponsors
|
||||
}
|
||||
|
||||
const formatResults = (graphqlResponse) => {
|
||||
console.log('graph', graphqlResponse)
|
||||
return graphqlResponse.nodes
|
||||
.filter((x) => !!x.sponsor)
|
||||
.map((x) => ({
|
||||
@@ -65,6 +68,7 @@ const writeFile = (data) => {
|
||||
|
||||
const main = async () => {
|
||||
const sponsorsResponse = await fetchAllSponsors()
|
||||
// console.log('sponsorsResponse.totalCount', sponsorsResponse.totalCount)
|
||||
const formatted = formatResults(sponsorsResponse)
|
||||
writeFile(formatted)
|
||||
}
|
||||
|
||||
@@ -199,4 +199,4 @@
|
||||
"tier": "$49 a month",
|
||||
"sponsor": "CryptoJobsList"
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -253,7 +253,7 @@ const Nav = (props: Props) => {
|
||||
<a href="https://app.supabase.io/">
|
||||
<Button type="default">Sign in</Button>
|
||||
</a>
|
||||
<a href="https://app.supabase.io/">
|
||||
<a href="https://app.supabase.io/new/project">
|
||||
<Button>Start your project</Button>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
},
|
||||
{
|
||||
"question": "Is there a cap on the number of projects for the Free Tier?",
|
||||
"answer": "Yes, on the Free Tier you can have a maximum of two organizations, each with up to two projects. This means that you can have a maximum of four free projects in your account."
|
||||
"answer": "Yes, you have can up to 2 free projects in your account across all organizations that you own. You also are able to create as many organizations as you want."
|
||||
},
|
||||
{
|
||||
"question": "When will I be billed?",
|
||||
|
||||
Reference in new issue
Block a user