mirror of
https://github.com/supabase/supabase.git
synced 2026-10-18 07:39:07 +03:00
85 files changed
+3807
-5947
No files matched your search
@@ -181,6 +181,7 @@ Our approach for client libraries is modular. Each sub-library is a standalone i
|
||||
|
||||
- [Arabic | العربية](/i18n/README.ar.md)
|
||||
- [Albanian / Shqip](/i18n/README.sq.md)
|
||||
- [Bangla / বাংলা](/i18n/README.bn.md)
|
||||
- [Catalan / Català](/i18n/README.ca.md)
|
||||
- [Danish / Dansk](/i18n/README.da.md)
|
||||
- [Dutch / Nederlands](/i18n/README.nl.md)
|
||||
@@ -213,7 +214,6 @@ Our approach for client libraries is modular. Each sub-library is a standalone i
|
||||
- [Turkish / Türkçe](/i18n/README.tr.md)
|
||||
- [Ukrainian / Українська](/i18n/README.uk.md)
|
||||
- [Vietnamese / Tiếng Việt](/i18n/README.vi-vn.md)
|
||||
- [Bangla / বাংলা](/i18n/README.bn.md)
|
||||
- [List of translations](/i18n/languages.md) <!--- Keep only this -->
|
||||
|
||||
---
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
node_modules
|
||||
build
|
||||
.docusaurus
|
||||
docs/client
|
||||
docs/gotrue/client
|
||||
docs/postgrest/client
|
||||
docs/realtime/client
|
||||
docs/reference
|
||||
@@ -1,268 +0,0 @@
|
||||
/**
|
||||
* Usage:
|
||||
* ts-node ReferenceGenerator.ts -o {output_dir} {input}.yml
|
||||
*
|
||||
* Example:
|
||||
* ts-node ReferenceGenerator.ts -o docs/client spec/supabase.yml
|
||||
*/
|
||||
|
||||
import Example from './spec/gen/components/Example'
|
||||
import Page from './spec/gen/components/Page'
|
||||
import Sidebar from './spec/gen/components/Sidebar'
|
||||
import SidebarCategory from './spec/gen/components/SidebarCategory'
|
||||
import Tab from './spec/gen/components/Tab'
|
||||
import Tabs from './spec/gen/components/Tabs'
|
||||
import { slugify, tsDocCommentToMdComment, writeToDisk } from './spec/gen/lib/helpers'
|
||||
import { TsDoc, OpenRef } from './spec/gen/definitions'
|
||||
|
||||
const yaml = require('js-yaml')
|
||||
const fs = require('fs')
|
||||
|
||||
const main = (fileNames, options) => {
|
||||
try {
|
||||
const outputDir = options.o || options.output || ''
|
||||
fileNames.forEach((inputFileName) => {
|
||||
gen(inputFileName, outputDir)
|
||||
})
|
||||
return
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
async function gen(inputFileName, outputDir) {
|
||||
const docSpec = yaml.safeLoad(fs.readFileSync(inputFileName, 'utf8'))
|
||||
const defRef = fs.readFileSync(docSpec.info.definition, 'utf8')
|
||||
if (!defRef) return
|
||||
|
||||
const definition = JSON.parse(defRef)
|
||||
const id = docSpec.info.id
|
||||
const allLanguages = docSpec.info.libraries
|
||||
const pages = Object.entries(docSpec.pages).map(([name, x]: [string, OpenRef.Page]) => ({
|
||||
...x,
|
||||
pageName: name,
|
||||
}))
|
||||
|
||||
// Sidebar
|
||||
const inputFileNameToSnakeCase = inputFileName.replace('/', '_').replace('.yml', '')
|
||||
const sidebarFileName = `sidebar_${inputFileNameToSnakeCase}.js`
|
||||
const sidebar = generateSidebar(docSpec)
|
||||
await writeToDisk(sidebarFileName, sidebar)
|
||||
console.log('Sidebar created: ', sidebarFileName)
|
||||
|
||||
// Index Page
|
||||
const indexFilename = outputDir + `/index.mdx`
|
||||
const index = generateDocsIndexPage(docSpec, inputFileName)
|
||||
await writeToDisk(indexFilename, index)
|
||||
console.log('The index was saved: ', indexFilename)
|
||||
|
||||
// Generate Pages
|
||||
pages.forEach(async (pageSpec: OpenRef.Page) => {
|
||||
try {
|
||||
const slug = slugify(pageSpec.pageName)
|
||||
const hasTsRef = pageSpec['$ref'] || null
|
||||
const tsDefinition = hasTsRef && extractTsDocNode(hasTsRef, definition)
|
||||
if (hasTsRef && !tsDefinition) throw new Error('Definition not found: ' + hasTsRef)
|
||||
|
||||
const description =
|
||||
pageSpec.description || tsDocCommentToMdComment(getDescriptionFromDefintion(tsDefinition))
|
||||
|
||||
// Create page
|
||||
const content = Page({
|
||||
slug,
|
||||
id: slug,
|
||||
specFileName: inputFileName,
|
||||
title: pageSpec.title || pageSpec.pageName,
|
||||
description,
|
||||
parameters: hasTsRef ? generateParameters(tsDefinition) : '',
|
||||
spotlight: generateSpotlight(id, pageSpec['examples'] || [], allLanguages),
|
||||
examples: generateExamples(id, pageSpec['examples'] || [], allLanguages),
|
||||
notes: pageSpec.notes,
|
||||
})
|
||||
|
||||
// Write to disk
|
||||
const dest = outputDir + `/${slug}.mdx`
|
||||
await writeToDisk(dest, content)
|
||||
console.log('Saved: ', dest)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function generateParameters(tsDefinition: any) {
|
||||
let functionDeclaration = null
|
||||
if (tsDefinition.kindString == 'Method') {
|
||||
functionDeclaration = tsDefinition
|
||||
} else if (tsDefinition.kindString == 'Constructor') {
|
||||
functionDeclaration = tsDefinition
|
||||
} else functionDeclaration = tsDefinition?.type?.declaration
|
||||
if (!functionDeclaration) return ''
|
||||
|
||||
const paramDefinitions: TsDoc.TypeDefinition[] = functionDeclaration.signatures[0].parameters // PMC: seems flaky.. why the [0]?
|
||||
if (!paramDefinitions) return ''
|
||||
|
||||
// const paramsComments: TsDoc.CommentTag = tsDefinition.comment?.tags?.filter(x => x.tag == 'param')
|
||||
let parameters = paramDefinitions.map((x) => recurseThroughParams(x)).join(`\n`)
|
||||
return methodListGroup(parameters)
|
||||
}
|
||||
|
||||
function getDescriptionFromDefintion(tsDefinition) {
|
||||
if (!tsDefinition) return null
|
||||
if (['Method', 'Constructor', 'Constructor signature'].includes(tsDefinition.kindString))
|
||||
return tsDefinition?.signatures[0].comment
|
||||
else return tsDefinition?.comment || ''
|
||||
}
|
||||
|
||||
function recurseThroughParams(paramDefinition: TsDoc.TypeDefinition) {
|
||||
let children = paramDefinition.type?.declaration?.children
|
||||
const labelParams = {
|
||||
name: paramDefinition.name,
|
||||
isOptional: !!paramDefinition.flags.isOptional,
|
||||
type: extractParamTypeAsString(paramDefinition),
|
||||
description: paramDefinition.comment ? tsDocCommentToMdComment(paramDefinition.comment) : null,
|
||||
}
|
||||
let subContent = ''
|
||||
|
||||
if (!!children) {
|
||||
let properties = children
|
||||
.sort((a, b) => a.name.localeCompare(b.name)) // first alphabetical
|
||||
.sort((a, b) => (a.flags?.isOptional ? 1 : -1)) // required params first
|
||||
.map((x) => recurseThroughParams(x))
|
||||
let heading = `<h5 class="method-list-title method-list-title-isChild expanded">Properties</h5>`
|
||||
subContent = methodListGroup([heading].concat(properties).join('\n'))
|
||||
}
|
||||
|
||||
return methodListItemLabel(labelParams, subContent)
|
||||
}
|
||||
|
||||
const methodListGroup = (items) => `
|
||||
<ul className="method-list-group">
|
||||
${items}
|
||||
</ul>
|
||||
`
|
||||
|
||||
const methodListItemLabel = ({ name, isOptional, type, description }, subContent) => `
|
||||
<li className="method-list-item">
|
||||
<h4 className="method-list-item-label">
|
||||
<span className="method-list-item-label-name">
|
||||
${name}
|
||||
</span>
|
||||
<span className="method-list-item-label-badge ${!isOptional && 'required'}">
|
||||
${isOptional ? 'optional' : 'required'}
|
||||
</span>
|
||||
<span className="method-list-item-validation">
|
||||
${type}
|
||||
</span>
|
||||
</h4>
|
||||
<div class="method-list-item-description">
|
||||
|
||||
${description ? description : 'No description provided. '}
|
||||
|
||||
</div>
|
||||
${subContent}
|
||||
</li>
|
||||
`
|
||||
|
||||
function generateExamples(id: string, specExamples: any, allLanguages: any) {
|
||||
return specExamples.map((example) => {
|
||||
let allTabs = example.hideCodeBlock
|
||||
? ''
|
||||
: Tabs(id, allLanguages, generateTabs(allLanguages, example))
|
||||
return Example({ name: example.name, description: example.description, tabs: allTabs })
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* A spotlight is an example which appears at the top of the page.
|
||||
*/
|
||||
function generateSpotlight(id: string, specExamples: any, allLanguages: any) {
|
||||
const spotlight = specExamples.find((x) => x.isSpotlight) || null
|
||||
const spotlightContent = !spotlight
|
||||
? ''
|
||||
: Tabs(id, allLanguages, generateTabs(allLanguages, spotlight))
|
||||
return spotlightContent
|
||||
}
|
||||
|
||||
function generateTabs(allLanguages: any, example: any) {
|
||||
return allLanguages
|
||||
.map((library) => {
|
||||
let content = example[library.id] || notImplemented
|
||||
return Tab(library.id, content)
|
||||
})
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
const notImplemented = `
|
||||
\`\`\`
|
||||
Not yet implemented
|
||||
\`\`\`
|
||||
`
|
||||
|
||||
function extractParamTypeAsString(paramDefinition) {
|
||||
if (paramDefinition.type?.name) {
|
||||
return `<code>${paramDefinition.type.name}</code>`
|
||||
}
|
||||
if (paramDefinition.type?.type == 'union') {
|
||||
return paramDefinition.type.types
|
||||
.map((x) =>
|
||||
x.value
|
||||
? `<code>${x.value}</code>`
|
||||
: x.name
|
||||
? `<code>${x.name}</code>`
|
||||
: x.type
|
||||
? `<code>${x.type}</code>`
|
||||
: ''
|
||||
)
|
||||
.join(' | ')
|
||||
} else {
|
||||
return '<code>object</code>'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the definition to find the correct definition.
|
||||
* You can pass it a deeply nested node using dot notation. eg: 'LoggedInUser.data.email'
|
||||
*/
|
||||
function extractTsDocNode(nodeToFind: string, definition: any) {
|
||||
const nodePath = nodeToFind.split('.')
|
||||
let i = 0
|
||||
let previousNode = definition
|
||||
let currentNode = definition
|
||||
while (i < nodePath.length) {
|
||||
previousNode = currentNode
|
||||
currentNode = previousNode.children.find((x) => x.name == nodePath[i]) || null
|
||||
if (currentNode == null) {
|
||||
console.log(`Cant find ${nodePath[i]} in ${previousNode.children.map((x) => '\n' + x.name)}`)
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
return currentNode
|
||||
}
|
||||
|
||||
function generateSidebar(docSpec: any) {
|
||||
let path = docSpec.info.docs.path || ''
|
||||
let categories = docSpec.info.docs.sidebar.map((x) => {
|
||||
const items = x.items.map((item) => {
|
||||
let slug = slugify(item)
|
||||
return `'${path}${slug}'`
|
||||
})
|
||||
return SidebarCategory(x.name, items)
|
||||
})
|
||||
return Sidebar(categories)
|
||||
}
|
||||
|
||||
function generateDocsIndexPage(docSpec: any, inputFileName: string) {
|
||||
return Page({
|
||||
slug: slugify(docSpec.info.title),
|
||||
id: 'index',
|
||||
title: docSpec.info.title,
|
||||
specFileName: inputFileName,
|
||||
description: docSpec.info.description,
|
||||
})
|
||||
}
|
||||
|
||||
// Run everything
|
||||
const argv = require('minimist')(process.argv.slice(2))
|
||||
main(argv['_'], argv)
|
||||
+11
-11
@@ -4,28 +4,28 @@ title: Work at Supabase
|
||||
description: We're hiring. Start your career at Supabase.
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## Roles
|
||||
## Roles
|
||||
|
||||
<Roles/>
|
||||
<Roles />
|
||||
|
||||
## About Supabase
|
||||
|
||||
<About/>
|
||||
<About />
|
||||
|
||||
## About the team
|
||||
|
||||
<Team/>
|
||||
<Team />
|
||||
|
||||
## Apply
|
||||
|
||||
<Apply/>
|
||||
<Apply />
|
||||
|
||||
## Process
|
||||
|
||||
<Process/>
|
||||
<Process />
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -5,11 +5,11 @@ title: Auth Engineers.
|
||||
description: Supabase is hiring Auth Engineers
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
|
||||
@@ -5,20 +5,20 @@ title: Data Engineers.
|
||||
description: Supabase is hiring Data Engineers
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
- Be the business intelligence star player at Supabase by helping dig deep into the data we are generating. Deep knowledge of SQL and relevant tooling is a must.
|
||||
- Help customer success & sales team by working to identify and monitor:
|
||||
- Usage Insights
|
||||
- Find and segment cohorts based around account level data, behavior, traffic sources, and measure their subsequent behaviors
|
||||
- Find and monitor product qualified leads based around account and behavior characteristics
|
||||
- Customer health segmentation into actionable cohorts (e.g. healthy, churn, at risk)
|
||||
- Usage Insights
|
||||
- Find and segment cohorts based around account level data, behavior, traffic sources, and measure their subsequent behaviors
|
||||
- Find and monitor product qualified leads based around account and behavior characteristics
|
||||
- Customer health segmentation into actionable cohorts (e.g. healthy, churn, at risk)
|
||||
- Help identify opportunities high touch, low touch, & tech touch customer success & sales approaches
|
||||
- Help sales & customer success identify opportunity for unscheduled outreach
|
||||
- Working with internal tooling team to identify and implement solutions for growth, sales, customer success teams needs
|
||||
|
||||
@@ -5,12 +5,11 @@ title: Developer Advocate (US Timezone).
|
||||
description: Supabase is hiring Developer Advocates and Community Managers
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
|
||||
@@ -5,12 +5,11 @@ title: Developer Success Engineer
|
||||
description: Supabase is hiring Developer Success Engineers
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
@@ -26,20 +25,18 @@ Supabase is hiring Developer Success Engineers. Help us build the easiest databa
|
||||
- Triage/clean/close issues on any of our repos.
|
||||
- Work with the community on all of our channels: GitHub, Discord, and Email.
|
||||
|
||||
## About you
|
||||
## About you
|
||||
|
||||
- 2+ years experience in engineering or a highly technical support role.
|
||||
- You must love remote work.
|
||||
- You possess exceptional communication skills.
|
||||
- Availability to work within a weekend and on-call rota.
|
||||
|
||||
|
||||
## Bonus if you:
|
||||
|
||||
- Are a Polyglot developer, with some skill in NodeJS/Javascript.
|
||||
- Have PostgreSQL experience.
|
||||
|
||||
|
||||
## About Supabase
|
||||
|
||||
<About />{' '}
|
||||
|
||||
@@ -5,12 +5,11 @@ title: Ex-Founders.
|
||||
description: Supabase is hiring ex-Founders
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ title: Front End Developers
|
||||
description: Supabase is hiring Front End Developers
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
|
||||
@@ -5,12 +5,11 @@ title: Full Stack Developers.
|
||||
description: Supabase is hiring Full Stack Developers
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ title: Graphic / Web Designers
|
||||
description: Supabase is hiring Designers
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ title: Growth Marketer.
|
||||
description: Supabase is hiring a Growth Marketer
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
@@ -35,7 +35,7 @@ The ideal candidate has experience helping grow products which enable developers
|
||||
- Help running email campaigns
|
||||
- Community management
|
||||
|
||||
## Skills and Experience
|
||||
## Skills and Experience
|
||||
|
||||
- Building marketing funnels and running outbound campaigns
|
||||
- Creating and managing social media campaigns
|
||||
|
||||
@@ -5,12 +5,11 @@ title: Postgres Experts.
|
||||
description: Supabase is hiring Postgres Experts
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
|
||||
@@ -5,12 +5,11 @@ title: Cloud Platform Engineers and SREs.
|
||||
description: Supabase is hiring Cloud Platform Engineers and SREs
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ title: Support Engineers.
|
||||
description: Supabase is hiring Support Engineers
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
@@ -35,7 +35,6 @@ For the right candidate, additional responsibilities may include:
|
||||
- Familiar with popular JavaScript frameworks (React, Vue, Svelte) and Node.js.
|
||||
- Experience working with GitHub source code management, and CI/CD tools.
|
||||
|
||||
|
||||
## Nice to have
|
||||
|
||||
- Experience writing tests
|
||||
@@ -47,7 +46,7 @@ For the right candidate, additional responsibilities may include:
|
||||
|
||||
## Four day work week
|
||||
|
||||
This role is optionally a four-day workweek if you are interested in working from Friday to Monday. We can also discuss a shorter (pro-rated) week.
|
||||
This role is optionally a four-day workweek if you are interested in working from Friday to Monday. We can also discuss a shorter (pro-rated) week.
|
||||
In particular we would like to hire people who would be willing to work on weekends (or at least one of the days (Saturday or Sunday).
|
||||
|
||||
## About Supabase
|
||||
|
||||
@@ -5,11 +5,11 @@ title: Technical Recruiter
|
||||
description: Supabase is hiring Technical Recruiters
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
@@ -38,7 +38,6 @@ import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
- You're Comfortable coordinating all candidate touch points
|
||||
- You can plan out batch days & other projects to drive excellence for our candidate experience and quality of interviews
|
||||
|
||||
|
||||
## About Supabase
|
||||
|
||||
<About />{' '}
|
||||
|
||||
@@ -5,11 +5,11 @@ title: Technical Writers.
|
||||
description: Supabase is hiring Technical Writers
|
||||
---
|
||||
|
||||
import Roles from '@site/docs/careers/snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/snippets/process.mdx'
|
||||
import Roles from '@site/docs/careers/_snippets/roles.mdx'
|
||||
import About from '@site/docs/careers/_snippets/about.mdx'
|
||||
import Team from '@site/docs/careers/_snippets/team.mdx'
|
||||
import Apply from '@site/docs/careers/_snippets/apply.mdx'
|
||||
import Process from '@site/docs/careers/_snippets/process.mdx'
|
||||
|
||||
## About the role
|
||||
|
||||
@@ -19,16 +19,16 @@ Do you have experience building for the web?
|
||||
|
||||
Are you an engaging writer with an eye for detail?
|
||||
|
||||
Responsibilities includes:
|
||||
Responsibilities includes:
|
||||
|
||||
- Blog posts for the Supabase website
|
||||
- Helping other team members communicate their wins with edits and suggestions
|
||||
- Writing internal docs such as: documenting processes, how-to guides etc.
|
||||
- Writing and Organizing our documentation, and generally setting the direction on how they are structured
|
||||
- Writing and Organizing our documentation, and generally setting the direction on how they are structured
|
||||
- Helping with enterprise orientated marketing collateral: thought leadership, white papers, case studies
|
||||
- Working directly with the Founders, Growth, and Dev Rel teams on strategy
|
||||
|
||||
Must Have:
|
||||
Must Have:
|
||||
|
||||
- Intermediate understanding of Postgres
|
||||
- Full stack development experience
|
||||
@@ -38,7 +38,7 @@ Must Have:
|
||||
|
||||
Nice to Have:
|
||||
|
||||
- Understanding of SEO
|
||||
- Understanding of SEO
|
||||
- Previous experience with SaaS content marketing
|
||||
|
||||
## About Supabase
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
module.exports = {
|
||||
title: 'Supabase',
|
||||
tagline: 'Build in a weekend. Scale to millions.',
|
||||
@@ -169,7 +163,6 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
],
|
||||
scripts: [{ src: '/scripts/telemetry.js' }],
|
||||
plugins: [
|
||||
// [
|
||||
// '@docusaurus/plugin-content-docs',
|
||||
|
||||
Generated
+3
-3
@@ -13308,9 +13308,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
"version": "0.7.22",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz",
|
||||
"integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q=="
|
||||
"version": "0.7.31",
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
|
||||
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ=="
|
||||
},
|
||||
"unherit": {
|
||||
"version": "1.1.3",
|
||||
|
||||
+1
-12
@@ -1,11 +1,3 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
|
||||
module.exports = {
|
||||
docs: [
|
||||
{
|
||||
@@ -18,10 +10,7 @@ module.exports = {
|
||||
type: 'category',
|
||||
label: 'See Also',
|
||||
collapsed: false,
|
||||
items: [
|
||||
'handbook/contributing',
|
||||
'handbook/supasquad',
|
||||
],
|
||||
items: ['handbook/contributing', 'handbook/supasquad'],
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
require('dotenv').config()
|
||||
var axios = require('axios')
|
||||
var fs = require('fs')
|
||||
|
||||
const query = `
|
||||
query BIO_QUERY($username: String!) {
|
||||
organization(login: $username) {
|
||||
id
|
||||
sponsorshipsAsMaintainer(first: 100) {
|
||||
totalCount
|
||||
nodes {
|
||||
createdAt
|
||||
privacyLevel
|
||||
tier {
|
||||
name
|
||||
}
|
||||
sponsor {
|
||||
login
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const fetchAllSponsors = async () => {
|
||||
const { data } = await axios.post(
|
||||
`https://api.github.com/graphql`,
|
||||
{
|
||||
query,
|
||||
variables: {
|
||||
username: 'supabase',
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `token ${process.env.GITHUB_SPONSORS_TOKEN}`,
|
||||
},
|
||||
}
|
||||
)
|
||||
return data.data.organization.sponsorshipsAsMaintainer
|
||||
}
|
||||
|
||||
const formatResults = (graphqlResponse) => {
|
||||
return graphqlResponse.nodes
|
||||
.filter((x) => !!x.sponsor)
|
||||
.map((x) => ({
|
||||
tier: x.tier.name,
|
||||
sponsor: x.sponsor.login,
|
||||
}))
|
||||
}
|
||||
|
||||
const writeFile = (data) => {
|
||||
fs.writeFile(
|
||||
'./src/data/sponsors.json',
|
||||
JSON.stringify(data, null, 2),
|
||||
'utf8',
|
||||
function (err) {
|
||||
if (err) throw err
|
||||
console.log('sponsors.json saved.')
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const main = async () => {
|
||||
const sponsorsResponse = await fetchAllSponsors()
|
||||
const formatted = formatResults(sponsorsResponse)
|
||||
writeFile(formatted)
|
||||
}
|
||||
main()
|
||||
@@ -1,10 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function Collapsable({ title, children }) {
|
||||
return (
|
||||
<details className="Collapsable">
|
||||
<summary>{title}</summary>
|
||||
<div>{children}</div>
|
||||
</details>
|
||||
)
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import CodeBlock from '@theme/CodeBlock'
|
||||
|
||||
export default function CustomCodeBlock({
|
||||
header,
|
||||
code,
|
||||
highlight,
|
||||
js,
|
||||
jsHighlight,
|
||||
response,
|
||||
language,
|
||||
}) {
|
||||
const [showResponse, toggleResponse] = useState(false)
|
||||
|
||||
let wrapperClass = ''
|
||||
if (header) wrapperClass += ' code-with-header'
|
||||
if (response) wrapperClass += ' code-with-response'
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={wrapperClass}>
|
||||
{header && <div className="code-header">{header}</div>}
|
||||
<>
|
||||
{code && (
|
||||
<CodeBlock className={language || 'bash'} metastring={highlight}>
|
||||
{code}
|
||||
</CodeBlock>
|
||||
)}
|
||||
{js && <CodeBlock metastring={jsHighlight}>{js}</CodeBlock>}
|
||||
</>
|
||||
</div>
|
||||
{response && (
|
||||
<>
|
||||
<div className={'code-with-header repsonse-header'}>
|
||||
<a
|
||||
className="code-header has-hover-pointer"
|
||||
style={showResponse ? styles.responseShown : styles.responseHidden}
|
||||
onClick={() => toggleResponse(!showResponse)}
|
||||
>
|
||||
{showResponse ? 'Hide' : 'Show'} Response
|
||||
</a>
|
||||
{showResponse && <CodeBlock>{response}</CodeBlock>}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = {
|
||||
responseShown: {
|
||||
textAlign: 'right',
|
||||
display: 'block',
|
||||
borderRadius: '0',
|
||||
color: 'var(--custom-primary)',
|
||||
borderTop: '1px solid #444',
|
||||
},
|
||||
responseHidden: {
|
||||
textAlign: 'right',
|
||||
display: 'block',
|
||||
borderBottom: 'none',
|
||||
borderRadius: '0 0 4px 4px',
|
||||
borderTop: '1px solid #444',
|
||||
color: '#ccc',
|
||||
},
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import extensions from '../data/extensions.json'
|
||||
|
||||
export default function Extensions() {
|
||||
const [filter, setFilter] = useState('')
|
||||
return (
|
||||
<>
|
||||
<div style={styles.inputContainer}>
|
||||
<input
|
||||
type="text"
|
||||
style={styles.input}
|
||||
placeholder="Filter"
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="row" style={styles.row}>
|
||||
{extensions
|
||||
.filter((x) => x.name.indexOf(filter) >= 0)
|
||||
.map((extension) => (
|
||||
<div className={'col col--6'} key={extension.name} style={styles.column}>
|
||||
<div style={styles.card}>
|
||||
<h3>
|
||||
<code style={styles.title}>{extension.name}</code>
|
||||
</h3>
|
||||
<p style={styles.description}>
|
||||
{extension.comment.charAt(0).toUpperCase() + extension.comment.slice(1)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = {
|
||||
inputContainer: {
|
||||
marginBottom: '15px',
|
||||
},
|
||||
input: {
|
||||
border: '1px solid var(--ifm-panel-border-color)',
|
||||
borderRadius: 4,
|
||||
backgroundColor: 'var(--custom-background-color-diff)',
|
||||
color: 'var(--ifm-font-color-base)',
|
||||
margin: 0,
|
||||
padding: '6px 8px',
|
||||
width: 300,
|
||||
},
|
||||
column: {
|
||||
margin: '5px 0px',
|
||||
padding: '0px 5px',
|
||||
},
|
||||
card: {
|
||||
border: '1px solid var(--ifm-panel-border-color)',
|
||||
borderRadius: 5,
|
||||
padding: 8,
|
||||
},
|
||||
title: {
|
||||
margin: 0,
|
||||
fontSize: '0.9rem',
|
||||
border: '1px solid var(--ifm-panel-border-color)',
|
||||
},
|
||||
description: {
|
||||
fontSize: '0.8rem',
|
||||
margin: 0,
|
||||
},
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function Figure({ src, alt, caption }) {
|
||||
return (
|
||||
<div className="Figure">
|
||||
<figure>
|
||||
<img src={src} alt={alt} />
|
||||
<figcaption>{caption}</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function GithubCard({ title, description, href, stars, handle }) {
|
||||
return (
|
||||
<a className={'card'} href={href} style={{ height: '100%' }}>
|
||||
<div className="card__body">
|
||||
<h4 style={styles.h4} style={{ margin: 0 }}>
|
||||
{title.toUpperCase()}
|
||||
</h4>
|
||||
<small>{description}</small>
|
||||
</div>
|
||||
<hr style={styles.hr} />
|
||||
<div style={styles.cardBase}>
|
||||
<div>@{handle}</div>
|
||||
<div>{stars} ★</div>
|
||||
</div>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = {
|
||||
hr: {
|
||||
margin: '15px 0 10px 0',
|
||||
},
|
||||
h3: {
|
||||
margin: 0,
|
||||
textTransform: 'capitalize',
|
||||
},
|
||||
cardBase: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
padding: '0 15px 10px 15px',
|
||||
fontSize: '0.8em',
|
||||
},
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function HowCard({ title, description, featureTitle, features }) {
|
||||
return (
|
||||
<div className={'HowCard'}>
|
||||
<div className={'card'} style={styles.card}>
|
||||
<h4 style={styles.h4}>{title}</h4>
|
||||
<div className="card__body" style={styles.cardBase}>
|
||||
{description}
|
||||
<h5 style={styles.h5}>{featureTitle}</h5>
|
||||
<div style={styles.features}>
|
||||
{features.map((x, i) => (
|
||||
<div key={i}>
|
||||
<span>
|
||||
<img src="/img/check.svg" alt="✔" style={styles.check} />
|
||||
</span>
|
||||
<span>{x}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = {
|
||||
h4: {
|
||||
padding: 10,
|
||||
textAlign: 'center',
|
||||
borderBottom: '1px solid #000',
|
||||
margin: 0,
|
||||
},
|
||||
h5: {
|
||||
textTransform: 'uppercase',
|
||||
// opacity: 0.5,
|
||||
margin: '10px 0 0px 0',
|
||||
fontSize: '0.9em',
|
||||
},
|
||||
card: {
|
||||
border: '1px solid #000',
|
||||
boxShadow: 'none',
|
||||
},
|
||||
cardBase: {
|
||||
fontSize: '0.9em',
|
||||
},
|
||||
check: {
|
||||
width: 10,
|
||||
height: 10,
|
||||
marginRight: 10,
|
||||
},
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import mermaid from 'mermaid'
|
||||
|
||||
const theme = `
|
||||
.node rect { fill: rgba(62,207,142, 0.3); stroke: #24b47e; }
|
||||
.cluster rect { fill: var(--custom-background-color-highlight); stroke: #999; }
|
||||
.edgePath path { fill: var(--custom-primary) }
|
||||
.edgePath .path { stroke: var(--custom-primary) }
|
||||
|
||||
g.classGroup rect { fill: rgba(62,207,142, 0.3); stroke: #24b47e; }
|
||||
g.classGroup line { stroke: var(--custom-primary); }
|
||||
g.classGroup text { fill: var(--ifm-color-content); color: var(--ifm-color-content); }
|
||||
.classLabel .label { fill: var(--ifm-color-content); color: var(--ifm-color-content); }
|
||||
classGroup .title { fill: var(--ifm-color-content); color: var(--ifm-color-content); }
|
||||
composition { stroke: var(--custom-primary); }
|
||||
aggregation { stroke: var(--custom-primary); }
|
||||
dependency { stroke: var(--custom-primary); }
|
||||
.relation { stroke: var(--custom-primary); }
|
||||
`
|
||||
|
||||
mermaid.initialize({ themeCSS: theme })
|
||||
|
||||
export default function Mermaid({ graph, classNames, caption }) {
|
||||
let [rendered, setRendered] = useState(<div></div>)
|
||||
|
||||
useEffect(() => {
|
||||
mermaid.render('mermaid-ID', graph.toString(), (html) => setRendered(html))
|
||||
}, [graph])
|
||||
|
||||
return (
|
||||
<div className={`Mermaid ${classNames || ''}`}>
|
||||
{caption && <figcaption>{caption}</figcaption>}
|
||||
<div className="graph" dangerouslySetInnerHTML={{ __html: rendered }}></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
import React, { useRef, useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
export default function Section({ title, id, style, children }) {
|
||||
const hash = String(id ? id : title)
|
||||
.trim()
|
||||
.replace(/\s/g, '-')
|
||||
.toLowerCase()
|
||||
const sectionRef = useRef(null)
|
||||
|
||||
useEffect(() => {
|
||||
function scrollOnHash() {
|
||||
const clearedLocationHash = window.location.hash.substring(1)
|
||||
|
||||
if (clearedLocationHash == hash) {
|
||||
sectionRef.current.scrollIntoView({ behavior: 'smooth' })
|
||||
}
|
||||
}
|
||||
|
||||
function changeHash() {
|
||||
const el = document.getElementById(hash)
|
||||
|
||||
if (el) {
|
||||
const elementPos = el.getBoundingClientRect()
|
||||
|
||||
if (elementPos.top <= 80 && elementPos.top >= 0) replaceHistoryHash()
|
||||
}
|
||||
}
|
||||
scrollOnHash()
|
||||
window.addEventListener('scroll', changeHash)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('scroll', changeHash)
|
||||
}
|
||||
}, [])
|
||||
|
||||
function replaceHistoryHash() {
|
||||
history.replaceState(history.state, '', `#${hash}`)
|
||||
}
|
||||
|
||||
function handleHashClick() {
|
||||
replaceHistoryHash()
|
||||
sectionRef.current.scrollIntoView({ behavior: 'smooth' })
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="section-lg">
|
||||
<div className="container Section">
|
||||
<h2
|
||||
className={`${stylePropOptions[style]} Section-Title`}
|
||||
ref={sectionRef}
|
||||
onClick={handleHashClick}
|
||||
id={hash}
|
||||
>
|
||||
{title}
|
||||
<span className="Section-Hash">#</span>
|
||||
</h2>
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
const stylePropOptions = {
|
||||
underline: 'with-underline',
|
||||
}
|
||||
|
||||
Section.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
style: PropTypes.oneOf(['underline']),
|
||||
}
|
||||
+6
-293
@@ -33,9 +33,9 @@
|
||||
/*
|
||||
Customization here for both Light and Dark themes
|
||||
*/
|
||||
--custom-font-base: 'Inter', BlinkMacSystemFont, -apple-system, 'Segoe UI', 'Roboto',
|
||||
'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Helvetica',
|
||||
'Arial', sans-serif;
|
||||
--custom-font-base: 'Inter', BlinkMacSystemFont, -apple-system, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Helvetica', 'Arial',
|
||||
sans-serif;
|
||||
--custom-font-code: 'office code pro', Menlo, monospace;
|
||||
--custom-font-size-base: 1rem;
|
||||
--custom-border-radius: 3px;
|
||||
@@ -236,7 +236,9 @@ body {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
@@ -652,20 +654,6 @@ div[class^='sidebar_'] .menu__link.menu__link--active:not(.menu__link--sublist)
|
||||
}
|
||||
}
|
||||
|
||||
.DummyData {
|
||||
overflow-x: auto;
|
||||
}
|
||||
.DummyData div {
|
||||
padding-right: 30px;
|
||||
}
|
||||
.Collapsable summary {
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.Collapsable summary:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div[class^='codeBlockContent'],
|
||||
div[class*=' codeBlockContent'],
|
||||
.prism-code {
|
||||
@@ -804,49 +792,6 @@ a.hash-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.HowSections .col {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.HowSections img.diagram {
|
||||
margin: 0px auto 30px auto;
|
||||
display: block;
|
||||
}
|
||||
.HowCard {
|
||||
position: relative;
|
||||
}
|
||||
.HowCard::before,
|
||||
.HowCard::after {
|
||||
bottom: 100%;
|
||||
border: solid transparent;
|
||||
content: '';
|
||||
height: 0;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
.HowCard::before {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
|
||||
border-bottom: 5px solid black;
|
||||
border-width: 12px;
|
||||
margin-left: -12px;
|
||||
}
|
||||
.HowCard::after {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
|
||||
border-bottom: 5px solid var(--ifm-card-background-color);
|
||||
border-width: 11px;
|
||||
margin-left: -11px;
|
||||
}
|
||||
|
||||
.Blog .code-with-header {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
@@ -854,46 +799,6 @@ a.hash-link {
|
||||
color: var(--ifm-color-content);
|
||||
}
|
||||
|
||||
.Figure {
|
||||
text-align: center;
|
||||
margin: 30px 0;
|
||||
}
|
||||
.Figure figure {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
.Figure img {
|
||||
box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.Figure figcaption {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.Mermaid {
|
||||
text-align: center;
|
||||
margin: 80px 0;
|
||||
font-family: var(--custom-font-base);
|
||||
color: var(--ifm-color-content);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.Mermaid .graph {
|
||||
overflow-x: auto;
|
||||
margin: 0px calc(var(--ifm-spacing-horizontal) * -1);
|
||||
padding: var(--ifm-spacing-horizontal);
|
||||
}
|
||||
.Mermaid div,
|
||||
.Mermaid tspan,
|
||||
.Mermaid g.classGroup text {
|
||||
font-family: var(--custom-font-base);
|
||||
color: var(--ifm-color-content);
|
||||
/* font-size: 0.9em; */
|
||||
}
|
||||
.Mermaid figcaption {
|
||||
font-size: 0.8rem;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.DocSearch-Button {
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
@@ -1075,198 +980,6 @@ html[data-theme='dark'] .navbar-item-twitter:before {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Section */
|
||||
.Section {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.Section-Hash {
|
||||
margin-left: 8px;
|
||||
color: var(--custom-content-color-light);
|
||||
opacity: 0.4;
|
||||
}
|
||||
.Section-Title:hover .Section-Hash {
|
||||
color: var(--custom-primary);
|
||||
opacity: 1;
|
||||
}
|
||||
.Section-Title {
|
||||
cursor: pointer;
|
||||
scroll-margin: 74px; /* Navbar size (60) + a little margin */
|
||||
}
|
||||
|
||||
/* Showcase */
|
||||
.ShowcaseCard {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: none;
|
||||
border: 1px solid #333;
|
||||
padding: var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing);
|
||||
}
|
||||
|
||||
.ShowcaseCard:hover {
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid var(--custom-primary);
|
||||
box-shadow: var(--custom-shadow-xl), 0 0 0 1px var(--custom-primary) !important;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Img {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.ShowcaseCard-ImgContainer {
|
||||
height: 140px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Text {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Text p {
|
||||
width: 100%;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Text h3 {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
backdrop-filter: blur(3px) contrast(80%);
|
||||
padding: var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing);
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: var(--ifm-card-vertical-spacing);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ShowcaseCard:hover h3 {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Tag {
|
||||
color: var(--custom-primary);
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
margin: 8px 4px 12px 0px;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Footer-Item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Spaces between children */
|
||||
.ShowcaseCard-Footer-Spaced .ShowcaseCard-Footer-Item:first-child {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Footer-Spaced .ShowcaseCard-Footer-Item:nth-child(even) {
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Footer-Spaced .ShowcaseCard-Footer-Item:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 997px) {
|
||||
.ShowcaseCard-ImgContainer {
|
||||
height: 120px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Text {
|
||||
width: 100%;
|
||||
margin-left: var(--ifm-card-horizontal-spacing);
|
||||
}
|
||||
|
||||
.ShowcaseCard-Tag {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Footer a {
|
||||
margin: var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing) 0 0;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Text h3 {
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
opacity: 1;
|
||||
backdrop-filter: blur(0) contrast(100%);
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 650px) {
|
||||
.ShowcaseCard-ImgContainer {
|
||||
height: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 650px) {
|
||||
.ShowcaseCard-Content {
|
||||
flex-direction: column;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Text {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Text h3 {
|
||||
margin-top: var(--ifm-card-vertical-spacing);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 380px) {
|
||||
.ShowcaseCard-Footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Spaces between children */
|
||||
.ShowcaseCard-Footer-Spaced .ShowcaseCard-Footer-Item:first-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.ShowcaseCard-Footer-Spaced .ShowcaseCard-Footer-Item:nth-child(even) {
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
/* New CSS */
|
||||
|
||||
code {
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* CSS files with the .module.css suffix will be treated as CSS modules
|
||||
* and scoped locally.
|
||||
|
||||
+57
-57
@@ -39,74 +39,74 @@
|
||||
}
|
||||
},
|
||||
"@next/env": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.0.10.tgz",
|
||||
"integrity": "sha512-mQVj0K6wQ5WEk/sL9SZ+mJXJUaG7el8CpZ6io1uFe9GgNTSC7EgUyNGqM6IQovIFc5ukF4O/hqsdh3S/DCgT2g=="
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.0.tgz",
|
||||
"integrity": "sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ=="
|
||||
},
|
||||
"@next/swc-android-arm64": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.0.10.tgz",
|
||||
"integrity": "sha512-xYwXGkNhzZZsM5MD7KRwF5ZNiC8OLPtVMUiagpPnwENg8Hb0GSQo/NbYWXM8YrawEwp9LaZ7OXiuRKPh2JyBdA==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz",
|
||||
"integrity": "sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-arm64": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.0.10.tgz",
|
||||
"integrity": "sha512-f2zngulkpIJKWHckhRi7X8GZ+J/tNgFF7lYIh7Qx15JH0OTBsjkqxORlkzy+VZyHJ5sWTCaI6HYYd3ow6qkEEg==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz",
|
||||
"integrity": "sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-x64": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.0.10.tgz",
|
||||
"integrity": "sha512-Qykcu/gVC5oTvOQoRBhyuS5GYm5SbcgrFTsaLFkGBmEkg9eMQRiaCswk4IafpDXVzITkVFurzSM28q3tLW2qUw==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz",
|
||||
"integrity": "sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm-gnueabihf": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.0.10.tgz",
|
||||
"integrity": "sha512-EhqrTFsIXAXN9B/fiiW/QKUK/lSLCXRsLalkUp58KDfMqVLLlj1ORbESAcswiNQOChLuHQSldGEEtOBPQZcd9A==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz",
|
||||
"integrity": "sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-gnu": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.0.10.tgz",
|
||||
"integrity": "sha512-kqGtC72g3+JYXZbY2ca6digXR5U6AQ6Dzv4eAxYluMePLHjI/Xye1mf9dwVsgmeXfrD/IRDp5K/3A6UNvBm4oQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz",
|
||||
"integrity": "sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-musl": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.0.10.tgz",
|
||||
"integrity": "sha512-bG9zTSNwnSgc1Un/7oz1ZVN4UeXsTWrsQhAGWU78lLLCn4Zj9HQoUCRCGLt0OVs2DBZ+WC8CzzFliQ1SKipVbg==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz",
|
||||
"integrity": "sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-x64-gnu": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.0.10.tgz",
|
||||
"integrity": "sha512-c79PcfWtyThiYRa1+3KVfDq0zXaI8o1d6dQWNVqDrtLz5HKM/rbjLdvoNuxDwUeZhxI/d9CtyH6GbuKPw5l/5A==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz",
|
||||
"integrity": "sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-x64-musl": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.0.10.tgz",
|
||||
"integrity": "sha512-g/scgn+21/MLfizOCZOZt+MxNj2/8Tdlwjvy+QZcSUPZRUI2Y5o3HwBvI1f/bSci+NGRU+bUAO0NFtRJ9MzH5w==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz",
|
||||
"integrity": "sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-arm64-msvc": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.0.10.tgz",
|
||||
"integrity": "sha512-gl6B/ravwMeY5Nv4Il2/ARYJQ6u+KPRwGMjS1ZrNudIKlNn4YBeXh5A4cIVm+dHaff6/O/lGOa5/SUYDMZpkww==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz",
|
||||
"integrity": "sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-ia32-msvc": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.0.10.tgz",
|
||||
"integrity": "sha512-7RVpZ3tSThC6j+iZB0CUYmFiA3kXmN+pE7QcfyAxFaflKlaZoWNMKHIEZDuxSJc6YmQ6kyxsjqxVay2F5+/YCg==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz",
|
||||
"integrity": "sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-x64-msvc": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.0.10.tgz",
|
||||
"integrity": "sha512-oUIWRKd24jFLRWUYO1CZmML5+32BcpVfqhimGaaZIXcOkfQW+iqiAzdqsv688zaGtyKGeB9ZtiK3NDf+Q0v+Vw==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz",
|
||||
"integrity": "sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==",
|
||||
"optional": true
|
||||
},
|
||||
"@supabase/gotrue-js": {
|
||||
@@ -658,27 +658,27 @@
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
|
||||
"integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA=="
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
|
||||
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw=="
|
||||
},
|
||||
"next": {
|
||||
"version": "12.0.10",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-12.0.10.tgz",
|
||||
"integrity": "sha512-1y3PpGzpb/EZzz1jgne+JfZXKAVJUjYXwxzrADf/LWN+8yi9o79vMLXpW3mevvCHkEF2sBnIdjzNn16TJrINUw==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-12.1.0.tgz",
|
||||
"integrity": "sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==",
|
||||
"requires": {
|
||||
"@next/env": "12.0.10",
|
||||
"@next/swc-android-arm64": "12.0.10",
|
||||
"@next/swc-darwin-arm64": "12.0.10",
|
||||
"@next/swc-darwin-x64": "12.0.10",
|
||||
"@next/swc-linux-arm-gnueabihf": "12.0.10",
|
||||
"@next/swc-linux-arm64-gnu": "12.0.10",
|
||||
"@next/swc-linux-arm64-musl": "12.0.10",
|
||||
"@next/swc-linux-x64-gnu": "12.0.10",
|
||||
"@next/swc-linux-x64-musl": "12.0.10",
|
||||
"@next/swc-win32-arm64-msvc": "12.0.10",
|
||||
"@next/swc-win32-ia32-msvc": "12.0.10",
|
||||
"@next/swc-win32-x64-msvc": "12.0.10",
|
||||
"@next/env": "12.1.0",
|
||||
"@next/swc-android-arm64": "12.1.0",
|
||||
"@next/swc-darwin-arm64": "12.1.0",
|
||||
"@next/swc-darwin-x64": "12.1.0",
|
||||
"@next/swc-linux-arm-gnueabihf": "12.1.0",
|
||||
"@next/swc-linux-arm64-gnu": "12.1.0",
|
||||
"@next/swc-linux-arm64-musl": "12.1.0",
|
||||
"@next/swc-linux-x64-gnu": "12.1.0",
|
||||
"@next/swc-linux-x64-musl": "12.1.0",
|
||||
"@next/swc-win32-arm64-msvc": "12.1.0",
|
||||
"@next/swc-win32-ia32-msvc": "12.1.0",
|
||||
"@next/swc-win32-x64-msvc": "12.1.0",
|
||||
"caniuse-lite": "^1.0.30001283",
|
||||
"postcss": "8.4.5",
|
||||
"styled-jsx": "5.0.0",
|
||||
@@ -686,9 +686,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001305",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001305.tgz",
|
||||
"integrity": "sha512-p7d9YQMji8haf0f+5rbcv9WlQ+N5jMPfRAnUmZRlNxsNeBO3Yr7RYG6M2uTY1h9tCVdlkJg6YNNc4kiAiBLdWA=="
|
||||
"version": "1.0.30001312",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz",
|
||||
"integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+891
-773
File diff suppressed because it is too large.
Load diff
@@ -7,9 +7,8 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^1.11.9",
|
||||
"@supabase/ui": "^0.24.2",
|
||||
"next": "11.1.1",
|
||||
"@supabase/supabase-auth-helpers": "^1.0.6",
|
||||
"next": "^11.1.4",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"swr": "^0.5.5"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Auth } from '@supabase/ui'
|
||||
import { supabase } from '../utils/initSupabase'
|
||||
import { UserProvider } from '@supabase/supabase-auth-helpers/react'
|
||||
import { supabaseClient } from '@supabase/supabase-auth-helpers/nextjs'
|
||||
import './../style.css'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<main className={'dark'}>
|
||||
<Auth.UserContextProvider supabaseClient={supabase}>
|
||||
<UserProvider supabaseClient={supabaseClient}>
|
||||
<Component {...pageProps} />
|
||||
</Auth.UserContextProvider>
|
||||
</UserProvider>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/**
|
||||
* NOTE: this file is only needed if you're doing SSR (getServerSideProps)!
|
||||
*/
|
||||
import { supabase } from '../../utils/initSupabase'
|
||||
|
||||
export default function handler(req, res) {
|
||||
supabase.auth.api.setAuthCookie(req, res)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { handleAuth } from '@supabase/supabase-auth-helpers/nextjs'
|
||||
|
||||
export default handleAuth()
|
||||
@@ -1,13 +0,0 @@
|
||||
import { supabase } from '../../utils/initSupabase'
|
||||
|
||||
// Example of how to verify and get user data server-side.
|
||||
const getUser = async (req, res) => {
|
||||
const token = req.headers.token
|
||||
|
||||
const { data: user, error } = await supabase.auth.api.getUser(token)
|
||||
|
||||
if (error) return res.status(401).json({ error: error.message })
|
||||
return res.status(200).json(user)
|
||||
}
|
||||
|
||||
export default getUser
|
||||
@@ -1,106 +1,43 @@
|
||||
import Link from 'next/link'
|
||||
import useSWR from 'swr'
|
||||
import { Auth, Card, Typography, Space, Button, Icon } from '@supabase/ui'
|
||||
import { supabase } from '../utils/initSupabase'
|
||||
import { useUser, Auth } from '@supabase/supabase-auth-helpers/react'
|
||||
import { supabaseClient } from '@supabase/supabase-auth-helpers/nextjs'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const fetcher = (url, token) =>
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
headers: new Headers({ 'Content-Type': 'application/json', token }),
|
||||
credentials: 'same-origin',
|
||||
}).then((res) => res.json())
|
||||
|
||||
const Index = () => {
|
||||
const { user, session } = Auth.useUser()
|
||||
const { data, error } = useSWR(session ? ['/api/getUser', session.access_token] : null, fetcher)
|
||||
const [authView, setAuthView] = useState('sign_in')
|
||||
const LoginPage = () => {
|
||||
const { user, error } = useUser()
|
||||
const [data, setData] = useState({})
|
||||
|
||||
useEffect(() => {
|
||||
const { data: authListener } = supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (event === 'PASSWORD_RECOVERY') setAuthView('forgotten_password')
|
||||
if (event === 'USER_UPDATED') setTimeout(() => setAuthView('sign_in'), 1000)
|
||||
// Send session to /api/auth route to set the auth cookie.
|
||||
// NOTE: this is only needed if you're doing SSR (getServerSideProps)!
|
||||
fetch('/api/auth', {
|
||||
method: 'POST',
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({ event, session }),
|
||||
}).then((res) => res.json())
|
||||
})
|
||||
|
||||
return () => {
|
||||
authListener.unsubscribe()
|
||||
async function loadData() {
|
||||
const { data } = await supabaseClient.from('test').select('*')
|
||||
setData(data)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const View = () => {
|
||||
if (!user)
|
||||
return (
|
||||
<Space direction="vertical" size={8}>
|
||||
<div>
|
||||
<img src="https://app.supabase.io/img/supabase-dark.svg" width="96" />
|
||||
<Typography.Title level={3}>Welcome to Supabase Auth</Typography.Title>
|
||||
</div>
|
||||
<Auth
|
||||
supabaseClient={supabase}
|
||||
providers={['google', 'github']}
|
||||
view={authView}
|
||||
socialLayout="horizontal"
|
||||
socialButtonSize="xlarge"
|
||||
/>
|
||||
</Space>
|
||||
)
|
||||
// Only run query once user is logged in.
|
||||
if (user) loadData()
|
||||
}, [user])
|
||||
|
||||
if (!user)
|
||||
return (
|
||||
<Space direction="vertical" size={6}>
|
||||
{authView === 'forgotten_password' && <Auth.UpdatePassword supabaseClient={supabase} />}
|
||||
{user && (
|
||||
<>
|
||||
<Typography.Text>You're signed in</Typography.Text>
|
||||
<Typography.Text strong>Email: {user.email}</Typography.Text>
|
||||
|
||||
<Button
|
||||
icon={<Icon type="LogOut" />}
|
||||
type="outline"
|
||||
onClick={() => supabase.auth.signOut()}
|
||||
>
|
||||
Log out
|
||||
</Button>
|
||||
{error && <Typography.Text type="danger">Failed to fetch user!</Typography.Text>}
|
||||
{data && !error ? (
|
||||
<>
|
||||
<Typography.Text type="success">
|
||||
User data retrieved server-side (in API route):
|
||||
</Typography.Text>
|
||||
|
||||
<Typography.Text>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
</Typography.Text>
|
||||
</>
|
||||
) : (
|
||||
<div>Loading...</div>
|
||||
)}
|
||||
|
||||
<Typography.Text>
|
||||
<Link href="/profile">
|
||||
<a>SSR example with getServerSideProps</a>
|
||||
</Link>
|
||||
</Typography.Text>
|
||||
</>
|
||||
)}
|
||||
</Space>
|
||||
<>
|
||||
{error && <p>{error.message}</p>}
|
||||
<Auth
|
||||
// view="update_password"
|
||||
supabaseClient={supabaseClient}
|
||||
providers={['google', 'github']}
|
||||
socialLayout="horizontal"
|
||||
socialButtonSize="xlarge"
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ maxWidth: '420px', margin: '96px auto' }}>
|
||||
<Card>
|
||||
<View />
|
||||
</Card>
|
||||
</div>
|
||||
<>
|
||||
<button onClick={() => supabaseClient.auth.signOut()}>Sign out</button>
|
||||
<p>user:</p>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
<p>client-side data fetching with RLS</p>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Index
|
||||
export default LoginPage
|
||||
@@ -1,41 +1,13 @@
|
||||
import Link from 'next/link'
|
||||
import { Card, Typography, Space } from '@supabase/ui'
|
||||
import { supabase } from '../utils/initSupabase'
|
||||
// pages/profile.js
|
||||
import { withAuthRequired } from '@supabase/supabase-auth-helpers/nextjs'
|
||||
|
||||
export default function Profile({ user }) {
|
||||
return (
|
||||
<div style={{ maxWidth: '420px', margin: '96px auto' }}>
|
||||
<Card>
|
||||
<Space direction="vertical" size={6}>
|
||||
<Typography.Text>You're signed in</Typography.Text>
|
||||
<Typography.Text strong>Email: {user.email}</Typography.Text>
|
||||
<Typography.Text type="success">
|
||||
User data retrieved server-side (from Cookie in getServerSideProps):
|
||||
</Typography.Text>
|
||||
|
||||
<Typography.Text>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
</Typography.Text>
|
||||
|
||||
<Typography.Text>
|
||||
<Link href="/">
|
||||
<a>Static example with useSWR</a>
|
||||
</Link>
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
<>
|
||||
<div>Hello {user.email}</div>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getServerSideProps({ req }) {
|
||||
const { user } = await supabase.auth.api.getUserByCookie(req)
|
||||
|
||||
if (!user) {
|
||||
// If no user, redirect to index.
|
||||
return { props: {}, redirect: { destination: '/', permanent: false } }
|
||||
}
|
||||
|
||||
// If there is a user, return it.
|
||||
return { props: { user } }
|
||||
}
|
||||
export const getServerSideProps = withAuthRequired()
|
||||
@@ -1,6 +0,0 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
export const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
|
||||
)
|
||||
File diff suppressed because it is too large.
Load diff
+5
-14
@@ -1317,6 +1317,8 @@
|
||||
},
|
||||
"@supabase/supabase-js": {
|
||||
"version": "0.35.10",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-0.35.10.tgz",
|
||||
"integrity": "sha512-mjEvM5cHL0zu7iBZepl0OyNBOXmNmKa7POkutSvME6rLWW+Fu4j+IJ6rFjqc8I884yRggMoxkEc506YnMSp+jg==",
|
||||
"requires": {
|
||||
"@supabase/doctest-js": "^0.1.0",
|
||||
"@supabase/postgrest-js": "^0.17.0",
|
||||
@@ -3057,17 +3059,6 @@
|
||||
"indent-string": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.3",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
|
||||
"integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"amdefine": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
||||
@@ -10361,9 +10352,9 @@
|
||||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
|
||||
"integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+3
-3
@@ -17009,9 +17009,9 @@
|
||||
}
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
|
||||
"integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
|
||||
"version": "1.5.7",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.7.tgz",
|
||||
"integrity": "sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==",
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
"requires-port": "^1.0.0"
|
||||
|
||||
@@ -1625,7 +1625,7 @@
|
||||
"@svgr/plugin-svgo" "^5.4.0"
|
||||
loader-utils "^2.0.0"
|
||||
|
||||
"@tailwindcss/postcss7-compat@^2.0.2", "tailwindcss@npm:@tailwindcss/postcss7-compat":
|
||||
"@tailwindcss/postcss7-compat@^2.0.2":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/postcss7-compat/-/postcss7-compat-2.0.2.tgz#49cb21703dfb4447620fceab5cef3285cff8c69d"
|
||||
integrity sha512-KM8kjG5dd8qoXBX2a6r3r1TOqhFh8NtFBheG9qpVPwSjrD8wRdoM7s+Xz56HEA1XmeN64gEKqjmY6vm55DiS3Q==
|
||||
@@ -10982,9 +10982,9 @@ url-loader@4.1.1:
|
||||
schema-utils "^3.0.0"
|
||||
|
||||
url-parse@^1.4.3:
|
||||
version "1.4.7"
|
||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
|
||||
integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
|
||||
version "1.5.7"
|
||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.7.tgz#00780f60dbdae90181f51ed85fb24109422c932a"
|
||||
integrity sha512-HxWkieX+STA38EDk7CE9MEryFeHCKzgagxlGvsdS7WBImq9Mk+PGwiT56w82WI3aicwJA8REp42Cxo98c8FZMA==
|
||||
dependencies:
|
||||
querystringify "^2.1.1"
|
||||
requires-port "^1.0.0"
|
||||
|
||||
+6
-6
@@ -8609,9 +8609,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
|
||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -28333,9 +28333,9 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
|
||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg=="
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
|
||||
+1
-1
@@ -2,6 +2,7 @@
|
||||
|
||||
- [Arabic | العربية](/i18n/README.ar.md)
|
||||
- [Albanian / Shqip](/i18n/README.sq.md)
|
||||
- [Bangla / বাংলা](/i18n/README.bn.md)
|
||||
- [Catalan / Català](/i18n/README.ca.md)
|
||||
- [Danish / Dansk](/i18n/README.da.md)
|
||||
- [Dutch / Nederlands](/i18n/README.nl.md)
|
||||
@@ -36,4 +37,3 @@
|
||||
- [Turkish / Türkçe](/i18n/README.tr.md)
|
||||
- [Ukrainian / Українська](/i18n/README.uk.md)
|
||||
- [Vietnamese / Tiếng Việt](/i18n/README.vi-vn.md)
|
||||
- [Bangla / বাংলা](/i18n/README.bn.md)
|
||||
@@ -16,11 +16,10 @@ import {
|
||||
import { Dictionary } from '@supabase/grid'
|
||||
import { makeAutoObservable } from 'mobx'
|
||||
|
||||
import { POSTGRES_DATA_TYPES } from 'lib/constants'
|
||||
import { useStore } from 'hooks'
|
||||
import Panel from 'components/to-be-cleaned/Panel'
|
||||
import SqlEditor from 'components/to-be-cleaned/SqlEditor'
|
||||
|
||||
import { POSTGRES_DATA_TYPES } from 'components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.constants'
|
||||
|
||||
class CreateFunctionFormState {
|
||||
id: number | undefined
|
||||
@@ -780,12 +779,16 @@ const SelectLanguage: FC = observer(({}) => {
|
||||
<Select.Option value="sql">sql</Select.Option>
|
||||
{
|
||||
//map through all selected extensions that start with pl
|
||||
enabledExtensions.filter((ex:any) => {
|
||||
return ex.name.startsWith('pl')
|
||||
}).map(ex => (<Select.Option key={ex.name} value={ex.name}>{ex.name}</Select.Option>))
|
||||
|
||||
enabledExtensions
|
||||
.filter((ex: any) => {
|
||||
return ex.name.startsWith('pl')
|
||||
})
|
||||
.map((ex) => (
|
||||
<Select.Option key={ex.name} value={ex.name}>
|
||||
{ex.name}
|
||||
</Select.Option>
|
||||
))
|
||||
}
|
||||
|
||||
</Select>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -33,6 +33,8 @@ const InvoicesSettings: FC<Props> = ({ organization }) => {
|
||||
|
||||
useEffect(() => {
|
||||
let cancel = false
|
||||
const page = 1
|
||||
|
||||
const fetchInvoiceCount = async () => {
|
||||
const res = await head(`${API_URL}/stripe/invoices?customer=${stripe_customer_id}`, [
|
||||
'X-Total-Count',
|
||||
@@ -45,6 +47,9 @@ const InvoicesSettings: FC<Props> = ({ organization }) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setPage(page)
|
||||
fetchInvoices(page)
|
||||
fetchInvoiceCount()
|
||||
|
||||
return () => {
|
||||
@@ -52,29 +57,23 @@ const InvoicesSettings: FC<Props> = ({ organization }) => {
|
||||
}
|
||||
}, [stripe_customer_id])
|
||||
|
||||
useEffect(() => {
|
||||
let cancel = false
|
||||
const fetchInvoices = async (page: number) => {
|
||||
setLoading(true)
|
||||
setPage(page)
|
||||
|
||||
const fetchInvoices = async () => {
|
||||
setLoading(true)
|
||||
const invoices = await get(
|
||||
`${API_URL}/stripe/invoices?offset=${offset}&limit=${PAGE_LIMIT}&customer=${stripe_customer_id}`
|
||||
)
|
||||
if (!cancel) {
|
||||
if (invoices.error) {
|
||||
ui.setNotification({ category: 'error', message: invoices.error.message })
|
||||
} else {
|
||||
setInvoices(invoices)
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
fetchInvoices()
|
||||
const offset = (page - 1) * PAGE_LIMIT
|
||||
const invoices = await get(
|
||||
`${API_URL}/stripe/invoices?offset=${offset}&limit=${PAGE_LIMIT}&customer=${stripe_customer_id}`
|
||||
)
|
||||
|
||||
return () => {
|
||||
cancel = true
|
||||
if (invoices.error) {
|
||||
ui.setNotification({ category: 'error', message: invoices.error.message })
|
||||
} else {
|
||||
setInvoices(invoices)
|
||||
}
|
||||
}, [stripe_customer_id, page])
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="my-4 container max-w-4xl space-y-1">
|
||||
@@ -140,14 +139,14 @@ const InvoicesSettings: FC<Props> = ({ organization }) => {
|
||||
type="secondary"
|
||||
size="tiny"
|
||||
disabled={page === 1}
|
||||
onClick={() => setPage(page - 1)}
|
||||
onClick={async () => await fetchInvoices(page - 1)}
|
||||
/>
|
||||
<Button
|
||||
icon={<IconChevronRight />}
|
||||
type="secondary"
|
||||
size="tiny"
|
||||
disabled={page * PAGE_LIMIT >= count}
|
||||
onClick={() => setPage(page + 1)}
|
||||
onClick={async () => await fetchInvoices(page + 1)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,16 +16,24 @@ export const TEMPLATES: LogTemplate[] = [
|
||||
|
||||
{
|
||||
label: '10 Minutes Ago',
|
||||
mode: 'simple',
|
||||
mode: 'custom',
|
||||
searchString: 'timestamp < TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 10 MINUTE)',
|
||||
for: ['database', 'api'],
|
||||
},
|
||||
{
|
||||
label: 'POST or PATCH',
|
||||
label: 'Commits By User',
|
||||
mode: 'custom',
|
||||
searchString:
|
||||
"REGEXP_CONTAINS(event_message, 'POST') OR REGEXP_CONTAINS(event_message, 'PATCH')",
|
||||
for: ['api'],
|
||||
searchString: `SELECT
|
||||
p.user_name, count(*) as count
|
||||
FROM postgres_logs
|
||||
LEFT JOIN UNNEST(metadata) as m ON TRUE
|
||||
LEFT JOIN UNNEST(m.parsed) AS p ON TRUE
|
||||
WHERE
|
||||
REGEXP_CONTAINS(event_message, 'COMMIT')
|
||||
GROUP BY
|
||||
p.user_name
|
||||
`,
|
||||
for: ['database'],
|
||||
},
|
||||
{
|
||||
label: 'Metadata IP',
|
||||
@@ -37,7 +45,7 @@ FROM edge_logs
|
||||
LEFT JOIN UNNEST(r.headers) AS h ON TRUE
|
||||
WHERE h.x_real_ip IS NOT NULL
|
||||
`,
|
||||
for: ['database'],
|
||||
for: ['api'],
|
||||
},
|
||||
{
|
||||
label: 'Requests by Country',
|
||||
@@ -51,7 +59,7 @@ FROM edge_logs
|
||||
GROUP BY
|
||||
cf.country
|
||||
ORDER BY
|
||||
DESC count
|
||||
count DESC
|
||||
`,
|
||||
for: ['api'],
|
||||
},
|
||||
|
||||
+6
-1
@@ -2,7 +2,7 @@ import { sortBy, concat } from 'lodash'
|
||||
import { PostgresDataTypeOption } from './SidePanelEditor.types'
|
||||
|
||||
export const DATE_FORMAT = 'YYYY-MM-DDTHH:mm:ssZ'
|
||||
export const NUMERICAL_TYPES = ['int2', 'int4', 'int8', 'float4', 'float8']
|
||||
export const NUMERICAL_TYPES = ['int2', 'int4', 'int8', 'float4', 'float8', 'numeric']
|
||||
export const JSON_TYPES = ['json', 'jsonb']
|
||||
export const TEXT_TYPES = ['text', 'varchar']
|
||||
export const TIMESTAMP_TYPES = ['date', 'time', 'timestamp', 'timetz', 'timestamptz']
|
||||
@@ -37,6 +37,11 @@ export const POSTGRES_DATA_TYPE_OPTIONS: PostgresDataTypeOption[] = [
|
||||
description: 'Double precision floating-point number (8 bytes)',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'numeric',
|
||||
description: 'Exact numeric of selectable precision',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'json',
|
||||
description: 'Textual JSON data',
|
||||
|
||||
@@ -2,8 +2,10 @@ import useSWR from 'swr'
|
||||
import { FC } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { get } from 'lib/common/fetch'
|
||||
import { JwtSecretUpdateStatus, ProjectEvents } from '@supabase/shared-types/out/events'
|
||||
import { IconAlertCircle, Input, Loading, Typography } from '@supabase/ui'
|
||||
|
||||
import { useJwtSecretUpdateStatus } from 'hooks'
|
||||
import { API_URL } from 'lib/constants'
|
||||
import Panel from './Panel'
|
||||
|
||||
@@ -15,12 +17,20 @@ export const DisplayApiSettings = () => {
|
||||
const { ref } = router.query
|
||||
|
||||
const { data, error }: any = useSWR(`${API_URL}/props/project/${ref}/settings`, get)
|
||||
const {
|
||||
isError: isJwtSecretUpdateStatusError,
|
||||
isLoading: isJwtSecretUpdateStatusLoading,
|
||||
jwtSecretUpdateStatus,
|
||||
}: any = useJwtSecretUpdateStatus(ref)
|
||||
|
||||
if (!data)
|
||||
const isNotUpdatingJwtSecret =
|
||||
jwtSecretUpdateStatus === undefined || jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updated
|
||||
|
||||
if (!data || isJwtSecretUpdateStatusLoading)
|
||||
return (
|
||||
<ApiContentWrapper>
|
||||
<Panel.Content className="py-8">
|
||||
{error ? (
|
||||
{error || isJwtSecretUpdateStatusError ? (
|
||||
<div className="flex items-center space-x-2">
|
||||
<Typography.Text type="secondary">
|
||||
<IconAlertCircle strokeWidth={2} />
|
||||
@@ -43,7 +53,7 @@ export const DisplayApiSettings = () => {
|
||||
|
||||
return (
|
||||
<ApiContentWrapper>
|
||||
{!data ? (
|
||||
{!data || isJwtSecretUpdateStatusLoading ? (
|
||||
// @ts-ignore
|
||||
<Loading active={true} />
|
||||
) : (
|
||||
@@ -74,11 +84,17 @@ export const DisplayApiSettings = () => {
|
||||
</>
|
||||
}
|
||||
readOnly
|
||||
copy
|
||||
copy={isNotUpdatingJwtSecret}
|
||||
className="input-mono"
|
||||
disabled
|
||||
reveal={x.tags !== 'anon' && true}
|
||||
value={x.api_key}
|
||||
reveal={x.tags !== 'anon' && isNotUpdatingJwtSecret}
|
||||
value={
|
||||
jwtSecretUpdateStatus === JwtSecretUpdateStatus.Failed
|
||||
? 'JWT secret update failed, new API key may have issues'
|
||||
: jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updating
|
||||
? 'Updating JWT secret...'
|
||||
: x.api_key
|
||||
}
|
||||
onChange={() => {}}
|
||||
descriptionText={
|
||||
x.tags === 'service_role'
|
||||
@@ -98,12 +114,20 @@ export const DisplayConfigSettings = () => {
|
||||
const { ref } = router.query
|
||||
|
||||
const { data, error }: any = useSWR(`${API_URL}/props/project/${ref}/settings`, get)
|
||||
const {
|
||||
isError: isJwtSecretUpdateStatusError,
|
||||
isLoading: isJwtSecretUpdateStatusLoading,
|
||||
jwtSecretUpdateStatus,
|
||||
}: any = useJwtSecretUpdateStatus(ref)
|
||||
|
||||
if (!data)
|
||||
const isNotUpdatingJwtSecret =
|
||||
jwtSecretUpdateStatus === undefined || jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updated
|
||||
|
||||
if (!data || isJwtSecretUpdateStatusLoading)
|
||||
return (
|
||||
<ConfigContentWrapper>
|
||||
<Panel.Content className="py-8">
|
||||
{error ? (
|
||||
{error || isJwtSecretUpdateStatusError ? (
|
||||
<div className="flex items-center space-x-2">
|
||||
<Typography.Text type="secondary">
|
||||
<IconAlertCircle strokeWidth={2} />
|
||||
@@ -152,10 +176,16 @@ export const DisplayConfigSettings = () => {
|
||||
<Input
|
||||
label="JWT Secret"
|
||||
readOnly
|
||||
copy
|
||||
reveal
|
||||
copy={isNotUpdatingJwtSecret}
|
||||
reveal={isNotUpdatingJwtSecret}
|
||||
disabled
|
||||
value={jwtSecret}
|
||||
value={
|
||||
jwtSecretUpdateStatus === JwtSecretUpdateStatus.Failed
|
||||
? 'JWT secret update failed'
|
||||
: jwtSecretUpdateStatus === JwtSecretUpdateStatus.Updating
|
||||
? 'Updating JWT secret...'
|
||||
: jwtSecret
|
||||
}
|
||||
className="input-mono"
|
||||
descriptionText="Used to decode your JWTs. You can also use this to mint your own JWTs."
|
||||
layout="horizontal"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './useJwtSecretUpdateStatus'
|
||||
export * from './useOrganizationDetail'
|
||||
export * from './useProfile'
|
||||
export * from './useProjectAuthConfig'
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import useSWR from 'swr'
|
||||
import { get } from 'lib/common/fetch'
|
||||
import { JwtSecretUpdateStatus } from '@supabase/shared-types/out/events'
|
||||
import { API_URL } from 'lib/constants'
|
||||
|
||||
export function useJwtSecretUpdateStatus(projectRef: string | string[] | undefined) {
|
||||
const url = `${API_URL}/props/project/${projectRef}/jwt-secret-update-status`
|
||||
const { data, error, mutate } = useSWR<any>(url, get, {
|
||||
refreshInterval: (data) =>
|
||||
data?.jwtSecretUpdateStatus?.meta?.status === JwtSecretUpdateStatus.Updating ? 1_000 : 0,
|
||||
})
|
||||
const anyError = data?.error || error
|
||||
const meta = data?.jwtSecretUpdateStatus?.meta
|
||||
return {
|
||||
changeTrackingId: meta?.change_tracking_id,
|
||||
isError: !!anyError,
|
||||
isLoading: !anyError && !data,
|
||||
jwtSecretUpdateError: meta?.error,
|
||||
jwtSecretUpdateProgress: meta?.progress,
|
||||
jwtSecretUpdateStatus: meta?.status,
|
||||
mutateJwtSecretUpdateStatus: mutate,
|
||||
}
|
||||
}
|
||||
@@ -11,17 +11,6 @@ export const PG_META_URL = IS_PLATFORM
|
||||
|
||||
export const DATE_FORMAT = 'YYYY-MM-DDTHH:mm:ssZ'
|
||||
|
||||
// Data types primarily for mapping icon in editor
|
||||
|
||||
export const NUMERICAL_TYPES = ['int2', 'int4', 'int8', 'float4', 'float8']
|
||||
export const JSON_TYPES = ['json', 'jsonb']
|
||||
export const TEXT_TYPES = ['text', 'varchar']
|
||||
export const TIMESTAMP_TYPES = ['date', 'time', 'timestamp', 'timetz', 'timestamptz']
|
||||
export const OTHER_DATA_TYPES = ['uuid', 'bool']
|
||||
export const POSTGRES_DATA_TYPES = sortBy(
|
||||
concat(NUMERICAL_TYPES, JSON_TYPES, TEXT_TYPES, TIMESTAMP_TYPES, OTHER_DATA_TYPES)
|
||||
)
|
||||
|
||||
// Keyboard Shortcuts Related
|
||||
export const SHORTCUT_KEYS = {
|
||||
VIEW_ALL_SHORTCUTS: 'VIEW_ALL_SHORTCUTS',
|
||||
|
||||
Generated
+35
-42
@@ -15,11 +15,12 @@
|
||||
"@radix-ui/react-tooltip": "^0.1.6",
|
||||
"@sentry/browser": "^6.15.0",
|
||||
"@sentry/nextjs": "^6.15.0",
|
||||
"@supabase/grid": "^2.4.1",
|
||||
"@supabase/grid": "^2.4.3",
|
||||
"@supabase/postgres-meta": "^0.26.1",
|
||||
"@supabase/react-data-grid": "^7.1.0-beta.7",
|
||||
"@supabase/shared-types": "^0.1.15",
|
||||
"@supabase/supabase-js": "^1.29.1",
|
||||
"@supabase/ui": "^0.35.0",
|
||||
"@supabase/ui": "^0.36.4",
|
||||
"ajv": "^8.6.3",
|
||||
"analytics-node": "^3.5.0",
|
||||
"clipboard": "^2.0.8",
|
||||
@@ -53,7 +54,7 @@
|
||||
"sass": "^1.43.4",
|
||||
"semver": "^6.3.0",
|
||||
"sqlstring": "^2.3.2",
|
||||
"swr": "^1.0.1",
|
||||
"swr": "^1.2.1",
|
||||
"uniforms-bootstrap4": "^3.6.2",
|
||||
"uniforms-bridge-json-schema": "^3.6.2",
|
||||
"zxcvbn": "^4.4.2"
|
||||
@@ -2679,9 +2680,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/grid": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/grid/-/grid-2.4.1.tgz",
|
||||
"integrity": "sha512-KDlm8wSwGqX/UvGMOnKwMSJjq3vlKScSyNNfLnr1UMu3thZ14DkJ9J5wi8TUkD5CaBpEquHR4felREJ+JCaPfg==",
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/grid/-/grid-2.4.3.tgz",
|
||||
"integrity": "sha512-CfWh3m12eIUWOGYyY/XzTA39fsPEqW4fIaVwPNU770gW6IvzwoN/LItCqoTEQtEHkCttmGuMc1ZzG7z7hpJqYA==",
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "^4.3.1",
|
||||
"@scaleleap/pg-format": "^1.0.0",
|
||||
@@ -2699,7 +2700,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@supabase/react-data-grid": "^7.1.0-beta.7",
|
||||
"@supabase/ui": "^0.35.0",
|
||||
"@supabase/ui": "^0.36.4",
|
||||
"react": "^16.14 || ^17.0.0",
|
||||
"react-dom": "^16.14 || ^17.0.0"
|
||||
}
|
||||
@@ -2747,6 +2748,11 @@
|
||||
"websocket": "^1.0.34"
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/shared-types": {
|
||||
"version": "0.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/shared-types/-/shared-types-0.1.15.tgz",
|
||||
"integrity": "sha512-0IJqw0nU526NTxKnAW4N3eNNU9PSG961fXFS3BrguFPmhCUGuapW6zJOZM1FVFeMpn7y6pWw0iV7UqbRoiy8sg=="
|
||||
},
|
||||
"node_modules/@supabase/storage-js": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-1.5.0.tgz",
|
||||
@@ -2767,9 +2773,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/ui": {
|
||||
"version": "0.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/ui/-/ui-0.35.0.tgz",
|
||||
"integrity": "sha512-bftQoDcX2Vl6Gcu6IYUjteN7ZKNs5YhvhOz3c/8kTYU6DuD33VKOYCMQBKwU4IuBbEsNXVRlJxHK4RjXIiS4ww==",
|
||||
"version": "0.36.4",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/ui/-/ui-0.36.4.tgz",
|
||||
"integrity": "sha512-7Wq4D/5269q1wpmSo8V57hhWEXB83eKKEW9NHBdSS7wnsAb9hK+m6D/DN8ImpSdybDheHOdT/C4xjc2W6luOxg==",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.20",
|
||||
"prop-types": "^15.7.2"
|
||||
@@ -4831,14 +4837,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
|
||||
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/des.js": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
|
||||
@@ -12212,14 +12210,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/swr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-1.0.1.tgz",
|
||||
"integrity": "sha512-EPQAxSjoD4IaM49rpRHK0q+/NzcwoT8c0/Ylu/u3/6mFj/CWnQVjNJ0MV2Iuw/U+EJSd2TX5czdAwKPYZIG0YA==",
|
||||
"dependencies": {
|
||||
"dequal": "2.0.2"
|
||||
},
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-1.2.1.tgz",
|
||||
"integrity": "sha512-1cuWXqJqXcFwbgONGCY4PHZ8v05009JdHsC3CIC6u7d00kgbMswNr1sHnnhseOBxtzVqcCNpOHEgVDciRer45w==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.11.0 || ^17.0.0"
|
||||
"react": "^16.11.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/symbol-tree": {
|
||||
@@ -15444,9 +15439,9 @@
|
||||
}
|
||||
},
|
||||
"@supabase/grid": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/grid/-/grid-2.4.1.tgz",
|
||||
"integrity": "sha512-KDlm8wSwGqX/UvGMOnKwMSJjq3vlKScSyNNfLnr1UMu3thZ14DkJ9J5wi8TUkD5CaBpEquHR4felREJ+JCaPfg==",
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/grid/-/grid-2.4.3.tgz",
|
||||
"integrity": "sha512-CfWh3m12eIUWOGYyY/XzTA39fsPEqW4fIaVwPNU770gW6IvzwoN/LItCqoTEQtEHkCttmGuMc1ZzG7z7hpJqYA==",
|
||||
"requires": {
|
||||
"@monaco-editor/react": "^4.3.1",
|
||||
"@scaleleap/pg-format": "^1.0.0",
|
||||
@@ -15498,6 +15493,11 @@
|
||||
"websocket": "^1.0.34"
|
||||
}
|
||||
},
|
||||
"@supabase/shared-types": {
|
||||
"version": "0.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/shared-types/-/shared-types-0.1.15.tgz",
|
||||
"integrity": "sha512-0IJqw0nU526NTxKnAW4N3eNNU9PSG961fXFS3BrguFPmhCUGuapW6zJOZM1FVFeMpn7y6pWw0iV7UqbRoiy8sg=="
|
||||
},
|
||||
"@supabase/storage-js": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-1.5.0.tgz",
|
||||
@@ -15518,9 +15518,9 @@
|
||||
}
|
||||
},
|
||||
"@supabase/ui": {
|
||||
"version": "0.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/ui/-/ui-0.35.0.tgz",
|
||||
"integrity": "sha512-bftQoDcX2Vl6Gcu6IYUjteN7ZKNs5YhvhOz3c/8kTYU6DuD33VKOYCMQBKwU4IuBbEsNXVRlJxHK4RjXIiS4ww==",
|
||||
"version": "0.36.4",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/ui/-/ui-0.36.4.tgz",
|
||||
"integrity": "sha512-7Wq4D/5269q1wpmSo8V57hhWEXB83eKKEW9NHBdSS7wnsAb9hK+m6D/DN8ImpSdybDheHOdT/C4xjc2W6luOxg==",
|
||||
"requires": {
|
||||
"fsevents": "^2.3.2",
|
||||
"lodash": "^4.17.20",
|
||||
@@ -17276,11 +17276,6 @@
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
|
||||
},
|
||||
"dequal": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
|
||||
"integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug=="
|
||||
},
|
||||
"des.js": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
|
||||
@@ -22860,12 +22855,10 @@
|
||||
}
|
||||
},
|
||||
"swr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-1.0.1.tgz",
|
||||
"integrity": "sha512-EPQAxSjoD4IaM49rpRHK0q+/NzcwoT8c0/Ylu/u3/6mFj/CWnQVjNJ0MV2Iuw/U+EJSd2TX5czdAwKPYZIG0YA==",
|
||||
"requires": {
|
||||
"dequal": "2.0.2"
|
||||
}
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-1.2.1.tgz",
|
||||
"integrity": "sha512-1cuWXqJqXcFwbgONGCY4PHZ8v05009JdHsC3CIC6u7d00kgbMswNr1sHnnhseOBxtzVqcCNpOHEgVDciRer45w==",
|
||||
"requires": {}
|
||||
},
|
||||
"symbol-tree": {
|
||||
"version": "3.2.4",
|
||||
|
||||
+4
-3
@@ -17,11 +17,12 @@
|
||||
"@radix-ui/react-tooltip": "^0.1.6",
|
||||
"@sentry/browser": "^6.15.0",
|
||||
"@sentry/nextjs": "^6.15.0",
|
||||
"@supabase/grid": "^2.4.1",
|
||||
"@supabase/grid": "^2.4.3",
|
||||
"@supabase/postgres-meta": "^0.26.1",
|
||||
"@supabase/react-data-grid": "^7.1.0-beta.7",
|
||||
"@supabase/shared-types": "^0.1.15",
|
||||
"@supabase/supabase-js": "^1.29.1",
|
||||
"@supabase/ui": "^0.35.0",
|
||||
"@supabase/ui": "^0.36.4",
|
||||
"ajv": "^8.6.3",
|
||||
"analytics-node": "^3.5.0",
|
||||
"clipboard": "^2.0.8",
|
||||
@@ -55,7 +56,7 @@
|
||||
"sass": "^1.43.4",
|
||||
"semver": "^6.3.0",
|
||||
"sqlstring": "^2.3.2",
|
||||
"swr": "^1.0.1",
|
||||
"swr": "^1.2.1",
|
||||
"uniforms-bootstrap4": "^3.6.2",
|
||||
"uniforms-bridge-json-schema": "^3.6.2",
|
||||
"zxcvbn": "^4.4.2"
|
||||
|
||||
@@ -82,7 +82,7 @@ const DocView: FC<any> = observer(({}) => {
|
||||
|
||||
const { data: jsonSchema, error: jsonSchemaError } = useSWR(
|
||||
() => swaggerUrl,
|
||||
(url) => get(url, { headers, credentials: 'omit' }).then((res) => res)
|
||||
(url: string) => get(url, { headers, credentials: 'omit' }).then((res) => res)
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -717,7 +717,7 @@ const Settings = () => {
|
||||
</>
|
||||
)}
|
||||
<Divider light />
|
||||
{/* <ToggleField
|
||||
<ToggleField
|
||||
name="EXTERNAL_LINKEDIN_ENABLED"
|
||||
addOns={
|
||||
externalProvidersModel.EXTERNAL_LINKEDIN_ENABLED && (
|
||||
@@ -774,7 +774,7 @@ const Settings = () => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Divider light /> */}
|
||||
<Divider light />
|
||||
<ToggleField
|
||||
name="EXTERNAL_TWITCH_ENABLED"
|
||||
addOns={
|
||||
|
||||
@@ -1,20 +1,69 @@
|
||||
import useSWR from 'swr'
|
||||
import { FC, createContext, useContext, useState } from 'react'
|
||||
import {
|
||||
Dispatch,
|
||||
FC,
|
||||
SetStateAction,
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { indexOf } from 'lodash'
|
||||
import { useRouter } from 'next/router'
|
||||
import { AutoField } from 'uniforms-bootstrap4'
|
||||
import { observer, useLocalObservable } from 'mobx-react-lite'
|
||||
import { Typography, Input, IconAlertCircle, Modal, IconKey } from '@supabase/ui'
|
||||
import {
|
||||
JwtSecretUpdateError,
|
||||
JwtSecretUpdateProgress,
|
||||
JwtSecretUpdateStatus,
|
||||
} from '@supabase/shared-types/out/events'
|
||||
import {
|
||||
Alert,
|
||||
Typography,
|
||||
Input,
|
||||
IconAlertCircle,
|
||||
Modal,
|
||||
IconKey,
|
||||
Button,
|
||||
Dropdown,
|
||||
Divider,
|
||||
IconPenTool,
|
||||
IconRefreshCw,
|
||||
IconChevronDown,
|
||||
IconLoader,
|
||||
} from '@supabase/ui'
|
||||
|
||||
import { API_URL } from 'lib/constants'
|
||||
import { useStore, withAuth } from 'hooks'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import { patch, get } from 'lib/common/fetch'
|
||||
import { useStore, useJwtSecretUpdateStatus, withAuth } from 'hooks'
|
||||
import { SettingsLayout } from 'components/layouts'
|
||||
import Panel from 'components/to-be-cleaned/Panel'
|
||||
import MultiSelectUI from 'components/to-be-cleaned/MultiSelect'
|
||||
import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
|
||||
import { DisplayApiSettings } from 'components/to-be-cleaned/DisplayProjectSettings'
|
||||
import ConfirmationModal from 'components/ui/ConfirmationModal'
|
||||
import Flag from 'components/ui/Flag/Flag'
|
||||
|
||||
const JWT_SECRET_UPDATE_ERROR_MESSAGES = {
|
||||
[JwtSecretUpdateError.APIServicesConfigurationUpdateFailed]:
|
||||
'failed to update configuration for API services',
|
||||
[JwtSecretUpdateError.APIServicesRestartFailed]: 'failed to restart API services',
|
||||
[JwtSecretUpdateError.DatabaseAdminAPIConfigurationUpdateFailed]:
|
||||
'failed to update configuration for database admin API',
|
||||
[JwtSecretUpdateError.PostgreSQLRestartFailed]: 'failed to restart PostgreSQL service',
|
||||
[JwtSecretUpdateError.SupabaseAPIKeyUpdateFailed]: 'failed to update Supabase API key',
|
||||
}
|
||||
|
||||
const JWT_SECRET_UPDATE_PROGRESS_MESSAGES = {
|
||||
[JwtSecretUpdateProgress.RestartedAPIServices]: 'restarted API services',
|
||||
[JwtSecretUpdateProgress.RestartedPostgreSQL]: 'restarted PostgreSQL service',
|
||||
[JwtSecretUpdateProgress.Started]: 'started updating',
|
||||
[JwtSecretUpdateProgress.UpdatedAPIServicesConfiguration]:
|
||||
'updated configuration for API services',
|
||||
[JwtSecretUpdateProgress.UpdatedDatabaseAdminAPIConfiguration]:
|
||||
'updated configuration for database admin API',
|
||||
}
|
||||
|
||||
const PageContext: any = createContext(null)
|
||||
|
||||
@@ -66,7 +115,8 @@ const ServiceList: FC<any> = ({ projectRef }) => {
|
||||
const [customToken, setCustomToken] = useState<string>('')
|
||||
const [isRegeneratingKey, setIsGeneratingKey] = useState<boolean>(false)
|
||||
const [isCreatingKey, setIsCreatingKey] = useState<boolean>(false)
|
||||
const [isLoadingCreatingKey, setIsLoadingCreatingKey] = useState<boolean>(false)
|
||||
const [isSubmittingJwtSecretUpdateRequest, setIsSubmittingJwtSecretUpdateRequest] =
|
||||
useState<boolean>(false)
|
||||
|
||||
const {
|
||||
data,
|
||||
@@ -77,15 +127,57 @@ const ServiceList: FC<any> = ({ projectRef }) => {
|
||||
`${API_URL}/projects/${projectRef}/config?app=postgrest`,
|
||||
get
|
||||
)
|
||||
const {
|
||||
changeTrackingId,
|
||||
isError: isJwtSecretUpdateStatusError,
|
||||
isLoading: isJwtSecretUpdateStatusLoading,
|
||||
jwtSecretUpdateError,
|
||||
jwtSecretUpdateProgress,
|
||||
jwtSecretUpdateStatus,
|
||||
mutateJwtSecretUpdateStatus,
|
||||
}: any = useJwtSecretUpdateStatus(ref)
|
||||
|
||||
if (error) {
|
||||
const { Failed, Updated, Updating } = JwtSecretUpdateStatus
|
||||
|
||||
const isJwtSecretUpdateFailed = jwtSecretUpdateStatus === Failed
|
||||
const isNotUpdatingJwtSecret =
|
||||
jwtSecretUpdateStatus === undefined || jwtSecretUpdateStatus === Updated
|
||||
const isUpdatingJwtSecret = jwtSecretUpdateStatus === Updating
|
||||
const jwtSecretUpdateErrorMessage =
|
||||
JWT_SECRET_UPDATE_ERROR_MESSAGES[jwtSecretUpdateError as JwtSecretUpdateError]
|
||||
const jwtSecretUpdateProgressMessage =
|
||||
JWT_SECRET_UPDATE_PROGRESS_MESSAGES[jwtSecretUpdateProgress as JwtSecretUpdateProgress]
|
||||
|
||||
const previousJwtSecretUpdateStatus = useRef()
|
||||
|
||||
useEffect(() => {
|
||||
if (previousJwtSecretUpdateStatus.current === Updating) {
|
||||
switch (jwtSecretUpdateStatus) {
|
||||
case Updated:
|
||||
mutateConfig()
|
||||
mutateSettings()
|
||||
ui.setNotification({ category: 'success', message: 'Successfully updated JWT secret' })
|
||||
break
|
||||
case Failed:
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `JWT secret update failed: ${jwtSecretUpdateErrorMessage}`,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
previousJwtSecretUpdateStatus.current = jwtSecretUpdateStatus
|
||||
}, [jwtSecretUpdateStatus])
|
||||
|
||||
if (error || isJwtSecretUpdateStatusError) {
|
||||
return (
|
||||
<div className="p-6 mx-auto sm:w-full md:w-3/4 text-center">
|
||||
<Typography.Title level={3}>Error loading API settings</Typography.Title>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (!data) {
|
||||
if (!data || isJwtSecretUpdateStatusLoading) {
|
||||
return (
|
||||
<div className="p-6 mx-auto sm:w-full md:w-3/4 text-center">
|
||||
<Typography.Title level={3}>Loading...</Typography.Title>
|
||||
@@ -100,38 +192,29 @@ const ServiceList: FC<any> = ({ projectRef }) => {
|
||||
const apiService = services.find((x: any) => x.app.id == API_SERVICE_ID)
|
||||
const apiConfig = apiService?.app_config
|
||||
|
||||
async function handleGenerateNewJwtToken() {
|
||||
async function handleJwtSecretUpdate(
|
||||
jwt_secret: string,
|
||||
setModalVisibility: Dispatch<SetStateAction<boolean>>
|
||||
) {
|
||||
setIsSubmittingJwtSecretUpdateRequest(true)
|
||||
try {
|
||||
const trackingId = uuidv4()
|
||||
const res = await patch(`${API_URL}/projects/${ref}/config?app=secrets`, {
|
||||
jwt_secret: 'ROLL',
|
||||
jwt_secret,
|
||||
change_tracking_id: trackingId,
|
||||
})
|
||||
if (res.error) throw res.error
|
||||
setIsGeneratingKey(false)
|
||||
// refetch data in forms
|
||||
mutateSettings()
|
||||
mutateConfig()
|
||||
ui.setNotification({ category: 'success', message: 'Successfully updated JWT secret' })
|
||||
} catch (error: any) {
|
||||
ui.setNotification({ category: 'error', message: error.message })
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCustomNewJwtToken() {
|
||||
setIsLoadingCreatingKey(true)
|
||||
try {
|
||||
const res = await patch(`${API_URL}/projects/${ref}/config?app=secrets`, {
|
||||
jwt_secret: customToken,
|
||||
setModalVisibility(false)
|
||||
mutateJwtSecretUpdateStatus()
|
||||
ui.setNotification({
|
||||
category: 'info',
|
||||
message:
|
||||
'Successfully submitted JWT secret update request. Please wait while your project is updated.',
|
||||
})
|
||||
if (res.error) throw res.error
|
||||
setIsCreatingKey(false)
|
||||
// refetch data in forms
|
||||
mutateSettings()
|
||||
mutateConfig()
|
||||
ui.setNotification({ category: 'success', message: 'Successfully updated JWT secret' })
|
||||
} catch (error: any) {
|
||||
ui.setNotification({ category: 'error', message: error.message })
|
||||
} finally {
|
||||
setIsLoadingCreatingKey(false)
|
||||
setIsSubmittingJwtSecretUpdateRequest(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,92 +246,154 @@ const ServiceList: FC<any> = ({ projectRef }) => {
|
||||
<Input
|
||||
label="JWT Secret"
|
||||
readOnly
|
||||
copy
|
||||
reveal
|
||||
disabled={true}
|
||||
value={config?.jwt_secret || ''}
|
||||
copy={isNotUpdatingJwtSecret}
|
||||
reveal={isNotUpdatingJwtSecret}
|
||||
disabled
|
||||
value={
|
||||
isJwtSecretUpdateFailed
|
||||
? 'JWT secret update failed'
|
||||
: isUpdatingJwtSecret
|
||||
? 'Updating JWT secret...'
|
||||
: config?.jwt_secret || ''
|
||||
}
|
||||
className="input-mono"
|
||||
descriptionText={
|
||||
'Used to decode your JWTs. You can also use this to mint your own JWTs.'
|
||||
}
|
||||
layout="horizontal"
|
||||
/>
|
||||
{/* Temporarily hide the jwt secret rolling feature */}
|
||||
{/* <div className="space-y-3">
|
||||
<div className="p-3 px-6 dark:bg-bg-alt-dark bg-bg-alt-light rounded-md shadow-sm border dark:border-dark flex items-center justify-between">
|
||||
<div>
|
||||
<Typography.Text>Generate a new JWT secret</Typography.Text>
|
||||
<div>
|
||||
<Typography.Text type="secondary">
|
||||
A random secret will be created, or you can create your own.
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-end">
|
||||
<Dropdown
|
||||
align="end"
|
||||
side="bottom"
|
||||
overlay={
|
||||
<>
|
||||
<Dropdown.Item
|
||||
onClick={() => setIsGeneratingKey(true)}
|
||||
icon={<IconRefreshCw size={16} />}
|
||||
>
|
||||
Generate a random secret
|
||||
</Dropdown.Item>
|
||||
<Divider light />
|
||||
<Dropdown.Item
|
||||
onClick={() => setIsCreatingKey(true)}
|
||||
icon={<IconPenTool size={16} />}
|
||||
>
|
||||
Create my own secret
|
||||
</Dropdown.Item>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Button as="span" type="secondary" iconRight={<IconChevronDown />}>
|
||||
Generate a new secret
|
||||
</Button>
|
||||
</Dropdown>
|
||||
<Flag name="jwtSecretUpdate">
|
||||
<div className="space-y-3">
|
||||
<div className="p-3 px-6 dark:bg-bg-alt-dark bg-bg-alt-light rounded-md shadow-sm border dark:border-dark">
|
||||
{isJwtSecretUpdateFailed ? (
|
||||
<Alert withIcon variant="warning" title="Failed to update JWT secret">
|
||||
Please contact Supabase support with the following details: <br />
|
||||
Change tracking ID: {changeTrackingId} <br />
|
||||
Error message: {jwtSecretUpdateErrorMessage}
|
||||
</Alert>
|
||||
) : (
|
||||
<>
|
||||
{isUpdatingJwtSecret ? (
|
||||
<div className="flex items-center space-x-2">
|
||||
<IconLoader className="animate-spin" size={14} />
|
||||
<Typography.Text>
|
||||
Updating JWT secret: {jwtSecretUpdateProgressMessage}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full space-y-2">
|
||||
<div className="w-full flex items-center justify-between">
|
||||
<div className="flex flex-col space-y-1">
|
||||
<Typography.Text>Generate a new JWT secret</Typography.Text>
|
||||
<Typography.Text type="secondary">
|
||||
A random secret will be created, or you can create your own.
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div className="flex flex-col items-end">
|
||||
{isUpdatingJwtSecret ? (
|
||||
<Button loading type="secondary">
|
||||
Updating JWT secret...
|
||||
</Button>
|
||||
) : (
|
||||
<Dropdown
|
||||
align="end"
|
||||
side="bottom"
|
||||
overlay={
|
||||
<>
|
||||
<Dropdown.Item
|
||||
onClick={() => setIsGeneratingKey(true)}
|
||||
icon={<IconRefreshCw size={16} />}
|
||||
>
|
||||
Generate a random secret
|
||||
</Dropdown.Item>
|
||||
<Divider light />
|
||||
<Dropdown.Item
|
||||
onClick={() => setIsCreatingKey(true)}
|
||||
icon={<IconPenTool size={16} />}
|
||||
>
|
||||
Create my own secret
|
||||
</Dropdown.Item>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
as="span"
|
||||
type="secondary"
|
||||
iconRight={<IconChevronDown />}
|
||||
>
|
||||
Generate a new secret
|
||||
</Button>
|
||||
</Dropdown>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Alert
|
||||
withIcon
|
||||
variant="warning"
|
||||
title="This will invalidate all existing API keys!"
|
||||
>
|
||||
Your project will also be restarted during this process, which will
|
||||
terminate any existing connections.
|
||||
</Alert>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</Flag>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
</section>
|
||||
<section>{config && <PostgrestConfig config={config} projectRef={projectRef} />}</section>
|
||||
</article>
|
||||
<ConfirmationModal
|
||||
danger
|
||||
<Modal
|
||||
visible={isRegeneratingKey}
|
||||
title="Generate new JWT secret"
|
||||
buttonLabel="Generate new secret"
|
||||
buttonLoadingLabel="Generating"
|
||||
children={
|
||||
<Typography.Text type="secondary">
|
||||
Are you sure you want to genereate a random new JWT secret? This action cannot be undone
|
||||
and the old JWT secret will be lost.
|
||||
</Typography.Text>
|
||||
}
|
||||
onSelectCancel={() => setIsGeneratingKey(false)}
|
||||
onSelectConfirm={handleGenerateNewJwtToken}
|
||||
/>
|
||||
onCancel={() => setIsGeneratingKey(false)}
|
||||
title="Are you absolutely sure?"
|
||||
icon={<IconAlertCircle background={'red'} />}
|
||||
hideFooter
|
||||
size="medium"
|
||||
closable
|
||||
>
|
||||
<Typography.Text>
|
||||
<p className="text-sm">
|
||||
This action cannot be undone and the old JWT secret will be lost. All existing API keys
|
||||
will be invalidated, and any open connections will be terminated.
|
||||
</p>
|
||||
</Typography.Text>
|
||||
<Button
|
||||
onClick={() => handleJwtSecretUpdate('ROLL', setIsGeneratingKey)}
|
||||
size="small"
|
||||
block
|
||||
danger
|
||||
loading={isSubmittingJwtSecretUpdateRequest}
|
||||
>
|
||||
Generate new secret
|
||||
</Button>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
closable
|
||||
title="Create a custom JWT secret"
|
||||
visible={isCreatingKey}
|
||||
size="small"
|
||||
size="medium"
|
||||
confirmText="Apply new JWT secret"
|
||||
variant="danger"
|
||||
alignFooter="right"
|
||||
loading={isLoadingCreatingKey}
|
||||
loading={isSubmittingJwtSecretUpdateRequest}
|
||||
onCancel={() => setIsCreatingKey(false)}
|
||||
onConfirm={handleCustomNewJwtToken}
|
||||
onConfirm={() => handleJwtSecretUpdate(customToken, setIsCreatingKey)}
|
||||
>
|
||||
<Typography.Text type="secondary">
|
||||
Create a custom JWT secret. Make sure it is a strong combination of characters that cannot
|
||||
be guessed easily.
|
||||
</Typography.Text>
|
||||
<Alert
|
||||
withIcon
|
||||
variant="warning"
|
||||
title="All existing API keys will be invalidated, and any open connections will be terminated."
|
||||
/>
|
||||
<Input
|
||||
onChange={(e: any) => setCustomToken(e.target.value)}
|
||||
value={customToken}
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
LOG_TYPE_LABEL_MAPPING,
|
||||
} from 'components/interfaces/Settings/Logs'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import useSWRInfinite from 'swr/infinite'
|
||||
import useSWRInfinite, { SWRInfiniteKeyLoader } from 'swr/infinite'
|
||||
import { isUndefined } from 'lodash'
|
||||
import { useFlag } from 'hooks'
|
||||
import dayjs from 'dayjs'
|
||||
@@ -107,7 +107,7 @@ export const LogPage: NextPage = () => {
|
||||
return qs
|
||||
}
|
||||
// handle log fetching
|
||||
const getKeyLogs: KeyLoader<Logs> = (_pageIndex: number, prevPageData) => {
|
||||
const getKeyLogs: SWRInfiniteKeyLoader = (_pageIndex: number, prevPageData) => {
|
||||
let queryParams
|
||||
// if prev page data is 100 items, could possibly have more records that are not yet fetched within this interval
|
||||
if (prevPageData === null) {
|
||||
@@ -268,10 +268,11 @@ export const LogPage: NextPage = () => {
|
||||
onInputRun={handleRefresh}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row justify-between items-center px-2 py-1 w-full">
|
||||
<div className="flex flex-row justify-end items-center px-2 py-1 w-full">
|
||||
{isSelectQuery && (
|
||||
<InformationBox
|
||||
block
|
||||
className="shrink mr-auto"
|
||||
block={false}
|
||||
size="tiny"
|
||||
icon={<IconInfo size="tiny" />}
|
||||
title={`Custom queries are restricted to a ${
|
||||
|
||||
@@ -391,6 +391,14 @@
|
||||
{
|
||||
"value": "messagebird",
|
||||
"label": "Messagebird"
|
||||
},
|
||||
{
|
||||
"value": "vonage",
|
||||
"label": "Vonage"
|
||||
},
|
||||
{
|
||||
"value": "textlocal",
|
||||
"label": "Textlocal"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -128,7 +128,7 @@ let { data, error } = await supabase
|
||||
... you can simply define a rule on your database table, `auth.uid() = user_id`, and your request will return the rows which pass the rule, even when you remove the filter from your middleware:
|
||||
|
||||
```js
|
||||
let user = await supabase.from('users').select('user_id, name')
|
||||
let { data, error } = await supabase.from('users').select('user_id, name')
|
||||
|
||||
// console.log(data)
|
||||
// Still => { id: 'd0714948', name: 'Jane' }
|
||||
|
||||
@@ -43,8 +43,8 @@ values={[
|
||||
|
||||
```sql
|
||||
|
||||
-- Example: enable the "pgtap" extension
|
||||
create extension pgtap;
|
||||
-- Example: enable the "pgtap" extension and ensure it is installed
|
||||
create extension pgtap with schema extensions;
|
||||
|
||||
-- Example: disable the "pgtap" extension
|
||||
drop extension pgtap;
|
||||
@@ -54,6 +54,8 @@ drop extension pgtap;
|
||||
Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
|
||||
To disable an extension you can call `drop extension`.
|
||||
|
||||
Enabling few extensions by the SQL code `create extension <extension-name> with schema extensions` may lead to permission issues (e.g. `dblink`, `http`, `pg_cron`).
|
||||
|
||||
</TabItem>
|
||||
|
||||
</Tabs>
|
||||
|
||||
@@ -275,7 +275,7 @@ select * from add_planet('Jakku');
|
||||
<TabItem value="JS">
|
||||
|
||||
```js
|
||||
const { data, error } = supabase
|
||||
const { data, error } = await supabase
|
||||
.rpc('add_planet', { name: 'Jakku' })
|
||||
```
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ By default, Supabase limits the maximum statement execution time to _3 seconds_
|
||||
|
||||
### Changing the default timeout
|
||||
|
||||
The timeout values were picked as a reasonable default for the majority of use-cases, but can be modified using the [`alter role`](https://www.postgresql.org/docs/13/sql-alterrole.html) statement:
|
||||
The timeout values were picked as a reasonable default for the majority of use-cases, but can be modified using the [`alter role`](https://www.postgresql.org/docs/current/sql-alterrole.html) statement:
|
||||
|
||||
```sql
|
||||
alter role authenticated set statement_timeout = '15s';
|
||||
@@ -22,6 +22,6 @@ set statement_timeout to 60000; -- 1 minute in milliseconds
|
||||
|
||||
### Statement Optimization
|
||||
|
||||
All Supabase projects come with the [`pg_stat_statements`](https://www.postgresql.org/docs/13/pgstatstatements.html) extension installed, which tracks planning and execution statistics for all statements executed against it. These statistics can be used in order to diagnose the performance of your project.
|
||||
All Supabase projects come with the [`pg_stat_statements`](https://www.postgresql.org/docs/current/pgstatstatements.html) extension installed, which tracks planning and execution statistics for all statements executed against it. These statistics can be used in order to diagnose the performance of your project.
|
||||
|
||||
This data can further be used in conjunction with the [`explain`](https://www.postgresql.org/docs/13/using-explain.html) functionality of Postgres to optimize your usage.
|
||||
This data can further be used in conjunction with the [`explain`](https://www.postgresql.org/docs/current/using-explain.html) functionality of Postgres to optimize your usage.
|
||||
@@ -401,7 +401,7 @@ Write the following and click `Run`.
|
||||
|
||||
```sql
|
||||
create or replace function auth.user_id() returns text as $$
|
||||
select nullif(current_setting('request.jwt.claims.userId', true), '')::text;
|
||||
select nullif(current_setting('request.jwt.claims', true)::json->>'userId', '')::text;
|
||||
$$ language sql stable;
|
||||
```
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
import {
|
||||
Badge,
|
||||
@@ -17,17 +17,15 @@ import { Swiper, SwiperSlide } from 'swiper/react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { useTheme } from '../Providers'
|
||||
|
||||
const supabase = createClient(
|
||||
'https://rsnibhkhsbfnncjmwnkj.supabase.co',
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYxNTIxNDE1MywiZXhwIjoxOTMwNzkwMTUzfQ.OQEbAaTfgDdLCCht251P2JRD3QDnui6nsU8N-tZA_Mc'
|
||||
)
|
||||
|
||||
type Props = {
|
||||
darkMode: boolean
|
||||
}
|
||||
|
||||
function AuthComponentExample(props: Props) {
|
||||
const { darkMode } = props
|
||||
function AuthComponentExample() {
|
||||
const { isDarkMode } = useTheme()
|
||||
const { basePath } = useRouter()
|
||||
|
||||
// store API swiper instance
|
||||
@@ -91,9 +89,9 @@ function AuthComponentExample(props: Props) {
|
||||
<Space size={3} direction="vertical">
|
||||
<img
|
||||
src={
|
||||
darkMode
|
||||
? `${basePath}/brand-assets/supabase-logo-wordmark--light.svg`
|
||||
: `${basePath}/brand-assets/supabase-logo-wordmark--dark.svg`
|
||||
isDarkMode
|
||||
? `${basePath}/brand-assets/supabase-logo-wordmark--dark.svg`
|
||||
: `${basePath}/brand-assets/supabase-logo-wordmark--light.svg`
|
||||
}
|
||||
width="96"
|
||||
alt="Logo"
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
interface Props {
|
||||
darkMode: boolean
|
||||
updateTheme: Function
|
||||
}
|
||||
import { useTheme } from '~/components/Providers'
|
||||
|
||||
const SunEmoji = () => (
|
||||
<svg width="32" height="32" fill="none">
|
||||
@@ -44,12 +39,15 @@ const MoonEmoji = () => (
|
||||
</svg>
|
||||
)
|
||||
|
||||
function DarkModeToggle(props: Props) {
|
||||
const { darkMode, updateTheme } = props
|
||||
function DarkModeToggle() {
|
||||
const { isDarkMode, toggleTheme } = useTheme()
|
||||
|
||||
const toggleDarkMode = () => {
|
||||
localStorage.setItem('supabaseDarkMode', (!darkMode).toString())
|
||||
updateTheme(!darkMode)
|
||||
localStorage.setItem('supabaseDarkMode', (!isDarkMode).toString())
|
||||
toggleTheme()
|
||||
|
||||
const key = localStorage.getItem('supabaseDarkMode')
|
||||
document.documentElement.className = key === 'true' ? 'dark' : ''
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -61,7 +59,7 @@ function DarkModeToggle(props: Props) {
|
||||
className={`
|
||||
relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer
|
||||
transition-colors ease-in-out duration-200 focus:outline-none ${
|
||||
darkMode ? 'bg-dark-500' : 'bg-gray-200'
|
||||
isDarkMode ? 'bg-dark-500' : 'bg-gray-200'
|
||||
} mx-5
|
||||
`}
|
||||
onClick={() => toggleDarkMode()}
|
||||
@@ -70,7 +68,9 @@ function DarkModeToggle(props: Props) {
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className={`
|
||||
${darkMode ? 'translate-x-5' : 'translate-x-0'} inline-block h-5 w-5 rounded-full
|
||||
${
|
||||
isDarkMode ? 'translate-x-5' : 'translate-x-0'
|
||||
} inline-block h-5 w-5 rounded-full
|
||||
bg-white dark:bg-dark-700 shadow-lg transform ring-0 transition ease-in-out duration-200
|
||||
`}
|
||||
/>
|
||||
@@ -79,4 +79,5 @@ function DarkModeToggle(props: Props) {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DarkModeToggle
|
||||
@@ -3,15 +3,11 @@ import FooterLinks from 'data/Footer.json'
|
||||
import SectionContainer from '../Layouts/SectionContainer'
|
||||
import DarkModeToggle from '../DarkModeToggle'
|
||||
import Link from 'next/link'
|
||||
import { useTheme } from '../Providers'
|
||||
|
||||
type Props = {
|
||||
darkMode: boolean
|
||||
updateTheme: Function
|
||||
}
|
||||
|
||||
const Footer = (props: Props) => {
|
||||
const Footer = () => {
|
||||
const { basePath } = useRouter()
|
||||
const { darkMode, updateTheme } = props
|
||||
const { isDarkMode } = useTheme()
|
||||
|
||||
return (
|
||||
<footer
|
||||
@@ -29,7 +25,7 @@ const Footer = (props: Props) => {
|
||||
<img
|
||||
className="w-40"
|
||||
src={
|
||||
darkMode
|
||||
isDarkMode
|
||||
? `${basePath}/brand-assets/supabase-logo-wordmark--dark.svg`
|
||||
: `${basePath}/brand-assets/supabase-logo-wordmark--light.svg`
|
||||
}
|
||||
@@ -37,7 +33,7 @@ const Footer = (props: Props) => {
|
||||
/>
|
||||
</a>
|
||||
</Link>
|
||||
<div className="flex space-x-6">
|
||||
<div className="flex space-x-5">
|
||||
<a href="https://twitter.com/supabase" className="text-gray-300 hover:text-gray-400">
|
||||
<span className="sr-only">Twitter</span>
|
||||
<svg className="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
@@ -66,6 +62,21 @@ const Footer = (props: Props) => {
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://youtube.com/c/supabase"
|
||||
className="text-gray-300 hover:text-gray-400"
|
||||
>
|
||||
<span className="sr-only">Youtube</span>
|
||||
<svg
|
||||
className="h-6 w-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 576 512"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-12 grid grid-cols-1 gap-8 xl:mt-0 xl:col-span-2">
|
||||
@@ -105,7 +116,7 @@ const Footer = (props: Props) => {
|
||||
<p className="mb-0 self-center text-base text-gray-400 dark:text-dark-400">
|
||||
© Supabase Inc
|
||||
</p>
|
||||
<DarkModeToggle darkMode={darkMode} updateTheme={updateTheme} />
|
||||
<DarkModeToggle />
|
||||
</div>
|
||||
</SectionContainer>
|
||||
</footer>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import Nav from 'components/Nav/index'
|
||||
import Footer from 'components/Footer/index'
|
||||
|
||||
@@ -10,28 +10,19 @@ type Props = {
|
||||
|
||||
const DefaultLayout = (props: Props) => {
|
||||
const { hideHeader = false, hideFooter = false, children } = props
|
||||
const [darkMode, setDarkMode] = useState<boolean>(true)
|
||||
|
||||
useEffect(() => {
|
||||
const isDarkMode = localStorage.getItem('supabaseDarkMode')
|
||||
if (isDarkMode) {
|
||||
setDarkMode(isDarkMode === 'true')
|
||||
document.documentElement.className = isDarkMode === 'true' ? 'dark' : ''
|
||||
}
|
||||
const key = localStorage.getItem('supabaseDarkMode')
|
||||
document.documentElement.className = key === 'true' ? 'dark' : ''
|
||||
}, [])
|
||||
|
||||
const updateTheme = (isDarkMode: boolean) => {
|
||||
document.documentElement.className = isDarkMode ? 'dark' : ''
|
||||
setDarkMode(isDarkMode)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{!hideHeader && <Nav darkMode={darkMode} />}
|
||||
{!hideHeader && <Nav />}
|
||||
<div className="min-h-screen bg-white dark:bg-gray-800">
|
||||
<main>{children}</main>
|
||||
</div>
|
||||
{!hideFooter && <Footer darkMode={darkMode} updateTheme={updateTheme} />}
|
||||
{!hideFooter && <Footer />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,13 +12,11 @@ import Solutions from '~/components/Nav/Product'
|
||||
import Developers from '~/components/Nav/Developers'
|
||||
import Announcement from '~/components/Nav/Announcement'
|
||||
|
||||
type Props = {
|
||||
darkMode: boolean
|
||||
}
|
||||
import { useTheme } from '~/components/Providers'
|
||||
|
||||
const Nav = (props: Props) => {
|
||||
const Nav = () => {
|
||||
const { basePath } = useRouter()
|
||||
const { darkMode } = props
|
||||
const { isDarkMode } = useTheme()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const [openProduct, setOpenProduct] = useState(false)
|
||||
@@ -199,7 +197,7 @@ const Nav = (props: Props) => {
|
||||
<img
|
||||
className="block h-6 w-auto"
|
||||
src={
|
||||
darkMode
|
||||
isDarkMode
|
||||
? `${basePath}/brand-assets/supabase-logo-wordmark--dark.svg`
|
||||
: `${basePath}/brand-assets/supabase-logo-wordmark--light.svg`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { createContext, useContext, useEffect, useState } from 'react'
|
||||
|
||||
interface UseThemeProps {
|
||||
isDarkMode?: boolean
|
||||
toggleTheme: () => void
|
||||
}
|
||||
|
||||
interface ThemeProviderProps {
|
||||
children?: any
|
||||
}
|
||||
|
||||
export const ThemeContext = createContext<UseThemeProps>({
|
||||
isDarkMode: true,
|
||||
toggleTheme: () => {},
|
||||
})
|
||||
|
||||
export const useTheme = () => useContext(ThemeContext)
|
||||
|
||||
export const ThemeProvider = ({ children }: ThemeProviderProps) => {
|
||||
const [isDarkMode, setIsDarkMode] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const key = localStorage.getItem('supabaseDarkMode')
|
||||
setIsDarkMode(key === 'true')
|
||||
}, [])
|
||||
|
||||
const toggleTheme = () => {
|
||||
setIsDarkMode(!isDarkMode)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ThemeContext.Provider
|
||||
value={{
|
||||
isDarkMode,
|
||||
toggleTheme,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Generated
+103
-103
@@ -1841,9 +1841,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.0.9.tgz",
|
||||
"integrity": "sha512-oBlkyDop0Stf7MPIzETGv5r0YT/G/weBrknoPOUTaa5qwOeGjuy6gsOVc/SBtrBkOoBmRpD+fFhQJPvmo1mS+g=="
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.0.tgz",
|
||||
"integrity": "sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ=="
|
||||
},
|
||||
"node_modules/@next/mdx": {
|
||||
"version": "10.2.3",
|
||||
@@ -1855,9 +1855,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-android-arm64": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.0.9.tgz",
|
||||
"integrity": "sha512-aVqgsEn5plmUH2X58sjzhHsH/6majucWTMaaBEs7hHO2+GCwCZc7zaLH4XCBMKPES9Yaja8/pYUbvZQE9DqgFw==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz",
|
||||
"integrity": "sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1870,9 +1870,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.0.9.tgz",
|
||||
"integrity": "sha512-uAgRKm4a2nVdyBiPPJokvmDD1saugOvxljz9ld2ih0CCg5S9vBhqaj3kPGCQBj9hSu3q+Lng2CHnQqG3ga1jzA==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz",
|
||||
"integrity": "sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1885,9 +1885,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.0.9.tgz",
|
||||
"integrity": "sha512-fDOs2lZIyrAdU18IxMA5orBPn9qLbOdu55gXSTNZOhyRJ8ugtbUAejsK7OL0boJy0CCHPAdVRXm01Mwk8tZ9RQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz",
|
||||
"integrity": "sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1900,9 +1900,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm-gnueabihf": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.0.9.tgz",
|
||||
"integrity": "sha512-/ni0p9DBvATUML9RQ1ycQuf05uOYKdzA6iI8+eRsARjpGbFVUFbge7XPzlj9g2Q9YWgoN8CSjFGnKRlyky5uHA==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz",
|
||||
"integrity": "sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1915,9 +1915,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.0.9.tgz",
|
||||
"integrity": "sha512-AphxilJDf95rUxJDHgM9Ww1DaYXZWqTvoKwXeej/0SgSvICcRZrLaFDrkojdXz0Rxr4igX2OdYR1S4/Hj1jWOQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz",
|
||||
"integrity": "sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1930,9 +1930,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.0.9.tgz",
|
||||
"integrity": "sha512-K5jbvNNzF3mRjWmPdxP5Bg87i7FHivfBj/L0KJlxpkLSC8sffBJDmB6jtMnI7wiPj9J6vmLkbGtSosln78xAlQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz",
|
||||
"integrity": "sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1945,9 +1945,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.0.9.tgz",
|
||||
"integrity": "sha512-bJZ9bkMkQzsY+UyWezEZ77GWQ4TzwKeXdayX3U3+aEkL8k5C6eKBXlidWdrhu0teLmaUXIyWerWrLnJzwGXdfw==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz",
|
||||
"integrity": "sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1960,9 +1960,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.0.9.tgz",
|
||||
"integrity": "sha512-SR9p0R+v1T32DTXPVAXZw31pmJAkSDotC6Afy+mfC0xrEL3pp95R8sGXYAAUCEPkQp0MEeUOVy2LrToe92X7hQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz",
|
||||
"integrity": "sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1975,9 +1975,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.0.9.tgz",
|
||||
"integrity": "sha512-mzQ1A8vfHhJrvEy5KJZGZWEByXthyKfWofvFaf+oo/5nJl/0Bz1ODP2ajSmbLG++77Eo2AROgbm9pkW1ucvG2A==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz",
|
||||
"integrity": "sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1990,9 +1990,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.0.9.tgz",
|
||||
"integrity": "sha512-MpD2vj1zjo1u3J3wiz3pEKse19Etz+P0GL6XfQkB/9a84vJQ1JWMaWBjmIdivzZv718Il2pRSSx8hymwPfguYQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz",
|
||||
"integrity": "sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -2005,9 +2005,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.0.9.tgz",
|
||||
"integrity": "sha512-1c/sxp/4Qz4F6rCxiYqAnrmghCOFt5hHZ9Kd+rXFW5Mqev4C4XDOUMHdBH55HgnJZqngYhOE0r/XNkCtsIojig==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz",
|
||||
"integrity": "sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -5443,11 +5443,11 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-12.0.9.tgz",
|
||||
"integrity": "sha512-omfYqoR/DvbdOIJ6SS1unKJ4mGIxUPs0RPa7wr/Mft22OCKgJhuG+aI9KFYi5ZJBwoFQk1vqaMKpWz5qr+dN0Q==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-12.1.0.tgz",
|
||||
"integrity": "sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==",
|
||||
"dependencies": {
|
||||
"@next/env": "12.0.9",
|
||||
"@next/env": "12.1.0",
|
||||
"caniuse-lite": "^1.0.30001283",
|
||||
"postcss": "8.4.5",
|
||||
"styled-jsx": "5.0.0",
|
||||
@@ -5460,21 +5460,21 @@
|
||||
"node": ">=12.22.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-android-arm64": "12.0.9",
|
||||
"@next/swc-darwin-arm64": "12.0.9",
|
||||
"@next/swc-darwin-x64": "12.0.9",
|
||||
"@next/swc-linux-arm-gnueabihf": "12.0.9",
|
||||
"@next/swc-linux-arm64-gnu": "12.0.9",
|
||||
"@next/swc-linux-arm64-musl": "12.0.9",
|
||||
"@next/swc-linux-x64-gnu": "12.0.9",
|
||||
"@next/swc-linux-x64-musl": "12.0.9",
|
||||
"@next/swc-win32-arm64-msvc": "12.0.9",
|
||||
"@next/swc-win32-ia32-msvc": "12.0.9",
|
||||
"@next/swc-win32-x64-msvc": "12.0.9"
|
||||
"@next/swc-android-arm64": "12.1.0",
|
||||
"@next/swc-darwin-arm64": "12.1.0",
|
||||
"@next/swc-darwin-x64": "12.1.0",
|
||||
"@next/swc-linux-arm-gnueabihf": "12.1.0",
|
||||
"@next/swc-linux-arm64-gnu": "12.1.0",
|
||||
"@next/swc-linux-arm64-musl": "12.1.0",
|
||||
"@next/swc-linux-x64-gnu": "12.1.0",
|
||||
"@next/swc-linux-x64-musl": "12.1.0",
|
||||
"@next/swc-win32-arm64-msvc": "12.1.0",
|
||||
"@next/swc-win32-ia32-msvc": "12.1.0",
|
||||
"@next/swc-win32-x64-msvc": "12.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"fibers": ">= 3.1.0",
|
||||
"node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0",
|
||||
"node-sass": "^6.0.0 || ^7.0.0",
|
||||
"react": "^17.0.2 || ^18.0.0-0",
|
||||
"react-dom": "^17.0.2 || ^18.0.0-0",
|
||||
"sass": "^1.3.0"
|
||||
@@ -10525,9 +10525,9 @@
|
||||
"integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA=="
|
||||
},
|
||||
"@next/env": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.0.9.tgz",
|
||||
"integrity": "sha512-oBlkyDop0Stf7MPIzETGv5r0YT/G/weBrknoPOUTaa5qwOeGjuy6gsOVc/SBtrBkOoBmRpD+fFhQJPvmo1mS+g=="
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.0.tgz",
|
||||
"integrity": "sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ=="
|
||||
},
|
||||
"@next/mdx": {
|
||||
"version": "10.2.3",
|
||||
@@ -10536,69 +10536,69 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@next/swc-android-arm64": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.0.9.tgz",
|
||||
"integrity": "sha512-aVqgsEn5plmUH2X58sjzhHsH/6majucWTMaaBEs7hHO2+GCwCZc7zaLH4XCBMKPES9Yaja8/pYUbvZQE9DqgFw==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz",
|
||||
"integrity": "sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-arm64": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.0.9.tgz",
|
||||
"integrity": "sha512-uAgRKm4a2nVdyBiPPJokvmDD1saugOvxljz9ld2ih0CCg5S9vBhqaj3kPGCQBj9hSu3q+Lng2CHnQqG3ga1jzA==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz",
|
||||
"integrity": "sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-darwin-x64": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.0.9.tgz",
|
||||
"integrity": "sha512-fDOs2lZIyrAdU18IxMA5orBPn9qLbOdu55gXSTNZOhyRJ8ugtbUAejsK7OL0boJy0CCHPAdVRXm01Mwk8tZ9RQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz",
|
||||
"integrity": "sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm-gnueabihf": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.0.9.tgz",
|
||||
"integrity": "sha512-/ni0p9DBvATUML9RQ1ycQuf05uOYKdzA6iI8+eRsARjpGbFVUFbge7XPzlj9g2Q9YWgoN8CSjFGnKRlyky5uHA==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz",
|
||||
"integrity": "sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-gnu": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.0.9.tgz",
|
||||
"integrity": "sha512-AphxilJDf95rUxJDHgM9Ww1DaYXZWqTvoKwXeej/0SgSvICcRZrLaFDrkojdXz0Rxr4igX2OdYR1S4/Hj1jWOQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz",
|
||||
"integrity": "sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-arm64-musl": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.0.9.tgz",
|
||||
"integrity": "sha512-K5jbvNNzF3mRjWmPdxP5Bg87i7FHivfBj/L0KJlxpkLSC8sffBJDmB6jtMnI7wiPj9J6vmLkbGtSosln78xAlQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz",
|
||||
"integrity": "sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-x64-gnu": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.0.9.tgz",
|
||||
"integrity": "sha512-bJZ9bkMkQzsY+UyWezEZ77GWQ4TzwKeXdayX3U3+aEkL8k5C6eKBXlidWdrhu0teLmaUXIyWerWrLnJzwGXdfw==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz",
|
||||
"integrity": "sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-linux-x64-musl": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.0.9.tgz",
|
||||
"integrity": "sha512-SR9p0R+v1T32DTXPVAXZw31pmJAkSDotC6Afy+mfC0xrEL3pp95R8sGXYAAUCEPkQp0MEeUOVy2LrToe92X7hQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz",
|
||||
"integrity": "sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-arm64-msvc": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.0.9.tgz",
|
||||
"integrity": "sha512-mzQ1A8vfHhJrvEy5KJZGZWEByXthyKfWofvFaf+oo/5nJl/0Bz1ODP2ajSmbLG++77Eo2AROgbm9pkW1ucvG2A==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz",
|
||||
"integrity": "sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-ia32-msvc": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.0.9.tgz",
|
||||
"integrity": "sha512-MpD2vj1zjo1u3J3wiz3pEKse19Etz+P0GL6XfQkB/9a84vJQ1JWMaWBjmIdivzZv718Il2pRSSx8hymwPfguYQ==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz",
|
||||
"integrity": "sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q==",
|
||||
"optional": true
|
||||
},
|
||||
"@next/swc-win32-x64-msvc": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.0.9.tgz",
|
||||
"integrity": "sha512-1c/sxp/4Qz4F6rCxiYqAnrmghCOFt5hHZ9Kd+rXFW5Mqev4C4XDOUMHdBH55HgnJZqngYhOE0r/XNkCtsIojig==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz",
|
||||
"integrity": "sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg==",
|
||||
"optional": true
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
@@ -13241,22 +13241,22 @@
|
||||
"peer": true
|
||||
},
|
||||
"next": {
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-12.0.9.tgz",
|
||||
"integrity": "sha512-omfYqoR/DvbdOIJ6SS1unKJ4mGIxUPs0RPa7wr/Mft22OCKgJhuG+aI9KFYi5ZJBwoFQk1vqaMKpWz5qr+dN0Q==",
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-12.1.0.tgz",
|
||||
"integrity": "sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q==",
|
||||
"requires": {
|
||||
"@next/env": "12.0.9",
|
||||
"@next/swc-android-arm64": "12.0.9",
|
||||
"@next/swc-darwin-arm64": "12.0.9",
|
||||
"@next/swc-darwin-x64": "12.0.9",
|
||||
"@next/swc-linux-arm-gnueabihf": "12.0.9",
|
||||
"@next/swc-linux-arm64-gnu": "12.0.9",
|
||||
"@next/swc-linux-arm64-musl": "12.0.9",
|
||||
"@next/swc-linux-x64-gnu": "12.0.9",
|
||||
"@next/swc-linux-x64-musl": "12.0.9",
|
||||
"@next/swc-win32-arm64-msvc": "12.0.9",
|
||||
"@next/swc-win32-ia32-msvc": "12.0.9",
|
||||
"@next/swc-win32-x64-msvc": "12.0.9",
|
||||
"@next/env": "12.1.0",
|
||||
"@next/swc-android-arm64": "12.1.0",
|
||||
"@next/swc-darwin-arm64": "12.1.0",
|
||||
"@next/swc-darwin-x64": "12.1.0",
|
||||
"@next/swc-linux-arm-gnueabihf": "12.1.0",
|
||||
"@next/swc-linux-arm64-gnu": "12.1.0",
|
||||
"@next/swc-linux-arm64-musl": "12.1.0",
|
||||
"@next/swc-linux-x64-gnu": "12.1.0",
|
||||
"@next/swc-linux-x64-musl": "12.1.0",
|
||||
"@next/swc-win32-arm64-msvc": "12.1.0",
|
||||
"@next/swc-win32-ia32-msvc": "12.1.0",
|
||||
"@next/swc-win32-x64-msvc": "12.1.0",
|
||||
"caniuse-lite": "^1.0.30001283",
|
||||
"postcss": "8.4.5",
|
||||
"styled-jsx": "5.0.0",
|
||||
|
||||
+6
-8
@@ -6,13 +6,11 @@ import { Button, Typography } from '@supabase/ui'
|
||||
|
||||
import DefaultLayout from '../components/Layouts/Default'
|
||||
|
||||
type Props = {
|
||||
darkMode: boolean
|
||||
}
|
||||
import { useTheme } from '~/components/Providers'
|
||||
|
||||
const Error404 = (props: Props) => {
|
||||
const Error404 = () => {
|
||||
const [show404, setShow404] = useState<boolean>(false)
|
||||
const { darkMode } = props
|
||||
const { isDarkMode } = useTheme()
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
@@ -30,9 +28,9 @@ const Error404 = (props: Props) => {
|
||||
<a href="/">
|
||||
<Image
|
||||
src={
|
||||
darkMode
|
||||
? '/images/supabase-logo-wordmark--light.svg'
|
||||
: '/images/supabase-logo-wordmark--dark.svg'
|
||||
isDarkMode
|
||||
? '/images/supabase-logo-wordmark--dark.svg'
|
||||
: '/images/supabase-logo-wordmark--light.svg'
|
||||
}
|
||||
alt=""
|
||||
height={24}
|
||||
|
||||
+4
-1
@@ -6,6 +6,7 @@ import { useEffect } from 'react'
|
||||
import Meta from '~/components/Favicons'
|
||||
import '../styles/index.css'
|
||||
import { post } from './../lib/fetchWrapper'
|
||||
import { ThemeProvider } from '~/components/Providers'
|
||||
|
||||
export default function MyApp({ Component, pageProps }: AppProps) {
|
||||
const router = useRouter()
|
||||
@@ -66,7 +67,9 @@ export default function MyApp({ Component, pageProps }: AppProps) {
|
||||
cardType: 'summary_large_image',
|
||||
}}
|
||||
/>
|
||||
<Component {...pageProps} />
|
||||
<ThemeProvider>
|
||||
<Component {...pageProps} />
|
||||
</ThemeProvider>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -30,13 +30,7 @@ import GithubExamples from '~/components/Sections/GithubExamples'
|
||||
import ProductHeader from '~/components/Sections/ProductHeader'
|
||||
import AuthProviders from '~/data/auth.json'
|
||||
|
||||
type Props = {
|
||||
darkMode: boolean
|
||||
}
|
||||
|
||||
function AuthPage(props: Props) {
|
||||
const { darkMode } = props
|
||||
|
||||
function AuthPage() {
|
||||
// base path for images
|
||||
const { basePath } = useRouter()
|
||||
|
||||
@@ -262,7 +256,7 @@ function AuthPage(props: Props) {
|
||||
<SectionContainer>
|
||||
<div className="grid grid-cols-12 lg:gap-16">
|
||||
<div className="order-last col-span-12 lg:order-first lg:col-span-6 mt-8 lg:mt-0">
|
||||
<AuthComponentExample darkMode={darkMode} />
|
||||
<AuthComponentExample />
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-6 lg:col-start-7 xl:col-span-4 xl:col-start-8">
|
||||
<Space className="mb-4">
|
||||
|
||||
Reference in new issue
Block a user