diff --git a/studio/pages/project/[ref]/settings/logs/[type].tsx b/studio/pages/project/[ref]/settings/logs/[type].tsx index d69cf8ae186..1c711e7c8c6 100644 --- a/studio/pages/project/[ref]/settings/logs/[type].tsx +++ b/studio/pages/project/[ref]/settings/logs/[type].tsx @@ -12,6 +12,7 @@ import { IconInfo, Card, Loading, + Input, } from '@supabase/ui' import { withAuth } from 'hooks' @@ -75,15 +76,15 @@ export const LogPage: NextPage = () => { useEffect(() => { // on mount, set initial values - if (q) { + if (q !== undefined && q !== '') { onSelectTemplate({ mode: 'custom', searchString: q as string, }) - } else if (s) { + } else { onSelectTemplate({ mode: 'simple', - searchString: s as string, + searchString: (s || '') as string, }) } if (te) { @@ -91,7 +92,7 @@ export const LogPage: NextPage = () => { } else { setParams((prev) => ({ ...prev, timestamp_end: '' })) } - }, []) + }, [q, s, te]) const genQueryParams = (params: { [k: string]: string }) => { // remove keys which are empty strings, null, or undefined @@ -329,21 +330,19 @@ export const LogPage: NextPage = () => { {error && (
- +
Sorry! An error occured when fetching data.
-
- - Error Message - - - {JSON.stringify(error, null, 2)} - -
+
)} diff --git a/studio/pages/vercel/integrate.tsx b/studio/pages/vercel/integrate.tsx index 685c5d85fff..7fb5595db7e 100644 --- a/studio/pages/vercel/integrate.tsx +++ b/studio/pages/vercel/integrate.tsx @@ -54,7 +54,6 @@ interface IVercelIntegrationStore { }[] isDeployButtonFlow: boolean - isSupabaseProjectListEmpty: boolean integrationComplete: boolean queryParams: Dictionary projectLinkRemaining: number @@ -97,12 +96,6 @@ class VercelIntegrationStore implements IVercelIntegrationStore { return !!this.currentProjectId } - get isSupabaseProjectListEmpty() { - const { app } = useStore() - const projects = app.projects.list() - return projects.length == 0 - } - // @ts-ignore get queryParams() { return { @@ -191,6 +184,9 @@ type VercelIntegrationProps = {} & any const VercelIntegration: FC = ({}) => { // @ts-ignore const _store: IVercelIntegrationStore = useLocalObservable(() => new VercelIntegrationStore()) + const { app } = useStore() + const projects = app.projects.list() + const isSupabaseProjectListEmpty = projects.length == 0 useEffect(() => { _store.loadInitialData() @@ -203,7 +199,7 @@ const VercelIntegration: FC = ({}) => { ) : _store.isDeployButtonFlow ? ( - ) : _store.isSupabaseProjectListEmpty ? ( + ) : isSupabaseProjectListEmpty ? ( ) : ( diff --git a/studio/tests/pages/projects/logs.test.js b/studio/tests/pages/projects/logs.test.js index b6433d41f07..c1cbe61d4b1 100644 --- a/studio/tests/pages/projects/logs.test.js +++ b/studio/tests/pages/projects/logs.test.js @@ -15,11 +15,14 @@ observer.mockImplementation((v) => v) // mock the router jest.mock('next/router') import { useRouter } from 'next/router' -const router = jest.fn() -router.query = { ref: '123', type: 'auth' } -router.push = jest.fn() -router.pathname = 'logs/path' -useRouter.mockReturnValue(router) +const defaultRouterMock = () => { + const router = jest.fn() + router.query = { ref: '123', type: 'auth' } + router.push = jest.fn() + router.pathname = 'logs/path' + return router +} +useRouter.mockReturnValue(defaultRouterMock()) // mock monaco editor jest.mock('@monaco-editor/react') @@ -67,6 +70,8 @@ import { logDataFixture } from '../../fixtures' beforeEach(() => { // reset mocks between tests get.mockReset() + useRouter.mockReset() + useRouter.mockReturnValue(defaultRouterMock()) }) test('can display log data and metadata', async () => { const data = [ @@ -134,6 +139,7 @@ test('Search will trigger a log refresh', async () => { expect(get).toHaveBeenCalledWith(expect.stringContaining('something')) // updates router query params + const router = useRouter() expect(router.push).toHaveBeenCalledWith( expect.objectContaining({ pathname: expect.any(String), @@ -203,6 +209,7 @@ test('where clause will trigger a log refresh', async () => { expect(get).toHaveBeenCalledWith(expect.stringContaining('metadata.field')) // updates router query params + const router = useRouter() expect(router.push).toHaveBeenCalledWith( expect.objectContaining({ pathname: expect.any(String), @@ -222,10 +229,9 @@ test('where clause will trigger a log refresh', async () => { }) test('s= query param will populate the search bar', async () => { - useRouter.mockReturnValueOnce({ - query: { ref: '123', type: 'api', s: 'someSearch' }, - push: jest.fn(), - }) + const router = defaultRouterMock() + router.query = { ...router.query, type: 'api', s: 'someSearch' } + useRouter.mockReturnValue(router) render() // should populate search input with the search param screen.getByDisplayValue('someSearch') @@ -235,10 +241,9 @@ test('s= query param will populate the search bar', async () => { }) test('q= query param will populate the query input', async () => { - useRouter.mockReturnValueOnce({ - query: { ref: '123', type: 'api', q: 'some_query', s: 'someSearch' }, - push: jest.fn(), - }) + const router = defaultRouterMock() + router.query = { ...router.query, type: 'api', q: 'some_query', s: 'someSearch' } + useRouter.mockReturnValue(router) render() // should populate editor with the query param await waitFor(() => { @@ -255,11 +260,9 @@ test('te= query param will populate the timestamp from input', async () => { newDate.setMinutes(new Date().getMinutes() - 20) const isoString = newDate.toISOString() const unixMicro = newDate.getTime() * 1000 //microseconds - - useRouter.mockReturnValueOnce({ - query: { ref: '123', type: 'api', te: unixMicro }, - push: jest.fn(), - }) + const router = defaultRouterMock() + router.query = { ...router.query, te: unixMicro } + useRouter.mockReturnValue(router) render() await waitFor(() => { @@ -407,3 +410,43 @@ test('log event chart hide', async () => { userEvent.click(toggle) await expect(screen.findByText('Events')).rejects.toThrow() }) + +test('bug: nav backwards with params change results in ui changing', async () => { + // bugfix for https://sentry.io/organizations/supabase/issues/2903331460/?project=5459134&referrer=slack + get.mockImplementation((url) => { + if (url.includes('count')) { + return {} + } + return { data: [] } + }) + const { container, rerender } = render() + + await waitFor(() => { + let editor = container.querySelector('.monaco-editor') + expect(editor).toBeFalsy() + }) + await expect(screen.findByDisplayValue('simple-query')).rejects.toThrow() + + // change the router values for query editor + const router = defaultRouterMock() + router.query = { ...router.query, q: 'advanced-query' } + useRouter.mockReturnValue(router) + rerender() + + await waitFor(() => { + let editor = container.querySelector('.monaco-editor') + expect(editor).toBeTruthy() + }) + await expect(screen.findByDisplayValue('simple-query')).rejects.toThrow() + + // change the router values + router.query = { ...router.query, q: undefined, s: 'simple-query' } + useRouter.mockReturnValue(router) + rerender() + + await waitFor(() => { + let editor = container.querySelector('.monaco-editor') + expect(editor).toBeFalsy() + }) + await screen.findByDisplayValue('simple-query') +}) diff --git a/web/spec/dart.yml b/web/spec/dart.yml index 5aa685e56ec..78b8639b3e4 100644 --- a/web/spec/dart.yml +++ b/web/spec/dart.yml @@ -1213,6 +1213,14 @@ pages: .or(): description: | Finds all rows satisfying at least one of the filters. + notes: | + - `.or()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values. + + ```dart + .or('id.in.(6,7),arraycol.cs.{"a","b"}') // Use Postgres list () and 'in' for in_ filter. Array {} and 'cs' for contains. + .or('id.in.(${mylist.join(',')}),arraycol.cs.{${mylistArray.join(',')}}') // You can insert a Dart list for list or array column. + .or('id.in.(${mylist.join(',')}),rangecol.cs.(${mylistRange.join(',')}]') // You can insert a Dart list for list or range column. + ``` examples: - name: With `select()` isSpotlight: true @@ -1248,6 +1256,16 @@ pages: .not(): description: | Finds all rows which doesn't satisfy the filter. + notes: | + - `.not()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values. + + ```dart + .not('name','eq','Paris') + .not('arraycol','cs','{"a","b"}') // Use Postgres array {} for array column and 'cs' for contains. + .not('rangecol','cs','(1,2]') // Use Postgres range syntax for range column. + .not('id','in','(6,7)') // Use Postgres list () and 'in' for in_ filter. + .not('id','in','(${mylist.join(',')})') // You can insert a Dart list array. + ``` examples: - name: With `select()` isSpotlight: true @@ -2144,7 +2162,13 @@ pages: description: | Finds all rows whose `column` satisfies the filter. notes: | - - `.filter()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter values, so it should only be used as an escape hatch in case other filters don't work. + - `.filter()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values, so it should only be used as an escape hatch in case other filters don't work. + ```dart + .filter('arraycol','cs','{"a","b"}') // Use Postgres array {} and 'cs' for contains. + .filter('rangecol','cs','(1,2]') // Use Postgres range syntax for range column. + .filter('id','in','(6,7)') // Use Postgres list () and 'in' for in_ filter. + .filter('id','cs','{${mylist.join(',')}}') // You can insert a Dart array list. + ``` examples: - name: With `select()` isSpotlight: true diff --git a/web/spec/supabase.yml b/web/spec/supabase.yml index 627a8bef127..e8003a850f2 100644 --- a/web/spec/supabase.yml +++ b/web/spec/supabase.yml @@ -1882,6 +1882,14 @@ pages: .or(): $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.or' + notes: | + - `.or()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values. + + ```js + .or('id.in.(6,7), arraycol.cs.{"a","b"}') // Use Postgres list () for in filter. Array {} for array column and 'cs' for contains. + .or(`id.in.(${arrList}),arraycol.cs.{${arr}}`) // You can insert a javascipt array for list or array on array column. + .or(`id.in.(${arrList}),rangecol.cs.[${arrRange})`) // You can insert a javascipt array for list or range on a range column. + ``` examples: - name: With `select()` isSpotlight: true @@ -1913,6 +1921,16 @@ pages: .not(): $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.not' + notes: | + - `.not()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values. + + ```js + .not('name','eq','Paris') + .not('arraycol','cs','{"a","b"}') // Use Postgres array {} for array column and 'cs' for contains. + .not('rangecol','cs','(1,2]') // Use Postgres range syntax for range column. + .not('id','in','(6,7)') // Use Postgres list () for in filter. + .not('id','in',`(${arr})`) // You can insert a javascript array. + ``` examples: - name: With `select()` isSpotlight: true @@ -2357,6 +2375,16 @@ pages: .contains(): $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.cs' + notes: | + - `.contains()` can work on array columns or range columns. + It is very useful for finding rows where a tag array contains all the values in the filter array. + + ```js + .contains('arraycol',["a","b"]) // You can use a javascript array for an array column + .contains('arraycol','{"a","b"}') // You can use a string with Postgres array {} for array column. + .contains('rangecol','(1,2]') // Use Postgres range syntax for range column. + .contains('rangecol',`(${arr}]`) // You can insert an array into a string. + ``` examples: - name: With `select()` isSpotlight: true @@ -2394,6 +2422,15 @@ pages: .containedBy(): $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.cd' + notes: | + - `.containedBy()` can work on array columns or range columns. + + ```js + .containedBy('arraycol',["a","b"]) // You can use a javascript array for an array column + .containedBy('arraycol','{"a","b"}') // You can use a string with Postgres array {} for array column. + .containedBy('rangecol','(1,2]') // Use Postgres range syntax for range column. + .containedBy('rangecol',`(${arr}]`) // You can insert an array into a string. + ``` examples: - name: With `select()` isSpotlight: true @@ -2439,7 +2476,7 @@ pages: const { data, error } = await supabase .from('countries') .select('name, id, population_range_millions') - .rangeLt('population_range_millions', [150, 250]) + .rangeLt('population_range_millions', '[150, 250]') ``` - name: With `update()` js: | @@ -2447,7 +2484,7 @@ pages: const { data, error } = await supabase .from('countries') .update({ name: 'Mordor' }) - .rangeLt('population_range_millions', [150, 250]) + .rangeLt('population_range_millions', '[150, 250]') ``` - name: With `delete()` js: | @@ -2455,7 +2492,7 @@ pages: const { data, error } = await supabase .from('countries') .delete() - .rangeLt('population_range_millions', [150, 250]) + .rangeLt('population_range_millions', '[150, 250]') ``` - name: With `rpc()` js: | @@ -2463,7 +2500,7 @@ pages: // Only valid if the Postgres function returns a table type. const { data, error } = await supabase .rpc('echo_all_countries') - .rangeLt('population_range_millions', [150, 250]) + .rangeLt('population_range_millions', '[150, 250]') ``` .rangeGt(): @@ -2476,7 +2513,7 @@ pages: const { data, error } = await supabase .from('countries') .select('name, id, population_range_millions') - .rangeGt('population_range_millions', [150, 250]) + .rangeGt('population_range_millions', '[150, 250]') ``` - name: With `update()` js: | @@ -2484,7 +2521,7 @@ pages: const { data, error } = await supabase .from('countries') .update({ name: 'Mordor' }) - .rangeGt('population_range_millions', [150, 250]) + .rangeGt('population_range_millions', '[150, 250]') ``` - name: With `delete()` js: | @@ -2492,7 +2529,7 @@ pages: const { data, error } = await supabase .from('countries') .delete() - .rangeGt('population_range_millions', [150, 250]) + .rangeGt('population_range_millions', '[150, 250]') ``` - name: With `rpc()` js: | @@ -2500,7 +2537,7 @@ pages: // Only valid if the Postgres function returns a table type. const { data, error } = await supabase .rpc('echo_all_countries') - .rangeGt('population_range_millions', [150, 250]) + .rangeGt('population_range_millions', '[150, 250]') ``` .rangeGte(): @@ -2513,7 +2550,7 @@ pages: const { data, error } = await supabase .from('countries') .select('name, id, population_range_millions') - .rangeGte('population_range_millions', [150, 250]) + .rangeGte('population_range_millions', '[150, 250]') ``` - name: With `update()` js: | @@ -2521,7 +2558,7 @@ pages: const { data, error } = await supabase .from('countries') .update({ name: 'Mordor' }) - .rangeGte('population_range_millions', [150, 250]) + .rangeGte('population_range_millions', '[150, 250]') ``` - name: With `delete()` js: | @@ -2529,7 +2566,7 @@ pages: const { data, error } = await supabase .from('countries') .delete() - .rangeGte('population_range_millions', [150, 250]) + .rangeGte('population_range_millions', '[150, 250]') ``` - name: With `rpc()` js: | @@ -2537,7 +2574,7 @@ pages: // Only valid if the Postgres function returns a table type. const { data, error } = await supabase .rpc('echo_all_countries') - .rangeGte('population_range_millions', [150, 250]) + .rangeGte('population_range_millions', '[150, 250]') ``` .rangeLte(): @@ -2550,7 +2587,7 @@ pages: const { data, error } = await supabase .from('countries') .select('name, id, population_range_millions') - .rangeLte('population_range_millions', [150, 250]) + .rangeLte('population_range_millions', '[150, 250]') ``` - name: With `update()` js: | @@ -2558,7 +2595,7 @@ pages: const { data, error } = await supabase .from('countries') .update({ name: 'Mordor' }) - .rangeLte('population_range_millions', [150, 250]) + .rangeLte('population_range_millions', '[150, 250]') ``` - name: With `delete()` js: | @@ -2566,7 +2603,7 @@ pages: const { data, error } = await supabase .from('countries') .delete() - .rangeLte('population_range_millions', [150, 250]) + .rangeLte('population_range_millions', '[150, 250]') ``` - name: With `rpc()` js: | @@ -2574,7 +2611,7 @@ pages: // Only valid if the Postgres function returns a table type. const { data, error } = await supabase .rpc('echo_all_countries') - .rangeLte('population_range_millions', [150, 250]) + .rangeLte('population_range_millions', '[150, 250]') ``` .rangeAdjacent(): @@ -2587,7 +2624,7 @@ pages: const { data, error } = await supabase .from('countries') .select('name, id, population_range_millions') - .rangeAdjacent('population_range_millions', [70, 185]) + .rangeAdjacent('population_range_millions', '[70, 185]') ``` - name: With `update()` js: | @@ -2595,7 +2632,7 @@ pages: const { data, error } = await supabase .from('countries') .update({ name: 'Mordor' }) - .rangeAdjacent('population_range_millions', [70, 185]) + .rangeAdjacent('population_range_millions', '[70, 185]') ``` - name: With `delete()` js: | @@ -2603,7 +2640,7 @@ pages: const { data, error } = await supabase .from('countries') .delete() - .rangeAdjacent('population_range_millions', [70, 185]) + .rangeAdjacent('population_range_millions', '[70, 185]') ``` - name: With `rpc()` js: | @@ -2611,11 +2648,20 @@ pages: // Only valid if the Postgres function returns a table type. const { data, error } = await supabase .rpc('echo_all_countries') - .rangeAdjacent('population_range_millions', [70, 185]) + .rangeAdjacent('population_range_millions', '[70, 185]') ``` .overlaps(): $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.ov' + notes: | + - `.overlaps()` can work on array columns or range columns. + + ```js + .overlaps('arraycol',["a","b"]) // You can use a javascript array for an array column + .overlaps('arraycol','{"a","b"}') // You can use a string with Postgres array {} for array column. + .overlaps('rangecol','(1,2]') // Use Postgres range syntax for range column. + .overlaps('rangecol',`(${arr}]`) // You can insert an array into a string. + ``` examples: - name: With `select()` isSpotlight: true @@ -2713,7 +2759,13 @@ pages: .filter(): $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.filter' notes: | - - `.filter()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter values, so it should only be used as an escape hatch in case other filters don't work. + - `.filter()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values, so it should only be used as an escape hatch in case other filters don't work. + ```js + .filter('arraycol','cs','{"a","b"}') // Use Postgres array {} for array column and 'cs' for contains. + .filter('rangecol','cs','(1,2]') // Use Postgres range syntax for range column. + .filter('id','in','(6,7)') // Use Postgres list () for in filter. + .filter('id','in',`(${arr})`) // You can insert a javascript array. + ``` examples: - name: With `select()` isSpotlight: true