From d56aeeb359b2408f814a7dacfea0d90e767a95db Mon Sep 17 00:00:00 2001 From: Jason Zi Feng Lei Date: Tue, 12 Apr 2022 10:12:07 +0800 Subject: [PATCH 001/208] Updated default values for "Default Organization" and "Default Project" to be able to read from a .env file. --- docker/.env.example | 2 ++ docker/docker-compose.yml | 3 +++ studio/.env | 3 +++ studio/README.md | 7 +++++++ studio/pages/api/organizations/index.ts | 5 +++-- studio/pages/api/profile/index.ts | 7 ++++--- studio/pages/api/projects/[ref]/index.ts | 5 +++-- studio/pages/api/props/project/[ref]/api.ts | 3 ++- studio/pages/api/props/project/[ref]/index.ts | 3 ++- studio/pages/api/props/project/[ref]/settings.ts | 3 ++- 10 files changed, 31 insertions(+), 10 deletions(-) diff --git a/docker/.env.example b/docker/.env.example index 37e4b9a21d0..8d1b25b9770 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -41,6 +41,8 @@ KONG_HTTPS_PORT=8443 POSTGRES_PORT=5432 # Studio +STUDIO_ORGANIZATION_NAME=Default Organization +STUDIO_PROJECT_NAME=Default Project ## Public REST endpoint - replace this if you intend to use Studio outside of localhost PUBLIC_REST_URL=http://localhost:8000/rest/v1/ diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index cd965f3457d..be10619c4e0 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -17,6 +17,9 @@ services: STUDIO_PG_META_URL: http://meta:8080 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + DEFAULT_ORGANIZATION: ${STUDIO_DEFAULT_ORGANIZATION} + DEFAULT_PROJECT: ${STUDIO_DEFAULT_PROJECT} + SUPABASE_URL: http://kong:8000 SUPABASE_REST_URL: ${PUBLIC_REST_URL} SUPABASE_ANON_KEY: ${ANON_KEY} diff --git a/studio/.env b/studio/.env index db284f3411e..478baf5dc20 100644 --- a/studio/.env +++ b/studio/.env @@ -1,6 +1,9 @@ STUDIO_PG_META_URL=http://localhost:8000/pg POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password +DEFAULT_ORGANIZATION_NAME=Default Organization +DEFAULT_PROJECT_NAME=Default Project + SUPABASE_URL=http://localhost:8000 SUPABASE_REST_URL=http://localhost:8000/rest/v1/ SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE diff --git a/studio/README.md b/studio/README.md index df0df945274..e493579522d 100644 --- a/studio/README.md +++ b/studio/README.md @@ -73,6 +73,13 @@ npm install npm run dev ``` +If you would like to configure different defaults for "Default Organization" and "Default Project", you will need to update the `.env` in the studio folder with the corresponding values. + +``` +DEFAULT_ORGANIZATION_NAME= +DEFAULT_PROJECT_NAME= +``` + ## UI Testing Notes ### `` vs `` diff --git a/studio/pages/api/organizations/index.ts b/studio/pages/api/organizations/index.ts index d347ad0c017..c3b41b29bbd 100644 --- a/studio/pages/api/organizations/index.ts +++ b/studio/pages/api/organizations/index.ts @@ -1,6 +1,7 @@ -import apiWrapper from 'lib/api/apiWrapper' import { NextApiRequest, NextApiResponse } from 'next' +import apiWrapper from 'lib/api/apiWrapper' + export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler) async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -20,7 +21,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { const response = [ { id: 1, - name: 'Default Organization', + name: 'Default Organization' || process.env.DEFAULT_ORGANIZATION_NAME, slug: 'default-org-slug', billing_email: 'billing@supabase.co', }, diff --git a/studio/pages/api/profile/index.ts b/studio/pages/api/profile/index.ts index c6945b970ef..a985c48479b 100644 --- a/studio/pages/api/profile/index.ts +++ b/studio/pages/api/profile/index.ts @@ -1,7 +1,8 @@ import { NextApiRequest, NextApiResponse } from 'next' + import { IS_PLATFORM } from 'lib/constants' -import { createEncryptedDbConnectionString } from 'lib/api/apiHelpers' import apiWrapper from 'lib/api/apiWrapper' +import { createEncryptedDbConnectionString } from 'lib/api/apiHelpers' export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler) @@ -28,14 +29,14 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { organizations: [ { id: 1, - name: 'Default Organization', + name: 'Default Organization' || process.env.DEFAULT_ORGANIZATION_NAME, slug: 'default-org-slug', billing_email: 'billing@supabase.co', projects: [ { id: 1, ref: 'default', - name: 'Default Project', + name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, organization_id: 1, cloud_provider: 'localhost', status: 'ACTIVE_HEALTHY', diff --git a/studio/pages/api/projects/[ref]/index.ts b/studio/pages/api/projects/[ref]/index.ts index 4c525abd79f..6339dbe5543 100644 --- a/studio/pages/api/projects/[ref]/index.ts +++ b/studio/pages/api/projects/[ref]/index.ts @@ -1,6 +1,7 @@ -import apiWrapper from 'lib/api/apiWrapper' import { NextApiRequest, NextApiResponse } from 'next' +import apiWrapper from 'lib/api/apiWrapper' + export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler) async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -20,7 +21,7 @@ const handleGet = async (req: NextApiRequest, res: NextApiResponse) => { const response = { id: 1, ref: 'default', - name: 'Default Project', + name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, organization_id: 1, cloud_provider: 'localhost', status: 'ACTIVE_HEALTHY', diff --git a/studio/pages/api/props/project/[ref]/api.ts b/studio/pages/api/props/project/[ref]/api.ts index 0f0cd019722..10705a675e0 100644 --- a/studio/pages/api/props/project/[ref]/api.ts +++ b/studio/pages/api/props/project/[ref]/api.ts @@ -1,4 +1,5 @@ import { NextApiRequest, NextApiResponse } from 'next' + import apiWrapper from 'lib/api/apiWrapper' export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler) @@ -27,7 +28,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { db_user: 'postgres', id: 1, inserted_at: undefined, - name: 'Default Project', + name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, ref: 'default', status: 'ACTIVE_HEALTHY', services: [ diff --git a/studio/pages/api/props/project/[ref]/index.ts b/studio/pages/api/props/project/[ref]/index.ts index 27de041115f..1d14d1bf382 100644 --- a/studio/pages/api/props/project/[ref]/index.ts +++ b/studio/pages/api/props/project/[ref]/index.ts @@ -1,4 +1,5 @@ import { NextApiRequest, NextApiResponse } from 'next' + import apiWrapper from 'lib/api/apiWrapper' export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler) @@ -21,7 +22,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { project: { id: 1, ref: 'default', - name: 'Default Project', + name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, status: 'ACTIVE_HEALTHY', organization_id: 1, inserted_at: '2021-08-02T06:40:40.646362', diff --git a/studio/pages/api/props/project/[ref]/settings.ts b/studio/pages/api/props/project/[ref]/settings.ts index a5ed9be25e9..a6132cf3d0a 100644 --- a/studio/pages/api/props/project/[ref]/settings.ts +++ b/studio/pages/api/props/project/[ref]/settings.ts @@ -1,4 +1,5 @@ import { NextApiRequest, NextApiResponse } from 'next' + import apiWrapper from 'lib/api/apiWrapper' export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler) @@ -29,7 +30,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { id: 1, inserted_at: undefined, jwt_secret: '-', - name: 'Default Project', + name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, ref: 'default', region: 'ap-southeast-1', status: 'ACTIVE_HEALTHY', From e61aedf8c00fe2042ee31142c0254aaeda572c55 Mon Sep 17 00:00:00 2001 From: Jason Zi Feng Lei Date: Tue, 12 Apr 2022 10:39:40 +0800 Subject: [PATCH 002/208] Fixed a silly mistake in order of definition for the `process.env` variables. --- studio/pages/api/organizations/index.ts | 2 +- studio/pages/api/profile/index.ts | 4 ++-- studio/pages/api/projects/[ref]/index.ts | 2 +- studio/pages/api/projects/index.ts | 5 +++-- studio/pages/api/props/project/[ref]/api.ts | 2 +- studio/pages/api/props/project/[ref]/index.ts | 2 +- studio/pages/api/props/project/[ref]/settings.ts | 2 +- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/studio/pages/api/organizations/index.ts b/studio/pages/api/organizations/index.ts index c3b41b29bbd..48ac8439cfc 100644 --- a/studio/pages/api/organizations/index.ts +++ b/studio/pages/api/organizations/index.ts @@ -21,7 +21,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { const response = [ { id: 1, - name: 'Default Organization' || process.env.DEFAULT_ORGANIZATION_NAME, + name: process.env.DEFAULT_ORGANIZATION_NAME || 'Default Organization', slug: 'default-org-slug', billing_email: 'billing@supabase.co', }, diff --git a/studio/pages/api/profile/index.ts b/studio/pages/api/profile/index.ts index a985c48479b..6b25f3d3396 100644 --- a/studio/pages/api/profile/index.ts +++ b/studio/pages/api/profile/index.ts @@ -29,14 +29,14 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { organizations: [ { id: 1, - name: 'Default Organization' || process.env.DEFAULT_ORGANIZATION_NAME, + name: process.env.DEFAULT_ORGANIZATION_NAME || 'Default Organization', slug: 'default-org-slug', billing_email: 'billing@supabase.co', projects: [ { id: 1, ref: 'default', - name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, + name: process.env.DEFAULT_PROJECT_NAME || 'Default Project', organization_id: 1, cloud_provider: 'localhost', status: 'ACTIVE_HEALTHY', diff --git a/studio/pages/api/projects/[ref]/index.ts b/studio/pages/api/projects/[ref]/index.ts index 6339dbe5543..d8747eafb49 100644 --- a/studio/pages/api/projects/[ref]/index.ts +++ b/studio/pages/api/projects/[ref]/index.ts @@ -21,7 +21,7 @@ const handleGet = async (req: NextApiRequest, res: NextApiResponse) => { const response = { id: 1, ref: 'default', - name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, + name: process.env.DEFAULT_PROJECT_NAME || 'Default Project', organization_id: 1, cloud_provider: 'localhost', status: 'ACTIVE_HEALTHY', diff --git a/studio/pages/api/projects/index.ts b/studio/pages/api/projects/index.ts index f708142b571..a6a20f609b3 100644 --- a/studio/pages/api/projects/index.ts +++ b/studio/pages/api/projects/index.ts @@ -1,6 +1,7 @@ -import apiWrapper from 'lib/api/apiWrapper' import { NextApiRequest, NextApiResponse } from 'next' +import apiWrapper from 'lib/api/apiWrapper' + export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler) async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -21,7 +22,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { { id: 1, ref: 'default', - name: 'Default Project', + name: process.env.DEFAULT_PROJECT_NAME || 'Default Project', organization_id: 1, cloud_provider: 'localhost', status: 'ACTIVE_HEALTHY', diff --git a/studio/pages/api/props/project/[ref]/api.ts b/studio/pages/api/props/project/[ref]/api.ts index 10705a675e0..b9a8b68743b 100644 --- a/studio/pages/api/props/project/[ref]/api.ts +++ b/studio/pages/api/props/project/[ref]/api.ts @@ -28,7 +28,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { db_user: 'postgres', id: 1, inserted_at: undefined, - name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, + name: process.env.DEFAULT_PROJECT_NAME || 'Default Project', ref: 'default', status: 'ACTIVE_HEALTHY', services: [ diff --git a/studio/pages/api/props/project/[ref]/index.ts b/studio/pages/api/props/project/[ref]/index.ts index 1d14d1bf382..a197855ddaf 100644 --- a/studio/pages/api/props/project/[ref]/index.ts +++ b/studio/pages/api/props/project/[ref]/index.ts @@ -22,7 +22,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { project: { id: 1, ref: 'default', - name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, + name: process.env.DEFAULT_PROJECT_NAME || 'Default Project', status: 'ACTIVE_HEALTHY', organization_id: 1, inserted_at: '2021-08-02T06:40:40.646362', diff --git a/studio/pages/api/props/project/[ref]/settings.ts b/studio/pages/api/props/project/[ref]/settings.ts index a6132cf3d0a..5677414b23a 100644 --- a/studio/pages/api/props/project/[ref]/settings.ts +++ b/studio/pages/api/props/project/[ref]/settings.ts @@ -30,7 +30,7 @@ const handleGetAll = async (req: NextApiRequest, res: NextApiResponse) => { id: 1, inserted_at: undefined, jwt_secret: '-', - name: 'Default Project' || process.env.DEFAULT_PROJECT_NAME, + name: process.env.DEFAULT_PROJECT_NAME || 'Default Project', ref: 'default', region: 'ap-southeast-1', status: 'ACTIVE_HEALTHY', From 7dbfd69b13b5174cb7bab9eacba50392653c71cb Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Mon, 30 May 2022 09:17:08 -0230 Subject: [PATCH 003/208] Add link to data types --- .../ColumnEditor/ColumnType.tsx | 130 ++++++++++-------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx index c88cb1aabff..d7ddcefcc1b 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react' -import { IconCalendar, IconType, IconHash, Listbox, IconToggleRight, Input } from '@supabase/ui' +import { IconCalendar, IconType, IconHash, Listbox, IconToggleRight, Input, IconArrowUpRight } from '@supabase/ui' import { PostgresType } from '@supabase/postgres-meta' import { POSTGRES_DATA_TYPES, POSTGRES_DATA_TYPE_OPTIONS } from '../SidePanelEditor.constants' import { PostgresDataTypeOption } from '../SidePanelEditor.types' @@ -68,73 +68,83 @@ const ColumnType: FC = ({ } return ( - onOptionSelect(value)} - optionsWidth={480} - > - - --- - - - {/* - Weird issue with Listbox here - 1. Can't do render conditionally (&&) within Listbox hence why using Fragment - 2. Can't wrap these 2 components within a Fragment conditional (enumTypes.length) - as selecting the enumType option will not render it in the Listbox component - */} - {enumTypes.length > 0 ? ( - - User-defined Enumerated Types + <> + onOptionSelect(value)} + optionsWidth={480} + > + + --- - ) : ( - <> - )} - {enumTypes.length > 0 ? ( - // @ts-ignore - enumTypes.map((enumType: PostgresType) => ( + {/* + Weird issue with Listbox here + 1. Can't do render conditionally (&&) within Listbox hence why using Fragment + 2. Can't wrap these 2 components within a Fragment conditional (enumTypes.length) + as selecting the enumType option will not render it in the Listbox component + */} + {enumTypes.length > 0 ? ( + + User-defined Enumerated Types + + ) : ( + <> + )} + + {enumTypes.length > 0 ? ( + // @ts-ignore + enumTypes.map((enumType: PostgresType) => ( + { + return
+ }} + > +
+

