From adf96c7bf0173b49ffa3bbe27d39b222ede78479 Mon Sep 17 00:00:00 2001 From: samrose Date: Thu, 22 Feb 2024 16:15:07 -0500 Subject: [PATCH 01/50] chore: add self to humans (#21437) --- apps/docs/public/humans.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/docs/public/humans.txt b/apps/docs/public/humans.txt index 43f41400d89..3de2edb9edc 100644 --- a/apps/docs/public/humans.txt +++ b/apps/docs/public/humans.txt @@ -55,6 +55,7 @@ Qiao Han Raminder Singh Rodrigo Mansueli Rory Wilding +Sam Rose Sreyas Udayavarman Stanislav M Steve Chavez From 698ec3243346f36cb1dc81d6472889ea473cae75 Mon Sep 17 00:00:00 2001 From: Wen Bo Xie <5532241+w3b6x9@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:58:09 -0800 Subject: [PATCH 02/50] chore: add Karan S to humans.txt (#21467) --- apps/docs/public/humans.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/docs/public/humans.txt b/apps/docs/public/humans.txt index 3de2edb9edc..fba74a36703 100644 --- a/apps/docs/public/humans.txt +++ b/apps/docs/public/humans.txt @@ -35,6 +35,7 @@ Jordi Enric Joshen Lim Kamil Ogórek Kang Ming Tay +Karan S Karlo Ison Kevin Brolly Kevin Grüneberg From d1ab275beacd83e4a5bdec46a4aca0a0b0425315 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Fri, 23 Feb 2024 18:08:06 +0800 Subject: [PATCH 03/50] Chore/read replica final touches (#21420) * Add validation for max replicas check * Small UI fixes * Add useMemo for edges * Fix nodes not shwoing up when switching between map and flow view * Fix logs explorer copy button * Add edge changes to useEffect * Bump wait duration when creating replica * Sync database selector and use pooler checkbox states across panels on settings database * Fix InstanceConfiguration not showing any nodes * Sort databases in DatabaseSelector to have primary first * Logs explorer border fotter * Add database selector for edge logs * Make buttons more concise in logs * Clean up * Fix * Fix home page empty empty state * Attempt to support pooler logs * minor qol fix for database selector * Update shared-data pgbouncer to supavisor * small fix --- .../components/interfaces/HomePageActions.tsx | 2 +- .../DatabaseConnectionString.tsx | 42 ++--- .../DatabaseSettings/DatabaseSettings.tsx | 13 +- .../DeployNewReplicaPanel.tsx | 28 ++- .../DropReplicaConfirmationModal.tsx | 11 +- .../InstanceConfiguration.tsx | 92 +++++----- .../interfaces/Settings/Logs/LogTable.tsx | 29 +-- .../interfaces/Settings/Logs/Logs.utils.ts | 27 ++- .../Settings/Logs/LogsFormatters.tsx | 14 +- .../Settings/Logs/LogsPreviewer.tsx | 56 ++++-- .../Settings/Logs/PreviewFilterPanel.tsx | 172 +++++++++++------- .../layouts/SQLEditorLayout/SQLEditorMenu.tsx | 2 +- apps/studio/components/ui/CSVButton.tsx | 41 +++-- .../studio/components/ui/DatabaseSelector.tsx | 36 ++-- .../components/ui/Logs/LogsExplorerHeader.tsx | 7 +- .../read-replicas/replica-remove-mutation.ts | 2 +- .../read-replicas/replica-setup-mutation.ts | 3 +- .../pages/project/[ref]/logs/edge-logs.tsx | 1 + apps/studio/pages/projects.tsx | 2 +- apps/studio/state/database-settings.tsx | 4 + packages/shared-data/logConstants.ts | 4 +- 21 files changed, 356 insertions(+), 232 deletions(-) diff --git a/apps/studio/components/interfaces/HomePageActions.tsx b/apps/studio/components/interfaces/HomePageActions.tsx index 613181ec8d7..dae381e1fcc 100644 --- a/apps/studio/components/interfaces/HomePageActions.tsx +++ b/apps/studio/components/interfaces/HomePageActions.tsx @@ -54,7 +54,7 @@ const HomePageActions = ({ - {IS_PLATFORM && organizationCreationEnabled && orgsLoaded && organizations.length !== 0 && ( + {IS_PLATFORM && organizationCreationEnabled && orgsLoaded && ( + } + loading={isLoading} + disabled={isLoading} + onClick={onRefresh} + /> + + + Refresh logs + + ) + const handleDatepickerChange = ({ to, from }: Partial[1]>) => { onSearch('datepicker-change', { to, from }) } + const handleInputSearch = (query: string) => onSearch('search-input-change', { query }) return (
-
+
+ + -
- -
+ {FILTER_OPTIONS[table] !== undefined && ( +
+ {FILTER_OPTIONS[table] && + Object.values(FILTER_OPTIONS[table]).map((x, i: number) => { + const classes = [] -
- {FILTER_OPTIONS[table] && - Object.values(FILTER_OPTIONS[table]).map((x, i: number) => { - const classes = [] - - if (Object.values(FILTER_OPTIONS[table]).length >= 2) { - if (i === 0) { - classes.push('rounded-tr-none rounded-br-none') - } else if (i === Object.values(FILTER_OPTIONS[table]).length - 1) { - classes.push('rounded-tl-none rounded-bl-none') - } else { - classes.push('rounded-none') + if (Object.values(FILTER_OPTIONS[table]).length >= 2) { + if (i === 0) { + classes.push('rounded-tr-none rounded-br-none') + } else if (i === Object.values(FILTER_OPTIONS[table]).length - 1) { + classes.push('rounded-tl-none rounded-bl-none') + } else { + classes.push('rounded-none') + } } - } - return ( - - ) - })} -
+ return ( + + ) + })} +
+ )}
- + {showDatabaseSelector ? ( +
+ + + + + + Open query in Logs Explorer + + + +
+ ) : ( + + )}
) } diff --git a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorMenu.tsx b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorMenu.tsx index 2be0ab6e683..4ceef5b5b4f 100644 --- a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorMenu.tsx +++ b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorMenu.tsx @@ -314,7 +314,7 @@ const SideBarContent = observer(() => { onClick={() => setSelectedQueries([])} /> - + Clear selection diff --git a/apps/studio/components/ui/CSVButton.tsx b/apps/studio/components/ui/CSVButton.tsx index 3289641afe0..36db8de8ea2 100644 --- a/apps/studio/components/ui/CSVButton.tsx +++ b/apps/studio/components/ui/CSVButton.tsx @@ -1,8 +1,13 @@ -import { Button, IconDownloadCloud } from 'ui' -import { ButtonProps } from 'ui/src/components/Button/Button' -import { flattenDeep } from 'lodash' import React, { PropsWithChildren, useMemo, useRef } from 'react' import { CSVLink } from 'react-csv' +import { + Button, + IconDownload, + TooltipContent_Shadcn_, + TooltipTrigger_Shadcn_, + Tooltip_Shadcn_, +} from 'ui' +import { ButtonProps } from 'ui/src/components/Button/Button' interface CSVButtonProps { buttonType?: ButtonProps['type'] @@ -52,17 +57,25 @@ const CSVButton = ({ filename={`supabase_logs.csv`} title={title} /> - + + + + + + Download logs as CSV + + ) } diff --git a/apps/studio/components/ui/DatabaseSelector.tsx b/apps/studio/components/ui/DatabaseSelector.tsx index 6fe27c61c8e..ab43c7fa5ba 100644 --- a/apps/studio/components/ui/DatabaseSelector.tsx +++ b/apps/studio/components/ui/DatabaseSelector.tsx @@ -1,7 +1,8 @@ +import { useParams } from 'common' +import { noop } from 'lodash' import Link from 'next/link' import { useRouter } from 'next/router' import { useState } from 'react' -import { useParams } from 'common' import { Button, CommandGroup_Shadcn_, @@ -10,6 +11,7 @@ import { Command_Shadcn_, IconCheck, IconChevronDown, + IconLoader, IconPlus, PopoverContent_Shadcn_, PopoverTrigger_Shadcn_, @@ -25,25 +27,26 @@ import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' interface DatabaseSelectorProps { variant?: 'regular' | 'connected-on-right' | 'connected-on-left' | 'connected-on-both' additionalOptions?: { id: string; name: string }[] - selectedId?: string // Optional to let parent component control its state (e.g Database Settings page) - setSelectedId?: (value: string) => void + onSelectId?: (id: string) => void // Optional callback } const DatabaseSelector = ({ variant = 'regular', additionalOptions = [], - selectedId, - setSelectedId, + onSelectId = noop, }: DatabaseSelectorProps) => { const router = useRouter() const { ref: projectRef } = useParams() const [open, setOpen] = useState(false) const state = useDatabaseSelectorStateSnapshot() - const selectedDatabaseId = selectedId || state.selectedDatabaseId + const selectedDatabaseId = state.selectedDatabaseId - const { data } = useReadReplicasQuery({ projectRef }) + const { data, isLoading, isSuccess } = useReadReplicasQuery({ projectRef }) const databases = data ?? [] + const sortedDatabases = databases + .sort((a, b) => (a.inserted_at > b.inserted_at ? 1 : 0)) + .sort((database) => (database.identifier === projectRef ? -1 : 0)) const selectedDatabase = databases.find((db) => db.identifier === selectedDatabaseId) const selectedDatabaseRegion = formatDatabaseRegion(selectedDatabase?.region ?? '') @@ -63,6 +66,7 @@ const DatabaseSelector = ({ variant === 'connected-on-left' && 'rounded-l-none border-l-0', variant === 'connected-on-both' && 'rounded-none border-x-0' )} + icon={isLoading && } iconRight={ } @@ -73,11 +77,11 @@ const DatabaseSelector = ({ ) : ( <> - {selectedDatabase?.identifier === projectRef + {isLoading || selectedDatabase?.identifier === projectRef ? 'Primary database' : 'Read replica'} {' '} - {selectedDatabase?.identifier !== projectRef && ( + {isSuccess && selectedDatabase?.identifier !== projectRef && ( ({selectedDatabaseRegion} - {formattedDatabaseId}) @@ -116,7 +120,7 @@ const DatabaseSelector = ({ )} 7 ? 'h-[210px]' : ''}> - {databases?.map((database) => { + {sortedDatabases?.map((database) => { const region = formatDatabaseRegion(database.region) const id = formatDatabaseID(database.identifier) @@ -126,14 +130,14 @@ const DatabaseSelector = ({ value={database.identifier} className="cursor-pointer w-full" onSelect={() => { - if (setSelectedId) setSelectedId(database.identifier) - else state.setSelectedDatabaseId(database.identifier) + state.setSelectedDatabaseId(database.identifier) setOpen(false) + onSelectId(database.identifier) }} onClick={() => { - if (setSelectedId) setSelectedId(database.identifier) - else state.setSelectedDatabaseId(database.identifier) + state.setSelectedDatabaseId(database.identifier) setOpen(false) + onSelectId(database.identifier) }} >
@@ -160,9 +164,7 @@ const DatabaseSelector = ({ > { - setOpen(false) - }} + onClick={() => setOpen(false)} className="w-full flex items-center gap-2" > diff --git a/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx b/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx index 2202d62f3cc..e2ae887e49b 100644 --- a/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx +++ b/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx @@ -1,7 +1,4 @@ import * as Tooltip from '@radix-ui/react-tooltip' -import { LOGS_EXPLORER_DOCS_URL } from 'components/interfaces/Settings/Logs' -import Table from 'components/to-be-cleaned/Table' -import { copyToClipboard } from 'lib/helpers' import Link from 'next/link' import { useState } from 'react' import { logConstants } from 'shared-data' @@ -17,6 +14,10 @@ import { Tabs, } from 'ui' +import { LOGS_EXPLORER_DOCS_URL } from 'components/interfaces/Settings/Logs' +import Table from 'components/to-be-cleaned/Table' +import { copyToClipboard } from 'lib/helpers' + export interface LogsExplorerHeaderProps { subtitle?: string } diff --git a/apps/studio/data/read-replicas/replica-remove-mutation.ts b/apps/studio/data/read-replicas/replica-remove-mutation.ts index 4c8d016d98d..be4f655bfa7 100644 --- a/apps/studio/data/read-replicas/replica-remove-mutation.ts +++ b/apps/studio/data/read-replicas/replica-remove-mutation.ts @@ -20,7 +20,6 @@ export async function removeReadReplica({ projectRef, identifier }: ReadReplicaR database_identifier: identifier, }, }) - if (error) throw error return data } @@ -49,6 +48,7 @@ export const useReadReplicaRemoveMutation = ({ setTimeout(async () => { await queryClient.invalidateQueries(replicaKeys.list(projectRef)) + await queryClient.invalidateQueries(replicaKeys.loadBalancers(projectRef)) }, 5000) await onSuccess?.(data, variables, context) diff --git a/apps/studio/data/read-replicas/replica-setup-mutation.ts b/apps/studio/data/read-replicas/replica-setup-mutation.ts index 157ffd06023..44f44e32e4e 100644 --- a/apps/studio/data/read-replicas/replica-setup-mutation.ts +++ b/apps/studio/data/read-replicas/replica-setup-mutation.ts @@ -77,9 +77,10 @@ export const useReadReplicaSetUpMutation = ({ return [...old, scaffoldNewDatabase] }) + // [Joshen] Wait 30 seconds before checking if the replica actually is coming up setTimeout(async () => { await queryClient.invalidateQueries(replicaKeys.list(projectRef)) - }, 5000) + }, 30000) await onSuccess?.(data, variables, context) }, diff --git a/apps/studio/pages/project/[ref]/logs/edge-logs.tsx b/apps/studio/pages/project/[ref]/logs/edge-logs.tsx index 9c8b817e535..f414db60935 100644 --- a/apps/studio/pages/project/[ref]/logs/edge-logs.tsx +++ b/apps/studio/pages/project/[ref]/logs/edge-logs.tsx @@ -4,6 +4,7 @@ import { observer } from 'mobx-react-lite' import { LogsLayout } from 'components/layouts' import LogsPreviewer from 'components/interfaces/Settings/Logs/LogsPreviewer' import { NextPageWithLayout } from 'types' +import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' export const LogPage: NextPageWithLayout = () => { const router = useRouter() diff --git a/apps/studio/pages/projects.tsx b/apps/studio/pages/projects.tsx index 3c45b41afb7..cf8bda6dba0 100644 --- a/apps/studio/pages/projects.tsx +++ b/apps/studio/pages/projects.tsx @@ -53,7 +53,7 @@ const ProjectsPage: NextPageWithLayout = () => { )} {!navLayoutV2 && (
- {IS_PLATFORM && projectCreationEnabled && isSuccess && organizations.length !== 0 && ( + {IS_PLATFORM && projectCreationEnabled && isSuccess && ( )}
diff --git a/apps/studio/state/database-settings.tsx b/apps/studio/state/database-settings.tsx index 93ce2c7723d..afd626df6bc 100644 --- a/apps/studio/state/database-settings.tsx +++ b/apps/studio/state/database-settings.tsx @@ -5,6 +5,10 @@ import { useConstant } from 'common' export function createDatabaseSettingsState() { const state = proxy({ + usePoolerConnection: true, + setUsePoolerConnection: (value: boolean) => { + state.usePoolerConnection = value + }, showPoolingModeHelper: false, setShowPoolingModeHelper: (value: boolean) => { state.showPoolingModeHelper = value diff --git a/packages/shared-data/logConstants.ts b/packages/shared-data/logConstants.ts index d828202f53a..379c706b4d0 100644 --- a/packages/shared-data/logConstants.ts +++ b/packages/shared-data/logConstants.ts @@ -225,8 +225,8 @@ const schemas = [ ], }, { - name: 'PgBouncer', - reference: 'pgbouncer_logs', + name: 'Supavisor', + reference: 'supavisor_logs', fields: [ { path: 'event_message', type: 'string' }, { path: 'id', type: 'string' }, From bc8e4374a755eb4207fa86a9cbf0494a5730055b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Gr=C3=BCneberg?= Date: Fri, 23 Feb 2024 19:32:55 +0800 Subject: [PATCH 04/50] fix: dev vulnerabilities (#21474) --- apps/docs/package.json | 2 +- apps/studio/package.json | 2 +- package-lock.json | 30 ++++++++++++++++-------------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index b9132607c5d..b2a5e9a083d 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -90,7 +90,7 @@ "jest-environment-jsdom": "^29.7.0", "npm-run-all": "^4.1.5", "openapi-types": "^12.0.2", - "openapi-typescript": "^6.7.2", + "openapi-typescript": "^6.7.4", "tsconfig": "*", "tsx": "^4.6.2", "typescript": "^5.2.2" diff --git a/apps/studio/package.json b/apps/studio/package.json index 63b09ae3bba..ac8145c8553 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -145,7 +145,7 @@ "jest-canvas-mock": "^2.5.2", "jest-environment-jsdom": "^29.7.0", "openapi-types": "^12.1.3", - "openapi-typescript": "^6.7.1", + "openapi-typescript": "^6.7.4", "postcss": "^8.4.31", "prettier": "^4.0.0-alpha.8", "storybook-dark-mode": "^3.0.1", diff --git a/package-lock.json b/package-lock.json index 7e909769c28..127b9226f16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -540,7 +540,7 @@ "jest-environment-jsdom": "^29.7.0", "npm-run-all": "^4.1.5", "openapi-types": "^12.0.2", - "openapi-typescript": "^6.7.2", + "openapi-typescript": "^6.7.4", "tsconfig": "*", "tsx": "^4.6.2", "typescript": "^5.2.2" @@ -894,7 +894,7 @@ "jest-canvas-mock": "^2.5.2", "jest-environment-jsdom": "^29.7.0", "openapi-types": "^12.1.3", - "openapi-typescript": "^6.7.1", + "openapi-typescript": "^6.7.4", "postcss": "^8.4.31", "prettier": "^4.0.0-alpha.8", "storybook-dark-mode": "^3.0.1", @@ -18651,8 +18651,9 @@ } }, "node_modules/fast-glob": { - "version": "3.3.1", - "license": "MIT", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -20940,8 +20941,9 @@ "dev": true }, "node_modules/ip": { - "version": "2.0.0", - "license": "MIT" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" }, "node_modules/ip-num": { "version": "1.5.1", @@ -28082,16 +28084,16 @@ "license": "MIT" }, "node_modules/openapi-typescript": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-6.7.2.tgz", - "integrity": "sha512-7rsUArlMBqmSaRd6EzPl2nGKzPFNRicsRGrxf6W+/HLEDZoOxghR3B53YlyGjcqak8YDZMBNzZQ3o93Bp3qY9Q==", + "version": "6.7.4", + "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-6.7.4.tgz", + "integrity": "sha512-EZyeW9Wy7UDCKv0iYmKrq2pVZtquXiD/YHiUClAKqiMi42nodx/EQH11K6fLqjt1IZlJmVokrAsExsBMM2RROQ==", "dev": true, "dependencies": { "ansi-colors": "^4.1.3", - "fast-glob": "^3.3.1", + "fast-glob": "^3.3.2", "js-yaml": "^4.1.0", "supports-color": "^9.4.0", - "undici": "^5.27.2", + "undici": "^5.28.2", "yargs-parser": "^21.1.1" }, "bin": { @@ -35333,9 +35335,9 @@ } }, "node_modules/undici": { - "version": "5.28.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.1.tgz", - "integrity": "sha512-xcIIvj1LOQH9zAL54iWFkuDEaIVEjLrru7qRpa3GrEEHk6OBhb/LycuUY2m7VCcTuDeLziXCxobQVyKExyGeIA==", + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" From 9e3221d1066ac02c7ffa8ccffe85480165d0edbb Mon Sep 17 00:00:00 2001 From: Div Arora Date: Fri, 23 Feb 2024 20:37:56 +0800 Subject: [PATCH 05/50] wip chore: flesh out RR docs a little (#21480) --- .../content/guides/platform/read-replicas.mdx | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/docs/content/guides/platform/read-replicas.mdx b/apps/docs/content/guides/platform/read-replicas.mdx index d8ef2b741a5..29f048a7a1b 100644 --- a/apps/docs/content/guides/platform/read-replicas.mdx +++ b/apps/docs/content/guides/platform/read-replicas.mdx @@ -135,16 +135,22 @@ All settings made through the dashboard will be propagated across all databases A project needs to satisfy these requirements to spin up a read replica: 1. Running on AWS. - - Support for projects on Fly is in progress. -2. Running on at least a small compute. -3. PostgreSQL 15. - - For projects running on older versions of PostgreSQL, you can initiate self-serve upgrades with pg_upgrade. For details, see the [upgrade guide](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade). + - Support for projects on Fly.io will be added at a later date. +1. Running on at least a [Small compute add-on](/docs/guides/platform/compute-add-ons). +1. Using [physical backups](/docs/guides/platform/backups#point-in-time-recovery) + - Physical backups are automatically enabled if using [PITR](/docs/guides/platform/backups#point-in-time-recovery) +1. Running on Postgres 15. + - For projects running on older versions of PostgreSQL, you will need to [upgrade to the latest platform version](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade). ### Read replicas need to be brought down before starting the following procedures The following procedures require all read replicas for a project to be brought down before they can be started: -1. Upgrading a project via pg_upgrade. -2. Performing data restoration. +1. [Upgrading a project](/docs/guides/platform/migrating-and-upgrading-projects#pgupgrade) +1. Performing [data restoration](/docs/guides/platform/backups#pitr-restoration-process). -Changes made to the primary database during these operations heavily disrupt replication and potentially leave active read replicas in unstable states. Once these operations complete, read replicas can be spun back up. +Once these operations complete, read replicas can be spun back up. + +### Compute Add-ons + +In order to avoid replicas being unable to keep up with activity on the primaries they're following, Read Replicas are currently placed on the same Compute Add-on as the primary they're following. From b510595abf5dc79d33aa21c7090c4999a2904822 Mon Sep 17 00:00:00 2001 From: hallidayo <22655069+Hallidayo@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:32:20 +0000 Subject: [PATCH 06/50] feat: connect - expo react native (#21350) * add react native expo for connect * Update apps/studio/components/interfaces/Home/Connect/content/exporeactnative/supabasejs/content.tsx --------- Co-authored-by: Terry Sutton --- .../Home/Connect/Connect.constants.ts | 14 +++ .../exporeactnative/supabasejs/content.tsx | 99 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 apps/studio/components/interfaces/Home/Connect/content/exporeactnative/supabasejs/content.tsx diff --git a/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts b/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts index edfb80c697c..7293d31270b 100644 --- a/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts +++ b/apps/studio/components/interfaces/Home/Connect/Connect.constants.ts @@ -155,6 +155,20 @@ export const FRAMEWORKS: ConnectionType[] = [ }, ], }, + { + key: 'exporeactnative', + label: 'Expo React Native', + icon: 'expo', + guideLink: 'https://supabase.com/docs/guides/getting-started/tutorials/with-expo-react-native', + children: [ + { + key: 'supabasejs', + label: 'Supabase-js', + children: [], + icon: 'supabase', + }, + ], + }, ] export const ORMS: ConnectionType[] = [ diff --git a/apps/studio/components/interfaces/Home/Connect/content/exporeactnative/supabasejs/content.tsx b/apps/studio/components/interfaces/Home/Connect/content/exporeactnative/supabasejs/content.tsx new file mode 100644 index 00000000000..56e535f80c3 --- /dev/null +++ b/apps/studio/components/interfaces/Home/Connect/content/exporeactnative/supabasejs/content.tsx @@ -0,0 +1,99 @@ +import { ContentFileProps } from 'components/interfaces/Home/Connect/Connect.types' + +import { + ConnectTabs, + ConnectTabTrigger, + ConnectTabTriggers, + ConnectTabContent, +} from 'components/interfaces/Home/Connect/ConnectTabs' +import SimpleCodeBlock from 'components/to-be-cleaned/SimpleCodeBlock' + +const ContentFile = ({ projectKeys }: ContentFileProps) => { + return ( + + + + + + + + + + {` +SUPABASE_URL=${projectKeys.apiUrl ?? 'your-project-url'} +SUPABASE_ANON_KEY=${projectKeys.anonKey ?? 'your-anon-key'} + `} + + + + + + {` +import 'react-native-url-polyfill/auto' +import AsyncStorage from '@react-native-async-storage/async-storage' +import { createClient } from '@supabase/supabase-js' +import { SUPABASE_URL, SUPABASE_ANON_KEY } from "@env"; + +export const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, { + auth: { + storage: AsyncStorage, + autoRefreshToken: true, + persistSession: true, + detectSessionInUrl: false, + }, +}) + `} + + + + + + {` +import React, { useState, useEffect } from 'react'; +import { View, Text, FlatList } from 'react-native'; +import { supabase } from '../utils/supabase'; + +export default function App() { + const [todos, setTodos] = useState([]); + + useEffect(() => { + const getTodos = async () => { + try { + const { data: todos, error } = await supabase.from('todos').select(); + + if (error) { + console.error('Error fetching todos:', error.message); + return; + } + + if (todos && todos.length > 0) { + setTodos(todos); + } + } catch (error) { + console.error('Error fetching todos:', error.message); + } + }; + + getTodos(); + }, []); + + return ( + + Todo List + item.id.toString()} + renderItem={({ item }) => {item.title}} + /> + + ); +}; + +`} + + + + ) +} + +export default ContentFile From 13ea35f63162ad5ac901e77fa458aa0669abb93c Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Fri, 23 Feb 2024 21:50:46 +0800 Subject: [PATCH 07/50] a11y updates on table editor entity items (#21482) a11y updates on entity items. fixed bg-selection issue --- .../TableEditorLayout/EntityListItem.tsx | 278 ++++++++---------- 1 file changed, 130 insertions(+), 148 deletions(-) diff --git a/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx b/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx index 60eef71bc66..054a596a557 100644 --- a/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx +++ b/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx @@ -118,161 +118,143 @@ const EntityListItem: ItemRenderer = ({ } return ( -
- - - - {entity.type === ENTITY_TYPE.TABLE ? ( - - ) : entity.type === ENTITY_TYPE.VIEW ? ( - - ) : ( -
- {Object.entries(ENTITY_TYPE) - .find(([, value]) => value === entity.type)?.[0]?.[0] - ?.toUpperCase()} -
- )} -
- - - - {formatTooltipText(entity.type)} - - -
-
- {/* only show tooltips if required, to reduce noise */} - {entity.name.length > 20 ? ( - - - {entity.name} - - - - - {entity.name} - - - + + + {entity.type === ENTITY_TYPE.TABLE ? ( + + ) : entity.type === ENTITY_TYPE.VIEW ? ( + ) : ( - entity.name - )} - - {entity.type === ENTITY_TYPE.TABLE && !entity.rls_enabled && ( -
- +
+ {Object.entries(ENTITY_TYPE) + .find(([, value]) => value === entity.type)?.[0]?.[0] + ?.toUpperCase()}
)} -
- -
- {entity.type === ENTITY_TYPE.TABLE && isActive && !isLocked && ( - - -
- -
-
- - { - e.stopPropagation() - snap.onEditTable() - }} - > - - Edit Table - - { - e.stopPropagation() - snap.onDuplicateTable() - }} - > - - Duplicate Table - - - - - View Policies - - - { - e.stopPropagation() - exportTableAsCSV() - }} - > - - Export as CSV - - - { - e.stopPropagation() - snap.onDeleteTable() - }} - > - - Delete Table - - -
+ + + + + {formatTooltipText(entity.type)} + + + +
+ {/* only show tooltips if required, to reduce noise */} + + {entity.name} + + + {entity.type === ENTITY_TYPE.TABLE && !entity.rls_enabled && ( + )}
-
+ + {entity.type === ENTITY_TYPE.TABLE && isActive && !isLocked && ( + + + + + + { + e.stopPropagation() + snap.onEditTable() + }} + > + + Edit Table + + { + e.stopPropagation() + snap.onDuplicateTable() + }} + > + + Duplicate Table + + + + + View Policies + + + { + e.stopPropagation() + exportTableAsCSV() + }} + > + + Export as CSV + + + { + e.stopPropagation() + snap.onDeleteTable() + }} + > + + Delete Table + + + + )} + ) } From 79c291f31d34d4fb809a729d12e93ce5da32165f Mon Sep 17 00:00:00 2001 From: Dane Miller Date: Fri, 23 Feb 2024 08:53:29 -0500 Subject: [PATCH 08/50] fix: dark mode icon for remix icon on the connector dropdown (#21397) fix: fix dark mode icon for remix icon on the connector dropdown --- .../components/interfaces/Home/Connect/ConnectionIcon.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/studio/components/interfaces/Home/Connect/ConnectionIcon.tsx b/apps/studio/components/interfaces/Home/Connect/ConnectionIcon.tsx index 06fea207496..4f13bec8806 100644 --- a/apps/studio/components/interfaces/Home/Connect/ConnectionIcon.tsx +++ b/apps/studio/components/interfaces/Home/Connect/ConnectionIcon.tsx @@ -13,7 +13,7 @@ const ConnectionIcon = ({ connection }: ConnectionIconProps) => { Date: Fri, 23 Feb 2024 21:53:46 +0800 Subject: [PATCH 09/50] fix: update brand colors in SQL editor AI (#21483) * update brand colors * Update SQLEditor.tsx * Update SQLEditor.tsx * Update SQLEditor.tsx --- .../components/interfaces/SQLEditor/SQLEditor.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx index 1d1f53413ab..d8a4d621257 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx +++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx @@ -600,7 +600,7 @@ const SQLEditor = () => { }} initial={isFirstRender ? 'visible' : 'hidden'} animate="visible" - className="w-full flex justify-center z-10 h-[60px] bg-brand-300 border-b border-brand-400 px-5" + className="w-full flex justify-center z-10 h-[60px] bg-brand-200 border-b border-brand-400 px-5" >
{ exit="hidden" > { type="alternative" size="tiny" icon={} - iconRight={ESC} + iconRight={ESC} onClick={discardAiHandler} > Discard @@ -838,8 +838,8 @@ const SQLEditor = () => { <>
@@ -854,7 +854,7 @@ const SQLEditor = () => { +
+ +
+ + {mobileMenuOpen + ? 'Close' + : menuLevel + ? levelsData[menuLevel].name + : levelsData['home'].name} + +
+ ) +}) + +const MobileMenuBackdrop = memo(function MobileMenuBackdrop() { + const mobileMenuOpen = useMenuMobileOpen() + + useEffect(() => { + window.addEventListener('resize', (e: UIEvent) => { + const w = e.target as Window + if (mobileMenuOpen && w.innerWidth >= 1024) { + menuState.setMenuMobileOpen(!mobileMenuOpen) + } + }) + return () => { + window.removeEventListener('resize', () => {}) + } + }, [mobileMenuOpen]) + + return ( +
menuState.setMenuMobileOpen(!mobileMenuOpen)} + >
+ ) +}) + +const HeaderLogo = memo(function HeaderLogo() { + const { resolvedTheme } = useTheme() + return ( + + Supabase Logo + DOCS + + ) +}) + +const Container = memo(function Container(props: PropsWithChildren) { + const mobileMenuOpen = useMenuMobileOpen() + + return ( +
+
{props.children}
+
+ ) +}) + +const NavContainer = memo(function NavContainer({ menuId }: { menuId: MenuId }) { + const mobileMenuOpen = useMenuMobileOpen() + + return ( + + ) +}) + +function MainSkeleton({ children, menuId }: PropsWithChildren<{ menuId: MenuId }>) { + return ( +
+ + +
+ +
+
+
+ +
+
+
+ {children} +
+
+ +
+
+ ) +} + +export { MainSkeleton } diff --git a/apps/docs/layouts/SiteLayout.tsx b/apps/docs/layouts/SiteLayout.tsx index ed1447aa80c..5754ddff924 100644 --- a/apps/docs/layouts/SiteLayout.tsx +++ b/apps/docs/layouts/SiteLayout.tsx @@ -1,349 +1,5 @@ -import { useTheme } from 'next-themes' -import Image from 'next/legacy/image' -import Link from 'next/link' -import NavigationMenu from '~/components/Navigation/NavigationMenu/NavigationMenu' -import TopNavBar from '~/components/Navigation/NavigationMenu/TopNavBar' - import Head from 'next/head' -import { PropsWithChildren, memo, useEffect } from 'react' -import Footer from '~/components/Navigation/Footer' -import { menuState, useMenuLevelId, useMenuMobileOpen } from '~/hooks/useMenuState' - -const levelsData = { - home: { - icon: '/docs/img/icons/menu/home', - name: 'Home', - }, - gettingstarted: { - icon: '/docs/img/icons/menu/getting-started', - name: 'Getting Started', - }, - database: { - icon: '/docs/img/icons/menu/database', - name: 'Database', - }, - api: { - icon: '/docs/img/icons/menu/rest', - name: 'REST API', - }, - graphql: { - icon: '/docs/img/icons/menu/graphql', - name: 'GraphQL', - }, - auth: { - icon: '/docs/img/icons/menu/auth', - name: 'Auth', - }, - functions: { - icon: '/docs/img/icons/menu/functions', - name: 'Edge Functions', - }, - realtime: { - icon: '/docs/img/icons/menu/realtime', - name: 'Realtime', - }, - analytics: { - icon: '/docs/img/icons/menu/analytics', - name: 'Analytics', - }, - storage: { - icon: '/docs/img/icons/menu/storage', - name: 'Storage', - }, - ai: { - icon: '/docs/img/icons/menu/ai', - name: 'AI & Vectors', - }, - supabase_cli: { - icon: '/docs/img/icons/menu/reference-cli', - name: 'Supabase CLI', - }, - platform: { - icon: '/docs/img/icons/menu/platform', - name: 'Platform', - }, - resources: { - icon: '/docs/img/icons/menu/resources', - name: 'Resources', - }, - self_hosting: { - icon: '/docs/img/icons/menu/self-hosting', - name: 'Self-Hosting', - }, - integrations: { - icon: '/docs/img/icons/menu/integrations', - name: 'Integrations', - }, - reference_javascript_v1: { - icon: '/docs/img/icons/menu/reference-javascript', - name: 'Javascript Reference v1.0', - }, - reference_javascript_v2: { - icon: '/docs/img/icons/menu/reference-javascript', - name: 'Javascript Reference v2.0', - }, - reference_dart_v1: { - icon: '/docs/img/icons/menu/reference-dart', - name: 'Dart Reference v1.0', - }, - reference_dart_v2: { - icon: '/docs/img/icons/menu/reference-dart', - name: 'Dart Reference v2.0', - }, - reference_csharp_v0: { - icon: '/docs/img/icons/menu/reference-csharp', - name: 'C# Reference v0.0', - }, - reference_python_v2: { - icon: '/docs/img/icons/menu/reference-python', - name: 'Python Reference v2.0', - }, - reference_swift_v1: { - icon: '/docs/img/icons/menu/reference-swift', - name: 'Swift Reference v1.0', - }, - reference_swift_v2: { - icon: '/docs/img/icons/menu/reference-swift', - name: 'Swift Reference v2.0', - }, - reference_kotlin_v1: { - icon: '/docs/img/icons/menu/reference-kotlin', - name: 'Kotlin Reference v1.0', - }, - reference_kotlin_v2: { - icon: '/docs/img/icons/menu/reference-kotlin', - name: 'Kotlin Reference v2.0', - }, - reference_cli: { - icon: '/docs/img/icons/menu/reference-cli', - name: 'CLI Reference', - }, - reference_api: { - icon: '/docs/img/icons/menu/reference-api', - name: 'Management API Reference', - }, - reference_self_hosting_auth: { - icon: '/docs/img/icons/menu/reference-auth', - name: 'Auth Server Reference', - }, - reference_self_hosting_storage: { - icon: '/docs/img/icons/menu/reference-storage', - name: 'Storage Server Reference', - }, - reference_self_hosting_realtime: { - icon: '/docs/img/icons/menu/reference-realtime', - name: 'Realtime Server Reference', - }, - reference_self_hosting_analytics: { - icon: '/docs/img/icons/menu/reference-analytics', - name: 'Analytics Server Reference', - }, - reference_self_hosting_functions: { - icon: '/docs/img/icons/menu/reference-functions', - name: 'Functions Server Reference', - }, -} - -const MobileHeader = memo(function MobileHeader() { - const mobileMenuOpen = useMenuMobileOpen() - const menuLevel = useMenuLevelId() - - return ( -
- -
- -
- - {mobileMenuOpen - ? 'Close' - : menuLevel - ? levelsData[menuLevel].name - : levelsData['home'].name} - -
- ) -}) - -const MobileMenuBackdrop = memo(function MobileMenuBackdrop() { - const mobileMenuOpen = useMenuMobileOpen() - - useEffect(() => { - window.addEventListener('resize', (e: UIEvent) => { - const w = e.target as Window - if (mobileMenuOpen && w.innerWidth >= 1024) { - menuState.setMenuMobileOpen(!mobileMenuOpen) - } - }) - return () => { - window.removeEventListener('resize', () => {}) - } - }, [mobileMenuOpen]) - - return ( -
menuState.setMenuMobileOpen(!mobileMenuOpen)} - >
- ) -}) - -const HeaderLogo = memo(function HeaderLogo() { - const { resolvedTheme } = useTheme() - return ( - - Supabase Logo - DOCS - - ) -}) - -const Container = memo(function Container(props: PropsWithChildren) { - const mobileMenuOpen = useMenuMobileOpen() - - return ( -
-
{props.children}
-
- ) -}) - -const NavContainer = memo(function NavContainer() { - const mobileMenuOpen = useMenuMobileOpen() - - return ( - - ) -}) +import { PropsWithChildren } from 'react' const SiteLayout = ({ children }: PropsWithChildren<{}>) => { return ( @@ -351,32 +7,7 @@ const SiteLayout = ({ children }: PropsWithChildren<{}>) => { Supabase Docs -
-
- - -
- -
-
-
- -
-
-
- {children} -
-
- -
-
-
+
{children}
) } diff --git a/apps/docs/layouts/guides/index.tsx b/apps/docs/layouts/guides/index.tsx index 105e250dd5b..34768852a2e 100644 --- a/apps/docs/layouts/guides/index.tsx +++ b/apps/docs/layouts/guides/index.tsx @@ -10,8 +10,10 @@ import components from '~/components' import { highlightSelectedTocItem } from '~/components/CustomHTMLElements/CustomHTMLElements.utils' import { FooterHelpCalloutType } from '~/components/FooterHelpCallout' import GuidesTableOfContents from '~/components/GuidesTableOfContents' +import { type MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import useHash from '~/hooks/useHash' import { LayoutMainContent } from '../DefaultLayout' +import { MainSkeleton } from '../MainSkeleton' interface Props { meta: { @@ -30,6 +32,7 @@ interface Props { toc?: any currentPage?: string hideToc?: boolean + menuId: MenuId } const Layout: FC = (props) => { @@ -42,6 +45,8 @@ const Layout: FC = (props) => { const { asPath } = useRouter() const router = useRouter() + const menuId = props.menuId + const EDIT_BUTTON_EXCLUDE_LIST = ['/404'] useEffect(() => { @@ -108,77 +113,79 @@ const Layout: FC = (props) => { }, }} /> - -
-
- {props.meta?.breadcrumb && ( -

{props.meta.breadcrumb}

- )} -
-

{props.meta.title}

- {props.meta?.subtitle && ( -

{props.meta.subtitle}

- )} -
- {props.children} - - {EDIT_BUTTON_EXCLUDE_LIST.includes(router.route) ? ( - <> - ) : ( - - )} -
-
- {!props.hideToc && hasTableOfContents && !props.meta?.hide_table_of_contents && ( + + +
+ + ) } diff --git a/apps/docs/pages/guides/ai/[[...slug]].tsx b/apps/docs/pages/guides/ai/[[...slug]].tsx index af8cc713906..a19f8a02e54 100644 --- a/apps/docs/pages/guides/ai/[[...slug]].tsx +++ b/apps/docs/pages/guides/ai/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function AiGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/ai/python/[slug].tsx b/apps/docs/pages/guides/ai/python/[slug].tsx index fcbd53160c0..952e4bfa099 100644 --- a/apps/docs/pages/guides/ai/python/[slug].tsx +++ b/apps/docs/pages/guides/ai/python/[slug].tsx @@ -11,6 +11,7 @@ import Layout from '~/layouts/DefaultGuideLayout' import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition' import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' // We fetch these docs at build time from an external repo const org = 'supabase' @@ -61,7 +62,7 @@ interface PythonClientDocsProps { export default function PythonClientDocs({ source, meta }: PythonClientDocsProps) { return ( - + ) diff --git a/apps/docs/pages/guides/api/[[...slug]].tsx b/apps/docs/pages/guides/api/[[...slug]].tsx index 94951837d6d..d46e03fd7cc 100644 --- a/apps/docs/pages/guides/api/[[...slug]].tsx +++ b/apps/docs/pages/guides/api/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function ApiGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/auth/[[...slug]].tsx b/apps/docs/pages/guides/auth/[[...slug]].tsx index 777f65e6ddd..9e645a917ea 100644 --- a/apps/docs/pages/guides/auth/[[...slug]].tsx +++ b/apps/docs/pages/guides/auth/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function AuthGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/cli/[[...slug]].tsx b/apps/docs/pages/guides/cli/[[...slug]].tsx index 3e690745906..2dd168f672d 100644 --- a/apps/docs/pages/guides/cli/[[...slug]].tsx +++ b/apps/docs/pages/guides/cli/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function CliGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/cli/config.tsx b/apps/docs/pages/guides/cli/config.tsx index 3830af444f1..193f25fca66 100644 --- a/apps/docs/pages/guides/cli/config.tsx +++ b/apps/docs/pages/guides/cli/config.tsx @@ -5,6 +5,8 @@ import GuidesTableOfContents from '~/components/GuidesTableOfContents' import { Heading } from '~/components/CustomHTMLElements' import Head from 'next/head' import { CodeBlock } from 'ui' +import { MainSkeleton } from '~/layouts/MainSkeleton' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' // Parameters are grouped on the page by tag const tocList = [] @@ -29,24 +31,26 @@ export default function Config() { Supabase CLI config -
-
-
-

CLI configuration

-
- {specFile.info.description} -
{content}
+ +
+
+
+

CLI configuration

+
+ {specFile.info.description} +
{content}
+
+
+
+
+ + On this page + + +
-
-
- - On this page - - -
-
-
+ ) } diff --git a/apps/docs/pages/guides/cli/github-action/[slug].tsx b/apps/docs/pages/guides/cli/github-action/[slug].tsx index 049e3f1072d..d06701295e5 100644 --- a/apps/docs/pages/guides/cli/github-action/[slug].tsx +++ b/apps/docs/pages/guides/cli/github-action/[slug].tsx @@ -12,6 +12,7 @@ import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLin import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition' import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle' import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' // We fetch these docs at build time from an external repo const org = 'supabase' @@ -62,7 +63,7 @@ interface ActionDocsProps { export default function ActionDocs({ source, meta }: ActionDocsProps) { return ( - + ) diff --git a/apps/docs/pages/guides/database/[[...slug]].tsx b/apps/docs/pages/guides/database/[[...slug]].tsx index fc7519ad2ba..0ee6416477b 100644 --- a/apps/docs/pages/guides/database/[[...slug]].tsx +++ b/apps/docs/pages/guides/database/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -31,7 +32,7 @@ export default function DatabaseGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/database/extensions/wrappers/[[...slug]].tsx b/apps/docs/pages/guides/database/extensions/wrappers/[[...slug]].tsx index 564d96d51d2..0d34ede0dcb 100644 --- a/apps/docs/pages/guides/database/extensions/wrappers/[[...slug]].tsx +++ b/apps/docs/pages/guides/database/extensions/wrappers/[[...slug]].tsx @@ -10,6 +10,7 @@ import remarkGfm from 'remark-gfm' import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' @@ -83,7 +84,7 @@ export default function WrappersDocs({ editLink, }: InferGetStaticPropsType) { return ( - + ) diff --git a/apps/docs/pages/guides/functions/[[...slug]].tsx b/apps/docs/pages/guides/functions/[[...slug]].tsx index 8e41b131d3e..8a8ed0defd2 100644 --- a/apps/docs/pages/guides/functions/[[...slug]].tsx +++ b/apps/docs/pages/guides/functions/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function FunctionsGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/getting-started/[[...slug]].tsx b/apps/docs/pages/guides/getting-started/[[...slug]].tsx index 8791fae3a10..e16c15ac68f 100644 --- a/apps/docs/pages/guides/getting-started/[[...slug]].tsx +++ b/apps/docs/pages/guides/getting-started/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function GettingStartedGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/graphql/[[...slug]].tsx b/apps/docs/pages/guides/graphql/[[...slug]].tsx index 559e10f592b..00eaecfe221 100644 --- a/apps/docs/pages/guides/graphql/[[...slug]].tsx +++ b/apps/docs/pages/guides/graphql/[[...slug]].tsx @@ -5,14 +5,17 @@ import { serialize } from 'next-mdx-remote/serialize' import { isAbsolute, relative } from 'path' import rehypeSlug from 'rehype-slug' import remarkGfm from 'remark-gfm' -import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } + import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition' import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle' import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs' +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } + // We fetch these docs at build time from an external repo const org = 'supabase' const repo = 'pg_graphql' @@ -114,7 +117,7 @@ interface PGGraphQLDocsProps { export default function PGGraphQLDocs({ source, meta }: PGGraphQLDocsProps) { return ( - + ) diff --git a/apps/docs/pages/guides/platform/[[...slug]].tsx b/apps/docs/pages/guides/platform/[[...slug]].tsx index 06340742556..f20307d7974 100644 --- a/apps/docs/pages/guides/platform/[[...slug]].tsx +++ b/apps/docs/pages/guides/platform/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function PlatformGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/realtime/[[...slug]].tsx b/apps/docs/pages/guides/realtime/[[...slug]].tsx index dddabae2a82..3a90134f5ad 100644 --- a/apps/docs/pages/guides/realtime/[[...slug]].tsx +++ b/apps/docs/pages/guides/realtime/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function RealtimeGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/resources/[[...slug]].tsx b/apps/docs/pages/guides/resources/[[...slug]].tsx index 1fb37bfe708..d73ad930fe5 100644 --- a/apps/docs/pages/guides/resources/[[...slug]].tsx +++ b/apps/docs/pages/guides/resources/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function ResourcesGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/self-hosting/[[...slug]].tsx b/apps/docs/pages/guides/self-hosting/[[...slug]].tsx index fee43e2be5b..c63d1c13b75 100644 --- a/apps/docs/pages/guides/self-hosting/[[...slug]].tsx +++ b/apps/docs/pages/guides/self-hosting/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function SelfHostingGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/guides/self-hosting/analytics/config.tsx b/apps/docs/pages/guides/self-hosting/analytics/config.tsx index 073411ca703..3946fc2c55c 100644 --- a/apps/docs/pages/guides/self-hosting/analytics/config.tsx +++ b/apps/docs/pages/guides/self-hosting/analytics/config.tsx @@ -3,6 +3,7 @@ import { MDXRemote } from 'next-mdx-remote' import { serialize } from 'next-mdx-remote/serialize' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Param from '~/components/Params' import Layout from '~/layouts/DefaultGuideLayout' import { getAnalyticsConfigV0 } from '~/lib/mdx/getConfig' @@ -27,6 +28,7 @@ export const Page = (props: InferGetStaticPropsType) => ( diff --git a/apps/docs/pages/guides/self-hosting/auth/config.tsx b/apps/docs/pages/guides/self-hosting/auth/config.tsx index 50734320dfe..5702f8a5379 100644 --- a/apps/docs/pages/guides/self-hosting/auth/config.tsx +++ b/apps/docs/pages/guides/self-hosting/auth/config.tsx @@ -3,6 +3,7 @@ import { MDXRemote } from 'next-mdx-remote' import { serialize } from 'next-mdx-remote/serialize' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Param from '~/components/Params' import Layout from '~/layouts/DefaultGuideLayout' import { getAuthConfigV1 } from '~/lib/mdx/getConfig' @@ -27,6 +28,7 @@ export const Page = (props: InferGetStaticPropsType) => ( diff --git a/apps/docs/pages/guides/self-hosting/realtime/config.tsx b/apps/docs/pages/guides/self-hosting/realtime/config.tsx index 1dd5086b214..09df809537c 100644 --- a/apps/docs/pages/guides/self-hosting/realtime/config.tsx +++ b/apps/docs/pages/guides/self-hosting/realtime/config.tsx @@ -3,6 +3,7 @@ import { MDXRemote } from 'next-mdx-remote' import { serialize } from 'next-mdx-remote/serialize' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Param from '~/components/Params' import Layout from '~/layouts/DefaultGuideLayout' import { getRealtimeConfigV0 } from '~/lib/mdx/getConfig' @@ -27,6 +28,7 @@ export const Page = (props: InferGetStaticPropsType) => ( diff --git a/apps/docs/pages/guides/self-hosting/storage/config.tsx b/apps/docs/pages/guides/self-hosting/storage/config.tsx index 57a32f7cb96..8a131f674ac 100644 --- a/apps/docs/pages/guides/self-hosting/storage/config.tsx +++ b/apps/docs/pages/guides/self-hosting/storage/config.tsx @@ -3,6 +3,7 @@ import { MDXRemote } from 'next-mdx-remote' import { serialize } from 'next-mdx-remote/serialize' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Param from '~/components/Params' import Layout from '~/layouts/DefaultGuideLayout' import { getStorageConfigV0 } from '~/lib/mdx/getConfig' @@ -27,6 +28,7 @@ export const Page = (props: InferGetStaticPropsType) => ( diff --git a/apps/docs/pages/guides/storage/[[...slug]].tsx b/apps/docs/pages/guides/storage/[[...slug]].tsx index c3ae4c4b3c3..90c4b978d88 100644 --- a/apps/docs/pages/guides/storage/[[...slug]].tsx +++ b/apps/docs/pages/guides/storage/[[...slug]].tsx @@ -2,6 +2,7 @@ import { type GetStaticPaths, type GetStaticProps, type InferGetStaticPropsType import { MDXRemote } from 'next-mdx-remote' import components from '~/components' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import Layout from '~/layouts/DefaultGuideLayout' import { getGuidesStaticPaths, getGuidesStaticProps } from '~/lib/docs' @@ -21,7 +22,7 @@ export default function StorageGuide({ const { hideToc, ...meta } = frontmatter return ( - + ) diff --git a/apps/docs/pages/handbook/contributing.mdx b/apps/docs/pages/handbook/contributing.mdx deleted file mode 100644 index 5365b2fb9f9..00000000000 --- a/apps/docs/pages/handbook/contributing.mdx +++ /dev/null @@ -1,32 +0,0 @@ -import Layout from '~/layouts/DefaultGuideLayout' - -export const meta = { - id: 'contributing', - title: 'Contributing', - description: 'Want to help?', -} - -## How to contribute - -Supabase has many [open source repos](https://github.com/orgs/supabase/repositories). Some of the more popular ones are: - -- [Supabase](https://github.com/supabase/supabase) - Our Dashboard, Websites, and example apps -- [Supabase-js](https://github.com/supabase/supabase-js) - A client-side library written in TypeScript -- [Gotrue](https://github.com/supabase/gotrue) - Our auth server, written in Go -- [Realtime](https://github.com/supabase/realtime) - A server for streaming changes from Postgres, written in Elixir -- [browse all](https://github.com/orgs/supabase/repositories) - -Want to contribute? Why not jump into our GitHub repo and: - -- [Sponsor Supabase](https://github.com/sponsors/supabase). -- [Answer Discussions](https://github.com/supabase/supabase/discussions). -- Submit an issue to one of our [repos](https://github.com/orgs/supabase/repositories) -- Report a performance issue or a part of the documentation that you find confusing. -- Create a pull request in one of our [repos](https://github.com/orgs/supabase/repositories) -- [Translate our Readme](https://github.com/supabase/supabase/issues/1341). -- Try our products and give feedback. -- Spread the word if you like what we are doing. - -export const Page = ({ children }) => - -export default Page diff --git a/apps/docs/pages/handbook/introduction.mdx b/apps/docs/pages/handbook/introduction.mdx deleted file mode 100644 index f6f2fc2c162..00000000000 --- a/apps/docs/pages/handbook/introduction.mdx +++ /dev/null @@ -1,21 +0,0 @@ -import Layout from '~/layouts/DefaultGuideLayout' - -export const meta = { - id: 'introduction', - title: 'Supabase Handbook', - description: 'The Supabase public handbook and manifesto', -} - -Supabase is thinking in public. Everything is online, no matter how raw the current state of things. - -This is our public handbook and manifesto. We are completely opensource and this means that you, our users, are also our team members. - ---- - -## Opensource - -Wherever we can we will support existing opensource tools and libraries. - -export const Page = ({ children }) => - -export default Page diff --git a/apps/docs/pages/reference/analytics/[...slug].tsx b/apps/docs/pages/reference/analytics/[...slug].tsx deleted file mode 100644 index 6ba5e15111c..00000000000 --- a/apps/docs/pages/reference/analytics/[...slug].tsx +++ /dev/null @@ -1,168 +0,0 @@ -import specFile from '~/spec/transforms/analytics_v0_openapi_deparsed.json' assert { type: 'json' } -import { gen_v3, enrichedOperation } from '~/lib/refGenerator/helpers' -import { Tabs, CodeBlock } from 'ui' - -import RefSubLayout from '~/layouts/ref/RefSubLayout' - -export type AcceptedValue = { - id: string - name: string - type: 'string' | 'boolean' | 'object' - description?: string -} - -export type Flag = { - id: string - name: string - description: string - default_value: string - accepted_values: AcceptedValue[] -} - -export type ApiParameter = { - example: string - in: string - name: string - required: boolean - schema: { - type: string - example: string - } -} -// @ts-ignore -const generatedSpec = gen_v3(specFile, 'wat', { apiUrl: 'apiv0' }) - -export default function Config() { - return ( - -
-
-
-

{generatedSpec.info.title}

-

{generatedSpec.info.description}

-
- -
- {generatedSpec.operations.map((operation: any) => ( -
- - -
- - {operation.operation} - {operation.fullPath} - -
- {/* Path Parameters */} - {operation.parameters && - operation.parameters.filter((parameter) => parameter.in === 'path').length > - 0 && ( -
-

Path parameters

-
    - {operation.parameters && - operation.parameters - .filter((parameter: any) => parameter.in === 'path') - .map((parameter: any) => ( -
  • -
    -
    - {parameter.name} -
    - {parameter.required && ( -
    - REQUIRED -
    - )} -
    -
    -

    {parameter.description}

    -
    - {parameter.example && ( -
    - Example: - - {parameter.example} - -
    - )} -
  • - ))} -
-
- )} - - {/* Header Parameters */} - {operation.parameters && - operation.parameters.filter((parameter) => parameter.in === 'header').length > - 0 && ( -
-

Header parameters

-
    - {operation.parameters && - operation.parameters - .filter((parameter: any) => parameter.in === 'header') - .map((parameter: any) => ( -
  • -
    - {parameter.name} - - {parameter.required && 'required'} - -
    -
    - Example: - - {parameter.example} - -
    -
  • - ))} -
-
- )} -
- - {operation.responseList.length > 0 && ( - <> -

Responses

- - {operation.responseList.map((response: any) => ( - -

{response.description}

- {response?.content && response?.content['application/json'] && ( -
- - {JSON.stringify(response.content['application/json'], null, 2)} - -
- )} -
- ))} -
- - )} -
-
-
- ))} -
-
-
-
- ) -} diff --git a/apps/docs/pages/reference/analytics/config.tsx b/apps/docs/pages/reference/analytics/config.tsx deleted file mode 100644 index 4db5c72958f..00000000000 --- a/apps/docs/pages/reference/analytics/config.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import fs from 'fs' -import matter from 'gray-matter' -import components from '~/components/index' -import { MDXRemote } from 'next-mdx-remote' -import { serialize } from 'next-mdx-remote/serialize' - -import specFile from '~/spec/analytics_v0_config.yaml' assert { type: 'yml' } -import { Parameter } from '~/lib/refGenerator/refTypes' - -import ReactMarkdown from 'react-markdown' - -// Parameters are grouped on the page by tag -const TAGS = ['general', 'database'] - -export default function Config(props) { - return ( -
- ) -} -export async function getServerSideProps() { - // an array of ids of the intro sections for this library - const introPages = ['analytics'] - - const pages = [...introPages] - - // Grab custom markdown intro page files - const allMarkdownDocs = await Promise.all( - pages.map(async (x: any, i) => { - const pathName = `docs/ref/analytics/${x}.mdx` - - const markdownExists = fs.existsSync(pathName) - - const fileContents = markdownExists ? fs.readFileSync(pathName, 'utf8') : '' - const { data, content } = matter(fileContents) - - return { - id: x, - title: x, - // ...content, - meta: data, - introPage: introPages.includes(x), - content: content ? await serialize(content || '') : null, - } - }) - ) - - return { - props: { - docs: allMarkdownDocs, - }, - } -} diff --git a/apps/docs/pages/reference/api/[...slug].tsx b/apps/docs/pages/reference/api/[...slug].tsx index 27760ce04d8..d9c72242668 100644 --- a/apps/docs/pages/reference/api/[...slug].tsx +++ b/apps/docs/pages/reference/api/[...slug].tsx @@ -1,18 +1,28 @@ -import apiCommonSections from '~/spec/common-api-sections.json' assert { type: 'json' } -import specFile from '~/spec/transforms/api_v0_openapi_deparsed.json' assert { type: 'json' } +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import RefSectionHandler from '~/components/reference/RefSectionHandler' import { flattenSections } from '~/lib/helpers' import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' import { gen_v3 } from '~/lib/refGenerator/helpers' +import apiCommonSections from '~/spec/common-api-sections.json' assert { type: 'json' } +import specFile from '~/spec/transforms/api_v0_openapi_deparsed.json' assert { type: 'json' } + // @ts-ignore const generatedSpec = gen_v3(specFile, 'wat', { apiUrl: 'apiv0' }) const sections = flattenSections(apiCommonSections) const libraryPath = '/api' export default function Config(props) { - return + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/auth/[...slug].tsx b/apps/docs/pages/reference/auth/[...slug].tsx deleted file mode 100644 index 8664fe97acb..00000000000 --- a/apps/docs/pages/reference/auth/[...slug].tsx +++ /dev/null @@ -1,168 +0,0 @@ -import { CodeBlock, Tabs } from 'ui' -import specFile from '~/spec/transforms/auth_v1_openapi_deparsed.json' assert { type: 'json' } -import { gen_v3 } from '~/lib/refGenerator/helpers' - -import RefSubLayout from '~/layouts/ref/RefSubLayout' - -export type AcceptedValue = { - id: string - name: string - type: 'string' | 'boolean' | 'object' - description?: string -} - -export type Flag = { - id: string - name: string - description: string - default_value: string - accepted_values: AcceptedValue[] -} - -export type ApiParameter = { - example: string - in: string - name: string - required: boolean - schema: { - type: string - example: string - } -} -// @ts-ignore -const generatedSpec = gen_v3(specFile, 'wat', { apiUrl: 'apiv0' }) - -export default function Config() { - return ( - -
-
-
-

{generatedSpec.info.title}

-

{generatedSpec.info.description}

-
- -
- {generatedSpec.operations.map((operation: any) => ( -
- - -
- - {operation.operation} - {operation.fullPath} - -
- {/* Path Parameters */} - {operation.parameters && - operation.parameters.filter((parameter) => parameter.in === 'path').length > - 0 && ( -
-

Path parameters

-
    - {operation.parameters && - operation.parameters - .filter((parameter: any) => parameter.in === 'path') - .map((parameter: any) => ( -
  • -
    -
    - {parameter.name} -
    - {parameter.required && ( -
    - REQUIRED -
    - )} -
    -
    -

    {parameter.description}

    -
    - {parameter.example && ( -
    - Example: - - {parameter.example} - -
    - )} -
  • - ))} -
-
- )} - - {/* Header Parameters */} - {operation.parameters && - operation.parameters.filter((parameter) => parameter.in === 'header').length > - 0 && ( -
-

Header parameters

-
    - {operation.parameters && - operation.parameters - .filter((parameter: any) => parameter.in === 'header') - .map((parameter: any) => ( -
  • -
    - {parameter.name} - - {parameter.required && 'required'} - -
    -
    - Example: - - {parameter.example} - -
    -
  • - ))} -
-
- )} -
- - {operation.responseList.length > 0 && ( - <> -

Responses

- - {operation.responseList.map((response: any) => ( - -

{response.description}

- {response?.content && response?.content['application/json'] && ( -
- - {JSON.stringify(response.content['application/json'], null, 2)} - -
- )} -
- ))} -
- - )} -
-
-
- ))} -
-
-
-
- ) -} diff --git a/apps/docs/pages/reference/auth/config.tsx b/apps/docs/pages/reference/auth/config.tsx deleted file mode 100644 index d9c1e5eacbf..00000000000 --- a/apps/docs/pages/reference/auth/config.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import specFile from '~/spec/gotrue_v1_config.yaml' assert { type: 'yml' } -import { Parameter } from '~/lib/refGenerator/refTypes' -import ReactMarkdown from 'react-markdown' -import Head from 'next/head' - -// Parameters are grouped on the page by tag -const TAGS = ['general'] - -export default function Config() { - return ( - <> - - Auth config - -
- - ) -} diff --git a/apps/docs/pages/reference/cli/[...slug].tsx b/apps/docs/pages/reference/cli/[...slug].tsx index 75b9088f7fa..779e04540b6 100644 --- a/apps/docs/pages/reference/cli/[...slug].tsx +++ b/apps/docs/pages/reference/cli/[...slug].tsx @@ -1,17 +1,25 @@ -import spec from '~/spec/cli_v1_commands.yaml' assert { type: 'yml' } - -import { flattenSections } from '~/lib/helpers' - -import cliCommonSections from '~/spec/common-cli-sections.json' assert { type: 'json' } +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import RefSectionHandler from '~/components/reference/RefSectionHandler' +import { flattenSections } from '~/lib/helpers' import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' +import spec from '~/spec/cli_v1_commands.yaml' assert { type: 'yml' } +import cliCommonSections from '~/spec/common-cli-sections.json' assert { type: 'json' } + const sections = flattenSections(cliCommonSections) const libraryPath = '/cli' export default function CliRef(props) { - return + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/csharp/[...slug].tsx b/apps/docs/pages/reference/csharp/[...slug].tsx index 8145e38f7c9..77dba701704 100644 --- a/apps/docs/pages/reference/csharp/[...slug].tsx +++ b/apps/docs/pages/reference/csharp/[...slug].tsx @@ -4,12 +4,21 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler' import { flattenSections } from '~/lib/helpers' import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' const sections = flattenSections(clientLibsCommonSections) const libraryPath = '/csharp' export default function CSharpReference(props) { - return + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/csharp/crawlers/[...slug].tsx b/apps/docs/pages/reference/csharp/crawlers/[...slug].tsx index 0d515778deb..aa454e5d162 100644 --- a/apps/docs/pages/reference/csharp/crawlers/[...slug].tsx +++ b/apps/docs/pages/reference/csharp/crawlers/[...slug].tsx @@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' import { useRouter } from 'next/router' import RefSEO from '~/components/reference/RefSEO' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' const sections = flattenSections(clientLibsCommonSections) const libraryPath = '/csharp' @@ -25,6 +26,7 @@ export default function CSharpReference(props) { + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/csharp/v0/crawlers/[...slug].tsx b/apps/docs/pages/reference/csharp/v0/crawlers/[...slug].tsx index 5e20575d173..101c289bddb 100644 --- a/apps/docs/pages/reference/csharp/v0/crawlers/[...slug].tsx +++ b/apps/docs/pages/reference/csharp/v0/crawlers/[...slug].tsx @@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' import { useRouter } from 'next/router' import RefSEO from '~/components/reference/RefSEO' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' const sections = flattenSections(clientLibsCommonSections) const libraryPath = '/csharp/v0' @@ -24,6 +25,7 @@ export default function JSReference(props) { + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/dart/crawlers/[...slug].tsx b/apps/docs/pages/reference/dart/crawlers/[...slug].tsx index faace96a0ba..b18c2eeff9b 100644 --- a/apps/docs/pages/reference/dart/crawlers/[...slug].tsx +++ b/apps/docs/pages/reference/dart/crawlers/[...slug].tsx @@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' import { useRouter } from 'next/router' import RefSEO from '~/components/reference/RefSEO' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' const sections = flattenSections(clientLibsCommonSections) const libraryPath = '/dart' @@ -25,6 +26,7 @@ export default function DartReference(props) { + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/kotlin/crawlers/[...slug].tsx b/apps/docs/pages/reference/kotlin/crawlers/[...slug].tsx index 2a0d1cadc29..2f3885d524b 100644 --- a/apps/docs/pages/reference/kotlin/crawlers/[...slug].tsx +++ b/apps/docs/pages/reference/kotlin/crawlers/[...slug].tsx @@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' import { useRouter } from 'next/router' import RefSEO from '~/components/reference/RefSEO' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' const sections = flattenSections(clientLibsCommonSections) const libraryPath = '/kotlin' @@ -25,6 +26,7 @@ export default function KotlinReference(props) { + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/self-hosting-auth/[...slug].tsx b/apps/docs/pages/reference/self-hosting-auth/[...slug].tsx index 723d11e079b..fbd09b75644 100644 --- a/apps/docs/pages/reference/self-hosting-auth/[...slug].tsx +++ b/apps/docs/pages/reference/self-hosting-auth/[...slug].tsx @@ -1,11 +1,13 @@ -import authSpec from '~/spec/auth_v1_openapi.json' assert { type: 'json' } -import selfHostingAuthCommonSections from '~/spec/common-self-hosting-auth-sections.json' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import RefSectionHandler from '~/components/reference/RefSectionHandler' import { flattenSections } from '~/lib/helpers' import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' import { gen_v3 } from '~/lib/refGenerator/helpers' +import authSpec from '~/spec/auth_v1_openapi.json' assert { type: 'json' } +import selfHostingAuthCommonSections from '~/spec/common-self-hosting-auth-sections.json' + const sections = flattenSections(selfHostingAuthCommonSections) const libraryPath = '/self-hosting-auth' @@ -13,7 +15,15 @@ const libraryPath = '/self-hosting-auth' const spec = gen_v3(authSpec, 'wat', { apiUrl: 'apiv0' }) export default function SelfHostAuthReference(props) { - return + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/self-hosting-functions/[...slug].tsx b/apps/docs/pages/reference/self-hosting-functions/[...slug].tsx index bbd3f335313..432e1a6cec0 100644 --- a/apps/docs/pages/reference/self-hosting-functions/[...slug].tsx +++ b/apps/docs/pages/reference/self-hosting-functions/[...slug].tsx @@ -1,16 +1,23 @@ -import selfHostingFunctionsCommonSections from '~/spec/common-self-hosting-functions-sections.json' - +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import RefSectionHandler from '~/components/reference/RefSectionHandler' import { flattenSections } from '~/lib/helpers' import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' -import { gen_v3 } from '~/lib/refGenerator/helpers' + +import selfHostingFunctionsCommonSections from '~/spec/common-self-hosting-functions-sections.json' assert { type: 'json' } const sections = flattenSections(selfHostingFunctionsCommonSections) const libraryPath = '/self-hosting-functions' export default function SelfHostFunctionsReference(props) { - return + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/self-hosting-realtime/[...slug].tsx b/apps/docs/pages/reference/self-hosting-realtime/[...slug].tsx index 59c9276e5b7..3b894c15f8b 100644 --- a/apps/docs/pages/reference/self-hosting-realtime/[...slug].tsx +++ b/apps/docs/pages/reference/self-hosting-realtime/[...slug].tsx @@ -1,15 +1,23 @@ -import selfHostingRealtimeCommonSections from '~/spec/common-self-hosting-realtime-sections.json' - +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import RefSectionHandler from '~/components/reference/RefSectionHandler' import { flattenSections } from '~/lib/helpers' import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' +import selfHostingRealtimeCommonSections from '~/spec/common-self-hosting-realtime-sections.json' assert { type: 'json' } + const sections = flattenSections(selfHostingRealtimeCommonSections) const libraryPath = '/self-hosting-realtime' export default function SelfHostRealtimeReference(props) { - return + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/self-hosting-storage/[...slug].tsx b/apps/docs/pages/reference/self-hosting-storage/[...slug].tsx index 1468b40f3a9..13559bdc7dc 100644 --- a/apps/docs/pages/reference/self-hosting-storage/[...slug].tsx +++ b/apps/docs/pages/reference/self-hosting-storage/[...slug].tsx @@ -1,11 +1,13 @@ -import storageSpec from '~/spec/storage_v0_openapi.json' assert { type: 'json' } -import selfHostingStorageCommonSections from '~/spec/common-self-hosting-storage-sections.json' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import RefSectionHandler from '~/components/reference/RefSectionHandler' import { flattenSections } from '~/lib/helpers' import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' import { gen_v3 } from '~/lib/refGenerator/helpers' +import storageSpec from '~/spec/storage_v0_openapi.json' assert { type: 'json' } +import selfHostingStorageCommonSections from '~/spec/common-self-hosting-storage-sections.json' assert { type: 'json' } + const sections = flattenSections(selfHostingStorageCommonSections) const libraryPath = '/self-hosting-storage' @@ -13,7 +15,15 @@ const libraryPath = '/self-hosting-storage' const spec = gen_v3(storageSpec, 'wat', { apiUrl: 'apiv0' }) export default function SelfHostStorageReference(props) { - return + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/swift/[...slug].tsx b/apps/docs/pages/reference/swift/[...slug].tsx index 6c84806c676..c459f833e11 100644 --- a/apps/docs/pages/reference/swift/[...slug].tsx +++ b/apps/docs/pages/reference/swift/[...slug].tsx @@ -4,12 +4,21 @@ import RefSectionHandler from '~/components/reference/RefSectionHandler' import { flattenSections } from '~/lib/helpers' import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' const sections = flattenSections(clientLibsCommonSections) const libraryPath = '/swift' export default function SwiftReference(props) { - return + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/swift/crawlers/[...slug].tsx b/apps/docs/pages/reference/swift/crawlers/[...slug].tsx index d8e3be4f79c..69000ea9674 100644 --- a/apps/docs/pages/reference/swift/crawlers/[...slug].tsx +++ b/apps/docs/pages/reference/swift/crawlers/[...slug].tsx @@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' import { useRouter } from 'next/router' import RefSEO from '~/components/reference/RefSEO' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' const sections = flattenSections(clientLibsCommonSections) const libraryPath = '/swift' @@ -25,6 +26,7 @@ export default function SwiftReference(props) { + return ( + + ) } export async function getStaticProps() { diff --git a/apps/docs/pages/reference/swift/v0/crawlers/[...slug].tsx b/apps/docs/pages/reference/swift/v1/crawlers/[...slug].tsx similarity index 92% rename from apps/docs/pages/reference/swift/v0/crawlers/[...slug].tsx rename to apps/docs/pages/reference/swift/v1/crawlers/[...slug].tsx index 6c19debf234..1ef50177ac2 100644 --- a/apps/docs/pages/reference/swift/v0/crawlers/[...slug].tsx +++ b/apps/docs/pages/reference/swift/v1/crawlers/[...slug].tsx @@ -7,6 +7,7 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' import { useRouter } from 'next/router' import RefSEO from '~/components/reference/RefSEO' +import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' const sections = flattenSections(clientLibsCommonSections) const libraryPath = '/swift/v2' @@ -24,6 +25,7 @@ export default function SwiftReference(props) { Date: Fri, 23 Feb 2024 12:10:16 -0500 Subject: [PATCH 12/50] ci: add docs linting (#21462) Add a prose linter that runs on docs content changes and a basic config. Linter only lints changed lines, and it will fail on error. For now, this is not a mandatory check because we expect a lot of false positives while we tweak the linter to suit our conventions. --- .github/workflows/lint-prose.yml | 23 +++ .vale.ini | 12 ++ vale/styles/Custom/AMPM.yml | 9 + vale/styles/Custom/Acronyms.yml | 68 +++++++ vale/styles/Custom/Colons.yml | 8 + vale/styles/Custom/Contractions.yml | 30 +++ vale/styles/Custom/DateFormat.yml | 9 + vale/styles/Custom/Ellipses.yml | 9 + vale/styles/Custom/EmDash.yml | 13 ++ vale/styles/Custom/Exclamation.yml | 12 ++ vale/styles/Custom/FirstPerson.yml | 13 ++ vale/styles/Custom/Gender.yml | 9 + vale/styles/Custom/GenderBias.yml | 47 +++++ vale/styles/Custom/HeadingPunctuation.yml | 13 ++ vale/styles/Custom/Headings.yml | 37 ++++ vale/styles/Custom/Latin.yml | 11 ++ vale/styles/Custom/LyHyphens.yml | 14 ++ vale/styles/Custom/OptionalPlurals.yml | 12 ++ vale/styles/Custom/Ordinal.yml | 7 + vale/styles/Custom/OxfordComma.yml | 7 + vale/styles/Custom/Parens.yml | 7 + vale/styles/Custom/Passive.yml | 184 ++++++++++++++++++ vale/styles/Custom/Periods.yml | 7 + vale/styles/Custom/Quotes.yml | 7 + vale/styles/Custom/Ranges.yml | 7 + vale/styles/Custom/Semicolons.yml | 8 + vale/styles/Custom/Slang.yml | 11 ++ vale/styles/Custom/Spacing.yml | 10 + vale/styles/Custom/Spelling.yml | 10 + vale/styles/Custom/Units.yml | 8 + vale/styles/Custom/We.yml | 11 ++ vale/styles/Custom/Will.yml | 7 + vale/styles/Custom/WordList.yml | 82 ++++++++ vale/styles/Custom/meta.json | 4 + vale/styles/Custom/vocab.txt | 0 .../config/vocabularies/Supabase/accept.txt | 18 ++ 36 files changed, 744 insertions(+) create mode 100644 .github/workflows/lint-prose.yml create mode 100644 .vale.ini create mode 100644 vale/styles/Custom/AMPM.yml create mode 100644 vale/styles/Custom/Acronyms.yml create mode 100644 vale/styles/Custom/Colons.yml create mode 100644 vale/styles/Custom/Contractions.yml create mode 100644 vale/styles/Custom/DateFormat.yml create mode 100644 vale/styles/Custom/Ellipses.yml create mode 100644 vale/styles/Custom/EmDash.yml create mode 100644 vale/styles/Custom/Exclamation.yml create mode 100644 vale/styles/Custom/FirstPerson.yml create mode 100644 vale/styles/Custom/Gender.yml create mode 100644 vale/styles/Custom/GenderBias.yml create mode 100644 vale/styles/Custom/HeadingPunctuation.yml create mode 100644 vale/styles/Custom/Headings.yml create mode 100644 vale/styles/Custom/Latin.yml create mode 100644 vale/styles/Custom/LyHyphens.yml create mode 100644 vale/styles/Custom/OptionalPlurals.yml create mode 100644 vale/styles/Custom/Ordinal.yml create mode 100644 vale/styles/Custom/OxfordComma.yml create mode 100644 vale/styles/Custom/Parens.yml create mode 100644 vale/styles/Custom/Passive.yml create mode 100644 vale/styles/Custom/Periods.yml create mode 100644 vale/styles/Custom/Quotes.yml create mode 100644 vale/styles/Custom/Ranges.yml create mode 100644 vale/styles/Custom/Semicolons.yml create mode 100644 vale/styles/Custom/Slang.yml create mode 100644 vale/styles/Custom/Spacing.yml create mode 100644 vale/styles/Custom/Spelling.yml create mode 100644 vale/styles/Custom/Units.yml create mode 100644 vale/styles/Custom/We.yml create mode 100644 vale/styles/Custom/Will.yml create mode 100644 vale/styles/Custom/WordList.yml create mode 100644 vale/styles/Custom/meta.json create mode 100644 vale/styles/Custom/vocab.txt create mode 100644 vale/styles/config/vocabularies/Supabase/accept.txt diff --git a/.github/workflows/lint-prose.yml b/.github/workflows/lint-prose.yml new file mode 100644 index 00000000000..8e8c46480f8 --- /dev/null +++ b/.github/workflows/lint-prose.yml @@ -0,0 +1,23 @@ +name: reviewdog +on: + pull_request: + paths: + - '.vale.ini' + - 'vale/**' + - 'apps/docs/content/**' + +jobs: + vale: + name: runner / vale + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + sparse-checkout: | + .vale.ini + vale + apps/docs/content + - uses: errata-ai/vale-action@reviewdog + with: + files: apps/docs/content + fail_on_error: true diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 00000000000..6b721717743 --- /dev/null +++ b/.vale.ini @@ -0,0 +1,12 @@ +StylesPath = './vale/styles' +MinAlertLevel = 'suggestion' + +Vocab = Supabase + +[formats] +mdx = md + +[*] +BasedOnStyles = Vale, Custom +BlockIgnores = (?s) *(.*?) +TokenIgnores = (href=".*?") diff --git a/vale/styles/Custom/AMPM.yml b/vale/styles/Custom/AMPM.yml new file mode 100644 index 00000000000..fbdc6e4f84b --- /dev/null +++ b/vale/styles/Custom/AMPM.yml @@ -0,0 +1,9 @@ +extends: existence +message: "Use 'AM' or 'PM' (preceded by a space)." +link: 'https://developers.google.com/style/word-list' +level: error +nonword: true +tokens: + - '\d{1,2}[AP]M' + - '\d{1,2} ?[ap]m' + - '\d{1,2} ?[aApP]\.[mM]\.' diff --git a/vale/styles/Custom/Acronyms.yml b/vale/styles/Custom/Acronyms.yml new file mode 100644 index 00000000000..2fdabe6af4c --- /dev/null +++ b/vale/styles/Custom/Acronyms.yml @@ -0,0 +1,68 @@ +extends: conditional +message: "Spell out '%s', if it's unfamiliar to the audience." +link: 'https://developers.google.com/style/abbreviations' +level: suggestion +ignorecase: false +# Ensures that the existence of 'first' implies the existence of 'second'. +first: '\b([A-Z]{3,5})\b' +second: '(?:\b[A-Z][a-z]+ )+\(([A-Z]{3,5})\)' +# ... with the exception of these: +exceptions: + - API + - ASP + - CLI + - CPU + - CSS + - CSV + - DEBUG + - DOM + - DPI + - FAQ + - GCC + - GDB + - GET + - GPT + - GPU + - GTK + - GUI + - HTML + - HTTP + - HTTPS + - IDE + - IMDB + - JAR + - JSON + - JSX + - JWT + - LESS + - LLDB + - NET + - NOTE + - NVDA + - OSS + - PATH + - PDF + - PHP + - POST + - RAM + - REPL + - REST + - RSA + - SCM + - SCSS + - SDK + - SQL + - SSH + - SSL + - SVG + - TBD + - TCP + - TODO + - URI + - URL + - USB + - UTF + - XML + - XSS + - YAML + - ZIP diff --git a/vale/styles/Custom/Colons.yml b/vale/styles/Custom/Colons.yml new file mode 100644 index 00000000000..99363fbd46d --- /dev/null +++ b/vale/styles/Custom/Colons.yml @@ -0,0 +1,8 @@ +extends: existence +message: "'%s' should be in lowercase." +link: 'https://developers.google.com/style/colons' +nonword: true +level: warning +scope: sentence +tokens: + - ':\s[A-Z]' diff --git a/vale/styles/Custom/Contractions.yml b/vale/styles/Custom/Contractions.yml new file mode 100644 index 00000000000..4f6fd5d489d --- /dev/null +++ b/vale/styles/Custom/Contractions.yml @@ -0,0 +1,30 @@ +extends: substitution +message: "Use '%s' instead of '%s'." +link: 'https://developers.google.com/style/contractions' +level: suggestion +ignorecase: true +action: + name: replace +swap: + are not: aren't + cannot: can't + could not: couldn't + did not: didn't + do not: don't + does not: doesn't + has not: hasn't + have not: haven't + how is: how's + is not: isn't + it is: it's + should not: shouldn't + that is: that's + they are: they're + was not: wasn't + we are: we're + we have: we've + were not: weren't + what is: what's + when is: when's + where is: where's + will not: won't diff --git a/vale/styles/Custom/DateFormat.yml b/vale/styles/Custom/DateFormat.yml new file mode 100644 index 00000000000..e9d227fa13d --- /dev/null +++ b/vale/styles/Custom/DateFormat.yml @@ -0,0 +1,9 @@ +extends: existence +message: "Use 'July 31, 2016' format, not '%s'." +link: 'https://developers.google.com/style/dates-times' +ignorecase: true +level: error +nonword: true +tokens: + - '\d{1,2}(?:\.|/)\d{1,2}(?:\.|/)\d{4}' + - '\d{1,2} (?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)|May|Jun(?:e)|Jul(?:y)|Aug(?:ust)|Sep(?:tember)?|Oct(?:ober)|Nov(?:ember)?|Dec(?:ember)?) \d{4}' diff --git a/vale/styles/Custom/Ellipses.yml b/vale/styles/Custom/Ellipses.yml new file mode 100644 index 00000000000..1e070517bfe --- /dev/null +++ b/vale/styles/Custom/Ellipses.yml @@ -0,0 +1,9 @@ +extends: existence +message: "In general, don't use an ellipsis." +link: 'https://developers.google.com/style/ellipses' +nonword: true +level: warning +action: + name: remove +tokens: + - '\.\.\.' diff --git a/vale/styles/Custom/EmDash.yml b/vale/styles/Custom/EmDash.yml new file mode 100644 index 00000000000..5a81fb0942e --- /dev/null +++ b/vale/styles/Custom/EmDash.yml @@ -0,0 +1,13 @@ +extends: existence +message: "Don't put a space before or after a dash." +link: "https://developers.google.com/style/dashes" +nonword: true +level: error +action: + name: edit + params: + - trim + - " " +tokens: + - '\s[—–]\s' + diff --git a/vale/styles/Custom/Exclamation.yml b/vale/styles/Custom/Exclamation.yml new file mode 100644 index 00000000000..b4e4a1f7e9a --- /dev/null +++ b/vale/styles/Custom/Exclamation.yml @@ -0,0 +1,12 @@ +extends: existence +message: "Don't use exclamation points in text." +link: "https://developers.google.com/style/exclamation-points" +nonword: true +level: error +action: + name: edit + params: + - trim_right + - "!" +tokens: + - '\w+!(?:\s|$)' diff --git a/vale/styles/Custom/FirstPerson.yml b/vale/styles/Custom/FirstPerson.yml new file mode 100644 index 00000000000..0b7b8828ca5 --- /dev/null +++ b/vale/styles/Custom/FirstPerson.yml @@ -0,0 +1,13 @@ +extends: existence +message: "Avoid first-person pronouns such as '%s'." +link: 'https://developers.google.com/style/pronouns#personal-pronouns' +ignorecase: true +level: warning +nonword: true +tokens: + - (?:^|\s)I\s + - (?:^|\s)I,\s + - \bI'm\b + - \bme\b + - \bmy\b + - \bmine\b diff --git a/vale/styles/Custom/Gender.yml b/vale/styles/Custom/Gender.yml new file mode 100644 index 00000000000..c8486181d69 --- /dev/null +++ b/vale/styles/Custom/Gender.yml @@ -0,0 +1,9 @@ +extends: existence +message: "Don't use '%s' as a gender-neutral pronoun." +link: 'https://developers.google.com/style/pronouns#gender-neutral-pronouns' +level: error +ignorecase: true +tokens: + - he/she + - s/he + - \(s\)he diff --git a/vale/styles/Custom/GenderBias.yml b/vale/styles/Custom/GenderBias.yml new file mode 100644 index 00000000000..9e701908630 --- /dev/null +++ b/vale/styles/Custom/GenderBias.yml @@ -0,0 +1,47 @@ +extends: substitution +message: "Consider using '%s' instead of '%s'." +link: 'https://developers.google.com/style/inclusive-documentation' +ignorecase: true +level: error +action: + name: replace +swap: + (?:alumna|alumnus): graduate + (?:alumnae|alumni): graduates + air(?:m[ae]n|wom[ae]n): pilot(s) + anchor(?:m[ae]n|wom[ae]n): anchor(s) + authoress: author + camera(?:m[ae]n|wom[ae]n): camera operator(s) + chair(?:m[ae]n|wom[ae]n): chair(s) + congress(?:m[ae]n|wom[ae]n): member(s) of congress + door(?:m[ae]|wom[ae]n): concierge(s) + draft(?:m[ae]n|wom[ae]n): drafter(s) + fire(?:m[ae]n|wom[ae]n): firefighter(s) + fisher(?:m[ae]n|wom[ae]n): fisher(s) + fresh(?:m[ae]n|wom[ae]n): first-year student(s) + garbage(?:m[ae]n|wom[ae]n): waste collector(s) + lady lawyer: lawyer + ladylike: courteous + landlord: building manager + mail(?:m[ae]n|wom[ae]n): mail carriers + man and wife: husband and wife + man enough: strong enough + mankind: human kind + manmade: manufactured + manpower: personnel + men and girls: men and women + middle(?:m[ae]n|wom[ae]n): intermediary + news(?:m[ae]n|wom[ae]n): journalist(s) + ombuds(?:man|woman): ombuds + oneupmanship: upstaging + poetess: poet + police(?:m[ae]n|wom[ae]n): police officer(s) + repair(?:m[ae]n|wom[ae]n): technician(s) + sales(?:m[ae]n|wom[ae]n): salesperson or sales people + service(?:m[ae]n|wom[ae]n): soldier(s) + steward(?:ess)?: flight attendant + tribes(?:m[ae]n|wom[ae]n): tribe member(s) + waitress: waiter + woman doctor: doctor + woman scientist[s]?: scientist(s) + work(?:m[ae]n|wom[ae]n): worker(s) diff --git a/vale/styles/Custom/HeadingPunctuation.yml b/vale/styles/Custom/HeadingPunctuation.yml new file mode 100644 index 00000000000..c1729868b64 --- /dev/null +++ b/vale/styles/Custom/HeadingPunctuation.yml @@ -0,0 +1,13 @@ +extends: existence +message: "Don't put a period at the end of a heading." +link: "https://developers.google.com/style/capitalization#capitalization-in-titles-and-headings" +nonword: true +level: warning +scope: heading +action: + name: edit + params: + - trim_right + - "." +tokens: + - '[a-z0-9][.]\s*$' diff --git a/vale/styles/Custom/Headings.yml b/vale/styles/Custom/Headings.yml new file mode 100644 index 00000000000..beb9022e6a5 --- /dev/null +++ b/vale/styles/Custom/Headings.yml @@ -0,0 +1,37 @@ +extends: capitalization +message: "'%s' should use sentence-style capitalization." +link: "https://developers.google.com/style/capitalization#capitalization-in-titles-and-headings" +level: warning +scope: heading +match: $sentence +indicators: + - ":" +exceptions: + - API + - Azure + - ChatGPT + - ChatGPT Retrieval Plugin + - CLI + - Cosmos + - Docker + - Edge Functions? + - Emmet + - gRPC + - HNSW + - I + - JWT + - Kubernetes + - Linux + - macOS + - Marketplace + - MongoDB + - OpenAI + - REPL + - REST + - Studio + - Transformers.js + - TypeScript + - URLs + - Visual + - VS + - Windows diff --git a/vale/styles/Custom/Latin.yml b/vale/styles/Custom/Latin.yml new file mode 100644 index 00000000000..ca03b9154b1 --- /dev/null +++ b/vale/styles/Custom/Latin.yml @@ -0,0 +1,11 @@ +extends: substitution +message: "Use '%s' instead of '%s'." +link: 'https://developers.google.com/style/abbreviations' +ignorecase: true +level: error +nonword: true +action: + name: replace +swap: + '\b(?:eg|e\.g\.)(?=[\s,;])': for example + '\b(?:ie|i\.e\.)(?=[\s,;])': that is diff --git a/vale/styles/Custom/LyHyphens.yml b/vale/styles/Custom/LyHyphens.yml new file mode 100644 index 00000000000..50dacb40db8 --- /dev/null +++ b/vale/styles/Custom/LyHyphens.yml @@ -0,0 +1,14 @@ +extends: existence +message: "'%s' doesn't need a hyphen." +link: "https://developers.google.com/style/hyphens" +level: error +ignorecase: false +nonword: true +action: + name: edit + params: + - regex + - "-" + - " " +tokens: + - '\b[^\s-]+ly-\w+\b' diff --git a/vale/styles/Custom/OptionalPlurals.yml b/vale/styles/Custom/OptionalPlurals.yml new file mode 100644 index 00000000000..4a8767d6f55 --- /dev/null +++ b/vale/styles/Custom/OptionalPlurals.yml @@ -0,0 +1,12 @@ +extends: existence +message: "Don't use plurals in parentheses such as in '%s'." +link: "https://developers.google.com/style/plurals-parentheses" +level: error +nonword: true +action: + name: edit + params: + - trim_right + - "(s)" +tokens: + - '\b\w+\(s\)' diff --git a/vale/styles/Custom/Ordinal.yml b/vale/styles/Custom/Ordinal.yml new file mode 100644 index 00000000000..d1ac7d27e80 --- /dev/null +++ b/vale/styles/Custom/Ordinal.yml @@ -0,0 +1,7 @@ +extends: existence +message: "Spell out all ordinal numbers ('%s') in text." +link: 'https://developers.google.com/style/numbers' +level: error +nonword: true +tokens: + - \d+(?:st|nd|rd|th) diff --git a/vale/styles/Custom/OxfordComma.yml b/vale/styles/Custom/OxfordComma.yml new file mode 100644 index 00000000000..b9ba21ebb25 --- /dev/null +++ b/vale/styles/Custom/OxfordComma.yml @@ -0,0 +1,7 @@ +extends: existence +message: "Use the Oxford comma in '%s'." +link: 'https://developers.google.com/style/commas' +scope: sentence +level: warning +tokens: + - '(?:[^,]+,){1,}\s\w+\s(?:and|or)' diff --git a/vale/styles/Custom/Parens.yml b/vale/styles/Custom/Parens.yml new file mode 100644 index 00000000000..3b8711d0c88 --- /dev/null +++ b/vale/styles/Custom/Parens.yml @@ -0,0 +1,7 @@ +extends: existence +message: "Use parentheses judiciously." +link: 'https://developers.google.com/style/parentheses' +nonword: true +level: suggestion +tokens: + - '\(.+\)' diff --git a/vale/styles/Custom/Passive.yml b/vale/styles/Custom/Passive.yml new file mode 100644 index 00000000000..3265890e520 --- /dev/null +++ b/vale/styles/Custom/Passive.yml @@ -0,0 +1,184 @@ +extends: existence +link: 'https://developers.google.com/style/voice' +message: "In general, use active voice instead of passive voice ('%s')." +ignorecase: true +level: suggestion +raw: + - \b(am|are|were|being|is|been|was|be)\b\s* +tokens: + - '[\w]+ed' + - awoken + - beat + - become + - been + - begun + - bent + - beset + - bet + - bid + - bidden + - bitten + - bled + - blown + - born + - bought + - bound + - bred + - broadcast + - broken + - brought + - built + - burnt + - burst + - cast + - caught + - chosen + - clung + - come + - cost + - crept + - cut + - dealt + - dived + - done + - drawn + - dreamt + - driven + - drunk + - dug + - eaten + - fallen + - fed + - felt + - fit + - fled + - flown + - flung + - forbidden + - foregone + - forgiven + - forgotten + - forsaken + - fought + - found + - frozen + - given + - gone + - gotten + - ground + - grown + - heard + - held + - hidden + - hit + - hung + - hurt + - kept + - knelt + - knit + - known + - laid + - lain + - leapt + - learnt + - led + - left + - lent + - let + - lighted + - lost + - made + - meant + - met + - misspelt + - mistaken + - mown + - overcome + - overdone + - overtaken + - overthrown + - paid + - pled + - proven + - put + - quit + - read + - rid + - ridden + - risen + - run + - rung + - said + - sat + - sawn + - seen + - sent + - set + - sewn + - shaken + - shaven + - shed + - shod + - shone + - shorn + - shot + - shown + - shrunk + - shut + - slain + - slept + - slid + - slit + - slung + - smitten + - sold + - sought + - sown + - sped + - spent + - spilt + - spit + - split + - spoken + - spread + - sprung + - spun + - stolen + - stood + - stridden + - striven + - struck + - strung + - stuck + - stung + - stunk + - sung + - sunk + - swept + - swollen + - sworn + - swum + - swung + - taken + - taught + - thought + - thrived + - thrown + - thrust + - told + - torn + - trodden + - understood + - upheld + - upset + - wed + - wept + - withheld + - withstood + - woken + - won + - worn + - wound + - woven + - written + - wrung diff --git a/vale/styles/Custom/Periods.yml b/vale/styles/Custom/Periods.yml new file mode 100644 index 00000000000..d24a6a6c033 --- /dev/null +++ b/vale/styles/Custom/Periods.yml @@ -0,0 +1,7 @@ +extends: existence +message: "Don't use periods with acronyms or initialisms such as '%s'." +link: 'https://developers.google.com/style/abbreviations' +level: error +nonword: true +tokens: + - '\b(?:[A-Z]\.){3,}' diff --git a/vale/styles/Custom/Quotes.yml b/vale/styles/Custom/Quotes.yml new file mode 100644 index 00000000000..3cb6f1abd18 --- /dev/null +++ b/vale/styles/Custom/Quotes.yml @@ -0,0 +1,7 @@ +extends: existence +message: "Commas and periods go inside quotation marks." +link: 'https://developers.google.com/style/quotation-marks' +level: error +nonword: true +tokens: + - '"[^"]+"[.,?]' diff --git a/vale/styles/Custom/Ranges.yml b/vale/styles/Custom/Ranges.yml new file mode 100644 index 00000000000..3ec045e777d --- /dev/null +++ b/vale/styles/Custom/Ranges.yml @@ -0,0 +1,7 @@ +extends: existence +message: "Don't add words such as 'from' or 'between' to describe a range of numbers." +link: 'https://developers.google.com/style/hyphens' +nonword: true +level: warning +tokens: + - '(?:from|between)\s\d+\s?-\s?\d+' diff --git a/vale/styles/Custom/Semicolons.yml b/vale/styles/Custom/Semicolons.yml new file mode 100644 index 00000000000..bb8b85b420e --- /dev/null +++ b/vale/styles/Custom/Semicolons.yml @@ -0,0 +1,8 @@ +extends: existence +message: "Use semicolons judiciously." +link: 'https://developers.google.com/style/semicolons' +nonword: true +scope: sentence +level: suggestion +tokens: + - ';' diff --git a/vale/styles/Custom/Slang.yml b/vale/styles/Custom/Slang.yml new file mode 100644 index 00000000000..63f4c248a84 --- /dev/null +++ b/vale/styles/Custom/Slang.yml @@ -0,0 +1,11 @@ +extends: existence +message: "Don't use internet slang abbreviations such as '%s'." +link: 'https://developers.google.com/style/abbreviations' +ignorecase: true +level: error +tokens: + - 'tl;dr' + - ymmv + - rtfm + - imo + - fwiw diff --git a/vale/styles/Custom/Spacing.yml b/vale/styles/Custom/Spacing.yml new file mode 100644 index 00000000000..66e45a6b72a --- /dev/null +++ b/vale/styles/Custom/Spacing.yml @@ -0,0 +1,10 @@ +extends: existence +message: "'%s' should have one space." +link: 'https://developers.google.com/style/sentence-spacing' +level: error +nonword: true +action: + name: remove +tokens: + - '[a-z][.?!] {2,}[A-Z]' + - '[a-z][.?!][A-Z]' diff --git a/vale/styles/Custom/Spelling.yml b/vale/styles/Custom/Spelling.yml new file mode 100644 index 00000000000..527ac07d318 --- /dev/null +++ b/vale/styles/Custom/Spelling.yml @@ -0,0 +1,10 @@ +extends: existence +message: "In general, use American spelling instead of '%s'." +link: 'https://developers.google.com/style/spelling' +ignorecase: true +level: warning +tokens: + - '(?:\w+)nised?' + - 'colour' + - 'labour' + - 'centre' diff --git a/vale/styles/Custom/Units.yml b/vale/styles/Custom/Units.yml new file mode 100644 index 00000000000..53522ab2dea --- /dev/null +++ b/vale/styles/Custom/Units.yml @@ -0,0 +1,8 @@ +extends: existence +message: "Put a nonbreaking space between the number and the unit in '%s'." +link: "https://developers.google.com/style/units-of-measure" +nonword: true +level: error +tokens: + - \b\d+(?:B|kB|MB|GB|TB) + - \b\d+(?:ns|ms|s|min|h|d) diff --git a/vale/styles/Custom/We.yml b/vale/styles/Custom/We.yml new file mode 100644 index 00000000000..c7ac7d36221 --- /dev/null +++ b/vale/styles/Custom/We.yml @@ -0,0 +1,11 @@ +extends: existence +message: "Try to avoid using first-person plural like '%s'." +link: 'https://developers.google.com/style/pronouns#personal-pronouns' +level: warning +ignorecase: true +tokens: + - we + - we'(?:ve|re) + - ours? + - us + - let's diff --git a/vale/styles/Custom/Will.yml b/vale/styles/Custom/Will.yml new file mode 100644 index 00000000000..128a918362b --- /dev/null +++ b/vale/styles/Custom/Will.yml @@ -0,0 +1,7 @@ +extends: existence +message: "Avoid using '%s'." +link: 'https://developers.google.com/style/tense' +ignorecase: true +level: warning +tokens: + - will diff --git a/vale/styles/Custom/WordList.yml b/vale/styles/Custom/WordList.yml new file mode 100644 index 00000000000..bb53e8f7471 --- /dev/null +++ b/vale/styles/Custom/WordList.yml @@ -0,0 +1,82 @@ +extends: substitution +message: "Use '%s' instead of '%s'." +link: "https://developers.google.com/style/word-list" +level: warning +ignorecase: false +action: + name: replace +swap: + "(?:API Console|dev|developer) key": API key + "(?:cell ?phone|smart ?phone)": phone|mobile phone + "(?:dev|developer|APIs) console": API console + "(?:e-mail|Email|E-mail)": email + "(?:file ?path|path ?name)": path + "(?:kill|terminate|abort)": stop|exit|cancel|end + "(?:OAuth ?2|Oauth)": OAuth 2.0 + "(?:ok|Okay)": OK|okay + "(?:WiFi|wifi)": Wi-Fi + "(?i)postgresql": Postgres + "(?i)repository": repo + '[\.]+apk': APK + '3\-D': 3D + 'Google (?:I\-O|IO)': Google I/O + "tap (?:&|and) hold": touch & hold + "un(?:check|select)": clear + above: preceding + account name: username + action bar: app bar + admin: administrator + Ajax: AJAX + a\.k\.a|aka: or|also known as + Android device: Android-powered device + android: Android + API explorer: APIs Explorer + application: app + approx\.: approximately + authN: authentication + authZ: authorization + autoupdate: automatically update + cellular data: mobile data + cellular network: mobile network + chapter: documents|pages|sections + check box: checkbox + check: select + click on: click|click in + Cloud: Google Cloud Platform|GCP + Container Engine: Kubernetes Engine + content type: media type + curated roles: predefined roles + data are: data is + Developers Console: Google API Console|API Console + disabled?: turn off|off + ephemeral IP address: ephemeral external IP address + fewer data: less data + file name: filename + firewalls: firewall rules + functionality: capability|feature + Google account: Google Account + Google accounts: Google Accounts + Googling: search with Google + grayed-out: unavailable + HTTPs: HTTPS + in order to: to + ingest: import|load + k8s: Kubernetes + long press: touch & hold + network IP address: internal IP address + omnibox: address bar + open-source: open source + overview screen: recents screen + regex: regular expression + SHA1: SHA-1|HAS-SHA1 + sign into: sign in to + sign-?on: single sign-on + static IP address: static external IP address + stylesheet: style sheet + synch: sync + tablename: table name + tablet: device + touch: tap + url: URL + vs\.: versus + World Wide Web: web diff --git a/vale/styles/Custom/meta.json b/vale/styles/Custom/meta.json new file mode 100644 index 00000000000..a5da2a8480e --- /dev/null +++ b/vale/styles/Custom/meta.json @@ -0,0 +1,4 @@ +{ + "feed": "https://github.com/errata-ai/Google/releases.atom", + "vale_version": ">=1.0.0" +} diff --git a/vale/styles/Custom/vocab.txt b/vale/styles/Custom/vocab.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/vale/styles/config/vocabularies/Supabase/accept.txt b/vale/styles/config/vocabularies/Supabase/accept.txt new file mode 100644 index 00000000000..f02c243b654 --- /dev/null +++ b/vale/styles/config/vocabularies/Supabase/accept.txt @@ -0,0 +1,18 @@ +ChatGPT +Clippy +Colab +CPUs? +[Dd]eduplicat(e|ion) +GPUs? +IVFFlat +OpenAI +[Pp]erformant +pgvector +Postgres +repo +Roboflow +[Ss]crollable +SQLAlchemy +Supabase +[Uu]psert + From 27c752de1774323646ff6eff526276d38f0642a7 Mon Sep 17 00:00:00 2001 From: Charis <26616127+charislam@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:13:13 -0500 Subject: [PATCH 13/50] docs: update contributing guide for new repo organization (#21470) --- apps/docs/CONTRIBUTING.md | 54 ++++++++++----------------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/apps/docs/CONTRIBUTING.md b/apps/docs/CONTRIBUTING.md index cc5845c1cec..fa482554221 100644 --- a/apps/docs/CONTRIBUTING.md +++ b/apps/docs/CONTRIBUTING.md @@ -70,7 +70,7 @@ They shouldn't include: ## Repo organization -Most docs pages are contained in the `apps/docs/pages` directory. Some docs sections are federated from other repositories, for example [`pg_graphql`](https://github.com/supabase/pg_graphql/tree/master/docs). Reference docs are generated from spec files in the `spec` directory. +Most docs pages are contained in the `apps/docs/content` directory. Some docs sections are federated from other repositories, for example [`pg_graphql`](https://github.com/supabase/pg_graphql/tree/master/docs). Reference docs are generated from spec files in the `spec` directory. You can usually identify a federated or reference doc because it uses a Next.js dynamic route (for example, `[[...slug]].tsx`). Look for the spec file import or the repo definition to find the content location. @@ -98,43 +98,16 @@ The Supabase docs use [MDX](https://mdxjs.com/). Guides are written in unstructu Adding a new guide requires: -- A layout -- Metadata -- A page export +- YAML frontmatter - A navigation entry (in a separate file) -```js -// required import -import Layout from '~/layouts/DefaultGuideLayout' +Frontmatter looks like this. `title` is mandatory. There are also optional properties that you can use to control the page display, including `subtitle`, `tocVideo`, and `hideToc`. - -/* - * required metadata fields - * title: required - page title - * description: required - page description - * - * optional metadata fields - * id: optional - not currently being used - * subtitle: optional - displayed below the title - * sidebar_label: optional - if you want the sidebar text to be different from the title - * hide_table_of_contents: optional - hides the table of contents on the right side - * tocVideo: optional - a YouTube slug, displays the video above the table of contents - */ -export const meta = { - id: 'nextjs-server-components', - title: 'Supabase Auth with Next.js Server Components', - description: - 'Authentication helpers for creating an authenticated Supabase client in Next.js 13 app directory Server Components.', - sidebar_label: 'Next.js Server Components', -} - -// content -You can use **Markdown syntax**. - -// required export -export const Page = ({ children }) => - -export default Page +```yaml +--- +title: How to connect to Supabase +hideToc: true +--- ``` The navigation is defined in [`NavigationMenu.constants.ts`](https://github.com/supabase/supabase/blob/master/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts). @@ -305,13 +278,12 @@ The `queryGroup` param is optional. It lets you link directly to a tab by using Include videos as TOC (Table of Contents) videos rather than putting them in the main text. -You can define a TOC video in the page metadata: +You can define a TOC video in the page frontmatter: -```js -export const meta = { - ... - tocVideo: 'rzglqRdZUQE', -} +```yaml +--- +tocVideo: 'rzglqRdZUQE', +--- ``` ## Styling, formatting, and grammar From 9484436d96d009b961693740fcc2c507bdeaea55 Mon Sep 17 00:00:00 2001 From: Copple <10214025+kiwicopple@users.noreply.github.com> Date: Fri, 23 Feb 2024 20:46:54 +0100 Subject: [PATCH 14/50] docs: Maturity model - making it even clearer (#21485) * docs: Maturity model - making it even clearer * Update apps/docs/content/guides/platform/maturity-model.mdx * Update apps/docs/content/guides/platform/maturity-model.mdx * remove hardcoded part from the link --------- Co-authored-by: Rodrigo Mansueli Nunes --- apps/docs/content/guides/platform/maturity-model.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/docs/content/guides/platform/maturity-model.mdx b/apps/docs/content/guides/platform/maturity-model.mdx index 1a4f414063e..8bcad22377b 100644 --- a/apps/docs/content/guides/platform/maturity-model.mdx +++ b/apps/docs/content/guides/platform/maturity-model.mdx @@ -22,12 +22,14 @@ Resources: ## In production -Once your application is live, you should never change your database using the Dashboard. Supabase provides various [access levels](https://supabase.com/docs/guides/platform/access-control) for the Dashboard that can help enforce this. Some other important things to consider at this point include: +Once your application is live, you should never change your database using the Dashboard - everything should be done with [Migrations](/docs/guides/cli/managing-environments#create-a-new-migration). Some other important things to consider at this point include: -- Read the [Production Checklist](/docs/guides/platform/going-into-prod). -- Make your team aware of the [Shared Responsibilities](/docs/guides/platform/shared-responsibility-model) between your organization and Supabase. -- Design a [safe workflow](https://supabase.com/docs/guides/platform/shared-responsibility-model#you-decide-your-own-workflow) for managing your database. We strongly recommend running [multiple environments](/docs/guides/cli/managing-environments) as part of your development workflow (`local` -> `staging` -> `prod`). +- The Dashboard has various [access levels](/docs/guides/platform/access-control) that can prevent changes being made via the UI. +- Design a [safe workflow](/docs/guides/platform/shared-responsibility-model#you-decide-your-own-workflow) for managing your database. We strongly recommend running [multiple environments](/docs/guides/cli/managing-environments) as part of your development workflow (`local` -> `staging` -> `prod`). +- Do not share any production passwords with your team, _especially_ your `postgres` password. All changes should be made via version-controlled migrations which run via a bastion host or a CI platform (like [GitHub Actions](/docs/guides/cli/managing-environments#configure-github-actions). If you use GitHub Actions, use [approval workflows](https://docs.github.com/en/actions/managing-workflow-runs/reviewing-deployments) to prevent any migrations being run accidentally. +- Restrict production access to your database using [Network Restrictions](/docs/guides/platform/network-restrictions). - As your database to grows, we strongly recommend moving to [Point-in-Time Recovery](/docs/guides/platform/backups#point-in-time-recovery). This is safer and has less impact on your database performance during maintenance windows. +- Read the [Production Checklist](/docs/guides/platform/going-into-prod) and familiarize your team with the [Shared Responsibilities](/docs/guides/platform/shared-responsibility-model) between your organization and Supabase. Resources: From 3349468023fe9bbc1ded0eac6a08e99745070091 Mon Sep 17 00:00:00 2001 From: Francesco Sansalvadore Date: Fri, 23 Feb 2024 21:46:50 +0100 Subject: [PATCH 15/50] fix open source card height (#21456) --- apps/www/components/OpenSource/RepoCard.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/www/components/OpenSource/RepoCard.tsx b/apps/www/components/OpenSource/RepoCard.tsx index 2d537678aa1..1b873bf04b7 100644 --- a/apps/www/components/OpenSource/RepoCard.tsx +++ b/apps/www/components/OpenSource/RepoCard.tsx @@ -10,10 +10,12 @@ const RepoCard = ({ repo, activeTab, index }: { repo: any; activeTab: number; in initial={{ opacity: 0, y: 5 }} animate={{ opacity: 1, y: 0, transition: { delay: 0 + index / 25 } }} exit={{ opacity: 0, y: 5, transition: { duration: 0.05 } }} + className="h-full" > - +
@@ -38,7 +40,7 @@ const RepoCard = ({ repo, activeTab, index }: { repo: any; activeTab: number; in

{repo.description}

-
+

{repo.full_name}

From 79d806ad22624baf086df7385827dc73e9a38316 Mon Sep 17 00:00:00 2001 From: Francesco Sansalvadore Date: Sat, 24 Feb 2024 06:01:26 +0100 Subject: [PATCH 16/50] improve initial load (#21496) * lazy hide nav and footer * remove mount useEffect * eager load supabase logo in nav * remove mount check in footer * improve initial load layout shifts --- apps/www/components/Footer/index.tsx | 17 +++------------- apps/www/components/Hero/Hero.tsx | 10 ++------- apps/www/components/Layouts/Default.tsx | 4 ++-- apps/www/components/Nav/index.tsx | 27 +++++++++---------------- 4 files changed, 17 insertions(+), 41 deletions(-) diff --git a/apps/www/components/Footer/index.tsx b/apps/www/components/Footer/index.tsx index e933a405c4a..cc3d28c87dd 100644 --- a/apps/www/components/Footer/index.tsx +++ b/apps/www/components/Footer/index.tsx @@ -1,4 +1,3 @@ -import { useEffect, useState } from 'react' import Link from 'next/link' import { useTheme } from 'next-themes' import { Badge, IconDiscord, IconGitHubSolid, IconTwitterX, IconYoutubeSolid, cn } from 'ui' @@ -14,6 +13,7 @@ import { ThemeToggle } from 'ui-patterns/ThemeToggle' interface Props { className?: string + hideFooter?: boolean } const Footer = (props: Props) => { @@ -23,18 +23,7 @@ const Footer = (props: Props) => { const isLaunchWeek = pathname.includes('launch-week') const forceDark = isLaunchWeek || pathname === '/' - /** - * Temporary fix for next-theme client side bug - * https://github.com/pacocoursey/next-themes/issues/169 - * TODO: remove when bug has been fixed - */ - const [mounted, setMounted] = useState(false) - - useEffect(() => { - setMounted(true) - }, []) - - if (!mounted) { + if (props.hideFooter) { return null } @@ -75,7 +64,7 @@ const Footer = (props: Props) => { src={ forceDark ? supabaseLogoWordmarkDark - : mounted && resolvedTheme?.includes('dark') + : resolvedTheme?.includes('dark') ? supabaseLogoWordmarkDark : supabaseLogoWordmarkLight } diff --git a/apps/www/components/Hero/Hero.tsx b/apps/www/components/Hero/Hero.tsx index ca54e4aeea3..a6082ccfe61 100644 --- a/apps/www/components/Hero/Hero.tsx +++ b/apps/www/components/Hero/Hero.tsx @@ -3,10 +3,9 @@ import { useRouter } from 'next/router' import Telemetry, { TelemetryEvent } from '~/lib/telemetry' import { useTelemetryProps } from 'common/hooks/useTelemetryProps' import gaEvents from '~/lib/gaEvents' -import { Button, IconBookOpen, cn } from 'ui' +import { Button, IconBookOpen } from 'ui' import SectionContainer from '~/components/Layouts/SectionContainer' import HeroFrameworks from './HeroFrameworks' -import styles from './hero.module.css' const Hero = () => { const router = useRouter() @@ -21,12 +20,7 @@ const Hero = () => {
-
+
{/*
{ return ( <> - {!hideHeader &&
-
+
{!isUserLoading && ( <> From 321594b3bef7c83ada571d53922138c055a18c44 Mon Sep 17 00:00:00 2001 From: Charlie Coppinger Date: Mon, 26 Feb 2024 15:16:22 +1300 Subject: [PATCH 17/50] fix: introduce missing sveltekit icon causing an error in a connections component (#21540) duplicate svelte icon using sveltekit filename --- .../public/img/libraries/sveltekit-icon.svg | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 apps/studio/public/img/libraries/sveltekit-icon.svg diff --git a/apps/studio/public/img/libraries/sveltekit-icon.svg b/apps/studio/public/img/libraries/sveltekit-icon.svg new file mode 100644 index 00000000000..4bf279659a9 --- /dev/null +++ b/apps/studio/public/img/libraries/sveltekit-icon.svg @@ -0,0 +1,20 @@ + + + + + + + From 052dc6c53f4caf45463439a9abf23441acddf4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Gr=C3=BCneberg?= Date: Mon, 26 Feb 2024 10:54:58 +0800 Subject: [PATCH 18/50] chore: bump Stripe deps (#21541) --- apps/studio/package.json | 4 ++-- package-lock.json | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/studio/package.json b/apps/studio/package.json index ac8145c8553..b97f0a09088 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -29,8 +29,8 @@ "@scaleleap/pg-format": "^1.0.0", "@sentry/nextjs": "^7.77.0", "@serafin/schema-builder": "^0.18.2", - "@stripe/react-stripe-js": "^2.3.1", - "@stripe/stripe-js": "^2.1.11", + "@stripe/react-stripe-js": "^2.5.0", + "@stripe/stripe-js": "^3.0.5", "@supabase/auth-helpers-react": "^0.4.2", "@supabase/shared-types": "0.1.55", "@supabase/supabase-js": "^2.39.3", diff --git a/package-lock.json b/package-lock.json index 127b9226f16..7aa43d9883b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -778,8 +778,8 @@ "@scaleleap/pg-format": "^1.0.0", "@sentry/nextjs": "^7.77.0", "@serafin/schema-builder": "^0.18.2", - "@stripe/react-stripe-js": "^2.3.1", - "@stripe/stripe-js": "^2.1.11", + "@stripe/react-stripe-js": "^2.5.0", + "@stripe/stripe-js": "^3.0.5", "@supabase/auth-helpers-react": "^0.4.2", "@supabase/shared-types": "0.1.55", "@supabase/supabase-js": "^2.39.3", @@ -10839,20 +10839,25 @@ } }, "node_modules/@stripe/react-stripe-js": { - "version": "2.3.1", - "license": "MIT", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-2.5.0.tgz", + "integrity": "sha512-ys5bnrufNoBlUPRblWkiN7dUCX3s2noBZS0Lf5GkHYO9x3SXJMZccif53IdP4X6tZyNLn7aSMgZBUZqsdzrvhg==", "dependencies": { "prop-types": "^15.7.2" }, "peerDependencies": { - "@stripe/stripe-js": "^1.44.1 || ^2.0.0", + "@stripe/stripe-js": "^1.44.1 || ^2.0.0 || ^3.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/@stripe/stripe-js": { - "version": "2.1.11", - "license": "MIT" + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-3.0.5.tgz", + "integrity": "sha512-0BTd2bC+8gSKty7jXKRntLnvmWgFTmpZkY0oP7ADBYfdV0JtuGoDbfQawui0W5eUlwT3CcKh2IeRV4SPOBIeXQ==", + "engines": { + "node": ">=12.16" + } }, "node_modules/@supabase/auth-helpers-react": { "version": "0.4.2", From 36cac47e50fed7d0f83f1cd415b93d0bbf2d38b2 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 26 Feb 2024 12:30:45 +0900 Subject: [PATCH 19/50] docs: Clarified Apple sign in instruction for Flutter (#21542) Clarified Apple sign in instruction for Flutter --- .../content/guides/auth/social-login/auth-apple.mdx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/docs/content/guides/auth/social-login/auth-apple.mdx b/apps/docs/content/guides/auth/social-login/auth-apple.mdx index 1bc10b0de90..daa141be5f0 100644 --- a/apps/docs/content/guides/auth/social-login/auth-apple.mdx +++ b/apps/docs/content/guides/auth/social-login/auth-apple.mdx @@ -240,15 +240,16 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app, 1. Have an **App ID** which uniquely identifies the app you are building. You can create a new App ID from the [Identifiers](https://developer.apple.com/account/resources/identifiers/list/bundleId) section in the Apple Developer Console (use the filter menu in the upper right side to see all App IDs). These usually are a reverse domain name string, for example `com.example.app`. Make sure you configure Sign in with Apple for the App ID you created or already have, in the Capabilities list. At this time Supabase Auth does not support Server-to-Server notification endpoints, so you should leave that setting blank. (In the past App IDs were referred to as _bundle IDs._) 2. Register all of the App IDs that will be using your Supabase project in the [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Authorized Client IDs_. - - - If you're building a native app only, you do not need to configure the OAuth settings. - - - ## Apple sign in on Android, Web, Windows and Linux For platforms that doesn't support native Apple sign in, you can use the `signInWithOAuth()` method to perform the Apple sign in. + + + + Do **NOT** follow the Android or Web setup instructions on [sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple) package README for these platforms. sign_in_with_apple package is not used for performing Apple sign-in on non-Apple platforms for Supabase. + + + This method of signing in is web based, and will open a browser window to perform the sign in. For non-web platforms, the user is brought back to the app via [deep linking](/docs/guides/auth/native-mobile-deep-linking?platform=flutter). ```dart From 05edf56f5503a136bf45335cc8f93e8a68a00f46 Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Mon, 26 Feb 2024 12:50:29 +0800 Subject: [PATCH 20/50] fix: browser jwt generation (#21544) --- apps/studio/lib/role-impersonation.ts | 91 +++++++++++++-------------- 1 file changed, 43 insertions(+), 48 deletions(-) diff --git a/apps/studio/lib/role-impersonation.ts b/apps/studio/lib/role-impersonation.ts index 781aab9b7d8..634045fc9ec 100644 --- a/apps/studio/lib/role-impersonation.ts +++ b/apps/studio/lib/role-impersonation.ts @@ -112,7 +112,49 @@ export function wrapWithRoleImpersonation( ` } -export async function getRoleImpersonationJWT( +function encodeText(data: string) { + return new TextEncoder().encode(data) +} + +function encodeBase64Url(data: ArrayBuffer | Uint8Array | string): string { + return btoa( + String.fromCharCode(...new Uint8Array(typeof data === 'string' ? encodeText(data) : data)) + ) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, '') +} + +function genKey(rawKey: string) { + return window.crypto.subtle.importKey( + 'raw', + encodeText(rawKey), + { name: 'HMAC', hash: 'SHA-256' }, + false, + ['sign', 'verify'] + ) +} + +async function createToken(jwtPayload: object, key: string) { + const headerAndPayload = + encodeBase64Url(encodeText(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))) + + '.' + + encodeBase64Url(encodeText(JSON.stringify(jwtPayload))) + + const signature = encodeBase64Url( + new Uint8Array( + await window.crypto.subtle.sign( + { name: 'HMAC' }, + await genKey(key), + encodeText(headerAndPayload) + ) + ) + ) + + return `${headerAndPayload}.${signature}` +} + +export function getRoleImpersonationJWT( projectRef: string, jwtSecret: string, role: PostgrestImpersonationRole @@ -120,50 +162,3 @@ export async function getRoleImpersonationJWT( const claims = getPostgrestClaims(projectRef, role) return createToken(claims, jwtSecret) } - -async function createToken(payload: object, key: string) { - const header = { typ: 'JWT', alg: 'HS256' } - - const segments = [] - segments.push(btoa(JSON.stringify(header)).replace(/=/g, '')) - segments.push(btoa(JSON.stringify(payload)).replace(/=/g, '')) - - const footer = await sign(segments.join('.'), btoa(key).replace(/=/g, '')) - segments.push(footer.replace(/=/g, '')) - return segments.join('.') -} - -async function sign(data: string, key: string) { - return window.crypto.subtle - .importKey( - 'jwk', - { - //this is an example jwk key, "raw" would be an ArrayBuffer - kty: 'oct', - k: key, - alg: 'HS256', - }, - { - name: 'HMAC', - hash: { name: 'SHA-256' }, - }, - false, - ['sign', 'verify'] - ) - .then((key) => { - const jsonString = JSON.stringify(data) - const encodedData = new TextEncoder().encode(jsonString) - return window.crypto.subtle.sign( - { - name: 'HMAC', - }, - key, - encodedData - ) - }) - .then((token) => { - const u8 = new Uint8Array(token) - const b64encoded = btoa(String.fromCharCode(...u8)) - return b64encoded - }) -} From dcdc3cd23083fa7d9fb76bca278ef6bf050066bc Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Mon, 26 Feb 2024 14:21:42 +0800 Subject: [PATCH 21/50] Fix table editor unable to update PK after renaming table (#21285) * Fix table editor unable to update PK after renaming table * Lint --- .../ColumnEditor/ColumnEditor.tsx | 20 +++++- .../SidePanelEditor/SidePanelEditor.tsx | 10 ++- .../SidePanelEditor/SidePanelEditor.utils.tsx | 40 ++++++++--- .../TableEditor/TableEditor.tsx | 17 +++++ .../studio/data/database/constraints-query.ts | 69 +++++++++++++++++++ .../data/database/database-query-constants.ts | 9 --- 6 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 apps/studio/data/database/constraints-query.ts diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx index a5b13a8aa1f..0d63b7684fb 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnEditor.tsx @@ -40,6 +40,11 @@ import { import ColumnForeignKey from './ColumnForeignKey' import ColumnType from './ColumnType' import HeaderTitle from './HeaderTitle' +import { + CONSTRAINT_TYPE, + Constraint, + useTableConstraintsQuery, +} from 'data/database/constraints-query' export interface ColumnEditorProps { column?: PostgresColumn @@ -50,7 +55,8 @@ export interface ColumnEditorProps { payload: CreateColumnPayload | UpdateColumnPayload, isNewRecord: boolean, configuration: { - columnId: string | undefined + columnId?: string + primaryKey?: Constraint }, resolve: any ) => void @@ -80,6 +86,16 @@ const ColumnEditor = ({ (type) => !EXCLUDED_SCHEMAS_WITHOUT_EXTENSIONS.includes(type.schema) ) + const { data: constraints } = useTableConstraintsQuery({ + projectRef: project?.ref, + connectionString: project?.connectionString, + schema: selectedTable?.schema, + table: selectedTable?.name, + }) + const primaryKey = (constraints ?? []).find( + (constraint) => constraint.type === CONSTRAINT_TYPE.PRIMARY_KEY_CONSTRAINT + ) + const { data } = useForeignKeyConstraintsQuery({ projectRef: project?.ref, connectionString: project?.connectionString, @@ -131,7 +147,7 @@ const ColumnEditor = ({ const payload = isNewRecord ? generateCreateColumnPayload(selectedTable.id, columnFields) : generateUpdateColumnPayload(column!, selectedTable, columnFields) - const configuration = { columnId: column?.id } + const configuration = { columnId: column?.id, primaryKey } saveChanges(payload, isNewRecord, configuration, resolve) } else { resolve() diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.tsx index bfacdc7e05e..b0f85d5ac50 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.tsx @@ -38,6 +38,7 @@ import { updateTable, } from './SidePanelEditor.utils' import { ImportContent } from './TableEditor/TableEditor.types' +import { Constraint } from 'data/database/constraints-query' export interface SidePanelEditorProps { editable?: boolean @@ -201,11 +202,11 @@ const SidePanelEditor = ({ const saveColumn = async ( payload: CreateColumnPayload | UpdateColumnPayload, isNewRecord: boolean, - configuration: { columnId?: string }, + configuration: { columnId?: string; primaryKey?: Constraint }, resolve: any ) => { const selectedColumnToEdit = snap.sidePanel?.type === 'column' && snap.sidePanel.column - const { columnId } = configuration + const { columnId, primaryKey } = configuration const response = isNewRecord ? await createColumn({ @@ -213,6 +214,7 @@ const SidePanelEditor = ({ connectionString: project?.connectionString, payload: payload as CreateColumnPayload, selectedTable: selectedTable as PostgresTable, + primaryKey, }) : await updateColumn({ projectRef: project?.ref!, @@ -220,6 +222,7 @@ const SidePanelEditor = ({ id: columnId as string, payload: payload as UpdateColumnPayload, selectedTable: selectedTable as PostgresTable, + primaryKey, }) if (response?.error) { @@ -361,6 +364,7 @@ const SidePanelEditor = ({ isRealtimeEnabled: boolean isDuplicateRows: boolean existingForeignKeyRelations: ForeignKeyConstraint[] + primaryKey?: Constraint }, resolve: any ) => { @@ -372,6 +376,7 @@ const SidePanelEditor = ({ isRealtimeEnabled, isDuplicateRows, existingForeignKeyRelations, + primaryKey, } = configuration try { @@ -436,6 +441,7 @@ const SidePanelEditor = ({ columns, foreignKeyRelations, existingForeignKeyRelations, + primaryKey, }) await updateTableRealtime(table, isRealtimeEnabled) diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.utils.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.utils.tsx index 7587564ac8b..0ad5c98e484 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.utils.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.utils.tsx @@ -33,6 +33,7 @@ import { ForeignKey } from './ForeignKeySelector/ForeignKeySelector.types' import { ColumnField, CreateColumnPayload, UpdateColumnPayload } from './SidePanelEditor.types' import { checkIfRelationChanged } from './TableEditor/ForeignKeysManagement/ForeignKeysManagement.utils' import { ImportContent } from './TableEditor/TableEditor.types' +import { Constraint } from 'data/database/constraints-query' const BATCH_SIZE = 1000 const CHUNK_SIZE = 1024 * 1024 * 0.1 // 0.1MB @@ -112,18 +113,19 @@ export const addPrimaryKey = async ( }) } -export const removePrimaryKey = async ( +export const dropConstraint = async ( projectRef: string, connectionString: string | undefined, schema: string, - table: string + table: string, + name: string ) => { - const query = `ALTER TABLE "${schema}"."${table}" DROP CONSTRAINT "${table}_pkey"` + const query = `ALTER TABLE "${schema}"."${table}" DROP CONSTRAINT "${name}"` return await executeSql({ projectRef: projectRef, connectionString: connectionString, sql: query, - queryKey: ['primary-keys'], + queryKey: ['drop-constraint'], }) } @@ -266,11 +268,13 @@ export const createColumn = async ({ connectionString, payload, selectedTable, + primaryKey, }: { projectRef: string connectionString: string | undefined payload: CreateColumnPayload selectedTable: PostgresTable + primaryKey?: Constraint }) => { const toastId = toast.loading(`Creating column "${payload.name}"...`) try { @@ -288,8 +292,14 @@ export const createColumn = async ({ // Same logic in createTable: Remove any primary key constraints first (we'll add it back later) const existingPrimaryKeys = selectedTable.primary_keys.map((x) => x.name) - if (existingPrimaryKeys.length > 0) { - await removePrimaryKey(projectRef, connectionString, column.schema, column.table) + if (existingPrimaryKeys.length > 0 && primaryKey !== undefined) { + await dropConstraint( + projectRef, + connectionString, + column.schema, + column.table, + primaryKey.name + ) } const primaryKeyColumns = existingPrimaryKeys.concat([column.name]) @@ -314,6 +324,7 @@ export const updateColumn = async ({ id, payload, selectedTable, + primaryKey, skipPKCreation, skipSuccessMessage = false, }: { @@ -322,6 +333,7 @@ export const updateColumn = async ({ id: string payload: UpdateColumnPayload selectedTable: PostgresTable + primaryKey?: Constraint skipPKCreation?: boolean skipSuccessMessage?: boolean }) => { @@ -338,8 +350,14 @@ export const updateColumn = async ({ const existingPrimaryKeys = selectedTable.primary_keys.map((x) => x.name) // Primary key is getting updated for the column - if (existingPrimaryKeys.length > 0) { - await removePrimaryKey(projectRef, connectionString, column.schema, column.table) + if (existingPrimaryKeys.length > 0 && primaryKey !== undefined) { + await dropConstraint( + projectRef, + connectionString, + column.schema, + column.table, + primaryKey.name + ) } const primaryKeyColumns = isPrimaryKey @@ -632,6 +650,7 @@ export const updateTable = async ({ columns, foreignKeyRelations, existingForeignKeyRelations, + primaryKey, }: { projectRef: string connectionString: string | undefined @@ -641,6 +660,7 @@ export const updateTable = async ({ columns: ColumnField[] foreignKeyRelations: ForeignKey[] existingForeignKeyRelations: ForeignKeyConstraint[] + primaryKey?: Constraint }) => { // Prepare a check to see if primary keys to the tables were updated or not const primaryKeyColumns = columns @@ -655,8 +675,8 @@ export const updateTable = async ({ // If we do it later, and if the user deleted a PK column, we'd need to do // an additional check when removing PK if the column in the PK was removed // So doing this one step earlier, lets us skip that additional check. - if (table.primary_keys.length > 0) { - await removePrimaryKey(projectRef, connectionString, table.schema, table.name) + if (primaryKey !== undefined) { + await dropConstraint(projectRef, connectionString, table.schema, table.name, primaryKey.name) } } diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableEditor.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableEditor.tsx index 2433c8c413c..d69ee875b54 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableEditor.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableEditor.tsx @@ -32,6 +32,11 @@ import { generateTableFieldFromPostgresTable, validateFields, } from './TableEditor.utils' +import { + CONSTRAINT_TYPE, + Constraint, + useTableConstraintsQuery, +} from 'data/database/constraints-query' export interface TableEditorProps { table?: PostgresTable @@ -54,6 +59,7 @@ export interface TableEditorProps { isRealtimeEnabled: boolean isDuplicateRows: boolean existingForeignKeyRelations: ForeignKeyConstraint[] + primaryKey?: Constraint }, resolve: any ) => void @@ -103,6 +109,16 @@ const TableEditor = ({ const [isImportingSpreadsheet, setIsImportingSpreadsheet] = useState(false) const [rlsConfirmVisible, setRlsConfirmVisible] = useState(false) + const { data: constraints } = useTableConstraintsQuery({ + projectRef: project?.ref, + connectionString: project?.connectionString, + schema: table?.schema, + table: table?.name, + }) + const primaryKey = (constraints ?? []).find( + (constraint) => constraint.type === CONSTRAINT_TYPE.PRIMARY_KEY_CONSTRAINT + ) + const { data: foreignKeyMeta } = useForeignKeyConstraintsQuery({ projectRef: project?.ref, connectionString: project?.connectionString, @@ -173,6 +189,7 @@ const TableEditor = ({ isRealtimeEnabled: tableFields.isRealtimeEnabled, isDuplicateRows: isDuplicateRows, existingForeignKeyRelations: foreignKeys, + primaryKey, } saveChanges(payload, tableFields.columns, fkRelations, isNewRecord, configuration, resolve) diff --git a/apps/studio/data/database/constraints-query.ts b/apps/studio/data/database/constraints-query.ts new file mode 100644 index 00000000000..2c7db7134e7 --- /dev/null +++ b/apps/studio/data/database/constraints-query.ts @@ -0,0 +1,69 @@ +import { UseQueryOptions } from '@tanstack/react-query' +import { ExecuteSqlData, useExecuteSqlQuery } from '../sql/execute-sql-query' + +type GetTableConstraintsVariables = { + schema?: string + table?: string +} + +export type Constraint = { + id: number + name: string + type: string +} + +export enum CONSTRAINT_TYPE { + CHECK_CONSTRAINT = 'c', + FOREIGN_KEY_CONSTRAINT = 'f', + PRIMARY_KEY_CONSTRAINT = 'p', + UNIQUE_CONSTRAINT = 'u', + CONSTRAINT_TRIGGER = 't', + EXCLUSION_CONSTRAINT = 'x', +} + +export const getTableConstraints = ({ schema, table }: GetTableConstraintsVariables) => { + const sql = /* SQL */ ` + SELECT + con.oid as id, + con.conname as name, + con.contype as type + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel + ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp + ON nsp.oid = connamespace + WHERE nsp.nspname = '${schema}' + AND rel.relname = '${table}'; +`.trim() + + return sql +} + +export type TableConstraintsVariables = GetTableConstraintsVariables & { + projectRef?: string + connectionString?: string +} + +export type TableConstraintsData = Constraint[] +export type TableConstraintsError = unknown + +export const useTableConstraintsQuery = ( + { projectRef, connectionString, schema, table }: TableConstraintsVariables, + options: UseQueryOptions = {} +) => { + return useExecuteSqlQuery( + { + projectRef, + connectionString, + sql: getTableConstraints({ schema, table }), + queryKey: ['table-constraints'], + }, + { + enabled: typeof schema !== 'undefined' && typeof table !== 'undefined', + select(data) { + return (data as any)?.result ?? [] + }, + ...options, + } + ) +} diff --git a/apps/studio/data/database/database-query-constants.ts b/apps/studio/data/database/database-query-constants.ts index 31b677d87d9..67934d5f686 100644 --- a/apps/studio/data/database/database-query-constants.ts +++ b/apps/studio/data/database/database-query-constants.ts @@ -10,15 +10,6 @@ export enum FOREIGN_KEY_CASCADE_ACTION { SET_DEFAULT = 'd', } -export enum CONSTRAINT_TYPE { - CHECK_CONSTRAINT = 'c', - FOREIGN_KEY_CONSTRAINT = 'f', - PRIMARY_KEY_CONSTRAINT = 'p', - UNIQUE_CONSTRAINT = 'u', - CONSTRAINT_TRIGGER = 't', - EXCLUSION_CONSTRAINT = 'x', -} - // Derived from https://github.com/MichaelDBA/pg_get_tabledef // NOTE: when updating, \n must be replaced with \\n in the SQL below From b4e768b74fbf3281d2a8141c19c03951c8d4dfa7 Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Mon, 26 Feb 2024 09:39:23 +0100 Subject: [PATCH 22/50] fix: Migrate SQL editor and Log explrorer to use ShadCN Resizable (#21454) * Add resizable component to ui package. * Migrate the LogExplorer to use the new resizable component. * Migrate the SQL editor to use the new component. * Remove react-split. --- .../interfaces/SQLEditor/SQLEditor.tsx | 46 +++++------------- apps/studio/lib/constants/index.ts | 1 + apps/studio/package.json | 1 - .../project/[ref]/logs/explorer/index.tsx | 47 ++++++++++--------- apps/studio/pages/project/[ref]/sql/[id].tsx | 2 +- apps/studio/styles/monaco.scss | 5 -- apps/studio/styles/ui.scss | 8 ---- package-lock.json | 10 ++++ packages/ui/index.tsx | 2 + packages/ui/package.json | 1 + .../ui/src/components/shadcn/ui/resizable.tsx | 39 +++++++++++++++ 11 files changed, 92 insertions(+), 70 deletions(-) create mode 100644 packages/ui/src/components/shadcn/ui/resizable.tsx diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx index d8a4d621257..d71235efc0a 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx +++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx @@ -4,7 +4,6 @@ import { AnimatePresence, motion } from 'framer-motion' import dynamic from 'next/dynamic' import { useRouter } from 'next/router' import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react' -import Split from 'react-split' import { format } from 'sql-formatter' import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog' @@ -20,7 +19,6 @@ import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-que import { isError } from 'data/utils/error-check' import { useFlag, - useLocalStorage, useLocalStorageQuery, useSelectedOrganization, useSelectedProject, @@ -50,6 +48,9 @@ import { IconSettings, IconX, Input_Shadcn_, + ResizableHandle, + ResizablePanel, + ResizablePanelGroup, cn, } from 'ui' import { subscriptionHasHipaaAddon } from '../Billing/Subscription/Subscription.utils' @@ -178,13 +179,6 @@ const SQLEditor = () => { const isDiffOpen = !!sqlDiff - const [savedSplitSize, setSavedSplitSize] = useLocalStorage( - LOCAL_STORAGE_KEYS.SQL_EDITOR_SPLIT_SIZE, - `[50, 50]` - ) - - const splitSize = savedSplitSize ? JSON.parse(savedSplitSize) : undefined - const { mutate: execute, isLoading: isExecuting } = useExecuteSqlMutation({ onSuccess(data) { if (id) snap.addResult(id, data.result) @@ -230,20 +224,10 @@ const SQLEditor = () => { }, }) - const minSize = 44 const snippet = id ? snap.snippets[id] : null - const snapOffset = 50 const isLoading = urlId === 'new' ? false : !(id && ref && snap.loaded[ref]) - const onDragEnd = useCallback( - (sizes: number[]) => { - if (id) snap.setSplitSizes(id, sizes) - setSavedSplitSize(JSON.stringify(sizes)) - }, - [id] - ) - const editorRef = useRef(null) const monacoRef = useRef(null) const diffEditorRef = useRef(null) @@ -866,19 +850,12 @@ const SQLEditor = () => { )} - -
+ {!isAiOpen && ( { )} -
-
+ + + {isLoading ? (
Loading...
) : ( @@ -1020,8 +998,8 @@ const SQLEditor = () => { executeQuery={executeQuery} /> )} -
-
+ +
) diff --git a/apps/studio/lib/constants/index.ts b/apps/studio/lib/constants/index.ts index 952ace51da5..7ea1d43dc97 100644 --- a/apps/studio/lib/constants/index.ts +++ b/apps/studio/lib/constants/index.ts @@ -36,6 +36,7 @@ export const LOCAL_STORAGE_KEYS = { UI_PREVIEW_CLS: 'supabase-ui-cls', SQL_EDITOR_SPLIT_SIZE: 'supabase_sql-editor-split-size', + LOG_EXPLORER_SPLIT_SIZE: 'supabase_log-explorer-split-size', GRAPHIQL_RLS_BYPASS_WARNING: 'graphiql-rls-bypass-warning-dismissed', CLS_DIFF_WARNING: 'cls-diff-warning-dismissed', CLS_SELECT_STAR_WARNING: 'cls-select-star-warning-dismissed', diff --git a/apps/studio/package.json b/apps/studio/package.json index b97f0a09088..6b74ac3f293 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -87,7 +87,6 @@ "react-intersection-observer": "^9.5.3", "react-markdown": "^8.0.3", "react-simple-maps": "4.0.0-beta.6", - "react-split": "^2.0.13", "react-tracked": "^1.7.11", "react-virtualized-auto-sizer": "^1.0.20", "react-window": "^1.8.6", diff --git a/apps/studio/pages/project/[ref]/logs/explorer/index.tsx b/apps/studio/pages/project/[ref]/logs/explorer/index.tsx index 2f4c666aba0..1a3c08e11b7 100644 --- a/apps/studio/pages/project/[ref]/logs/explorer/index.tsx +++ b/apps/studio/pages/project/[ref]/logs/explorer/index.tsx @@ -1,20 +1,28 @@ +import { useParams } from 'common/hooks' import dayjs from 'dayjs' import { observer } from 'mobx-react-lite' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' -import { Button, Form, Input, Modal } from 'ui' -import Split from 'react-split' -import { useParams } from 'common/hooks' +import { + Button, + Form, + Input, + Modal, + ResizableHandle, + ResizablePanel, + ResizablePanelGroup, +} from 'ui' + import { DatePickerToFrom, - LogsQueryPanel, - LogsTableName, - LogsWarning, LOGS_LARGE_DATE_RANGE_DAYS_THRESHOLD, LogTable, LogTemplate, - maybeShowUpgradePrompt, + LogsQueryPanel, + LogsTableName, + LogsWarning, TEMPLATES, + maybeShowUpgradePrompt, useEditorHints, } from 'components/interfaces/Settings/Logs' import UpgradePrompt from 'components/interfaces/Settings/Logs/UpgradePrompt' @@ -23,12 +31,13 @@ import CodeEditor from 'components/ui/CodeEditor' import LoadingOpacity from 'components/ui/LoadingOpacity' import ShimmerLine from 'components/ui/ShimmerLine' import { useContentInsertMutation } from 'data/content/content-insert-mutation' +import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' import { useLocalStorage, useSelectedOrganization, useStore } from 'hooks' import useLogsQuery from 'hooks/analytics/useLogsQuery' import { useUpgradePrompt } from 'hooks/misc/useUpgradePrompt' +import { LOCAL_STORAGE_KEYS } from 'lib/constants' import { uuidv4 } from 'lib/helpers' import { LogSqlSnippets, NextPageWithLayout } from 'types' -import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' const PLACEHOLDER_QUERY = 'select\n cast(timestamp as datetime) as timestamp,\n event_message, metadata \nfrom edge_logs \nlimit 5' @@ -187,17 +196,12 @@ export const LogsExplorerPage: NextPageWithLayout = () => { return (
- -
+ { onInputChange={(v) => setEditorValue(v || '')} onInputRun={handleRun} /> -
-
+ + +
{
-
- +
+ { }, [isPgInfoReady]) return ( -
+
) diff --git a/apps/studio/styles/monaco.scss b/apps/studio/styles/monaco.scss index 3994d267308..642bc197a1d 100644 --- a/apps/studio/styles/monaco.scss +++ b/apps/studio/styles/monaco.scss @@ -3,11 +3,6 @@ -webkit-text-size-adjust: 100%; } -.gutter { - @apply bg-border-control; - cursor: row-resize; -} - .grid-monaco-editor, .monaco-editor p, label, diff --git a/apps/studio/styles/ui.scss b/apps/studio/styles/ui.scss index 48371a9c57f..226be4a80b1 100644 --- a/apps/studio/styles/ui.scss +++ b/apps/studio/styles/ui.scss @@ -349,14 +349,6 @@ scrollbar-width: none; // auto | thin | none | ; } -.SQLTabContainer { - height: calc(100vh - 3rem); - min-height: calc(100vh - 3rem); - .gutter { - cursor: row-resize; - } -} - .radix-tooltip-arrow { polygon { @apply fill-background-alternative [[data-theme*=dark]_&]:fill-background-alternative; diff --git a/package-lock.json b/package-lock.json index 7aa43d9883b..abf52bd49a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30149,6 +30149,15 @@ "react": ">= 16.3" } }, + "node_modules/react-resizable-panels": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.0.9.tgz", + "integrity": "sha512-ZylBvs7oG7Y/INWw3oYGolqgpFvoPW8MPeg9l1fURDeKpxrmUuCHBUmPj47BdZ11MODImu3kZYXG85rbySab7w==", + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-resize-detector": { "version": "8.1.0", "license": "MIT", @@ -37364,6 +37373,7 @@ "react-hook-form": "^7.45.0", "react-hot-toast": "^2.4.1", "react-markdown": "^8.0.3", + "react-resizable-panels": "^2.0.9", "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^4.2.17", "reactflow": "^11.10.1", diff --git a/packages/ui/index.tsx b/packages/ui/index.tsx index 4dd90fe2fac..e4a92577b6b 100644 --- a/packages/ui/index.tsx +++ b/packages/ui/index.tsx @@ -206,6 +206,8 @@ export { ScrollArea, ScrollBar } from './src/components/shadcn/ui/scroll-area' export { Separator } from './src/components/shadcn/ui/separator' +export * from './src/components/shadcn/ui/resizable' + // links export * from './src/components/TextLink' diff --git a/packages/ui/package.json b/packages/ui/package.json index 5f13fae221d..cbd1e654608 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -74,6 +74,7 @@ "react-hook-form": "^7.45.0", "react-hot-toast": "^2.4.1", "react-markdown": "^8.0.3", + "react-resizable-panels": "^2.0.9", "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^4.2.17", "reactflow": "^11.10.1", diff --git a/packages/ui/src/components/shadcn/ui/resizable.tsx b/packages/ui/src/components/shadcn/ui/resizable.tsx new file mode 100644 index 00000000000..837e962ba42 --- /dev/null +++ b/packages/ui/src/components/shadcn/ui/resizable.tsx @@ -0,0 +1,39 @@ +import { GripVertical } from 'lucide-react' +import * as ResizablePrimitive from 'react-resizable-panels' +import { cn } from '../../../lib/utils/cn' + +const ResizablePanelGroup = ({ + className, + ...props +}: React.ComponentProps) => ( + +) + +const ResizablePanel = ResizablePrimitive.Panel + +const ResizableHandle = ({ + withHandle, + className, + ...props +}: React.ComponentProps & { + withHandle?: boolean +}) => ( + div]:rotate-90', + className + )} + {...props} + > + {withHandle && ( +
+ +
+ )} +
+) + +export { ResizableHandle, ResizablePanel, ResizablePanelGroup } From d8ae6de7a8a7ebaa0bb7e0bc932bb2742c9c1df8 Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Mon, 26 Feb 2024 16:40:56 +0800 Subject: [PATCH 23/50] feat: add new Icons package for custom made icons (#21477) * feat: add new Icons package * Create README.md * add more icons * add "Home" icon and "Postgres" icon * reduce helpers * remove old files * make dev deps * Delete package-lock.json * Update README.md * add to packages for other apps * remove from db.design * Update README.md * Move the build-icons package in the packages folder. --------- Co-authored-by: Ivan Vasilov --- apps/docs/next.config.mjs | 1 + apps/docs/package.json | 1 + apps/studio/next.config.js | 2 +- apps/studio/package.json | 1 + apps/www/next.config.mjs | 2 +- apps/www/package.json | 1 + package-lock.json | 305 +++++++++++++++++- packages/build-icons/package.json | 24 ++ .../src/building/generateAliasesFile.mjs | 102 ++++++ .../src/building/generateDynamicImports.mjs | 30 ++ .../src/building/generateExportsFile.mjs | 23 ++ .../src/building/generateIconFiles.mjs | 57 ++++ packages/build-icons/src/index.mjs | 3 + packages/build-icons/src/main.mjs | 100 ++++++ .../build-icons/src/render/default-attrs.json | 11 + .../src/render/renderIconsObject.mjs | 39 +++ packages/build-icons/src/utils/base64SVG.mjs | 11 + .../build-icons/src/utils/getIconMetaData.mjs | 16 + packages/build-icons/src/utils/helpers.mjs | 131 ++++++++ packages/icons/README.md | 122 +++++++ packages/icons/package.json | 11 + packages/icons/scripts/exportTemplate.mjs | 25 ++ packages/icons/src/createSupabaseIcon.ts | 77 +++++ packages/icons/src/defaultAttributes.ts | 11 + packages/icons/src/icon.schema.json | 57 ++++ packages/icons/src/icons/REST-api.ts | 23 ++ packages/icons/src/icons/_example-template.ts | 20 ++ packages/icons/src/icons/api-docs.ts | 23 ++ packages/icons/src/icons/auth.ts | 23 ++ packages/icons/src/icons/database.ts | 31 ++ packages/icons/src/icons/edge-functions.ts | 44 +++ packages/icons/src/icons/home.ts | 23 ++ packages/icons/src/icons/index.ts | 20 ++ packages/icons/src/icons/insert-code.ts | 58 ++++ packages/icons/src/icons/integrations.ts | 23 ++ packages/icons/src/icons/logs.ts | 23 ++ packages/icons/src/icons/postgres.ts | 30 ++ packages/icons/src/icons/realtime.ts | 23 ++ packages/icons/src/icons/replace-code.ts | 60 ++++ packages/icons/src/icons/reports.ts | 23 ++ packages/icons/src/icons/settings.ts | 30 ++ packages/icons/src/icons/sql-editor.ts | 23 ++ packages/icons/src/icons/storage.ts | 23 ++ packages/icons/src/icons/table-editor.ts | 23 ++ packages/icons/src/icons/user.ts | 23 ++ packages/icons/src/raw-icons/REST-api.svg | 5 + .../src/raw-icons/_example-template.json | 20 ++ .../icons/src/raw-icons/_example-template.svg | 16 + packages/icons/src/raw-icons/api-docs.svg | 5 + packages/icons/src/raw-icons/auth.svg | 5 + packages/icons/src/raw-icons/database.svg | 9 + .../icons/src/raw-icons/edge-functions.svg | 11 + packages/icons/src/raw-icons/home.svg | 5 + packages/icons/src/raw-icons/insert-code.svg | 9 + packages/icons/src/raw-icons/integrations.svg | 5 + packages/icons/src/raw-icons/logs.svg | 5 + packages/icons/src/raw-icons/postgres.svg | 7 + packages/icons/src/raw-icons/realtime.svg | 5 + packages/icons/src/raw-icons/replace-code.svg | 13 + packages/icons/src/raw-icons/reports.svg | 5 + packages/icons/src/raw-icons/settings.svg | 7 + packages/icons/src/raw-icons/sql-editor.svg | 5 + packages/icons/src/raw-icons/storage.svg | 5 + packages/icons/src/raw-icons/table-editor.svg | 5 + packages/icons/src/raw-icons/user.svg | 5 + packages/icons/tsconfig.json | 8 + 66 files changed, 1882 insertions(+), 10 deletions(-) create mode 100644 packages/build-icons/package.json create mode 100644 packages/build-icons/src/building/generateAliasesFile.mjs create mode 100644 packages/build-icons/src/building/generateDynamicImports.mjs create mode 100644 packages/build-icons/src/building/generateExportsFile.mjs create mode 100644 packages/build-icons/src/building/generateIconFiles.mjs create mode 100644 packages/build-icons/src/index.mjs create mode 100755 packages/build-icons/src/main.mjs create mode 100644 packages/build-icons/src/render/default-attrs.json create mode 100644 packages/build-icons/src/render/renderIconsObject.mjs create mode 100644 packages/build-icons/src/utils/base64SVG.mjs create mode 100644 packages/build-icons/src/utils/getIconMetaData.mjs create mode 100644 packages/build-icons/src/utils/helpers.mjs create mode 100644 packages/icons/README.md create mode 100644 packages/icons/package.json create mode 100644 packages/icons/scripts/exportTemplate.mjs create mode 100644 packages/icons/src/createSupabaseIcon.ts create mode 100644 packages/icons/src/defaultAttributes.ts create mode 100644 packages/icons/src/icon.schema.json create mode 100644 packages/icons/src/icons/REST-api.ts create mode 100644 packages/icons/src/icons/_example-template.ts create mode 100644 packages/icons/src/icons/api-docs.ts create mode 100644 packages/icons/src/icons/auth.ts create mode 100644 packages/icons/src/icons/database.ts create mode 100644 packages/icons/src/icons/edge-functions.ts create mode 100644 packages/icons/src/icons/home.ts create mode 100644 packages/icons/src/icons/index.ts create mode 100644 packages/icons/src/icons/insert-code.ts create mode 100644 packages/icons/src/icons/integrations.ts create mode 100644 packages/icons/src/icons/logs.ts create mode 100644 packages/icons/src/icons/postgres.ts create mode 100644 packages/icons/src/icons/realtime.ts create mode 100644 packages/icons/src/icons/replace-code.ts create mode 100644 packages/icons/src/icons/reports.ts create mode 100644 packages/icons/src/icons/settings.ts create mode 100644 packages/icons/src/icons/sql-editor.ts create mode 100644 packages/icons/src/icons/storage.ts create mode 100644 packages/icons/src/icons/table-editor.ts create mode 100644 packages/icons/src/icons/user.ts create mode 100644 packages/icons/src/raw-icons/REST-api.svg create mode 100644 packages/icons/src/raw-icons/_example-template.json create mode 100644 packages/icons/src/raw-icons/_example-template.svg create mode 100644 packages/icons/src/raw-icons/api-docs.svg create mode 100644 packages/icons/src/raw-icons/auth.svg create mode 100644 packages/icons/src/raw-icons/database.svg create mode 100644 packages/icons/src/raw-icons/edge-functions.svg create mode 100644 packages/icons/src/raw-icons/home.svg create mode 100644 packages/icons/src/raw-icons/insert-code.svg create mode 100644 packages/icons/src/raw-icons/integrations.svg create mode 100644 packages/icons/src/raw-icons/logs.svg create mode 100644 packages/icons/src/raw-icons/postgres.svg create mode 100644 packages/icons/src/raw-icons/realtime.svg create mode 100644 packages/icons/src/raw-icons/replace-code.svg create mode 100644 packages/icons/src/raw-icons/reports.svg create mode 100644 packages/icons/src/raw-icons/settings.svg create mode 100644 packages/icons/src/raw-icons/sql-editor.svg create mode 100644 packages/icons/src/raw-icons/storage.svg create mode 100644 packages/icons/src/raw-icons/table-editor.svg create mode 100644 packages/icons/src/raw-icons/user.svg create mode 100644 packages/icons/tsconfig.json diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs index 6e5f75eec60..08e4943e944 100644 --- a/apps/docs/next.config.mjs +++ b/apps/docs/next.config.mjs @@ -68,6 +68,7 @@ const nextConfig = { 'mdx-mermaid', 'dayjs', 'shared-data', + 'icons', ], async headers() { return [ diff --git a/apps/docs/package.json b/apps/docs/package.json index b2a5e9a083d..b934a33525a 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -68,6 +68,7 @@ "remark-gfm": "^3.0.1", "shared-data": "*", "ui": "*", + "icons": "*", "ui-patterns": "*", "unist-builder": "^3.0.1", "unist-util-filter": "^4.0.1", diff --git a/apps/studio/next.config.js b/apps/studio/next.config.js index 06f233ff017..f163c115db7 100644 --- a/apps/studio/next.config.js +++ b/apps/studio/next.config.js @@ -390,7 +390,7 @@ const nextConfig = { 'vercel.com', ], }, - transpilePackages: ['ui', 'ui-patterns', 'common', 'shared-data'], + transpilePackages: ['ui', 'ui-patterns', 'common', 'shared-data', 'icons'], webpack(config) { config.module?.rules .find((rule) => rule.oneOf) diff --git a/apps/studio/package.json b/apps/studio/package.json index 6b74ac3f293..745be8c4021 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -99,6 +99,7 @@ "sqlstring": "^2.3.2", "ui": "*", "ui-patterns": "*", + "icons": "*", "uuid": "^9.0.1", "valtio": "^1.11.2", "yup": "^0.32.11", diff --git a/apps/www/next.config.mjs b/apps/www/next.config.mjs index 34219c26a99..da0813e49a6 100644 --- a/apps/www/next.config.mjs +++ b/apps/www/next.config.mjs @@ -41,7 +41,7 @@ const nextConfig = { basePath: '', pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'], trailingSlash: false, - transpilePackages: ['ui', 'ui-patterns', 'common', 'shared-data'], + transpilePackages: ['ui', 'ui-patterns', 'common', 'shared-data', 'icons'], images: { dangerouslyAllowSVG: true, domains: [ diff --git a/apps/www/package.json b/apps/www/package.json index ed6fa2407d3..3b9b92fa12f 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -64,6 +64,7 @@ "typescript": "^5.2.2", "ui": "*", "ui-patterns": "*", + "icons": "*", "use-debounce": "^7.0.1", "vanilla-tilt": "1.7.0", "yup": "^0.32.11" diff --git a/package-lock.json b/package-lock.json index abf52bd49a7..b52005e5a69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -488,6 +488,7 @@ "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", "hast-util-has-property": "^2.0.1", + "icons": "*", "isbot": "^3.6.5", "jsrsasign": "^11.0.0", "lodash": "^4.17.21", @@ -801,6 +802,7 @@ "framer-motion": "^11.0.3", "generate-password-browser": "^1.1.0", "html-to-image": "^1.10.8", + "icons": "*", "immutability-helper": "^3.1.1", "ip-num": "^1.5.1", "json-logic-js": "^2.0.2", @@ -1103,6 +1105,7 @@ "framer-motion": "^11.0.3", "globby": "^13.2.2", "gray-matter": "^4.0.3", + "icons": "*", "markdown-toc": "^1.2.0", "next": "^13.5.6", "next-mdx-remote": "^4.4.1", @@ -10886,6 +10889,10 @@ "@supabase/supabase-js": "^2.21.0" } }, + "node_modules/@supabase/build-icons": { + "resolved": "packages/build-icons", + "link": true + }, "node_modules/@supabase/functions-js": { "version": "2.1.5", "license": "MIT", @@ -11424,6 +11431,15 @@ "node": ">= 10" } }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "license": "MIT", @@ -15951,6 +15967,39 @@ "dev": true, "license": "MIT" }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, "node_modules/cssom": { "version": "0.5.0", "dev": true, @@ -16403,6 +16452,15 @@ "version": "0.7.9", "license": "Apache-2.0" }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/data-urls": { "version": "3.0.2", "dev": true, @@ -16537,6 +16595,31 @@ "version": "0.1.4", "license": "MIT" }, + "node_modules/deep-rename-keys": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/deep-rename-keys/-/deep-rename-keys-0.2.1.tgz", + "integrity": "sha512-RHd9ABw4Fvk+gYDWqwOftG849x0bYOySl/RgX0tLI9i27ZIeSO91mLZJEp7oPHOMFqHvpgu21YptmDt0FYD/0A==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2", + "rename-keys": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-rename-keys/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "license": "MIT", @@ -20698,6 +20781,10 @@ "version": "1.0.4", "license": "BSD-3-Clause" }, + "node_modules/icons": { + "resolved": "packages/icons", + "link": true + }, "node_modules/iconv-lite": { "version": "0.6.3", "license": "MIT", @@ -31922,6 +32009,15 @@ "version": "0.4.2", "license": "MIT" }, + "node_modules/rename-keys": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rename-keys/-/rename-keys-1.2.0.tgz", + "integrity": "sha512-U7XpAktpbSgHTRSNRrjKSrjYkZKuhUukfoBlXWXUExCAqhzh1TU3BDRAfJmarcl5voKS+pbKU9MvyLWKZ4UEEg==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/renderkid": { "version": "3.0.0", "dev": true, @@ -33696,14 +33792,6 @@ "node": ">= 14" } }, - "node_modules/supabase/node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, "node_modules/supabase/node_modules/https-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", @@ -33820,6 +33908,119 @@ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "peer": true }, + "node_modules/svgo": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.2.0.tgz", + "integrity": "sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/svgo/node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "node_modules/svgson": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/svgson/-/svgson-5.3.1.tgz", + "integrity": "sha512-qdPgvUNWb40gWktBJnbJRelWcPzkLed/ShhnRsjbayXz8OtdPOzbil9jtiZdrYvSDumAz/VNQr6JaNfPx/gvPA==", + "dev": true, + "dependencies": { + "deep-rename-keys": "^0.2.1", + "xml-reader": "2.4.3" + } + }, "node_modules/swagger2openapi": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", @@ -36872,6 +37073,21 @@ "resolved": "apps/www", "link": true }, + "node_modules/xml-lexer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xml-lexer/-/xml-lexer-0.2.2.tgz", + "integrity": "sha512-G0i98epIwiUEiKmMcavmVdhtymW+pCAohMRgybyIME9ygfVu8QheIi+YoQh3ngiThsT0SQzJT4R0sKDEv8Ou0w==", + "dev": true, + "dependencies": { + "eventemitter3": "^2.0.0" + } + }, + "node_modules/xml-lexer/node_modules/eventemitter3": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", + "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==", + "dev": true + }, "node_modules/xml-name-validator": { "version": "4.0.0", "dev": true, @@ -36880,6 +37096,22 @@ "node": ">=12" } }, + "node_modules/xml-reader": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/xml-reader/-/xml-reader-2.4.3.tgz", + "integrity": "sha512-xWldrIxjeAMAu6+HSf9t50ot1uL5M+BtOidRCWHXIeewvSeIpscWCsp4Zxjk8kHHhdqFBrfK8U0EJeCcnyQ/gA==", + "dev": true, + "dependencies": { + "eventemitter3": "^2.0.0", + "xml-lexer": "^0.2.2" + } + }, + "node_modules/xml-reader/node_modules/eventemitter3": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", + "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==", + "dev": true + }, "node_modules/xmlchars": { "version": "2.2.0", "dev": true, @@ -37111,6 +37343,57 @@ "sql-formatter": "bin/sql-formatter-cli.cjs" } }, + "packages/build-icons": { + "name": "@supabase/build-icons", + "version": "1.0.0", + "license": "ISC", + "bin": { + "build-icons": "src/main.mjs" + }, + "devDependencies": { + "minimist": "^1.2.7", + "node-fetch": "^3.2.10", + "prettier": "2.7.1", + "svgo": "^3.0.0", + "svgson": "^5.2.1" + }, + "engines": { + "node": ">= 16" + } + }, + "packages/build-icons/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "packages/build-icons/node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "packages/common": { "version": "0.0.0", "license": "MIT", @@ -37306,6 +37589,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/icons": { + "dependencies": { + "@supabase/build-icons": "*", + "typescript": "^5.2.2" + } + }, "packages/shared-data": { "version": "0.0.0", "license": "MIT" diff --git a/packages/build-icons/package.json b/packages/build-icons/package.json new file mode 100644 index 00000000000..5bff7f699e2 --- /dev/null +++ b/packages/build-icons/package.json @@ -0,0 +1,24 @@ +{ + "name": "@supabase/build-icons", + "private": true, + "version": "1.0.0", + "description": "", + "main": "src/index.mjs", + "type": "module", + "bin": { + "build-icons": "src/main.mjs" + }, + "engines": { + "node": ">= 16" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "minimist": "^1.2.7", + "node-fetch": "^3.2.10", + "prettier": "2.7.1", + "svgo": "^3.0.0", + "svgson": "^5.2.1" + } +} diff --git a/packages/build-icons/src/building/generateAliasesFile.mjs b/packages/build-icons/src/building/generateAliasesFile.mjs new file mode 100644 index 00000000000..8ee6b822b39 --- /dev/null +++ b/packages/build-icons/src/building/generateAliasesFile.mjs @@ -0,0 +1,102 @@ +import fs from 'fs' +import path from 'path' +import { appendFile, resetFile, toPascalCase } from '../utils/helpers.mjs' + +const getImportString = (componentName, iconName, aliasImportFileExtension = '') => + `export { default as ${componentName} } from './icons/${iconName}${aliasImportFileExtension}';\n` + +export default async function generateAliasesFile({ + iconNodes, + outputDirectory, + fileExtension, + iconFileExtension = '.js', + iconMetaData, + aliasImportFileExtension, + aliasNamesOnly = false, + separateAliasesFile = false, + showLog = true, +}) { + const iconsDistDirectory = path.join(outputDirectory, `icons`) + const fileName = path.basename(`aliases${fileExtension}`) + const icons = Object.keys(iconNodes) + + // Reset file + resetFile(fileName, outputDirectory) + + // Generate Import for Icon VNodes + await Promise.all( + icons.map(async (iconName, index) => { + const componentName = toPascalCase(iconName) + const iconAliases = iconMetaData[iconName]?.aliases + + let importString = '' + + if ((iconAliases != null && Array.isArray(iconAliases)) || !aliasNamesOnly) { + if (index > 0) { + importString += '\n' + } + + importString += `// ${componentName} aliases\n` + } + + if (!aliasNamesOnly) { + importString += getImportString(`${componentName}Icon`, iconName, aliasImportFileExtension) + importString += getImportString( + `Lucide${componentName}`, + iconName, + aliasImportFileExtension + ) + } + + if (iconAliases != null && Array.isArray(iconAliases)) { + await Promise.all( + iconAliases.map(async (alias) => { + const componentNameAlias = toPascalCase(alias) + + if (separateAliasesFile) { + const output = `export { default } from "./${iconName}"` + const location = path.join(iconsDistDirectory, `${alias}${iconFileExtension}`) + + await fs.promises.writeFile(location, output, 'utf-8') + } + + // Don't import the same icon twice + if (componentName === componentNameAlias) { + return + } + + const exportFileIcon = separateAliasesFile ? alias : iconName + + importString += getImportString( + componentNameAlias, + exportFileIcon, + aliasImportFileExtension + ) + + if (!aliasNamesOnly) { + importString += getImportString( + `${componentNameAlias}Icon`, + exportFileIcon, + aliasImportFileExtension + ) + + importString += getImportString( + `Lucide${componentNameAlias}`, + exportFileIcon, + aliasImportFileExtension + ) + } + }) + ) + } + + appendFile(importString, fileName, outputDirectory) + }) + ) + + appendFile('\n', fileName, outputDirectory) + + if (showLog) { + console.log(`Successfully generated ${fileName} file`) + } +} diff --git a/packages/build-icons/src/building/generateDynamicImports.mjs b/packages/build-icons/src/building/generateDynamicImports.mjs new file mode 100644 index 00000000000..58fdb26e6ba --- /dev/null +++ b/packages/build-icons/src/building/generateDynamicImports.mjs @@ -0,0 +1,30 @@ +import path from 'path' +import { appendFile, resetFile } from '../utils/helpers.mjs' + +export default function generateDynamicImports({ + iconNodes, + outputDirectory, + fileExtension, + showLog = true, +}) { + const fileName = path.basename(`dynamicIconImports${fileExtension}`) + const icons = Object.keys(iconNodes) + + // Reset file + resetFile(fileName, outputDirectory) + + let importString = `const dynamicIconImports = {\n` + + // Generate Import for Icon VNodes + icons.forEach((iconName) => { + importString += ` '${iconName}': () => import('./icons/${iconName}'),\n` + }) + + importString += '};\nexport default dynamicIconImports;\n' + + appendFile(importString, fileName, outputDirectory) + + if (showLog) { + console.log(`Successfully generated ${fileName} file`) + } +} diff --git a/packages/build-icons/src/building/generateExportsFile.mjs b/packages/build-icons/src/building/generateExportsFile.mjs new file mode 100644 index 00000000000..73c58cb00b8 --- /dev/null +++ b/packages/build-icons/src/building/generateExportsFile.mjs @@ -0,0 +1,23 @@ +import path from 'path' + +import { appendFile, resetFile, toPascalCase } from '../utils/helpers.mjs' + +export default (inputEntry, outputDirectory, iconNodes, iconFileExtension = '') => { + const fileName = path.basename(inputEntry) + + // Reset file + resetFile(fileName, outputDirectory) + + const icons = Object.keys(iconNodes) + + // Generate Import for Icon VNodes + icons.forEach((iconName) => { + const componentName = toPascalCase(iconName) + const importString = `export { default as ${componentName} } from './${iconName}${iconFileExtension}';\n` + appendFile(importString, fileName, outputDirectory) + }) + + appendFile('\n', fileName, outputDirectory) + + console.log(`Successfully generated ${fileName} file`) +} diff --git a/packages/build-icons/src/building/generateIconFiles.mjs b/packages/build-icons/src/building/generateIconFiles.mjs new file mode 100644 index 00000000000..7b0336487f5 --- /dev/null +++ b/packages/build-icons/src/building/generateIconFiles.mjs @@ -0,0 +1,57 @@ +import fs from 'fs' +import path from 'path' +import prettier from 'prettier' +import { readSvg, toPascalCase } from '../utils/helpers.mjs' + +export default ({ + iconNodes, + outputDirectory, + template, + showLog = true, + iconFileExtension = '.js', + pretty = true, + iconsDir, + iconMetaData, +}) => { + const icons = Object.keys(iconNodes) + const iconsDistDirectory = path.join(outputDirectory, `icons`) + + if (!fs.existsSync(iconsDistDirectory)) { + fs.mkdirSync(iconsDistDirectory) + } + + const writeIconFiles = icons.map(async (iconName) => { + const location = path.join(iconsDistDirectory, `${iconName}${iconFileExtension}`) + + const componentName = toPascalCase(iconName) + + let { children } = iconNodes[iconName] + children = children.map(({ name, attributes }) => [name, attributes]) + + const getSvg = () => readSvg(`${iconName}.svg`, iconsDir) + // const { deprecated = false } = iconMetaData[iconName] + const deprecated = false + + const elementTemplate = template({ componentName, iconName, children, getSvg, deprecated }) + const output = pretty + ? prettier.format(elementTemplate, { + singleQuote: true, + trailingComma: 'all', + printWidth: 100, + parser: 'babel', + }) + : elementTemplate + + await fs.promises.writeFile(location, output, 'utf-8') + }) + + Promise.all(writeIconFiles) + .then(() => { + if (showLog) { + console.log('Successfully built', icons.length, 'icons.') + } + }) + .catch((error) => { + throw new Error(`Something went wrong generating icon files,\n ${error}`) + }) +} diff --git a/packages/build-icons/src/index.mjs b/packages/build-icons/src/index.mjs new file mode 100644 index 00000000000..965229681e2 --- /dev/null +++ b/packages/build-icons/src/index.mjs @@ -0,0 +1,3 @@ +// eslint-disable-next-line import/prefer-default-export +export { default as base64SVG } from './utils/base64SVG.mjs' +export { default as getIconMetaData } from './utils/getIconMetaData.mjs' diff --git a/packages/build-icons/src/main.mjs b/packages/build-icons/src/main.mjs new file mode 100755 index 00000000000..701eb0a8d93 --- /dev/null +++ b/packages/build-icons/src/main.mjs @@ -0,0 +1,100 @@ +#!/usr/bin/env node +import fs from 'fs' +import getArgumentOptions from 'minimist' +import path from 'path' + +import generateExportsFile from './building/generateExportsFile.mjs' +import generateIconFiles from './building/generateIconFiles.mjs' +import renderIconsObject from './render/renderIconsObject.mjs' + +import generateAliasesFile from './building/generateAliasesFile.mjs' +import generateDynamicImports from './building/generateDynamicImports.mjs' +import getIconMetaData from './utils/getIconMetaData.mjs' +import { readSvgDirectory } from './utils/helpers.mjs' + +const cliArguments = getArgumentOptions(process.argv.slice(2)) + +const ICONS_DIR = path.resolve(process.cwd(), 'src/raw-icons') +const OUTPUT_DIR = path.resolve(process.cwd(), cliArguments.output || 'src') + +if (!fs.existsSync(OUTPUT_DIR)) { + fs.mkdirSync(OUTPUT_DIR) +} + +const { + renderUniqueKey = false, + templateSrc, + silent = false, + iconFileExtension = '.js', + importImportFileExtension = '', + exportFileName = 'index.js', + withAliases = false, + aliasNamesOnly = false, + withDynamicImports = false, + separateAliasesFile = false, + aliasesFileExtension = '.js', + aliasImportFileExtension = '', + pretty = true, +} = cliArguments + +async function buildIcons() { + if (templateSrc == null) { + throw new Error('No `templateSrc` argument given.') + } + const svgFiles = readSvgDirectory(ICONS_DIR) + + const icons = renderIconsObject(svgFiles, ICONS_DIR, renderUniqueKey) + + const { default: iconFileTemplate } = await import(path.resolve(process.cwd(), templateSrc)) + + const iconMetaData = await getIconMetaData(ICONS_DIR) + + // Generates iconsNodes files for each icon + generateIconFiles({ + iconNodes: icons, + outputDirectory: OUTPUT_DIR, + template: iconFileTemplate, + showLog: !silent, + iconFileExtension, + pretty: JSON.parse(pretty), + iconsDir: ICONS_DIR, + iconMetaData, + }) + + if (withAliases) { + await generateAliasesFile({ + iconNodes: icons, + iconMetaData, + aliasNamesOnly, + iconFileExtension, + outputDirectory: OUTPUT_DIR, + fileExtension: aliasesFileExtension, + aliasImportFileExtension, + separateAliasesFile, + showLog: !silent, + }) + } + + if (withDynamicImports) { + generateDynamicImports({ + iconNodes: icons, + outputDirectory: OUTPUT_DIR, + fileExtension: aliasesFileExtension, + showLog: !silent, + }) + } + + // Generates entry files for the compiler filled with icons exports + generateExportsFile( + path.join(OUTPUT_DIR, 'icons', exportFileName), + path.join(OUTPUT_DIR, 'icons'), + icons, + importImportFileExtension + ) +} + +try { + buildIcons() +} catch (error) { + console.error(error) +} diff --git a/packages/build-icons/src/render/default-attrs.json b/packages/build-icons/src/render/default-attrs.json new file mode 100644 index 00000000000..e57e91b7e86 --- /dev/null +++ b/packages/build-icons/src/render/default-attrs.json @@ -0,0 +1,11 @@ +{ + "xmlns": "http://www.w3.org/2000/svg", + "width": 24, + "height": 24, + "viewBox": "0 0 24 24", + "fill": "none", + "stroke": "currentColor", + "stroke-width": 2, + "stroke-linecap": "round", + "stroke-linejoin": "round" +} diff --git a/packages/build-icons/src/render/renderIconsObject.mjs b/packages/build-icons/src/render/renderIconsObject.mjs new file mode 100644 index 00000000000..0b982080351 --- /dev/null +++ b/packages/build-icons/src/render/renderIconsObject.mjs @@ -0,0 +1,39 @@ +import { basename } from 'path' +import { parseSync } from 'svgson' +import { generateHashedKey, hasDuplicatedChildren, readSvg } from '../utils/helpers.mjs' + +/** + * Build an object in the format: `{ : }`. + * @param {string[]} svgFiles - A list of filenames. + * @param {Function} getSvg - A function that returns the contents of an SVG file given a filename. + * @returns {Object} + */ +export default (svgFiles, iconsDirectory, renderUniqueKey = false) => + svgFiles + .map((svgFile) => { + const name = basename(svgFile, '.svg') + const svg = readSvg(svgFile, iconsDirectory) + const contents = parseSync(svg) + + if (!(contents.children && contents.children.length)) { + throw new Error(`${name}.svg has no children!`) + } + + if (hasDuplicatedChildren(contents.children)) { + throw new Error(`Duplicated children in ${name}.svg`) + } + + if (renderUniqueKey) { + contents.children = contents.children.map((child) => { + child.attributes.key = generateHashedKey(child) + + return child + }) + } + + return { name, contents } + }) + .reduce((icons, icon) => { + icons[icon.name] = icon.contents + return icons + }, {}) diff --git a/packages/build-icons/src/utils/base64SVG.mjs b/packages/build-icons/src/utils/base64SVG.mjs new file mode 100644 index 00000000000..b883d0fff9a --- /dev/null +++ b/packages/build-icons/src/utils/base64SVG.mjs @@ -0,0 +1,11 @@ +const base64SVG = (svgContents) => + Buffer.from( + svgContents + .replace('\n', '') + .replace( + 'stroke="currentColor"', + 'stroke="#000" style="background-color: #fff; border-radius: 2px"', + ), + ).toString('base64'); + +export default base64SVG; diff --git a/packages/build-icons/src/utils/getIconMetaData.mjs b/packages/build-icons/src/utils/getIconMetaData.mjs new file mode 100644 index 00000000000..7facf8b3574 --- /dev/null +++ b/packages/build-icons/src/utils/getIconMetaData.mjs @@ -0,0 +1,16 @@ +import path from 'path' +import { readSvgDirectory } from '../utils/helpers.mjs' + +async function getIconMetaData(iconDirectory) { + const iconJsons = readSvgDirectory(iconDirectory, '.json') + const aliasesEntries = await Promise.all( + iconJsons.map(async (jsonFile) => { + const file = await import(path.join(iconDirectory, jsonFile), { assert: { type: 'json' } }) + return [path.basename(jsonFile, '.json'), file.default] + }) + ) + + return Object.fromEntries(aliasesEntries) +} + +export default getIconMetaData diff --git a/packages/build-icons/src/utils/helpers.mjs b/packages/build-icons/src/utils/helpers.mjs new file mode 100644 index 00000000000..04aaf4a1735 --- /dev/null +++ b/packages/build-icons/src/utils/helpers.mjs @@ -0,0 +1,131 @@ +import fs from 'fs' +import path from 'path' + +/** + * Converts string to CamelCase + * + * @param {string} string + * @returns {string} A camelized string + */ +const toCamelCase = (string) => + string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => + p2 ? p2.toUpperCase() : p1.toLowerCase() + ) + +/** + * Converts string to PascalCase + * + * @param {string} string + * @returns {string} A pascalized string + */ +export const toPascalCase = (string) => { + const camelCase = toCamelCase(string) + + return camelCase.charAt(0).toUpperCase() + camelCase.slice(1) +} + +/** + * Converts string to KebabCase + * + * @param {string} string + * @returns {string} A kebabized string + */ +const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() + +/** + * Resets the file contents. + * + * @param {string} fileName + * @param {string} outputDirectory + */ +export const resetFile = (fileName, outputDirectory) => + fs.writeFileSync(path.join(outputDirectory, fileName), '', 'utf-8') + +/** + * Reads the file contents. + * + * @param {string} path + * @returns {string} The contents of a file + */ +const readFile = (entry) => fs.readFileSync(path.resolve(__dirname, '../', entry), 'utf-8') + +/** + * append content to a file + * + * @param {string} content + * @param {string} fileName + * @param {string} outputDirectory + */ +export const appendFile = (content, fileName, outputDirectory) => + fs.appendFileSync(path.join(outputDirectory, fileName), content, 'utf-8') + +/** + * writes content to a file + * + * @param {string} content + * @param {string} fileName + * @param {string} outputDirectory + */ +const writeFile = (content, fileName, outputDirectory) => + fs.writeFileSync(path.join(outputDirectory, fileName), content, 'utf-8') + +/** + * reads the icon directory + * + * @param {string} directory + * @returns {array} An array of file paths containing svgs + */ +export const readSvgDirectory = (directory, fileExtension = '.svg') => + fs.readdirSync(directory).filter((file) => path.extname(file) === fileExtension) + +/** + * Read svg from directory + * + * @param {string} fileName + * @param {string} directory + */ +export const readSvg = (fileName, directory) => + fs.readFileSync(path.join(directory, fileName), 'utf-8') + +/** + * djb2 hashing function + * + * @param {string} string + * @param {number} seed + * @returns {string} A hashed string of 6 characters + */ +const hash = (string, seed = 5381) => { + let i = string.length + + while (i) { + // eslint-disable-next-line no-bitwise, no-plusplus + seed = (seed * 33) ^ string.charCodeAt(--i) + } + + // eslint-disable-next-line no-bitwise + return (seed >>> 0).toString(36).substr(0, 6) +} + +/** + * Generate Hashed string based on name and attributes + * + * @param {object} seed + * @param {string} seed.name A name, for example an icon name + * @param {object} seed.attributes An object of SVGElement Attrbutes + * @returns {string} A hashed string of 6 characters + */ +export const generateHashedKey = ({ name, attributes }) => hash(JSON.stringify([name, attributes])) + +/** + * Checks if array of items contains duplicated items + * + * @param {array} children an array of items + * @returns {Boolean} if items contains duplicated items. + */ +export const hasDuplicatedChildren = (children) => { + const hashedKeys = children.map(generateHashedKey) + + return !hashedKeys.every( + (key, index) => index === hashedKeys.findIndex((childKey) => childKey === key) + ) +} diff --git a/packages/icons/README.md b/packages/icons/README.md new file mode 100644 index 00000000000..bb6e71ae47c --- /dev/null +++ b/packages/icons/README.md @@ -0,0 +1,122 @@ +# ./packages/icons + +This package is for custom Supabase icons +They can be used alongside any other icon packages + +## example use + +```jsx +import { ReplaceCode, InsertCode } from 'icons' + +function app() { + return ( + <> + + + + ) +} +``` + +## adding new icons + +Add new icons into ./src/raw-icons + +Make sure there are no inline stroke/border/fill colors (see below) + +run this in ./internal/build-icons + +```bash +npm run build +``` + +This will output icons into ./src/icons and update import names/paths + +### Design spec + +Icons should: + +- always be exported 24x24px, +- and have an icon inside that frame that's around 18x18px(ish) + +### ❌ bad example + +Notice the stroke, stroke-linecap, fills, etc. +These need to be in the parent so the react component can easily control it. +The SVG child elements will then respect their parent's attributes. + +```svg + + + + + + + + + +``` + +✅ Good example + +We've now cleaned it up, and the parent SVG element now has all the attributes for color and stroke width styling. +We have also removed the redundant elements that figma adds in like background / artboard backgrounds. + +```svg + + + + + + + +``` diff --git a/packages/icons/package.json b/packages/icons/package.json new file mode 100644 index 00000000000..c3f5262a17d --- /dev/null +++ b/packages/icons/package.json @@ -0,0 +1,11 @@ +{ + "name": "icons", + "main": "./src/icons/index.ts", + "scripts": { + "build:icons": "build-icons --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --iconFileExtension=.ts --exportFileName=index.ts" + }, + "dependencies": { + "typescript": "^5.2.2", + "@supabase/build-icons": "*" + } +} diff --git a/packages/icons/scripts/exportTemplate.mjs b/packages/icons/scripts/exportTemplate.mjs new file mode 100644 index 00000000000..3403186cc89 --- /dev/null +++ b/packages/icons/scripts/exportTemplate.mjs @@ -0,0 +1,25 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { base64SVG } from '@supabase/build-icons' + +export default ({ componentName, iconName, children, getSvg, deprecated }) => { + const svgContents = getSvg() + const svgBase64 = base64SVG(svgContents) + + return ` +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name ${componentName} + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,${svgBase64}) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * ${deprecated ? '@deprecated' : ''} + */ +const ${componentName} = createSupabaseIcon('${componentName}', ${JSON.stringify(children)}); + +export default ${componentName}; +` +} diff --git a/packages/icons/src/createSupabaseIcon.ts b/packages/icons/src/createSupabaseIcon.ts new file mode 100644 index 00000000000..172a509f94e --- /dev/null +++ b/packages/icons/src/createSupabaseIcon.ts @@ -0,0 +1,77 @@ +import { + forwardRef, + createElement, + ReactSVG, + SVGProps, + ForwardRefExoticComponent, + RefAttributes, +} from 'react'; +import defaultAttributes from './defaultAttributes'; + +export type IconNode = [elementName: keyof ReactSVG, attrs: Record][]; + +export type SVGAttributes = Partial>; +type ComponentAttributes = RefAttributes & SVGAttributes; + +export interface LucideProps extends ComponentAttributes { + size?: string | number; + absoluteStrokeWidth?: boolean; +} + +export type LucideIcon = ForwardRefExoticComponent; +/** + * Converts string to KebabCase + * Copied from scripts/helper. If anyone knows how to properly import it here + * then please fix it. + * + * @param {string} string + * @returns {string} A kebabized string + */ +export const toKebabCase = (string: string) => + string + .replace(/([a-z0-9])([A-Z])/g, '$1-$2') + .toLowerCase() + .trim(); + +const createLucideIcon = (iconName: string, iconNode: IconNode): LucideIcon => { + const Component = forwardRef( + ( + { + color = 'currentColor', + size = 24, + strokeWidth = 2, + absoluteStrokeWidth, + className = '', + children, + ...rest + }, + ref, + ) => { + return createElement( + 'svg', + { + ref, + ...defaultAttributes, + width: size, + height: size, + stroke: color, + strokeWidth: absoluteStrokeWidth + ? (Number(strokeWidth) * 24) / Number(size) + : strokeWidth, + className: ['lucide', `lucide-${toKebabCase(iconName)}`, className].join(' '), + ...rest, + }, + [ + ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)), + ...(Array.isArray(children) ? children : [children]), + ], + ); + }, + ); + + Component.displayName = `${iconName}`; + + return Component; +}; + +export default createLucideIcon; diff --git a/packages/icons/src/defaultAttributes.ts b/packages/icons/src/defaultAttributes.ts new file mode 100644 index 00000000000..ce97fb05877 --- /dev/null +++ b/packages/icons/src/defaultAttributes.ts @@ -0,0 +1,11 @@ +export default { + xmlns: 'http://www.w3.org/2000/svg', + width: 24, + height: 24, + viewBox: '0 0 24 24', + fill: 'none', + stroke: 'currentColor', + strokeWidth: 2, + strokeLinecap: 'round', + strokeLinejoin: 'round', +}; diff --git a/packages/icons/src/icon.schema.json b/packages/icons/src/icon.schema.json new file mode 100644 index 00000000000..895420b486c --- /dev/null +++ b/packages/icons/src/icon.schema.json @@ -0,0 +1,57 @@ +{ + "$id": "https://lucide.dev/icons.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/core": true, + "https://json-schema.org/draft/2020-12/vocab/applicator": true, + "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, + "https://json-schema.org/draft/2020-12/vocab/validation": true, + "https://json-schema.org/draft/2020-12/vocab/meta-data": true, + "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, + "https://json-schema.org/draft/2020-12/vocab/content": true + }, + "title": "Supabase icon schema (Originally from lucide.dev)", + "type": "object", + "additionalProperties": false, + "required": ["$schema", "categories", "tags"], + "properties": { + "$schema": { + "type": "string" + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "categories": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "contributors": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "deprecated": { + "type": "boolean", + "default": false + } + }, + "description": "A JSON Schema for icons, originally defined by Lucide Icons." +} diff --git a/packages/icons/src/icons/REST-api.ts b/packages/icons/src/icons/REST-api.ts new file mode 100644 index 00000000000..7619003584d --- /dev/null +++ b/packages/icons/src/icons/REST-api.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name RESTApi + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0zLjIwOTQ3IDEyLjEwNTJDMy4yMDk0NyAxMy40NDAzIDMuNTA3MTUgMTQuNzA2IDQuMDM5NzcgMTUuODM5NE0xMS45OTk3IDMuMzE0OTRDMTAuNjM5MSAzLjMxNDk0IDkuMzUwNjYgMy42MjQwOCA4LjIwMDg1IDQuMTc1OTRNMjAuNzg5OSAxMi4xMDUyQzIwLjc4OTkgMTAuNzU2NiAyMC40ODYyIDkuNDc4OTggMTkuOTQzNSA4LjMzNjk0TTExLjk5OTcgMjAuODk1NEMxMy4zNTc2IDIwLjg5NTQgMTQuNjQzNiAyMC41ODc1IDE1Ljc5MTcgMjAuMDM3N00xNS43OTE3IDIwLjAzNzdDMTYuMzMzNCAyMC44MTggMTcuMjM2IDIxLjMyODkgMTguMjU3OCAyMS4zMjg5QzE5LjkxNDcgMjEuMzI4OSAyMS4yNTc4IDE5Ljk4NTcgMjEuMjU3OCAxOC4zMjg5QzIxLjI1NzggMTYuNjcyIDE5LjkxNDcgMTUuMzI4OSAxOC4yNTc4IDE1LjMyODlDMTYuNjAxIDE1LjMyODkgMTUuMjU3OCAxNi42NzIgMTUuMjU3OCAxOC4zMjg5QzE1LjI1NzggMTguOTYzOSAxNS40NTUxIDE5LjU1MjggMTUuNzkxNyAyMC4wMzc3Wk00LjAzOTc3IDE1LjgzOTRDMy4yNDAyMiAxNi4zNzgyIDIuNzE0MzYgMTcuMjkyMSAyLjcxNDM2IDE4LjMyODlDMi43MTQzNiAxOS45ODU3IDQuMDU3NSAyMS4zMjg5IDUuNzE0MzYgMjEuMzI4OUM3LjM3MTIxIDIxLjMyODkgOC43MTQzNiAxOS45ODU3IDguNzE0MzYgMTguMzI4OUM4LjcxNDM2IDE2LjY3MiA3LjM3MTIxIDE1LjMyODkgNS43MTQzNiAxNS4zMjg5QzUuMDk0MjIgMTUuMzI4OSA0LjUxODAzIDE1LjUxNyA0LjAzOTc3IDE1LjgzOTRaTTguMjAwODUgNC4xNzU5NEM3LjY2MTU4IDMuMzc4OSA2Ljc0OTE1IDIuODU0OTggNS43MTQzNiAyLjg1NDk4QzQuMDU3NSAyLjg1NDk4IDIuNzE0MzYgNC4xOTgxMyAyLjcxNDM2IDUuODU0OThDMi43MTQzNiA3LjUxMTgzIDQuMDU3NSA4Ljg1NDk4IDUuNzE0MzYgOC44NTQ5OEM3LjM3MTIxIDguODU0OTggOC43MTQzNiA3LjUxMTgzIDguNzE0MzYgNS44NTQ5OEM4LjcxNDM2IDUuMjMyOTIgOC41MjUwMyA0LjY1NTA4IDguMjAwODUgNC4xNzU5NFpNMTkuOTQzNSA4LjMzNjk0QzIwLjczNjggNy43OTcwOSAyMS4yNTc4IDYuODg2ODggMjEuMjU3OCA1Ljg1NDk4QzIxLjI1NzggNC4xOTgxMyAxOS45MTQ3IDIuODU0OTggMTguMjU3OCAyLjg1NDk4QzE2LjYwMSAyLjg1NDk4IDE1LjI1NzggNC4xOTgxMyAxNS4yNTc4IDUuODU0OThDMTUuMjU3OCA3LjUxMTgzIDE2LjYwMSA4Ljg1NDk4IDE4LjI1NzggOC44NTQ5OEMxOC44ODI4IDguODU0OTggMTkuNDYzMSA4LjY2Mzg4IDE5Ljk0MzUgOC4zMzY5NFoiIC8+Cjwvc3ZnPg==) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const RESTApi = createSupabaseIcon('RESTApi', [ + [ + 'path', + { + d: 'M3.20947 12.1052C3.20947 13.4403 3.50715 14.706 4.03977 15.8394M11.9997 3.31494C10.6391 3.31494 9.35066 3.62408 8.20085 4.17594M20.7899 12.1052C20.7899 10.7566 20.4862 9.47898 19.9435 8.33694M11.9997 20.8954C13.3576 20.8954 14.6436 20.5875 15.7917 20.0377M15.7917 20.0377C16.3334 20.818 17.236 21.3289 18.2578 21.3289C19.9147 21.3289 21.2578 19.9857 21.2578 18.3289C21.2578 16.672 19.9147 15.3289 18.2578 15.3289C16.601 15.3289 15.2578 16.672 15.2578 18.3289C15.2578 18.9639 15.4551 19.5528 15.7917 20.0377ZM4.03977 15.8394C3.24022 16.3782 2.71436 17.2921 2.71436 18.3289C2.71436 19.9857 4.0575 21.3289 5.71436 21.3289C7.37121 21.3289 8.71436 19.9857 8.71436 18.3289C8.71436 16.672 7.37121 15.3289 5.71436 15.3289C5.09422 15.3289 4.51803 15.517 4.03977 15.8394ZM8.20085 4.17594C7.66158 3.3789 6.74915 2.85498 5.71436 2.85498C4.0575 2.85498 2.71436 4.19813 2.71436 5.85498C2.71436 7.51183 4.0575 8.85498 5.71436 8.85498C7.37121 8.85498 8.71436 7.51183 8.71436 5.85498C8.71436 5.23292 8.52503 4.65508 8.20085 4.17594ZM19.9435 8.33694C20.7368 7.79709 21.2578 6.88688 21.2578 5.85498C21.2578 4.19813 19.9147 2.85498 18.2578 2.85498C16.601 2.85498 15.2578 4.19813 15.2578 5.85498C15.2578 7.51183 16.601 8.85498 18.2578 8.85498C18.8828 8.85498 19.4631 8.66388 19.9435 8.33694Z', + key: 'xusdjk', + }, + ], +]); + +export default RESTApi; diff --git a/packages/icons/src/icons/_example-template.ts b/packages/icons/src/icons/_example-template.ts new file mode 100644 index 00000000000..9b4e8187c35 --- /dev/null +++ b/packages/icons/src/icons/_example-template.ts @@ -0,0 +1,20 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name ExampleTemplate + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHN0cm9rZT0iIzAwMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNmZmY7IGJvcmRlci1yYWRpdXM6IDJweCIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cGF0aCBkPSJNMy41IDEzaDYiIC8+CiAgPHBhdGggZD0ibTIgMTYgNC41LTkgNC41IDkiIC8+CiAgPHBhdGggZD0iTTE4IDd2OSIgLz4KICA8cGF0aCBkPSJtMTQgMTIgNCA0IDQtNCIgLz4KPC9zdmc+) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const ExampleTemplate = createSupabaseIcon('ExampleTemplate', [ + ['path', { d: 'M3.5 13h6', key: 'p1my2r' }], + ['path', { d: 'm2 16 4.5-9 4.5 9', key: 'ndf0b3' }], + ['path', { d: 'M18 7v9', key: 'pknjwm' }], + ['path', { d: 'm14 12 4 4 4-4', key: 'buelq4' }], +]); + +export default ExampleTemplate; diff --git a/packages/icons/src/icons/api-docs.ts b/packages/icons/src/icons/api-docs.ts new file mode 100644 index 00000000000..e8c26b1418d --- /dev/null +++ b/packages/icons/src/icons/api-docs.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name ApiDocs + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik03LjQ0NDM0IDE0LjMzNDdIMTYuNDQ0M003LjQ0NDM0IDExLjMzNDdIMTYuNDQ0M003LjQ0NDM0IDE3LjMzNDdIMTMuNDQ0M00xOS40OTk0IDguNTA3MTRWMTkuMTA1MkMxOS40OTk0IDIwLjIwOTcgMTguNjAzOSAyMS4xMDUyIDE3LjQ5OTQgMjEuMTA1Mkg2LjVDNS4zOTU0MyAyMS4xMDUyIDQuNSAyMC4yMDk3IDQuNSAxOS4xMDUyVjUuMTA1OTZDNC41IDQuMDAxMzkgNS4zOTU0MyAzLjEwNTk2IDYuNSAzLjEwNTk2SDE0LjA3MjNMMTkuNDk5NCA4LjUwNzE0Wk0xOS40NDY1IDguNDgxOTNMMTQuMDcwNCAzLjEwNTk2TDE0LjA3MDEgNy40ODE4NkMxNC4wNzAxIDguMDM0MTggMTQuNTE3OCA4LjQ4MTkzIDE1LjA3MDEgOC40ODE5M0wxOS40NDY1IDguNDgxOTNaIiAvPgo8L3N2Zz4=) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const ApiDocs = createSupabaseIcon('ApiDocs', [ + [ + 'path', + { + d: 'M7.44434 14.3347H16.4443M7.44434 11.3347H16.4443M7.44434 17.3347H13.4443M19.4994 8.50714V19.1052C19.4994 20.2097 18.6039 21.1052 17.4994 21.1052H6.5C5.39543 21.1052 4.5 20.2097 4.5 19.1052V5.10596C4.5 4.00139 5.39543 3.10596 6.5 3.10596H14.0723L19.4994 8.50714ZM19.4465 8.48193L14.0704 3.10596L14.0701 7.48186C14.0701 8.03418 14.5178 8.48193 15.0701 8.48193L19.4465 8.48193Z', + key: '2ysat9', + }, + ], +]); + +export default ApiDocs; diff --git a/packages/icons/src/icons/auth.ts b/packages/icons/src/icons/auth.ts new file mode 100644 index 00000000000..efa3dd02465 --- /dev/null +++ b/packages/icons/src/icons/auth.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Auth + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik01LjI0MTIxIDE1LjA2NzRIMTIuNzQxMk01LjI0MTIxIDE1LjA2NzRWMTguMDY3NEgxMi43NDEyVjE1LjA2NzRNNS4yNDEyMSAxNS4wNjc0VjEyLjA2NzRIMTIuNzQxMlYxNS4wNjc0TTE1IDcuNjA1NDdWNC42MDU0N0MxNSAyLjk0ODYxIDEzLjY1NjkgMS42MDU0NyAxMiAxLjYwNTQ3QzEwLjM0MzEgMS42MDU0NyA5IDIuOTQ4NjEgOSA0LjYwNTQ3VjcuNjA1NDdNNS4yMDg5OCA5LjYwNTQ3TDUuMjA4OTggMTkuMTA1NUM1LjIwODk4IDIwLjIxIDYuMTA0NDEgMjEuMTA1NSA3LjIwODk4IDIxLjEwNTVIMTYuNzA5QzE3LjgxMzYgMjEuMTA1NSAxOC43MDkgMjAuMjEgMTguNzA5IDE5LjEwNTVWOS42MDU0N0MxOC43MDkgOC41MDA5IDE3LjgxMzYgNy42MDU0NyAxNi43MDkgNy42MDU0N0w3LjIwODk5IDcuNjA1NDdDNi4xMDQ0MiA3LjYwNTQ3IDUuMjA4OTggOC41MDA5IDUuMjA4OTggOS42MDU0N1oiIC8+Cjwvc3ZnPg==) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Auth = createSupabaseIcon('Auth', [ + [ + 'path', + { + d: 'M5.24121 15.0674H12.7412M5.24121 15.0674V18.0674H12.7412V15.0674M5.24121 15.0674V12.0674H12.7412V15.0674M15 7.60547V4.60547C15 2.94861 13.6569 1.60547 12 1.60547C10.3431 1.60547 9 2.94861 9 4.60547V7.60547M5.20898 9.60547L5.20898 19.1055C5.20898 20.21 6.10441 21.1055 7.20898 21.1055H16.709C17.8136 21.1055 18.709 20.21 18.709 19.1055V9.60547C18.709 8.5009 17.8136 7.60547 16.709 7.60547L7.20899 7.60547C6.10442 7.60547 5.20898 8.5009 5.20898 9.60547Z', + key: 'h65u22', + }, + ], +]); + +export default Auth; diff --git a/packages/icons/src/icons/database.ts b/packages/icons/src/icons/database.ts new file mode 100644 index 00000000000..d97720e76a4 --- /dev/null +++ b/packages/icons/src/icons/database.ts @@ -0,0 +1,31 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Database + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aCBkPSIgTTUuNTY3NzQgOS43MDY0MkgxOC40NTQ3VjE1LjcwNjRINS41Njc3NFY5LjcwNjQyWiIgLz4KICAgIDxwYXRoIGQ9IiBNNC41IDE2LjcwOTRDNC41IDE2LjE1NzEgNC45NDc3MiAxNS43MDk0IDUuNSAxNS43MDk0SDE4LjVDMTkuMDUyMyAxNS43MDk0IDE5LjUgMTYuMTU3MSAxOS41CiAgICAgICAgMTYuNzA5NFYyMC43MDk0QzE5LjUgMjEuMjYxNiAxOS4wNTIzIDIxLjcwOTQgMTguNSAyMS43MDk0SDUuNUM0Ljk0NzcyIDIxLjcwOTQgNC41IDIxLjI2MTYgNC41CiAgICAgICAgMjAuNzA5NFYxNi43MDk0WiIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTQuNSA0LjcwNjc5QzQuNSA0LjE1NDUgNC45NDc3MiAzLjcwNjc5IDUuNSAzLjcwNjc5SDE4LjVDMTkuMDUyMyAzLjcwNjc5IDE5LjUgNC4xNTQ1IDE5LjUgNC43MDY3OVY4LjcwNjc5QzE5LjUgOS4yNTkwNyAxOS4wNTIzIDkuNzA2NzkgMTguNSA5LjcwNjc5SDUuNUM0Ljk0NzcyIDkuNzA2NzkgNC41IDkuMjU5MDcgNC41IDguNzA2NzlWNC43MDY3OVoiIC8+Cjwvc3ZnPg==) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Database = createSupabaseIcon('Database', [ + ['path', { d: ' M5.56774 9.70642H18.4547V15.7064H5.56774V9.70642Z', key: 'g5hndz' }], + [ + 'path', + { + d: ' M4.5 16.7094C4.5 16.1571 4.94772 15.7094 5.5 15.7094H18.5C19.0523 15.7094 19.5 16.1571 19.5\n 16.7094V20.7094C19.5 21.2616 19.0523 21.7094 18.5 21.7094H5.5C4.94772 21.7094 4.5 21.2616 4.5\n 20.7094V16.7094Z', + key: '1m5ehm', + }, + ], + [ + 'path', + { + d: 'M4.5 4.70679C4.5 4.1545 4.94772 3.70679 5.5 3.70679H18.5C19.0523 3.70679 19.5 4.1545 19.5 4.70679V8.70679C19.5 9.25907 19.0523 9.70679 18.5 9.70679H5.5C4.94772 9.70679 4.5 9.25907 4.5 8.70679V4.70679Z', + key: '1w4kbe', + }, + ], +]); + +export default Database; diff --git a/packages/icons/src/icons/edge-functions.ts b/packages/icons/src/icons/edge-functions.ts new file mode 100644 index 00000000000..86487185a46 --- /dev/null +++ b/packages/icons/src/icons/edge-functions.ts @@ -0,0 +1,44 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name EdgeFunctions + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0xOCAxMi4xMDU1QzE4IDE1LjQxOTIgMTUuMzEzNyAxOC4xMDU1IDEyIDE4LjEwNTVDOC42ODYzIDE4LjEwNTUgNi4wMDAwMSAxNS40MTkyIDYuMDAwMDEgMTIuMTA1NUM2LjAwMDAxIDguNzkxNzYgOC42ODYzIDYuMTA1NDcgMTIgNi4xMDU0N0MxNS4zMTM3IDYuMTA1NDcgMTggOC43OTE3NiAxOCAxMi4xMDU1WiIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTIxLjM5OTkgNS43MDE1NEMyMS4zOTk5IDcuMzU4MzkgMjAuMDU2OCA4LjcwMTU0IDE4LjM5OTkgOC43MDE1NEMxNi43NDMxIDguNzAxNTQgMTUuMzk5OSA3LjM1ODM5IDE1LjM5OTkgNS43MDE1NEMxNS4zOTk5IDQuMDQ0NjggMTYuNzQzMSAyLjcwMTU0IDE4LjM5OTkgMi43MDE1NEMyMC4wNTY4IDIuNzAxNTQgMjEuMzk5OSA0LjA0NDY4IDIxLjM5OTkgNS43MDE1NFoiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik04LjYyMjE2IDE4LjQzNjNDOC42MjIxNiAyMC4wOTMyIDcuMjc5MDIgMjEuNDM2MyA1LjYyMjE2IDIxLjQzNjNDMy45NjUzMSAyMS40MzYzIDIuNjIyMTYgMjAuMDkzMiAyLjYyMjE2IDE4LjQzNjNDMi42MjIxNiAxNi43Nzk1IDMuOTY1MzEgMTUuNDM2MyA1LjYyMjE2IDE1LjQzNjNDNy4yNzkwMiAxNS40MzYzIDguNjIyMTYgMTYuNzc5NSA4LjYyMjE2IDE4LjQzNjNaIiAvPgogICAgPHBhdGgKICAgICAgICBkPSJNMy4xODEyMSAxNi4yNjkxQzIuNTg0MDEgMTUuMDA2NSAyLjI1IDEzLjU5NSAyLjI1IDEyLjEwNTVDMi4yNSA2LjcyMDY5IDYuNjE1MjIgMi4zNTU0NyAxMiAyLjM1NTQ3QzEzLjQ4OTMgMi4zNTU0NyAxNC45MDA1IDIuNjg5MzcgMTYuMTYzIDMuMjg2MzhNNy42ODY3OSAyMC44NTJDOC45ODcxNSAyMS40OTQ0IDEwLjQ1MTQgMjEuODU1NSAxMiAyMS44NTU1QzE3LjM4NDggMjEuODU1NSAyMS43NSAxNy40OTAyIDIxLjc1IDEyLjEwNTVDMjEuNzUgMTAuNjE2MiAyMS40MTYxIDkuMjA0OTMgMjAuODE5MSA3Ljk0MjQyIiAvPgo8L3N2Zz4=) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const EdgeFunctions = createSupabaseIcon('EdgeFunctions', [ + [ + 'path', + { + d: 'M18 12.1055C18 15.4192 15.3137 18.1055 12 18.1055C8.6863 18.1055 6.00001 15.4192 6.00001 12.1055C6.00001 8.79176 8.6863 6.10547 12 6.10547C15.3137 6.10547 18 8.79176 18 12.1055Z', + key: '1vv84o', + }, + ], + [ + 'path', + { + d: 'M21.3999 5.70154C21.3999 7.35839 20.0568 8.70154 18.3999 8.70154C16.7431 8.70154 15.3999 7.35839 15.3999 5.70154C15.3999 4.04468 16.7431 2.70154 18.3999 2.70154C20.0568 2.70154 21.3999 4.04468 21.3999 5.70154Z', + key: '1vzce8', + }, + ], + [ + 'path', + { + d: 'M8.62216 18.4363C8.62216 20.0932 7.27902 21.4363 5.62216 21.4363C3.96531 21.4363 2.62216 20.0932 2.62216 18.4363C2.62216 16.7795 3.96531 15.4363 5.62216 15.4363C7.27902 15.4363 8.62216 16.7795 8.62216 18.4363Z', + key: 's8poqq', + }, + ], + [ + 'path', + { + d: 'M3.18121 16.2691C2.58401 15.0065 2.25 13.595 2.25 12.1055C2.25 6.72069 6.61522 2.35547 12 2.35547C13.4893 2.35547 14.9005 2.68937 16.163 3.28638M7.68679 20.852C8.98715 21.4944 10.4514 21.8555 12 21.8555C17.3848 21.8555 21.75 17.4902 21.75 12.1055C21.75 10.6162 21.4161 9.20493 20.8191 7.94242', + key: 'xs92pm', + }, + ], +]); + +export default EdgeFunctions; diff --git a/packages/icons/src/icons/home.ts b/packages/icons/src/icons/home.ts new file mode 100644 index 00000000000..e9a0eaaea55 --- /dev/null +++ b/packages/icons/src/icons/home.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Home + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik05LjQzNDE0IDIwLjgwM1YxMy4wNTU3QzkuNDM0MTQgMTIuNTAzNCA5Ljg4MTg2IDEyLjA1NTcgMTAuNDM0MSAxMi4wNTU3SDE0Ljc2NzlDMTUuMzIwMiAxMi4wNTU3IDE1Ljc2NzkgMTIuNTAzNCAxNS43Njc5IDEzLjA1NTdWMjAuODAzTTEyLjAxODEgMy40ODc5OEw1LjUzMDMxIDcuOTk4NEM1LjI2MTQ1IDguMTg1MzIgNS4xMDExNCA4LjQ5MjAyIDUuMTAxMTQgOC44MTk0OEw1LjEwMTE3IDE4LjgwM0M1LjEwMTE3IDE5LjkwNzUgNS45OTY2IDIwLjgwMyA3LjEwMTE3IDIwLjgwM0gxOC4xMDEyQzE5LjIwNTcgMjAuODAzIDIwLjEwMTIgMTkuOTA3NSAyMC4xMDEyIDE4LjgwM0wyMC4xMDExIDguODg1NTRDMjAuMTAxMSA4LjU1OTg4IDE5Ljk0MjYgOC4yNTQ2MiAxOS42NzYxIDguMDY3MzdMMTMuMTYzOSAzLjQ5MDg4QzEyLjgyMDQgMy4yNDk1MSAxMi4zNjI3IDMuMjQ4MzYgMTIuMDE4MSAzLjQ4Nzk4WiIgLz4KPC9zdmc+) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Home = createSupabaseIcon('Home', [ + [ + 'path', + { + d: 'M9.43414 20.803V13.0557C9.43414 12.5034 9.88186 12.0557 10.4341 12.0557H14.7679C15.3202 12.0557 15.7679 12.5034 15.7679 13.0557V20.803M12.0181 3.48798L5.53031 7.9984C5.26145 8.18532 5.10114 8.49202 5.10114 8.81948L5.10117 18.803C5.10117 19.9075 5.9966 20.803 7.10117 20.803H18.1012C19.2057 20.803 20.1012 19.9075 20.1012 18.803L20.1011 8.88554C20.1011 8.55988 19.9426 8.25462 19.6761 8.06737L13.1639 3.49088C12.8204 3.24951 12.3627 3.24836 12.0181 3.48798Z', + key: '1bkqgr', + }, + ], +]); + +export default Home; diff --git a/packages/icons/src/icons/index.ts b/packages/icons/src/icons/index.ts new file mode 100644 index 00000000000..080ce9b415c --- /dev/null +++ b/packages/icons/src/icons/index.ts @@ -0,0 +1,20 @@ +export { default as RESTApi } from './REST-api'; +export { default as ExampleTemplate } from './_example-template'; +export { default as ApiDocs } from './api-docs'; +export { default as Auth } from './auth'; +export { default as Database } from './database'; +export { default as EdgeFunctions } from './edge-functions'; +export { default as Home } from './home'; +export { default as InsertCode } from './insert-code'; +export { default as Integrations } from './integrations'; +export { default as Logs } from './logs'; +export { default as Postgres } from './postgres'; +export { default as Realtime } from './realtime'; +export { default as ReplaceCode } from './replace-code'; +export { default as Reports } from './reports'; +export { default as Settings } from './settings'; +export { default as SqlEditor } from './sql-editor'; +export { default as Storage } from './storage'; +export { default as TableEditor } from './table-editor'; +export { default as User } from './user'; + diff --git a/packages/icons/src/icons/insert-code.ts b/packages/icons/src/icons/insert-code.ts new file mode 100644 index 00000000000..f79645722a9 --- /dev/null +++ b/packages/icons/src/icons/insert-code.ts @@ -0,0 +1,58 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name InsertCode + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj4KICAgIDxwYXRoCiAgICAgICAgZD0iTS0yMDQzNyAtMTExNDJIMTIxMzFWLTExMTQ0SC0yMDQzN1YtMTExNDJaTTEyMTMyIC0xMTE0MVY3MTEzSDEyMTM0Vi0xMTE0MUgxMjEzMlpNMTIxMzEgNzExNEgtMjA0MzdWNzExNkgxMjEzMVY3MTE0Wk0tMjA0MzggNzExM1YtMTExNDFILTIwNDQwVjcxMTNILTIwNDM4Wk0tMjA0MzcgNzExNEMtMjA0MzcuNiA3MTE0IC0yMDQzOCA3MTEzLjU1IC0yMDQzOCA3MTEzSC0yMDQ0MEMtMjA0NDAgNzExNC42NiAtMjA0MzguNyA3MTE2IC0yMDQzNyA3MTE2VjcxMTRaTTEyMTMyIDcxMTNDMTIxMzIgNzExMy41NSAxMjEzMS42IDcxMTQgMTIxMzEgNzExNFY3MTE2QzEyMTMyLjcgNzExNiAxMjEzNCA3MTE0LjY2IDEyMTM0IDcxMTNIMTIxMzJaTTEyMTMxIC0xMTE0MkMxMjEzMS42IC0xMTE0MiAxMjEzMiAtMTExNDEuNiAxMjEzMiAtMTExNDFIMTIxMzRDMTIxMzQgLTExMTQyLjcgMTIxMzIuNyAtMTExNDQgMTIxMzEgLTExMTQ0Vi0xMTE0MlpNLTIwNDM3IC0xMTE0NEMtMjA0MzguNyAtMTExNDQgLTIwNDQwIC0xMTE0Mi43IC0yMDQ0MCAtMTExNDFILTIwNDM4Qy0yMDQzOCAtMTExNDEuNiAtMjA0MzcuNiAtMTExNDIgLTIwNDM3IC0xMTE0MlYtMTExNDRaIgogICAgICAgIGZpbGw9IndoaXRlIiBmaWxsLW9wYWNpdHk9IjAuMSIgLz4KICAgIDxwYXRoIGQ9Ik0yMi44NDM3IDguNjk0OTlMMTkuNTM2OSAxMi4wMDE4TDIyLjg0MzggMTUuMzA4NiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiAvPgogICAgPHJlY3QgeD0iMC41IiB5PSIxNC4wNjI1IiB3aWR0aD0iMTYiIGhlaWdodD0iOCIgcng9IjEiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIC8+CiAgICA8cmVjdCB4PSIwLjUiIHk9IjEuOTM3NSIgd2lkdGg9IjE2IiBoZWlnaHQ9IjgiIHJ4PSIxIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiAvPgo8L3N2Zz4=) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const InsertCode = createSupabaseIcon('InsertCode', [ + [ + 'path', + { + d: 'M-20437 -11142H12131V-11144H-20437V-11142ZM12132 -11141V7113H12134V-11141H12132ZM12131 7114H-20437V7116H12131V7114ZM-20438 7113V-11141H-20440V7113H-20438ZM-20437 7114C-20437.6 7114 -20438 7113.55 -20438 7113H-20440C-20440 7114.66 -20438.7 7116 -20437 7116V7114ZM12132 7113C12132 7113.55 12131.6 7114 12131 7114V7116C12132.7 7116 12134 7114.66 12134 7113H12132ZM12131 -11142C12131.6 -11142 12132 -11141.6 12132 -11141H12134C12134 -11142.7 12132.7 -11144 12131 -11144V-11142ZM-20437 -11144C-20438.7 -11144 -20440 -11142.7 -20440 -11141H-20438C-20438 -11141.6 -20437.6 -11142 -20437 -11142V-11144Z', + fill: 'white', + 'fill-opacity': '0.1', + key: 'iaqtc1', + }, + ], + [ + 'path', + { + d: 'M22.8437 8.69499L19.5369 12.0018L22.8438 15.3086', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + key: '1gnkuu', + }, + ], + [ + 'rect', + { + x: '0.5', + y: '14.0625', + width: '16', + height: '8', + rx: '1', + 'stroke-linejoin': 'round', + key: 't6herz', + }, + ], + [ + 'rect', + { + x: '0.5', + y: '1.9375', + width: '16', + height: '8', + rx: '1', + 'stroke-linejoin': 'round', + key: '718qtu', + }, + ], +]); + +export default InsertCode; diff --git a/packages/icons/src/icons/integrations.ts b/packages/icons/src/icons/integrations.ts new file mode 100644 index 00000000000..34efe273ac2 --- /dev/null +++ b/packages/icons/src/icons/integrations.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Integrations + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0xNy4yNjYxIDMuMjMyNTRWMTAuNzMyNU0xMy41MTYxIDYuOTgyOTFMMjEuMDE2MSA2Ljk4MjkxTTExLjAzOTEgMTYuOTUwOEMxMS4wMzkxIDE5LjE3NTIgOS4yMzU4NSAyMC45Nzg0IDcuMDExNDcgMjAuOTc4NEM0Ljc4NzEgMjAuOTc4NCAyLjk4Mzg5IDE5LjE3NTIgMi45ODM4OSAxNi45NTA4QzIuOTgzODkgMTQuNzI2NCA0Ljc4NzEgMTIuOTIzMiA3LjAxMTQ3IDEyLjkyMzJDOS4yMzU4NSAxMi45MjMyIDExLjAzOTEgMTQuNzI2NCAxMS4wMzkxIDE2Ljk1MDhaTTIxLjAxNjEgMTkuODU2OFYxNC4zNTY4QzIxLjAxNjEgMTMuODA0NSAyMC41Njg0IDEzLjM1NjggMjAuMDE2MSAxMy4zNTY4SDE0LjUxNjFDMTMuOTYzOCAxMy4zNTY4IDEzLjUxNjEgMTMuODA0NSAxMy41MTYxIDE0LjM1NjhWMTkuODU2OEMxMy41MTYxIDIwLjQwOTEgMTMuOTYzOCAyMC44NTY4IDE0LjUxNjEgMjAuODU2OEgyMC4wMTYxQzIwLjU2ODQgMjAuODU2OCAyMS4wMTYxIDIwLjQwOTEgMjEuMDE2MSAxOS44NTY4Wk00LjI2MjIxIDEwLjczMjVIOS43NjIyMUMxMC4zMTQ1IDEwLjczMjUgMTAuNzYyMiAxMC4yODQ4IDEwLjc2MjIgOS43MzI1NFY0LjIzMjU0QzEwLjc2MjIgMy42ODAyNiAxMC4zMTQ1IDMuMjMyNTQgOS43NjIyMSAzLjIzMjU0SDQuMjYyMjFDMy43MDk5MiAzLjIzMjU0IDMuMjYyMjEgMy42ODAyNiAzLjI2MjIxIDQuMjMyNTRWOS43MzI1NEMzLjI2MjIxIDEwLjI4NDggMy43MDk5MiAxMC43MzI1IDQuMjYyMjEgMTAuNzMyNVoiIC8+Cjwvc3ZnPg==) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Integrations = createSupabaseIcon('Integrations', [ + [ + 'path', + { + d: 'M17.2661 3.23254V10.7325M13.5161 6.98291L21.0161 6.98291M11.0391 16.9508C11.0391 19.1752 9.23585 20.9784 7.01147 20.9784C4.7871 20.9784 2.98389 19.1752 2.98389 16.9508C2.98389 14.7264 4.7871 12.9232 7.01147 12.9232C9.23585 12.9232 11.0391 14.7264 11.0391 16.9508ZM21.0161 19.8568V14.3568C21.0161 13.8045 20.5684 13.3568 20.0161 13.3568H14.5161C13.9638 13.3568 13.5161 13.8045 13.5161 14.3568V19.8568C13.5161 20.4091 13.9638 20.8568 14.5161 20.8568H20.0161C20.5684 20.8568 21.0161 20.4091 21.0161 19.8568ZM4.26221 10.7325H9.76221C10.3145 10.7325 10.7622 10.2848 10.7622 9.73254V4.23254C10.7622 3.68026 10.3145 3.23254 9.76221 3.23254H4.26221C3.70992 3.23254 3.26221 3.68026 3.26221 4.23254V9.73254C3.26221 10.2848 3.70992 10.7325 4.26221 10.7325Z', + key: '3dnck7', + }, + ], +]); + +export default Integrations; diff --git a/packages/icons/src/icons/logs.ts b/packages/icons/src/icons/logs.ts new file mode 100644 index 00000000000..4f6bbe369d7 --- /dev/null +++ b/packages/icons/src/icons/logs.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Logs + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik00LjUgNS4yMDY3OUg0LjUzNzEzTTcuNDYyNDEgNS4yMTcwN0gxOS41TTQuNSA5LjY1ODM5SDQuNTM3MTNNNy40NjI0MSA5LjY2ODY4SDE5LjVNNC41MjY5MiAxNC4xNjRINC41MzcxM003LjQ2MjQxIDE0LjE3NDJIMTkuNU00LjUyNjkyIDE4LjcwNjhMNC41MzcxMyAxOC42OTY1TTcuNDYyNDEgMTguNzA2OEgxOS41IiAvPgo8L3N2Zz4=) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Logs = createSupabaseIcon('Logs', [ + [ + 'path', + { + d: 'M4.5 5.20679H4.53713M7.46241 5.21707H19.5M4.5 9.65839H4.53713M7.46241 9.66868H19.5M4.52692 14.164H4.53713M7.46241 14.1742H19.5M4.52692 18.7068L4.53713 18.6965M7.46241 18.7068H19.5', + key: '2ab8w8', + }, + ], +]); + +export default Logs; diff --git a/packages/icons/src/icons/postgres.ts b/packages/icons/src/icons/postgres.ts new file mode 100644 index 00000000000..424ed6c3f27 --- /dev/null +++ b/packages/icons/src/icons/postgres.ts @@ -0,0 +1,30 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Postgres + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0xMS41NDY2IDMuMjMxMDhDMTEuMjcwNCAzLjIzMTA4IDExLjA0NjYgMy40NTQ5NCAxMS4wNDY2IDMuNzMxMDhDMTEuMDQ2NiA0LjAwNzIyIDExLjI3MDQgNC4yMzEwOCAxMS41NDY2IDQuMjMxMDhWMy4yMzEwOFpNMjAuNjU2OSAxOS41MDQ2QzIwLjY1NjkgMTkuMjI4NSAyMC40MzMgMTkuMDA0NiAyMC4xNTY5IDE5LjAwNDZDMTkuODgwOCAxOS4wMDQ2IDE5LjY1NjkgMTkuMjI4NSAxOS42NTY5IDE5LjUwNDZIMjAuNjU2OVpNMTkuNjU2OSAxNS45NjU2QzE5LjY1NjkgMTYuMjQxNyAxOS44ODA4IDE2LjQ2NTYgMjAuMTU2OSAxNi40NjU2QzIwLjQzMyAxNi40NjU2IDIwLjY1NjkgMTYuMjQxNyAyMC42NTY5IDE1Ljk2NTZIMTkuNjU2OVpNMTMuMDExOSAxOS41NTM2QzEyLjk1OSAxOS4yODI2IDEyLjY5NjQgMTkuMTA1OCAxMi40MjU0IDE5LjE1ODZDMTIuMTU0NCAxOS4yMTE1IDExLjk3NzUgMTkuNDc0MSAxMi4wMzA0IDE5Ljc0NTJMMTMuMDExOSAxOS41NTM2Wk05Ljg3MzgxIDE4Ljg1NjVMOS4zNzM4MSAxOC44NTY1VjE4Ljg1NjVIOS44NzM4MVpNNC4yMDcyMSA1LjI5OTMyTDMuNzM3ODQgNS4xMjY5OUwzLjczNzg0IDUuMTI3TDQuMjA3MjEgNS4yOTkzMlpNMi41MjUyNyA5Ljg4MDQ2TDIuMDU1OSA5LjcwODE0TDIuMDU1OSA5LjcwODE0TDIuNTI1MjcgOS44ODA0NlpNMy4yNDkyMiAxMi42ODczTDIuOTIxNzYgMTMuMDY1MUwyLjkyMTc2IDEzLjA2NTFMMy4yNDkyMiAxMi42ODczWk00LjQwMzM0IDEzLjY4NzVMNC4wNzU4OCAxNC4wNjUzTDQuMDc1ODggMTQuMDY1M0w0LjQwMzM0IDEzLjY4NzVaTTUuMDA5NzEgMTUuMDE1NEw0LjUwOTcxIDE1LjAxNTRMNC41MDk3MSAxNS4wMTU0TDUuMDA5NzEgMTUuMDE1NFpNNS4wMDk2OSAxNi44NTM2TDUuNTA5NjkgMTYuODUzNkw1LjUwOTY5IDE2Ljg1MzZMNS4wMDk2OSAxNi44NTM2Wk05Ljg3Mzg1IDEwLjY2NjFMOS4zNzM4NSAxMC42NjYxTDkuMzczODUgMTAuNjY2MUw5Ljg3Mzg1IDEwLjY2NjFaTTExLjkzOTkgNi45MDc4M0MxMi4xMzYgNi43MTMzOSAxMi4xMzczIDYuMzk2ODEgMTEuOTQyOSA2LjIwMDczQzExLjc0ODQgNi4wMDQ2NCAxMS40MzE5IDYuMDAzMzEgMTEuMjM1OCA2LjE5Nzc0TDExLjkzOTkgNi45MDc4M1pNMTcuODQxIDE4Ljc1MDZMMTcuODQwOSAxOC4yNTA2TDE3Ljg0MDkgMTguMjUwNkwxNy44NDEgMTguNzUwNlpNMjMuMDY3NiAxOS4yNTA2QzIzLjM0MzcgMTkuMjUwNiAyMy41Njc2IDE5LjAyNjcgMjMuNTY3NSAxOC43NTA2QzIzLjU2NzUgMTguNDc0NCAyMy4zNDM3IDE4LjI1MDYgMjMuMDY3NSAxOC4yNTA2TDIzLjA2NzYgMTkuMjUwNlpNMTMuMDE3MSAxNS4yNDQ2QzEyLjg5NTUgMTQuOTk2NyAxMi41OTU5IDE0Ljg5NDMgMTIuMzQ4IDE1LjAxNkMxMi4xMDAxIDE1LjEzNzYgMTEuOTk3OCAxNS40MzcyIDEyLjExOTQgMTUuNjg1MUwxMy4wMTcxIDE1LjI0NDZaTTExLjU0NjYgNC4yMzEwOEgxMi42MDhWMy4yMzEwOEgxMS41NDY2VjQuMjMxMDhaTTE5LjY1NjkgMTkuNTA0NkMxOS42NTY5IDIxLjAyNjQgMTguMjQ2NyAyMi4yNjA2IDE2LjMwMzMgMjIuMjYwNlYyMy4yNjA2QzE4LjYxNjUgMjMuMjYwNiAyMC42NTY5IDIxLjc0NDkgMjAuNjU2OSAxOS41MDQ2SDE5LjY1NjlaTTEyLjYwOCA0LjIzMTA4QzE2LjUwMSA0LjIzMTA4IDE5LjY1NjkgNy4zODY5OCAxOS42NTY5IDExLjI4SDIwLjY1NjlDMjAuNjU2OSA2LjgzNDcgMTcuMDUzMyAzLjIzMTA4IDEyLjYwOCAzLjIzMTA4VjQuMjMxMDhaTTE5LjY1NjkgMTEuMjhWMTUuOTY1NkgyMC42NTY5VjExLjI4SDE5LjY1NjlaTTE2LjMwMzMgMjIuMjYwNkMxNC42NzI3IDIyLjI2MDYgMTMuMzEzIDIxLjA5NjQgMTMuMDExOSAxOS41NTM2TDEyLjAzMDQgMTkuNzQ1MkMxMi40MjE0IDIxLjc0ODUgMTQuMTg1MiAyMy4yNjA2IDE2LjMwMzMgMjMuMjYwNlYyMi4yNjA2Wk0xMS42NTUyIDMuMjIzMzlINi40NjQ1OVY0LjIyMzM5SDExLjY1NTJWMy4yMjMzOVpNMy43Mzc4NCA1LjEyN0wyLjA1NTkgOS43MDgxNEwyLjk5NDY0IDEwLjA1MjhMNC42NzY1OCA1LjQ3MTY0TDMuNzM3ODQgNS4xMjdaTTIuOTIxNzYgMTMuMDY1MUw0LjA3NTg4IDE0LjA2NTNMNC43MzA4IDEzLjMwOTZMMy41NzY2OCAxMi4zMDk0TDIuOTIxNzYgMTMuMDY1MVpNNC41MDk3MSAxNS4wMTU0TDQuNTA5NjkgMTYuODUzNkw1LjUwOTY5IDE2Ljg1MzZMNS41MDk3MSAxNS4wMTU0TDQuNTA5NzEgMTUuMDE1NFpNMTAuMzczOSAxMC42NjYxQzEwLjM3MzkgOS4yNTQ2MyAxMC45Mzc2IDcuOTAxNjYgMTEuOTM5OSA2LjkwNzgzTDExLjIzNTggNi4xOTc3NEMxMC4wNDQyIDcuMzc5MzQgOS4zNzM4NyA4Ljk4Nzk1IDkuMzczODUgMTAuNjY2MUwxMC4zNzM5IDEwLjY2NjFaTTIuMDU1OSA5LjcwODE0QzEuNjE4OTMgMTAuODk4MyAxLjk2MzYzIDEyLjIzNDggMi45MjE3NiAxMy4wNjUxTDMuNTc2NjggMTIuMzA5NEMyLjkzMjYgMTEuNzUxMiAyLjcwMDg5IDEwLjg1MjkgMi45OTQ2NCAxMC4wNTI4TDIuMDU1OSA5LjcwODE0Wk04LjQ0MzE5IDIwLjc4NzJDOS41MDk0NCAyMC43ODcyIDEwLjM3MzggMTkuOTIyOCAxMC4zNzM4IDE4Ljg1NjVIOS4zNzM4MUM5LjM3MzgxIDE5LjM3MDUgOC45NTcxNiAxOS43ODcyIDguNDQzMTkgMTkuNzg3MlYyMC43ODcyWk04LjQ0MzE5IDE5Ljc4NzJDNi44MjMwNSAxOS43ODcyIDUuNTA5NjcgMTguNDczOCA1LjUwOTY5IDE2Ljg1MzZMNC41MDk2OSAxNi44NTM2QzQuNTA5NjYgMTkuMDI2IDYuMjcwNzUgMjAuNzg3MiA4LjQ0MzE5IDIwLjc4NzJWMTkuNzg3MlpNNC4wNzU4OCAxNC4wNjUzQzQuMzUxNDIgMTQuMzA0MSA0LjUwOTcyIDE0LjY1MDggNC41MDk3MSAxNS4wMTU0TDUuNTA5NzEgMTUuMDE1NEM1LjUwOTcyIDE0LjM2MDggNS4yMjU1MiAxMy43Mzg0IDQuNzMwOCAxMy4zMDk2TDQuMDc1ODggMTQuMDY1M1pNNi40NjQ1OSAzLjIyMzM5QzUuMjQ2NDMgMy4yMjMzOSA0LjE1NzY4IDMuOTgzNDcgMy43Mzc4NCA1LjEyNjk5TDQuNjc2NTggNS40NzE2NEM0Ljk1MTg4IDQuNzIxOCA1LjY2NTgxIDQuMjIzMzkgNi40NjQ1OSA0LjIyMzM5VjMuMjIzMzlaTTE3Ljg0MSAxOS4yNTA2TDIzLjA2NzYgMTkuMjUwNkwyMy4wNjc1IDE4LjI1MDZMMTcuODQwOSAxOC4yNTA2TDE3Ljg0MSAxOS4yNTA2Wk0xMi4xMTk0IDE1LjY4NTFDMTMuMTkwNSAxNy44Njc2IDE1LjQwOTggMTkuMjUwNyAxNy44NDEgMTkuMjUwNkwxNy44NDA5IDE4LjI1MDZDMTUuNzkxMyAxOC4yNTA3IDEzLjkyMDEgMTcuMDg0NiAxMy4wMTcxIDE1LjI0NDZMMTIuMTE5NCAxNS42ODUxWk0xMC4zNzM4IDE4Ljg1NjVMMTAuMzczOSAxMC42NjYxTDkuMzczODUgMTAuNjY2MUw5LjM3MzgxIDE4Ljg1NjVMMTAuMzczOCAxOC44NTY1WiIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTE1LjcxNTEgMTEuMjA1NkMxNS43MTUxIDExLjYyNTcgMTYuMDU1NiAxMS45NjYzIDE2LjQ3NTggMTEuOTY2M0MxNi44OTU5IDExLjk2NjMgMTcuMjM2NSAxMS42MjU3IDE3LjIzNjUgMTEuMjA1NkMxNy4yMzY1IDEwLjc4NTQgMTYuODk1OSAxMC40NDQ4IDE2LjQ3NTggMTAuNDQ0OEMxNi4wNTU2IDEwLjQ0NDggMTUuNzE1MSAxMC43ODU0IDE1LjcxNTEgMTEuMjA1NloiIC8+Cjwvc3ZnPg==) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Postgres = createSupabaseIcon('Postgres', [ + [ + 'path', + { + d: 'M11.5466 3.23108C11.2704 3.23108 11.0466 3.45494 11.0466 3.73108C11.0466 4.00722 11.2704 4.23108 11.5466 4.23108V3.23108ZM20.6569 19.5046C20.6569 19.2285 20.433 19.0046 20.1569 19.0046C19.8808 19.0046 19.6569 19.2285 19.6569 19.5046H20.6569ZM19.6569 15.9656C19.6569 16.2417 19.8808 16.4656 20.1569 16.4656C20.433 16.4656 20.6569 16.2417 20.6569 15.9656H19.6569ZM13.0119 19.5536C12.959 19.2826 12.6964 19.1058 12.4254 19.1586C12.1544 19.2115 11.9775 19.4741 12.0304 19.7452L13.0119 19.5536ZM9.87381 18.8565L9.37381 18.8565V18.8565H9.87381ZM4.20721 5.29932L3.73784 5.12699L3.73784 5.127L4.20721 5.29932ZM2.52527 9.88046L2.0559 9.70814L2.0559 9.70814L2.52527 9.88046ZM3.24922 12.6873L2.92176 13.0651L2.92176 13.0651L3.24922 12.6873ZM4.40334 13.6875L4.07588 14.0653L4.07588 14.0653L4.40334 13.6875ZM5.00971 15.0154L4.50971 15.0154L4.50971 15.0154L5.00971 15.0154ZM5.00969 16.8536L5.50969 16.8536L5.50969 16.8536L5.00969 16.8536ZM9.87385 10.6661L9.37385 10.6661L9.37385 10.6661L9.87385 10.6661ZM11.9399 6.90783C12.136 6.71339 12.1373 6.39681 11.9429 6.20073C11.7484 6.00464 11.4319 6.00331 11.2358 6.19774L11.9399 6.90783ZM17.841 18.7506L17.8409 18.2506L17.8409 18.2506L17.841 18.7506ZM23.0676 19.2506C23.3437 19.2506 23.5676 19.0267 23.5675 18.7506C23.5675 18.4744 23.3437 18.2506 23.0675 18.2506L23.0676 19.2506ZM13.0171 15.2446C12.8955 14.9967 12.5959 14.8943 12.348 15.016C12.1001 15.1376 11.9978 15.4372 12.1194 15.6851L13.0171 15.2446ZM11.5466 4.23108H12.608V3.23108H11.5466V4.23108ZM19.6569 19.5046C19.6569 21.0264 18.2467 22.2606 16.3033 22.2606V23.2606C18.6165 23.2606 20.6569 21.7449 20.6569 19.5046H19.6569ZM12.608 4.23108C16.501 4.23108 19.6569 7.38698 19.6569 11.28H20.6569C20.6569 6.8347 17.0533 3.23108 12.608 3.23108V4.23108ZM19.6569 11.28V15.9656H20.6569V11.28H19.6569ZM16.3033 22.2606C14.6727 22.2606 13.313 21.0964 13.0119 19.5536L12.0304 19.7452C12.4214 21.7485 14.1852 23.2606 16.3033 23.2606V22.2606ZM11.6552 3.22339H6.46459V4.22339H11.6552V3.22339ZM3.73784 5.127L2.0559 9.70814L2.99464 10.0528L4.67658 5.47164L3.73784 5.127ZM2.92176 13.0651L4.07588 14.0653L4.7308 13.3096L3.57668 12.3094L2.92176 13.0651ZM4.50971 15.0154L4.50969 16.8536L5.50969 16.8536L5.50971 15.0154L4.50971 15.0154ZM10.3739 10.6661C10.3739 9.25463 10.9376 7.90166 11.9399 6.90783L11.2358 6.19774C10.0442 7.37934 9.37387 8.98795 9.37385 10.6661L10.3739 10.6661ZM2.0559 9.70814C1.61893 10.8983 1.96363 12.2348 2.92176 13.0651L3.57668 12.3094C2.9326 11.7512 2.70089 10.8529 2.99464 10.0528L2.0559 9.70814ZM8.44319 20.7872C9.50944 20.7872 10.3738 19.9228 10.3738 18.8565H9.37381C9.37381 19.3705 8.95716 19.7872 8.44319 19.7872V20.7872ZM8.44319 19.7872C6.82305 19.7872 5.50967 18.4738 5.50969 16.8536L4.50969 16.8536C4.50966 19.026 6.27075 20.7872 8.44319 20.7872V19.7872ZM4.07588 14.0653C4.35142 14.3041 4.50972 14.6508 4.50971 15.0154L5.50971 15.0154C5.50972 14.3608 5.22552 13.7384 4.7308 13.3096L4.07588 14.0653ZM6.46459 3.22339C5.24643 3.22339 4.15768 3.98347 3.73784 5.12699L4.67658 5.47164C4.95188 4.7218 5.66581 4.22339 6.46459 4.22339V3.22339ZM17.841 19.2506L23.0676 19.2506L23.0675 18.2506L17.8409 18.2506L17.841 19.2506ZM12.1194 15.6851C13.1905 17.8676 15.4098 19.2507 17.841 19.2506L17.8409 18.2506C15.7913 18.2507 13.9201 17.0846 13.0171 15.2446L12.1194 15.6851ZM10.3738 18.8565L10.3739 10.6661L9.37385 10.6661L9.37381 18.8565L10.3738 18.8565Z', + key: '1mbkmc', + }, + ], + [ + 'path', + { + d: 'M15.7151 11.2056C15.7151 11.6257 16.0556 11.9663 16.4758 11.9663C16.8959 11.9663 17.2365 11.6257 17.2365 11.2056C17.2365 10.7854 16.8959 10.4448 16.4758 10.4448C16.0556 10.4448 15.7151 10.7854 15.7151 11.2056Z', + key: '1vir92', + }, + ], +]); + +export default Postgres; diff --git a/packages/icons/src/icons/realtime.ts b/packages/icons/src/icons/realtime.ts new file mode 100644 index 00000000000..0335626fb36 --- /dev/null +++ b/packages/icons/src/icons/realtime.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Realtime + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik04LjA0MjczIDEuNTgyMDNWNS4zMjIwNU01LjI0MzU0IDUuMzIyMDVMMi4wNDcxMiAyLjAyNzkxTTUuMjQzNTQgNy45MDk3OUgxLjU3NzY0TTE1LjM3NzYgMTUuNTUwN0wyMS4wNzkgMTQuMTMxNkMyMS41NDE3IDE0LjAxNjQgMjEuNTk1OSAxMy4zODA2IDIxLjE1OTUgMTMuMTg4N0w4LjAwODI4IDcuNDA1ODZDNy41OTEzNyA3LjIyMjU0IDcuMTY2NDMgNy42NDY2MSA3LjM0ODkgOC4wNjM4OUwxMy4wMzIxIDIxLjA2MDdDMTMuMjIyNCAyMS40OTYgMTMuODU1NiAyMS40NDU0IDEzLjk3NDMgMjAuOTg1NEwxNS4zNzc2IDE1LjU1MDdaIiAvPgo8L3N2Zz4=) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Realtime = createSupabaseIcon('Realtime', [ + [ + 'path', + { + d: 'M8.04273 1.58203V5.32205M5.24354 5.32205L2.04712 2.02791M5.24354 7.90979H1.57764M15.3776 15.5507L21.079 14.1316C21.5417 14.0164 21.5959 13.3806 21.1595 13.1887L8.00828 7.40586C7.59137 7.22254 7.16643 7.64661 7.3489 8.06389L13.0321 21.0607C13.2224 21.496 13.8556 21.4454 13.9743 20.9854L15.3776 15.5507Z', + key: '1w2oqg', + }, + ], +]); + +export default Realtime; diff --git a/packages/icons/src/icons/replace-code.ts b/packages/icons/src/icons/replace-code.ts new file mode 100644 index 00000000000..329a5fe90d6 --- /dev/null +++ b/packages/icons/src/icons/replace-code.ts @@ -0,0 +1,60 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name ReplaceCode + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiAgICBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj4KICAgIDxwYXRoCiAgICAgICAgZD0iTS0yMDQwMyAtMTExNDJIMTIxNjVWLTExMTQ0SC0yMDQwM1YtMTExNDJaTTEyMTY2IC0xMTE0MVY3MTEzSDEyMTY4Vi0xMTE0MUgxMjE2NlpNMTIxNjUgNzExNEgtMjA0MDNWNzExNkgxMjE2NVY3MTE0Wk0tMjA0MDQgNzExM1YtMTExNDFILTIwNDA2VjcxMTNILTIwNDA0Wk0tMjA0MDMgNzExNEMtMjA0MDMuNiA3MTE0IC0yMDQwNCA3MTEzLjU1IC0yMDQwNCA3MTEzSC0yMDQwNkMtMjA0MDYgNzExNC42NiAtMjA0MDQuNyA3MTE2IC0yMDQwMyA3MTE2VjcxMTRaTTEyMTY2IDcxMTNDMTIxNjYgNzExMy41NSAxMjE2NS42IDcxMTQgMTIxNjUgNzExNFY3MTE2QzEyMTY2LjcgNzExNiAxMjE2OCA3MTE0LjY2IDEyMTY4IDcxMTNIMTIxNjZaTTEyMTY1IC0xMTE0MkMxMjE2NS42IC0xMTE0MiAxMjE2NiAtMTExNDEuNiAxMjE2NiAtMTExNDFIMTIxNjhDMTIxNjggLTExMTQyLjcgMTIxNjYuNyAtMTExNDQgMTIxNjUgLTExMTQ0Vi0xMTE0MlpNLTIwNDAzIC0xMTE0NEMtMjA0MDQuNyAtMTExNDQgLTIwNDA2IC0xMTE0Mi43IC0yMDQwNiAtMTExNDFILTIwNDA0Qy0yMDQwNCAtMTExNDEuNiAtMjA0MDMuNiAtMTExNDIgLTIwNDAzIC0xMTE0MlYtMTExNDRaIgogICAgICAgIGZpbGwtb3BhY2l0eT0iMC4xIiAvPgogICAgPHJlY3QgeD0iNi40NDUzMSIgeT0iMTQuMTEzMyIgd2lkdGg9IjE1Ljg0NTUiIGhlaWdodD0iNy45MTgxOCIgcng9IjMuOTU5MDkiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0xMC41ODk2IDEwLjAxOTVMMTguMjE0OCAxMC4wMTk1QzE5LjA0MzMgMTAuMDE5NSAxOS43MTQ4IDkuMzQ3OTYgMTkuNzE0OCA4LjUxOTUzTDE5LjcxNDggMy41OTIyNUMxOS43MTQ4IDIuNzYzODMgMTkuMDQzMyAyLjA5MjI2IDE4LjIxNDggMi4wOTIyNkw1Ljk5NjA5IDIuMDkyMjYiCiAgICAgICAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiAvPgogICAgPHBhdGggZD0iTTUuOTg5MDIgMTAuNDY1NlY1Ljc4OTA2SDEuMzEyNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiAvPgogICAgPHBhdGggZD0iTTMuMjcxMTEgMTMuNjEzM1YxMy42MTMzQzEuNjE1MTUgMTIuMzkxNCAxLjQ3OTQ4IDkuOTY0NDYgMi45ODg5NCA4LjU2NTY0TDUuOTk2MDkgNS43Nzg5MSIKICAgICAgICBzdHJva2UtbGluZWNhcD0icm91bmQiIC8+Cjwvc3ZnPg==) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const ReplaceCode = createSupabaseIcon('ReplaceCode', [ + [ + 'path', + { + d: 'M-20403 -11142H12165V-11144H-20403V-11142ZM12166 -11141V7113H12168V-11141H12166ZM12165 7114H-20403V7116H12165V7114ZM-20404 7113V-11141H-20406V7113H-20404ZM-20403 7114C-20403.6 7114 -20404 7113.55 -20404 7113H-20406C-20406 7114.66 -20404.7 7116 -20403 7116V7114ZM12166 7113C12166 7113.55 12165.6 7114 12165 7114V7116C12166.7 7116 12168 7114.66 12168 7113H12166ZM12165 -11142C12165.6 -11142 12166 -11141.6 12166 -11141H12168C12168 -11142.7 12166.7 -11144 12165 -11144V-11142ZM-20403 -11144C-20404.7 -11144 -20406 -11142.7 -20406 -11141H-20404C-20404 -11141.6 -20403.6 -11142 -20403 -11142V-11144Z', + 'fill-opacity': '0.1', + key: 'g9kgmq', + }, + ], + [ + 'rect', + { + x: '6.44531', + y: '14.1133', + width: '15.8455', + height: '7.91818', + rx: '3.95909', + key: '1evqnx', + }, + ], + [ + 'path', + { + d: 'M10.5896 10.0195L18.2148 10.0195C19.0433 10.0195 19.7148 9.34796 19.7148 8.51953L19.7148 3.59225C19.7148 2.76383 19.0433 2.09226 18.2148 2.09226L5.99609 2.09226', + 'stroke-linecap': 'round', + key: '18tp5x', + }, + ], + [ + 'path', + { + d: 'M5.98902 10.4656V5.78906H1.3125', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + key: 'sfubon', + }, + ], + [ + 'path', + { + d: 'M3.27111 13.6133V13.6133C1.61515 12.3914 1.47948 9.96446 2.98894 8.56564L5.99609 5.77891', + 'stroke-linecap': 'round', + key: '1w6ie7', + }, + ], +]); + +export default ReplaceCode; diff --git a/packages/icons/src/icons/reports.ts b/packages/icons/src/icons/reports.ts new file mode 100644 index 00000000000..9b5c2888645 --- /dev/null +++ b/packages/icons/src/icons/reports.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Reports + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0zLjAzNDc5IDkuMDg0OUw4LjA3MjQxIDQuMDU3NUM4LjQ2Mjk2IDMuNjY3NzQgOS4wOTU0IDMuNjY3OTYgOS40ODU2OCA0LjA1Nzk5TDE0LjAyOTUgOC41OTg4MUMxNC40MiA4Ljk4OTEyIDE1LjA1MyA4Ljk4OTAxIDE1LjQ0MzUgOC41OTg1N0wyMC41ODc3IDMuNDU0MThNMTYuNDk5NiAzLjAxNTI2SDE5Ljk5OTZDMjAuNTUxOSAzLjAxNTI2IDIwLjk5OTYgMy40NjI5NyAyMC45OTk2IDQuMDE1MjZWNy41MTUyNk0yLjk5OTYzIDEyLjAxNTNMMi45OTk2MyAyMC4xOTU4QzIuOTk5NjMgMjAuNzQ4MSAzLjQ0NzM1IDIxLjE5NTggMy45OTk2MyAyMS4xOTU4TDIwLjAwMDQgMjEuMTk1OEMyMC41NTI3IDIxLjE5NTggMjEuMDAwNCAyMC43NDgxIDIxLjAwMDQgMjAuMTk1OFY5Ljg4NTc0TTguODI1MzIgOS44NzE4M0w4LjgyNTMxIDIxLjE5NThNMTUuMTc1NCAxNS4wNzQ2VjIxLjE5NDkiIC8+Cjwvc3ZnPg==) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Reports = createSupabaseIcon('Reports', [ + [ + 'path', + { + d: 'M3.03479 9.0849L8.07241 4.0575C8.46296 3.66774 9.0954 3.66796 9.48568 4.05799L14.0295 8.59881C14.42 8.98912 15.053 8.98901 15.4435 8.59857L20.5877 3.45418M16.4996 3.01526H19.9996C20.5519 3.01526 20.9996 3.46297 20.9996 4.01526V7.51526M2.99963 12.0153L2.99963 20.1958C2.99963 20.7481 3.44735 21.1958 3.99963 21.1958L20.0004 21.1958C20.5527 21.1958 21.0004 20.7481 21.0004 20.1958V9.88574M8.82532 9.87183L8.82531 21.1958M15.1754 15.0746V21.1949', + key: '1g8azg', + }, + ], +]); + +export default Reports; diff --git a/packages/icons/src/icons/settings.ts b/packages/icons/src/icons/settings.ts new file mode 100644 index 00000000000..de5f9204bea --- /dev/null +++ b/packages/icons/src/icons/settings.ts @@ -0,0 +1,30 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Settings + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0xOS4wMjIyIDkuMjQ3NzhDMTguNzY4NiA4LjYzMjA5IDE4LjkyMjYgNy45MDQ0NSAxOS4wMDg1IDcuMjQ0MTNDMTkuMDc0NSA2LjczNjg4IDE4LjkxNTggNi4yMDU0NiAxOC41MzA2IDUuODExMkMxOC4xNTYxIDUuNDI3OTUgMTcuNjQ3MSA1LjI1NTc0IDE3LjE1MTcgNS4yOTYyOEMxNi40NjUgNS4zNTI0OCAxNS42OTkzIDUuNDkxNjkgMTUuMDY3MyA1LjIxNzFDMTUuMDMzNyA1LjIwMjQ5IDE1IDUuMTg4MTIgMTQuOTY2MSA1LjE3Mzk5QzE0LjM2MzcgNC45MjI3MiAxMy45NDY3IDQuMzMzODggMTMuNTQ4IDMuODE3MDdDMTMuMjExIDMuMzgwMjUgMTIuNjgyMyAzLjA5ODg4IDEyLjA4OCAzLjA5ODg4QzExLjQ5NTQgMy4wOTg4OCAxMC45NjgxIDMuMzc4NTkgMTAuNjMxIDMuODEzMThDMTAuMjMwOSA0LjMyODk1IDkuODEyMjkgNC45MTY3MyA5LjIwOTE4IDUuMTY2NEM5LjE3MDQ0IDUuMTgyNDQgOS4xMzE4NyA1LjE5ODc5IDkuMDkzNDcgNS4yMTU0NUM4LjQ2NTM4IDUuNDg3OTQgNy43MDU2OSA1LjM1MTU3IDcuMDIzMjggNS4yOTYxOUM2LjUyODMgNS4yNTYwMSA2LjAxOTc4IDUuNDI4MjUgNS42NDU1OCA1LjgxMTJDNS4yNjY5MyA2LjE5ODcxIDUuMTA3MTUgNi43MTg3MiA1LjE2NDQ3IDcuMjE4MDZDNS4yNDExNiA3Ljg4NjE5IDUuMzkzMTMgOC42MjE3NCA1LjEzNjU3IDkuMjQzNEM0Ljg5Mjc2IDkuODM0MTcgNC4zMTczMiAxMC4yNTExIDMuODA4NCAxMC42Mzc3QzMuMzY1MzYgMTAuOTc0MyAzLjA3OTI4IDExLjUwNjggMy4wNzkyOCAxMi4xMDYxQzMuMDc5MjggMTIuNzA2IDMuMzY1OTUgMTMuMjM5IDMuODA5NzggMTMuNTc1NUM0LjMxODQ0IDEzLjk2MTIgNC44OTMyIDE0LjM3NzUgNS4xMzY3NiAxNC45Njc1QzUuMzkzNTMgMTUuNTg5NiA1LjI0MDc3IDE2LjMyNTggNS4xNjMxNSAxNi45OTQzQzUuMTA1MSAxNy40OTQzIDUuMjY0NzkgMTguMDE1MyA1LjY0NDAxIDE4LjQwMzRDNi4wMTg2NCAxOC43ODY4IDYuNTI3OSAxOC45NTkgNy4wMjM0MyAxOC45MTgzQzcuNzA3MDUgMTguODYyMSA4LjQ2ODM1IDE4LjcyNDMgOS4wOTc3NyAxOC45OTY5QzkuMTMzNzggMTkuMDEyNSA5LjE2OTkzIDE5LjAyNzggOS4yMDYyMiAxOS4wNDI5QzkuODEwNTIgMTkuMjkzMyAxMC4yMjk0IDE5Ljg4MzIgMTAuNjI5OCAyMC40MDA1QzEwLjk2NjkgMjAuODM1OSAxMS40OTQ3IDIxLjExNjMgMTIuMDg4IDIxLjExNjNDMTIuNjgzIDIxLjExNjMgMTMuMjEyMiAyMC44MzQzIDEzLjU0OTEgMjAuMzk2NkMxMy45NDgxIDE5Ljg3ODMgMTQuMzY1NCAxOS4yODczIDE0Ljk2OSAxOS4wMzUzQzE1LjAwMDUgMTkuMDIyMSAxNS4wMzE4IDE5LjAwODggMTUuMDYzMSAxOC45OTUyQzE1LjY5NjMgMTguNzIwNSAxNi40NjM2IDE4Ljg2MTIgMTcuMTUxNiAxOC45MTgyQzE3LjY0NzUgMTguOTU5MiAxOC4xNTcyIDE4Ljc4NzEgMTguNTMyMSAxOC40MDM0QzE4LjkxNzkgMTguMDA4NSAxOS4wNzY1IDE3LjQ3NjEgMTkuMDA5OCAxNi45NjgyQzE4LjkyMjkgMTYuMzA3NiAxOC43NjgyIDE1LjU3OTMgMTkuMDIyIDE0Ljk2MzJDMTkuMjYzNCAxNC4zNzc0IDE5LjgzNiAxMy45NjY0IDIwLjM0NiAxMy41OTA2QzIwLjgwMTMgMTMuMjU1IDIxLjA5NjcgMTIuNzE1IDIxLjA5NjcgMTIuMTA2MUMyMS4wOTY3IDExLjQ5NzcgMjAuODAxOSAxMC45NTgyIDIwLjM0NzQgMTAuNjIyNkMxOS44MzcyIDEwLjI0NTggMTkuMjYzOCA5LjgzNDI2IDE5LjAyMjIgOS4yNDc3OFoiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0xMi4wMDAyIDE1LjEwNTFDMTMuNjU3IDE1LjEwNTEgMTUuMDAwMiAxMy43NjIgMTUuMDAwMiAxMi4xMDUxQzE1LjAwMDIgMTAuNDQ4MiAxMy42NTcgOS4xMDUxIDEyLjAwMDIgOS4xMDUxQzEwLjM0MzMgOS4xMDUxIDkuMDAwMTggMTAuNDQ4MiA5LjAwMDE4IDEyLjEwNTFDOS4wMDAxOCAxMy43NjIgMTAuMzQzMyAxNS4xMDUxIDEyLjAwMDIgMTUuMTA1MVoiIC8+Cjwvc3ZnPg==) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Settings = createSupabaseIcon('Settings', [ + [ + 'path', + { + d: 'M19.0222 9.24778C18.7686 8.63209 18.9226 7.90445 19.0085 7.24413C19.0745 6.73688 18.9158 6.20546 18.5306 5.8112C18.1561 5.42795 17.6471 5.25574 17.1517 5.29628C16.465 5.35248 15.6993 5.49169 15.0673 5.2171C15.0337 5.20249 15 5.18812 14.9661 5.17399C14.3637 4.92272 13.9467 4.33388 13.548 3.81707C13.211 3.38025 12.6823 3.09888 12.088 3.09888C11.4954 3.09888 10.9681 3.37859 10.631 3.81318C10.2309 4.32895 9.81229 4.91673 9.20918 5.1664C9.17044 5.18244 9.13187 5.19879 9.09347 5.21545C8.46538 5.48794 7.70569 5.35157 7.02328 5.29619C6.5283 5.25601 6.01978 5.42825 5.64558 5.8112C5.26693 6.19871 5.10715 6.71872 5.16447 7.21806C5.24116 7.88619 5.39313 8.62174 5.13657 9.2434C4.89276 9.83417 4.31732 10.2511 3.8084 10.6377C3.36536 10.9743 3.07928 11.5068 3.07928 12.1061C3.07928 12.706 3.36595 13.239 3.80978 13.5755C4.31844 13.9612 4.8932 14.3775 5.13676 14.9675C5.39353 15.5896 5.24077 16.3258 5.16315 16.9943C5.1051 17.4943 5.26479 18.0153 5.64401 18.4034C6.01864 18.7868 6.5279 18.959 7.02343 18.9183C7.70705 18.8621 8.46835 18.7243 9.09777 18.9969C9.13378 19.0125 9.16993 19.0278 9.20622 19.0429C9.81052 19.2933 10.2294 19.8832 10.6298 20.4005C10.9669 20.8359 11.4947 21.1163 12.088 21.1163C12.683 21.1163 13.2122 20.8343 13.5491 20.3966C13.9481 19.8783 14.3654 19.2873 14.969 19.0353C15.0005 19.0221 15.0318 19.0088 15.0631 18.9952C15.6963 18.7205 16.4636 18.8612 17.1516 18.9182C17.6475 18.9592 18.1572 18.7871 18.5321 18.4034C18.9179 18.0085 19.0765 17.4761 19.0098 16.9682C18.9229 16.3076 18.7682 15.5793 19.022 14.9632C19.2634 14.3774 19.836 13.9664 20.346 13.5906C20.8013 13.255 21.0967 12.715 21.0967 12.1061C21.0967 11.4977 20.8019 10.9582 20.3474 10.6226C19.8372 10.2458 19.2638 9.83426 19.0222 9.24778Z', + key: '102x66', + }, + ], + [ + 'path', + { + d: 'M12.0002 15.1051C13.657 15.1051 15.0002 13.762 15.0002 12.1051C15.0002 10.4482 13.657 9.1051 12.0002 9.1051C10.3433 9.1051 9.00018 10.4482 9.00018 12.1051C9.00018 13.762 10.3433 15.1051 12.0002 15.1051Z', + key: '153c57', + }, + ], +]); + +export default Settings; diff --git a/packages/icons/src/icons/sql-editor.ts b/packages/icons/src/icons/sql-editor.ts new file mode 100644 index 00000000000..82c4e46e777 --- /dev/null +++ b/packages/icons/src/icons/sql-editor.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name SqlEditor + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik03Ljg5ODQ0IDguNDM0MkwxMS41MDA0IDEyLjAzNTZMNy44OTg0NCAxNS42Mzc1TTEyIDE1LjMyOTJIMTYuNU01IDIxLjEwNTVIMTlDMjAuMTA0NiAyMS4xMDU1IDIxIDIwLjIxIDIxIDE5LjEwNTVWNS4xMDU0N0MyMSA0LjAwMDkgMjAuMTA0NiAzLjEwNTQ3IDE5IDMuMTA1NDdINUMzLjg5NTQzIDMuMTA1NDcgMyA0LjAwMDkgMyA1LjEwNTQ3VjE5LjEwNTVDMyAyMC4yMSAzLjg5NTQzIDIxLjEwNTUgNSAyMS4xMDU1WiIgLz4KPC9zdmc+) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const SqlEditor = createSupabaseIcon('SqlEditor', [ + [ + 'path', + { + d: 'M7.89844 8.4342L11.5004 12.0356L7.89844 15.6375M12 15.3292H16.5M5 21.1055H19C20.1046 21.1055 21 20.21 21 19.1055V5.10547C21 4.0009 20.1046 3.10547 19 3.10547H5C3.89543 3.10547 3 4.0009 3 5.10547V19.1055C3 20.21 3.89543 21.1055 5 21.1055Z', + key: 'orzc99', + }, + ], +]); + +export default SqlEditor; diff --git a/packages/icons/src/icons/storage.ts b/packages/icons/src/icons/storage.ts new file mode 100644 index 00000000000..4f4f633848e --- /dev/null +++ b/packages/icons/src/icons/storage.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name Storage + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0xOS40OTk1IDExLjM2ODVWOC41MDcyNUwxNC4wNzIzIDMuMTA1ODRINS40OTk1MUM0Ljk0NzIyIDMuMTA1ODQgNC40OTk1MSAzLjU1MzU1IDQuNDk5NTEgNC4xMDU4NFY5LjEwNTFNMTkuNDQ2OCA4LjQ4MjE4TDE0LjA3MDEgMy4xMDU0N0wxNC4wNzAxIDcuNDgyMThDMTQuMDcwMSA4LjAzNDQ2IDE0LjUxNzggOC40ODIxOCAxNS4wNzAxIDguNDgyMThMMTkuNDQ2OCA4LjQ4MjE4Wk02Ljg2Njc1IDkuMTA1MUgzLjk2MDQ1QzMuNDA4MTYgOS4xMDUxIDIuOTYwNDUgOS41NTI4MiAyLjk2MDQ1IDEwLjEwNTFWMTkuMTA1MUMyLjk2MDQ1IDIwLjIwOTcgMy44NTU4OCAyMS4xMDUxIDQuOTYwNDUgMjEuMTA1MUgxOC45NjA0QzIwLjA2NSAyMS4xMDUxIDIwLjk2MDQgMjAuMjA5NyAyMC45NjA0IDE5LjEwNTFWMTIuMzY4NUMyMC45NjA0IDExLjgxNjIgMjAuNTEyNyAxMS4zNjg1IDE5Ljk2MDUgMTEuMzY4NUg5Ljk4NjIyQzkuNzIzODIgMTEuMzY4NSA5LjQ3MTk0IDExLjI2NTQgOS4yODQ4OSAxMS4wODEzTDcuNTY4MDggOS4zOTIyNkM3LjM4MTAzIDkuMjA4MjQgNy4xMjkxNSA5LjEwNTEgNi44NjY3NSA5LjEwNTFaIiAvPgo8L3N2Zz4=) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const Storage = createSupabaseIcon('Storage', [ + [ + 'path', + { + d: 'M19.4995 11.3685V8.50725L14.0723 3.10584H5.49951C4.94722 3.10584 4.49951 3.55355 4.49951 4.10584V9.1051M19.4468 8.48218L14.0701 3.10547L14.0701 7.48218C14.0701 8.03446 14.5178 8.48218 15.0701 8.48218L19.4468 8.48218ZM6.86675 9.1051H3.96045C3.40816 9.1051 2.96045 9.55282 2.96045 10.1051V19.1051C2.96045 20.2097 3.85588 21.1051 4.96045 21.1051H18.9604C20.065 21.1051 20.9604 20.2097 20.9604 19.1051V12.3685C20.9604 11.8162 20.5127 11.3685 19.9605 11.3685H9.98622C9.72382 11.3685 9.47194 11.2654 9.28489 11.0813L7.56808 9.39226C7.38103 9.20824 7.12915 9.1051 6.86675 9.1051Z', + key: '1liyj6', + }, + ], +]); + +export default Storage; diff --git a/packages/icons/src/icons/table-editor.ts b/packages/icons/src/icons/table-editor.ts new file mode 100644 index 00000000000..f80163ccb96 --- /dev/null +++ b/packages/icons/src/icons/table-editor.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name TableEditor + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0yLjk3MDcgMTUuMzQ5NEwyMC45NzA3IDE1LjM1NU0yMC45NDA1IDkuNjE1ODhIMi45OTY5OU04Ljc3NjYxIDkuNjE1ODhWMjEuMTM2N00yMC45NDA1IDUuODU1NDdWMTkuMTM2N0MyMC45NDA1IDIwLjI0MTMgMjAuMDQ1MSAyMS4xMzY3IDE4Ljk0MDUgMjEuMTM2N0g0Ljk5Njk5QzMuODkyNDIgMjEuMTM2NyAyLjk5Njk5IDIwLjI0MTMgMi45OTY5OSAxOS4xMzY3VjUuODU1NDdDMi45OTY5OSA0Ljc1MDkgMy44OTI0MiAzLjg1NTQ3IDQuOTk2OTkgMy44NTU0N0gxOC45NDA1QzIwLjA0NTEgMy44NTU0NyAyMC45NDA1IDQuNzUwOSAyMC45NDA1IDUuODU1NDdaIiAvPgo8L3N2Zz4=) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const TableEditor = createSupabaseIcon('TableEditor', [ + [ + 'path', + { + d: 'M2.9707 15.3494L20.9707 15.355M20.9405 9.61588H2.99699M8.77661 9.61588V21.1367M20.9405 5.85547V19.1367C20.9405 20.2413 20.0451 21.1367 18.9405 21.1367H4.99699C3.89242 21.1367 2.99699 20.2413 2.99699 19.1367V5.85547C2.99699 4.7509 3.89242 3.85547 4.99699 3.85547H18.9405C20.0451 3.85547 20.9405 4.7509 20.9405 5.85547Z', + key: '1qrasg', + }, + ], +]); + +export default TableEditor; diff --git a/packages/icons/src/icons/user.ts b/packages/icons/src/icons/user.ts new file mode 100644 index 00000000000..bc00fde031f --- /dev/null +++ b/packages/icons/src/icons/user.ts @@ -0,0 +1,23 @@ +import createSupabaseIcon from '../createSupabaseIcon'; + +/** + * @component @name User + * @description Supabase SVG icon component, renders SVG Element with children. + * + * @preview ![img](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmOyBib3JkZXItcmFkaXVzOiAycHgiICAgIHN0cm9rZS13aWR0aD0iMSI+CiAgICA8cGF0aAogICAgICAgIGQ9Ik03LjA2NDczIDE5LjYzMjhDNC42MTY0OCAxOC4wMjQ0IDMgMTUuMjUzNyAzIDEyLjEwNTVDMyA3LjEzNDkxIDcuMDI5NDQgMy4xMDU0NyAxMiAzLjEwNTQ3QzE2Ljk3MDYgMy4xMDU0NyAyMSA3LjEzNDkxIDIxIDEyLjEwNTVDMjEgMTUuMjUzNyAxOS40MjczIDE4LjAwOTQgMTYuOTc5IDE5LjYxNzhNMTYuOTc5OSAyMi4yODQ0VjE5LjcxMzZDMTYuOTc5OSAxNy4wMjU4IDE0LjgwMTEgMTQuODQ2OSAxMi4xMTMzIDE0Ljg0NjlDOS40MjU0NyAxNC44NDY5IDcuMjQ2NTggMTcuMDI1OCA3LjI0NjU4IDE5LjcxMzZWMjIuMjg0NE0xNSAxMS44NDY5QzE1IDEzLjUwMzggMTMuNjU2OSAxNC44NDY5IDEyIDE0Ljg0NjlDMTAuMzQzMSAxNC44NDY5IDkgMTMuNTAzOCA5IDExLjg0NjlDOSAxMC4xOTAxIDEwLjM0MzEgOC44NDY5MiAxMiA4Ljg0NjkyQzEzLjY1NjkgOC44NDY5MiAxNSAxMC4xOTAxIDE1IDExLjg0NjlaIiAvPgo8L3N2Zz4=) + * + * @param {Object} props - Supabase icons props and any valid SVG attribute + * @returns {JSX.Element} JSX Element + * + */ +const User = createSupabaseIcon('User', [ + [ + 'path', + { + d: 'M7.06473 19.6328C4.61648 18.0244 3 15.2537 3 12.1055C3 7.13491 7.02944 3.10547 12 3.10547C16.9706 3.10547 21 7.13491 21 12.1055C21 15.2537 19.4273 18.0094 16.979 19.6178M16.9799 22.2844V19.7136C16.9799 17.0258 14.8011 14.8469 12.1133 14.8469C9.42547 14.8469 7.24658 17.0258 7.24658 19.7136V22.2844M15 11.8469C15 13.5038 13.6569 14.8469 12 14.8469C10.3431 14.8469 9 13.5038 9 11.8469C9 10.1901 10.3431 8.84692 12 8.84692C13.6569 8.84692 15 10.1901 15 11.8469Z', + key: '173y10', + }, + ], +]); + +export default User; diff --git a/packages/icons/src/raw-icons/REST-api.svg b/packages/icons/src/raw-icons/REST-api.svg new file mode 100644 index 00000000000..16243c09d97 --- /dev/null +++ b/packages/icons/src/raw-icons/REST-api.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/_example-template.json b/packages/icons/src/raw-icons/_example-template.json new file mode 100644 index 00000000000..90144eed90b --- /dev/null +++ b/packages/icons/src/raw-icons/_example-template.json @@ -0,0 +1,20 @@ +{ + "$schema": "../icon.schema.json", + "contributors": [ + "it-is-not", + "jguddas", + "danielbayley", + "ericfennis" + ], + "tags": [ + "letter", + "font size", + "text", + "formatting", + "smaller" + ], + "categories": [ + "text", + "design" + ] +} diff --git a/packages/icons/src/raw-icons/_example-template.svg b/packages/icons/src/raw-icons/_example-template.svg new file mode 100644 index 00000000000..59f4ac860a1 --- /dev/null +++ b/packages/icons/src/raw-icons/_example-template.svg @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/api-docs.svg b/packages/icons/src/raw-icons/api-docs.svg new file mode 100644 index 00000000000..d7a25e37969 --- /dev/null +++ b/packages/icons/src/raw-icons/api-docs.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/auth.svg b/packages/icons/src/raw-icons/auth.svg new file mode 100644 index 00000000000..9d0de6b8d5c --- /dev/null +++ b/packages/icons/src/raw-icons/auth.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/database.svg b/packages/icons/src/raw-icons/database.svg new file mode 100644 index 00000000000..c01112b6883 --- /dev/null +++ b/packages/icons/src/raw-icons/database.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/edge-functions.svg b/packages/icons/src/raw-icons/edge-functions.svg new file mode 100644 index 00000000000..fcee4aa7672 --- /dev/null +++ b/packages/icons/src/raw-icons/edge-functions.svg @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/home.svg b/packages/icons/src/raw-icons/home.svg new file mode 100644 index 00000000000..42cb8187fbb --- /dev/null +++ b/packages/icons/src/raw-icons/home.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/insert-code.svg b/packages/icons/src/raw-icons/insert-code.svg new file mode 100644 index 00000000000..bb3bcb5fb7d --- /dev/null +++ b/packages/icons/src/raw-icons/insert-code.svg @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/integrations.svg b/packages/icons/src/raw-icons/integrations.svg new file mode 100644 index 00000000000..d221330d211 --- /dev/null +++ b/packages/icons/src/raw-icons/integrations.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/logs.svg b/packages/icons/src/raw-icons/logs.svg new file mode 100644 index 00000000000..1ef4e7bc9e3 --- /dev/null +++ b/packages/icons/src/raw-icons/logs.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/postgres.svg b/packages/icons/src/raw-icons/postgres.svg new file mode 100644 index 00000000000..bcc62fff7bc --- /dev/null +++ b/packages/icons/src/raw-icons/postgres.svg @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/realtime.svg b/packages/icons/src/raw-icons/realtime.svg new file mode 100644 index 00000000000..0de41f31280 --- /dev/null +++ b/packages/icons/src/raw-icons/realtime.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/replace-code.svg b/packages/icons/src/raw-icons/replace-code.svg new file mode 100644 index 00000000000..9d7c6242357 --- /dev/null +++ b/packages/icons/src/raw-icons/replace-code.svg @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/reports.svg b/packages/icons/src/raw-icons/reports.svg new file mode 100644 index 00000000000..fa5948b0aee --- /dev/null +++ b/packages/icons/src/raw-icons/reports.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/settings.svg b/packages/icons/src/raw-icons/settings.svg new file mode 100644 index 00000000000..0d6963dd5c3 --- /dev/null +++ b/packages/icons/src/raw-icons/settings.svg @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/sql-editor.svg b/packages/icons/src/raw-icons/sql-editor.svg new file mode 100644 index 00000000000..e41f2a4d6e5 --- /dev/null +++ b/packages/icons/src/raw-icons/sql-editor.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/storage.svg b/packages/icons/src/raw-icons/storage.svg new file mode 100644 index 00000000000..4e1a08563c0 --- /dev/null +++ b/packages/icons/src/raw-icons/storage.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/table-editor.svg b/packages/icons/src/raw-icons/table-editor.svg new file mode 100644 index 00000000000..578722406f2 --- /dev/null +++ b/packages/icons/src/raw-icons/table-editor.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/src/raw-icons/user.svg b/packages/icons/src/raw-icons/user.svg new file mode 100644 index 00000000000..521844213f8 --- /dev/null +++ b/packages/icons/src/raw-icons/user.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/icons/tsconfig.json b/packages/icons/tsconfig.json new file mode 100644 index 00000000000..c6e40b7c779 --- /dev/null +++ b/packages/icons/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "tsconfig/react-library.json", + "compilerOptions": { + "resolveJsonModule": true + }, + "include": ["."], + "exclude": ["dist", "build", "node_modules"] +} From 72d00070f32036b59dca7fe45bf1b4e7e168ed78 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Mon, 26 Feb 2024 16:59:49 +0800 Subject: [PATCH 24/50] Expose Shadcnui toast components from UI and partially implement in storage explorer (#21308) * Expose Shadcnui toast components from UI and partially implement in storage explorer * Fix --- .../StorageExplorer/FileExplorerHeader.tsx | 14 +++--- .../storageExplorer/StorageExplorerStore.ts | 44 +++++++------------ apps/studio/pages/_app.tsx | 2 + packages/ui/index.tsx | 3 ++ .../ui/src/components/shadcn/ui/toast.tsx | 6 +-- .../ui/src/components/shadcn/ui/use-toast.ts | 2 +- 6 files changed, 31 insertions(+), 40 deletions(-) diff --git a/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerHeader.tsx b/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerHeader.tsx index 451c70485b8..d1b725d7477 100644 --- a/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerHeader.tsx +++ b/apps/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerHeader.tsx @@ -6,9 +6,13 @@ import { Button, DropdownMenu, DropdownMenuContent, - DropdownMenuSeparator, DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, DropdownMenuTrigger, + IconCheck, IconChevronLeft, IconChevronRight, IconColumns, @@ -21,18 +25,14 @@ import { IconUpload, IconX, Input, - IconCheck, - DropdownMenuSub, - DropdownMenuSubTrigger, - DropdownMenuSubContent, } from 'ui' +import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import APIDocsButton from 'components/ui/APIDocsButton' import { useCheckPermissions } from 'hooks' import { useStorageStore } from 'localStores/storageExplorer/StorageExplorerStore' import { useStorageExplorerStateSnapshot } from 'state/storage-explorer' import { STORAGE_SORT_BY, STORAGE_SORT_BY_ORDER, STORAGE_VIEWS } from '../Storage.constants' -import APIDocsButton from 'components/ui/APIDocsButton' -import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' const VIEW_OPTIONS = [ { key: STORAGE_VIEWS.COLUMNS, name: 'As columns' }, diff --git a/apps/studio/localStores/storageExplorer/StorageExplorerStore.ts b/apps/studio/localStores/storageExplorer/StorageExplorerStore.ts index 632ce1df1b2..1f400d094fc 100644 --- a/apps/studio/localStores/storageExplorer/StorageExplorerStore.ts +++ b/apps/studio/localStores/storageExplorer/StorageExplorerStore.ts @@ -5,6 +5,7 @@ import { BlobReader, BlobWriter, ZipWriter } from '@zip.js/zip.js' import { chunk, compact, find, findIndex, has, isEqual, some, uniq, uniqBy } from 'lodash' import { makeAutoObservable } from 'mobx' import toast from 'react-hot-toast' +import { toast as UiToast } from 'ui' import { STORAGE_ROW_STATUS, @@ -283,22 +284,13 @@ class StorageExplorerStore { if (formattedName === null) return if (!/^[a-zA-Z0-9_-\s]*$/.test(formattedName)) { - return this.ui.setNotification({ - message: 'Folder name contains invalid special characters', - category: 'error', - duration: 8000, - }) - } - /** - * todo: move this to a util file, as renameFolder() uses same logic - */ - if (formattedName.includes('/') || formattedName.includes('\\')) { - return this.ui.setNotification({ - message: 'Folder names should not have forward or back slashes.', - category: 'error', - duration: 8000, + return UiToast({ + variant: 'destructive', + description: 'Folder name contains invalid special characters', + duration: 6000, }) } + if (formattedName.length === 0) { return this.removeTempRows(columnIndex) } @@ -425,10 +417,7 @@ class StorageExplorerStore { // https://stackoverflow.com/a/53058574 getFilesDataTransferItems = async (items) => { - const toastId = this.ui.setNotification({ - category: 'loading', - message: 'Retrieving items to upload...', - }) + const { dismiss } = UiToast({ description: 'Retrieving items to upload...' }) const files = [] const queue = [] for (const item of items) { @@ -446,7 +435,7 @@ class StorageExplorerStore { queue.push(...(await this.readAllDirectoryEntries(entry.createReader()))) } } - toast.dismiss(toastId) + dismiss() return files } @@ -663,7 +652,8 @@ class StorageExplorerStore { let numberOfFilesMovedFail = 0 this.clearSelectedItems() - const infoToastId = toast('Please do not close the browser until the move is completed', { + const { dismiss } = UiToast({ + description: 'Please do not close the browser until the move is completed', duration: Infinity, }) @@ -690,20 +680,16 @@ class StorageExplorerStore { ) if (numberOfFilesMovedFail === this.selectedItemsToMove.length) { - this.ui.setNotification({ - message: 'Failed to move files', - category: 'error', - }) + UiToast({ variant: 'destructive', description: 'Failed to move files' }) } else { - this.ui.setNotification({ - message: `Successfully moved ${ + UiToast({ + description: `Successfully moved ${ this.selectedItemsToMove.length - numberOfFilesMovedFail - } to ${formattedNewPathToFile}`, - category: 'success', + } files to ${formattedNewPathToFile.length > 0 ? formattedNewPathToFile : 'the root of your bucket'}`, }) } - toast.dismiss(infoToastId) + dismiss() // Clear file preview cache if moved files exist in cache const idsOfItemsToMove = this.selectedItemsToMove.map((item) => item.id) diff --git a/apps/studio/pages/_app.tsx b/apps/studio/pages/_app.tsx index 9e54f4ff3c8..9e96606394c 100644 --- a/apps/studio/pages/_app.tsx +++ b/apps/studio/pages/_app.tsx @@ -59,6 +59,7 @@ import { useAppStateSnapshot } from 'state/app-state' import { RootStore } from 'stores' import HCaptchaLoadedStore from 'stores/hcaptcha-loaded-store' import { AppPropsWithLayout } from 'types' +import { Toaster } from 'ui' dayjs.extend(customParseFormat) dayjs.extend(utc) @@ -182,6 +183,7 @@ function CustomApp({ Component, pageProps }: AppPropsWithLayout) { + {!isTestEnv && } diff --git a/packages/ui/index.tsx b/packages/ui/index.tsx index e4a92577b6b..77b83b88a65 100644 --- a/packages/ui/index.tsx +++ b/packages/ui/index.tsx @@ -81,6 +81,9 @@ export * from './src/components/ThemeProvider/prefixedThemes' // shadcn export * from './src/components/shadcn/ui/dropdown-menu' +export * from './src/components/shadcn/ui/use-toast' +export * from './src/components/shadcn/ui/toast' +export * from './src/components/shadcn/ui/toaster' export { Command as Command_Shadcn_, diff --git a/packages/ui/src/components/shadcn/ui/toast.tsx b/packages/ui/src/components/shadcn/ui/toast.tsx index bba0efd8c58..9f865254157 100644 --- a/packages/ui/src/components/shadcn/ui/toast.tsx +++ b/packages/ui/src/components/shadcn/ui/toast.tsx @@ -14,7 +14,7 @@ const ToastViewport = React.forwardRef< Date: Mon, 26 Feb 2024 18:10:26 +0800 Subject: [PATCH 25/50] chore: nav icons updated (#21551) out with the old, in with the new --- .../NavigationBar/NavigationBar.tsx | 6 +- .../NavigationBar/NavigationBar.utils.tsx | 139 ++++-------------- 2 files changed, 31 insertions(+), 114 deletions(-) diff --git a/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.tsx b/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.tsx index 90aa9060350..cfe9255be01 100644 --- a/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.tsx +++ b/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.tsx @@ -39,6 +39,10 @@ import { generateToolRoutes, } from './NavigationBar.utils' import NavigationIconButton from './NavigationIconButton' +import { Home } from 'icons' + +export const ICON_SIZE = 20 +export const ICON_STROKE_WIDTH = 1.5 const NavigationBar = () => { const os = detectOS() @@ -96,7 +100,7 @@ const NavigationBar = () => { route={{ key: 'HOME', label: 'Home', - icon: , + icon: , link: `/project/${projectRef}`, }} /> diff --git a/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.utils.tsx b/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.utils.tsx index 09af36377a6..076268e978c 100644 --- a/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.utils.tsx +++ b/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.utils.tsx @@ -1,10 +1,20 @@ -import SVG from 'react-inlinesvg' -import { products } from 'shared-data' -import { IconBarChart, IconFileText, IconList, IconSettings } from 'ui' - import { Route } from 'components/ui/ui.types' import { Project } from 'data/projects/project-detail-query' -import { BASE_PATH, IS_PLATFORM, PROJECT_STATUS } from 'lib/constants' +import { IS_PLATFORM, PROJECT_STATUS } from 'lib/constants' +import { + ApiDocs, + Auth, + Database, + EdgeFunctions, + Logs, + Realtime, + Reports, + Settings, + SqlEditor, + Storage, + TableEditor, +} from 'icons' +import { ICON_SIZE, ICON_STROKE_WIDTH } from './NavigationBar' export const generateToolRoutes = (ref?: string, project?: Project): Route[] => { const isProjectBuilding = project?.status === PROJECT_STATUS.COMING_UP @@ -14,25 +24,13 @@ export const generateToolRoutes = (ref?: string, project?: Project): Route[] => { key: 'editor', label: 'Table Editor', - icon: ( - code.replace(/svg/, 'svg class="m-auto text-color-inherit"')} - /> - ), + icon: , link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/editor`), }, { key: 'sql', label: 'SQL Editor', - icon: ( - code.replace(/svg/, 'svg class="m-auto text-color-inherit"')} - /> - ), + icon: , link: !IS_PLATFORM ? `/project/${ref}/sql/1` : ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/sql/new`), @@ -56,24 +54,7 @@ export const generateProductRoutes = ( { key: 'database', label: 'Database', - icon: ( - - - - ), + icon: , link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/database/tables`), }, ...(authEnabled @@ -81,24 +62,7 @@ export const generateProductRoutes = ( { key: 'auth', label: 'Authentication', - icon: ( - - - - ), + icon: , link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/auth/users`), }, ] @@ -108,24 +72,7 @@ export const generateProductRoutes = ( { key: 'storage', label: 'Storage', - icon: ( - - - - ), + icon: , link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/storage/buckets`), }, ] @@ -135,24 +82,7 @@ export const generateProductRoutes = ( { key: 'functions', label: 'Edge Functions', - icon: ( - - - - ), + icon: , link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/functions`), }, ] @@ -162,24 +92,7 @@ export const generateProductRoutes = ( { key: 'realtime', label: 'Realtime', - icon: ( - - - - ), + icon: , link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/realtime/inspector`), }, ] @@ -197,7 +110,7 @@ export const generateOtherRoutes = (ref?: string, project?: Project): Route[] => { key: 'reports', label: 'Reports', - icon: , + icon: , link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/reports`), }, ] @@ -205,13 +118,13 @@ export const generateOtherRoutes = (ref?: string, project?: Project): Route[] => { key: 'logs', label: 'Logs', - icon: , + icon: , link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/logs/explorer`), }, { key: 'api', label: 'API Docs', - icon: , + icon: , link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/api`), }, ...(IS_PLATFORM @@ -219,7 +132,7 @@ export const generateOtherRoutes = (ref?: string, project?: Project): Route[] => { key: 'settings', label: 'Project Settings', - icon: , + icon: , link: ref && `/project/${ref}/settings/general`, }, ] From e1bbdd0ca7976b535974d079dbc218ade00a94af Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Mon, 26 Feb 2024 18:50:44 +0800 Subject: [PATCH 26/50] feat: add resizable inner sidebar (#21548) * init * update import names * Update resizable.tsx * resizable bg now goes lighter on drag * only resizable for table editor and sql editor * Update ProjectLayout.tsx * Update index.tsx * Remove unneeded console.log. --------- Co-authored-by: Ivan Vasilov --- .../layouts/ProjectLayout/ProductMenuBar.tsx | 2 +- .../layouts/ProjectLayout/ProjectLayout.tsx | 61 +++++++++++++------ .../SQLEditorLayout/SQLEditorLayout.tsx | 1 + .../TableEditorLayout/TableEditorLayout.tsx | 7 ++- package-lock.json | 24 ++------ packages/ui/package.json | 2 +- .../ui/src/components/shadcn/ui/resizable.tsx | 19 +++++- 7 files changed, 72 insertions(+), 44 deletions(-) diff --git a/apps/studio/components/layouts/ProjectLayout/ProductMenuBar.tsx b/apps/studio/components/layouts/ProjectLayout/ProductMenuBar.tsx index 1bf0e8b733f..dcd5ad39405 100644 --- a/apps/studio/components/layouts/ProjectLayout/ProductMenuBar.tsx +++ b/apps/studio/components/layouts/ProjectLayout/ProductMenuBar.tsx @@ -8,7 +8,7 @@ const ProductMenuBar = ({ title, children }: PropsWithChildren) => { const router = useRouter() const { ref: projectRef } = useParams() @@ -105,26 +108,46 @@ const ProjectLayout = ({ {/* Left-most navigation side bar to access products */} {!hideIconBar && } {/* Product menu bar */} - {!showPausedState && ( - - {productMenu} - - )} -
- {!navLayoutV2 && !hideHeader && IS_PLATFORM && } - {showPausedState ? ( -
-
- -
-
- ) : ( - - - {children} - + + {!showPausedState && productMenu && ( + <> + + + {productMenu} + + + + )} - + +
+ {!navLayoutV2 && !hideHeader && IS_PLATFORM && } + {showPausedState ? ( +
+
+ +
+
+ ) : ( + + + {children} + + )} +
+
+
diff --git a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorLayout.tsx b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorLayout.tsx index 3a00e1d1214..b20474dba70 100644 --- a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorLayout.tsx +++ b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorLayout.tsx @@ -17,6 +17,7 @@ const SQLEditorLayout = ({ title, children }: SQLEditorLayoutProps) => { product="SQL Editor" productMenu={productMenu} isBlocking={false} + resizableSidebar > {children} diff --git a/apps/studio/components/layouts/TableEditorLayout/TableEditorLayout.tsx b/apps/studio/components/layouts/TableEditorLayout/TableEditorLayout.tsx index 9ca18c1fb5d..abeb9fb5339 100644 --- a/apps/studio/components/layouts/TableEditorLayout/TableEditorLayout.tsx +++ b/apps/studio/components/layouts/TableEditorLayout/TableEditorLayout.tsx @@ -23,7 +23,12 @@ const TableEditorLayout = ({ children }: PropsWithChildren<{}>) => { } return ( - + {children} ) diff --git a/package-lock.json b/package-lock.json index b52005e5a69..fb73df93e1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -838,7 +838,6 @@ "react-intersection-observer": "^9.5.3", "react-markdown": "^8.0.3", "react-simple-maps": "4.0.0-beta.6", - "react-split": "^2.0.13", "react-tracked": "^1.7.11", "react-virtualized-auto-sizer": "^1.0.20", "react-window": "^1.8.6", @@ -30237,9 +30236,9 @@ } }, "node_modules/react-resizable-panels": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.0.9.tgz", - "integrity": "sha512-ZylBvs7oG7Y/INWw3oYGolqgpFvoPW8MPeg9l1fURDeKpxrmUuCHBUmPj47BdZ11MODImu3kZYXG85rbySab7w==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.0.11.tgz", + "integrity": "sha512-tA3OvGFEK/U9rKuEg6TpXcr+i+cN5X8B4UIvs7jqr5lby629pDTGvqRjo1EJLhBpRZfkg0Zz1INJlSYigaS99g==", "peerDependencies": { "react": "^16.14.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0" @@ -30306,17 +30305,6 @@ "react-dom": ">=15.0.0" } }, - "node_modules/react-split": { - "version": "2.0.14", - "license": "MIT", - "dependencies": { - "prop-types": "^15.5.7", - "split.js": "^1.6.0" - }, - "peerDependencies": { - "react": "*" - } - }, "node_modules/react-style-singleton": { "version": "2.2.1", "license": "MIT", @@ -32990,10 +32978,6 @@ "tiny-updater": "^3.5.1" } }, - "node_modules/split.js": { - "version": "1.6.5", - "license": "MIT" - }, "node_modules/split2": { "version": "4.2.0", "dev": true, @@ -37662,7 +37646,7 @@ "react-hook-form": "^7.45.0", "react-hot-toast": "^2.4.1", "react-markdown": "^8.0.3", - "react-resizable-panels": "^2.0.9", + "react-resizable-panels": "^2.0.11", "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^4.2.17", "reactflow": "^11.10.1", diff --git a/packages/ui/package.json b/packages/ui/package.json index cbd1e654608..aaba83d932b 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -74,7 +74,7 @@ "react-hook-form": "^7.45.0", "react-hot-toast": "^2.4.1", "react-markdown": "^8.0.3", - "react-resizable-panels": "^2.0.9", + "react-resizable-panels": "^2.0.11", "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^4.2.17", "reactflow": "^11.10.1", diff --git a/packages/ui/src/components/shadcn/ui/resizable.tsx b/packages/ui/src/components/shadcn/ui/resizable.tsx index 837e962ba42..9bfbfaf1721 100644 --- a/packages/ui/src/components/shadcn/ui/resizable.tsx +++ b/packages/ui/src/components/shadcn/ui/resizable.tsx @@ -1,5 +1,8 @@ +'use client' + import { GripVertical } from 'lucide-react' import * as ResizablePrimitive from 'react-resizable-panels' + import { cn } from '../../../lib/utils/cn' const ResizablePanelGroup = ({ @@ -24,16 +27,28 @@ const ResizableHandle = ({ div]:rotate-90', + 'data-[resize-handle-state=drag]:bg-border-strong', + 'group', + 'transition-colors', className )} {...props} > {withHandle && ( -
+
)} ) -export { ResizableHandle, ResizablePanel, ResizablePanelGroup } +export { ResizablePanelGroup, ResizablePanel, ResizableHandle } From 84f092ac439e949b480dc76eb4c741dbb8efc558 Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Mon, 26 Feb 2024 21:24:29 +0800 Subject: [PATCH 27/50] chore: update table editor input and schema selector styling (#21486) * init input and button changes * clean up * button now active state when dropdown or popover active * Update TableEditorMenu.tsx * Update TableEditorMenu.tsx * fix hover issues * Update SchemaSelector.tsx --- apps/database-new/package.json | 2 +- .../TableEditorLayout/EntityListItem.tsx | 13 +- .../TableEditorLayout/TableEditorMenu.tsx | 313 +++++++----------- apps/studio/components/ui/SchemaSelector.tsx | 26 +- apps/studio/package.json | 2 +- package-lock.json | 19 +- packages/ui/package.json | 2 +- packages/ui/src/components/Button/Button.tsx | 35 +- 8 files changed, 186 insertions(+), 226 deletions(-) diff --git a/apps/database-new/package.json b/apps/database-new/package.json index 8c7e69955d4..c198c0d1858 100644 --- a/apps/database-new/package.json +++ b/apps/database-new/package.json @@ -21,7 +21,7 @@ "dayjs": "^1.11.10", "eslint-config-next": "^14.1.0", "lodash": "^4.17.21", - "lucide-react": "^0.292.0", + "lucide-react": "^0.338.0", "next": "^14.0.3", "openai": "^4.17.0", "react": "^18.2.0", diff --git a/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx b/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx index 054a596a557..a84f73ef3e8 100644 --- a/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx +++ b/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx @@ -129,7 +129,7 @@ const EntityListItem: ItemRenderer = ({ 'py-1 px-2', 'text-light', 'rounded-md', - isActive ? 'text-foreground bg-selection' : 'hover:bg-surface-200 focus:bg-surface-200', + isActive ? 'bg-selection' : 'hover:bg-surface-200 focus:bg-surface-200', 'group', 'transition' )} @@ -177,11 +177,16 @@ const EntityListItem: ItemRenderer = ({ isActive && 'text-foreground' )} > - {/* only show tooltips if required, to reduce noise */} - + {entity.name} - {entity.type === ENTITY_TYPE.TABLE && !entity.rls_enabled && ( { return ( <>
- { - setSearchText('') - snap.setSelectedSchemaName(name) - router.push(`/project/${project?.ref}/editor`) - }} - onSelectCreateSchema={() => snap.onAddSchema()} - /> +
+ { + setSearchText('') + snap.setSelectedSchemaName(name) + router.push(`/project/${project?.ref}/editor`) + }} + onSelectCreateSchema={() => snap.onAddSchema()} + /> -
- {!isLocked ? ( - - -
- } - type="default" - className="justify-start h-7" - onClick={snap.onAddTable} - > - New table - - - {!canCreateTables && ( - - - -
- - You need additional permissions to create tables - -
-
-
- )} - - ) : ( - - Viewing protected schema - -

- This schema is managed by Supabase and is read-only through the table editor -

- -
-
- )} -
- -
-
-
- - {isSearchOpen && ( - + {!isLocked ? ( + + +
-
- - - - - - - + New table + + + {!canCreateTables && ( - + - Sort By +
+ + You need additional permissions to create tables + +
-
- - - setSort(value)} + )} + + ) : ( + + + Viewing protected schema + + +

+ This schema is managed by Supabase and is read-only through the table editor +

+ +
+
+ )} +
+
+
+
+ + + + + + + + + + - - Alphabetical - - - Entity Type - - - - -
+ + Sort By + + + + + setSort(value)}> + + Alphabetical + + + Entity Type + + + +
{isLoading && ( diff --git a/apps/studio/components/ui/SchemaSelector.tsx b/apps/studio/components/ui/SchemaSelector.tsx index f5f57ecfc55..a6a01069364 100644 --- a/apps/studio/components/ui/SchemaSelector.tsx +++ b/apps/studio/components/ui/SchemaSelector.tsx @@ -23,6 +23,7 @@ import { import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import { useSchemasQuery } from 'data/database/schemas-query' +import { ChevronDownIcon, ChevronsUpDown } from 'lucide-react' interface SchemaSelectorProps { className?: string @@ -65,16 +66,8 @@ const SchemaSelector = ({ return (
{isSchemasLoading && ( - )} @@ -98,15 +91,16 @@ const SchemaSelector = ({ - {!canTriggerPhysicalBackup && ( - - - -
- - You need additional permissions to trigger a PITR recovery - -
-
-
- )} + {hasReadReplicas || + (!canTriggerPhysicalBackup && ( + + + +
+ + {hasReadReplicas + ? 'You will need to remove all read replicas first to trigger a PITR recovery' + : !canTriggerPhysicalBackup + ? 'You need additional permissions to trigger a PITR recovery' + : null} + +
+
+
+ ))}
} diff --git a/apps/studio/components/interfaces/Settings/Addons/ComputeInstanceSidePanel.tsx b/apps/studio/components/interfaces/Settings/Addons/ComputeInstanceSidePanel.tsx index 5771f56abc6..991f0f5477d 100644 --- a/apps/studio/components/interfaces/Settings/Addons/ComputeInstanceSidePanel.tsx +++ b/apps/studio/components/interfaces/Settings/Addons/ComputeInstanceSidePanel.tsx @@ -35,6 +35,8 @@ import { import * as Tooltip from '@radix-ui/react-tooltip' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' import { AddonVariantId, ProjectAddonVariantMeta } from 'data/subscriptions/types' +import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' +import { WarningIcon } from 'components/ui/Icons' const ComputeInstanceSidePanel = () => { const queryClient = useQueryClient() @@ -61,6 +63,7 @@ const ComputeInstanceSidePanel = () => { snap.setPanelKey(undefined) } + const { data: databases } = useReadReplicasQuery({ projectRef }) const { data: addons, isLoading } = useProjectAddonsQuery({ projectRef }) const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug }) const { mutate: updateAddon, isLoading: isUpdating } = useProjectAddonUpdateMutation({ @@ -105,7 +108,6 @@ const ComputeInstanceSidePanel = () => { const [selectedOption, setSelectedOption] = useState('') const isSubmitting = isUpdating || isRemoving - const projectId = selectedProject?.id const cpuArchitecture = getCloudProviderArchitecture(selectedProject?.cloud_provider) const selectedAddons = addons?.selected_addons ?? [] @@ -162,9 +164,12 @@ const ComputeInstanceSidePanel = () => { const selectedCompute = availableOptions.find((option) => option.identifier === selectedOption) const hasChanges = selectedOption !== (subscriptionCompute?.variant.identifier ?? defaultInstanceSize) + const hasReadReplicas = (databases ?? []).length > 1 const blockDowngradeDueToPitr = pitrAddon !== undefined && ['ci_micro', 'ci_nano'].includes(selectedOption) && hasChanges + const blockDowngradeDueToReadReplicas = + hasChanges && hasReadReplicas && ['ci_micro', 'ci_nano'].includes(selectedOption) useEffect(() => { if (visible) { @@ -217,7 +222,12 @@ const ComputeInstanceSidePanel = () => { onConfirm={() => setShowConfirmationModal(true)} loading={isLoading} disabled={ - isFreePlan || isLoading || !hasChanges || blockDowngradeDueToPitr || !canUpdateCompute + isFreePlan || + isLoading || + !hasChanges || + blockDowngradeDueToPitr || + blockDowngradeDueToReadReplicas || + !canUpdateCompute } tooltip={ isFreePlan @@ -382,38 +392,66 @@ const ComputeInstanceSidePanel = () => {

)} - {hasChanges && !blockDowngradeDueToPitr && ( - - Your project will be unavailable for up to 2 minutes while the changes take place. - + {hasChanges && !blockDowngradeDueToPitr && !blockDowngradeDueToReadReplicas && ( + + + + Your project will need to be restarted when changing it's compute size + + + Your project will be unavailable for up to 2 minutes while the changes take place. + + {hasReadReplicas && ( + + The compute sizes for all read replicas{' '} + on your project will also be changed to the {selectedCompute?.name} size as + well. + + )} + )} - {blockDowngradeDueToPitr && ( - + + + Unable to downgrade as project has active read replicas + + + The minimum compute instance size for using read replicas is the Small Compute. + You need to remove all read replicas before downgrading Compute as it requires at + least a Small compute instance. + + + + + + ) : blockDowngradeDueToPitr ? ( + + + Disable PITR before downgrading + + You currently have PITR enabled. The minimum compute instance size for using PITR + is the Small Compute. + + + You need to disable PITR before downgrading Compute as it requires at least a + Small compute instance. + + - } - > -

- You currently have PITR enabled. The minimum compute instance size for using PITR - is the Small Compute. -

-

- You need to disable PITR before downgrading Compute as it requires at least a - Small compute instance. -

-
- )} + + + ) : null} {hasChanges && subscription?.billing_via_partner && diff --git a/apps/studio/components/interfaces/Settings/Addons/PITRSidePanel.tsx b/apps/studio/components/interfaces/Settings/Addons/PITRSidePanel.tsx index e539aa53a37..70a052fa4d0 100644 --- a/apps/studio/components/interfaces/Settings/Addons/PITRSidePanel.tsx +++ b/apps/studio/components/interfaces/Settings/Addons/PITRSidePanel.tsx @@ -5,14 +5,20 @@ import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { useParams } from 'common' -import { useTheme } from 'next-themes' import { useProjectAddonRemoveMutation } from 'data/subscriptions/project-addon-remove-mutation' import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation' import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query' import { useCheckPermissions, useSelectedOrganization, useSelectedProject, useStore } from 'hooks' import { BASE_PATH } from 'lib/constants' import Telemetry from 'lib/telemetry' +import { useTheme } from 'next-themes' +import { subscriptionHasHipaaAddon } from 'components/interfaces/Billing/Subscription/Subscription.utils' +import { CriticalIcon, WarningIcon } from 'components/ui/Icons' +import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' +import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' +import { AddonVariantId } from 'data/subscriptions/types' +import { formatCurrency } from 'lib/helpers' import { useSubscriptionPageStateSnapshot } from 'state/subscription-page' import { Alert, @@ -20,16 +26,11 @@ import { AlertTitle_Shadcn_, Alert_Shadcn_, Button, + IconAlertTriangle, IconExternalLink, Radio, SidePanel, - IconAlertTriangle, } from 'ui' -import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' -import { AlertTriangleIcon } from 'lucide-react' -import { AddonVariantId } from 'data/subscriptions/types' -import { subscriptionHasHipaaAddon } from 'components/interfaces/Billing/Subscription/Subscription.utils' -import { formatCurrency } from 'lib/helpers' const PITR_CATEGORY_OPTIONS: { id: 'off' | 'on' @@ -76,6 +77,7 @@ const PITRSidePanel = () => { snap.setPanelKey(undefined) } + const { data: databases } = useReadReplicasQuery({ projectRef }) const { data: addons, isLoading } = useProjectAddonsQuery({ projectRef }) const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug }) const hasHipaaAddon = subscriptionHasHipaaAddon(subscription) @@ -121,9 +123,12 @@ const PITRSidePanel = () => { const subscriptionPitr = selectedAddons.find((addon) => addon.type === 'pitr') const availableOptions = availableAddons.find((addon) => addon.type === 'pitr')?.variants ?? [] + const hasReadReplicas = (databases ?? []).length > 1 const hasChanges = selectedOption !== (subscriptionPitr?.variant.identifier ?? 'pitr_0') const selectedPitr = availableOptions.find((option) => option.identifier === selectedOption) const isFreePlan = subscription?.plan?.id === 'free' + const blockDowngradeDueToReadReplicas = + hasChanges && hasReadReplicas && selectedCategory === 'off' && selectedOption === 'pitr_0' useEffect(() => { if (visible) { @@ -167,7 +172,13 @@ const PITRSidePanel = () => { onConfirm={onConfirm} loading={isLoading || isSubmitting} disabled={ - isFreePlan || isLoading || !hasChanges || isSubmitting || !canUpdatePitr || hasHipaaAddon + isFreePlan || + isLoading || + !hasChanges || + isSubmitting || + !canUpdatePitr || + hasHipaaAddon || + blockDowngradeDueToReadReplicas } tooltip={ hasHipaaAddon @@ -225,7 +236,13 @@ const PITRSidePanel = () => { className={clsx('col-span-3 group space-y-1', isFreePlan && 'opacity-75')} onClick={() => { setSelectedCategory(option.id) - if (option.id === 'off') setSelectedOption('pitr_0') + if (option.id === 'off') { + setSelectedOption('pitr_0') + } else if (subscriptionPitr?.variant.identifier !== undefined) { + setSelectedOption(subscriptionPitr.variant.identifier) + } else { + setSelectedOption('pitr_7') + } Telemetry.sendActivity( { activity: 'Option Selected', @@ -270,7 +287,7 @@ const PITRSidePanel = () => { {selectedCategory === 'off' && subscriptionPitr !== undefined && isBranchingEnabled && ( - + Are you sure you want to disable this while using Branching? @@ -281,6 +298,25 @@ const PITRSidePanel = () => { )} + {blockDowngradeDueToReadReplicas && ( + + + Remove all read replicas before downgrading + + You currently have active read replicas. The minimum compute instance size for using + read replicas is the Small Compute. You need to remove all read replicas before + downgrading Compute as it requires at least a Small compute instance. + + + + + + )} + {selectedCategory === 'on' && (
{isFreePlan ? ( @@ -358,7 +394,7 @@ const PITRSidePanel = () => {
)} - {hasChanges && ( + {hasChanges && !blockDowngradeDueToReadReplicas && ( <> {selectedOption === 'pitr_0' || (selectedPitr?.price ?? 0) < (subscriptionPitr?.variant.price ?? 0) ? ( diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx index 0faf37c0f5c..34d5447fe2b 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx @@ -6,7 +6,6 @@ import { AlertTitle_Shadcn_, Alert_Shadcn_, Button, - IconAlertCircle, Listbox, SidePanel, } from 'ui' @@ -20,6 +19,7 @@ import Link from 'next/link' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' import { useSelectedOrganization, useSelectedProject } from 'hooks' import { WarningIcon } from 'components/ui/Icons' +import { getSemanticVersion } from 'lib/helpers' // [Joshen] FYI this is purely for AWS only, need to update to support Fly eventually @@ -53,6 +53,10 @@ const DeployNewReplicaPanel = ({ }, }) + const currentPgVersion = Number( + (project?.dbVersion ?? '').split('supabase-postgres-')[1]?.split('.')[0] + ) + const reachedMaxReplicas = (data ?? []).filter((db) => db.identifier !== projectRef).length >= 2 const isFreePlan = subscription?.plan.id === 'free' const currentComputeAddon = addons?.selected_addons.find( @@ -61,6 +65,7 @@ const DeployNewReplicaPanel = ({ const currentPitrAddon = addons?.selected_addons.find((addon) => addon.type === 'pitr') const canDeployReplica = !reachedMaxReplicas && + currentPgVersion >= 15 && project?.cloud_provider === 'AWS' && !isFreePlan && currentComputeAddon !== undefined && @@ -82,6 +87,11 @@ const DeployNewReplicaPanel = ({ const [selectedCompute, setSelectedCompute] = useState(defaultCompute) const selectedComputeMeta = computeAddons.find((addon) => addon.identifier === selectedCompute) + const availableRegions = + process.env.NEXT_PUBLIC_ENVIRONMENT === 'staging' + ? AVAILABLE_REPLICA_REGIONS.filter((x) => x.key === 'SOUTHEAST_ASIA') + : AVAILABLE_REPLICA_REGIONS + const onSubmit = async () => { const regionKey = AWS_REGIONS_VALUES[selectedRegion] if (!projectRef) return console.error('Project is required') @@ -162,6 +172,41 @@ const DeployNewReplicaPanel = ({ )} + {/* [Joshen] Not particular about this warning as all users on prod are on AWS */} + {project?.cloud_provider !== 'AWS' && ( + + + + Read replicas can only be deployed with projects on AWS + + + If you'd like to use read replicas, please migrate your project to AWS by creating a + new one. + + + )} + {currentPgVersion < 15 && ( + + + + Read replicas can only be deployed with projects on Postgres version 15 and above + + + If you'd like to use read replicas, please contact us via support + + + + + + )} - {AVAILABLE_REPLICA_REGIONS.map((region) => ( + {availableRegions.map((region) => ( void + onCancel: () => void +} + +const DropAllReplicasConfirmationModal = ({ + visible, + onSuccess, + onCancel, +}: DropAllReplicasConfirmationModalProps) => { + const { ref: projectRef } = useParams() + const queryClient = useQueryClient() + const { data: databases } = useReadReplicasQuery({ projectRef }) + const { mutateAsync: removeReadReplica, isLoading: isRemoving } = useReadReplicaRemoveMutation() + + const onConfirmRemove = async () => { + if (!projectRef) return console.error('Project is required') + if (databases === undefined) return console.error('Unable to retrieve replicas') + if (databases.length === 1) toast('Your project has no read replicas') + + const replicas = databases.filter((db) => db.identifier !== projectRef) + await Promise.all( + replicas.map((db) => + removeReadReplica({ projectRef, identifier: db.identifier, skipInvalidateOnSuccess: true }) + ) + ) + toast.success(`Tearing down all read replicas`) + + queryClient.setQueriesData(replicaKeys.list(projectRef), (old: Database[]) => { + return old.filter((db: Database) => db.identifier === projectRef) + }) + queryClient.setQueriesData(replicaKeys.loadBalancers(projectRef), (old: Database[]) => []) + + setTimeout(async () => { + await queryClient.invalidateQueries(replicaKeys.list(projectRef)) + await queryClient.invalidateQueries(replicaKeys.loadBalancers(projectRef)) + }, 5000) + + onSuccess() + onCancel() + } + + return ( + onCancel()} + onSelectConfirm={() => onConfirmRemove()} + > + + + + This action cannot be undone + + You may still deploy new replicas in this region thereafter + + +
+

Before deleting all replicas, consider:

+
    +
  • Network traffic from this region may slow down
  • +
+
+
+
+ ) +} + +export default DropAllReplicasConfirmationModal diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx index ae311a2ef92..319b7f661c8 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx @@ -26,7 +26,7 @@ const DropReplicaConfirmationModal = ({ }: DropReplicaConfirmationModalProps) => { const { ref: projectRef } = useParams() const formattedId = formatDatabaseID(selectedReplica?.identifier ?? '') - const { mutateAsync: removeReadReplica } = useReadReplicaRemoveMutation({ + const { mutateAsync: removeReadReplica, isLoading: isRemoving } = useReadReplicaRemoveMutation({ onSuccess: () => { toast.success(`Tearing down read replica (ID: ${formattedId})`) onSuccess() @@ -45,6 +45,7 @@ const DropReplicaConfirmationModal = ({ { const { resolvedTheme } = useTheme() const { ref: projectRef } = useParams() const numComingUp = useRef() + const snap = useSubscriptionPageStateSnapshot() const [view, setView] = useState<'flow' | 'map'>('flow') + const [showDeleteAllModal, setShowDeleteAllModal] = useState(false) const [showNewReplicaPanel, setShowNewReplicaPanel] = useState(false) const [refetchInterval, setRefetchInterval] = useState(10000) const [newReplicaRegion, setNewReplicaRegion] = useState() - const [selectedReplicaToResize, setSelectedReplicaToResize] = useState() const [selectedReplicaToDrop, setSelectedReplicaToDrop] = useState() const [selectedReplicaToRestart, setSelectedReplicaToRestart] = useState() @@ -86,7 +98,6 @@ const InstanceConfigurationUI = () => { isSuccessReplicas && isSuccessLoadBalancers ? generateNodes(primary, replicas, loadBalancers ?? [], { onSelectRestartReplica: setSelectedReplicaToRestart, - onSelectResizeReplica: setSelectedReplicaToResize, onSelectDropReplica: setSelectedReplicaToDrop, }) : [], @@ -134,10 +145,6 @@ const InstanceConfigurationUI = () => { [] ) - const onConfirmRestartReplica = () => { - console.log('Restart replica', selectedReplicaToRestart) - } - const setReactFlow = async () => { const graph = getDagreGraphLayout(nodes, edges) const { nodes: updatedNodes } = addRegionNodes(graph.nodes, graph.edges) @@ -168,9 +175,33 @@ const InstanceConfigurationUI = () => { {isSuccessReplicas && ( <>
- +
+ + + +
-
- -
@@ -453,8 +428,8 @@ const Addons = () => {

Current option:

{ipv4 !== undefined - ? 'IPv4 address is enabled' - : 'IPv4 address is not enabled'} + ? 'Dedicated IPv4 address is enabled' + : 'Dedicated IPv4 address is not enabled'}

@@ -470,7 +445,7 @@ const Addons = () => { !(canUpdateIPv4 || ipv4) } > - Change IPv4 address + Change dedicated IPv4 address
@@ -494,19 +469,6 @@ const Addons = () => { )} - {/* - - */}
diff --git a/apps/studio/components/interfaces/Settings/Addons/IPv4SidePanel.tsx b/apps/studio/components/interfaces/Settings/Addons/IPv4SidePanel.tsx index 27f518c6d13..3286477e8e3 100644 --- a/apps/studio/components/interfaces/Settings/Addons/IPv4SidePanel.tsx +++ b/apps/studio/components/interfaces/Settings/Addons/IPv4SidePanel.tsx @@ -130,14 +130,14 @@ const IPv4SidePanel = () => { } header={
-

IPv4 address

+

Dedicated IPv4 address

@@ -147,10 +147,12 @@ const IPv4SidePanel = () => {

Direct connections to the database only work if your client is able to resolve IPv6 - addresses from January 26th. Enabling the IPv4 add-on allows you to directly connect to - your database via a IPv4 address. If you are connecting via our connection pooler, you - do not need this add-on as our pooler resolves to IPv4 addresses. You can check your - connection info in your{' '} + addresses. Enabling the dedicated IPv4 add-on allows you to directly connect to your + database via a IPv4 address. +

+

+ If you are connecting via our connection pooler, you do not need this add-on as our + pooler resolves to IPv4 addresses. You can check your connection info in your{' '} project database settings @@ -213,7 +215,7 @@ const IPv4SidePanel = () => { >

-

IPv4 address

+

Dedicated IPv4 address

diff --git a/apps/studio/public/img/ipv4-off--light.svg b/apps/studio/public/img/ipv4-off--light.svg index 21436d4df33..f4176a836ef 100644 --- a/apps/studio/public/img/ipv4-off--light.svg +++ b/apps/studio/public/img/ipv4-off--light.svg @@ -1,15 +1,17 @@ - + + + - - - + + + - - - + + + diff --git a/apps/studio/public/img/ipv4-off.svg b/apps/studio/public/img/ipv4-off.svg index faa01508c51..cf2cd5098d9 100644 --- a/apps/studio/public/img/ipv4-off.svg +++ b/apps/studio/public/img/ipv4-off.svg @@ -1,15 +1,19 @@ - + + + + - - - + + + - - - + + + + diff --git a/apps/studio/public/img/ipv4-on--light.svg b/apps/studio/public/img/ipv4-on--light.svg index 8c9906336fd..62090b8f6fe 100644 --- a/apps/studio/public/img/ipv4-on--light.svg +++ b/apps/studio/public/img/ipv4-on--light.svg @@ -1,16 +1,17 @@ - + + + - - - + + + + - - - + diff --git a/apps/studio/public/img/ipv4-on.svg b/apps/studio/public/img/ipv4-on.svg index ec02c70d9e4..ee1ccd47cb3 100644 --- a/apps/studio/public/img/ipv4-on.svg +++ b/apps/studio/public/img/ipv4-on.svg @@ -1,17 +1,17 @@ - + + - - - - - - + + + + + + + - - - + From 1e03efd8b50b4a498358ca79938de9da2e068165 Mon Sep 17 00:00:00 2001 From: Tyler Date: Tue, 27 Feb 2024 13:35:46 +0900 Subject: [PATCH 40/50] docs: Update Google sign-in docs for Android(Kotlin) to use credential manager and raw gotrue-kt (#21337) * docs: Focus Google sign-in guide for Kotlin on Android * refine the Kotlin code and add instructions to add dependencies * Add Kotlin multiplatform instructions on Kotlin tab * minor style tiding up * refine instructions for creating client IDs for Android apps * Update apps/docs/content/guides/auth/social-login/auth-google.mdx * Update apps/docs/content/guides/auth/social-login/auth-google.mdx Co-authored-by: Jan Tennert * ci: Autofix updates from GitHub workflow --------- Co-authored-by: Jan Tennert Co-authored-by: github-tidy-bot --- .../guides/auth/social-login/auth-google.mdx | 115 ++++++++++++++++-- 1 file changed, 108 insertions(+), 7 deletions(-) diff --git a/apps/docs/content/guides/auth/social-login/auth-google.mdx b/apps/docs/content/guides/auth/social-login/auth-google.mdx index 38f6936b717..6279925e6f3 100644 --- a/apps/docs/content/guides/auth/social-login/auth-google.mdx +++ b/apps/docs/content/guides/auth/social-login/auth-google.mdx @@ -16,7 +16,7 @@ There are three general ways to use Sign in with Google, depending on the applic - Sign in on the web or in web-based apps - Using an OAuth flow initiated by Supabase Auth using [Google Identity Authorization with OAuth 2.0 for Web Server Applications](https://developers.google.com/identity/protocols/oauth2/web-server). - Using a [personalized sign-in button](https://developers.google.com/identity/gsi/web/guides/personalized-button) or [One Tap](https://developers.google.com/identity/gsi/web/guides/display-google-one-tap) and [automatic sign-in](https://developers.google.com/identity/gsi/web/guides/automatic-sign-in-sign-out) for users already logged in to their Google account. -- Sign in in native Android apps and Chrome extensions +- Sign in in native Android apps and Chrome extensions. In some cases you're able to use the OAuth flow within web-based native apps such as with React Native, Expo or other similar frameworks. It is best practice to use native Sign in with Google capabilities whenever possible. @@ -232,7 +232,7 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf - ## Using native sign in with Google in Flutter + ## Using native sign-in with Google on Flutter Native Google sign in with Supabase is done through the [google_sign_in](https://pub.dev/packages/google_sign_in) package for iOS and Android. Follow the instructions on the [google_sign_in](https://pub.dev/packages/google_sign_in) package for plugin specific settings. @@ -301,11 +301,114 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf - Unlike the OAuth flow which requires the use of a web browser, the native Sign in with Google flow on Android uses the [operating system's built-in functionalities](https://developers.google.com/android/reference/com/google/android/gms/auth/api/identity/package-summary) to prompt the user for consent. Note that native sign-in has been rebranded as _One Tap sign-in on Android_ by Google, which you should not confuse with _One Tap sign in for web_, as mentioned below. + ## Using Google sign-in on Android + + The Sign in with Google flow on Android uses the [operating system's built-in functionalities](https://developer.android.com/training/sign-in/credential-manager) to prompt the user for consent. When the user provides consent, Google issues an identity token (commonly abbreviated as ID token) that is then sent to your project's Supabase Auth server. When valid, a new user session is started by issuing an access and refresh token from Supabase Auth. - When using [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/), you can use the [compose-auth](https://supabase.com/docs/reference/kotlin/installing) plugin. On Android it uses Google OneTap (or Credential Manager on Android 14+) automatically and on other platforms it uses `auth.signInWith(Google)`. + **Note:** You have to create OAuth client IDs for both a Web and Android application. The Web client ID is the one used in your Android app. + + Add the following dependencies to your app. You can find the latest version of `credentials` [here](https://developer.android.com/jetpack/androidx/releases/credentials) and `googleid` [here](https://developers.google.com/identity/android-credential-manager/releases). + + ```kotlin + implementation("androidx.credentials:credentials:") + implementation ("com.google.android.libraries.identity.googleid:googleid:") + + // optional - needed for credentials support from play services, for devices running + // Android 13 and below. + implementation("androidx.credentials:credentials-play-services-auth:") + ``` + + Add the following proguard rules to your `proguard-rules.pro` file: + + ```proguard + -if class androidx.credentials.CredentialManager + -keep class androidx.credentials.playservices.** { + *; + } + ``` + + Follow the code sample below to implement native Google sign-in with Supabase using Credential Manager in your Android app. + + ```kotlin + @Composable + fun GoogleSignInButton() { + val coroutineScope = rememberCoroutineScope() + val context = LocalContext.current + + val onClick: () -> Unit = { + val credentialManager = CredentialManager.create(context) + + // Generate a nonce and hash it with sha-256 + // Providing a nonce is optional but recommended + val rawNonce = UUID.randomUUID().toString() // Generate a random String. UUID should be sufficient, but can also be any other random string. + val bytes = rawNonce.toString().toByteArray() + val md = MessageDigest.getInstance("SHA-256") + val digest = md.digest(bytes) + val hashedNonce = digest.fold("") { str, it -> str + "%02x".format(it) } // Hashed nonce to be passed to Google sign-in + + + val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder() + .setFilterByAuthorizedAccounts(false) + .setServerClientId("WEB_GOOGLE_CLIENT_ID") + .setNonce(hashedNonce) // Provide the nonce if you have one + .build() + + val request: GetCredentialRequest = GetCredentialRequest.Builder() + .addCredentialOption(googleIdOption) + .build() + + coroutineScope.launch { + try { + val result = credentialManager.getCredential( + request = request, + context = context, + ) + + val googleIdTokenCredential = GoogleIdTokenCredential + .createFrom(result.credential.data) + + val googleIdToken = googleIdTokenCredential.idToken + + supabase.auth.signInWith(IDToken) { + idToken = googleIdToken + provider = Google + nonce = rawNonce + } + + // Handle successful sign-in + } catch (e: GetCredentialException) { + // Handle GetCredentialException thrown by `credentialManager.getCredential()` + } catch (e: GoogleIdTokenParsingException) { + // Handle GoogleIdTokenParsingException thrown by `GoogleIdTokenCredential.createFrom()` + } catch (e: RestException) { + // Handle RestException thrown by Supabase + } catch (e: Exception) { + // Handle unknown exceptions + } + } + } + + Button( + onClick = onClick, + ) { + Text("Sign in with Google") + } + } + ``` + + ### Configuration [#android-configuration] + + 1. Configure OAuth credentials for your Google Cloud project in the [Credentials](https://console.cloud.google.com/apis/credentials) page of the console. You need two client IDs, a web client ID and Android client ID. When creating a new Android OAuth client ID, use the instructions on screen to provide the SHA-1 certificate fingerprint used to sign your Android app. + 2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service. + 3. Finally, add the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_. + + Note that you do not have to configure the OAuth flow in the Supabase Dashboard in order to use native sign in. + + ## Using Google sign-in with Kotlin Multiplatform + + When using [Compose Multiplatform](https://www.jetbrains.com/lp/compose-multiplatform/), you can use the [compose-auth](https://supabase.com/docs/reference/kotlin/installing) plugin. On Android it uses Google OneTap (or Credential Manager on Android 14+) automatically and on other platforms it uses `auth.signInWith(Google)`. Alternatively, you can have a look at [Google One Tap](https://developers.google.com/identity/one-tap/android/overview), just login with the IdToken after you receive it. **Initialize the Supabase Client** @@ -343,7 +446,7 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf } ``` - ### Configuration [#kotlin-configuration-native-app] + ### Configuration [#kotlin-multiplatform-configuration] 1. Configure OAuth credentials for your Google Cloud project in the [Credentials](https://console.cloud.google.com/apis/credentials) page of the console. When creating a new OAuth client ID, choose _Android_ or _iOS_ depending on the mobile operating system your app is built for. @@ -353,8 +456,6 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf 2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service. 3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_. - Note that you do not have to configure the OAuth flow in the Supabase Dashboard in order to use native sign in. - From 4e039c9bf5d4b17d3cc9c8f03a0e3c98c3ad2a5f Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Tue, 27 Feb 2024 13:14:21 +0800 Subject: [PATCH 41/50] Remove config cat flag for read replicas (#21587) * Remove config cat flag for read replicas * Remove --- .../interfaces/SQLEditor/SQLEditor.tsx | 55 ++++++++----------- .../SQLEditor/UtilityPanel/UtilityActions.tsx | 6 +- .../interfaces/Settings/API/ServiceList.tsx | 13 ++--- .../DatabaseConnectionString.tsx | 3 +- .../DatabaseSettings/DatabaseSettings.tsx | 19 +++---- .../Settings/Database/PoolingModesModal.tsx | 3 +- .../Settings/Database/UsePoolerCheckbox.tsx | 3 +- .../Infrastructure/InfrastructureInfo.tsx | 5 +- .../Settings/Logs/LogsPreviewer.tsx | 12 ++-- .../Settings/Logs/PreviewFilterPanel.tsx | 3 - .../read-replicas/load-balancers-query.ts | 8 +-- .../data/read-replicas/replicas-query.ts | 13 ++--- .../read-replicas/replicas-status-query.ts | 10 +--- apps/studio/pages/projects.tsx | 2 +- 14 files changed, 60 insertions(+), 95 deletions(-) diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx index d71235efc0a..8a1bcb68464 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx +++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.tsx @@ -4,36 +4,8 @@ import { AnimatePresence, motion } from 'framer-motion' import dynamic from 'next/dynamic' import { useRouter } from 'next/router' import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react' -import { format } from 'sql-formatter' - -import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog' -import { useSqlEditMutation } from 'data/ai/sql-edit-mutation' -import { useSqlGenerateMutation } from 'data/ai/sql-generate-mutation' -import { useSqlTitleGenerateMutation } from 'data/ai/sql-title-mutation' -import { SqlSnippet } from 'data/content/sql-snippets-query' -import { useEntityDefinitionsQuery } from 'data/database/entity-definitions-query' -import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' -import { useExecuteSqlMutation } from 'data/sql/execute-sql-mutation' -import { useFormatQueryMutation } from 'data/sql/format-sql-query' -import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' -import { isError } from 'data/utils/error-check' -import { - useFlag, - useLocalStorageQuery, - useSelectedOrganization, - useSelectedProject, - useStore, -} from 'hooks' -import { IS_PLATFORM, LOCAL_STORAGE_KEYS, OPT_IN_TAGS } from 'lib/constants' -import { uuidv4 } from 'lib/helpers' -import { useProfile } from 'lib/profile' -import { wrapWithRoleImpersonation } from 'lib/role-impersonation' -import Telemetry from 'lib/telemetry' import toast from 'react-hot-toast' -import { useAppStateSnapshot } from 'state/app-state' -import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' -import { isRoleImpersonationEnabled, useGetImpersonatedRole } from 'state/role-impersonation-state' -import { getSqlEditorStateSnapshot, useSqlEditorStateSnapshot } from 'state/sql-editor' +import { format } from 'sql-formatter' import { AiIconAnimation, Button, @@ -53,6 +25,28 @@ import { ResizablePanelGroup, cn, } from 'ui' + +import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog' +import { useSqlEditMutation } from 'data/ai/sql-edit-mutation' +import { useSqlGenerateMutation } from 'data/ai/sql-generate-mutation' +import { useSqlTitleGenerateMutation } from 'data/ai/sql-title-mutation' +import { SqlSnippet } from 'data/content/sql-snippets-query' +import { useEntityDefinitionsQuery } from 'data/database/entity-definitions-query' +import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' +import { useExecuteSqlMutation } from 'data/sql/execute-sql-mutation' +import { useFormatQueryMutation } from 'data/sql/format-sql-query' +import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' +import { isError } from 'data/utils/error-check' +import { useLocalStorageQuery, useSelectedOrganization, useSelectedProject, useStore } from 'hooks' +import { IS_PLATFORM, LOCAL_STORAGE_KEYS, OPT_IN_TAGS } from 'lib/constants' +import { uuidv4 } from 'lib/helpers' +import { useProfile } from 'lib/profile' +import { wrapWithRoleImpersonation } from 'lib/role-impersonation' +import Telemetry from 'lib/telemetry' +import { useAppStateSnapshot } from 'state/app-state' +import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' +import { isRoleImpersonationEnabled, useGetImpersonatedRole } from 'state/role-impersonation-state' +import { getSqlEditorStateSnapshot, useSqlEditorStateSnapshot } from 'state/sql-editor' import { subscriptionHasHipaaAddon } from '../Billing/Subscription/Subscription.utils' import AISchemaSuggestionPopover from './AISchemaSuggestionPopover' import { sqlAiDisclaimerComment, untitledSnippetTitle } from './SQLEditor.constants' @@ -122,8 +116,7 @@ const SQLEditor = () => { const [hasSelection, setHasSelection] = useState(false) const inputRef = useRef(null) - const readReplicasEnabled = useFlag('readReplicas') - const showReadReplicasUI = readReplicasEnabled && project?.is_read_replicas_enabled + const showReadReplicasUI = project?.is_read_replicas_enabled const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug }) const { data: databases, isSuccess: isSuccessReadReplicas } = useReadReplicasQuery({ diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx index 74387b88bda..490f135e622 100644 --- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx @@ -5,7 +5,7 @@ import { Button, IconAlignLeft, IconCommand, IconCornerDownLeft } from 'ui' import { RoleImpersonationPopover } from 'components/interfaces/RoleImpersonationSelector' import DatabaseSelector from 'components/ui/DatabaseSelector' -import { useFlag, useSelectedProject } from 'hooks' +import { useSelectedProject } from 'hooks' import FavoriteButton from './FavoriteButton' import SavingIndicator from './SavingIndicator' @@ -28,9 +28,7 @@ const UtilityActions = ({ }: UtilityActionsProps) => { const os = detectOS() const project = useSelectedProject() - const readReplicasEnabled = useFlag('readReplicas') - - const showReadReplicasUI = readReplicasEnabled && project?.is_read_replicas_enabled + const showReadReplicasUI = project?.is_read_replicas_enabled return ( <> diff --git a/apps/studio/components/interfaces/Settings/API/ServiceList.tsx b/apps/studio/components/interfaces/Settings/API/ServiceList.tsx index 37ba646a136..72c50f94124 100644 --- a/apps/studio/components/interfaces/Settings/API/ServiceList.tsx +++ b/apps/studio/components/interfaces/Settings/API/ServiceList.tsx @@ -8,19 +8,19 @@ import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectConte import DatabaseSelector from 'components/ui/DatabaseSelector' import Panel from 'components/ui/Panel' import { DisplayApiSettings } from 'components/ui/ProjectSettings' +import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' import { useJwtSecretUpdatingStatusQuery } from 'data/config/jwt-secret-updating-status-query' import { configKeys } from 'data/config/keys' import { useProjectApiQuery } from 'data/config/project-api-query' import { useCustomDomainsQuery } from 'data/custom-domains/custom-domains-query' +import { useLoadBalancersQuery } from 'data/read-replicas/load-balancers-query' import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' -import { useFlag, useStore } from 'hooks' +import { useStore } from 'hooks' +import { PROJECT_STATUS } from 'lib/constants' import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import { JWT_SECRET_UPDATE_ERROR_MESSAGES } from './API.constants' import JWTSettings from './JWTSettings' import PostgrestConfig from './PostgrestConfig' -import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' -import { PROJECT_STATUS } from 'lib/constants' -import { useLoadBalancersQuery } from 'data/read-replicas/load-balancers-query' const ServiceList = () => { const { ui } = useStore() @@ -29,8 +29,7 @@ const ServiceList = () => { const { ref: projectRef, source } = useParams() const state = useDatabaseSelectorStateSnapshot() - const readReplicasEnabled = useFlag('readReplicas') - const showReadReplicasUI = readReplicasEnabled && project?.is_read_replicas_enabled + const showReadReplicasUI = project?.is_read_replicas_enabled const { data: settings, isError } = useProjectApiQuery({ projectRef, @@ -91,7 +90,7 @@ const ServiceList = () => { }, [jwtSecretUpdateStatus]) useEffect(() => { - if (readReplicasEnabled && source !== undefined) { + if (showReadReplicasUI && source !== undefined) { state.setSelectedDatabaseId('load-balancer') } }, [source]) diff --git a/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseConnectionString.tsx b/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseConnectionString.tsx index a8373e8849e..78e327fd269 100644 --- a/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseConnectionString.tsx +++ b/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseConnectionString.tsx @@ -23,7 +23,6 @@ import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useProjectSettingsQuery } from 'data/config/project-settings-query' import { usePoolingConfigurationQuery } from 'data/database/pooling-configuration-query' import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' -import { useFlag } from 'hooks' import { pluckObjectFields } from 'lib/helpers' import Telemetry from 'lib/telemetry' import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' @@ -58,7 +57,7 @@ export const DatabaseConnectionString = ({ appearance }: DatabaseConnectionStrin const snap = useDatabaseSettingsStateSnapshot() const state = useDatabaseSelectorStateSnapshot() const { project: projectDetails, isLoading: isProjectLoading } = useProjectContext() - const readReplicasEnabled = useFlag('readReplicas') && projectDetails?.is_read_replicas_enabled + const readReplicasEnabled = projectDetails?.is_read_replicas_enabled const connectionStringsRef = useRef(null) const [poolingMode, setPoolingMode] = useState<'transaction' | 'session' | 'statement'>('session') diff --git a/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseSettings.tsx b/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseSettings.tsx index 5eebfc8fbad..cccd2e741f3 100644 --- a/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseSettings.tsx +++ b/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/DatabaseSettings.tsx @@ -1,6 +1,13 @@ import { useParams, useTelemetryProps } from 'common' import { useRouter } from 'next/router' import { useEffect, useRef, useState } from 'react' +import { + AlertDescription_Shadcn_, + AlertTitle_Shadcn_, + Alert_Shadcn_, + IconAlertCircle, + Input, +} from 'ui' import AlertError from 'components/ui/AlertError' import DatabaseSelector from 'components/ui/DatabaseSelector' @@ -9,18 +16,11 @@ import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useProjectSettingsQuery } from 'data/config/project-settings-query' import { usePoolingConfigurationQuery } from 'data/database/pooling-configuration-query' import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' -import { useFlag, useSelectedProject } from 'hooks' +import { useSelectedProject } from 'hooks' import { pluckObjectFields } from 'lib/helpers' import Telemetry from 'lib/telemetry' import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import { useDatabaseSettingsStateSnapshot } from 'state/database-settings' -import { - AlertDescription_Shadcn_, - AlertTitle_Shadcn_, - Alert_Shadcn_, - IconAlertCircle, - Input, -} from 'ui' import { IPv4DeprecationNotice } from '../IPv4DeprecationNotice' import { UsePoolerCheckbox } from '../UsePoolerCheckbox' import ResetDbPassword from './ResetDbPassword' @@ -33,8 +33,7 @@ const DatabaseSettings = () => { const state = useDatabaseSelectorStateSnapshot() const selectedProject = useSelectedProject() - const readReplicasEnabled = useFlag('readReplicas') - const showReadReplicasUI = readReplicasEnabled && selectedProject?.is_read_replicas_enabled + const showReadReplicasUI = selectedProject?.is_read_replicas_enabled const connectionStringsRef = useRef(null) const [poolingMode, setPoolingMode] = useState<'transaction' | 'session' | 'statement'>('session') diff --git a/apps/studio/components/interfaces/Settings/Database/PoolingModesModal.tsx b/apps/studio/components/interfaces/Settings/Database/PoolingModesModal.tsx index ed08d417d25..c6b9c395d7c 100644 --- a/apps/studio/components/interfaces/Settings/Database/PoolingModesModal.tsx +++ b/apps/studio/components/interfaces/Settings/Database/PoolingModesModal.tsx @@ -18,7 +18,6 @@ import { import { Markdown } from 'components/interfaces/Markdown' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import { usePoolingConfigurationQuery } from 'data/database/pooling-configuration-query' -import { useFlag } from 'hooks' import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import { useDatabaseSettingsStateSnapshot } from 'state/database-settings' @@ -27,7 +26,7 @@ export const PoolingModesModal = () => { const { project } = useProjectContext() const snap = useDatabaseSettingsStateSnapshot() const state = useDatabaseSelectorStateSnapshot() - const readReplicasEnabled = useFlag('readReplicas') && project?.is_read_replicas_enabled + const readReplicasEnabled = project?.is_read_replicas_enabled const { data } = usePoolingConfigurationQuery({ projectRef: projectRef }) const primaryConfig = readReplicasEnabled diff --git a/apps/studio/components/interfaces/Settings/Database/UsePoolerCheckbox.tsx b/apps/studio/components/interfaces/Settings/Database/UsePoolerCheckbox.tsx index 7b7a7533142..33592a1d8ed 100644 --- a/apps/studio/components/interfaces/Settings/Database/UsePoolerCheckbox.tsx +++ b/apps/studio/components/interfaces/Settings/Database/UsePoolerCheckbox.tsx @@ -18,7 +18,6 @@ import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { usePgBouncerStatus } from 'data/config/pgbouncer-enabled-query' import { useProjectSettingsQuery } from 'data/config/project-settings-query' import { usePoolingConfigurationQuery } from 'data/database/pooling-configuration-query' -import { useFlag } from 'hooks' import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import { useDatabaseSettingsStateSnapshot } from 'state/database-settings' @@ -47,7 +46,7 @@ export const UsePoolerCheckbox = ({ const { data: settings, isSuccess: isSuccessSettings } = useProjectSettingsQuery({ projectRef }) const { data: pgBouncerStatus } = usePgBouncerStatus({ projectRef: projectRef }) - const readReplicasEnabled = useFlag('readReplicas') && project?.is_read_replicas_enabled + const readReplicasEnabled = project?.is_read_replicas_enabled const poolingConfiguration = readReplicasEnabled ? data?.find((x) => x.identifier === state.selectedDatabaseId) : data?.find((x) => x.database_type === 'PRIMARY') diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureInfo.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureInfo.tsx index 766de0d1e44..ac36896a3fd 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureInfo.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureInfo.tsx @@ -23,7 +23,7 @@ import AlertError from 'components/ui/AlertError' import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' import { useProjectUpgradeEligibilityQuery } from 'data/config/project-upgrade-eligibility-query' import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' -import { useFlag, useIsFeatureEnabled } from 'hooks' +import { useIsFeatureEnabled } from 'hooks' import { AWS_REGIONS, FLY_REGIONS } from 'lib/constants' import ProjectUpgradeAlert from '../General/Infrastructure/ProjectUpgradeAlert' import InstanceConfiguration from './InfrastructureConfiguration/InstanceConfiguration' @@ -54,8 +54,7 @@ const InfrastructureInfo = () => { const currentPgVersion = (current_app_version ?? '').split('supabase-postgres-')[1] const latestPgVersion = (latest_app_version ?? '').split('supabase-postgres-')[1] - const readReplicasEnabled = useFlag('readReplicas') - const showReadReplicasUI = readReplicasEnabled && project?.is_read_replicas_enabled + const showReadReplicasUI = project?.is_read_replicas_enabled const hasReadReplicas = (databases ?? []).length > 1 const subject = 'Request%20for%20Postgres%20upgrade%20for%20project' const message = `Upgrade information:%0A• Manual intervention reason: ${requires_manual_intervention}` diff --git a/apps/studio/components/interfaces/Settings/Logs/LogsPreviewer.tsx b/apps/studio/components/interfaces/Settings/Logs/LogsPreviewer.tsx index 92b94adb206..34cea58a523 100644 --- a/apps/studio/components/interfaces/Settings/Logs/LogsPreviewer.tsx +++ b/apps/studio/components/interfaces/Settings/Logs/LogsPreviewer.tsx @@ -15,17 +15,17 @@ import { maybeShowUpgradePrompt, } from 'components/interfaces/Settings/Logs' import PreviewFilterPanel from 'components/interfaces/Settings/Logs/PreviewFilterPanel' +import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import LoadingOpacity from 'components/ui/LoadingOpacity' import ShimmerLine from 'components/ui/ShimmerLine' +import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' +import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' +import { useSelectedOrganization } from 'hooks' import useLogsPreview from 'hooks/analytics/useLogsPreview' import { useUpgradePrompt } from 'hooks/misc/useUpgradePrompt' +import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import { LOGS_TABLES } from './Logs.constants' import UpgradePrompt from './UpgradePrompt' -import { useFlag, useSelectedOrganization } from 'hooks' -import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' -import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' -import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' -import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' /** * Acts as a container component for the entire log display @@ -58,7 +58,7 @@ export const LogsPreviewer = ({ const { project } = useProjectContext() const organization = useSelectedOrganization() const state = useDatabaseSelectorStateSnapshot() - const readReplicasEnabled = useFlag('readReplicas') && project?.is_read_replicas_enabled + const readReplicasEnabled = project?.is_read_replicas_enabled const { data: databases, isSuccess } = useReadReplicasQuery({ projectRef }) const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug }) diff --git a/apps/studio/components/interfaces/Settings/Logs/PreviewFilterPanel.tsx b/apps/studio/components/interfaces/Settings/Logs/PreviewFilterPanel.tsx index 193375a0ef0..845d27b9c10 100644 --- a/apps/studio/components/interfaces/Settings/Logs/PreviewFilterPanel.tsx +++ b/apps/studio/components/interfaces/Settings/Logs/PreviewFilterPanel.tsx @@ -17,7 +17,6 @@ import { import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import CSVButton from 'components/ui/CSVButton' import DatabaseSelector from 'components/ui/DatabaseSelector' -import { useFlag } from 'hooks' import { Filters, LogSearchCallback, LogTemplate, PREVIEWER_DATEPICKER_HELPERS } from '.' import DatePickers from './Logs.DatePickers' import { FILTER_OPTIONS, LogsTableName } from './Logs.constants' @@ -69,12 +68,10 @@ const PreviewFilterPanel = ({ }: PreviewFilterPanelProps) => { const router = useRouter() const [search, setSearch] = useState('') - const readReplicasEnabled = useFlag('readReplicas') const { project } = useProjectContext() // [Joshen] These are the routes tested that can show replica logs const showDatabaseSelector = - readReplicasEnabled && project?.is_read_replicas_enabled && ['/project/[ref]/logs/edge-logs', '/project/[ref]/logs/pooler-logs'].includes(router.pathname) diff --git a/apps/studio/data/read-replicas/load-balancers-query.ts b/apps/studio/data/read-replicas/load-balancers-query.ts index e0fb4fff4d5..e80df9f15ed 100644 --- a/apps/studio/data/read-replicas/load-balancers-query.ts +++ b/apps/studio/data/read-replicas/load-balancers-query.ts @@ -3,7 +3,6 @@ import { useQuery, UseQueryOptions } from '@tanstack/react-query' import { components } from 'data/api' import { get, handleError } from 'data/fetchers' import { useProjectDetailQuery } from 'data/projects/project-detail-query' -import { useFlag } from 'hooks' import { ResponseError } from 'types' import { replicaKeys } from './keys' @@ -35,18 +34,13 @@ export const useLoadBalancersQuery = ( { projectRef }: LoadBalancersVariables, { enabled = true, ...options }: UseQueryOptions = {} ) => { - const readReplicasEnabled = useFlag('readReplicas') const { data } = useProjectDetailQuery({ ref: projectRef }) return useQuery( replicaKeys.loadBalancers(projectRef), ({ signal }) => getLoadBalancers({ projectRef }, signal), { - enabled: - enabled && - data?.is_read_replicas_enabled && - readReplicasEnabled && - typeof projectRef !== 'undefined', + enabled: enabled && data?.is_read_replicas_enabled && typeof projectRef !== 'undefined', ...options, } ) diff --git a/apps/studio/data/read-replicas/replicas-query.ts b/apps/studio/data/read-replicas/replicas-query.ts index dc95d6c9ae8..a4ad7f648db 100644 --- a/apps/studio/data/read-replicas/replicas-query.ts +++ b/apps/studio/data/read-replicas/replicas-query.ts @@ -1,10 +1,10 @@ import { useQuery, UseQueryOptions } from '@tanstack/react-query' + +import { components } from 'data/api' import { get } from 'data/fetchers' +import { useProjectDetailQuery } from 'data/projects/project-detail-query' import { ResponseError } from 'types' import { replicaKeys } from './keys' -import { components } from 'data/api' -import { useFlag } from 'hooks' -import { useProjectDetailQuery } from 'data/projects/project-detail-query' export type ReadReplicasVariables = { projectRef?: string @@ -31,18 +31,13 @@ export const useReadReplicasQuery = ( { projectRef }: ReadReplicasVariables, { enabled = true, ...options }: UseQueryOptions = {} ) => { - const readReplicasEnabled = useFlag('readReplicas') const { data } = useProjectDetailQuery({ ref: projectRef }) return useQuery( replicaKeys.list(projectRef), ({ signal }) => getReadReplicas({ projectRef }, signal), { - enabled: - enabled && - data?.is_read_replicas_enabled && - readReplicasEnabled && - typeof projectRef !== 'undefined', + enabled: enabled && data?.is_read_replicas_enabled && typeof projectRef !== 'undefined', ...options, } ) diff --git a/apps/studio/data/read-replicas/replicas-status-query.ts b/apps/studio/data/read-replicas/replicas-status-query.ts index 0276ca0e827..a0430316a42 100644 --- a/apps/studio/data/read-replicas/replicas-status-query.ts +++ b/apps/studio/data/read-replicas/replicas-status-query.ts @@ -1,9 +1,8 @@ import { useQuery, UseQueryOptions } from '@tanstack/react-query' import { get } from 'data/fetchers' +import { useProjectDetailQuery } from 'data/projects/project-detail-query' import { ResponseError } from 'types' import { replicaKeys } from './keys' -import { useFlag } from 'hooks' -import { useProjectDetailQuery } from 'data/projects/project-detail-query' export type ReadReplicasStatusesVariables = { projectRef?: string @@ -34,18 +33,13 @@ export const useReadReplicasStatusesQuery = ( ...options }: UseQueryOptions = {} ) => { - const readReplicasEnabled = useFlag('readReplicas') const { data } = useProjectDetailQuery({ ref: projectRef }) return useQuery( replicaKeys.statuses(projectRef), ({ signal }) => getReadReplicasStatuses({ projectRef }, signal), { - enabled: - enabled && - data?.is_read_replicas_enabled && - readReplicasEnabled && - typeof projectRef !== 'undefined', + enabled: enabled && data?.is_read_replicas_enabled && typeof projectRef !== 'undefined', ...options, } ) diff --git a/apps/studio/pages/projects.tsx b/apps/studio/pages/projects.tsx index cf8bda6dba0..4ca933cd0a9 100644 --- a/apps/studio/pages/projects.tsx +++ b/apps/studio/pages/projects.tsx @@ -2,8 +2,8 @@ import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import ProjectList from 'components/interfaces/Home/ProjectList' -import { AccountLayout } from 'components/layouts' import HomePageActions from 'components/interfaces/HomePageActions' +import { AccountLayout } from 'components/layouts' import AlertError from 'components/ui/AlertError' import Connecting from 'components/ui/Loading/Loading' import { useOrganizationsQuery } from 'data/organizations/organizations-query' From e444d337f1509a6eb1f67e19a1b9a6aab80c697d Mon Sep 17 00:00:00 2001 From: Charis <26616127+charislam@users.noreply.github.com> Date: Tue, 27 Feb 2024 01:38:41 -0500 Subject: [PATCH 42/50] chore: remove ipv4 deprecation banners (#21589) --- .../docs/components/IPv4DeprecationBanner.tsx | 45 ------------------- apps/docs/pages/_app.tsx | 2 - apps/www/components/Nav/index.tsx | 5 +-- .../src/layout/banners/IPV4Banner/index.tsx | 28 ------------ packages/ui/src/layout/banners/index.tsx | 1 - 5 files changed, 1 insertion(+), 80 deletions(-) delete mode 100644 apps/docs/components/IPv4DeprecationBanner.tsx delete mode 100644 packages/ui/src/layout/banners/IPV4Banner/index.tsx diff --git a/apps/docs/components/IPv4DeprecationBanner.tsx b/apps/docs/components/IPv4DeprecationBanner.tsx deleted file mode 100644 index f44662e2069..00000000000 --- a/apps/docs/components/IPv4DeprecationBanner.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import Link from 'next/link' -import { memo } from 'react' - -import { Button, IconExternalLink, cn } from 'ui' - -export const IPv4DeprecationBanner = memo(() => { - return ( -

-

- Prepare for the PgBouncer and IPv4 deprecations on 26th January 2024{' '} - - Learn more - -

-
- -
-
- ) -}) -IPv4DeprecationBanner.displayName = 'IPv4DeprecationBanner' diff --git a/apps/docs/pages/_app.tsx b/apps/docs/pages/_app.tsx index b1c048b72a4..c75ece1b38b 100644 --- a/apps/docs/pages/_app.tsx +++ b/apps/docs/pages/_app.tsx @@ -14,7 +14,6 @@ import { CommandMenuProvider, PortalToast, TabsProvider } from 'ui' import { useConsent } from 'ui-patterns/ConsentToast' import Favicons from '~/components/Favicons' -import { IPv4DeprecationBanner } from '~/components/IPv4DeprecationBanner' import SiteLayout from '~/layouts/SiteLayout' import { IS_PLATFORM, IS_PREVIEW } from '~/lib/constants' import { unauthedAllowedPost } from '~/lib/fetch/fetchWrappers' @@ -223,7 +222,6 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
- diff --git a/apps/www/components/Nav/index.tsx b/apps/www/components/Nav/index.tsx index cfd6655978b..22d3baf20a2 100644 --- a/apps/www/components/Nav/index.tsx +++ b/apps/www/components/Nav/index.tsx @@ -5,7 +5,7 @@ import { useRouter } from 'next/router' import { useTheme } from 'next-themes' import { useWindowSize } from 'react-use' -import { Announcement, Button, IPV4Banner, cn } from 'ui' +import { Button, cn } from 'ui' import { NavigationMenu, NavigationMenuContent, @@ -64,9 +64,6 @@ const Nav = (props: Props) => { return ( <> - - -
{ - return ( - - ) -}) - -export default index diff --git a/packages/ui/src/layout/banners/index.tsx b/packages/ui/src/layout/banners/index.tsx index 8ba69528077..49a7d6ec582 100644 --- a/packages/ui/src/layout/banners/index.tsx +++ b/packages/ui/src/layout/banners/index.tsx @@ -1,3 +1,2 @@ export { default as Announcement } from './Announcement' -export { default as IPV4Banner } from './IPV4Banner' export { default as LW8CountdownBanner } from './LW8CountdownBanner/LW8CountdownBanner' From 95991e313509707420bd73597740d60e2f289970 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Tue, 27 Feb 2024 15:18:07 +0800 Subject: [PATCH 43/50] Fix view definition query (#21590) --- apps/studio/data/database/view-definition-query.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/studio/data/database/view-definition-query.ts b/apps/studio/data/database/view-definition-query.ts index 21cbd47ae2a..39e3b96317b 100644 --- a/apps/studio/data/database/view-definition-query.ts +++ b/apps/studio/data/database/view-definition-query.ts @@ -7,10 +7,8 @@ type GetViewDefinition = { } export const getViewDefinitionQuery = ({ schema, name }: GetViewDefinition) => { - const fullName = [schema, name].filter(Boolean).join('.') - const sql = /* SQL */ ` - select pg_get_viewdef('${fullName}', true) as definition + select pg_get_viewdef(to_regclass('"${schema}"."${name}"'), true) as definition `.trim() return sql @@ -39,6 +37,7 @@ export const useViewDefinitionQuery = Date: Tue, 27 Feb 2024 10:13:07 +0100 Subject: [PATCH 44/50] fix: Make the playwright tests always succeed (#21591) * Make the playwright tests always succeed. * Push a change to trigger the tests. * Try moving the continue-on-error on the failed step. --- .github/workflows/playwright.yml | 2 ++ .../studio/components/interfaces/Auth/Users/AddUserDropdown.tsx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 6e3c4d377e4..fde83f5826d 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -39,6 +39,8 @@ jobs: run: npx playwright install --with-deps - name: Run Playwright tests run: npm run test:playwright + # mark the action as succeeded even if the tests failed. This is temporarily until we make the tests more stable. + continue-on-error: true # - uses: actions/upload-artifact@v3 # if: always() # with: diff --git a/apps/studio/components/interfaces/Auth/Users/AddUserDropdown.tsx b/apps/studio/components/interfaces/Auth/Users/AddUserDropdown.tsx index 5813fef3ad8..1bf095ff73a 100644 --- a/apps/studio/components/interfaces/Auth/Users/AddUserDropdown.tsx +++ b/apps/studio/components/interfaces/Auth/Users/AddUserDropdown.tsx @@ -15,8 +15,8 @@ import { import { useCheckPermissions } from 'hooks' import { IS_PLATFORM } from 'lib/constants' -import CreateUserModal from './CreateUserModal' import InviteUserModal from './InviteUserModal' +import CreateUserModal from './CreateUserModal' export type AddUserDropdownProps = { projectKpsVersion?: string From a122e926e96e6f6e0d17aa1ec1ff475c0bcf2abf Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Tue, 27 Feb 2024 17:49:09 +0800 Subject: [PATCH 45/50] RR node show restoring badge (#21603) --- .../Infrastructure/InfrastructureConfiguration/InstanceNode.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceNode.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceNode.tsx index 9c901748547..e4287339065 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceNode.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceNode.tsx @@ -194,6 +194,8 @@ export const ReplicaNode = ({ data }: NodeProps) => { Healthy ) : status === PROJECT_STATUS.COMING_UP ? ( Coming up + ) : status === PROJECT_STATUS.RESTORING ? ( + Restoring ) : ( Unhealthy )} From f4f5a8b7e9482117b77d819376badf0777650a64 Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Tue, 27 Feb 2024 10:57:43 +0100 Subject: [PATCH 46/50] chore: Add telemetry events for the realtime inspector (#20672) * Added telemetry events for the realtime inspector. * Add some fixes. * Add headers to the realtime inspector. * Minor fixes. --- .../Inspector/ChooseChannelPopover/index.tsx | 14 +++++++++++ .../interfaces/Realtime/Inspector/Header.tsx | 22 ++++++++++++++++- .../Realtime/Inspector/MessageSelection.tsx | 23 +++++++++++++++++- .../Realtime/Inspector/MessagesTable.tsx | 20 +++++++++++++--- .../Inspector/RealtimeFilterPopover/index.tsx | 16 ++++++++++++- .../Inspector/RealtimeTokensPopover/index.tsx | 24 ++++++++++++++++++- .../interfaces/Realtime/Inspector/index.tsx | 15 +++++++++++- .../Realtime/Inspector/useRealtimeMessages.ts | 9 +++++-- apps/studio/lib/telemetry.ts | 13 ++++++++-- 9 files changed, 144 insertions(+), 12 deletions(-) diff --git a/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx b/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx index e1d9be354c6..9719b931570 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx @@ -1,5 +1,7 @@ import { zodResolver } from '@hookform/resolvers/zod' +import { useTelemetryProps } from 'common' import Link from 'next/link' +import { useRouter } from 'next/router' import { Dispatch, SetStateAction, useState } from 'react' import { useForm } from 'react-hook-form' import { @@ -16,6 +18,7 @@ import { } from 'ui' import * as z from 'zod' +import Telemetry from 'lib/telemetry' import { RealtimeConfig } from '../useRealtimeMessages' interface ChooseChannelPopoverProps { @@ -25,6 +28,8 @@ interface ChooseChannelPopoverProps { export const ChooseChannelPopover = ({ config, onChangeConfig }: ChooseChannelPopoverProps) => { const [open, setOpen] = useState(false) + const telemetryProps = useTelemetryProps() + const router = useRouter() const FormSchema = z.object({ channel: z.string() }) const form = useForm>({ @@ -44,6 +49,15 @@ export const ChooseChannelPopover = ({ config, onChangeConfig }: ChooseChannelPo const onSubmit = () => { setOpen(false) + Telemetry.sendEvent( + { + category: 'realtime_inspector', + action: 'started_listening_to_channel_in_input_channel_popover', + label: 'realtime_inspector_config', + }, + telemetryProps, + router + ) onChangeConfig({ ...config, channelName: form.getValues('channel'), enabled: true }) } diff --git a/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx b/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx index 11c7e1bdd55..d400408ac8b 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx @@ -3,6 +3,9 @@ import { PlayCircle, StopCircle } from 'lucide-react' import { Dispatch, SetStateAction } from 'react' import { Button } from 'ui' +import { useTelemetryProps } from 'common' +import Telemetry from 'lib/telemetry' +import { useRouter } from 'next/router' import { ChooseChannelPopover } from './ChooseChannelPopover' import { RealtimeFilterPopover } from './RealtimeFilterPopover' import { RealtimeTokensPopover } from './RealtimeTokensPopover' @@ -14,6 +17,9 @@ interface HeaderProps { } export const Header = ({ config, onChangeConfig }: HeaderProps) => { + const telemetryProps = useTelemetryProps() + const router = useRouter() + return (
@@ -27,7 +33,21 @@ export const Header = ({ config, onChangeConfig }: HeaderProps) => { className="rounded-l-none border-l-0" disabled={config.channelName.length === 0} icon={config.enabled ? : } - onClick={() => onChangeConfig({ ...config, enabled: !config.enabled })} + onClick={() => { + onChangeConfig({ ...config, enabled: !config.enabled }) + if (!config.enabled) { + // the user has clicked to start listening + Telemetry.sendEvent( + { + category: 'realtime_inspector', + action: 'started_listening', + label: 'realtime_inspector_config', + }, + telemetryProps, + router + ) + } + }} > {config.enabled ? `Stop listening` : `Start listening`} diff --git a/apps/studio/components/interfaces/Realtime/Inspector/MessageSelection.tsx b/apps/studio/components/interfaces/Realtime/Inspector/MessageSelection.tsx index ad437a22520..dde4f3d36ad 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/MessageSelection.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/MessageSelection.tsx @@ -1,7 +1,10 @@ +import { useTelemetryProps } from 'common' +import { useRouter } from 'next/router' import { useMemo } from 'react' import { Button, IconX, cn } from 'ui' import CopyButton from 'components/ui/CopyButton' +import Telemetry from 'lib/telemetry' import { LogData } from './Messages.types' import { SelectedRealtimeMessagePanel } from './SelectedRealtimeMessagePanel' @@ -11,6 +14,9 @@ export interface MessageSelectionProps { } const MessageSelection = ({ log, onClose }: MessageSelectionProps) => { + const telemetryProps = useTelemetryProps() + const router = useRouter() + const selectionText = useMemo(() => { return JSON.stringify(log, null, 2) }, [log]) @@ -64,7 +70,22 @@ const MessageSelection = ({ log, onClose }: MessageSelectionProps) => {
- + { + Telemetry.sendEvent( + { + category: 'realtime_inspector', + action: 'copied_message', + label: 'realtime_inspector_results', + }, + telemetryProps, + router + ) + }} + />