From ba3db55dcf8f0dcb5a8eb830ab8cfb8ed8e22489 Mon Sep 17 00:00:00 2001 From: Waldemar Penner Date: Wed, 15 Dec 2021 08:54:44 +0100 Subject: [PATCH 01/77] Bugfix[#4490]: fix options toggle hover state --- .../RowEditor/JsonEditor/TwoOptionToggle.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/TwoOptionToggle.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/TwoOptionToggle.tsx index 708c43879ad..f487fe57301 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/TwoOptionToggle.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/TwoOptionToggle.tsx @@ -13,8 +13,12 @@ const TwoOptionToggle: FC = ({ onClickOption, borderOverride = 'border-gray-600 dark:border-gray-800', }) => { - const buttonStyle = `absolute top-0 z-1 text-xs inline-flex h-full items-center justify-center font-medium - hover:text-white focus:z-10 focus:outline-none focus:border-blue-300 focus:ring-blue active:bg-gray-100 + const buttonStyle = ( + isActive: boolean + ) => `absolute top-0 z-1 text-xs inline-flex h-full items-center justify-center font-medium + ${ + isActive ? 'hover:text-white' : 'hover:text-gray-600' + } dark:hover:text-white focus:z-10 focus:outline-none focus:border-blue-300 focus:ring-blue active:bg-gray-100 transition ease-in-out duration-150` return ( @@ -36,7 +40,7 @@ const TwoOptionToggle: FC = ({ className={` ${activeOption === option ? 'text-gray-200' : 'text-gray-400'} ${index === 0 ? 'right-0' : 'left-0'} - ${buttonStyle} + ${buttonStyle(activeOption === option)} cursor-pointer `} onClick={() => onClickOption(option)} From 30399667a1aa2b0824b4bd5d172e6ea71c0ad580 Mon Sep 17 00:00:00 2001 From: Benjamin Tan Date: Mon, 3 Jan 2022 15:31:59 +0800 Subject: [PATCH 02/77] studio: reduce Docker image size This switches to Alpine for generating the Docker image for the Studio. Additionally, the Studio is built first and unused dependencies and cache are removed. This reduces the uncompressed image size from ~1.7GB to ~600MB. Note: this has only been tested on an AMD64 machine. --- studio/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/studio/Dockerfile b/studio/Dockerfile index 3fe25f507a7..ae6c1ed9563 100644 --- a/studio/Dockerfile +++ b/studio/Dockerfile @@ -7,12 +7,12 @@ # docker builder prune -FROM node:14 as base +FROM node:14-alpine as base WORKDIR /usr/src/app # Do `npm ci` separately so we can cache `node_modules` # https://nodejs.org/en/docs/guides/nodejs-docker-webapp/ COPY package*.json ./ -RUN npm clean-install +RUN npm clean-install && npm cache clean --force COPY . . FROM base as dev @@ -20,6 +20,6 @@ EXPOSE 8082 CMD ["npm", "run", "dev"] FROM base as production -RUN npm run build +RUN npm run build && rm -rf .next/cache/webpack && npm prune --production EXPOSE 3000 CMD ["npm", "run", "start"] From 78336c6fcd903653d0098d78fb5a967a7d46934e Mon Sep 17 00:00:00 2001 From: Benjamin Tan Date: Fri, 7 Jan 2022 12:12:05 +0800 Subject: [PATCH 03/77] Switch to `node:14-slim` --- studio/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/Dockerfile b/studio/Dockerfile index ae6c1ed9563..89bce15872c 100644 --- a/studio/Dockerfile +++ b/studio/Dockerfile @@ -7,7 +7,7 @@ # docker builder prune -FROM node:14-alpine as base +FROM node:14-slim as base WORKDIR /usr/src/app # Do `npm ci` separately so we can cache `node_modules` # https://nodejs.org/en/docs/guides/nodejs-docker-webapp/ From b7a5dbd9b0b4c39abc0abc8bac45c476ab389204 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Mon, 10 Jan 2022 19:00:21 +0800 Subject: [PATCH 04/77] added failing test for LogPanel --- studio/tests/pages/projects/LogPanel.test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/studio/tests/pages/projects/LogPanel.test.js b/studio/tests/pages/projects/LogPanel.test.js index 35afe931a27..b18907e3b5c 100644 --- a/studio/tests/pages/projects/LogPanel.test.js +++ b/studio/tests/pages/projects/LogPanel.test.js @@ -54,3 +54,11 @@ test('reset search filter', async () => { expect(() => screen.getByTitle(/Clear search/)).toThrow() expect(() => screen.getByDisplayValue(/something123/)).toThrow() }) + +test('timestamp from filter', async () => { + render() + const dropdown = await screen.findByText(/Now/) + + // click the dropdown + throw Error('not impl') +}) From 026539b86abf8e305039e1b2711913fd4578c14e Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Mon, 10 Jan 2022 19:29:11 +0800 Subject: [PATCH 05/77] added additional assertions --- studio/tests/pages/projects/LogPanel.test.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/studio/tests/pages/projects/LogPanel.test.js b/studio/tests/pages/projects/LogPanel.test.js index b18907e3b5c..ec7f6a4fba5 100644 --- a/studio/tests/pages/projects/LogPanel.test.js +++ b/studio/tests/pages/projects/LogPanel.test.js @@ -58,7 +58,20 @@ test('reset search filter', async () => { test('timestamp from filter', async () => { render() const dropdown = await screen.findByText(/Now/) - + // click the dropdown throw Error('not impl') + + await screen.findByLabelText('From') + // display iso timestamp + const year = new Date().getFullYear() + await screen.findByDisplayValue(year) + + // input actions + await screen.findByRole('button', { name: /Clear input/ }) + const set = await screen.findByRole('button', { name: 'Set' }) + + userEvent.click(set) + await screen.findByRole('button', { name: /Custom/ }) + await screen.findByTitle('Clear timestamp filter') }) From 5926ab0f275adbc03eaeaea4397acbfbf516e865 Mon Sep 17 00:00:00 2001 From: Copple <10214025+kiwicopple@users.noreply.github.com> Date: Mon, 10 Jan 2022 20:54:27 +0100 Subject: [PATCH 06/77] -metamock up a blog post --- ...2022-12-10-supabase-beta-december-2021.mdx | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 www/_blog/2022-12-10-supabase-beta-december-2021.mdx diff --git a/www/_blog/2022-12-10-supabase-beta-december-2021.mdx b/www/_blog/2022-12-10-supabase-beta-december-2021.mdx new file mode 100644 index 00000000000..949fdfa4dd4 --- /dev/null +++ b/www/_blog/2022-12-10-supabase-beta-december-2021.mdx @@ -0,0 +1,114 @@ +--- +title: Supabase Beta December 2021 +description: New crypto extension, Postgres videos, and a bunch of cool integrations. +author: paul_copplestone +author_url: https://github.com/kiwicopple +author_image_url: https://github.com/kiwicopple.png +authorURL: https://github.com/kiwicopple +image: 2021-oct/release-oct-2021.jpg +thumb: 2021-oct/release-oct-2021-cover.jpg +tags: + - release-notes +date: '2022-12-10' +toc_depth: 3 +--- + +Happy 2022. We're looking forward to a year of shipping product and helping our users build great things! + +Here's a bunch of stuff we shipped throughout December... + +## Hackathon Winners + +We had a ton of awesome projects submitted for our Holiday Hackdays, all of the submissions are open source so come and check out the code for some of our top picks! + +## New crypto extension - pg_crypto + +We just added pg_sodium as an extension inside all postgres instances. +Which means you can easily do encryption, decryption, hashing, and cryptographic signing from within your postgres functions and queries. +Enable it from the Database > Extensions tab in the Supabase Dashboard. + +## PostgreSQL Videos + +### Call Postgres functions from JavaScript with RPC + +Jon Meyers walks you through how to write more complex queries and logic in your database, and invoke it via the API. + + + +### Call any API using PostgreSQL functions + +We recently added the ability to call any external HTTP endpoint from your postgres functions. Jon shows you how! + + + +### Create PostgreSQL Functions with Supabase + +Triggers allow you to execute SQL in response to any table changes. Learn how to write PostgreSQL triggers with Jon! + + + +## Community + +There was a lot of activity this month. + +### Divjoy integration + +Divjoy announced their Supabase Integration - The React codebase generator allows you to choose your stack, choose your template, and generate your codebase. + +### n8n + Supabase + +[n8n] added a Supabase node. + +TODO - https://twitter.com/n8n_io/status/1480502781320572931 + +### Python Upgrades + +The Community released a whole bunch of updated Python libs including: supabase v0.0.4 - gotrue v0.3.0 - realtime v0.0.4 - storage3 v0.1.0 + +See the full list of [community supported libs](https://github.com/supabase-community/). + +### GitHub + +We hit 20K stars!! 21,268 to be exact: [github.com/supabase/supabase](http://github.com/supabase/supabase) + +![GitHub](/images/blog/2021-oct/stars.png) + +Source: [repository.surf/supabase](https://repository.surf/supabase) + +Check out some of our other community stats in our latest [Series A Blog Post](/blog/2021/10/28/supabase-series-a). + +## Coming Next: Launch Week III + +TODO + +## Get started + +- Start using Supabase today: **[app.supabase.io](https://app.supabase.io/)** +- Make sure to **[star us on GitHub](https://github.com/supabase/supabase)** +- Follow us **[on Twitter](https://twitter.com/supabase)** +- Subscribe to our **[YouTube channel](https://www.youtube.com/channel/UCNTVzV1InxHV-YR0fSajqPQ)** +- Become a **[sponsor](https://github.com/sponsors/supabase)** From d153292c092ae01c2062defaa9f113a9384ebc8d Mon Sep 17 00:00:00 2001 From: Isaiah Hamilton Date: Tue, 11 Jan 2022 20:27:15 -0500 Subject: [PATCH 07/77] init react native quickstart --- web/docs/guides/with-react-native.mdx | 592 ++++++++++++++++++++++++++ web/sidebars.js | 1 + 2 files changed, 593 insertions(+) create mode 100644 web/docs/guides/with-react-native.mdx diff --git a/web/docs/guides/with-react-native.mdx b/web/docs/guides/with-react-native.mdx new file mode 100644 index 00000000000..9b1a8470f8e --- /dev/null +++ b/web/docs/guides/with-react-native.mdx @@ -0,0 +1,592 @@ +--- +id: with-react-native +title: "Quickstart: React Native" +description: Learn how to use Supabase in your React Native App. +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +## Intro + +This example provides the steps to build a simple user management app (from scratch!) using Supabase and React Native. It includes: + +- Supabase [Database](/docs/guides/database): a Postgres database for storing your user data. +- Supabase [Auth](/docs/guides/auth): users can sign in with magic links (no passwords, only email). +- Supabase [Storage](/docs/guides/storage): users can upload a photo. +- [Row Level Security](/docs/guides/auth#row-level-security): data is protected so that individuals can only access their own data. +- Instant [APIs](/docs/guides/api): APIs will be automatically generated when you create your database tables. + +By the end of this guide you'll have an app which allows users to login and update some basic profile details: + +![Supabase User Management example](/img/user-management-demo.png) + + + +## Project set up + +Before we start building we're going to set up our Database and API. This is as simple as starting a new Project in Supabase +and then creating a "schema" inside the database. + +### Create a project + +1. Go to [app.supabase.io](https://app.supabase.io). +1. Click on "New Project". +1. Enter your project details. +1. Wait for the new database to launch. + + +### Set up the database schema + +Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor, +or you can just copy/paste the SQL from below and run it yourself. + + + + +```sh +1. Go to the "SQL" section. +2. Click "User Management Starter". +3. Click "Run". +``` + + + + + + +```sql +-- Create a table for public "profiles" +create table profiles ( + id uuid references auth.users not null, + updated_at timestamp with time zone, + username text unique, + avatar_url text, + website text, + + primary key (id), + unique(username), + constraint username_length check (char_length(username) >= 3) +); + +alter table profiles enable row level security; + +create policy "Public profiles are viewable by everyone." + on profiles for select + using ( true ); + +create policy "Users can insert their own profile." + on profiles for insert + with check ( auth.uid() = id ); + +create policy "Users can update own profile." + on profiles for update + using ( auth.uid() = id ); + +-- Set up Realtime! +begin; + drop publication if exists supabase_realtime; + create publication supabase_realtime; +commit; +alter publication supabase_realtime add table profiles; + +-- Set up Storage! +insert into storage.buckets (id, name) +values ('avatars', 'avatars'); + +create policy "Avatar images are publicly accessible." + on storage.objects for select + using ( bucket_id = 'avatars' ); + +create policy "Anyone can upload an avatar." + on storage.objects for insert + with check ( bucket_id = 'avatars' ); + +``` + + + + + +### Get the API Keys + + +Now that you've created some database tables, you are ready to insert data using the auto-generated API. +We just need to get the URL and `anon` key from the API settings. + + + + +```sh +1. Go to the "Settings" section. +2. Click "API" in the sidebar. +3. Find your API URL in this page. +4. Find your "anon" and "service_role" keys on this page. +``` + + + + + + +## Building the App + +Let's start building the React Native app from scratch. + +### Initialize a React Naitve app + +We can use [`react-native`](https://reactnative.dev/blog/2016/11/08/introducing-button-yarn-and-a-public-roadmap#speed-up-react-native-init-using-yarn) to initialize +an app called `supabaseReactNative`: + +```bash +npx react-native init supabaseReactNative +cd supabaseReactNative +``` + +Then let's install the only additional dependency: [supabase-js](https://github.com/supabase/supabase-js) + +```bash +npm install @supabase/supabase-js +``` + +Now let's create a helper file to initialize the Supabase client. +We need the API URL and the `anon` key that you copied [earlier](#get-the-api-keys). +These variables will be exposed on the browser, and that's completely fine since we have +[Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database. + +```js title="lib/initSupabase.js" +import { createClient } from '@supabase/supabase-js' + +const supabaseUrl = YOUR_REACT_NATIVE_SUPABASE_URL +const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_ANON_KEY + +export const supabase = createClient(supabaseUrl, supabaseAnonKey) +``` + +### Set up a Login component + +Let's set up a React Native component to manage logins and sign ups. +We'll use Magic Links, so users can sign in with their email without using passwords. + +```jsx title="components/Auth.js" +import React, {useState} from 'react'; +import {Alert, StyleSheet, View} from 'react-native'; +import {Styles} from '../lib/constants'; +import {supabaseClient} from '../lib/initSupabase'; + +import {Button, Input} from 'react-native-elements'; + +export default function Auth() { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [loading, setLoading] = useState(''); + + const handleLogin = async type => { + setLoading(type); + const {error, user} = + type === 'LOGIN' + ? await supabaseClient.auth.signIn({email, password}) + : await supabaseClient.auth.signUp({email, password}); + console.log('Error: ', error); + console.log('User: ', user); + if (!error && user && type === 'SIGNUP') { + Alert.alert('Check your email for the login link!'); + } + if (error) { + Alert.alert(error.message); + } + setLoading(''); + }; + + return ( + + + setEmail(text)} + value={email} + placeholder="email@address.com" + autoCapitalize={'none'} + /> + + + setPassword(text)} + value={password} + secureTextEntry={true} + placeholder="Password" + autoCapitalize={'none'} + /> + + + + + + + + + + ) +} + +``` + + + +### Launch! + +Now that we have all the components in place, let's update `app.js`: + +```jsx title="app.js" +import { useState, useEffect } from 'react' +import { supabase } from './lib/supabaseClient' +import Auth from './components/Auth' +import Account from './components/Account' +import View from 'react-native' + +export default function App() { + const [session, setSession] = useState(null) + + useEffect(() => { + setSession(supabase.auth.session()) + + supabase.auth.onAuthStateChange((_event, session) => { + setSession(session) + }) + }, []) + + return ( + + {!session ? : } + + ) +} +``` + +Once that's done, run this in a terminal window: + +```bash +npx react-native run-ios +``` +or +```bash +npx react-native run-anroid +``` + +And then open the browser to [localhost:3000](http://localhost:3000) and you should see the completed app. + + +![Supabase User demo](/img/supabase-react-demo.png) + +## Bonus: Profile photos + +Every Supabase project is configured with [Storage](/docs/guides/storage) for managing large files like +photos and videos. + +### Create an upload widget + +Let's create an avatar for the user so that they can upload a profile photo. +We can start by creating a new component: + +```jsx title="components/Avatar.js" +import { useEffect, useState } from 'react' +import { supabase } from '../utils/supabaseClient' + +export default function Avatar({ url, size, onUpload }) { + const [avatarUrl, setAvatarUrl] = useState(null) + const [uploading, setUploading] = useState(false) + + useEffect(() => { + if (url) downloadImage(url) + }, [url]) + + async function downloadImage(path) { + try { + const { data, error } = await supabase.storage.from('avatars').download(path) + if (error) { + throw error + } + const url = URL.createObjectURL(data) + setAvatarUrl(url) + } catch (error) { + console.log('Error downloading image: ', error.message) + } + } + + + async function uploadAvatar(event) { + try { + setUploading(true) + + if (!event.target.files || event.target.files.length === 0) { + throw new Error('You must select an image to upload.') + } + + const file = event.target.files[0] + const fileExt = file.name.split('.').pop() + const fileName = `${Math.random()}.${fileExt}` + const filePath = `${fileName}` + + let { error: uploadError } = await supabase.storage + .from('avatars') + .upload(filePath, file) + + if (uploadError) { + throw uploadError + } + + onUpload(filePath) + } catch (error) { + alert(error.message) + } finally { + setUploading(false) + } + } + + return ( +
+ {avatarUrl ? ( + Avatar + ) : ( +
+ )} +
+ + +
+
+ ) +} +``` + + +### Add the new widget + +And then we can add the widget to the Account page: + + +```jsx title="components/Account.js" +// Import the new component +import Avatar from './Avatar' + +// ... + +return ( +
+ {/* Add to the body */} + { + setAvatarUrl(url) + updateProfile({ username, website, avatar_url: url }) + }} + /> + {/* ... */} +
+) + +``` + +## Next steps + +At this stage you have a fully functional application! + +- Got a question? [Ask here](https://github.com/supabase/supabase/discussions). +- Sign in: [app.supabase.io](https://app.supabase.io) diff --git a/web/sidebars.js b/web/sidebars.js index 4406d585699..7f0a735e0bd 100755 --- a/web/sidebars.js +++ b/web/sidebars.js @@ -60,6 +60,7 @@ module.exports = { 'guides/with-flutter', 'guides/with-nextjs', 'guides/with-react', + 'guides/with-react-native', 'guides/with-redwoodjs', 'guides/with-svelte', 'guides/with-vue-3', From 26115a27c117e2fc8326e3d6b6dc70bd7bed4ddd Mon Sep 17 00:00:00 2001 From: Isaiah Hamilton Date: Tue, 11 Jan 2022 20:36:20 -0500 Subject: [PATCH 08/77] remove video demo --- web/docs/guides/with-react-native.mdx | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/web/docs/guides/with-react-native.mdx b/web/docs/guides/with-react-native.mdx index 9b1a8470f8e..d815599c2ac 100644 --- a/web/docs/guides/with-react-native.mdx +++ b/web/docs/guides/with-react-native.mdx @@ -21,26 +21,6 @@ By the end of this guide you'll have an app which allows users to login and upda ![Supabase User Management example](/img/user-management-demo.png) - ## Project set up From 1ff3c6a1e8b1f702e35b497b64f65e31af00922f Mon Sep 17 00:00:00 2001 From: Isaiah Hamilton Date: Tue, 11 Jan 2022 23:09:59 -0500 Subject: [PATCH 09/77] update contributing page --- about/docs/handbook/contributing.mdx | 2 +- web/docs/handbook/contributing.mdx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/about/docs/handbook/contributing.mdx b/about/docs/handbook/contributing.mdx index 04176c9213a..bbdf5d90f3f 100644 --- a/about/docs/handbook/contributing.mdx +++ b/about/docs/handbook/contributing.mdx @@ -13,6 +13,6 @@ Want to contribute? Why not jump into our GitHub repo and: - [Submit an issue](https://github.com/supabase/supabase/issue) - Report a performance issue or a part of the documentation that you find confusing. - [Create a pull request](https://github.com/supabase/supabase/pulls) -- [Translate our Readme](https://github.com/supabase/supabase/issues/1341). +- [Translate our Readme](https://github.com/supabase/supabase/tree/master/i18n). - Try our products and give feedback. - Spread the word if you like what we are doing. diff --git a/web/docs/handbook/contributing.mdx b/web/docs/handbook/contributing.mdx index befc7809563..49d0254f8d8 100644 --- a/web/docs/handbook/contributing.mdx +++ b/web/docs/handbook/contributing.mdx @@ -12,10 +12,10 @@ Want to contribute? Why not jump into our GitHub repo and: - [Sponsor Supabase](https://github.com/sponsors/supabase). - [Answer Discussions](https://github.com/supabase/supabase/discussions). -- Submit an issue. +- [Submit an issue](https://github.com/supabase/supabase/issue). - Report a performance issue or a part of the documentation that you find confusing. -- Create a pull request. -- [Translate our Readme](https://github.com/supabase/supabase/issues/1341). +- [Create a pull request](https://github.com/supabase/supabase/pulls). +- [Translate our Readme](https://github.com/supabase/supabase/tree/master/i18n). - Try our products and give feedback. - Spread the word if you like what we are doing. From bdcd22745f61c904c7ccf56d3a06e6f68a7ebd8d Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Thu, 13 Jan 2022 03:47:58 +0800 Subject: [PATCH 10/77] added more assertions and tentative clickDropdown usage --- studio/tests/pages/projects/LogPanel.test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/studio/tests/pages/projects/LogPanel.test.js b/studio/tests/pages/projects/LogPanel.test.js index ec7f6a4fba5..8fa1a9dcdc4 100644 --- a/studio/tests/pages/projects/LogPanel.test.js +++ b/studio/tests/pages/projects/LogPanel.test.js @@ -1,6 +1,7 @@ import LogPanel from 'components/interfaces/Settings/Logs/LogPanel' import { render, waitFor, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' +import { clickDropdown } from 'tests/helpers' test('templates', async () => { const mockFn = jest.fn() @@ -60,8 +61,8 @@ test('timestamp from filter', async () => { const dropdown = await screen.findByText(/Now/) // click the dropdown - throw Error('not impl') - + clickDropdown(dropdown) + await screen.findByLabelText('From') // display iso timestamp const year = new Date().getFullYear() From dbe47e73dc3b72f564d41e975c00ebefb4bf59fb Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Thu, 13 Jan 2022 03:48:14 +0800 Subject: [PATCH 11/77] added basic dropdown implementation --- .../interfaces/Settings/Logs/LogPanel.tsx | 62 ++++++++++++++++++- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/studio/components/interfaces/Settings/Logs/LogPanel.tsx b/studio/components/interfaces/Settings/Logs/LogPanel.tsx index ed80630b45e..d5e471bc158 100644 --- a/studio/components/interfaces/Settings/Logs/LogPanel.tsx +++ b/studio/components/interfaces/Settings/Logs/LogPanel.tsx @@ -1,4 +1,4 @@ -import { FC, useEffect, useState } from 'react' +import React, { FC, SyntheticEvent, useEffect, useMemo, useState } from 'react' import { Button, Input, @@ -9,9 +9,11 @@ import { IconX, Toggle, IconSearch, + IconClock, } from '@supabase/ui' import { LogTemplate } from '.' - +import { isNull } from 'lodash' +import dayjs from 'dayjs' interface Props { defaultSearchValue?: string templates?: any @@ -39,7 +41,8 @@ const LogPanel: FC = ({ onSelectTemplate, }) => { const [search, setSearch] = useState('') - + const [from, setFrom] = useState({ value: '', error: '' }) + const [defaultTimestamp, setDefaultTimestamp] = useState(dayjs().toISOString()) // sync local state with provided default value useEffect(() => { if (search !== defaultSearchValue) { @@ -47,6 +50,18 @@ const LogPanel: FC = ({ } }, [defaultSearchValue]) + const handleFromChange = (e: React.ChangeEvent) => { + let error = '' + const value = e.target.value + // // try to parse the iso value + // if (isNaN(Date.parse(value))) + setFrom({ value, error }) + } + const handleFromReset = () => { + const value = dayjs().toISOString() + setFrom({ value, error: '' }) + setDefaultTimestamp(value) + } return (
@@ -99,6 +114,47 @@ const LogPanel: FC = ({
+
+ + + ), + , + ]} + /> + + } + > + + +
{/* wrap with form so that if user presses enter, the search value will submit automatically */}