{enumType.name}

+
+ + )) + ) : ( + <> + )} + + + PostgreSQL Data Types + + + {POSTGRES_DATA_TYPE_OPTIONS.map((option: PostgresDataTypeOption) => ( { - return
- }} + key={option.name} + value={option.name} + label={option.name} + addOnBefore={() => inferIcon(option.type)} >
-

{enumType.name}

+ {option.name} + {option.description}
- )) - ) : ( - <> - )} + ))} + +
+

+ + Learn more about data types + - - PostgreSQL Data Types - - - {POSTGRES_DATA_TYPE_OPTIONS.map((option: PostgresDataTypeOption) => ( - inferIcon(option.type)} - > -

- {option.name} - {option.description} -
- - ))} - +

+
+ ) } From b609120dcd07ad772a461ec53f5e9d9e1bb392e7 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Mon, 6 Jun 2022 08:55:19 -0230 Subject: [PATCH 004/208] Move link to proper panel --- .../SidePanelEditor/ColumnEditor/ColumnEditor.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx index ecd95e0ad71..3edf1ba9977 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx @@ -1,7 +1,7 @@ import { FC, useEffect, useState } from 'react' import { isUndefined, isEmpty } from 'lodash' import { Dictionary } from 'components/grid' -import { Checkbox, SidePanel, Input } from '@supabase/ui' +import { Checkbox, SidePanel, Input, IconArrowUpRight } from '@supabase/ui' import { PostgresColumn, PostgresRelationship, @@ -206,6 +206,16 @@ const ColumnEditor: FC = ({ disabled={!isUndefined(columnFields?.foreignKey)} onOptionSelect={(format: string) => onUpdateField({ format, defaultValue: null })} /> + + + {isUndefined(columnFields.foreignKey) && (
{columnFields.format.includes('int') && ( From b184f15471c4e86831b31be686ed062a99399766 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Mon, 6 Jun 2022 08:55:37 -0230 Subject: [PATCH 005/208] Add placeholder for column name input --- .../TableGridEditor/SidePanelEditor/TableEditor/Column.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx index f1beab72d82..9e3d48258cd 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx @@ -82,6 +82,7 @@ const Column: FC = ({ value={column.name} size="small" disabled={hasImportContent} + placeholder="column name" className={`table-editor-columns-input bg-white dark:bg-transparent lg:gap-0 ${ hasImportContent ? 'opacity-50' : '' } rounded-md`} From f60cfd66ee2a268225c965492cec73c5feffb0ce Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Mon, 6 Jun 2022 08:56:00 -0230 Subject: [PATCH 006/208] Add data types link to table creation panel --- .../SidePanelEditor/ColumnEditor/ColumnType.tsx | 8 -------- .../SidePanelEditor/TableEditor/ColumnManagement.tsx | 11 +++++++++++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx index d7ddcefcc1b..e869a3cf84b 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx @@ -136,14 +136,6 @@ const ColumnType: FC = ({ ))} - ) } diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx index 39d7b04071a..fcd74af88a5 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx @@ -3,6 +3,7 @@ import { partition, isEmpty, isUndefined } from 'lodash' import { Alert, Button, + IconArrowUpRight, IconEdit, IconHelpCircle, IconKey, @@ -318,11 +319,21 @@ const ColumnManagement: FC = ({
+
{!hasImportContent && ( )} +

+ + Learn more about data types + +

+
+ + +
Date: Wed, 8 Jun 2022 14:39:43 -0230 Subject: [PATCH 007/208] Add rough draft of new data types table --- web/docs/guides/database/tables.mdx | 104 ++++++++++++++++++---------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/web/docs/guides/database/tables.mdx b/web/docs/guides/database/tables.mdx index dbdd710c85a..b9ee2934b25 100644 --- a/web/docs/guides/database/tables.mdx +++ b/web/docs/guides/database/tables.mdx @@ -8,10 +8,10 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Tables are where you store your data. +Tables are where you store your data. -Tables are similar to excel spreadsheets. They contain columns and rows. +Tables are similar to excel spreadsheets. They contain columns and rows. For example, this table has 3 "columns" (`id`, `name`, `description`) and 4 "rows" of data: | `id` | `name` | `description` | @@ -26,14 +26,14 @@ There are a few important differences from a spreadsheet, but it's a good starti ## Creating Tables -When creating a table, it's best practice to add columns at the same time. +When creating a table, it's best practice to add columns at the same time. ![Tables and columns](/img/guides/database/tables-columns.png) -You must define the "data type" of each column when it is created. You can add and remove columns at any time after creating a table. +You must define the "data type" of each column when it is created. You can add and remove columns at any time after creating a table. -Supabase provides several options for creating tables. You can use the Dashboard or create them directly using SQL. -We provide a SQL editor within the Dashboard, or you can [connect](/docs/guides/database/connecting/connecting-to-postgres) to your database +Supabase provides several options for creating tables. You can use the Dashboard or create them directly using SQL. +We provide a SQL editor within the Dashboard, or you can [connect](/docs/guides/database/connecting/connecting-to-postgres) to your database and run the SQL queries yourself. @@ -76,19 +76,47 @@ create table movies ( It is best practice to use lowercase and underscores when naming tables. For example: `table_name`, not `Table Name`. -## Columns +## Columns You must define the "data type" when you create a column. ### Data types -Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) +Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) if the default types don't fit your needs. +Here's a list of the data types that are available to use in the dashboard. + +| `Name` | `Description` | `Example` | +| ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | +| int2 | Can contain numbers between -32,768 and 32,767 | For storing numbers like ages of people, distance between places or numbers you know will be fairly small. | +| int4 | Can contain numbers between -2,147,483,648 and +2,147,483,648 | For storing numbers like the population of small towns or cities that you know will be less than about 2 billion. | +| int8 | Can contain numbers between 9,223,372,036,854,775,808 and +9,223,372,036,854,775,808 | For storing numbers larger than about 2 billion. Like the number of people who live in the Northern vs Southern hemisphere or the total number of COVID-19 vaccinations administered. | +| float4 | Can contain numbers with up to 6 decimal places | For storing things like temperature (22.5 degrees Celsius) or distance (10.25kms)| +| float8 | Can contain numbers with up to 15 decimal places | For storing numbers with a high level of precision, like scientific or mathematical data. | +| numeric | Can contain 131, 072 digits before the decimal point and 16, 383 digits after the decimal point. | For storing number that require very high precision. Use the numeric type when you need more precision than float4 or float8 offer. | +| json | Can contain JSON data. | For storing data that logically belongs together, like a person’s street address. Useful for when you want to store dynamic fields and not have every field specified as a row in your table. | +| jsonb | The JSONB type stores your JSON input as a binary code instead of as an exact copy of the JSON data. JSONB is faster, more efficient and supports indexing. | Not sure what the json vs jsonb recommendation should be. I think we should make one though. It’s really not clear from my reading. | +| text | Can contain strings of any length. | For storing any kind of textual data. Examples include text contents of recipes or blog posts. This is the general purpose data type for textual content. | +| varchar | Can contain strings with a fixed length | For storing a string where you would want to limit the length to 255 characters. | +| uuid | Can store a universal unique identifier. | For storing unique IDs, like when you need to store a reference to another table row. | +| date | Can store a data value without time. | For storing dates like birthdays or holidays. | +| time | Can store the time of day | For storing things like when a process starts and stops. | +| timez | Can store the time of day, along with a timezone. | For storing things like event start times, like an Apple event starting at 10a.m. Pacific Time. | +| timestamp | Can store the date and time without a timezone. | For storing times like: May 1st, 2022 at 10a.m. | +| timestampz | Can store the date and time with a timezone. | For storing times like: May 1st, 2022 at 10a.m, Pacific Time. | +| bool | Can store boolean values | For storing things like user_is_subscribed or show_homepage_ad. | + + + + + + +Here's a complete list of all of the default data types provided by Postgres.
Show/Hide default data types - + | `Name` | `Aliases` | `Description` | | ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | @@ -141,17 +169,17 @@ if the default types don't fit your needs.
-You can "cast" columns from one type to another, however there can be some incompatibilities between types. +You can "cast" columns from one type to another, however there can be some incompatibilities between types. For example, if you cast a `timestamp` to a `date`, you will lose all the time information that was previously saved. -### Primary Keys +### Primary Keys A table can have a "primary key" - a unique identifier for every row of data. A few tips for Primary Keys: - It's recommended to create a Primary Key for every table in your database. - You can use any column as a primary key, as long as it is unique for every row. -- It's common to use a `uuid` type or a numbered `identity` column as your primary key. +- It's common to use a `uuid` type or a numbered `identity` column as your primary key. ```sql create table movies ( @@ -161,9 +189,9 @@ create table movies ( In the example above, we have: -1. created a column called `id` +1. created a column called `id` 1. assigned the data type `bigint` -1. instructed the database that this should be `generated always as identity`, which means that Postgres will automatically assign a unique number to this column. +1. instructed the database that this should be `generated always as identity`, which means that Postgres will automatically assign a unique number to this column. 1. Becuase it's unique, we can also use it as our `primary key`. We could also use `generated by default as identity`, which would allow us to insert our own unique values. @@ -174,9 +202,9 @@ create table movies ( ); ``` -## Loading data +## Loading data -There are several ways to load data in Supabase. You can load data directly into the database or using the [APIs](/docs/guides/api). +There are several ways to load data in Supabase. You can load data directly into the database or using the [APIs](/docs/guides/api). Use the "Bulk Loading" instructions if you are loading large data sets. ### Basic data loading @@ -191,7 +219,7 @@ values={[ ```sql -insert into movies +insert into movies (name, description) values ('The Empire Strikes Back', 'After the Rebels are brutally overpowered by the Empire on the ice planet Hoth, Luke Skywalker begins Jedi training with Yoda.'), @@ -204,12 +232,12 @@ values ```sql const { data, error } = await supabase .from('movies') - .insert([{ - name: 'The Empire Strikes Back', - description: 'After the Rebels are brutally overpowered by the Empire on the ice planet Hoth, Luke Skywalker begins Jedi training with Yoda.' - }, { - name: 'Return of the Jedi', - description: 'After a daring mission to rescue Han Solo from Jabba the Hutt, the Rebels dispatch to Endor to destroy the second Death Star.' + .insert([{ + name: 'The Empire Strikes Back', + description: 'After the Rebels are brutally overpowered by the Empire on the ice planet Hoth, Luke Skywalker begins Jedi training with Yoda.' + }, { + name: 'Return of the Jedi', + description: 'After a daring mission to rescue Han Solo from Jabba the Hutt, the Rebels dispatch to Endor to destroy the second Death Star.' }]) ``` @@ -219,21 +247,21 @@ const { data, error } = await supabase ```sql final res = await supabase .from('movies') - .insert([{ - name: 'The Empire Strikes Back', - description: 'After the Rebels are brutally overpowered by the Empire on the ice planet Hoth, Luke Skywalker begins Jedi training with Yoda.' - }, { - name: 'Return of the Jedi', - description: 'After a daring mission to rescue Han Solo from Jabba the Hutt, the Rebels dispatch to Endor to destroy the second Death Star.' + .insert([{ + name: 'The Empire Strikes Back', + description: 'After the Rebels are brutally overpowered by the Empire on the ice planet Hoth, Luke Skywalker begins Jedi training with Yoda.' + }, { + name: 'Return of the Jedi', + description: 'After a daring mission to rescue Han Solo from Jabba the Hutt, the Rebels dispatch to Endor to destroy the second Death Star.' }]).execute(); ``` -### Bulk data loading +### Bulk data loading -When inserting large data sets it's best to use PostgreSQL's [COPY](https://www.postgresql.org/docs/current/sql-copy.html) command. +When inserting large data sets it's best to use PostgreSQL's [COPY](https://www.postgresql.org/docs/current/sql-copy.html) command. This loads data directly from a file into a table. There are several file formats available for copying data: text, csv, binary, JSON, etc. For example, if you wanted to load a CSV file into your movies table: @@ -243,7 +271,7 @@ For example, if you wanted to load a CSV file into your movies table: "Return of the Jedi", "After a daring mission to rescue Han Solo from Jabba the Hutt, the Rebels dispatch to Endor to destroy the second Death Star." ``` -You would [connect](/docs/guides/database/connecting-to-postgres#direct-connections) to your database directly and load the file with the COPY command: +You would [connect](/docs/guides/database/connecting-to-postgres#direct-connections) to your database directly and load the file with the COPY command: ```bash psql -h DATABASE_URL -p 5432 postgres -U postgres \ @@ -257,9 +285,9 @@ Tables can be "joined" together using Foreign Keys. ![Foreign Keys](/img/guides/database/foreign-keys.png) -This is where the "Relational" naming comes from, as data typically forms some sort of relationship. +This is where the "Relational" naming comes from, as data typically forms some sort of relationship. -In our "movies" example above, we might want to add a "category" for each movie (for example, "Action", or "Documentary"). +In our "movies" example above, we might want to add a "category" for each movie (for example, "Action", or "Documentary"). Let's create a new table called `categories` and "link" our `movies` table. ```sql @@ -268,7 +296,7 @@ create table categories ( name text -- category name ); -alter table movies +alter table movies add column category_id bigint references categories; ``` @@ -323,15 +351,15 @@ allowFullScreen -## Schemas +## Schemas Tables belong to `schemas`. Schemas are a way of organizing your tables, often for security reasons. ![Schemas and tables](/img/guides/database/schema-tables.png) -If you don't explicitly pass a schema when creating a table, Postgres will assume that you want to create the table in the `public` schema. +If you don't explicitly pass a schema when creating a table, Postgres will assume that you want to create the table in the `public` schema. -We can create schemas for organizing tables. For example, we might want a private schema which is hidden from our API: +We can create schemas for organizing tables. For example, we might want a private schema which is hidden from our API: ```sql From 1c8e059d7fd2ea9fbf4076749158e7efbf332f92 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Thu, 16 Jun 2022 21:44:14 -0230 Subject: [PATCH 008/208] Format link to docs --- .../ColumnEditor/ColumnEditor.tsx | 6 +- .../TableEditor/ColumnManagement.tsx | 3 +- studio/package-lock.json | 63 ++++++++++++++++--- web/docs/guides/database/tables.mdx | 12 +--- 4 files changed, 62 insertions(+), 22 deletions(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx index 3edf1ba9977..0899f282991 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx @@ -1,7 +1,7 @@ import { FC, useEffect, useState } from 'react' import { isUndefined, isEmpty } from 'lodash' import { Dictionary } from 'components/grid' -import { Checkbox, SidePanel, Input, IconArrowUpRight } from '@supabase/ui' +import { Checkbox, SidePanel, Input } from '@supabase/ui' import { PostgresColumn, PostgresRelationship, @@ -209,8 +209,8 @@ const ColumnEditor: FC = ({

- - Learn more about data types + + Learn more about data types

diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx index fcd74af88a5..7bcda81f19c 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx @@ -3,7 +3,6 @@ import { partition, isEmpty, isUndefined } from 'lodash' import { Alert, Button, - IconArrowUpRight, IconEdit, IconHelpCircle, IconKey, @@ -327,7 +326,7 @@ const ColumnManagement: FC = ({ )}

- Learn more about data types + Learn more about data types

diff --git a/studio/package-lock.json b/studio/package-lock.json index 346948ff30f..5a72584b7e0 100644 --- a/studio/package-lock.json +++ b/studio/package-lock.json @@ -70,6 +70,7 @@ "swr": "^1.2.1", "uniforms-bootstrap4": "^3.6.2", "uniforms-bridge-json-schema": "^3.6.2", + "uuid": "^8.3.2", "zxcvbn": "^4.4.2" }, "devDependencies": { @@ -100,6 +101,7 @@ "@types/react-window-infinite-loader": "^1.0.5", "@types/semver": "^7.3.9", "@types/sqlstring": "^2.3.0", + "@types/uuid": "^8.3.4", "@types/zxcvbn": "^4.4.1", "autoprefixer": "^10.4.2", "babel-loader": "^8.2.3", @@ -9048,6 +9050,12 @@ "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==", "dev": true }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, "node_modules/@types/webpack": { "version": "4.41.32", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.32.tgz", @@ -9472,6 +9480,15 @@ "node": ">=4" } }, + "node_modules/analytics-node/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/anser": { "version": "1.4.9", "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.9.tgz", @@ -27444,12 +27461,11 @@ } }, "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "bin": { - "uuid": "bin/uuid" + "uuid": "dist/bin/uuid" } }, "node_modules/uuid-browser": { @@ -28143,6 +28159,16 @@ "node": ">= 6" } }, + "node_modules/webpack-log/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/webpack-sources": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", @@ -35769,6 +35795,12 @@ "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==", "dev": true }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, "@types/webpack": { "version": "4.41.32", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.32.tgz", @@ -36151,6 +36183,13 @@ "ms": "^2.0.0", "remove-trailing-slash": "^0.1.0", "uuid": "^3.2.1" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "anser": { @@ -49981,9 +50020,9 @@ "dev": true }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "uuid-browser": { "version": "3.1.0", @@ -50845,6 +50884,14 @@ "requires": { "ansi-colors": "^3.0.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "webpack-sources": { diff --git a/web/docs/guides/database/tables.mdx b/web/docs/guides/database/tables.mdx index b9ee2934b25..75c77c70293 100644 --- a/web/docs/guides/database/tables.mdx +++ b/web/docs/guides/database/tables.mdx @@ -83,10 +83,9 @@ You must define the "data type" when you create a column. ### Data types -Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) -if the default types don't fit your needs. +Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) if the default types don't fit your needs. -Here's a list of the data types that are available to use in the dashboard. +Here's a list of the data types that are available to use in the Dashboard. | `Name` | `Description` | `Example` | | ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | @@ -109,14 +108,9 @@ Here's a list of the data types that are available to use in the dashboard. | bool | Can store boolean values | For storing things like user_is_subscribed or show_homepage_ad. | - - - - Here's a complete list of all of the default data types provided by Postgres.
-Show/Hide default data types - +View all default data types | `Name` | `Aliases` | `Description` | | ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | From 56da65fab8dadb227bc09fe7b6c3d759b85179e1 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Thu, 16 Jun 2022 22:20:54 -0230 Subject: [PATCH 009/208] Add data types table to docs site old and new, link to it from the Dashboard --- .../temp-docs/docs/guides/database/tables.mdx | 35 ++++++++++++++++--- .../ColumnEditor/ColumnEditor.tsx | 3 +- .../TableEditor/ColumnManagement.tsx | 23 ++++++------ web/docs/guides/database/tables.mdx | 27 +++++++------- 4 files changed, 55 insertions(+), 33 deletions(-) diff --git a/apps/temp-docs/docs/guides/database/tables.mdx b/apps/temp-docs/docs/guides/database/tables.mdx index 89626dab66d..fbe8b1f9450 100644 --- a/apps/temp-docs/docs/guides/database/tables.mdx +++ b/apps/temp-docs/docs/guides/database/tables.mdx @@ -8,7 +8,7 @@ import Tabs from '@theme/Tabs'; import TabsPanel from '@theme/TabsPanel'; -In Postgres, data is stored in "tables". +In Postgres, data is stored in "tables". Tables are similar to excel spreadsheets. They contain columns & rows of data. There are a few key differences from a spreadsheet however: - Every column is a strict type of data. When you set up a column, you must define the "data type". @@ -26,8 +26,8 @@ For example, this table has 3 "columns" (`id`, `name`, `description`) and 4 "row ## Creating Tables -Supabase provides several options for creating tables. You can use the Table Editor or create them directly using SQL. -We provide a SQL editor within the Dashboard, or you can [connect](/docs/guides/database/connecting/connecting-to-postgres) to your database +Supabase provides several options for creating tables. You can use the Table Editor or create them directly using SQL. +We provide a SQL editor within the Dashboard, or you can [connect](/docs/guides/database/connecting/connecting-to-postgres) to your database and run the SQL queries yourself. @@ -77,12 +77,37 @@ create table todos ( ### Data types -Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) +Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) if the default types don't fit your needs. +Here's a list of the data types that are available to use in the table editor in the Dashboard: + +| `Name` | `Description` | `Example` | +| ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | +| int2 | Can contain numbers between -32,768 and 32,767 | For storing numbers like ages of people, distance between places or numbers you know will be fairly small. | +| int4 | Can contain numbers between -2,147,483,648 and +2,147,483,648 | For storing numbers like the population of small towns or cities that you know will be less than about 2 billion. | +| int8 | Can contain numbers between 9,223,372,036,854,775,808 and +9,223,372,036,854,775,808 | For storing numbers larger than roughly 2 billion. Like the number of people who live in the Northern vs Southern hemisphere or the total number of COVID-19 vaccinations administered. | +| float4 | Can contain numbers with up to 6 decimal places | For storing things like temperature (22.5 degrees Celsius) or distance (10.25kms)| +| float8 | Can contain numbers with up to 15 decimal places | For storing numbers with a high level of precision, like scientific or mathematical data. | +| numeric | Can contain 131,072 digits before the decimal point and 16,383 digits after the decimal point. | For storing number that require very high precision. Use the numeric type when you need more precision than float4 or float8 offer. | +| json | Can contain JSON data. | For storing data that logically belongs together, like a person's street address. Useful for when you want to store dynamic fields and not have every field represented as a column in your table. | +| jsonb | The JSONB type stores your JSON input as a binary code instead of as an exact copy of the JSON data. JSONB is faster, more efficient and supports indexing. | If you are doing a lot of JSON manipulation in Postgres you should consider using JSONB for efficiency. Otherwise, if you are just doing typical data storing and fetching, JSON should be fine. | +| text | Can contain strings of any length. | For storing any kind of textual data. Examples include text contents of recipes or blog posts. This is the general purpose data type for textual content. | +| varchar | Can contain strings with a fixed length | For storing a string where you would want to limit the length to 160 characters. | +| uuid | Can store a universal unique identifier. | For storing unique IDs, like when you need to store a reference to another table row. | +| date | Can store a data value without time. | For storing dates like birthdays or holidays with a year, month and day. | +| time | Can store the time of day | For storing things like when a process starts and stops at specific times in the day. The lights come on at 6:00:00 a.m. and go off at 10:00:00 p.m. | +| timez | Can store the time of day, along with a timezone. | For storing things like event start times, like an Apple event starting at 10:00:00 a.m. Pacific Time. | +| timestamp | Can store the date and time without a timezone. | For storing times like: May 1st, 2022 at 10 a.m. | +| timestampz | Can store the date and time with a timezone. | For storing times like: May 1st, 2022 at 10 a.m, Pacific Time. | +| bool | Can store boolean values | For storing things that will be true or false, like user_is_subscribed or show_homepage_ad. | + + +Here's a complete list of all of the default data types provided by Postgres: +
Show/Hide default data types - + | `Name` | `Aliases` | `Description` | | ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx index 0899f282991..11ba0519fc7 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx @@ -209,10 +209,9 @@ const ColumnEditor: FC = ({ diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx index 7bcda81f19c..46d7af3bd69 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ColumnManagement.tsx @@ -319,20 +319,17 @@ const ColumnManagement: FC = ({
- {!hasImportContent && ( - - )} -

- - Learn more about data types - -

+ {!hasImportContent && ( + + )} +

+ + Learn more about data types + +

- - - View all default data types From b1d6fa626b730f7be985d3ce3ffda3edd5df412a Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Thu, 16 Jun 2022 22:28:51 -0230 Subject: [PATCH 010/208] Fix line break --- apps/temp-docs/docs/guides/database/tables.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/temp-docs/docs/guides/database/tables.mdx b/apps/temp-docs/docs/guides/database/tables.mdx index fbe8b1f9450..6340cf5091f 100644 --- a/apps/temp-docs/docs/guides/database/tables.mdx +++ b/apps/temp-docs/docs/guides/database/tables.mdx @@ -77,8 +77,7 @@ create table todos ( ### Data types -Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) -if the default types don't fit your needs. +Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) if the default types don't fit your needs. Here's a list of the data types that are available to use in the table editor in the Dashboard: From 2f8951af6e983bdbdca74b3e253fa9a7f2a6638f Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Thu, 16 Jun 2022 22:32:16 -0230 Subject: [PATCH 011/208] Clean up imports --- .../SidePanelEditor/ColumnEditor/ColumnType.tsx | 4 +--- .../TableGridEditor/SidePanelEditor/TableEditor/Column.tsx | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx index e869a3cf84b..36f22b3553a 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react' -import { IconCalendar, IconType, IconHash, Listbox, IconToggleRight, Input, IconArrowUpRight } from '@supabase/ui' +import { IconCalendar, IconType, IconHash, Listbox, IconToggleRight, Input } from '@supabase/ui' import { PostgresType } from '@supabase/postgres-meta' import { POSTGRES_DATA_TYPES, POSTGRES_DATA_TYPE_OPTIONS } from '../SidePanelEditor.constants' import { PostgresDataTypeOption } from '../SidePanelEditor.types' @@ -68,7 +68,6 @@ const ColumnType: FC = ({ } return ( - <> = ({
))}
- ) } diff --git a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx index 9e3d48258cd..bf9fe6821ca 100644 --- a/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx +++ b/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx @@ -82,7 +82,7 @@ const Column: FC = ({ value={column.name} size="small" disabled={hasImportContent} - placeholder="column name" + placeholder="Column name" className={`table-editor-columns-input bg-white dark:bg-transparent lg:gap-0 ${ hasImportContent ? 'opacity-50' : '' } rounded-md`} From 69134e5a75760ea4d85914ab4e4a2e6fa9038566 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Mon, 27 Jun 2022 16:22:51 -0230 Subject: [PATCH 012/208] Combine two column helper tables into one --- .../temp-docs/docs/guides/database/tables.mdx | 118 +++++++----------- web/docs/guides/database/tables.mdx | 93 +++++++------- 2 files changed, 91 insertions(+), 120 deletions(-) diff --git a/apps/temp-docs/docs/guides/database/tables.mdx b/apps/temp-docs/docs/guides/database/tables.mdx index 6340cf5091f..7f8e4caa582 100644 --- a/apps/temp-docs/docs/guides/database/tables.mdx +++ b/apps/temp-docs/docs/guides/database/tables.mdx @@ -77,83 +77,55 @@ create table todos ( ### Data types -Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) if the default types don't fit your needs. - -Here's a list of the data types that are available to use in the table editor in the Dashboard: - -| `Name` | `Description` | `Example` | -| ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | -| int2 | Can contain numbers between -32,768 and 32,767 | For storing numbers like ages of people, distance between places or numbers you know will be fairly small. | -| int4 | Can contain numbers between -2,147,483,648 and +2,147,483,648 | For storing numbers like the population of small towns or cities that you know will be less than about 2 billion. | -| int8 | Can contain numbers between 9,223,372,036,854,775,808 and +9,223,372,036,854,775,808 | For storing numbers larger than roughly 2 billion. Like the number of people who live in the Northern vs Southern hemisphere or the total number of COVID-19 vaccinations administered. | -| float4 | Can contain numbers with up to 6 decimal places | For storing things like temperature (22.5 degrees Celsius) or distance (10.25kms)| -| float8 | Can contain numbers with up to 15 decimal places | For storing numbers with a high level of precision, like scientific or mathematical data. | -| numeric | Can contain 131,072 digits before the decimal point and 16,383 digits after the decimal point. | For storing number that require very high precision. Use the numeric type when you need more precision than float4 or float8 offer. | -| json | Can contain JSON data. | For storing data that logically belongs together, like a person's street address. Useful for when you want to store dynamic fields and not have every field represented as a column in your table. | -| jsonb | The JSONB type stores your JSON input as a binary code instead of as an exact copy of the JSON data. JSONB is faster, more efficient and supports indexing. | If you are doing a lot of JSON manipulation in Postgres you should consider using JSONB for efficiency. Otherwise, if you are just doing typical data storing and fetching, JSON should be fine. | -| text | Can contain strings of any length. | For storing any kind of textual data. Examples include text contents of recipes or blog posts. This is the general purpose data type for textual content. | -| varchar | Can contain strings with a fixed length | For storing a string where you would want to limit the length to 160 characters. | -| uuid | Can store a universal unique identifier. | For storing unique IDs, like when you need to store a reference to another table row. | -| date | Can store a data value without time. | For storing dates like birthdays or holidays with a year, month and day. | -| time | Can store the time of day | For storing things like when a process starts and stops at specific times in the day. The lights come on at 6:00:00 a.m. and go off at 10:00:00 p.m. | -| timez | Can store the time of day, along with a timezone. | For storing things like event start times, like an Apple event starting at 10:00:00 a.m. Pacific Time. | -| timestamp | Can store the date and time without a timezone. | For storing times like: May 1st, 2022 at 10 a.m. | -| timestampz | Can store the date and time with a timezone. | For storing times like: May 1st, 2022 at 10 a.m, Pacific Time. | -| bool | Can store boolean values | For storing things that will be true or false, like user_is_subscribed or show_homepage_ad. | - - -Here's a complete list of all of the default data types provided by Postgres: +Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) if the default types don't fit your needs. Here's a complete list of all of the default data types provided by Postgres:
Show/Hide default data types - -| `Name` | `Aliases` | `Description` | +| `Name` | `Aliases` | `Description` | | ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | -| bigint | int8 | signed eight-byte integer | -| bigserial | serial8 | autoincrementing eight-byte integer | -| bit | | fixed-length bit string | -| bit varying | varbit | variable-length bit string | -| boolean | bool | logical Boolean (true/false) | -| box | | rectangular box on a plane | -| bytea | | binary data (“byte array”) | -| character | char | fixed-length character string | -| character varying | varchar | variable-length character string | -| cidr | | IPv4 or IPv6 network address | -| circle | | circle on a plane | -| date | | calendar date (year, month, day) | -| double precision | float8 | double precision floating-point number (8 bytes) | -| inet | | IPv4 or IPv6 host address | -| integer | int, int4 | signed four-byte integer | -| interval \[ fields \] | | time span | -| json | | textual JSON data | -| jsonb | | binary JSON data, decomposed | -| line | | infinite line on a plane | -| lseg | | line segment on a plane | -| macaddr | | MAC (Media Access Control) address | -| macaddr8 | | MAC (Media Access Control) address (EUI-64 format) | -| money | | currency amount | -| numeric | decimal | exact numeric of selectable precision | -| path | | geometric path on a plane | -| pg\_lsn | | PostgreSQL Log Sequence Number | -| pg\_snapshot | | user-level transaction ID snapshot | -| point | | geometric point on a plane | -| polygon | | closed geometric path on a plane | -| real | float4 | single precision floating-point number (4 bytes) | -| smallint | int2 | signed two-byte integer | -| smallserial | serial2 | autoincrementing two-byte integer | -| serial | serial4 | autoincrementing four-byte integer | -| text | | variable-length character string | -| time \[ without time zone \] | | time of day (no time zone) | -| time with time zone | timetz | time of day, including time zone | -| timestamp \[ without time zone \] | | date and time (no time zone) | -| timestamp with time zone | timestamptz | date and time, including time zone | -| tsquery | | text search query | -| tsvector | | text search document | -| txid\_snapshot | | user-level transaction ID snapshot (deprecated; see pg\_snapshot) | -| uuid | | universally unique identifier | -| xml | | XML data | - - +| bigint | int8 | Signed eight-byte integer. For numbers ranging from -9223372036854775808 to +9223372036854775807. | +| bigserial | serial8 | Autoincrementing eight-byte integer. For numbers ranging from 1 to 9223372036854775807. | +| bit | | Fixed-length bit string. | +| bit varying | varbit | Variable-length bit string. | +| boolean | bool | Logical Boolean (true/false). | +| box | | Rectangular box on a plane. | +| bytea | | Binary data (“byte array”). | +| character | char | Fixed-length character string. | +| character varying | varchar | Variable-length character string. | +| cidr | | IPv4 or IPv6 network address. | +| circle | | Circle on a plane. | +| date | | Calendar date (year, month, day). | +| double precision | float8 | Double precision floating-point number (8 bytes). 15 decimal digits of precision. | +| inet | | IPv4 or IPv6 host address. | +| integer | int, int4 | Signed four-byte integer. -2147483648 to +2147483647. | +| interval \[ fields \] | | Time span. | +| json | | Textual JSON data. | +| jsonb | | Binary JSON data, decomposed. If you are doing a lot of JSON manipulation in Postgres you should consider using JSONB for efficiency. Otherwise, if you are just doing typical data storing and fetching, JSON should be fine. | +| line | | Infinite line on a plane. | +| lseg | | Line segment on a plane. | +| macaddr | | MAC (Media Access Control) address. | +| macaddr8 | | MAC (Media Access Control) address (EUI-64 format). | +| money | | currency. | +| numeric | decimal | Exact numeric of selectable precision. Up to 131072 digits before the decimal point; up to 16383 digits after. For storing number that require very high precision. Use the numeric type when you need more precision than float4 or float8 offer. | +| path | | Geometric path on a plane. | +| pg\_lsn | | PostgreSQL Log Sequence Numb. | +| pg\_snapshot | | User-level transaction ID snapshot. | +| point | | Geometric point on a plane. | +| polygon | | Closed geometric path on a plane. | +| real | float4 | Single precision floating-point number (4 byte). 6 decimal digits precision. | +| smallint | int2 | Signed two-byte integer. For numbers ranging from -32768 to +32767 | +| smallserial | serial2 | Autoincrementing two-byte integer. For numbers ranging from 1 to 32767. | +| serial | serial4 | Autoincrementing four-byte integer. For numbers ranging from 1 to 2147483647 | +| text | | Variable-length character string. This is the general purpose data type for textual content. | +| time \[ without time zone \] | | Time of day (no time zone). | +| time with time zone | timetz | Time of day, including time zone. | +| timestamp \[ without time zone \] | | Date and time (no time zone). | +| timestamp with time zone | timestamptz | Date and time, including time zone. | +| tsquery | | Text search query. | +| tsvector | | Text search document . | +| txid\_snapshot | | User-level transaction ID snapshot (deprecated; see pg\_snapshot). | +| uuid | | Universally unique identifier. | +| xml | | XML data. |
diff --git a/web/docs/guides/database/tables.mdx b/web/docs/guides/database/tables.mdx index 54b3236deda..cd394dbefd7 100644 --- a/web/docs/guides/database/tables.mdx +++ b/web/docs/guides/database/tables.mdx @@ -111,57 +111,56 @@ Here's a list of the data types that are available to use in the table editor in Here's a complete list of all of the default data types provided by Postgres:
-View all default data types +Show/Hide default data types -| `Name` | `Aliases` | `Description` | +| `Name` | `Aliases` | `Description` | | ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | -| bigint | int8 | signed eight-byte integer | -| bigserial | serial8 | autoincrementing eight-byte integer | -| bit | | fixed-length bit string | -| bit varying | varbit | variable-length bit string | -| boolean | bool | logical Boolean (true/false) | -| box | | rectangular box on a plane | -| bytea | | binary data (“byte array”) | -| character | char | fixed-length character string | -| character varying | varchar | variable-length character string | -| cidr | | IPv4 or IPv6 network address | -| circle | | circle on a plane | -| date | | calendar date (year, month, day) | -| double precision | float8 | double precision floating-point number (8 bytes) | -| inet | | IPv4 or IPv6 host address | -| integer | int, int4 | signed four-byte integer | -| interval \[ fields \] | | time span | -| json | | textual JSON data | -| jsonb | | binary JSON data, decomposed | -| line | | infinite line on a plane | -| lseg | | line segment on a plane | -| macaddr | | MAC (Media Access Control) address | -| macaddr8 | | MAC (Media Access Control) address (EUI-64 format) | -| money | | currency amount | -| numeric | decimal | exact numeric of selectable precision | -| path | | geometric path on a plane | -| pg\_lsn | | PostgreSQL Log Sequence Number | -| pg\_snapshot | | user-level transaction ID snapshot | -| point | | geometric point on a plane | -| polygon | | closed geometric path on a plane | -| real | float4 | single precision floating-point number (4 bytes) | -| smallint | int2 | signed two-byte integer | -| smallserial | serial2 | autoincrementing two-byte integer | -| serial | serial4 | autoincrementing four-byte integer | -| text | | variable-length character string | -| time \[ without time zone \] | | time of day (no time zone) | -| time with time zone | timetz | time of day, including time zone | -| timestamp \[ without time zone \] | | date and time (no time zone) | -| timestamp with time zone | timestamptz | date and time, including time zone | -| tsquery | | text search query | -| tsvector | | text search document | -| txid\_snapshot | | user-level transaction ID snapshot (deprecated; see pg\_snapshot) | -| uuid | | universally unique identifier | -| xml | | XML data | - - +| bigint | int8 | Signed eight-byte integer. For numbers ranging from -9223372036854775808 to +9223372036854775807. | +| bigserial | serial8 | Autoincrementing eight-byte integer. For numbers ranging from 1 to 9223372036854775807. | +| bit | | Fixed-length bit string. | +| bit varying | varbit | Variable-length bit string. | +| boolean | bool | Logical Boolean (true/false). | +| box | | Rectangular box on a plane. | +| bytea | | Binary data (“byte array”). | +| character | char | Fixed-length character string. | +| character varying | varchar | Variable-length character string. | +| cidr | | IPv4 or IPv6 network address. | +| circle | | Circle on a plane. | +| date | | Calendar date (year, month, day). | +| double precision | float8 | Double precision floating-point number (8 bytes). 15 decimal digits of precision. | +| inet | | IPv4 or IPv6 host address. | +| integer | int, int4 | Signed four-byte integer. -2147483648 to +2147483647. | +| interval \[ fields \] | | Time span. | +| json | | Textual JSON data. | +| jsonb | | Binary JSON data, decomposed. If you are doing a lot of JSON manipulation in Postgres you should consider using JSONB for efficiency. Otherwise, if you are just doing typical data storing and fetching, JSON should be fine. | +| line | | Infinite line on a plane. | +| lseg | | Line segment on a plane. | +| macaddr | | MAC (Media Access Control) address. | +| macaddr8 | | MAC (Media Access Control) address (EUI-64 format). | +| money | | currency. | +| numeric | decimal | Exact numeric of selectable precision. Up to 131072 digits before the decimal point; up to 16383 digits after. For storing number that require very high precision. Use the numeric type when you need more precision than float4 or float8 offer. | +| path | | Geometric path on a plane. | +| pg\_lsn | | PostgreSQL Log Sequence Numb. | +| pg\_snapshot | | User-level transaction ID snapshot. | +| point | | Geometric point on a plane. | +| polygon | | Closed geometric path on a plane. | +| real | float4 | Single precision floating-point number (4 byte). 6 decimal digits precision. | +| smallint | int2 | Signed two-byte integer. For numbers ranging from -32768 to +32767 | +| smallserial | serial2 | Autoincrementing two-byte integer. For numbers ranging from 1 to 32767. | +| serial | serial4 | Autoincrementing four-byte integer. For numbers ranging from 1 to 2147483647 | +| text | | Variable-length character string. This is the general purpose data type for textual content. | +| time \[ without time zone \] | | Time of day (no time zone). | +| time with time zone | timetz | Time of day, including time zone. | +| timestamp \[ without time zone \] | | Date and time (no time zone). | +| timestamp with time zone | timestamptz | Date and time, including time zone. | +| tsquery | | Text search query. | +| tsvector | | Text search document . | +| txid\_snapshot | | User-level transaction ID snapshot (deprecated; see pg\_snapshot). | +| uuid | | Universally unique identifier. | +| xml | | XML data. |
+
You can "cast" columns from one type to another, however there can be some incompatibilities between types. From 842214f41cb2f240048ce624709309fc08045780 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Mon, 27 Jun 2022 16:26:42 -0230 Subject: [PATCH 013/208] Cleanup --- .../temp-docs/docs/guides/database/tables.mdx | 12 ++++----- web/docs/guides/database/tables.mdx | 25 +------------------ 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/apps/temp-docs/docs/guides/database/tables.mdx b/apps/temp-docs/docs/guides/database/tables.mdx index 7f8e4caa582..c7b79387b11 100644 --- a/apps/temp-docs/docs/guides/database/tables.mdx +++ b/apps/temp-docs/docs/guides/database/tables.mdx @@ -77,7 +77,7 @@ create table todos ( ### Data types -Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) if the default types don't fit your needs. Here's a complete list of all of the default data types provided by Postgres: +Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) if the default types don't fit your needs. Here's a list of all of the default data types provided by Postgres:
Show/Hide default data types @@ -109,21 +109,21 @@ Every column is a predefined type. PostgreSQL provides many [default types](http | money | | currency. | | numeric | decimal | Exact numeric of selectable precision. Up to 131072 digits before the decimal point; up to 16383 digits after. For storing number that require very high precision. Use the numeric type when you need more precision than float4 or float8 offer. | | path | | Geometric path on a plane. | -| pg\_lsn | | PostgreSQL Log Sequence Numb. | +| pg\_lsn | | PostgreSQL Log Sequence Number. | | pg\_snapshot | | User-level transaction ID snapshot. | | point | | Geometric point on a plane. | | polygon | | Closed geometric path on a plane. | -| real | float4 | Single precision floating-point number (4 byte). 6 decimal digits precision. | -| smallint | int2 | Signed two-byte integer. For numbers ranging from -32768 to +32767 | +| real | float4 | Single precision floating-point number (4 bytes). 6 decimal digits precision. | +| smallint | int2 | Signed two-byte integer. For numbers ranging from -32768 to +32767. | | smallserial | serial2 | Autoincrementing two-byte integer. For numbers ranging from 1 to 32767. | -| serial | serial4 | Autoincrementing four-byte integer. For numbers ranging from 1 to 2147483647 | +| serial | serial4 | Autoincrementing four-byte integer. For numbers ranging from 1 to 2147483647. | | text | | Variable-length character string. This is the general purpose data type for textual content. | | time \[ without time zone \] | | Time of day (no time zone). | | time with time zone | timetz | Time of day, including time zone. | | timestamp \[ without time zone \] | | Date and time (no time zone). | | timestamp with time zone | timestamptz | Date and time, including time zone. | | tsquery | | Text search query. | -| tsvector | | Text search document . | +| tsvector | | Text search document. | | txid\_snapshot | | User-level transaction ID snapshot (deprecated; see pg\_snapshot). | | uuid | | Universally unique identifier. | | xml | | XML data. | diff --git a/web/docs/guides/database/tables.mdx b/web/docs/guides/database/tables.mdx index cd394dbefd7..7fee73deda3 100644 --- a/web/docs/guides/database/tables.mdx +++ b/web/docs/guides/database/tables.mdx @@ -85,30 +85,7 @@ You must define the "data type" when you create a column. Every column is a predefined type. PostgreSQL provides many [default types](https://www.postgresql.org/docs/current/datatype.html), and you can even design your own (or use extensions) if the default types don't fit your needs. -Here's a list of the data types that are available to use in the table editor in the Dashboard: - -| `Name` | `Description` | `Example` | -| ------------------------------------------- | -------------------- | ----------------------------------------------------------------- | -| int2 | Can contain numbers between -32,768 and 32,767 | For storing numbers like ages of people, distance between places or numbers you know will be fairly small. | -| int4 | Can contain numbers between -2,147,483,648 and +2,147,483,648 | For storing numbers like the population of small towns or cities that you know will be less than about 2 billion. | -| int8 | Can contain numbers between 9,223,372,036,854,775,808 and +9,223,372,036,854,775,808 | For storing numbers larger than roughly 2 billion. Like the number of people who live in the Northern vs Southern hemisphere or the total number of COVID-19 vaccinations administered. | -| float4 | Can contain numbers with up to 6 decimal places | For storing things like temperature (22.5 degrees Celsius) or distance (10.25kms)| -| float8 | Can contain numbers with up to 15 decimal places | For storing numbers with a high level of precision, like scientific or mathematical data. | -| numeric | Can contain 131,072 digits before the decimal point and 16,383 digits after the decimal point. | For storing number that require very high precision. Use the numeric type when you need more precision than float4 or float8 offer. | -| json | Can contain JSON data. | For storing data that logically belongs together, like a person's street address. Useful for when you want to store dynamic fields and not have every field represented as a column in your table. | -| jsonb | The JSONB type stores your JSON input as a binary code instead of as an exact copy of the JSON data. JSONB is faster, more efficient and supports indexing. | If you are doing a lot of JSON manipulation in Postgres you should consider using JSONB for efficiency. Otherwise, if you are just doing typical data storing and fetching, JSON should be fine. | -| text | Can contain strings of any length. | For storing any kind of textual data. Examples include text contents of recipes or blog posts. This is the general purpose data type for textual content. | -| varchar | Can contain strings with a fixed length | For storing a string where you would want to limit the length to 160 characters. | -| uuid | Can store a universal unique identifier. | For storing unique IDs, like when you need to store a reference to another table row. | -| date | Can store a data value without time. | For storing dates like birthdays or holidays with a year, month and day. | -| time | Can store the time of day | For storing things like when a process starts and stops at specific times in the day. The lights come on at 6:00:00 a.m. and go off at 10:00:00 p.m. | -| timez | Can store the time of day, along with a timezone. | For storing things like event start times, like an Apple event starting at 10:00:00 a.m. Pacific Time. | -| timestamp | Can store the date and time without a timezone. | For storing times like: May 1st, 2022 at 10 a.m. | -| timestampz | Can store the date and time with a timezone. | For storing times like: May 1st, 2022 at 10 a.m, Pacific Time. | -| bool | Can store boolean values | For storing things that will be true or false, like user_is_subscribed or show_homepage_ad. | - - -Here's a complete list of all of the default data types provided by Postgres: +Here's list of all of the default data types provided by Postgres:
Show/Hide default data types From a1412f71bf5120ce638ae0eeac855ef2bc7290bf Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Mon, 5 Sep 2022 18:17:50 +0800 Subject: [PATCH 014/208] Implement updated UI for PITR backups, midway refining components, validation --- .../Database/Backups/PITR/PITR.constants.ts | 1196 +++++++++++++++++ .../Database/Backups/PITR/PITR.types.ts | 14 + .../Database/Backups/PITR/PITR.utils.ts | 31 + .../Database/Backups/PITR/PITRNotice.tsx | 35 + .../Database/Backups/PITR/PITRSelection.tsx | 326 +++++ .../Database/Backups/PITR/PITRStatus.tsx | 72 + .../Database/Backups/PITR/TimeInput.tsx | 185 +++ .../Backups/PITR/TimezoneSelection.tsx | 78 ++ .../interfaces/Database/Backups/PITR/index.ts | 4 + .../PITRBackupSelection.tsx | 263 ++-- studio/components/ui/InformationBox.tsx | 40 +- studio/components/ui/PasswordStrengthBar.tsx | 1 + studio/package-lock.json | 32 +- studio/package.json | 4 +- .../project/[ref]/database/backups/pitr.tsx | 14 +- .../[ref]/database/backups/scheduled.tsx | 2 +- studio/styles/date-picker.scss | 8 + studio/styles/main.scss | 4 + studio/styles/ui.scss | 4 + 19 files changed, 2142 insertions(+), 171 deletions(-) create mode 100644 studio/components/interfaces/Database/Backups/PITR/PITR.constants.ts create mode 100644 studio/components/interfaces/Database/Backups/PITR/PITR.types.ts create mode 100644 studio/components/interfaces/Database/Backups/PITR/PITR.utils.ts create mode 100644 studio/components/interfaces/Database/Backups/PITR/PITRNotice.tsx create mode 100644 studio/components/interfaces/Database/Backups/PITR/PITRSelection.tsx create mode 100644 studio/components/interfaces/Database/Backups/PITR/PITRStatus.tsx create mode 100644 studio/components/interfaces/Database/Backups/PITR/TimeInput.tsx create mode 100644 studio/components/interfaces/Database/Backups/PITR/TimezoneSelection.tsx create mode 100644 studio/components/interfaces/Database/Backups/PITR/index.ts diff --git a/studio/components/interfaces/Database/Backups/PITR/PITR.constants.ts b/studio/components/interfaces/Database/Backups/PITR/PITR.constants.ts new file mode 100644 index 00000000000..bf1877b267c --- /dev/null +++ b/studio/components/interfaces/Database/Backups/PITR/PITR.constants.ts @@ -0,0 +1,1196 @@ +// https://github.com/dmfilipenko/timezones.json/blob/master/timezones.json +export const ALL_TIMEZONES = [ + { + value: 'Dateline Standard Time', + abbr: 'DST', + offset: -12, + isdst: false, + text: '(UTC-12:00) International Date Line West', + utc: ['Etc/GMT+12'], + }, + { + value: 'UTC-11', + abbr: 'U', + offset: -11, + isdst: false, + text: '(UTC-11:00) Coordinated Universal Time-11', + utc: ['Etc/GMT+11', 'Pacific/Midway', 'Pacific/Niue', 'Pacific/Pago_Pago'], + }, + { + value: 'Hawaiian Standard Time', + abbr: 'HST', + offset: -10, + isdst: false, + text: '(UTC-10:00) Hawaii', + utc: [ + 'Etc/GMT+10', + 'Pacific/Honolulu', + 'Pacific/Johnston', + 'Pacific/Rarotonga', + 'Pacific/Tahiti', + ], + }, + { + value: 'Alaskan Standard Time', + abbr: 'AKDT', + offset: -8, + isdst: true, + text: '(UTC-09:00) Alaska', + utc: [ + 'America/Anchorage', + 'America/Juneau', + 'America/Nome', + 'America/Sitka', + 'America/Yakutat', + ], + }, + { + value: 'Pacific Standard Time (Mexico)', + abbr: 'PDT', + offset: -7, + isdst: true, + text: '(UTC-08:00) Baja California', + utc: ['America/Santa_Isabel'], + }, + { + value: 'Pacific Daylight Time', + abbr: 'PDT', + offset: -7, + isdst: true, + text: '(UTC-07:00) Pacific Daylight Time (US & Canada)', + utc: ['America/Los_Angeles', 'America/Tijuana', 'America/Vancouver'], + }, + { + value: 'Pacific Standard Time', + abbr: 'PST', + offset: -8, + isdst: false, + text: '(UTC-08:00) Pacific Standard Time (US & Canada)', + utc: ['America/Los_Angeles', 'America/Tijuana', 'America/Vancouver', 'PST8PDT'], + }, + { + value: 'US Mountain Standard Time', + abbr: 'UMST', + offset: -7, + isdst: false, + text: '(UTC-07:00) Arizona', + utc: [ + 'America/Creston', + 'America/Dawson', + 'America/Dawson_Creek', + 'America/Hermosillo', + 'America/Phoenix', + 'America/Whitehorse', + 'Etc/GMT+7', + ], + }, + { + value: 'Mountain Standard Time (Mexico)', + abbr: 'MDT', + offset: -6, + isdst: true, + text: '(UTC-07:00) Chihuahua, La Paz, Mazatlan', + utc: ['America/Chihuahua', 'America/Mazatlan'], + }, + { + value: 'Mountain Standard Time', + abbr: 'MDT', + offset: -6, + isdst: true, + text: '(UTC-07:00) Mountain Time (US & Canada)', + utc: [ + 'America/Boise', + 'America/Cambridge_Bay', + 'America/Denver', + 'America/Edmonton', + 'America/Inuvik', + 'America/Ojinaga', + 'America/Yellowknife', + 'MST7MDT', + ], + }, + { + value: 'Central America Standard Time', + abbr: 'CAST', + offset: -6, + isdst: false, + text: '(UTC-06:00) Central America', + utc: [ + 'America/Belize', + 'America/Costa_Rica', + 'America/El_Salvador', + 'America/Guatemala', + 'America/Managua', + 'America/Tegucigalpa', + 'Etc/GMT+6', + 'Pacific/Galapagos', + ], + }, + { + value: 'Central Standard Time', + abbr: 'CDT', + offset: -5, + isdst: true, + text: '(UTC-06:00) Central Time (US & Canada)', + utc: [ + 'America/Chicago', + 'America/Indiana/Knox', + 'America/Indiana/Tell_City', + 'America/Matamoros', + 'America/Menominee', + 'America/North_Dakota/Beulah', + 'America/North_Dakota/Center', + 'America/North_Dakota/New_Salem', + 'America/Rainy_River', + 'America/Rankin_Inlet', + 'America/Resolute', + 'America/Winnipeg', + 'CST6CDT', + ], + }, + { + value: 'Central Standard Time (Mexico)', + abbr: 'CDT', + offset: -5, + isdst: true, + text: '(UTC-06:00) Guadalajara, Mexico City, Monterrey', + utc: [ + 'America/Bahia_Banderas', + 'America/Cancun', + 'America/Merida', + 'America/Mexico_City', + 'America/Monterrey', + ], + }, + { + value: 'Canada Central Standard Time', + abbr: 'CCST', + offset: -6, + isdst: false, + text: '(UTC-06:00) Saskatchewan', + utc: ['America/Regina', 'America/Swift_Current'], + }, + { + value: 'SA Pacific Standard Time', + abbr: 'SPST', + offset: -5, + isdst: false, + text: '(UTC-05:00) Bogota, Lima, Quito', + utc: [ + 'America/Bogota', + 'America/Cayman', + 'America/Coral_Harbour', + 'America/Eirunepe', + 'America/Guayaquil', + 'America/Jamaica', + 'America/Lima', + 'America/Panama', + 'America/Rio_Branco', + 'Etc/GMT+5', + ], + }, + { + value: 'Eastern Standard Time', + abbr: 'EST', + offset: -5, + isdst: false, + text: '(UTC-05:00) Eastern Time (US & Canada)', + utc: [ + 'America/Detroit', + 'America/Havana', + 'America/Indiana/Petersburg', + 'America/Indiana/Vincennes', + 'America/Indiana/Winamac', + 'America/Iqaluit', + 'America/Kentucky/Monticello', + 'America/Louisville', + 'America/Montreal', + 'America/Nassau', + 'America/New_York', + 'America/Nipigon', + 'America/Pangnirtung', + 'America/Port-au-Prince', + 'America/Thunder_Bay', + 'America/Toronto', + ], + }, + { + value: 'Eastern Daylight Time', + abbr: 'EDT', + offset: -4, + isdst: true, + text: '(UTC-04:00) Eastern Daylight Time (US & Canada)', + utc: [ + 'America/Detroit', + 'America/Havana', + 'America/Indiana/Petersburg', + 'America/Indiana/Vincennes', + 'America/Indiana/Winamac', + 'America/Iqaluit', + 'America/Kentucky/Monticello', + 'America/Louisville', + 'America/Montreal', + 'America/Nassau', + 'America/New_York', + 'America/Nipigon', + 'America/Pangnirtung', + 'America/Port-au-Prince', + 'America/Thunder_Bay', + 'America/Toronto', + ], + }, + { + value: 'US Eastern Standard Time', + abbr: 'UEDT', + offset: -5, + isdst: false, + text: '(UTC-05:00) Indiana (East)', + utc: ['America/Indiana/Marengo', 'America/Indiana/Vevay', 'America/Indianapolis'], + }, + { + value: 'Venezuela Standard Time', + abbr: 'VST', + offset: -4.5, + isdst: false, + text: '(UTC-04:30) Caracas', + utc: ['America/Caracas'], + }, + { + value: 'Paraguay Standard Time', + abbr: 'PYT', + offset: -4, + isdst: false, + text: '(UTC-04:00) Asuncion', + utc: ['America/Asuncion'], + }, + { + value: 'Atlantic Standard Time', + abbr: 'ADT', + offset: -3, + isdst: true, + text: '(UTC-04:00) Atlantic Time (Canada)', + utc: [ + 'America/Glace_Bay', + 'America/Goose_Bay', + 'America/Halifax', + 'America/Moncton', + 'America/Thule', + 'Atlantic/Bermuda', + ], + }, + { + value: 'Central Brazilian Standard Time', + abbr: 'CBST', + offset: -4, + isdst: false, + text: '(UTC-04:00) Cuiaba', + utc: ['America/Campo_Grande', 'America/Cuiaba'], + }, + { + value: 'SA Western Standard Time', + abbr: 'SWST', + offset: -4, + isdst: false, + text: '(UTC-04:00) Georgetown, La Paz, Manaus, San Juan', + utc: [ + 'America/Anguilla', + 'America/Antigua', + 'America/Aruba', + 'America/Barbados', + 'America/Blanc-Sablon', + 'America/Boa_Vista', + 'America/Curacao', + 'America/Dominica', + 'America/Grand_Turk', + 'America/Grenada', + 'America/Guadeloupe', + 'America/Guyana', + 'America/Kralendijk', + 'America/La_Paz', + 'America/Lower_Princes', + 'America/Manaus', + 'America/Marigot', + 'America/Martinique', + 'America/Montserrat', + 'America/Port_of_Spain', + 'America/Porto_Velho', + 'America/Puerto_Rico', + 'America/Santo_Domingo', + 'America/St_Barthelemy', + 'America/St_Kitts', + 'America/St_Lucia', + 'America/St_Thomas', + 'America/St_Vincent', + 'America/Tortola', + 'Etc/GMT+4', + ], + }, + { + value: 'Pacific SA Standard Time', + abbr: 'PSST', + offset: -4, + isdst: false, + text: '(UTC-04:00) Santiago', + utc: ['America/Santiago', 'Antarctica/Palmer'], + }, + { + value: 'Newfoundland Standard Time', + abbr: 'NDT', + offset: -2.5, + isdst: true, + text: '(UTC-03:30) Newfoundland', + utc: ['America/St_Johns'], + }, + { + value: 'E. South America Standard Time', + abbr: 'ESAST', + offset: -3, + isdst: false, + text: '(UTC-03:00) Brasilia', + utc: ['America/Sao_Paulo'], + }, + { + value: 'Argentina Standard Time', + abbr: 'AST', + offset: -3, + isdst: false, + text: '(UTC-03:00) Buenos Aires', + utc: [ + 'America/Argentina/La_Rioja', + 'America/Argentina/Rio_Gallegos', + 'America/Argentina/Salta', + 'America/Argentina/San_Juan', + 'America/Argentina/San_Luis', + 'America/Argentina/Tucuman', + 'America/Argentina/Ushuaia', + 'America/Buenos_Aires', + 'America/Catamarca', + 'America/Cordoba', + 'America/Jujuy', + 'America/Mendoza', + ], + }, + { + value: 'SA Eastern Standard Time', + abbr: 'SEST', + offset: -3, + isdst: false, + text: '(UTC-03:00) Cayenne, Fortaleza', + utc: [ + 'America/Araguaina', + 'America/Belem', + 'America/Cayenne', + 'America/Fortaleza', + 'America/Maceio', + 'America/Paramaribo', + 'America/Recife', + 'America/Santarem', + 'Antarctica/Rothera', + 'Atlantic/Stanley', + 'Etc/GMT+3', + ], + }, + { + value: 'Greenland Standard Time', + abbr: 'GDT', + offset: -3, + isdst: true, + text: '(UTC-03:00) Greenland', + utc: ['America/Godthab'], + }, + { + value: 'Montevideo Standard Time', + abbr: 'MST', + offset: -3, + isdst: false, + text: '(UTC-03:00) Montevideo', + utc: ['America/Montevideo'], + }, + { + value: 'Bahia Standard Time', + abbr: 'BST', + offset: -3, + isdst: false, + text: '(UTC-03:00) Salvador', + utc: ['America/Bahia'], + }, + { + value: 'UTC-02', + abbr: 'U', + offset: -2, + isdst: false, + text: '(UTC-02:00) Coordinated Universal Time-02', + utc: ['America/Noronha', 'Atlantic/South_Georgia', 'Etc/GMT+2'], + }, + { + value: 'Mid-Atlantic Standard Time', + abbr: 'MDT', + offset: -1, + isdst: true, + text: '(UTC-02:00) Mid-Atlantic - Old', + utc: [], + }, + { + value: 'Azores Standard Time', + abbr: 'ADT', + offset: 0, + isdst: true, + text: '(UTC-01:00) Azores', + utc: ['America/Scoresbysund', 'Atlantic/Azores'], + }, + { + value: 'Cape Verde Standard Time', + abbr: 'CVST', + offset: -1, + isdst: false, + text: '(UTC-01:00) Cape Verde Is.', + utc: ['Atlantic/Cape_Verde', 'Etc/GMT+1'], + }, + { + value: 'Morocco Standard Time', + abbr: 'MDT', + offset: 1, + isdst: true, + text: '(UTC) Casablanca', + utc: ['Africa/Casablanca', 'Africa/El_Aaiun'], + }, + { + value: 'UTC', + abbr: 'UTC', + offset: 0, + isdst: false, + text: '(UTC) Coordinated Universal Time', + utc: ['America/Danmarkshavn', 'Etc/GMT'], + }, + { + value: 'British Summer Time', + abbr: 'BST', + offset: 1, + isdst: true, + text: '(UTC+01:00) Edinburgh, London', + utc: ['Europe/Isle_of_Man', 'Europe/Guernsey', 'Europe/Jersey', 'Europe/London'], + }, + { + value: 'GMT Standard Time', + abbr: 'GDT', + offset: 1, + isdst: true, + text: '(UTC) Dublin, Lisbon', + utc: [ + 'Atlantic/Canary', + 'Atlantic/Faeroe', + 'Atlantic/Madeira', + 'Europe/Dublin', + 'Europe/Lisbon', + ], + }, + { + value: 'Greenwich Standard Time', + abbr: 'GST', + offset: 0, + isdst: false, + text: '(UTC) Monrovia, Reykjavik', + utc: [ + 'Africa/Abidjan', + 'Africa/Accra', + 'Africa/Bamako', + 'Africa/Banjul', + 'Africa/Bissau', + 'Africa/Conakry', + 'Africa/Dakar', + 'Africa/Freetown', + 'Africa/Lome', + 'Africa/Monrovia', + 'Africa/Nouakchott', + 'Africa/Ouagadougou', + 'Africa/Sao_Tome', + 'Atlantic/Reykjavik', + 'Atlantic/St_Helena', + ], + }, + { + value: 'W. Europe Standard Time', + abbr: 'WEDT', + offset: 2, + isdst: true, + text: '(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna', + utc: [ + 'Arctic/Longyearbyen', + 'Europe/Amsterdam', + 'Europe/Andorra', + 'Europe/Berlin', + 'Europe/Busingen', + 'Europe/Gibraltar', + 'Europe/Luxembourg', + 'Europe/Malta', + 'Europe/Monaco', + 'Europe/Oslo', + 'Europe/Rome', + 'Europe/San_Marino', + 'Europe/Stockholm', + 'Europe/Vaduz', + 'Europe/Vatican', + 'Europe/Vienna', + 'Europe/Zurich', + ], + }, + { + value: 'Central Europe Standard Time', + abbr: 'CEDT', + offset: 2, + isdst: true, + text: '(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague', + utc: [ + 'Europe/Belgrade', + 'Europe/Bratislava', + 'Europe/Budapest', + 'Europe/Ljubljana', + 'Europe/Podgorica', + 'Europe/Prague', + 'Europe/Tirane', + ], + }, + { + value: 'Romance Standard Time', + abbr: 'RDT', + offset: 2, + isdst: true, + text: '(UTC+01:00) Brussels, Copenhagen, Madrid, Paris', + utc: ['Africa/Ceuta', 'Europe/Brussels', 'Europe/Copenhagen', 'Europe/Madrid', 'Europe/Paris'], + }, + { + value: 'Central European Standard Time', + abbr: 'CEDT', + offset: 2, + isdst: true, + text: '(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb', + utc: ['Europe/Sarajevo', 'Europe/Skopje', 'Europe/Warsaw', 'Europe/Zagreb'], + }, + { + value: 'W. Central Africa Standard Time', + abbr: 'WCAST', + offset: 1, + isdst: false, + text: '(UTC+01:00) West Central Africa', + utc: [ + 'Africa/Algiers', + 'Africa/Bangui', + 'Africa/Brazzaville', + 'Africa/Douala', + 'Africa/Kinshasa', + 'Africa/Lagos', + 'Africa/Libreville', + 'Africa/Luanda', + 'Africa/Malabo', + 'Africa/Ndjamena', + 'Africa/Niamey', + 'Africa/Porto-Novo', + 'Africa/Tunis', + 'Etc/GMT-1', + ], + }, + { + value: 'Namibia Standard Time', + abbr: 'NST', + offset: 1, + isdst: false, + text: '(UTC+01:00) Windhoek', + utc: ['Africa/Windhoek'], + }, + { + value: 'GTB Standard Time', + abbr: 'GDT', + offset: 3, + isdst: true, + text: '(UTC+02:00) Athens, Bucharest', + utc: ['Asia/Nicosia', 'Europe/Athens', 'Europe/Bucharest', 'Europe/Chisinau'], + }, + { + value: 'Middle East Standard Time', + abbr: 'MEDT', + offset: 3, + isdst: true, + text: '(UTC+02:00) Beirut', + utc: ['Asia/Beirut'], + }, + { + value: 'Egypt Standard Time', + abbr: 'EST', + offset: 2, + isdst: false, + text: '(UTC+02:00) Cairo', + utc: ['Africa/Cairo'], + }, + { + value: 'Syria Standard Time', + abbr: 'SDT', + offset: 3, + isdst: true, + text: '(UTC+02:00) Damascus', + utc: ['Asia/Damascus'], + }, + { + value: 'E. Europe Standard Time', + abbr: 'EEDT', + offset: 3, + isdst: true, + text: '(UTC+02:00) E. Europe', + utc: [ + 'Asia/Nicosia', + 'Europe/Athens', + 'Europe/Bucharest', + 'Europe/Chisinau', + 'Europe/Helsinki', + 'Europe/Kiev', + 'Europe/Mariehamn', + 'Europe/Nicosia', + 'Europe/Riga', + 'Europe/Sofia', + 'Europe/Tallinn', + 'Europe/Uzhgorod', + 'Europe/Vilnius', + 'Europe/Zaporozhye', + ], + }, + { + value: 'South Africa Standard Time', + abbr: 'SAST', + offset: 2, + isdst: false, + text: '(UTC+02:00) Harare, Pretoria', + utc: [ + 'Africa/Blantyre', + 'Africa/Bujumbura', + 'Africa/Gaborone', + 'Africa/Harare', + 'Africa/Johannesburg', + 'Africa/Kigali', + 'Africa/Lubumbashi', + 'Africa/Lusaka', + 'Africa/Maputo', + 'Africa/Maseru', + 'Africa/Mbabane', + 'Etc/GMT-2', + ], + }, + { + value: 'FLE Standard Time', + abbr: 'FDT', + offset: 3, + isdst: true, + text: '(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius', + utc: [ + 'Europe/Helsinki', + 'Europe/Kiev', + 'Europe/Mariehamn', + 'Europe/Riga', + 'Europe/Sofia', + 'Europe/Tallinn', + 'Europe/Uzhgorod', + 'Europe/Vilnius', + 'Europe/Zaporozhye', + ], + }, + { + value: 'Turkey Standard Time', + abbr: 'TDT', + offset: 3, + isdst: false, + text: '(UTC+03:00) Istanbul', + utc: ['Europe/Istanbul'], + }, + { + value: 'Israel Standard Time', + abbr: 'JDT', + offset: 3, + isdst: true, + text: '(UTC+02:00) Jerusalem', + utc: ['Asia/Jerusalem'], + }, + { + value: 'Libya Standard Time', + abbr: 'LST', + offset: 2, + isdst: false, + text: '(UTC+02:00) Tripoli', + utc: ['Africa/Tripoli'], + }, + { + value: 'Jordan Standard Time', + abbr: 'JST', + offset: 3, + isdst: false, + text: '(UTC+03:00) Amman', + utc: ['Asia/Amman'], + }, + { + value: 'Arabic Standard Time', + abbr: 'AST', + offset: 3, + isdst: false, + text: '(UTC+03:00) Baghdad', + utc: ['Asia/Baghdad'], + }, + { + value: 'Kaliningrad Standard Time', + abbr: 'KST', + offset: 3, + isdst: false, + text: '(UTC+02:00) Kaliningrad', + utc: ['Europe/Kaliningrad'], + }, + { + value: 'Arab Standard Time', + abbr: 'AST', + offset: 3, + isdst: false, + text: '(UTC+03:00) Kuwait, Riyadh', + utc: ['Asia/Aden', 'Asia/Bahrain', 'Asia/Kuwait', 'Asia/Qatar', 'Asia/Riyadh'], + }, + { + value: 'E. Africa Standard Time', + abbr: 'EAST', + offset: 3, + isdst: false, + text: '(UTC+03:00) Nairobi', + utc: [ + 'Africa/Addis_Ababa', + 'Africa/Asmera', + 'Africa/Dar_es_Salaam', + 'Africa/Djibouti', + 'Africa/Juba', + 'Africa/Kampala', + 'Africa/Khartoum', + 'Africa/Mogadishu', + 'Africa/Nairobi', + 'Antarctica/Syowa', + 'Etc/GMT-3', + 'Indian/Antananarivo', + 'Indian/Comoro', + 'Indian/Mayotte', + ], + }, + { + value: 'Moscow Standard Time', + abbr: 'MSK', + offset: 3, + isdst: false, + text: '(UTC+03:00) Moscow, St. Petersburg, Volgograd, Minsk', + utc: ['Europe/Kirov', 'Europe/Moscow', 'Europe/Simferopol', 'Europe/Volgograd', 'Europe/Minsk'], + }, + { + value: 'Samara Time', + abbr: 'SAMT', + offset: 4, + isdst: false, + text: '(UTC+04:00) Samara, Ulyanovsk, Saratov', + utc: ['Europe/Astrakhan', 'Europe/Samara', 'Europe/Ulyanovsk'], + }, + { + value: 'Iran Standard Time', + abbr: 'IDT', + offset: 4.5, + isdst: true, + text: '(UTC+03:30) Tehran', + utc: ['Asia/Tehran'], + }, + { + value: 'Arabian Standard Time', + abbr: 'AST', + offset: 4, + isdst: false, + text: '(UTC+04:00) Abu Dhabi, Muscat', + utc: ['Asia/Dubai', 'Asia/Muscat', 'Etc/GMT-4'], + }, + { + value: 'Azerbaijan Standard Time', + abbr: 'ADT', + offset: 5, + isdst: true, + text: '(UTC+04:00) Baku', + utc: ['Asia/Baku'], + }, + { + value: 'Mauritius Standard Time', + abbr: 'MST', + offset: 4, + isdst: false, + text: '(UTC+04:00) Port Louis', + utc: ['Indian/Mahe', 'Indian/Mauritius', 'Indian/Reunion'], + }, + { + value: 'Georgian Standard Time', + abbr: 'GET', + offset: 4, + isdst: false, + text: '(UTC+04:00) Tbilisi', + utc: ['Asia/Tbilisi'], + }, + { + value: 'Caucasus Standard Time', + abbr: 'CST', + offset: 4, + isdst: false, + text: '(UTC+04:00) Yerevan', + utc: ['Asia/Yerevan'], + }, + { + value: 'Afghanistan Standard Time', + abbr: 'AST', + offset: 4.5, + isdst: false, + text: '(UTC+04:30) Kabul', + utc: ['Asia/Kabul'], + }, + { + value: 'West Asia Standard Time', + abbr: 'WAST', + offset: 5, + isdst: false, + text: '(UTC+05:00) Ashgabat, Tashkent', + utc: [ + 'Antarctica/Mawson', + 'Asia/Aqtau', + 'Asia/Aqtobe', + 'Asia/Ashgabat', + 'Asia/Dushanbe', + 'Asia/Oral', + 'Asia/Samarkand', + 'Asia/Tashkent', + 'Etc/GMT-5', + 'Indian/Kerguelen', + 'Indian/Maldives', + ], + }, + { + value: 'Yekaterinburg Time', + abbr: 'YEKT', + offset: 5, + isdst: false, + text: '(UTC+05:00) Yekaterinburg', + utc: ['Asia/Yekaterinburg'], + }, + { + value: 'Pakistan Standard Time', + abbr: 'PKT', + offset: 5, + isdst: false, + text: '(UTC+05:00) Islamabad, Karachi', + utc: ['Asia/Karachi'], + }, + { + value: 'India Standard Time', + abbr: 'IST', + offset: 5.5, + isdst: false, + text: '(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi', + utc: ['Asia/Kolkata', 'Asia/Calcutta'], + }, + { + value: 'Sri Lanka Standard Time', + abbr: 'SLST', + offset: 5.5, + isdst: false, + text: '(UTC+05:30) Sri Jayawardenepura', + utc: ['Asia/Colombo'], + }, + { + value: 'Nepal Standard Time', + abbr: 'NST', + offset: 5.75, + isdst: false, + text: '(UTC+05:45) Kathmandu', + utc: ['Asia/Kathmandu'], + }, + { + value: 'Central Asia Standard Time', + abbr: 'CAST', + offset: 6, + isdst: false, + text: '(UTC+06:00) Nur-Sultan (Astana)', + utc: [ + 'Antarctica/Vostok', + 'Asia/Almaty', + 'Asia/Bishkek', + 'Asia/Qyzylorda', + 'Asia/Urumqi', + 'Etc/GMT-6', + 'Indian/Chagos', + ], + }, + { + value: 'Bangladesh Standard Time', + abbr: 'BST', + offset: 6, + isdst: false, + text: '(UTC+06:00) Dhaka', + utc: ['Asia/Dhaka', 'Asia/Thimphu'], + }, + { + value: 'Myanmar Standard Time', + abbr: 'MST', + offset: 6.5, + isdst: false, + text: '(UTC+06:30) Yangon (Rangoon)', + utc: ['Asia/Rangoon', 'Indian/Cocos'], + }, + { + value: 'SE Asia Standard Time', + abbr: 'SAST', + offset: 7, + isdst: false, + text: '(UTC+07:00) Bangkok, Hanoi, Jakarta', + utc: [ + 'Antarctica/Davis', + 'Asia/Bangkok', + 'Asia/Hovd', + 'Asia/Jakarta', + 'Asia/Phnom_Penh', + 'Asia/Pontianak', + 'Asia/Saigon', + 'Asia/Vientiane', + 'Etc/GMT-7', + 'Indian/Christmas', + ], + }, + { + value: 'N. Central Asia Standard Time', + abbr: 'NCAST', + offset: 7, + isdst: false, + text: '(UTC+07:00) Novosibirsk', + utc: ['Asia/Novokuznetsk', 'Asia/Novosibirsk', 'Asia/Omsk'], + }, + { + value: 'China Standard Time', + abbr: 'CST', + offset: 8, + isdst: false, + text: '(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi', + utc: ['Asia/Hong_Kong', 'Asia/Macau', 'Asia/Shanghai'], + }, + { + value: 'North Asia Standard Time', + abbr: 'NAST', + offset: 8, + isdst: false, + text: '(UTC+08:00) Krasnoyarsk', + utc: ['Asia/Krasnoyarsk'], + }, + { + value: 'Singapore Standard Time', + abbr: 'MPST', + offset: 8, + isdst: false, + text: '(UTC+08:00) Kuala Lumpur, Singapore', + utc: [ + 'Asia/Brunei', + 'Asia/Kuala_Lumpur', + 'Asia/Kuching', + 'Asia/Makassar', + 'Asia/Manila', + 'Asia/Singapore', + 'Etc/GMT-8', + ], + }, + { + value: 'W. Australia Standard Time', + abbr: 'WAST', + offset: 8, + isdst: false, + text: '(UTC+08:00) Perth', + utc: ['Antarctica/Casey', 'Australia/Perth'], + }, + { + value: 'Taipei Standard Time', + abbr: 'TST', + offset: 8, + isdst: false, + text: '(UTC+08:00) Taipei', + utc: ['Asia/Taipei'], + }, + { + value: 'Ulaanbaatar Standard Time', + abbr: 'UST', + offset: 8, + isdst: false, + text: '(UTC+08:00) Ulaanbaatar', + utc: ['Asia/Choibalsan', 'Asia/Ulaanbaatar'], + }, + { + value: 'North Asia East Standard Time', + abbr: 'NAEST', + offset: 8, + isdst: false, + text: '(UTC+08:00) Irkutsk', + utc: ['Asia/Irkutsk'], + }, + { + value: 'Japan Standard Time', + abbr: 'JST', + offset: 9, + isdst: false, + text: '(UTC+09:00) Osaka, Sapporo, Tokyo', + utc: ['Asia/Dili', 'Asia/Jayapura', 'Asia/Tokyo', 'Etc/GMT-9', 'Pacific/Palau'], + }, + { + value: 'Korea Standard Time', + abbr: 'KST', + offset: 9, + isdst: false, + text: '(UTC+09:00) Seoul', + utc: ['Asia/Pyongyang', 'Asia/Seoul'], + }, + { + value: 'Cen. Australia Standard Time', + abbr: 'CAST', + offset: 9.5, + isdst: false, + text: '(UTC+09:30) Adelaide', + utc: ['Australia/Adelaide', 'Australia/Broken_Hill'], + }, + { + value: 'AUS Central Standard Time', + abbr: 'ACST', + offset: 9.5, + isdst: false, + text: '(UTC+09:30) Darwin', + utc: ['Australia/Darwin'], + }, + { + value: 'E. Australia Standard Time', + abbr: 'EAST', + offset: 10, + isdst: false, + text: '(UTC+10:00) Brisbane', + utc: ['Australia/Brisbane', 'Australia/Lindeman'], + }, + { + value: 'AUS Eastern Standard Time', + abbr: 'AEST', + offset: 10, + isdst: false, + text: '(UTC+10:00) Canberra, Melbourne, Sydney', + utc: ['Australia/Melbourne', 'Australia/Sydney'], + }, + { + value: 'West Pacific Standard Time', + abbr: 'WPST', + offset: 10, + isdst: false, + text: '(UTC+10:00) Guam, Port Moresby', + utc: [ + 'Antarctica/DumontDUrville', + 'Etc/GMT-10', + 'Pacific/Guam', + 'Pacific/Port_Moresby', + 'Pacific/Saipan', + 'Pacific/Truk', + ], + }, + { + value: 'Tasmania Standard Time', + abbr: 'TST', + offset: 10, + isdst: false, + text: '(UTC+10:00) Hobart', + utc: ['Australia/Currie', 'Australia/Hobart'], + }, + { + value: 'Yakutsk Standard Time', + abbr: 'YST', + offset: 9, + isdst: false, + text: '(UTC+09:00) Yakutsk', + utc: ['Asia/Chita', 'Asia/Khandyga', 'Asia/Yakutsk'], + }, + { + value: 'Central Pacific Standard Time', + abbr: 'CPST', + offset: 11, + isdst: false, + text: '(UTC+11:00) Solomon Is., New Caledonia', + utc: [ + 'Antarctica/Macquarie', + 'Etc/GMT-11', + 'Pacific/Efate', + 'Pacific/Guadalcanal', + 'Pacific/Kosrae', + 'Pacific/Noumea', + 'Pacific/Ponape', + ], + }, + { + value: 'Vladivostok Standard Time', + abbr: 'VST', + offset: 11, + isdst: false, + text: '(UTC+11:00) Vladivostok', + utc: ['Asia/Sakhalin', 'Asia/Ust-Nera', 'Asia/Vladivostok'], + }, + { + value: 'New Zealand Standard Time', + abbr: 'NZST', + offset: 12, + isdst: false, + text: '(UTC+12:00) Auckland, Wellington', + utc: ['Antarctica/McMurdo', 'Pacific/Auckland'], + }, + { + value: 'UTC+12', + abbr: 'U', + offset: 12, + isdst: false, + text: '(UTC+12:00) Coordinated Universal Time+12', + utc: [ + 'Etc/GMT-12', + 'Pacific/Funafuti', + 'Pacific/Kwajalein', + 'Pacific/Majuro', + 'Pacific/Nauru', + 'Pacific/Tarawa', + 'Pacific/Wake', + 'Pacific/Wallis', + ], + }, + { + value: 'Fiji Standard Time', + abbr: 'FST', + offset: 12, + isdst: false, + text: '(UTC+12:00) Fiji', + utc: ['Pacific/Fiji'], + }, + { + value: 'Magadan Standard Time', + abbr: 'MST', + offset: 12, + isdst: false, + text: '(UTC+12:00) Magadan', + utc: ['Asia/Anadyr', 'Asia/Kamchatka', 'Asia/Magadan', 'Asia/Srednekolymsk'], + }, + { + value: 'Kamchatka Standard Time', + abbr: 'KDT', + offset: 13, + isdst: true, + text: '(UTC+12:00) Petropavlovsk-Kamchatsky - Old', + utc: ['Asia/Kamchatka'], + }, + { + value: 'Tonga Standard Time', + abbr: 'TST', + offset: 13, + isdst: false, + text: "(UTC+13:00) Nuku'alofa", + utc: ['Etc/GMT-13', 'Pacific/Enderbury', 'Pacific/Fakaofo', 'Pacific/Tongatapu'], + }, + { + value: 'Samoa Standard Time', + abbr: 'SST', + offset: 13, + isdst: false, + text: '(UTC+13:00) Samoa', + utc: ['Pacific/Apia'], + }, +] diff --git a/studio/components/interfaces/Database/Backups/PITR/PITR.types.ts b/studio/components/interfaces/Database/Backups/PITR/PITR.types.ts new file mode 100644 index 00000000000..7b7d4955df9 --- /dev/null +++ b/studio/components/interfaces/Database/Backups/PITR/PITR.types.ts @@ -0,0 +1,14 @@ +export interface Timezone { + value: string + abbr: string + offset: number + isdst: boolean + text: string + utc: string[] +} + +export interface Time { + h: string + m: string + s: string +} diff --git a/studio/components/interfaces/Database/Backups/PITR/PITR.utils.ts b/studio/components/interfaces/Database/Backups/PITR/PITR.utils.ts new file mode 100644 index 00000000000..57477369ac8 --- /dev/null +++ b/studio/components/interfaces/Database/Backups/PITR/PITR.utils.ts @@ -0,0 +1,31 @@ +import dayjs from 'dayjs' +import { ALL_TIMEZONES } from './PITR.constants' +import { Timezone } from './PITR.types' + +export const getClientTimezone = () => { + const defaultTz = dayjs.tz.guess() + const timezone = ALL_TIMEZONES.find((option) => { + if (option.utc.includes(defaultTz)) return option + else return undefined + }) + return timezone ?? ALL_TIMEZONES[0] +} + +export const checkMatchingDates = (selectedDate: Date | undefined, targetDate: Date) => { + if (!selectedDate) return false + + const formattedSelectedDate = new Date(selectedDate.getTime()) + formattedSelectedDate.setHours(0, 0, 0, 0) + + const formattedTargetDate = new Date(targetDate.getTime()) + formattedTargetDate.setHours(0, 0, 0, 0) + + return Number(formattedSelectedDate) === Number(formattedTargetDate) +} + +export const formatNumberToTwoDigits = (number: Number) => { + return number.toLocaleString('en-US', { + minimumIntegerDigits: 2, + useGrouping: false, + }) +} diff --git a/studio/components/interfaces/Database/Backups/PITR/PITRNotice.tsx b/studio/components/interfaces/Database/Backups/PITR/PITRNotice.tsx new file mode 100644 index 00000000000..0cc70ce4940 --- /dev/null +++ b/studio/components/interfaces/Database/Backups/PITR/PITRNotice.tsx @@ -0,0 +1,35 @@ +import { Button, IconCalendar, IconClock } from '@supabase/ui' +import { FormPanel } from 'components/ui/Forms' + +const PITRNotice = ({}) => { + return ( + + + Recovery retention period can be increase by upgrading + + + + } + > +
+
+ +
+
+

Recovery retention period

+

+ Database changes are logged every 2 minutes, + with a total recovery period of up to 7 days. +

+
+
+
+ ) +} + +export default PITRNotice diff --git a/studio/components/interfaces/Database/Backups/PITR/PITRSelection.tsx b/studio/components/interfaces/Database/Backups/PITR/PITRSelection.tsx new file mode 100644 index 00000000000..60a8a97bdb6 --- /dev/null +++ b/studio/components/interfaces/Database/Backups/PITR/PITRSelection.tsx @@ -0,0 +1,326 @@ +import dayjs from 'dayjs' +import DatePicker from 'react-datepicker' +import { useState } from 'react' +import { format } from 'date-fns' +import { observer } from 'mobx-react-lite' +import { + Button, + Modal, + IconChevronLeft, + IconChevronRight, + IconHelpCircle, + IconDatabase, +} from '@supabase/ui' + +import { useStore } from 'hooks' + +import { Time } from './PITR.types' +import { getClientTimezone, checkMatchingDates, formatNumberToTwoDigits } from './PITR.utils' +import PITRStatus from './PITRStatus' +import TimeInput from './TimeInput' +import TimezoneSelection from './TimezoneSelection' +import { FormHeader, FormPanel } from 'components/ui/Forms' +import InformationBox from 'components/ui/InformationBox' + +// [Joshen TODO] Remaining todos: +// - Need to validate the selectedDate against earliest and latest here to disable the review restore details button +// - Refine messaging in confirmation modal +// - Actually hook up the BE API, please ensure that the unix timestamp getting sent is correct +// - Highlight available dates in the calendar and add a legend +// - Just need to check in thereafter with Jonny if the changes are okay +// - Deprecate old PITR components + +const PITRSelection = ({}) => { + const { backups } = useStore() + const { earliestPhysicalBackupDateUnix, latestPhysicalBackupDateUnix } = + backups?.configuration?.physicalBackupData ?? {} + + const [selectedDate, setSelectedDate] = useState() + const [selectedTimezone, setSelectedTimezone] = useState(getClientTimezone()) + const [showConfiguration, setShowConfiguration] = useState(false) + const [showConfirmation, setShowConfirmation] = useState(false) + + const formattedSelectedDate = dayjs.unix(Number(selectedDate) / 1000) + // Should only convert to timezone at when confirming + // const formattedSelectedDate = dayjs.unix(Number(selectedDate) / 1000).tz(selectedTimezone?.utc[0]) + + const earliestAvailableBackup = new Date(earliestPhysicalBackupDateUnix * 1000) + const earliestAvailableTiming = dayjs(earliestAvailableBackup).tz(selectedTimezone?.utc[0]) + + const latestAvailableBackup = new Date(latestPhysicalBackupDateUnix * 1000) + const latestAvailableTiming = dayjs(latestAvailableBackup).tz(selectedTimezone?.utc[0]) + + const isSelectedOnEarliest = checkMatchingDates(selectedDate, earliestAvailableBackup) + const isSelectedOnLatest = checkMatchingDates(selectedDate, latestAvailableBackup) + + const formattedSelectedTiming = + selectedDate !== undefined + ? { + h: formatNumberToTwoDigits(selectedDate.getHours()), + m: formatNumberToTwoDigits(selectedDate.getMinutes()), + s: formatNumberToTwoDigits(selectedDate.getSeconds()), + } + : undefined + + const formattedEarliestTiming = isSelectedOnEarliest + ? { + h: formatNumberToTwoDigits(earliestAvailableTiming.hour()), + m: formatNumberToTwoDigits(earliestAvailableTiming.minute()), + s: formatNumberToTwoDigits(earliestAvailableTiming.second()), + } + : undefined + + const formattedLatestTiming = isSelectedOnLatest + ? { + h: formatNumberToTwoDigits(latestAvailableTiming.hour()), + m: formatNumberToTwoDigits(latestAvailableTiming.minute()), + s: formatNumberToTwoDigits(latestAvailableTiming.second()), + } + : undefined + + const onCancel = () => { + setSelectedDate(undefined) + setSelectedTimezone(getClientTimezone()) + setShowConfiguration(false) + } + + const onUpdateDate = (date: Date) => { + const isSelectedOnEarliest = checkMatchingDates(date, earliestAvailableBackup) + const isSelectedOnLatest = checkMatchingDates(selectedDate, latestAvailableBackup) + + if (isSelectedOnEarliest) { + date.setHours( + earliestAvailableTiming.hour(), + earliestAvailableTiming.minute(), + earliestAvailableTiming.second(), + 0 + ) + } else if (isSelectedOnLatest) { + date.setHours( + latestAvailableTiming.hour(), + latestAvailableTiming.minute(), + latestAvailableTiming.second(), + 0 + ) + } else { + date.setHours(0, 0, 0, 0) + } + + setSelectedDate(date) + } + + const onUpdateTime = (time: Time) => { + if (!selectedDate) return + const updatedDate = new Date(Number(selectedDate)) + updatedDate.setHours(Number(time.h)) + updatedDate.setMinutes(Number(time.m)) + updatedDate.setSeconds(Number(time.s)) + setSelectedDate(updatedDate) + } + + return ( + <> + + {!showConfiguration ? ( + setShowConfiguration(true)} /> + ) : ( + + + + + } + > +
+
+ {/* Highlight the available dates better */} + 'cursor-pointer'} + minDate={earliestAvailableBackup} + maxDate={latestAvailableBackup} + // highlightDates={[new Date()]} + renderCustomHeader={({ + date, + decreaseMonth, + increaseMonth, + prevMonthButtonDisabled, + nextMonthButtonDisabled, + }) => ( +
+
+ + {format(date, 'MMMM yyyy')} + +
+
+ )} + /> +
+
+ {!selectedDate ? ( +
+
+ } + title="Select a date which you'd like to restore your database to" + /> +
+
+ ) : ( +
+
+

Restore database to

+

+ {formattedSelectedDate.format('DD MMM YYYY, HH:mm:ss')} +

+
+
+

Time of recovery

+
+ +
+ + + +
+ {isSelectedOnEarliest && ( +

+ Earliest available backup on this date is at{' '} + {earliestAvailableTiming.format('HH:mm:ss')} +

+ )} + {isSelectedOnLatest && ( +

+ Latest available backup on this date is at{' '} + {latestAvailableTiming.format('HH:mm:ss')} +

+ )} +
+
+
+ )} +
+
+
+ )} + setShowConfirmation(false)} + customFooter={ +
+ + +
+ } + > +
+ +

Point in time recovery review

+
+ + +
+

Your database will be restored to

+

{formattedSelectedDate.format('DD MMM YYYY, HH:mm:ss')}

+

{selectedTimezone?.text}

+
+
+ + +
+

+ Any changes made to your database up to this point of time will be lost. This + includes any changes involving storage and authentication. +

+

+ The restoration process will incur some downtime to your project and cannot be + undone. +

+ {/*
+
+ +
+
+

Potential loss of recent data

+

+ Any database changes being made currently could be lost. +

+
+
+
+
+
+

Potential loss of new users

+

+ Users that recently signed up to your project could be lost. +

+
+
+
+
+
+

Potential loss of storage files

+

+ Any files recently uploaded to your storage could be lost. +

+
+
*/} +
+ +
+ + + ) +} + +export default observer(PITRSelection) diff --git a/studio/components/interfaces/Database/Backups/PITR/PITRStatus.tsx b/studio/components/interfaces/Database/Backups/PITR/PITRStatus.tsx new file mode 100644 index 00000000000..593f062dd4b --- /dev/null +++ b/studio/components/interfaces/Database/Backups/PITR/PITRStatus.tsx @@ -0,0 +1,72 @@ +import dayjs from 'dayjs' +import { FC, useState } from 'react' +import { observer } from 'mobx-react-lite' +import { Button, IconAlertCircle } from '@supabase/ui' + +import { useStore } from 'hooks' +import { getClientTimezone } from './PITR.utils' +import { FormHeader, FormPanel } from 'components/ui/Forms' +import TimezoneSelection from './TimezoneSelection' + +interface Props { + onSetConfiguration: () => void +} + +const PITRStatus: FC = ({ onSetConfiguration }) => { + const { backups } = useStore() + const { earliestPhysicalBackupDateUnix, latestPhysicalBackupDateUnix } = + backups?.configuration?.physicalBackupData ?? {} + + const [selectedTimezone, setSelectedTimezone] = useState(getClientTimezone()) + + const earliestAvailableBackup = dayjs + .unix(earliestPhysicalBackupDateUnix) + .tz(selectedTimezone?.utc[0]) + .format('DD MMM YYYY, HH:mm:ss') + + const latestAvailableBackup = dayjs + .unix(latestPhysicalBackupDateUnix) + .tz(selectedTimezone?.utc[0]) + .format('DD MMM YYYY, HH:mm:ss') + + return ( + <> + +
+ + + You'll be able to pick the right date and time when you begin + +
+ +
+ } + > +
+
+ +
+
+
+

Database restore available from

+

{earliestAvailableBackup}

+
+
+

Latest restore available at

+

{latestAvailableBackup}

+
+
+
+ + + ) +} + +export default observer(PITRStatus) diff --git a/studio/components/interfaces/Database/Backups/PITR/TimeInput.tsx b/studio/components/interfaces/Database/Backups/PITR/TimeInput.tsx new file mode 100644 index 00000000000..236d4fbb354 --- /dev/null +++ b/studio/components/interfaces/Database/Backups/PITR/TimeInput.tsx @@ -0,0 +1,185 @@ +import dayjs from 'dayjs' +import { isNaN } from 'lodash' +import { ChangeEvent, FC, useEffect, useState } from 'react' +import * as Tooltip from '@radix-ui/react-tooltip' +import { IconClock } from '@supabase/ui' + +import { Time } from './PITR.types' +import { formatNumberToTwoDigits } from './PITR.utils' + +// [Joshen] This is trying to do the same thing as TimeSplitInput.tsx +// so can we please look to try to combine these 2 components together if possible +// The problem with TimeSplitInput is that it's tightly coupled to the date + its +// tightly coupled to the context of a range. Ideally it should be more modular +// which is what this component is trying to achieve + +// [Joshen] Potential extension, give option to toggle 24 hours or AM/PM + +interface Props { + defaultTime?: Time + minimumTime?: Time + maximumTime?: Time + onChange?: (time: Time) => void +} + +const TimeInput: FC = ({ defaultTime, minimumTime, maximumTime, onChange = () => {} }) => { + const [isFocused, setIsFocused] = useState(false) + const [error, setError] = useState() + const [time, setTime] = useState