From 9705aea5a662a8cb7f2e718d8bcfc1ac695bb7c4 Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Fri, 1 Sep 2023 13:14:22 +0200 Subject: [PATCH 01/21] Add a warning and disable save when the column types don't match during foreign column selection. --- .../ForeignKeySelector/ForeignKeySelector.tsx | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx index 9a97b7eba14..d019b7e4dc0 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx @@ -2,7 +2,17 @@ import type { PostgresColumn, PostgresSchema, PostgresTable } from '@supabase/po import { Dictionary } from 'components/grid' import { find, get, isEmpty, sortBy } from 'lodash' import { useEffect, useState } from 'react' -import { IconDatabase, IconHelpCircle, Input, Listbox, SidePanel } from 'ui' +import { + AlertDescription_Shadcn_, + AlertTitle_Shadcn_, + Alert_Shadcn_, + IconAlertTriangle, + IconDatabase, + IconHelpCircle, + Input, + Listbox, + SidePanel, +} from 'ui' import InformationBox from 'components/ui/InformationBox' import { FOREIGN_KEY_DELETION_ACTION } from 'data/database/database-query-constants' @@ -153,6 +163,8 @@ const ForeignKeySelector = ({ resolve() } + const matchingColumnTypes = selectedColumn?.format === column?.format + return ( )} + {!matchingColumnTypes && ( + + + The column types don't match + + The referenced column {column.name} is of + type {column.format} while the selected + foreign column + + {selectedTable?.name}.{selectedColumn?.name} + + has{selectedColumn?.data_type}type. These two + columns can't be referenced until one of them change its type. + + + )} } From d5b1f219a935a0dbd02e41b731fa3f3178f00981 Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Mon, 4 Sep 2023 17:03:35 +0200 Subject: [PATCH 02/21] Handle empty column names and types. --- .../ForeignKeySelector/ForeignKeySelector.tsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx index d019b7e4dc0..35769943d49 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx @@ -304,14 +304,23 @@ const ForeignKeySelector = ({ The column types don't match - The referenced column {column.name} is of - type {column.format} while the selected - foreign column + The referenced column + {column?.name && {column.name}} + {column?.format ? ( + <> + is of type + {column.format} + + ) : ( + has no type + )} + while the selected foreign column {selectedTable?.name}.{selectedColumn?.name} - has{selectedColumn?.data_type}type. These two - columns can't be referenced until one of them change its type. + has + {selectedColumn?.data_type}type. These two + columns can't be referenced until they of the same type. )} From b65ebe8bf9abf528013d07162c43c546a610721c Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Sat, 9 Sep 2023 04:09:54 +0800 Subject: [PATCH 03/21] feat: storage report cache misses --- .../interfaces/Reports/Reports.constants.ts | 44 +++++++ .../interfaces/Reports/Reports.types.ts | 1 + .../Reports/renderers/StorageRenderers.tsx | 83 +++++++++++++ .../ReportsLayout/ReportsMenu.utils.ts | 14 ++- .../components/ui/Charts/Charts.constants.ts | 49 ++++---- .../components/ui/Charts/StackedBarChart.tsx | 7 +- .../pages/project/[ref]/reports/storage.tsx | 114 ++++++++++++++++++ 7 files changed, 288 insertions(+), 24 deletions(-) create mode 100644 studio/components/interfaces/Reports/renderers/StorageRenderers.tsx create mode 100644 studio/pages/project/[ref]/reports/storage.tsx diff --git a/studio/components/interfaces/Reports/Reports.constants.ts b/studio/components/interfaces/Reports/Reports.constants.ts index 71b5f65324f..354614b26f0 100644 --- a/studio/components/interfaces/Reports/Reports.constants.ts +++ b/studio/components/interfaces/Reports/Reports.constants.ts @@ -228,6 +228,50 @@ export const PRESET_CONFIG: Record = { title: '', queries: {}, }, + [Presets.STORAGE]: { + title: 'Storage', + queries: { + cacheHitRate: { + queryType: 'logs', + // storage report does not perform any filtering + sql: (_filters) => ` +SELECT + timestamp_trunc(timestamp, hour) as timestamp, + countif( h.cf_cache_status in ('HIT', 'STALE', 'REVALIDATED', 'UPDATING') ) as hit_count, + countif( h.cf_cache_status in ('MISS', 'NONE/UNKNOWN', 'EXPIRED', 'BYPASS', 'DYNAMIC') ) as miss_count +from edge_logs f + cross join unnest(f.metadata) as m + cross join unnest(m.request) as r + cross join unnest(m.response) as res + cross join unnest(res.headers) as h +where starts_with(r.path, '/storage/v1/object') and r.method = 'GET' +group by timestamp +order by timestamp desc +`, + }, + topCacheMisses: { + queryType: 'logs', + // storage report does not perform any filtering + sql: (_filters) => ` +SELECT + r.path as path, + r.search as search, + count(id) as count +from edge_logs f + cross join unnest(f.metadata) as m + cross join unnest(m.request) as r + cross join unnest(m.response) as res + cross join unnest(res.headers) as h +where starts_with(r.path, '/storage/v1/object') + and r.method = 'GET' + and h.cf_cache_status in ('MISS', 'NONE/UNKNOWN', 'EXPIRED', 'BYPASS', 'DYNAMIC') +group by path, search +order by count desc +limit 12 + `, + }, + }, + }, [Presets.QUERY_PERFORMANCE]: { title: 'Query performance', queries: { diff --git a/studio/components/interfaces/Reports/Reports.types.ts b/studio/components/interfaces/Reports/Reports.types.ts index a13240a5125..900a7c0c437 100644 --- a/studio/components/interfaces/Reports/Reports.types.ts +++ b/studio/components/interfaces/Reports/Reports.types.ts @@ -3,6 +3,7 @@ import { DEFAULT_QUERY_PARAMS } from './Reports.constants' export enum Presets { API = 'api', + STORAGE = 'storage', AUTH = 'auth', QUERY_PERFORMANCE = 'query_performance', } diff --git a/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx b/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx new file mode 100644 index 00000000000..0cc73886f19 --- /dev/null +++ b/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx @@ -0,0 +1,83 @@ +import { TextFormatter } from 'components/interfaces/Settings/Logs/LogsFormatters' +import Table from 'components/to-be-cleaned/Table' +import StackedBarChart from 'components/ui/Charts/StackedBarChart' +import { Fragment } from 'react' +import { ReportWidgetProps, ReportWidgetRendererProps } from '../ReportWidget' + +export const CacheHitRateChartRenderer = ( + props: ReportWidgetProps<{ + timestamp: string + hit_count: number + miss_count: number + }> +) => { + const stackedData = props.data.flatMap((datum) => [ + { + timestamp: datum.timestamp, + count: datum.hit_count, + type: 'hit', + }, + { + timestamp: datum.timestamp, + count: datum.miss_count, + type: 'miss', + }, + ]) + + return ( + + ) +} + +export const TopCacheMissesRenderer = ( + props: ReportWidgetRendererProps<{ + path: string + search: string + count: number + }> +) => { + if (props.data.length === 0) return null + const headerClasses = '!text-xs !py-2 p-0 font-bold !bg-scale-400' + const cellClasses = '!text-xs !py-2' + + return ( + + Request + Count + + } + body={ + <> + {props.data.map((datum) => ( + + + +
+ + +
+
+ + {datum.count} + +
+
+ ))} + + } + /> + ) +} diff --git a/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts b/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts index 4e088fd0ae6..1595e65861b 100644 --- a/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts +++ b/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts @@ -1,9 +1,10 @@ import { Project } from 'types' import { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types' +import { useFlag } from 'hooks' export const generateReportsMenu = (project?: Project): ProductMenuGroup[] => { const ref = project?.ref ?? 'default' - + const storageReportFlag = useFlag('storageReport') return [ { title: '', @@ -25,6 +26,17 @@ export const generateReportsMenu = (project?: Project): ProductMenuGroup[] => { items: [], label: 'NEW', }, + ...(storageReportFlag + ? [ + { + name: 'Storage', + key: 'storage', + url: `/project/${ref}/reports/storage`, + items: [], + label: 'NEW', + }, + ] + : []), { name: 'Database', key: 'database', diff --git a/studio/components/ui/Charts/Charts.constants.ts b/studio/components/ui/Charts/Charts.constants.ts index d760c7bf7e6..1354ac68914 100644 --- a/studio/components/ui/Charts/Charts.constants.ts +++ b/studio/components/ui/Charts/Charts.constants.ts @@ -10,28 +10,35 @@ export const CHART_COLORS = { } // refer to packages/ui/radix-colors.js for full list of colors -export const STACK_COLORS = [ - ['brand', 9], - ['mint', 9], - ['blue', 9], - ['sky', 9], - ['lime', 9], - ['yellow', 9], - ['orange', 9], -].map(([color, n]) => ({ - lighter: `var(--colors-${color}${(n as number) - 1})`, - base: `var(--colors-${color}${n})`, - darker: `var(--colors-${color}${(n as number) + 1})`, -})) +export type ValidStackColor = + | 'brand' + | 'blue' + | 'red' + | 'yellow' + | 'green' + | 'slate' + | 'indigo' + | 'tomato' + | 'orange' + | 'amber' -export const USAGE_COLORS = { - 200: 'hsl(var(--brand-default))', - 201: 'hsl(var(--brand-500))', - 400: 'var(--colors-amber9)', - 401: 'var(--colors-amber8)', - 404: 'var(--colors-amber7)', - 500: 'var(--colors-red9)', -} +export const genStackColorScales = (colors: ValidStackColor[]) => + colors.map((color) => { + // override default base scale for certain colors that do not have good contrast + const scale = + ( + { + slate: 11, + } as any + )[color] ?? 9 + return { + lighter: `var(--colors-${color}${(scale as number) - 1})`, + base: `var(--colors-${color}${scale})`, + darker: `var(--colors-${color}${(scale as number) + 1})`, + } + }) + +export const DEFAULT_STACK_COLORS = ['brand', 'slate', 'blue', 'yellow', 'indigo'] export enum DateTimeFormats { FULL = 'MMM D, YYYY, hh:mma', diff --git a/studio/components/ui/Charts/StackedBarChart.tsx b/studio/components/ui/Charts/StackedBarChart.tsx index 4ce2b8e1ee8..f3123578129 100644 --- a/studio/components/ui/Charts/StackedBarChart.tsx +++ b/studio/components/ui/Charts/StackedBarChart.tsx @@ -1,7 +1,7 @@ import { useState } from 'react' import { BarChart, Bar, XAxis, Tooltip, Legend, Cell, TooltipProps } from 'recharts' import ChartHeader from './ChartHeader' -import { CHART_COLORS, STACK_COLORS, DateTimeFormats } from './Charts.constants' +import { CHART_COLORS, STACK_COLORS, DateTimeFormats, DEFAULT_STACK_COLORS, genStackColorScales } from './Charts.constants' import { CommonChartProps } from './Charts.types' import { timestampFormatter, useChartSize, useStacked } from './Charts.utils' import { precisionFormatter } from './Charts.utils' @@ -16,6 +16,7 @@ interface Props extends CommonChartProps { displayDateInUtc?: boolean hideLegend?: boolean hideHeader?: boolean + stackColors?: ValidStackColor } const StackedBarChart: React.FC = ({ size, @@ -33,6 +34,7 @@ const StackedBarChart: React.FC = ({ displayDateInUtc, hideLegend = false, hideHeader = false, + stackColors = DEFAULT_STACK_COLORS }) => { const { Container } = useChartSize(size) const { dataKeys, stackedData, percentagesStackedData } = useStacked({ @@ -44,6 +46,7 @@ const StackedBarChart: React.FC = ({ }) const [focusDataIndex, setFocusDataIndex] = useState(null) if (!data || data.length === 0) return + const stackColorScales = genStackColorScales(stackColors) return (
{!hideHeader && ( @@ -94,7 +97,7 @@ const StackedBarChart: React.FC = ({ dataKey={datum} type="monotone" legendType="circle" - fill={STACK_COLORS[stackIndex].base} + fill={stackColorScales[stackIndex].base} stackId={1} animationDuration={300} maxBarSize={48} diff --git a/studio/pages/project/[ref]/reports/storage.tsx b/studio/pages/project/[ref]/reports/storage.tsx new file mode 100644 index 00000000000..80047336e38 --- /dev/null +++ b/studio/pages/project/[ref]/reports/storage.tsx @@ -0,0 +1,114 @@ +import { observer } from 'mobx-react-lite' +import { NextPageWithLayout } from 'types' +import { ReportsLayout } from 'components/layouts' +import { + PRESET_CONFIG, + REPORTS_DATEPICKER_HELPERS, +} from 'components/interfaces/Reports/Reports.constants' +import ReportWidget from 'components/interfaces/Reports/ReportWidget' +import { queriesFactory } from 'components/interfaces/Reports/Reports.utils' +import { + CacheHitRateChartRenderer, + TopCacheMissesRenderer, +} from 'components/interfaces/Reports/renderers/StorageRenderers' +import { useMemo } from 'react' +import ReportHeader from 'components/interfaces/Reports/ReportHeader' +import { DatePickerToFrom, LogsEndpointParams } from 'components/interfaces/Settings/Logs' +import { useParams } from 'common' +import ShimmerLine from 'components/ui/ShimmerLine' +import ReportPadding from 'components/interfaces/Reports/ReportPadding' +import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query' +import DatePickers from 'components/interfaces/Settings/Logs/Logs.DatePickers' + +export const StorageReport: NextPageWithLayout = () => { + const { ref: projectRef } = useParams() + const report = useStorageReport() + + const { data: subscription } = useProjectSubscriptionV2Query({ projectRef }) + const plan = subscription?.plan + + const handleDatepickerChange = ({ from, to }: DatePickerToFrom) => { + report.mergeParams({ + iso_timestamp_start: from || '', + iso_timestamp_end: to || '', + }) + } + + const datepickerHelpers = useMemo( + () => + REPORTS_DATEPICKER_HELPERS.map((helper, index) => ({ + ...helper, + disabled: (index > 0 && plan?.id === 'free') || (index > 1 && plan?.id !== 'pro'), + })), + [] + ) + + return ( + + +
+
+ +
+
+ +
+
+ + +
+ ) +} + +// hook to fetch data +const useStorageReport = () => { + const { ref: projectRef } = useParams() + + const queryHooks = queriesFactory( + PRESET_CONFIG.storage.queries, + projectRef ?? 'default' + ) + const cacheHitRate = queryHooks.cacheHitRate() + const topCacheMisses = queryHooks.topCacheMisses() + const activeHooks = [cacheHitRate, topCacheMisses] + + const handleRefresh = async () => { + activeHooks.forEach((hook) => hook.runQuery()) + } + const handleSetParams = (params: Partial) => { + activeHooks.forEach((hook) => { + hook.setParams?.((prev: LogsEndpointParams) => ({ ...prev, ...params })) + }) + } + const isLoading = activeHooks.some((hook) => hook.isLoading) + return { + data: { + cacheHitRate: cacheHitRate.logData, + topCacheMisses: topCacheMisses.logData, + }, + params: { + cacheHitRate: cacheHitRate.params, + topCacheMisses: topCacheMisses.params, + }, + mergeParams: handleSetParams, + isLoading, + refresh: handleRefresh, + } +} + +StorageReport.getLayout = (page) => {page} + +export default observer(StorageReport) From 9938efd61a4004c5eb935dc6b2280cab5620e579 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Sat, 9 Sep 2023 04:15:45 +0800 Subject: [PATCH 04/21] feat: add title to cache misses, add tooltip, adjust widget title --- .../Reports/renderers/StorageRenderers.tsx | 77 +++++++++++-------- .../pages/project/[ref]/reports/storage.tsx | 3 +- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx b/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx index 0cc73886f19..5c2d72afc88 100644 --- a/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx +++ b/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx @@ -11,6 +11,13 @@ export const CacheHitRateChartRenderer = ( miss_count: number }> ) => { + props.data = [ + { + timestamp: new Date().toISOString(), + hit_count: 123, + miss_count: 123, + }, + ] const stackedData = props.data.flatMap((datum) => [ { timestamp: datum.timestamp, @@ -44,40 +51,50 @@ export const TopCacheMissesRenderer = ( count: number }> ) => { + props.data = [ + { + path: '123', + search: '?123', + count: 123, + }, + ] if (props.data.length === 0) return null const headerClasses = '!text-xs !py-2 p-0 font-bold !bg-scale-400' const cellClasses = '!text-xs !py-2' return ( -
- Request - Count - - } - body={ - <> - {props.data.map((datum) => ( - - - -
- - -
-
- - {datum.count} - -
-
- ))} - - } - /> + <> +

Top Cache Misses

+
+ Request + Count + + } + body={ + <> + {props.data.map((datum) => ( + + + +
+ + +
+
+ + {datum.count} + +
+
+ ))} + + } + /> + ) } diff --git a/studio/pages/project/[ref]/reports/storage.tsx b/studio/pages/project/[ref]/reports/storage.tsx index 80047336e38..fe49c1fe7e5 100644 --- a/studio/pages/project/[ref]/reports/storage.tsx +++ b/studio/pages/project/[ref]/reports/storage.tsx @@ -63,7 +63,8 @@ export const StorageReport: NextPageWithLayout = () => { Date: Sat, 9 Sep 2023 04:17:37 +0800 Subject: [PATCH 05/21] chore: remove new label --- studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts b/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts index 1595e65861b..7fa7ca0238b 100644 --- a/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts +++ b/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts @@ -24,7 +24,6 @@ export const generateReportsMenu = (project?: Project): ProductMenuGroup[] => { key: 'api-overview', url: `/project/${ref}/reports/api-overview`, items: [], - label: 'NEW', }, ...(storageReportFlag ? [ @@ -48,7 +47,6 @@ export const generateReportsMenu = (project?: Project): ProductMenuGroup[] => { key: 'query-performance', url: `/project/${ref}/reports/query-performance`, items: [], - label: 'NEW', }, ], }, From 0ef21e837d2763d40663d948066caee499d7a662 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Sat, 9 Sep 2023 04:34:27 +0800 Subject: [PATCH 06/21] chore: fix failing tests, add test coverage to storage report --- .../interfaces/Reports/Reports.constants.ts | 2 + .../Reports/renderers/StorageRenderers.tsx | 14 ------- .../components/ui/Charts/Charts.constants.ts | 2 +- .../components/ui/Charts/StackedBarChart.tsx | 4 +- .../pages/project/[ref]/reports/storage.tsx | 13 +++++- .../projects/reports/storage-report.test.js | 42 +++++++++++++++++++ 6 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 studio/tests/pages/projects/reports/storage-report.test.js diff --git a/studio/components/interfaces/Reports/Reports.constants.ts b/studio/components/interfaces/Reports/Reports.constants.ts index 354614b26f0..f4c4f69fc39 100644 --- a/studio/components/interfaces/Reports/Reports.constants.ts +++ b/studio/components/interfaces/Reports/Reports.constants.ts @@ -235,6 +235,7 @@ export const PRESET_CONFIG: Record = { queryType: 'logs', // storage report does not perform any filtering sql: (_filters) => ` +-- cache-hit-rate SELECT timestamp_trunc(timestamp, hour) as timestamp, countif( h.cf_cache_status in ('HIT', 'STALE', 'REVALIDATED', 'UPDATING') ) as hit_count, @@ -253,6 +254,7 @@ order by timestamp desc queryType: 'logs', // storage report does not perform any filtering sql: (_filters) => ` +-- top-cache-misses SELECT r.path as path, r.search as search, diff --git a/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx b/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx index 5c2d72afc88..cdff467d303 100644 --- a/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx +++ b/studio/components/interfaces/Reports/renderers/StorageRenderers.tsx @@ -11,13 +11,6 @@ export const CacheHitRateChartRenderer = ( miss_count: number }> ) => { - props.data = [ - { - timestamp: new Date().toISOString(), - hit_count: 123, - miss_count: 123, - }, - ] const stackedData = props.data.flatMap((datum) => [ { timestamp: datum.timestamp, @@ -51,13 +44,6 @@ export const TopCacheMissesRenderer = ( count: number }> ) => { - props.data = [ - { - path: '123', - search: '?123', - count: 123, - }, - ] if (props.data.length === 0) return null const headerClasses = '!text-xs !py-2 p-0 font-bold !bg-scale-400' const cellClasses = '!text-xs !py-2' diff --git a/studio/components/ui/Charts/Charts.constants.ts b/studio/components/ui/Charts/Charts.constants.ts index 1354ac68914..f9161102054 100644 --- a/studio/components/ui/Charts/Charts.constants.ts +++ b/studio/components/ui/Charts/Charts.constants.ts @@ -38,7 +38,7 @@ export const genStackColorScales = (colors: ValidStackColor[]) => } }) -export const DEFAULT_STACK_COLORS = ['brand', 'slate', 'blue', 'yellow', 'indigo'] +export const DEFAULT_STACK_COLORS : ValidStackColor[] = ['brand', 'slate', 'blue', 'yellow', 'indigo'] export enum DateTimeFormats { FULL = 'MMM D, YYYY, hh:mma', diff --git a/studio/components/ui/Charts/StackedBarChart.tsx b/studio/components/ui/Charts/StackedBarChart.tsx index f3123578129..3dbf7e214e0 100644 --- a/studio/components/ui/Charts/StackedBarChart.tsx +++ b/studio/components/ui/Charts/StackedBarChart.tsx @@ -1,7 +1,7 @@ import { useState } from 'react' import { BarChart, Bar, XAxis, Tooltip, Legend, Cell, TooltipProps } from 'recharts' import ChartHeader from './ChartHeader' -import { CHART_COLORS, STACK_COLORS, DateTimeFormats, DEFAULT_STACK_COLORS, genStackColorScales } from './Charts.constants' +import { CHART_COLORS, DateTimeFormats, DEFAULT_STACK_COLORS, genStackColorScales, ValidStackColor } from './Charts.constants' import { CommonChartProps } from './Charts.types' import { timestampFormatter, useChartSize, useStacked } from './Charts.utils' import { precisionFormatter } from './Charts.utils' @@ -16,7 +16,7 @@ interface Props extends CommonChartProps { displayDateInUtc?: boolean hideLegend?: boolean hideHeader?: boolean - stackColors?: ValidStackColor + stackColors?: ValidStackColor[] } const StackedBarChart: React.FC = ({ size, diff --git a/studio/pages/project/[ref]/reports/storage.tsx b/studio/pages/project/[ref]/reports/storage.tsx index fe49c1fe7e5..664265e07a0 100644 --- a/studio/pages/project/[ref]/reports/storage.tsx +++ b/studio/pages/project/[ref]/reports/storage.tsx @@ -11,7 +11,7 @@ import { CacheHitRateChartRenderer, TopCacheMissesRenderer, } from 'components/interfaces/Reports/renderers/StorageRenderers' -import { useMemo } from 'react' +import { useEffect, useMemo } from 'react' import ReportHeader from 'components/interfaces/Reports/ReportHeader' import { DatePickerToFrom, LogsEndpointParams } from 'components/interfaces/Settings/Logs' import { useParams } from 'common' @@ -94,6 +94,17 @@ const useStorageReport = () => { hook.setParams?.((prev: LogsEndpointParams) => ({ ...prev, ...params })) }) } + useEffect(()=>{ + + if (cacheHitRate.changeQuery) { + cacheHitRate.changeQuery(PRESET_CONFIG.storage.queries.cacheHitRate.sql([])) + } + + if (topCacheMisses.changeQuery) { + topCacheMisses.changeQuery(PRESET_CONFIG.storage.queries.topCacheMisses.sql([])) + } + + }, []) const isLoading = activeHooks.some((hook) => hook.isLoading) return { data: { diff --git a/studio/tests/pages/projects/reports/storage-report.test.js b/studio/tests/pages/projects/reports/storage-report.test.js new file mode 100644 index 00000000000..6d24e13ca85 --- /dev/null +++ b/studio/tests/pages/projects/reports/storage-report.test.js @@ -0,0 +1,42 @@ +import { get } from 'lib/common/fetch' +import { render } from '../../../helpers' +import { waitFor, screen } from '@testing-library/react' +import { StorageReport } from 'pages/project/[ref]/reports/storage' +import userEvent from '@testing-library/user-event' + +beforeEach(() => { + // reset mocks between tests + get.mockReset() + get.mockImplementation(async (_url) => [{ result: [] }]) +}) + +test(`static elements`, async () => { + render() + await screen.findByText('Request Caching') + await screen.findByText(/Last 24 hours/) + await screen.findByText(/Custom/) +}) + +test('refresh button', async () => { + render() + await waitFor(() => expect(get).toBeCalled()) + get.mockReset() + userEvent.click(await screen.findByText(/Refresh/)) + await waitFor(() => expect(get).toBeCalled()) +}) + +test('append - top cache misses', async () => { + get.mockImplementation(async (url) => { + if (decodeURIComponent(url).includes('misses')) { + return { + result: [{ path: 'mypath', search: 'some-query', count: 22 }], + } + } + return { result: [{ timestamp: new Date().toISOString(), miss_count: 123, hit_count: 123 }] } + }) + render() + await waitFor(() => expect(get).toBeCalled()) + await screen.findAllByText(/mypath/) + await screen.findAllByText(/some\-query/) + await screen.findAllByText(/22/) +}) From cb46a12e90670257f998eaceae4b493a9e803c05 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Sat, 9 Sep 2023 04:54:35 +0800 Subject: [PATCH 07/21] chore: fix compilation error --- .../layouts/ReportsLayout/ReportsLayout.tsx | 52 +++++++++++++++++- .../ReportsLayout/ReportsMenu.utils.ts | 54 ------------------- 2 files changed, 51 insertions(+), 55 deletions(-) delete mode 100644 studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts diff --git a/studio/components/layouts/ReportsLayout/ReportsLayout.tsx b/studio/components/layouts/ReportsLayout/ReportsLayout.tsx index f1517357776..ef82b75c120 100644 --- a/studio/components/layouts/ReportsLayout/ReportsLayout.tsx +++ b/studio/components/layouts/ReportsLayout/ReportsLayout.tsx @@ -5,6 +5,7 @@ import ProductMenu from 'components/ui/ProductMenu' import { useSelectedProject, withAuth } from 'hooks' import ProjectLayout from '../' import { generateReportsMenu } from './ReportsMenu.utils' +import { useFlag } from 'hooks' interface ReportsLayoutProps { title?: string @@ -15,12 +16,61 @@ const ReportsLayout = ({ title, children }: PropsWithChildren} + productMenu={} >
{children} diff --git a/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts b/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts deleted file mode 100644 index 7fa7ca0238b..00000000000 --- a/studio/components/layouts/ReportsLayout/ReportsMenu.utils.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Project } from 'types' -import { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types' -import { useFlag } from 'hooks' - -export const generateReportsMenu = (project?: Project): ProductMenuGroup[] => { - const ref = project?.ref ?? 'default' - const storageReportFlag = useFlag('storageReport') - return [ - { - title: '', - items: [ - { - name: 'Custom reports', - key: '', - url: `/project/${ref}/reports`, - items: [], - }, - ], - }, - { - items: [ - { - name: 'API', - key: 'api-overview', - url: `/project/${ref}/reports/api-overview`, - items: [], - }, - ...(storageReportFlag - ? [ - { - name: 'Storage', - key: 'storage', - url: `/project/${ref}/reports/storage`, - items: [], - label: 'NEW', - }, - ] - : []), - { - name: 'Database', - key: 'database', - url: `/project/${ref}/reports/database`, - items: [], - }, - { - name: 'Query Performance', - key: 'query-performance', - url: `/project/${ref}/reports/query-performance`, - items: [], - }, - ], - }, - ] -} From e35fbe564511ad4093deec4728e7323bdf51f0e5 Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Sat, 9 Sep 2023 05:09:14 +0800 Subject: [PATCH 08/21] chore fix compilation --- studio/components/layouts/ReportsLayout/ReportsLayout.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/studio/components/layouts/ReportsLayout/ReportsLayout.tsx b/studio/components/layouts/ReportsLayout/ReportsLayout.tsx index ef82b75c120..0bdd0813a26 100644 --- a/studio/components/layouts/ReportsLayout/ReportsLayout.tsx +++ b/studio/components/layouts/ReportsLayout/ReportsLayout.tsx @@ -4,7 +4,6 @@ import { PropsWithChildren } from 'react' import ProductMenu from 'components/ui/ProductMenu' import { useSelectedProject, withAuth } from 'hooks' import ProjectLayout from '../' -import { generateReportsMenu } from './ReportsMenu.utils' import { useFlag } from 'hooks' interface ReportsLayoutProps { From 4b7ea6eb8c6ac01ba7f5e46363575ae3c0214d8b Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Mon, 11 Sep 2023 17:13:11 +0800 Subject: [PATCH 09/21] chore: fix import --- studio/components/ui/Charts/Sparkline.stories.tsx | 2 +- studio/components/ui/Charts/StackedBarChart.stories.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/studio/components/ui/Charts/Sparkline.stories.tsx b/studio/components/ui/Charts/Sparkline.stories.tsx index 5cb2e257683..18a620f4576 100644 --- a/studio/components/ui/Charts/Sparkline.stories.tsx +++ b/studio/components/ui/Charts/Sparkline.stories.tsx @@ -3,7 +3,7 @@ import { ComponentStory, ComponentMeta } from '@storybook/react' import dayjs from 'dayjs' import Chart from './Sparkline' import { StackedChartProps } from './Charts.types' -import { STACK_COLORS } from './Charts.constants' +import { DEFAULT_STACK_COLORs } from './Charts.constants' export default { title: 'Charts/Sparkline', diff --git a/studio/components/ui/Charts/StackedBarChart.stories.tsx b/studio/components/ui/Charts/StackedBarChart.stories.tsx index 9eb71d42736..822542315cf 100644 --- a/studio/components/ui/Charts/StackedBarChart.stories.tsx +++ b/studio/components/ui/Charts/StackedBarChart.stories.tsx @@ -3,7 +3,7 @@ import { ComponentStory, ComponentMeta } from '@storybook/react' import dayjs from 'dayjs' import Chart from './StackedBarChart' import { StackedChartProps } from './Charts.types' -import { STACK_COLORS } from './Charts.constants' +import { DEFAULT_STACK_COLORS } from './Charts.constants' export default { title: 'Charts/StackedBarChart', @@ -38,7 +38,7 @@ export const StackedBarChart = () => (
Default Stacked Chart Colors
- {STACK_COLORS.map((c) => ( + {DEFAULT_STACK_COLORS.map((c) => (
))}
From e53d93c4dcb1622781af864602427355fc93c0ea Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Mon, 11 Sep 2023 18:32:06 +0800 Subject: [PATCH 10/21] chore: fix typo --- studio/components/ui/Charts/Sparkline.stories.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/studio/components/ui/Charts/Sparkline.stories.tsx b/studio/components/ui/Charts/Sparkline.stories.tsx index 18a620f4576..1808d40a2d6 100644 --- a/studio/components/ui/Charts/Sparkline.stories.tsx +++ b/studio/components/ui/Charts/Sparkline.stories.tsx @@ -1,9 +1,7 @@ import React from 'react' -import { ComponentStory, ComponentMeta } from '@storybook/react' +import { ComponentMeta } from '@storybook/react' import dayjs from 'dayjs' import Chart from './Sparkline' -import { StackedChartProps } from './Charts.types' -import { DEFAULT_STACK_COLORs } from './Charts.constants' export default { title: 'Charts/Sparkline', From 7d047ccd4da8f880581882e4320952f3260298af Mon Sep 17 00:00:00 2001 From: TzeYiing Date: Mon, 11 Sep 2023 18:45:05 +0800 Subject: [PATCH 11/21] chore: fix typing error --- studio/components/ui/Charts/StackedBarChart.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/studio/components/ui/Charts/StackedBarChart.stories.tsx b/studio/components/ui/Charts/StackedBarChart.stories.tsx index 822542315cf..8a308ea5ffd 100644 --- a/studio/components/ui/Charts/StackedBarChart.stories.tsx +++ b/studio/components/ui/Charts/StackedBarChart.stories.tsx @@ -3,7 +3,7 @@ import { ComponentStory, ComponentMeta } from '@storybook/react' import dayjs from 'dayjs' import Chart from './StackedBarChart' import { StackedChartProps } from './Charts.types' -import { DEFAULT_STACK_COLORS } from './Charts.constants' +import { DEFAULT_STACK_COLORS, genStackColorScales } from './Charts.constants' export default { title: 'Charts/StackedBarChart', @@ -38,7 +38,7 @@ export const StackedBarChart = () => (
Default Stacked Chart Colors
- {DEFAULT_STACK_COLORS.map((c) => ( + {genStackColorScales(DEFAULT_STACK_COLORS).map((c) => (
))}
From 9589b4eea62504e99fc261676d58c909c89f51c1 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Tue, 12 Sep 2023 17:34:17 +0800 Subject: [PATCH 12/21] Provide convenient unit selection for custom expiry in storage --- .../StorageExplorer/CustomExpiryModal.tsx | 56 +++++++++++++++---- .../StorageExplorer/FileExplorerRow.tsx | 1 + 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx b/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx index d20d137cdbc..55197f896fd 100644 --- a/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx +++ b/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx @@ -1,4 +1,4 @@ -import { Form, Modal, Input, Button } from 'ui' +import { Form, Modal, Input, Button, Listbox } from 'ui' import { observer } from 'mobx-react-lite' import { useStorageStore } from 'localStores/storageExplorer/StorageExplorerStore' @@ -6,6 +6,13 @@ export interface CustomExpiryModalProps { onCopyUrl: (name: string, url: string) => void } +const unitMap: { seconds: number; days: number; months: number; years: number } = { + seconds: 1, + days: 3600 * 24, + months: 3600 * 24 * 30, + years: 3600 * 24 * 365, +} + const CustomExpiryModal = ({ onCopyUrl }: CustomExpiryModalProps) => { const storageExplorerStore = useStorageStore() const { getFileUrl, selectedFileCustomExpiry, setSelectedFileCustomExpiry } = storageExplorerStore @@ -25,34 +32,59 @@ const CustomExpiryModal = ({ onCopyUrl }: CustomExpiryModalProps) => { >
{ setSubmitting(true) onCopyUrl( selectedFileCustomExpiry.name, - await getFileUrl(selectedFileCustomExpiry, values.expiresIn) + await getFileUrl( + selectedFileCustomExpiry, + values.expiresIn * unitMap[values.units as 'seconds' | 'days' | 'months' | 'years'] + ) ) setSubmitting(false) onClose() }} validate={(values: any) => { const errors: any = {} - if (values.expiresIn !== '' && values.expiresIn <= 0) + if (values.expiresIn !== '' && values.expiresIn <= 0) { errors.expiresIn = 'Expiry duration cannot be less than 0' + } return errors }} > {({ values, isSubmitting }: { values: any; isSubmitting: boolean }) => ( <> -
+
- seconds

} - /> +

+ Enter the duration for which the URL will be valid for: +

+
+ + + + seconds + + + days + + + months + + + years + + +
+ {values.units !== 'seconds' && ( +

+ Equivalent to{' '} + {values.expiresIn * + unitMap[values.units as 'seconds' | 'days' | 'months' | 'years']}{' '} + seconds +

+ )}
diff --git a/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerRow.tsx b/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerRow.tsx index ba4ee7bc678..36a73884997 100644 --- a/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerRow.tsx +++ b/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerRow.tsx @@ -409,6 +409,7 @@ const FileExplorerRow = ({ /> ) : ( Date: Tue, 12 Sep 2023 18:55:19 +0800 Subject: [PATCH 13/21] Update custom expiry units selection --- .../StorageExplorer/CustomExpiryModal.tsx | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx b/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx index 55197f896fd..82697ff1ce1 100644 --- a/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx +++ b/studio/components/to-be-cleaned/Storage/StorageExplorer/CustomExpiryModal.tsx @@ -1,14 +1,17 @@ -import { Form, Modal, Input, Button, Listbox } from 'ui' +import dayjs from 'dayjs' import { observer } from 'mobx-react-lite' +import { Button, Form, Input, Listbox, Modal } from 'ui' + +import { DATETIME_FORMAT } from 'lib/constants' import { useStorageStore } from 'localStores/storageExplorer/StorageExplorerStore' export interface CustomExpiryModalProps { onCopyUrl: (name: string, url: string) => void } -const unitMap: { seconds: number; days: number; months: number; years: number } = { - seconds: 1, +const unitMap = { days: 3600 * 24, + weeks: 3600 * 24 * 7, months: 3600 * 24 * 30, years: 3600 * 24 * 365, } @@ -32,14 +35,14 @@ const CustomExpiryModal = ({ onCopyUrl }: CustomExpiryModalProps) => { > { setSubmitting(true) onCopyUrl( selectedFileCustomExpiry.name, await getFileUrl( selectedFileCustomExpiry, - values.expiresIn * unitMap[values.units as 'seconds' | 'days' | 'months' | 'years'] + values.expiresIn * unitMap[values.units as 'days' | 'weeks' | 'months' | 'years'] ) ) setSubmitting(false) @@ -63,12 +66,12 @@ const CustomExpiryModal = ({ onCopyUrl }: CustomExpiryModalProps) => {
- - seconds - days + + weeks + months @@ -77,12 +80,10 @@ const CustomExpiryModal = ({ onCopyUrl }: CustomExpiryModalProps) => {
- {values.units !== 'seconds' && ( + {values.expiresIn !== '' && (

- Equivalent to{' '} - {values.expiresIn * - unitMap[values.units as 'seconds' | 'days' | 'months' | 'years']}{' '} - seconds + URL will expire on{' '} + {dayjs().add(values.expiresIn, values.units).format(DATETIME_FORMAT)}

)} From 97c990cd30e73d4b3502b1e0fddb602db0fa7774 Mon Sep 17 00:00:00 2001 From: Francesco Sansalvadore Date: Tue, 12 Sep 2023 17:50:56 +0200 Subject: [PATCH 14/21] remove lw8 announcement banner from www and docs --- apps/docs/layouts/SiteLayout.tsx | 4 ---- apps/www/components/Nav/index.tsx | 6 +----- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/apps/docs/layouts/SiteLayout.tsx b/apps/docs/layouts/SiteLayout.tsx index 1b0f0a75df1..953cb518817 100644 --- a/apps/docs/layouts/SiteLayout.tsx +++ b/apps/docs/layouts/SiteLayout.tsx @@ -8,7 +8,6 @@ import Head from 'next/head' import { PropsWithChildren, memo } from 'react' import Footer from '~/components/Navigation/Footer' import { menuState, useMenuLevelId, useMenuMobileOpen } from '~/hooks/useMenuState' -import { Announcement, LW8CountdownBanner } from 'ui' const levelsData = { home: { @@ -327,9 +326,6 @@ const SiteLayout = ({ children }: PropsWithChildren<{}>) => { Supabase Docs
- - -
diff --git a/apps/www/components/Nav/index.tsx b/apps/www/components/Nav/index.tsx index 2230165ec95..b36fd57c9dd 100644 --- a/apps/www/components/Nav/index.tsx +++ b/apps/www/components/Nav/index.tsx @@ -2,8 +2,7 @@ import React, { useState } from 'react' import Link from 'next/link' import { useRouter } from 'next/router' -import Announcement from '~/components/Announcement/Announcement' -import { Button, Badge, IconStar, IconChevronDown, LW8CountdownBanner } from 'ui' +import { Button, Badge, IconStar, IconChevronDown } from 'ui' import FlyOut from '~/components/UI/FlyOut' import Transition from 'lib/Transition' @@ -198,9 +197,6 @@ const Nav = () => { return ( <> - - -
Date: Tue, 12 Sep 2023 18:09:32 +0200 Subject: [PATCH 15/21] remove lw8 gradient from hp hero --- apps/www/components/Hero/Hero.tsx | 33 ++++--------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/apps/www/components/Hero/Hero.tsx b/apps/www/components/Hero/Hero.tsx index b9541ab3222..f67ade341c9 100644 --- a/apps/www/components/Hero/Hero.tsx +++ b/apps/www/components/Hero/Hero.tsx @@ -8,7 +8,7 @@ import SectionContainer from '~/components/Layouts/SectionContainer' import HeroFrameworks from './HeroFrameworks' import styles from './hero.module.css' import Image from 'next/image' -import AnnouncementBadge from '../Announcement/Badge' +// import AnnouncementBadge from '../Announcement/Badge' const Hero = () => { const router = useRouter() @@ -19,7 +19,7 @@ const Hero = () => { return (
- +
@@ -30,9 +30,9 @@ const Hero = () => { ].join(' ')} >
-
+ {/*
-
+
*/}

Build in a weekend @@ -80,32 +80,7 @@ const Hero = () => {

-
- - - -
-
- -
-
) } From 956f9443f8fd8747a9482dcc84887bf66622b450 Mon Sep 17 00:00:00 2001 From: Francesco Sansalvadore Date: Tue, 12 Sep 2023 18:42:00 +0200 Subject: [PATCH 16/21] update latest announcements in nav --- apps/www/data/Announcements.json | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/www/data/Announcements.json b/apps/www/data/Announcements.json index 66a4bdd4d57..d41e4517028 100644 --- a/apps/www/data/Announcements.json +++ b/apps/www/data/Announcements.json @@ -1,4 +1,19 @@ [ + { + "type": "Announcement", + "title": "Supabase Beta August 2023", + "description": "Launch Week 8 review and more things we shipped 🚀", + "imgUrl": "/images/blog/2023-09-07-beta-update-august-2023/monthly-update-august-2023.jpg", + "logoUrl": "/images/blog/2023-09-07-beta-update-august-2023/monthly-update-august-2023.jpg", + "organization": "Supabase", + "url": "/blog/beta-update-august-2023", + "postMeta": { + "name": "Ant Wilson", + "publishDate": "Sep 08, 2023", + "readLength": 5 + }, + "ctaText": "Learn more" + }, { "type": "Announcement", "title": "Launch Week 8 Hackathon Winners", @@ -13,20 +28,5 @@ "readLength": 3 }, "ctaText": "See the winners" - }, - { - "type": "Announcement", - "title": "Supabase Launch Week 8", - "description": "One new feature (or more) every day during a week.", - "imgUrl": "/images/launchweek/8/lw8-og.jpg", - "logoUrl": "/images/launchweek/8/lw8-og.jpg", - "organization": "Supabase", - "url": "/launch-week", - "postMeta": { - "name": "Paul Copplestone", - "publishDate": "Aug 07, 2023", - "readLength": 5 - }, - "ctaText": "Learn more" } ] From 6383d8ab26324874eceedb13340565decee3dddb Mon Sep 17 00:00:00 2001 From: Francesco Sansalvadore Date: Tue, 12 Sep 2023 18:42:26 +0200 Subject: [PATCH 17/21] fix react svg attributes --- apps/www/components/Nav/Developers.tsx | 2 +- apps/www/pages/partners/index.tsx | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/www/components/Nav/Developers.tsx b/apps/www/components/Nav/Developers.tsx index 9fdc46c12bf..1663d190aca 100644 --- a/apps/www/components/Nav/Developers.tsx +++ b/apps/www/components/Nav/Developers.tsx @@ -32,7 +32,7 @@ const Developers = () => { stroke="currentColor" aria-hidden="true" > - + )} {Svg && } diff --git a/apps/www/pages/partners/index.tsx b/apps/www/pages/partners/index.tsx index 6c3ae25aa8d..eae38fcd495 100644 --- a/apps/www/pages/partners/index.tsx +++ b/apps/www/pages/partners/index.tsx @@ -51,8 +51,8 @@ const Partners = () => { { y2="21.5" gradientUnits="userSpaceOnUse" > - - - + + + From 40e96436bea385f2b863743e67dd336227728f39 Mon Sep 17 00:00:00 2001 From: Francesco Sansalvadore Date: Tue, 12 Sep 2023 18:53:40 +0200 Subject: [PATCH 18/21] adjust Pricing page announcement badge --- apps/www/components/Announcement/Badge.tsx | 21 +++++++--- apps/www/pages/pricing/index.tsx | 49 ++++------------------ 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/apps/www/components/Announcement/Badge.tsx b/apps/www/components/Announcement/Badge.tsx index adbc7accd87..e2a379c8747 100644 --- a/apps/www/components/Announcement/Badge.tsx +++ b/apps/www/components/Announcement/Badge.tsx @@ -3,10 +3,17 @@ import Link from 'next/link' import { Badge } from 'ui' import { ArrowNarrowRightIcon } from '@heroicons/react/outline' -const AnnouncementBadge = () => ( +interface Props { + url: string + announcement: string + badge?: string + target?: '_self' | '_blank' +} +const AnnouncementBadge = ({ url, announcement, badge, target = '_self' }: Props) => (
- + - - Explore - - Launch Week 8 announcements + {badge && ( + + {badge} + + )} + {announcement}
+

Pricing

@@ -159,45 +160,13 @@ export default function IndexPage() {

Start building for free, collaborate with a team, then scale to millions of users.

-
From f72ef25e18ee25c89c81bce85c7df51cb6001eb5 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Tue, 12 Sep 2023 16:27:55 -0230 Subject: [PATCH 19/21] Update --- .../SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx index 35769943d49..477252ef4eb 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.tsx @@ -303,7 +303,7 @@ const ForeignKeySelector = ({ The column types don't match - + The referenced column {column?.name && {column.name}} {column?.format ? ( @@ -320,7 +320,7 @@ const ForeignKeySelector = ({ has {selectedColumn?.data_type}type. These two - columns can't be referenced until they of the same type. + columns can't be referenced until they are of the same type. )} From f4133d63d8da64e84dc4b5e221ff9ef15578328a Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Tue, 12 Sep 2023 13:15:17 -0600 Subject: [PATCH 20/21] chore(sql-editor): add more log information for ai requests --- studio/pages/api/ai/sql/debug.ts | 4 +++- studio/pages/api/ai/sql/edit.ts | 4 +++- studio/pages/api/ai/sql/generate.ts | 4 +++- studio/pages/api/ai/sql/title.ts | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/studio/pages/api/ai/sql/debug.ts b/studio/pages/api/ai/sql/debug.ts index 353f11b5a87..2a67dc50062 100644 --- a/studio/pages/api/ai/sql/debug.ts +++ b/studio/pages/api/ai/sql/debug.ts @@ -178,7 +178,9 @@ export async function handlePost(req: NextApiRequest, res: NextApiResponse) { return res.json(debugSqlResult) } catch (error) { console.error( - `AI SQL editing failed: ${isError(error) ? error.message : 'An unknown error occurred'}` + `AI SQL editing failed: ${ + isError(error) ? error.message : 'An unknown error occurred' + }, sqlResponseString: ${sqlResponseString}` ) return res.status(500).json({ diff --git a/studio/pages/api/ai/sql/edit.ts b/studio/pages/api/ai/sql/edit.ts index 70d4ad4e19a..979b13a5a2f 100644 --- a/studio/pages/api/ai/sql/edit.ts +++ b/studio/pages/api/ai/sql/edit.ts @@ -170,7 +170,9 @@ export async function handlePost(req: NextApiRequest, res: NextApiResponse) { return res.json(editSqlResult) } catch (error) { console.error( - `AI SQL editing failed: ${isError(error) ? error.message : 'An unknown error occurred'}` + `AI SQL editing failed: ${ + isError(error) ? error.message : 'An unknown error occurred' + }, sqlResponseString: ${sqlResponseString}` ) return res.status(500).json({ diff --git a/studio/pages/api/ai/sql/generate.ts b/studio/pages/api/ai/sql/generate.ts index 7fb2dbbfc77..7231c9c953c 100644 --- a/studio/pages/api/ai/sql/generate.ts +++ b/studio/pages/api/ai/sql/generate.ts @@ -158,7 +158,9 @@ export async function handlePost(req: NextApiRequest, res: NextApiResponse) { return res.json(generateSqlResult) } catch (error) { console.error( - `AI SQL editing failed: ${isError(error) ? error.message : 'An unknown error occurred'}` + `AI SQL editing failed: ${ + isError(error) ? error.message : 'An unknown error occurred' + }, sqlResponseString: ${sqlResponseString}` ) return res.status(500).json({ diff --git a/studio/pages/api/ai/sql/title.ts b/studio/pages/api/ai/sql/title.ts index bde2ee4db7c..7f34a3227bd 100644 --- a/studio/pages/api/ai/sql/title.ts +++ b/studio/pages/api/ai/sql/title.ts @@ -136,7 +136,9 @@ export async function handlePost(req: NextApiRequest, res: NextApiResponse) { return res.json(generateTitleResult) } catch (error) { console.error( - `AI SQL editing failed: ${isError(error) ? error.message : 'An unknown error occurred'}` + `AI SQL editing failed: ${ + isError(error) ? error.message : 'An unknown error occurred' + }, titleResponseString: ${titleResponseString}` ) return res.status(500).json({ From 9070a469df761142da019ea024cf09c93e4d25c0 Mon Sep 17 00:00:00 2001 From: Pamela Chia Date: Wed, 13 Sep 2023 08:07:58 +0800 Subject: [PATCH 21/21] fix/ correct hipaa description in pricing page --- packages/shared-data/plans.ts | 2 +- packages/shared-data/pricing.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/shared-data/plans.ts b/packages/shared-data/plans.ts index 5e40e4b5c51..d13c90cb463 100644 --- a/packages/shared-data/plans.ts +++ b/packages/shared-data/plans.ts @@ -94,7 +94,7 @@ export const plans: PricingInformation[] = [ 'Daily backups stored for 14 days', 'Standardised Security Questionnaire', 'SOC2', - 'HIPAA', + 'HIPAA available as paid add-on', 'SSO for Supabase Dashboard', 'Priority email support & SLAs', '28-day log retention', diff --git a/packages/shared-data/pricing.ts b/packages/shared-data/pricing.ts index b955a8cfe2f..3bd10372288 100644 --- a/packages/shared-data/pricing.ts +++ b/packages/shared-data/pricing.ts @@ -469,8 +469,8 @@ export const pricing: Pricing = { plans: { free: false, pro: false, - team: true, - enterprise: true, + team: 'Available as paid add-on', + enterprise: 'Available as paid add-on', }, tooltips: { main: 'Available as a paid add-on on Team plan and above.',