From c0db968541fc25bfb8e66592cd01ee2c21842fc3 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Thu, 30 Dec 2021 02:54:48 +0800 Subject: [PATCH 01/30] added failing test for custom sql querying --- studio/tests/pages/projects/logs.test.js | 54 +++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/studio/tests/pages/projects/logs.test.js b/studio/tests/pages/projects/logs.test.js index 48a1bc444d8..bd26f4c8c72 100644 --- a/studio/tests/pages/projects/logs.test.js +++ b/studio/tests/pages/projects/logs.test.js @@ -31,7 +31,7 @@ useMonaco.mockImplementation((v) => v) import { LogPage } from 'pages/project/[ref]/settings/logs/[type]' import { render, fireEvent, waitFor, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import {getToggleByText} from "../../helpers" +import { getToggleByText } from '../../helpers' beforeEach(() => { get.mockReset() @@ -177,3 +177,55 @@ test('where clause will trigger a log refresh', async () => { await waitFor(() => screen.getByText(/happened/)) }) + +test('custom sql querying', async () => { + get.mockImplementation((url) => { + if (url.includes('sql=') && url.includes('select')) { + return { + data: [ + { + my_count: 12345, + }, + ], + } + } + return { data: [] } + }) + const { container } = render() + let editor = container.querySelector('.monaco-editor') + expect(editor).toBeFalsy() + // TODO: abstract this out into a toggle selection helper + const toggle = getToggleByText(/via query/) + expect(toggle).toBeTruthy() + userEvent.click(toggle) + + // type into the query editor + await waitFor(() => { + editor = container.querySelector('.monaco-editor') + expect(editor).toBeTruthy() + }) + editor = container.querySelector('.monaco-editor') + userEvent.type(editor, 'select count(*) as my_count from edge_logs') + + // should show sandbox warning alert + await waitFor(() => screen.getByText(/free users are restricted to a 7 day querying window/)) + + // should trigger query + userEvent.click(screen.getByText('Run')) + await waitFor( + () => { + expect(get).toHaveBeenCalledWith(expect.stringContaining('sql=')) + expect(get).toHaveBeenCalledWith(expect.stringContaining('select')) + expect(get).toHaveBeenCalledWith(expect.stringContaining('edge_logs')) + expect(get).not.toHaveBeenCalledWith(expect.stringContaining('where')) + }, + { timeout: 1000 } + ) + + await waitFor(() => screen.getByText(/my_count/)) //column header + await waitFor(() => screen.getByText(/12345/)) // row value + + // clicking on the row value should not show log selection panel + userEvent.click(screen.getByText(/12345/)) + await waitFor(() => expect(() => screen.getByText(/Metadata/)).toThrow()) +}) From 7cb7e87504b9d7da90108dad52334099a162687d Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Mon, 3 Jan 2022 19:17:01 +0800 Subject: [PATCH 02/30] remove mentioning of free users. --- studio/tests/pages/projects/logs.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/tests/pages/projects/logs.test.js b/studio/tests/pages/projects/logs.test.js index aa50c0d2555..dc325434923 100644 --- a/studio/tests/pages/projects/logs.test.js +++ b/studio/tests/pages/projects/logs.test.js @@ -232,7 +232,7 @@ test('custom sql querying', async () => { userEvent.type(editor, 'select count(*) as my_count from edge_logs') // should show sandbox warning alert - await waitFor(() => screen.getByText(/free users are restricted to a 7 day querying window/)) + await waitFor(() => screen.getByText(/restricted to a 7 day querying window/)) // should trigger query userEvent.click(screen.getByText('Run')) From 31921c527c546c95bc9886b227fa2f1ef87642be Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Tue, 4 Jan 2022 01:48:25 +0800 Subject: [PATCH 03/30] added sql query params handling handling --- .../project/[ref]/settings/logs/[type].tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/studio/pages/project/[ref]/settings/logs/[type].tsx b/studio/pages/project/[ref]/settings/logs/[type].tsx index 5300d2f976d..5744ade2d7d 100644 --- a/studio/pages/project/[ref]/settings/logs/[type].tsx +++ b/studio/pages/project/[ref]/settings/logs/[type].tsx @@ -23,6 +23,7 @@ import { uuidv4 } from 'lib/helpers' import useSWRInfinite from 'swr/infinite' import { isUndefined } from 'lodash' import Flag from 'components/ui/Flag/Flag' +import { useFlag } from 'hooks' /** * Acts as a container component for the entire log display @@ -30,6 +31,7 @@ import Flag from 'components/ui/Flag/Flag' * */ export const LogPage: NextPage = () => { + const logsCustomSql = useFlag('logsCustomSql') const router = useRouter() const { ref, type } = router.query @@ -40,11 +42,13 @@ export const LogPage: NextPage = () => { const [params, setParams] = useState({ type: '', search_query: '', + sql: '', where: '', timestamp_start: '', timestamp_end: '', }) const title = `Logs - ${LOG_TYPE_LABEL_MAPPING[type as string]}` + const isCustomQuery = logsCustomSql && editorValue.toLowerCase().includes('select') ? true : false useEffect(() => { setParams({ ...params, type: type as string }) @@ -124,15 +128,24 @@ export const LogPage: NextPage = () => { const onSelectTemplate = (template: LogTemplate) => { setMode(template.mode) if (template.mode === 'simple') { - setParams((prev) => ({ ...prev, search_query: template.searchString, where: '' })) + setParams((prev) => ({ ...prev, search_query: template.searchString, sql: '', where: '' })) } else { setEditorValue(template.searchString) - setParams((prev) => ({ ...prev, where: template.searchString, search_query: '' })) + setParams((prev) => ({ + ...prev, + where: isCustomQuery ? '' : template.searchString, + sql: isCustomQuery ? template.searchString : '', + search_query: '', + })) setEditorId(uuidv4()) } } const handleEditorSubmit = () => { - setParams((prev) => ({ ...prev, where: editorValue })) + setParams((prev) => ({ + ...prev, + where: isCustomQuery ? '' : editorValue, + sql: isCustomQuery ? editorValue : '', + })) } const handleSearch = (v: string) => { setParams((prev) => ({ ...prev, search_query: v || '' })) From 78ab44fea5127c00d15ae27061fe8a1ca4fbbf4f Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Tue, 4 Jan 2022 01:48:46 +0800 Subject: [PATCH 04/30] added alert on querying restriction --- .../pages/project/[ref]/settings/logs/[type].tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/studio/pages/project/[ref]/settings/logs/[type].tsx b/studio/pages/project/[ref]/settings/logs/[type].tsx index 5744ade2d7d..06c03b5031e 100644 --- a/studio/pages/project/[ref]/settings/logs/[type].tsx +++ b/studio/pages/project/[ref]/settings/logs/[type].tsx @@ -3,7 +3,7 @@ import React, { useEffect, useRef, useState } from 'react' import { NextPage } from 'next' import { useRouter } from 'next/router' import { observer } from 'mobx-react-lite' -import { Typography, IconLoader, IconAlertCircle, IconRewind, Button } from '@supabase/ui' +import { Typography, IconLoader, IconAlertCircle, IconRewind, Button, IconInfo } from '@supabase/ui' import { withAuth } from 'hooks' import { get } from 'lib/common/fetch' @@ -177,6 +177,18 @@ export const LogPage: NextPage = () => { />
+ + {isCustomQuery && ( + // we don't have a slim Alert component yet +
+ + + Custom queries are restricted to a {type === 'database' ? '2 hour' : '7 day'}{' '} + querying window. + +
+ )} +
{editorValue && ( - + {!isSelectQuery && ( + + + + )}
From eb6fa789eafef2c2c42786951fdddc49ad6a8f67 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Tue, 4 Jan 2022 18:09:47 +0800 Subject: [PATCH 09/30] added assertion for hiding chronological feature --- studio/tests/pages/projects/logs.test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/studio/tests/pages/projects/logs.test.js b/studio/tests/pages/projects/logs.test.js index dc325434923..c98b3fd856d 100644 --- a/studio/tests/pages/projects/logs.test.js +++ b/studio/tests/pages/projects/logs.test.js @@ -31,6 +31,9 @@ useMonaco.mockImplementation((v) => v) jest.mock('components/ui/Flag/Flag') import Flag from 'components/ui/Flag/Flag' Flag.mockImplementation(({ children }) => <>{children}) +jest.mock('hooks') +import { useFlag } from 'hooks' +useFlag.mockReturnValue(true) import { SWRConfig } from 'swr' jest.mock('pages/project/[ref]/settings/logs/[type]') @@ -230,7 +233,6 @@ test('custom sql querying', async () => { }) editor = container.querySelector('.monaco-editor') userEvent.type(editor, 'select count(*) as my_count from edge_logs') - // should show sandbox warning alert await waitFor(() => screen.getByText(/restricted to a 7 day querying window/)) @@ -252,6 +254,9 @@ test('custom sql querying', async () => { // clicking on the row value should not show log selection panel userEvent.click(screen.getByText(/12345/)) await waitFor(() => expect(() => screen.getByText(/Metadata/)).toThrow()) + + // should not see chronological features + await waitFor(() => screen.queryByText(/Load older/)) //column header }) test('load older btn will fetch older logs', async () => { From b8fd95de40668e5a74769bd37eb1afa82f3993af Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Tue, 4 Jan 2022 18:10:03 +0800 Subject: [PATCH 10/30] fixed failing test due to 4 keys being required for chronological mode --- studio/tests/pages/projects/LogTable.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/studio/tests/pages/projects/LogTable.test.js b/studio/tests/pages/projects/LogTable.test.js index 3d23edb4e2b..612ea2aafa6 100644 --- a/studio/tests/pages/projects/LogTable.test.js +++ b/studio/tests/pages/projects/LogTable.test.js @@ -24,6 +24,7 @@ test('can display log data', async () => { }) test('dedupes log lines with exact id', async () => { + // chronological mode requires 4 columns render( { id: 'seome-uuid', timestamp: 1621323232312, event_message: 'some event happened', + metadata: {} }, { id: 'seome-uuid', timestamp: 1621323232312, event_message: 'some event happened', + metadata: {} }, ]} /> From b51bf18c1c7b6fa00e4fc23b5136cf311f85d7ca Mon Sep 17 00:00:00 2001 From: Isaiah Hamilton Date: Tue, 4 Jan 2022 18:07:39 -0500 Subject: [PATCH 11/30] add description to faq --- www/pages/pricing/index.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/www/pages/pricing/index.tsx b/www/pages/pricing/index.tsx index eddbe017055..e6b33d3515b 100644 --- a/www/pages/pricing/index.tsx +++ b/www/pages/pricing/index.tsx @@ -392,6 +392,22 @@ export default function IndexPage() {
Frequently asked questions + + Can't find the answer to your question, ask someone in the community either on our + Discord or Github. + + + + + + + + + + +
{pricingFaq.map((faq) => { From b13743d44578dbce52f36f426f67a4f3b5b7759b Mon Sep 17 00:00:00 2001 From: GodderE2D <55918888+GodderE2D@users.noreply.github.com> Date: Wed, 5 Jan 2022 15:52:52 +1100 Subject: [PATCH 12/30] chore: bump LICENSE year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 16fc02b5e4d..4a283904229 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2020 Supabase + Copyright 2021 Supabase Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From dacfbd4b17176c1216cf45cfb94fade1d55de402 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Wed, 5 Jan 2022 15:03:22 +0800 Subject: [PATCH 13/30] changed isChrono variable name to hasLogDataFormat --- .../interfaces/Settings/Logs/LogTable.tsx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/studio/components/interfaces/Settings/Logs/LogTable.tsx b/studio/components/interfaces/Settings/Logs/LogTable.tsx index 43cb2c24dcf..6f784befeac 100644 --- a/studio/components/interfaces/Settings/Logs/LogTable.tsx +++ b/studio/components/interfaces/Settings/Logs/LogTable.tsx @@ -22,30 +22,30 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { const [focusedLog, setFocusedLog] = useState(null) const columnNames = Object.keys(data[0] || {}) // whether it the data structure is LogData format. - const isChrono = + const hasLogDataFormat = columnNames.includes('timestamp') && columnNames.includes('event_message') && columnNames.length === 4 - const columns = (isChrono ? ['timestamp', 'event_message'] : columnNames).map((v) => ({ + const columns = (hasLogDataFormat ? ['timestamp', 'event_message'] : columnNames).map((v) => ({ key: v, name: v, - width: isChrono && v === 'timestamp' ? 210 : undefined, + width: hasLogDataFormat && v === 'timestamp' ? 210 : undefined, resizable: true, headerRenderer: () => { return
{v}
}, formatter: ({ row }: any) => { let value = row[v] - if (isChrono && v === 'timestamp') { + if (hasLogDataFormat && v === 'timestamp') { value = dayjs(Number(row['timestamp']) / 1000).toISOString() } return (

{value} @@ -55,7 +55,7 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { })) const logMap = useMemo(() => { - if (!isChrono) return {} as LogMap + if (!hasLogDataFormat) return {} as LogMap const logData = data as LogData[] return logData.reduce((acc: LogMap, d: LogData) => { acc[d.id] = d @@ -65,7 +65,7 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { const strData = JSON.stringify(data) useEffect(() => { - if (!isChrono) return + if (!hasLogDataFormat) return if (isNil(data)) return if (focusedLog && !(focusedLog.id in logMap)) { setFocusedLog(null) @@ -78,7 +78,7 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { const maxHeight = isCustomQuery ? 'calc(100vh - 42px - 10rem)' : 'calc(100vh - 42px - 3rem)' const logDataRows = useMemo(() => { - if (!isChrono) return data + if (!hasLogDataFormat) return data return Object.values(logMap).sort((a, b) => b.timestamp - a.timestamp) }, [strData]) return ( @@ -87,7 +87,7 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { style={{ height: '100%' }} className="flex-grow flex-1" onSelectedCellChange={({ idx, rowIdx }) => { - if (!isChrono) return + if (!hasLogDataFormat) return setFocusedLog(data[rowIdx] as LogData) }} noRowsFallback={ @@ -99,18 +99,18 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { } columns={columns as any} rowClass={(r) => { - if (!isChrono) return 'cursor-pointer' + if (!hasLogDataFormat) return 'cursor-pointer' const row = r as LogData return `${row.id === focusedLog?.id ? 'bg-green-800' : 'cursor-pointer'}` }} rows={logDataRows} rowKeyGetter={(r) => { - if (!isChrono) return Object.keys(r)[0] + if (!hasLogDataFormat) return Object.keys(r)[0] const row = r as LogData return row.id }} onRowClick={(r) => { - if (!isChrono) return + if (!hasLogDataFormat) return const row = r as LogData setFocusedLog(logMap[row.id]) }} From 3049dff8aafeb21df7cd3b7385144257c2b0e9ca Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Wed, 5 Jan 2022 15:05:26 +0800 Subject: [PATCH 14/30] expanded strData to stringData variable name --- studio/components/interfaces/Settings/Logs/LogTable.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/studio/components/interfaces/Settings/Logs/LogTable.tsx b/studio/components/interfaces/Settings/Logs/LogTable.tsx index 6f784befeac..1ea2b4d7df7 100644 --- a/studio/components/interfaces/Settings/Logs/LogTable.tsx +++ b/studio/components/interfaces/Settings/Logs/LogTable.tsx @@ -63,14 +63,14 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { }, {}) as LogMap }, [JSON.stringify(data)]) - const strData = JSON.stringify(data) + const stringData = JSON.stringify(data) useEffect(() => { if (!hasLogDataFormat) return if (isNil(data)) return if (focusedLog && !(focusedLog.id in logMap)) { setFocusedLog(null) } - }, [strData]) + }, [stringData]) if (!data) return null @@ -80,7 +80,7 @@ const LogTable = ({ isCustomQuery, data = [] }: Props) => { const logDataRows = useMemo(() => { if (!hasLogDataFormat) return data return Object.values(logMap).sort((a, b) => b.timestamp - a.timestamp) - }, [strData]) + }, [stringData]) return (

Date: Wed, 5 Jan 2022 15:05:59 +0800 Subject: [PATCH 15/30] fixed typo --- studio/tests/pages/projects/LogTable.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/studio/tests/pages/projects/LogTable.test.js b/studio/tests/pages/projects/LogTable.test.js index 612ea2aafa6..02b4a52d681 100644 --- a/studio/tests/pages/projects/LogTable.test.js +++ b/studio/tests/pages/projects/LogTable.test.js @@ -5,7 +5,7 @@ test('can display log data', async () => { { Date: Wed, 5 Jan 2022 15:06:27 +0800 Subject: [PATCH 16/30] fixed inline doc --- studio/components/interfaces/Settings/Logs/LogTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/components/interfaces/Settings/Logs/LogTable.tsx b/studio/components/interfaces/Settings/Logs/LogTable.tsx index 1ea2b4d7df7..4f61637ed34 100644 --- a/studio/components/interfaces/Settings/Logs/LogTable.tsx +++ b/studio/components/interfaces/Settings/Logs/LogTable.tsx @@ -21,7 +21,7 @@ type LogMap = { [id: string]: LogData } const LogTable = ({ isCustomQuery, data = [] }: Props) => { const [focusedLog, setFocusedLog] = useState(null) const columnNames = Object.keys(data[0] || {}) - // whether it the data structure is LogData format. + // whether the data structure is LogData format. const hasLogDataFormat = columnNames.includes('timestamp') && columnNames.includes('event_message') && From adcc31ab8f8fbd99443277bb409f8a8613b656a3 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Wed, 5 Jan 2022 16:30:41 +0800 Subject: [PATCH 17/30] added alert styling --- .../project/[ref]/settings/logs/[type].tsx | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/studio/pages/project/[ref]/settings/logs/[type].tsx b/studio/pages/project/[ref]/settings/logs/[type].tsx index 73ad36604db..d60a83f83b5 100644 --- a/studio/pages/project/[ref]/settings/logs/[type].tsx +++ b/studio/pages/project/[ref]/settings/logs/[type].tsx @@ -176,33 +176,35 @@ export const LogPage: NextPage = () => { onInputRun={handleRefresh} />
-
+
{isSelectQuery && ( - // we don't have a slim Alert component yet -
- - +
+ {/* // we don't have a slim Alert component yet */} + + Custom queries are restricted to a {type === 'database' ? '2 hour' : '7 day'}{' '} querying window.
)} - {editorValue && ( - + )} + - )} - +
)} From c954b5e4ea69ae63749c59f2781d76a7d46b1f7c Mon Sep 17 00:00:00 2001 From: phamhieu Date: Wed, 5 Jan 2022 10:23:00 +0700 Subject: [PATCH 18/30] chore: remove auth0 --- studio/components/interfaces/Home/Landing.tsx | 25 +++----- .../layouts/AccountLayout/AccountLayout.tsx | 8 +-- studio/lib/api/apiAuthenticate.ts | 60 ++++++------------- studio/lib/api/auth0.ts | 32 ---------- studio/lib/common/fetch/base.ts | 3 +- studio/lib/gotrue.ts | 3 +- 6 files changed, 31 insertions(+), 100 deletions(-) delete mode 100644 studio/lib/api/auth0.ts diff --git a/studio/components/interfaces/Home/Landing.tsx b/studio/components/interfaces/Home/Landing.tsx index ec00c7236b0..f1a9986f9fe 100644 --- a/studio/components/interfaces/Home/Landing.tsx +++ b/studio/components/interfaces/Home/Landing.tsx @@ -4,9 +4,8 @@ import Head from 'next/head' import { observer } from 'mobx-react-lite' import { Button, IconGitHub, Typography } from '@supabase/ui' -import { API_URL } from 'lib/constants' import { useStore } from 'hooks' -import { auth, GOTRUE_ENABLED } from 'lib/gotrue' +import { auth } from 'lib/gotrue' const Landing = () => { const { ui } = useStore() @@ -55,13 +54,9 @@ const Landing = () => { type="success" className="ml-8 font-medium hover:text-gray-300 focus:outline-none focus:text-gray-300 transition duration-150 ease-in-out" > - {GOTRUE_ENABLED ? ( - - ) : ( - Sign In - )} +
@@ -78,15 +73,9 @@ const Landing = () => {

- {GOTRUE_ENABLED ? ( - - ) : ( - - - - )} + +
+
+ + + +
+ + + + } + /> +
+ + } + /> + + ) +} + const DownloadCertificate: FC = ({ createdAt }) => { // instances before 3 : 08 pm sgt 29th April don't have certs installed if (new Date(createdAt) < new Date('2021-04-30')) return null @@ -142,10 +228,10 @@ const DownloadCertificate: FC = ({ createdAt }) => { return ( -
+
SSL Connection -
+

Use this cert when connecting to your database to prevent snooping and @@ -154,13 +240,15 @@ const DownloadCertificate: FC = ({ createdAt }) => {

- +
@@ -264,6 +352,7 @@ const GeneralSettings: FC = ({ projectRef }) => { +
From 5517979861359b697203c67405f39fe52d58f49d Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Tue, 21 Dec 2021 16:07:54 +0700 Subject: [PATCH 25/30] Implement reset db password functionality --- studio/components/ui/PasswordStrengthBar.tsx | 5 +- .../pages/project/[ref]/settings/database.tsx | 116 +++++++++++------- 2 files changed, 73 insertions(+), 48 deletions(-) diff --git a/studio/components/ui/PasswordStrengthBar.tsx b/studio/components/ui/PasswordStrengthBar.tsx index d0b5240d9db..25d4729a994 100644 --- a/studio/components/ui/PasswordStrengthBar.tsx +++ b/studio/components/ui/PasswordStrengthBar.tsx @@ -3,6 +3,7 @@ import { PASSWORD_STRENGTH_COLOR, PASSWORD_STRENGTH_PERCENTAGE, } from 'lib/constants' +import { Typography } from '@supabase/ui' interface Props { passwordStrengthScore: number @@ -36,7 +37,7 @@ const PasswordStrengthBar = ({ >
)} - = DEFAULT_MINIMUM_PASSWORD_STRENGTH ? 'text-green-600' : '' } @@ -44,7 +45,7 @@ const PasswordStrengthBar = ({ {passwordStrengthMessage ? passwordStrengthMessage : 'This is the password to your postgres database, so it must be a strong password and hard to guess.'} - + ) } diff --git a/studio/pages/project/[ref]/settings/database.tsx b/studio/pages/project/[ref]/settings/database.tsx index 5efc721e4c8..e4d9e648bea 100644 --- a/studio/pages/project/[ref]/settings/database.tsx +++ b/studio/pages/project/[ref]/settings/database.tsx @@ -1,15 +1,19 @@ -import { FC, useState, useRef } from 'react' -import { useStore, withAuth } from 'hooks' - -import { useRouter } from 'next/router' - +import dayjs from 'dayjs' +import customParseFormat from 'dayjs/plugin/customParseFormat' +import timezone from 'dayjs/plugin/timezone' +import utc from 'dayjs/plugin/utc' +import useSWR from 'swr' +import { FC, useState, useRef, useEffect } from 'react' import { toJS } from 'mobx' import { observer } from 'mobx-react-lite' -import useSWR from 'swr' +import { useRouter } from 'next/router' +import { debounce } from 'lodash' +import { Typography, Input, Button, IconDownload, IconArrowRight, Tabs, Modal } from '@supabase/ui' -import { API_URL, DEFAULT_MINIMUM_PASSWORD_STRENGTH, TIME_PERIODS_INFRA } from 'lib/constants' -import { get } from 'lib/common/fetch' +import { useStore, withAuth } from 'hooks' +import { get, patch } from 'lib/common/fetch' import { pluckObjectFields, passwordStrength } from 'lib/helpers' +import { API_URL, DEFAULT_MINIMUM_PASSWORD_STRENGTH, TIME_PERIODS_INFRA } from 'lib/constants' import { SettingsLayout } from 'components/layouts' import PasswordStrengthBar from 'components/ui/PasswordStrengthBar' @@ -18,15 +22,6 @@ import { ProjectUsageMinimal } from 'components/to-be-cleaned/Usage' import DateRangePicker from 'components/to-be-cleaned/DateRangePicker' import ChartHandler from 'components/to-be-cleaned/Charts/ChartHandler' -import { Typography, Input, Button, IconDownload, IconArrowRight, Tabs, Modal } from '@supabase/ui' - -import dayjs from 'dayjs' -import customParseFormat from 'dayjs/plugin/customParseFormat' -import timezone from 'dayjs/plugin/timezone' -import utc from 'dayjs/plugin/utc' - -import { isUndefined, debounce } from 'lodash' - dayjs.extend(customParseFormat) dayjs.extend(timezone) dayjs.extend(utc) @@ -142,10 +137,26 @@ const Usage: FC = ({ project }) => { } const ResetDbPassword: FC = () => { - const [password, setPassword] = useState('') - const [passwordStrengthMessage, setPasswordStrengthMessage] = useState('') - const [passwordStrengthWarning, setPasswordStrengthWarning] = useState('') - const [passwordStrengthScore, setPasswordStrengthScore] = useState(0) + const { ui } = useStore() + const projectRef = ui.selectedProject?.ref + + const [showResetDbPass, setShowResetDbPass] = useState(false) + const [isUpdatingPassword, setIsUpdatingPassword] = useState(false) + + const [password, setPassword] = useState('') + const [passwordStrengthMessage, setPasswordStrengthMessage] = useState('') + const [passwordStrengthWarning, setPasswordStrengthWarning] = useState('') + const [passwordStrengthScore, setPasswordStrengthScore] = useState(0) + + useEffect(() => { + if (showResetDbPass) { + setIsUpdatingPassword(false) + setPassword('') + setPasswordStrengthMessage('') + setPasswordStrengthWarning('') + setPasswordStrengthScore(0) + } + }, [showResetDbPass]) async function checkPasswordStrength(value: any) { const { message, warning, strength } = await passwordStrength(value) @@ -158,7 +169,7 @@ const ResetDbPassword: FC = () => { debounce((value) => checkPasswordStrength(value), 300) ).current - function onDbPassChange(e: any) { + const onDbPassChange = (e: any) => { const value = e.target.value setPassword(value) if (value == '') { @@ -167,6 +178,19 @@ const ResetDbPassword: FC = () => { } else delayedCheckPasswordStrength(value) } + const confirmResetDbPass = async () => { + if (passwordStrengthScore >= DEFAULT_MINIMUM_PASSWORD_STRENGTH) { + setIsUpdatingPassword(true) + const res = await patch(`${API_URL}/projects/${projectRef}/db-password`, { password }) + if (!res.error) { + ui.setNotification({ category: 'success', message: res.message }) + setShowResetDbPass(false) + } else { + ui.setNotification({ category: 'error', message: 'Failed to reset password' }) + } + } + } + return ( <> @@ -183,40 +207,40 @@ const ResetDbPassword: FC = () => {
- +
-
- - - - } + visible={showResetDbPass} + loading={isUpdatingPassword} + onCancel={() => setShowResetDbPass(false)} + onConfirm={() => confirmResetDbPass()} + > +
+ -
- - } - /> + } + /> +
+
) } From 25361cfa463975f3dc758ab69ffdc114407e98b8 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Wed, 22 Dec 2021 11:20:21 +0700 Subject: [PATCH 26/30] Use reusable password strength bar component in vercel setupProject --- studio/pages/vercel/setupProject.tsx | 41 +++++++++------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/studio/pages/vercel/setupProject.tsx b/studio/pages/vercel/setupProject.tsx index cbf63928e64..867e48b269c 100644 --- a/studio/pages/vercel/setupProject.tsx +++ b/studio/pages/vercel/setupProject.tsx @@ -9,6 +9,7 @@ import { Dictionary } from '@supabase/grid' import { useStore } from 'hooks' import { post } from 'lib/common/fetch' +import { passwordStrength } from 'lib/helpers' import { PROVIDERS, REGIONS, @@ -22,8 +23,9 @@ import { fetchVercelProject, prepareVercelEvns, } from 'components/to-be-cleaned/Integration/Vercel.utils' -import Loading from 'components/ui/Loading' import VercelIntegrationLayout from 'components/layouts/VercelIntegrationLayout' +import Loading from 'components/ui/Loading' +import PasswordStrengthBar from 'components/ui/PasswordStrengthBar' const PASSWORD_STRENGTH = { 0: "That's terrible.", @@ -165,6 +167,7 @@ const CreateProject = observer(() => { const delayedCheckPasswordStrength = useRef( debounce((value: string) => checkPasswordStrength(value), 300) ).current + const canSubmit = projectName != '' && passwordStrengthScore >= DEFAULT_MINIMUM_PASSWORD_STRENGTH && @@ -189,22 +192,9 @@ const CreateProject = observer(() => { } async function checkPasswordStrength(value: string) { - let passwordStrength = '' - if (value && value !== '') { - const response = await post(`${API_URL}/profile/password-check`, { password: value }) - if (!response.error) { - const { result } = response - const score = (PASSWORD_STRENGTH as any)[result.score] - const warning = result.feedback.warning ? `${result.feedback.warning}.` : '' - const suggestions = result.feedback?.suggestions - ? result.feedback.suggestions.join(' ') - : '' - passwordStrength = `${score} ${warning} ${suggestions}` - setPasswordStrengthScore(result.score) - } - } - - setPasswordStrengthMessage(passwordStrength) + const { message, strength } = await passwordStrength(value) + setPasswordStrengthScore(strength) + setPasswordStrengthMessage(message) } async function createSupabaseProject(dbSql: string) { @@ -294,7 +284,7 @@ const CreateProject = observer(() => { -
+
{ placeholder="· · · · · · · · · · · · ·" className="shadow-sm focus:ring-green-500 focus:border-green-500 block w-full sm:text-sm border-gray-300 rounded-md" /> - {passwordStrengthMessage && ( - -

{passwordStrengthMessage}

-
- )} - {passwordStrengthScore >= 0 && passwordStrengthScore < DEFAULT_MINIMUM_PASSWORD_STRENGTH && ( - -

You need a stronger password

-
- )} +
From 4a71fb5e818ca5ad7ad929968bce92c473b58f23 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Mon, 27 Dec 2021 10:38:40 +0700 Subject: [PATCH 27/30] Remove label --- studio/pages/project/[ref]/settings/database.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/studio/pages/project/[ref]/settings/database.tsx b/studio/pages/project/[ref]/settings/database.tsx index e4d9e648bea..32fd67c9c9f 100644 --- a/studio/pages/project/[ref]/settings/database.tsx +++ b/studio/pages/project/[ref]/settings/database.tsx @@ -228,7 +228,6 @@ const ResetDbPassword: FC = () => { Date: Thu, 6 Jan 2022 15:37:14 +0800 Subject: [PATCH 28/30] Only show reset db password panel for org owners --- studio/pages/project/[ref]/settings/database.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/studio/pages/project/[ref]/settings/database.tsx b/studio/pages/project/[ref]/settings/database.tsx index 32fd67c9c9f..fc8f8a0d39b 100644 --- a/studio/pages/project/[ref]/settings/database.tsx +++ b/studio/pages/project/[ref]/settings/database.tsx @@ -279,6 +279,9 @@ const DownloadCertificate: FC = ({ createdAt }) => { } const GeneralSettings: FC = ({ projectRef }) => { + const { ui } = useStore() + const isOwner = ui.selectedOrganization?.is_owner + const { data, error }: any = useSWR(`${API_URL}/props/project/${projectRef}/settings`, get) if (data?.error || error) { @@ -375,7 +378,7 @@ const GeneralSettings: FC = ({ projectRef }) => { - + {isOwner && }
From 20f2ba39ef07e82cf1ce3563ff20ef066f29034a Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 6 Jan 2022 14:50:29 +0800 Subject: [PATCH 29/30] Show warning messages better on the project creation page --- studio/pages/new/[slug].tsx | 65 ++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/studio/pages/new/[slug].tsx b/studio/pages/new/[slug].tsx index dc27ce64e84..3bcf9db40a1 100644 --- a/studio/pages/new/[slug].tsx +++ b/studio/pages/new/[slug].tsx @@ -245,11 +245,7 @@ export const Wizard = observer(() => { ))} - {!currentOrg?.is_owner ? ( - - ) : ( - <>{isSelectFreeTier && isOverFreeProjectLimit && } - )} + {!currentOrg?.is_owner && } {canCreateProject && ( @@ -296,36 +292,39 @@ export const Wizard = observer(() => { description="Select a region close to you for the best performance." /> - - - - Select a plan that suits your needs.  - - More details - - - } - > - {Object.entries(PRICING_PLANS).map(([k, v]) => ( - - {`${v}${v === PRICING_PLANS.PRO ? ' - $25/month' : ''}`} - - ))} - - - {!isSelectFreeTier && isEmptyPaymentMethod && ( - - )} - )} + + {currentOrg?.is_owner && ( + + + Select a plan that suits your needs.  + + More details + + + } + > + {Object.entries(PRICING_PLANS).map(([k, v]) => ( + + {`${v}${v === PRICING_PLANS.PRO ? ' - $25/month' : ''}`} + + ))} + + + {isSelectFreeTier && isOverFreeProjectLimit && } + {!isSelectFreeTier && isEmptyPaymentMethod && ( + + )} + + )} From 19383f9d7dbdbbfede76ac64ba6f7785a2f33306 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 6 Jan 2022 14:50:45 +0800 Subject: [PATCH 30/30] Fix self-host studio docker compose file --- docker/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 53d6fd7c08d..78197b5920e 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -154,5 +154,5 @@ services: environment: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - - ./volumes/db/data:/var/lib/postgresql/data + # - ./volumes/db/data:/var/lib/postgresql/data - ./volumes/db/init:/docker-entrypoint-initdb.d