diff --git a/apps/www/data/Community.tsx b/apps/www/data/Community.tsx
index 618092900c6..1da7c6df686 100644
--- a/apps/www/data/Community.tsx
+++ b/apps/www/data/Community.tsx
@@ -30,7 +30,7 @@ const data: CommunityItem[] = [
},
{
title: 'GitHub',
- stat: '32,000+',
+ stat: '34,000+',
statLabel: 'GitHub stars',
img: 'github.png',
invertImgDarkMode: true,
@@ -42,7 +42,7 @@ const data: CommunityItem[] = [
},
{
title: 'Twitter',
- stat: '30,000+',
+ stat: '32,000+',
statLabel: 'Followers',
img: 'twitter.png',
detail: () => (
@@ -54,7 +54,7 @@ const data: CommunityItem[] = [
{
title: 'Discord',
stat: '6,000+',
- statLabel: 'SuperTroopers',
+ statLabel: 'SupaTroopers',
img: 'discord.png',
detail: () => (
diff --git a/apps/www/data/Press.ts b/apps/www/data/Press.ts
index 43f1e2aeb27..598c3e712d6 100644
--- a/apps/www/data/Press.ts
+++ b/apps/www/data/Press.ts
@@ -14,39 +14,63 @@ const data: PressItem[] = [
},
{
type: 'article',
- href: 'https://techcrunch.com/2021/09/09/supabase-raises-30m-for-its-open-source-insta-backend',
- title: 'Open source backend-as-a-service startup Supabase raises $30M',
- publisher: 'TechCrunch',
+ href: 'https://www.prnewswire.com/news-releases/supabase-announces-80-million-series-b-led-by-felicis-301544453.html',
+ title: 'Supabase Announces $80 Million Series B Led by Felicis',
+ publisher: 'PR Newswire',
},
{
type: 'article',
- href: 'https://techcrunch.com/2020/12/15/supabase-raises-6m-for-its-open-source-firebase-alternative',
- title: 'Supabase raises $6M for its open-source Firebase alternative',
- publisher: 'TechCrunch',
+ href: 'https://medium.com/lightspeedindia/our-investment-in-supabase-2f443ff55aad',
+ title: 'Our investment in Supabase',
+ publisher: 'Medium',
},
{
type: 'podcast',
- href: 'https://softwareengineeringdaily.com/2020/10/15/supabase-open-source-firebase-with-paul-copplestone',
- title: 'Software Engineering Daily',
- publisher: 'Software Engineering Daily',
+ href: 'https://podcasts.apple.com/us/podcast/73-elixir-at-supabase-with-paul-copplestone/id1516100616?i=1000542087899',
+ title: 'Elixir at Supabase with Paul Copplestone',
+ publisher: 'Thinking Elixir Podcast',
+ },
+ {
+ type: 'podcast',
+ href: 'https://podcasts.apple.com/us/podcast/73-elixir-at-supabase-with-paul-copplestone/id1516100616?i=1000542087899',
+ title: 'Ant Wilson on Supabase ',
+ publisher: 'Software Engineering Radio',
+ },
+ {
+ type: 'podcast',
+ href: 'https://podcasts.apple.com/us/podcast/78-logflare-with-chase-granberry/id1516100616?i=1000545628124',
+ title: 'Logflare with Chase Granberry',
+ publisher: 'Thinking Elixir Podcast',
+ },
+ {
+ type: 'podcast',
+ href: 'https://stackoverflow.blog/2022/05/17/open-source-is-winning-over-developers-and-investors-ep-442/',
+ title: 'Open-source is winning over developers and investors',
+ publisher: 'Stackoverflow',
+ },
+ {
+ type: 'podcast',
+ href: 'https://changelog.com/podcast/476',
+ title: 'Supabase is all in on Postgres',
+ publisher: 'changelog',
},
{
type: 'podcast',
href: 'https://fsjam.org/episodes/episode-33-supabase-with-paul-copplestone',
- title: 'FS Jam',
+ title: 'Supabase with Paul Copplestone',
publisher: 'FS Jam',
},
{
type: 'podcast',
- href: 'https://www.heavybit.com/library/podcasts/jamstack-radio/ep-71-open-source-firebase-alternative-with-paul-copplestone-of-supabase',
- title: 'Jamstack Radio',
- publisher: 'Heavybit',
+ href: 'https://www.heavybit.com/library/podcasts/jamstack-radio/ep-71-open-source-firebase-alternative-with-paul-copplestone-of-supabase/',
+ title: 'Open Source Firebase Alternative with Paul Copplestone of Supabase',
+ publisher: 'Jamstack',
},
{
type: 'podcast',
href: 'https://podrocket.logrocket.com/9',
- title: 'PodRocket',
- publisher: 'LogRocket',
+ title: 'Supabase with Paul Copplestone',
+ publisher: 'Podrocket',
},
]
diff --git a/apps/www/pages/company.tsx b/apps/www/pages/company.tsx
index 7563952bb65..ff673e8de4e 100644
--- a/apps/www/pages/company.tsx
+++ b/apps/www/pages/company.tsx
@@ -15,6 +15,7 @@ import InvestorData from 'data/Investors'
import TeamData from 'data/Team'
import Image from 'next/image'
+import Link from 'next/link'
import {
Button,
@@ -313,30 +314,38 @@ const Press = () => {
diff --git a/apps/www/styles/index.css b/apps/www/styles/index.css
index 13b6b8b6e55..163baf6c97c 100644
--- a/apps/www/styles/index.css
+++ b/apps/www/styles/index.css
@@ -242,3 +242,10 @@ table {
position: relative !important;
height: unset !important;
}
+
+.line-clamp {
+ display: -webkit-box;
+ margin: 0 auto;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+}
diff --git a/studio/components/grid/SupabaseGrid.tsx b/studio/components/grid/SupabaseGrid.tsx
index 4f192d036d5..6a09b66a572 100644
--- a/studio/components/grid/SupabaseGrid.tsx
+++ b/studio/components/grid/SupabaseGrid.tsx
@@ -1,40 +1,33 @@
-import React from 'react';
-import { createPortal } from 'react-dom';
-import { useMonaco } from '@monaco-editor/react';
-import { DndProvider } from 'react-dnd';
-import { HTML5Backend } from 'react-dnd-html5-backend';
-import { Dictionary, SupabaseGridProps, SupabaseGridRef } from './types';
-import { DataGridHandle } from '@supabase/react-data-grid';
-import { RowContextMenu } from './components/menu';
-import { StoreProvider, useDispatch, useTrackedState } from './store';
-import { fetchCount, fetchPage, refreshPageDebounced } from './utils';
-import { REFRESH_PAGE_IMMEDIATELY, TOTAL_ROWS_RESET } from './constants';
-import { Grid } from './components/grid';
-import { Shortcuts } from './components/common';
-import Header from './components/header';
-import Footer from './components/footer';
-import {
- cleanupProps,
- initTable,
- saveStorageDebounced,
-} from './SupabaseGrid.utils';
+import { useEffect, useState, useRef, forwardRef, useImperativeHandle } from 'react'
+import { createPortal } from 'react-dom'
+import { useMonaco } from '@monaco-editor/react'
+import { DndProvider } from 'react-dnd'
+import { HTML5Backend } from 'react-dnd-html5-backend'
+import { Dictionary, SupabaseGridProps, SupabaseGridRef } from './types'
+import { DataGridHandle } from '@supabase/react-data-grid'
+import { RowContextMenu } from './components/menu'
+import { StoreProvider, useDispatch, useTrackedState } from './store'
+import { fetchCount, fetchPage, refreshPageDebounced } from './utils'
+import { REFRESH_PAGE_IMMEDIATELY, TOTAL_ROWS_RESET } from './constants'
+import { Grid } from './components/grid'
+import { Shortcuts } from './components/common'
+import Header from './components/header'
+import Footer from './components/footer'
+import { cleanupProps, initTable, saveStorageDebounced } from './SupabaseGrid.utils'
/**
* Supabase Grid.
*
* React component to render database table.
*/
-export const SupabaseGrid = React.forwardRef<
- SupabaseGridRef,
- SupabaseGridProps
->((props, ref) => {
- const monaco = useMonaco();
- const _props = cleanupProps(props);
- const { theme } = _props;
+export const SupabaseGrid = forwardRef((props, ref) => {
+ const monaco = useMonaco()
+ const _props = cleanupProps(props)
+ const { theme } = _props
- React.useEffect(() => {
+ useEffect(() => {
if (monaco) {
- const darkTheme = theme && theme === 'dark' ? true : false;
+ const darkTheme = theme && theme === 'dark' ? true : false
monaco.editor.defineTheme('supabase', {
base: 'vs-dark', // can also be vs-dark or hc-black
@@ -47,9 +40,9 @@ export const SupabaseGrid = React.forwardRef<
colors: {
'editor.background': darkTheme ? '#1f1f1f' : '#30313f',
},
- });
+ })
}
- }, [monaco]);
+ }, [monaco])
return (
@@ -57,103 +50,101 @@ export const SupabaseGrid = React.forwardRef<
- );
-});
+ )
+})
-const SupabaseGridLayout = React.forwardRef(
- (props, ref) => {
- const { editable, storageRef, gridProps, headerActions } = props;
- const dispatch = useDispatch();
- const state = useTrackedState();
- const gridRef = React.useRef(null);
- const [mounted, setMount] = React.useState(false);
+const SupabaseGridLayout = forwardRef((props, ref) => {
+ const { editable, storageRef, gridProps, headerActions } = props
+ const dispatch = useDispatch()
+ const state = useTrackedState()
+ const gridRef = useRef(null)
+ const [mounted, setMount] = useState(false)
- React.useImperativeHandle(ref, () => ({
- rowAdded(row: Dictionary) {
- dispatch({
- type: 'ADD_NEW_ROW',
- payload: row,
- });
- },
- rowEdited(row: Dictionary, idx: number) {
- dispatch({
- type: 'EDIT_ROW',
- payload: { row, idx },
- });
- },
- }));
+ useImperativeHandle(ref, () => ({
+ rowAdded(row: Dictionary) {
+ dispatch({
+ type: 'ADD_NEW_ROW',
+ payload: row,
+ })
+ },
+ rowEdited(row: Dictionary, idx: number) {
+ dispatch({
+ type: 'EDIT_ROW',
+ payload: { row, idx },
+ })
+ },
+ }))
- React.useEffect(() => {
- if (!mounted) setMount(true);
- }, []);
+ useEffect(() => {
+ if (!mounted) setMount(true)
+ }, [])
- React.useEffect(() => {
- if (state.isInitialComplete && storageRef && state.table) {
- saveStorageDebounced(state, storageRef);
- }
- }, [
- state.table,
- state.isInitialComplete,
- state.gridColumns,
- state.sorts,
- state.filters,
- storageRef,
- ]);
+ useEffect(() => {
+ if (state.isInitialComplete && storageRef && state.table) {
+ saveStorageDebounced(state, storageRef)
+ }
+ }, [
+ state.table,
+ state.isInitialComplete,
+ state.gridColumns,
+ state.sorts,
+ state.filters,
+ storageRef,
+ ])
- React.useEffect(() => {
- if (state.refreshPageFlag == REFRESH_PAGE_IMMEDIATELY) {
- fetchPage(state, dispatch);
- } else if (state.refreshPageFlag != 0) {
- refreshPageDebounced(state, dispatch);
- }
- }, [state.refreshPageFlag]);
+ useEffect(() => {
+ if (state.refreshPageFlag == REFRESH_PAGE_IMMEDIATELY) {
+ fetchPage(state, dispatch)
+ } else if (state.refreshPageFlag != 0) {
+ refreshPageDebounced(state, dispatch)
+ }
+ }, [state.refreshPageFlag])
- React.useEffect(() => {
- if (state.totalRows === TOTAL_ROWS_RESET) {
- fetchCount(state, dispatch);
- }
- }, [state.totalRows]);
+ useEffect(() => {
+ if (state.totalRows === TOTAL_ROWS_RESET) {
+ fetchCount(state, dispatch)
+ }
+ }, [state.totalRows])
- React.useEffect(() => {
- if (!state.metaService) {
- dispatch({
- type: 'INIT_CLIENT',
- payload: { onSqlQuery: props.onSqlQuery },
- });
- dispatch({
- type: 'INIT_CALLBACK',
- payload: { ...props },
- });
- }
- }, [state.metaService]);
+ useEffect(() => {
+ if (!state.metaService) {
+ dispatch({
+ type: 'INIT_CLIENT',
+ payload: { onSqlQuery: props.onSqlQuery },
+ })
+ dispatch({
+ type: 'INIT_CALLBACK',
+ payload: { ...props },
+ })
+ }
+ }, [state.metaService])
- React.useEffect(() => {
- if (!state.metaService) return;
+ useEffect(() => {
+ if (!state.metaService) return
- if (
- !state.table ||
- (typeof props.table == 'string' &&
- state.table!.name != props.table &&
- state.table!.schema != props.schema) ||
- (typeof props.table != 'string' &&
- JSON.stringify(props.table) !== JSON.stringify(state.table))
- ) {
- initTable(props, state, dispatch);
- }
- }, [state.metaService, state.table, props.table, props.schema]);
+ if (
+ !state.table ||
+ (typeof props.table == 'string' &&
+ state.table!.name != props.table &&
+ state.table!.schema != props.schema) ||
+ (typeof props.table != 'string' &&
+ JSON.stringify(props.table) !== JSON.stringify(state.table))
+ ) {
+ initTable(props, state, dispatch)
+ }
+ }, [state.metaService, state.table, props.table, props.schema])
- return (
-
-
-
-
-
- {mounted && createPortal(, document.body)}
-
- );
- }
-);
+ return (
+
+
+
+
+
+ {mounted && createPortal(, document.body)}
+
+ )
+})
diff --git a/studio/components/grid/components/common/ConfirmAlert.tsx b/studio/components/grid/components/common/ConfirmAlert.tsx
index d1e0dd7f03a..294e3916cc0 100644
--- a/studio/components/grid/components/common/ConfirmAlert.tsx
+++ b/studio/components/grid/components/common/ConfirmAlert.tsx
@@ -1,14 +1,14 @@
-import * as React from 'react';
-import { Button, Modal } from '@supabase/ui';
-import { render, unmountComponentAtNode } from 'react-dom';
+import * as React from 'react'
+import { Button, Modal } from '@supabase/ui'
+import { render, unmountComponentAtNode } from 'react-dom'
type ConfirmModalProps = {
- title: string;
- message: string;
- onConfirm?: () => void;
- onAsyncConfirm?: () => Promise;
- variant?: 'danger' | 'warning' | 'success' | undefined;
-};
+ title: string
+ message: string
+ onConfirm?: () => void
+ onAsyncConfirm?: () => Promise
+ variant?: 'danger' | 'warning' | 'success' | undefined
+}
const ConfirmModal: React.FC = ({
title,
message,
@@ -16,26 +16,26 @@ const ConfirmModal: React.FC = ({
onAsyncConfirm,
variant = 'danger',
}) => {
- const [loading, setLoading] = React.useState(false);
+ const [loading, setLoading] = React.useState(false)
function onCancelClick() {
- if (!loading) onClose();
+ if (!loading) onClose()
}
async function onConfirmClick() {
if (onAsyncConfirm) {
- setLoading(true);
- await onAsyncConfirm();
+ setLoading(true)
+ await onAsyncConfirm()
- onClose();
+ onClose()
} else if (onConfirm) {
- onConfirm();
- onClose();
+ onConfirm()
+ onClose()
}
}
function onClose() {
- removeElement();
+ removeElement()
}
return (
@@ -55,11 +55,7 @@ const ConfirmModal: React.FC = ({
-