global user dropdown in docs and www (#35063)
* docs: user nav dropdown * www: user dropdown nav * update menus * chore: add complete local storage allowlist * move all local-storage to common * reload after logOut * add local storage key changes from #35175 * fix errors * add more keys * fix merge bugs --------- Co-authored-by: Alaister Young <a@alaisteryoung.com>
This commit is contained in:
committed by
GitHub
parent
24afbe0497
commit
a4cfcd9b2e
@@ -1,15 +1,17 @@
|
||||
import { Command, Search, Menu } from 'lucide-react'
|
||||
import { memo, useState } from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import type { FC } from 'react'
|
||||
import { memo, useState } from 'react'
|
||||
import { Command, Search, Menu } from 'lucide-react'
|
||||
|
||||
import { useIsLoggedIn, useIsUserLoading } from 'common'
|
||||
import { useIsLoggedIn, useIsUserLoading, useUser } from 'common'
|
||||
import { Button, buttonVariants, cn } from 'ui'
|
||||
import { CommandMenuTrigger } from 'ui-patterns/CommandMenu'
|
||||
|
||||
import { AuthenticatedDropdownMenu, CommandMenuTrigger } from 'ui-patterns'
|
||||
import GlobalNavigationMenu from './GlobalNavigationMenu'
|
||||
import useDropdownMenu from './useDropdownMenu'
|
||||
|
||||
import type { FC } from 'react'
|
||||
|
||||
const GlobalMobileMenu = dynamic(() => import('./GlobalMobileMenu'))
|
||||
const TopNavDropdown = dynamic(() => import('./TopNavDropdown'))
|
||||
|
||||
@@ -17,6 +19,8 @@ const TopNavBar: FC = () => {
|
||||
const isLoggedIn = useIsLoggedIn()
|
||||
const isUserLoading = useIsUserLoading()
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
const user = useUser()
|
||||
const menu = useDropdownMenu(user)
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -95,7 +99,11 @@ const TopNavBar: FC = () => {
|
||||
<Link href="/dev-secret-auth">Dev-only secret sign-in</Link>
|
||||
</Button>
|
||||
)}
|
||||
<TopNavDropdown />
|
||||
{isLoggedIn ? (
|
||||
<AuthenticatedDropdownMenu menu={menu} user={user} site="docs" />
|
||||
) : (
|
||||
<TopNavDropdown />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
cn,
|
||||
themes,
|
||||
} from 'ui'
|
||||
|
||||
import MenuIconPicker from './MenuIconPicker'
|
||||
|
||||
const menu = [
|
||||
@@ -70,7 +69,7 @@ const TopNavDropdown = () => {
|
||||
<Menu size={18} strokeWidth={1} />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="bottom" align="end" className="w-64">
|
||||
<DropdownMenuContent side="bottom" align="end" className="w-52">
|
||||
{menu.map((menuSection, sectionIdx) => (
|
||||
<Fragment key={`topnav--${sectionIdx}`}>
|
||||
{sectionIdx !== 0 && <DropdownMenuSeparator key={`topnav--${sectionIdx}`} />}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
'use client'
|
||||
|
||||
import type { User } from '@supabase/supabase-js'
|
||||
import { LogOut, Globe, LifeBuoy, Settings, UserIcon, Database } from 'lucide-react'
|
||||
import { logOut } from 'common'
|
||||
|
||||
import type { menuItem } from 'ui-patterns/AuthenticatedDropdownMenu'
|
||||
import { IconGitHub } from './MenuIcons'
|
||||
|
||||
const useDropdownMenu = (user: User | null) => {
|
||||
const menu: menuItem[][] = [
|
||||
[
|
||||
{
|
||||
label: user?.email ?? "You're logged in",
|
||||
type: 'text',
|
||||
icon: UserIcon,
|
||||
},
|
||||
{
|
||||
label: 'Account Preferences',
|
||||
icon: Settings,
|
||||
href: 'https://supabase.com/dashboard/account/me',
|
||||
},
|
||||
{
|
||||
label: 'All Projects',
|
||||
icon: Database,
|
||||
href: 'https://supabase.com/dashboard/projects',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Supabase.com',
|
||||
icon: Globe,
|
||||
href: 'https://supabase.com',
|
||||
otherProps: {
|
||||
target: '_blank',
|
||||
rel: 'noreferrer noopener',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'GitHub',
|
||||
icon: IconGitHub as any,
|
||||
href: 'https://github.com/supabase/supabase',
|
||||
otherProps: {
|
||||
target: '_blank',
|
||||
rel: 'noreferrer noopener',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Support',
|
||||
icon: LifeBuoy,
|
||||
href: 'https://supabase.com/support',
|
||||
otherProps: {
|
||||
target: '_blank',
|
||||
rel: 'noreferrer noopener',
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Theme',
|
||||
type: 'theme',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Logout',
|
||||
type: 'button',
|
||||
icon: LogOut,
|
||||
onClick: async () => {
|
||||
await logOut()
|
||||
window.location.reload()
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
return menu
|
||||
}
|
||||
|
||||
export default useDropdownMenu
|
||||
@@ -15,7 +15,7 @@ import CopyToClipboard from 'react-copy-to-clipboard'
|
||||
import { withErrorBoundary } from 'react-error-boundary'
|
||||
import { proxy, useSnapshot } from 'valtio'
|
||||
|
||||
import { useIsLoggedIn, useIsUserLoading } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useIsLoggedIn, useIsUserLoading } from 'common'
|
||||
import { Button_Shadcn_ as Button, Input_Shadcn_ as Input, cn } from 'ui'
|
||||
|
||||
import {
|
||||
@@ -36,7 +36,7 @@ import { useOrganizationsQuery } from '~/lib/fetch/organizations'
|
||||
import { type SupavisorConfigData, useSupavisorConfigQuery } from '~/lib/fetch/pooler'
|
||||
import { useProjectApiQuery } from '~/lib/fetch/projectApi'
|
||||
import { isProjectPaused, type ProjectsData, useProjectsQuery } from '~/lib/fetch/projects'
|
||||
import { LOCAL_STORAGE_KEYS, retrieve, storeOrRemoveNull } from '~/lib/storage'
|
||||
import { retrieve, storeOrRemoveNull } from '~/lib/storage'
|
||||
import { useOnLogout } from '~/lib/userAuth'
|
||||
|
||||
type ProjectOrgDataState =
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client'
|
||||
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { AuthProvider } from 'common'
|
||||
import { AuthProvider, LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { type PropsWithChildren, useCallback } from 'react'
|
||||
import { LOCAL_STORAGE_KEYS, remove } from '~/lib/storage'
|
||||
import { remove } from '~/lib/storage'
|
||||
import { useOnLogout } from '~/lib/userAuth'
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
export const LOCAL_STORAGE_KEYS = {
|
||||
SAVED_ORG: 'docs.ui.user.selected.org',
|
||||
SAVED_PROJECT: 'docs.ui.user.selected.project',
|
||||
SAVED_BRANCH: 'docs.ui.user.selected.branch',
|
||||
} as const
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
type LocalStorageKey = (typeof LOCAL_STORAGE_KEYS)[keyof typeof LOCAL_STORAGE_KEYS]
|
||||
|
||||
type StorageType = 'local' | 'session'
|
||||
|
||||
function getStorage(storageType: StorageType) {
|
||||
@@ -17,7 +12,7 @@ export function store(storageType: StorageType, key: LocalStorageKey, value: str
|
||||
const storage = getStorage(storageType)
|
||||
|
||||
try {
|
||||
storage.setItem(key, value)
|
||||
storage.setItem(key as string, value)
|
||||
} catch {
|
||||
console.error(`Failed to set storage item with key "${key}"`)
|
||||
}
|
||||
@@ -26,13 +21,13 @@ export function store(storageType: StorageType, key: LocalStorageKey, value: str
|
||||
export function retrieve(storageType: StorageType, key: LocalStorageKey) {
|
||||
if (typeof window === 'undefined') return
|
||||
const storage = getStorage(storageType)
|
||||
return storage.getItem(key)
|
||||
return storage.getItem(key as string)
|
||||
}
|
||||
|
||||
export function remove(storageType: StorageType, key: LocalStorageKey) {
|
||||
if (typeof window === 'undefined') return
|
||||
const storage = getStorage(storageType)
|
||||
return storage.removeItem(key)
|
||||
return storage.removeItem(key as string)
|
||||
}
|
||||
|
||||
export function storeOrRemoveNull(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { SupportCategories } from '@supabase/shared-types/out/constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
@@ -27,6 +26,7 @@ import {
|
||||
Input_Shadcn_,
|
||||
Separator,
|
||||
} from 'ui'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
const setDeletionRequestFlag = () => {
|
||||
const expiryDate = new Date()
|
||||
|
||||
@@ -5,7 +5,7 @@ import SVG from 'react-inlinesvg'
|
||||
import { DEFAULT_SIDEBAR_BEHAVIOR } from 'components/interfaces/Sidebar'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { BASE_PATH, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import {
|
||||
Label_Shadcn_,
|
||||
RadioGroup_Shadcn_,
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
Theme,
|
||||
} from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
export const ThemeSettings = () => {
|
||||
const [mounted, setMounted] = useState(false)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { noop } from 'lodash'
|
||||
import { PropsWithChildren, createContext, useContext, useEffect, useState } from 'react'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
|
||||
const FLY_POSTGRES_DEPRECATION_WARNING_KEY = LOCAL_STORAGE_KEYS.FLY_POSTGRES_DEPRECATION_WARNING
|
||||
|
||||
// [Joshen] This file is meant to be dynamic - update this as and when we need to use the NoticeBanner
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { noop } from 'lodash'
|
||||
|
||||
import { FeatureFlagContext } from 'common'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { EMPTY_OBJ } from 'lib/void'
|
||||
import { PropsWithChildren, createContext, useContext, useEffect, useState } from 'react'
|
||||
import { APISidePanelPreview } from './APISidePanelPreview'
|
||||
@@ -11,6 +10,7 @@ import { InlineEditorPreview } from './InlineEditorPreview'
|
||||
import { LayoutUpdatePreview } from './LayoutUpdatePreview'
|
||||
import { SqlEditorTabsPreview } from './SqlEditorTabs'
|
||||
import { TableEditorTabsPreview } from './TableEditorTabs'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
export const FEATURE_PREVIEWS = [
|
||||
{
|
||||
|
||||
@@ -2,10 +2,11 @@ import { ExternalLink, Eye, EyeOff, FlaskConical } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { removeTabsByEditor } from 'state/tabs'
|
||||
import { Badge, Button, Modal, ScrollArea, cn } from 'ui'
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { BASE_PATH, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { ExternalLink, X } from 'lucide-react'
|
||||
import Image from 'next/image'
|
||||
import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, Badge, Button } from 'ui'
|
||||
import { useIsNewLayoutEnabled } from './FeaturePreviewContext'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
export const LayoutUpdatePreview = () => {
|
||||
return (
|
||||
|
||||
@@ -2,13 +2,13 @@ import { useRouter } from 'next/router'
|
||||
import { PropsWithChildren, useEffect } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useIsLoggedIn, useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useIsLoggedIn, useParams } from 'common'
|
||||
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import useLatest from 'hooks/misc/useLatest'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { useIsNewLayoutEnabled } from './FeaturePreview/FeaturePreviewContext'
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import { isEmpty, noop } from 'lodash'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { Modal } from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
|
||||
@@ -5,7 +5,7 @@ import { UIEvent, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
@@ -18,7 +18,6 @@ import { useUserDeleteMutation } from 'data/auth/user-delete-mutation'
|
||||
import { useUsersCountQuery } from 'data/auth/users-count-query'
|
||||
import { User, useUsersInfiniteQuery } from 'data/auth/users-infinite-query'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import {
|
||||
Button,
|
||||
cn,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useEffect, useMemo, useState } from 'react'
|
||||
import ReactFlow, { Background, BackgroundVariant, MiniMap, useReactFlow } from 'reactflow'
|
||||
import 'reactflow/dist/style.css'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
@@ -16,7 +16,6 @@ import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import { useLocalStorage } from 'hooks/misc/useLocalStorage'
|
||||
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { toast } from 'sonner'
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from 'ui'
|
||||
import { SchemaGraphLegend } from './SchemaGraphLegend'
|
||||
|
||||
@@ -4,9 +4,9 @@ import { uniqBy } from 'lodash'
|
||||
import { Edge, Node, Position } from 'reactflow'
|
||||
import 'reactflow/dist/style.css'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { tryParseJson } from 'lib/helpers'
|
||||
import { TABLE_NODE_ROW_HEIGHT, TABLE_NODE_WIDTH, TableNodeData } from './SchemaTableNode'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
const NODE_SEP = 25
|
||||
const RANK_SEP = 50
|
||||
|
||||
@@ -37,10 +37,10 @@ import { MouseEventHandler, useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useLocalStorage } from 'hooks/misc/useLocalStorage'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button, cn } from 'ui'
|
||||
import { RoleImpersonationSelector } from '../RoleImpersonationSelector'
|
||||
import styles from './graphiql.module.css'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
export interface GraphiQLProps {
|
||||
fetcher: Fetcher
|
||||
|
||||
@@ -3,12 +3,12 @@ import { useRouter } from 'next/router'
|
||||
import { useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useIsNewLayoutEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useOrganizationDeleteMutation } from 'data/organizations/organization-delete-mutation'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { Button, Form, Input, Modal } from 'ui'
|
||||
|
||||
const DeleteOrganizationButton = () => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useRouter } from 'next/router'
|
||||
import { useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useIsNewLayoutEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import {
|
||||
ScaffoldActionsContainer,
|
||||
@@ -22,7 +22,6 @@ import { usePermissionsQuery } from 'data/permissions/permissions-query'
|
||||
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { Input } from 'ui-patterns/DataInputs/Input'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
|
||||
@@ -4,14 +4,14 @@ import { useRouter } from 'next/router'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { formatDatabaseID } from 'data/read-replicas/replicas.utils'
|
||||
import { executeSql } from 'data/sql/execute-sql-query'
|
||||
import { DbQueryHook } from 'hooks/analytics/useDbQuery'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
||||
import {
|
||||
Button,
|
||||
|
||||
@@ -2,14 +2,13 @@ import { ArrowDown, ArrowUp, RefreshCw } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useState } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { DownloadResultsButton } from 'components/ui/DownloadResultsButton'
|
||||
import { FilterPopover } from 'components/ui/FilterPopover'
|
||||
import { useDatabaseRolesQuery } from 'data/database-roles/database-roles-query'
|
||||
import { DbQueryHook } from 'hooks/analytics/useDbQuery'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
|
||||
@@ -3,10 +3,9 @@ import { debounce } from 'lodash'
|
||||
import { useRouter } from 'next/router'
|
||||
import { MutableRefObject, useEffect, useRef } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
|
||||
import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2'
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useRouter } from 'next/router'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import ResizableAIWidget from 'components/ui/AIEditor/ResizableAIWidget'
|
||||
import { GridFooter } from 'components/ui/GridFooter'
|
||||
import { useSqlTitleGenerateMutation } from 'data/ai/sql-title-mutation'
|
||||
@@ -24,7 +24,7 @@ import { useOrgOptedIntoAi } from 'hooks/misc/useOrgOptedIntoAi'
|
||||
import { useSchemasForAi } from 'hooks/misc/useSchemasForAi'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { BASE_PATH, IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { BASE_PATH, IS_PLATFORM } from 'lib/constants'
|
||||
import { formatSql } from 'lib/formatSql'
|
||||
import { detectOS, uuidv4 } from 'lib/helpers'
|
||||
import { useProfile } from 'lib/profile'
|
||||
|
||||
@@ -2,13 +2,12 @@ import dayjs from 'dayjs'
|
||||
import { ArrowUpDown, X } from 'lucide-react'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import BarChart from 'components/ui/Charts/BarChart'
|
||||
import NoDataPlaceholder from 'components/ui/Charts/NoDataPlaceholder'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import Link from 'next/link'
|
||||
import {
|
||||
Badge,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { AlignLeft, Check, Heart, Keyboard, MoreVertical } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { RoleImpersonationPopover } from 'components/interfaces/RoleImpersonationSelector'
|
||||
import DatabaseSelector from 'components/ui/DatabaseSelector'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { detectOS } from 'lib/helpers'
|
||||
import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2'
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Monaco } from '@monaco-editor/react'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import getPgsqlCompletionProvider from 'components/ui/CodeEditor/Providers/PgSQLCompletionProvider'
|
||||
import getPgsqlSignatureHelpProvider from 'components/ui/CodeEditor/Providers/PgSQLSignatureHelpProvider'
|
||||
@@ -7,7 +8,6 @@ import { useKeywordsQuery } from 'data/database/keywords-query'
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { useTableColumnsQuery } from 'data/database/table-columns-query'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { formatSql } from 'lib/formatSql'
|
||||
import { IDisposable } from 'monaco-editor'
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
@@ -14,7 +14,7 @@ import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { ComponentProps, ComponentPropsWithoutRef, FC, ReactNode, useEffect } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import {
|
||||
generateOtherRoutes,
|
||||
generateProductRoutes,
|
||||
@@ -30,7 +30,6 @@ import { useLints } from 'hooks/misc/useLints'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { Home } from 'icons'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import {
|
||||
Button,
|
||||
|
||||
@@ -7,7 +7,8 @@ import { PropsWithChildren, useEffect } from 'react'
|
||||
import { useIsNewLayoutEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { withAuth } from 'hooks/misc/withAuth'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { cn, NavMenu, NavMenuItem } from 'ui'
|
||||
import {
|
||||
|
||||
@@ -6,9 +6,9 @@ import NoPermission from 'components/ui/NoPermission'
|
||||
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { withAuth } from 'hooks/misc/withAuth'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import ProjectLayout from '../ProjectLayout/ProjectLayout'
|
||||
import { LogsSidebarMenuV2 } from './LogsSidebarMenuV2'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
interface LogsLayoutProps {
|
||||
title?: string
|
||||
|
||||
@@ -7,7 +7,8 @@ import { useOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useShowLayoutHeader } from 'hooks/misc/useShowLayoutHeader'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
export const HomeIcon = () => {
|
||||
const newLayoutPreview = useIsNewLayoutEnabled()
|
||||
|
||||
@@ -11,7 +11,7 @@ import { cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
|
||||
import type { Route } from 'components/ui/ui.types'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
interface NavigationIconButtonProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||
route: Route
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useDebounce } from '@uidotdev/usehooks'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { FilePlus, FolderPlus, Plus, X } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useLocalStorage } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { getAppStateSnapshot } from 'state/app-state'
|
||||
import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useIsSQLEditorTabsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import DownloadSnippetModal from 'components/interfaces/SQLEditor/DownloadSnippetModal'
|
||||
import { MoveQueryModal } from 'components/interfaces/SQLEditor/MoveQueryModal'
|
||||
@@ -17,7 +17,6 @@ import { Snippet, SnippetFolder, useSQLSnippetFoldersQuery } from 'data/content/
|
||||
import { useSqlSnippetsQuery } from 'data/content/sql-snippets-query'
|
||||
import { useLocalStorage } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import uuidv4 from 'lib/uuid'
|
||||
import { Eye, EyeOffIcon, Heart, Unlock } from 'lucide-react'
|
||||
|
||||
@@ -16,8 +16,7 @@ import {
|
||||
TabsTrigger_Shadcn_,
|
||||
} from 'ui'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
|
||||
const ApiKeysLayout = ({ children }: PropsWithChildren) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
|
||||
@@ -3,12 +3,13 @@ import * as Sentry from '@sentry/nextjs'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useParams, useTelemetryCookie, useUser } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams, useTelemetryCookie, useUser } from 'common'
|
||||
import { useSendGroupsIdentifyMutation } from 'data/telemetry/send-groups-identify-mutation'
|
||||
import { useSendGroupsResetMutation } from 'data/telemetry/send-groups-reset-mutation'
|
||||
import { usePrevious } from 'hooks/deprecated'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
|
||||
const getAnonId = async (id: string) => {
|
||||
const encoder = new TextEncoder()
|
||||
|
||||
@@ -3,7 +3,7 @@ import { toast } from 'sonner'
|
||||
|
||||
import { handleError, post } from 'data/fetchers'
|
||||
import type { ResponseError } from 'types'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
export type GitHubAuthorizationCreateVariables = {
|
||||
code: string
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useLocalStorage } from './useLocalStorage'
|
||||
|
||||
export type LastSignInType = 'github' | 'email' | 'sso' | null
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { parseAsString, useQueryState } from 'nuqs'
|
||||
import { useEffect, useMemo } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
|
||||
/**
|
||||
* This hook wraps useQueryState because useQueryState imports app router for some reason which breaks the SSR in
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { Dispatch, SetStateAction } from 'react'
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { AuthProvider as AuthProviderInternal, gotrueClient } from 'common'
|
||||
import { AuthProvider as AuthProviderInternal, clearLocalStorage, gotrueClient } from 'common'
|
||||
import { PropsWithChildren, useCallback, useEffect } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { GOTRUE_ERRORS, IS_PLATFORM } from './constants'
|
||||
import { clearLocalStorage } from './local-storage'
|
||||
|
||||
export const AuthProvider = ({ children }: PropsWithChildren<{}>) => {
|
||||
// Check for unverified GitHub users after a GitHub sign in
|
||||
|
||||
@@ -38,65 +38,6 @@ export const STRIPE_PUBLIC_KEY =
|
||||
|
||||
export const USAGE_APPROACHING_THRESHOLD = 0.75
|
||||
|
||||
export const LOCAL_STORAGE_KEYS = {
|
||||
AI_ASSISTANT_STATE: (projectRef: string | undefined) =>
|
||||
`supabase-ai-assistant-state-${projectRef}`,
|
||||
SIDEBAR_BEHAVIOR: 'supabase-sidebar-behavior',
|
||||
EDITOR_PANEL_STATE: 'supabase-editor-panel-state',
|
||||
|
||||
UI_PREVIEW_API_SIDE_PANEL: 'supabase-ui-api-side-panel',
|
||||
UI_PREVIEW_CLS: 'supabase-ui-cls',
|
||||
UI_PREVIEW_INLINE_EDITOR: 'supabase-ui-preview-inline-editor',
|
||||
UI_ONBOARDING_NEW_PAGE_SHOWN: 'supabase-ui-onboarding-new-page-shown',
|
||||
UI_TABLE_EDITOR_TABS: 'supabase-ui-table-editor-tabs',
|
||||
UI_SQL_EDITOR_TABS: 'supabase-ui-sql-editor-tabs',
|
||||
UI_NEW_LAYOUT_PREVIEW: 'supabase-ui-new-layout-preview',
|
||||
NEW_LAYOUT_NOTICE_ACKNOWLEDGED: 'new-layout-notice-acknowledge',
|
||||
|
||||
DASHBOARD_HISTORY: (ref: string) => `dashboard-history-${ref}`,
|
||||
STORAGE_PREFERENCE: (ref: string) => `storage-explorer-${ref}`,
|
||||
|
||||
SQL_EDITOR_INTELLISENSE: 'supabase_sql-editor-intellisense-enabled',
|
||||
SQL_EDITOR_SPLIT_SIZE: 'supabase_sql-editor-split-size',
|
||||
// Key to track which schemas are ok to be sent to AI. The project ref is intentionally put at the end for easier search in the browser console.
|
||||
SQL_EDITOR_AI_SCHEMA: (ref: string) => `supabase_sql-editor-ai-schema-enabled-${ref}`,
|
||||
SQL_EDITOR_AI_OPEN: 'supabase_sql-editor-ai-open',
|
||||
SQL_EDITOR_LAST_SELECTED_DB: (ref: string) => `sql-editor-last-selected-db-${ref}`,
|
||||
SQL_EDITOR_SQL_BLOCK_ACKNOWLEDGED: (ref: string) => `sql-editor-sql-block-acknowledged-${ref}`,
|
||||
SQL_EDITOR_SECTION_STATE: (ref: string) => `sql-editor-section-state-${ref}`,
|
||||
SQL_EDITOR_SORT: (ref: string) => `sql-editor-sort-${ref}`,
|
||||
|
||||
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',
|
||||
QUERY_PERF_SHOW_BOTTOM_SECTION: 'supabase-query-perf-show-bottom-section',
|
||||
// Key to track account deletion requests
|
||||
ACCOUNT_DELETION_REQUEST: 'supabase-account-deletion-request',
|
||||
// Used for storing a user id when sending reports to Sentry. The id is hashed for anonymity.
|
||||
SENTRY_USER_ID: 'supabase-sentry-user-id',
|
||||
// Used for storing the last sign in method used by the user
|
||||
LAST_SIGN_IN_METHOD: 'supabase-last-sign-in-method',
|
||||
// Key to track the last selected schema. The project ref is intentionally put at the end for easier search in the browser console.
|
||||
LAST_SELECTED_SCHEMA: (ref: string) => `last-selected-schema-${ref}`,
|
||||
// Track position of nodes for schema visualizer
|
||||
SCHEMA_VISUALIZER_POSITIONS: (ref: string, schemaId: number) =>
|
||||
`schema-visualizer-positions-${ref}-${schemaId}`,
|
||||
// Used for allowing the main nav panel to expand on hover
|
||||
EXPAND_NAVIGATION_PANEL: 'supabase-expand-navigation-panel',
|
||||
GITHUB_AUTHORIZATION_STATE: 'supabase-github-authorization-state',
|
||||
// Notice banner keys
|
||||
FLY_POSTGRES_DEPRECATION_WARNING: 'fly-postgres-deprecation-warning-dismissed',
|
||||
AUTH_USERS_COLUMNS_CONFIGURATION: (ref: string) => `supabase-auth-users-columns-${ref}`,
|
||||
|
||||
// api keys view switcher for new and legacy api keys
|
||||
API_KEYS_VIEW: (ref: string) => `supabase-api-keys-view-${ref}`,
|
||||
|
||||
// last visited logs page
|
||||
LAST_VISITED_LOGS_PAGE: 'supabase-last-visited-logs-page',
|
||||
LAST_VISITED_ORGANIZATION: 'last-visited-organization',
|
||||
}
|
||||
|
||||
export const OPT_IN_TAGS = {
|
||||
AI_SQL: 'AI_SQL_GENERATOR_OPT_IN',
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LOCAL_STORAGE_KEYS } from './constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { makeRandomString } from './helpers'
|
||||
|
||||
const GITHUB_INTEGRATION_APP_NAME =
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { LOCAL_STORAGE_KEYS as COMMON_LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
|
||||
const LOCAL_STORAGE_KEYS_ALLOWLIST = [
|
||||
'graphiql:theme',
|
||||
'theme',
|
||||
'supabaseDarkMode',
|
||||
'supabase.dashboard.auth.debug',
|
||||
'supabase.dashboard.auth.navigatorLock.disabled',
|
||||
COMMON_LOCAL_STORAGE_KEYS.TELEMETRY_CONSENT,
|
||||
LOCAL_STORAGE_KEYS.UI_PREVIEW_API_SIDE_PANEL,
|
||||
LOCAL_STORAGE_KEYS.UI_PREVIEW_INLINE_EDITOR,
|
||||
LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS,
|
||||
LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS,
|
||||
LOCAL_STORAGE_KEYS.UI_NEW_LAYOUT_PREVIEW,
|
||||
LOCAL_STORAGE_KEYS.UI_PREVIEW_INLINE_EDITOR,
|
||||
LOCAL_STORAGE_KEYS.UI_PREVIEW_CLS,
|
||||
LOCAL_STORAGE_KEYS.LAST_SIGN_IN_METHOD,
|
||||
]
|
||||
|
||||
export function clearLocalStorage() {
|
||||
for (const key in localStorage) {
|
||||
if (!LOCAL_STORAGE_KEYS_ALLOWLIST.includes(key)) {
|
||||
localStorage.removeItem(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { components } from 'api-types'
|
||||
import { hasConsented } from 'common'
|
||||
import { handleError, post } from 'data/fetchers'
|
||||
import { IS_PLATFORM } from './constants'
|
||||
import { LOCAL_STORAGE_KEYS, hasConsented } from 'common'
|
||||
|
||||
type TrackFeatureFlagVariables = components['schemas']['TelemetryFeatureFlagBodyDto']
|
||||
|
||||
|
||||
@@ -42,11 +42,12 @@ import { downloadBucketObject } from 'data/storage/bucket-object-download-mutati
|
||||
import { StorageObject, listBucketObjects } from 'data/storage/bucket-objects-list-mutation'
|
||||
import { Bucket } from 'data/storage/buckets-query'
|
||||
import { moveStorageObject } from 'data/storage/object-move-mutation'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { tryParseJson } from 'lib/helpers'
|
||||
import { lookupMime } from 'lib/mime'
|
||||
import Link from 'next/link'
|
||||
import { Button, SONNER_DEFAULT_DURATION, SonnerProgress } from 'ui'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
type CachedFile = { id: string; fetchedAt: number; expiresIn: number; url: string }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { AlertCircle, XIcon } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
@@ -27,7 +27,6 @@ import { useTablePrivilegesQuery } from 'data/privileges/table-privileges-query'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import { useLocalStorage } from 'hooks/misc/useLocalStorage'
|
||||
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
|
||||
@@ -6,7 +6,8 @@ import { useRouter } from 'next/router'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { IS_PLATFORM, useParams } from 'common'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
|
||||
import {
|
||||
LOGS_LARGE_DATE_RANGE_DAYS_THRESHOLD,
|
||||
LOGS_TABLES,
|
||||
@@ -41,7 +42,6 @@ import useLogsQuery from 'hooks/analytics/useLogsQuery'
|
||||
import { useLogsUrlState } from 'hooks/analytics/useLogsUrlState'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useUpgradePrompt } from 'hooks/misc/useUpgradePrompt'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import type { LogSqlSnippets, NextPageWithLayout } from 'types'
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import LogsLayout from 'components/layouts/LogsLayout/LogsLayout'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
|
||||
export const LogPage: NextPageWithLayout = () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
|
||||
import LegacyAPIKeys from 'components/interfaces/APIKeys/LegacyAPIKeys'
|
||||
import { PublishableAPIKeys } from 'components/interfaces/APIKeys/PublishableAPIKeys'
|
||||
@@ -9,7 +9,6 @@ import ApiKeysLayout from 'components/layouts/project/[ref]/settings/APIKeysLayo
|
||||
import SettingsLayout from 'components/layouts/ProjectSettingsLayout/SettingsLayout'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
import { Separator } from 'ui'
|
||||
|
||||
|
||||
@@ -13,9 +13,10 @@ import { useOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import { useAutoProjectsPrefetch } from 'data/projects/projects-query'
|
||||
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS, PROJECT_STATUS } from 'lib/constants'
|
||||
import { IS_PLATFORM, PROJECT_STATUS } from 'lib/constants'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
import { cn } from 'ui'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
const ProjectsPage: NextPageWithLayout = () => {
|
||||
const newLayoutPreview = useIsNewLayoutEnabled()
|
||||
|
||||
@@ -3,8 +3,7 @@ import type { Message as MessageType } from 'ai/react'
|
||||
import { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react'
|
||||
import { proxy, snapshot, subscribe, useSnapshot } from 'valtio'
|
||||
import { debounce } from 'lodash'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
|
||||
type SuggestionsType = {
|
||||
title: string
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { proxy, snapshot, subscribe, useSnapshot } from 'valtio'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS as COMMON_LOCAL_STORAGE_KEYS, LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { SQL_TEMPLATES } from 'components/interfaces/SQLEditor/SQLEditor.queries'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
|
||||
export type Template = {
|
||||
name: string
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
STORAGE_SORT_BY_ORDER,
|
||||
STORAGE_VIEWS,
|
||||
} from 'components/to-be-cleaned/Storage/Storage.constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { tryParseJson } from 'lib/helpers'
|
||||
|
||||
const DEFAULT_PREFERENCES = {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useRouter } from 'next/router'
|
||||
import React, { useState } from 'react'
|
||||
import { useWindowSize } from 'react-use'
|
||||
|
||||
import { useIsLoggedIn } from 'common'
|
||||
import { useIsLoggedIn, useUser } from 'common'
|
||||
import { Button, buttonVariants, cn } from 'ui'
|
||||
import {
|
||||
NavigationMenu,
|
||||
@@ -23,6 +23,8 @@ import MenuItem from './MenuItem'
|
||||
import MobileMenu from './MobileMenu'
|
||||
import RightClickBrandLogo from './RightClickBrandLogo'
|
||||
import { useSendTelemetryEvent } from '~/lib/telemetry'
|
||||
import useDropdownMenu from './useDropdownMenu'
|
||||
import { AuthenticatedDropdownMenu } from 'ui-patterns'
|
||||
|
||||
interface Props {
|
||||
hideNavbar: boolean
|
||||
@@ -37,6 +39,8 @@ const Nav = ({ hideNavbar, stickyNavbar = true }: Props) => {
|
||||
const isLoggedIn = useIsLoggedIn()
|
||||
const menu = getMenu()
|
||||
const sendTelemetryEvent = useSendTelemetryEvent()
|
||||
const user = useUser()
|
||||
const userMenu = useDropdownMenu(user)
|
||||
|
||||
const isHomePage = router.pathname === '/'
|
||||
const isLaunchWeekPage = router.pathname.includes('/launch-week')
|
||||
@@ -130,9 +134,12 @@ const Nav = ({ hideNavbar, stickyNavbar = true }: Props) => {
|
||||
<GitHubButton />
|
||||
|
||||
{isLoggedIn ? (
|
||||
<Button className="hidden lg:block" asChild>
|
||||
<Link href="/dashboard/projects">Dashboard</Link>
|
||||
</Button>
|
||||
<>
|
||||
<Button className="hidden lg:block" asChild>
|
||||
<Link href="/dashboard/projects">Dashboard</Link>
|
||||
</Button>
|
||||
<AuthenticatedDropdownMenu menu={userMenu} user={user} site="www" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button type="default" className="hidden lg:block" asChild>
|
||||
|
||||
62
apps/www/components/Nav/useDropdownMenu.tsx
Normal file
62
apps/www/components/Nav/useDropdownMenu.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
'use client'
|
||||
|
||||
import type { User } from '@supabase/supabase-js'
|
||||
import { Command, Database, LogOut, Settings, UserIcon } from 'lucide-react'
|
||||
import { logOut } from 'common'
|
||||
|
||||
import type { menuItem } from 'ui-patterns/AuthenticatedDropdownMenu'
|
||||
import { useSetCommandMenuOpen } from 'ui-patterns'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const useDropdownMenu = (user: User | null) => {
|
||||
const router = useRouter()
|
||||
const setCommandMenuOpen = useSetCommandMenuOpen()
|
||||
|
||||
const menu: menuItem[][] = [
|
||||
[
|
||||
{
|
||||
label: user?.email ?? "You're logged in",
|
||||
type: 'text',
|
||||
icon: UserIcon,
|
||||
},
|
||||
{
|
||||
label: 'Account Preferences',
|
||||
icon: Settings,
|
||||
href: 'https://supabase.com/dashboard/account/me',
|
||||
},
|
||||
{
|
||||
label: 'All Projects',
|
||||
icon: Database,
|
||||
href: 'https://supabase.com/dashboard/projects',
|
||||
},
|
||||
{
|
||||
label: 'Command Menu',
|
||||
icon: Command,
|
||||
type: 'button',
|
||||
onClick: () => setCommandMenuOpen(true),
|
||||
shortcut: '⌘K',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Theme',
|
||||
type: 'theme',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Logout',
|
||||
type: 'button',
|
||||
icon: LogOut,
|
||||
onClick: async () => {
|
||||
await logOut()
|
||||
router.reload()
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
return menu
|
||||
}
|
||||
|
||||
export default useDropdownMenu
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
useState,
|
||||
} from 'react'
|
||||
import { gotrueClient, type User } from './gotrue'
|
||||
import { clearLocalStorage } from './constants/local-storage'
|
||||
|
||||
export type { User }
|
||||
|
||||
@@ -115,6 +116,13 @@ export const useIsLoggedIn = () => {
|
||||
return user !== null
|
||||
}
|
||||
|
||||
export const signOut = async () => await gotrueClient.signOut()
|
||||
|
||||
export const logOut = async () => {
|
||||
await signOut()
|
||||
clearLocalStorage()
|
||||
}
|
||||
|
||||
let currentSession: Session | null = null
|
||||
|
||||
gotrueClient.onAuthStateChange((event, session) => {
|
||||
|
||||
@@ -1,7 +1,111 @@
|
||||
export const LOCAL_STORAGE_KEYS = {
|
||||
/**
|
||||
* STUDIO
|
||||
*/
|
||||
AI_ASSISTANT_STATE: (projectRef: string | undefined) =>
|
||||
`supabase-ai-assistant-state-${projectRef}`,
|
||||
SIDEBAR_BEHAVIOR: 'supabase-sidebar-behavior',
|
||||
EDITOR_PANEL_STATE: 'supabase-editor-panel-state',
|
||||
|
||||
UI_PREVIEW_API_SIDE_PANEL: 'supabase-ui-api-side-panel',
|
||||
UI_PREVIEW_CLS: 'supabase-ui-cls',
|
||||
UI_PREVIEW_INLINE_EDITOR: 'supabase-ui-preview-inline-editor',
|
||||
UI_ONBOARDING_NEW_PAGE_SHOWN: 'supabase-ui-onboarding-new-page-shown',
|
||||
UI_TABLE_EDITOR_TABS: 'supabase-ui-table-editor-tabs',
|
||||
UI_SQL_EDITOR_TABS: 'supabase-ui-sql-editor-tabs',
|
||||
UI_NEW_LAYOUT_PREVIEW: 'supabase-ui-new-layout-preview',
|
||||
NEW_LAYOUT_NOTICE_ACKNOWLEDGED: 'new-layout-notice-acknowledge',
|
||||
|
||||
DASHBOARD_HISTORY: (ref: string) => `dashboard-history-${ref}`,
|
||||
STORAGE_PREFERENCE: (ref: string) => `storage-explorer-${ref}`,
|
||||
|
||||
SQL_EDITOR_INTELLISENSE: 'supabase_sql-editor-intellisense-enabled',
|
||||
SQL_EDITOR_SPLIT_SIZE: 'supabase_sql-editor-split-size',
|
||||
// Key to track which schemas are ok to be sent to AI. The project ref is intentionally put at the end for easier search in the browser console.
|
||||
SQL_EDITOR_AI_SCHEMA: (ref: string) => `supabase_sql-editor-ai-schema-enabled-${ref}`,
|
||||
SQL_EDITOR_AI_OPEN: 'supabase_sql-editor-ai-open',
|
||||
SQL_EDITOR_LAST_SELECTED_DB: (ref: string) => `sql-editor-last-selected-db-${ref}`,
|
||||
SQL_EDITOR_SQL_BLOCK_ACKNOWLEDGED: (ref: string) => `sql-editor-sql-block-acknowledged-${ref}`,
|
||||
SQL_EDITOR_SECTION_STATE: (ref: string) => `sql-editor-section-state-${ref}`,
|
||||
SQL_EDITOR_SORT: (ref: string) => `sql-editor-sort-${ref}`,
|
||||
|
||||
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',
|
||||
QUERY_PERF_SHOW_BOTTOM_SECTION: 'supabase-query-perf-show-bottom-section',
|
||||
// Key to track account deletion requests
|
||||
ACCOUNT_DELETION_REQUEST: 'supabase-account-deletion-request',
|
||||
// Used for storing a user id when sending reports to Sentry. The id is hashed for anonymity.
|
||||
SENTRY_USER_ID: 'supabase-sentry-user-id',
|
||||
// Used for storing the last sign in method used by the user
|
||||
LAST_SIGN_IN_METHOD: 'supabase-last-sign-in-method',
|
||||
// Key to track the last selected schema. The project ref is intentionally put at the end for easier search in the browser console.
|
||||
LAST_SELECTED_SCHEMA: (ref: string) => `last-selected-schema-${ref}`,
|
||||
// Track position of nodes for schema visualizer
|
||||
SCHEMA_VISUALIZER_POSITIONS: (ref: string, schemaId: number) =>
|
||||
`schema-visualizer-positions-${ref}-${schemaId}`,
|
||||
// Used for allowing the main nav panel to expand on hover
|
||||
EXPAND_NAVIGATION_PANEL: 'supabase-expand-navigation-panel',
|
||||
GITHUB_AUTHORIZATION_STATE: 'supabase-github-authorization-state',
|
||||
// Notice banner keys
|
||||
FLY_POSTGRES_DEPRECATION_WARNING: 'fly-postgres-deprecation-warning-dismissed',
|
||||
AUTH_USERS_COLUMNS_CONFIGURATION: (ref: string) => `supabase-auth-users-columns-${ref}`,
|
||||
|
||||
// api keys view switcher for new and legacy api keys
|
||||
API_KEYS_VIEW: (ref: string) => `supabase-api-keys-view-${ref}`,
|
||||
|
||||
// last visited logs page
|
||||
LAST_VISITED_LOGS_PAGE: 'supabase-last-visited-logs-page',
|
||||
LAST_VISITED_ORGANIZATION: 'last-visited-organization',
|
||||
|
||||
/**
|
||||
* COMMON
|
||||
*/
|
||||
/** @deprecated – we're using usercentrics instead to handle telemetry consent */
|
||||
TELEMETRY_CONSENT: 'supabase-consent-ph',
|
||||
TELEMETRY_DATA: 'supabase-telemetry-data',
|
||||
|
||||
/**
|
||||
* DOCS
|
||||
*/
|
||||
SAVED_ORG: 'docs.ui.user.selected.org',
|
||||
SAVED_PROJECT: 'docs.ui.user.selected.project',
|
||||
SAVED_BRANCH: 'docs.ui.user.selected.branch',
|
||||
|
||||
HIDE_PROMO_TOAST: 'supabase-hide-promo-toast-lw13-d1',
|
||||
|
||||
/**
|
||||
* WWW
|
||||
*/
|
||||
BLOG_VIEW: 'supabase-blog-view',
|
||||
} as const
|
||||
|
||||
export type LocalStorageKey = (typeof LOCAL_STORAGE_KEYS)[keyof typeof LOCAL_STORAGE_KEYS]
|
||||
|
||||
const LOCAL_STORAGE_KEYS_ALLOWLIST = [
|
||||
'graphiql:theme',
|
||||
'theme',
|
||||
'supabaseDarkMode',
|
||||
'supabase.dashboard.auth.debug',
|
||||
'supabase.dashboard.auth.navigatorLock.disabled',
|
||||
LOCAL_STORAGE_KEYS.TELEMETRY_CONSENT,
|
||||
LOCAL_STORAGE_KEYS.UI_PREVIEW_API_SIDE_PANEL,
|
||||
LOCAL_STORAGE_KEYS.UI_PREVIEW_INLINE_EDITOR,
|
||||
LOCAL_STORAGE_KEYS.UI_TABLE_EDITOR_TABS,
|
||||
LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS,
|
||||
LOCAL_STORAGE_KEYS.UI_NEW_LAYOUT_PREVIEW,
|
||||
LOCAL_STORAGE_KEYS.UI_PREVIEW_INLINE_EDITOR,
|
||||
LOCAL_STORAGE_KEYS.UI_PREVIEW_CLS,
|
||||
LOCAL_STORAGE_KEYS.LAST_SIGN_IN_METHOD,
|
||||
LOCAL_STORAGE_KEYS.HIDE_PROMO_TOAST,
|
||||
LOCAL_STORAGE_KEYS.BLOG_VIEW,
|
||||
]
|
||||
|
||||
export function clearLocalStorage() {
|
||||
for (const key in localStorage) {
|
||||
if (!LOCAL_STORAGE_KEYS_ALLOWLIST.includes(key)) {
|
||||
localStorage.removeItem(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
169
packages/ui-patterns/AuthenticatedDropdownMenu/index.tsx
Normal file
169
packages/ui-patterns/AuthenticatedDropdownMenu/index.tsx
Normal file
@@ -0,0 +1,169 @@
|
||||
'use client'
|
||||
|
||||
import { Fragment } from 'react'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { UserIcon } from 'lucide-react'
|
||||
import {
|
||||
cn,
|
||||
buttonVariants,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuTrigger,
|
||||
} from 'ui'
|
||||
import { themes } from 'ui/src/components/ThemeProvider/themes'
|
||||
|
||||
import type { User } from '@supabase/supabase-js'
|
||||
import type { LucideIcon } from 'icons/src/createSupabaseIcon'
|
||||
import type { Theme } from 'ui/src/components/ThemeProvider/themes'
|
||||
|
||||
interface Props {
|
||||
menu: menuItem[][]
|
||||
user: User | null
|
||||
hasThemeSelector?: boolean
|
||||
site?: 'docs' | 'www' | 'studio'
|
||||
}
|
||||
|
||||
export interface menuItem {
|
||||
label: string
|
||||
type?: 'link' | 'button' | 'text' | 'theme'
|
||||
icon?: LucideIcon
|
||||
href?: string
|
||||
shortcut?: string
|
||||
onClick?: VoidFunction
|
||||
otherProps?: {
|
||||
target?: '_blank'
|
||||
rel?: 'noreferrer noopener'
|
||||
}
|
||||
}
|
||||
|
||||
export const AuthenticatedDropdownMenu = ({ user, menu, site }: Props) => {
|
||||
const { theme, setTheme } = useTheme()
|
||||
const userAvatar = user && user.user_metadata?.avatar_url
|
||||
|
||||
return (
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild className="flex">
|
||||
<button
|
||||
title="Menu dropdown button"
|
||||
className={cn(
|
||||
buttonVariants({ type: 'default' }),
|
||||
'text-foreground-light border-default w-[30px] min-w-[30px] h-[30px] data-[state=open]:bg-overlay-hover/30 hover:border-strong data-[state=open]:border-stronger hover:!bg-overlay-hover/50 bg-transparent',
|
||||
'rounded-full overflow-hidden opacity-0 transition-opacity animate-fade-in'
|
||||
)}
|
||||
>
|
||||
{userAvatar ? (
|
||||
<Image
|
||||
src={userAvatar}
|
||||
alt={user?.email ?? ''}
|
||||
placeholder="blur"
|
||||
blurDataURL="/images/blur.png"
|
||||
fill
|
||||
sizes="30px"
|
||||
className="object-cover object-center"
|
||||
/>
|
||||
) : (
|
||||
<UserIcon size={16} strokeWidth={1.5} />
|
||||
)}
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="bottom" align="end" className="w-52">
|
||||
{menu.map((menuSection, sectionIdx) => (
|
||||
<Fragment key={`${site}-auth-dropdown--${sectionIdx}`}>
|
||||
{sectionIdx !== 0 && (
|
||||
<DropdownMenuSeparator key={`${site}-auth-dropdown--${sectionIdx}`} />
|
||||
)}
|
||||
{menuSection.map((sectionItem, itemIdx) => {
|
||||
switch (sectionItem.type) {
|
||||
case 'text':
|
||||
return (
|
||||
<div
|
||||
key={`${site}-auth-dropdown-${sectionItem.label}-${sectionIdx}-${itemIdx}`}
|
||||
className="flex cursor-text items-center text-foreground rounded-sm px-2 py-1.5 text-xs outline-none space-x-2"
|
||||
{...sectionItem.otherProps}
|
||||
>
|
||||
<DropdownItemContent {...sectionItem} />
|
||||
</div>
|
||||
)
|
||||
case 'button':
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={`${site}-auth-dropdown-${sectionItem.label}-${sectionIdx}-${itemIdx}`}
|
||||
className="space-x-2 hover:cursor-pointer"
|
||||
onClick={sectionItem.onClick!}
|
||||
{...sectionItem.otherProps}
|
||||
>
|
||||
<DropdownItemContent {...sectionItem} />
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
case 'theme':
|
||||
return (
|
||||
<>
|
||||
<DropdownMenuLabel
|
||||
key={`${site}-auth-dropdown-${sectionItem.label}-${sectionIdx}-${itemIdx}`}
|
||||
>
|
||||
{sectionItem.label}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuRadioGroup
|
||||
value={theme}
|
||||
onValueChange={(value) => {
|
||||
setTheme(value)
|
||||
}}
|
||||
>
|
||||
{themes
|
||||
.filter(
|
||||
(x) => x.value === 'light' || x.value === 'dark' || x.value === 'system'
|
||||
)
|
||||
.map((theme: Theme) => (
|
||||
<DropdownMenuRadioItem
|
||||
key={`${site}-auth-dropdown-theme-${theme.value}`}
|
||||
value={theme.value}
|
||||
className="hover:cursor-pointer"
|
||||
>
|
||||
{theme.name}
|
||||
</DropdownMenuRadioItem>
|
||||
))}
|
||||
</DropdownMenuRadioGroup>
|
||||
</>
|
||||
)
|
||||
case 'link':
|
||||
default:
|
||||
return (
|
||||
<Link
|
||||
key={`${site}-auth-dropdown-${sectionItem.label}-${sectionIdx}-${itemIdx}`}
|
||||
href={sectionItem.href!}
|
||||
{...sectionItem.otherProps}
|
||||
>
|
||||
<DropdownMenuItem
|
||||
className="space-x-2 hover:cursor-pointer"
|
||||
onClick={() => {}}
|
||||
>
|
||||
<DropdownItemContent {...sectionItem} />
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
})}
|
||||
</Fragment>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
|
||||
const DropdownItemContent = ({ icon: Icon, ...sectionItem }: menuItem) => (
|
||||
<>
|
||||
{Icon && <Icon className="w-3 h-3" />}
|
||||
<span className="grow truncate">{sectionItem.label}</span>
|
||||
{sectionItem.shortcut && <DropdownMenuShortcut>{sectionItem.shortcut}</DropdownMenuShortcut>}
|
||||
</>
|
||||
)
|
||||
|
||||
export default AuthenticatedDropdownMenu
|
||||
@@ -2,26 +2,28 @@
|
||||
* The components are listed here so that VsCode can find out about them and list them as import suggestions. Don't
|
||||
* import directly from here.
|
||||
*/
|
||||
export * from './admonition'
|
||||
export * from './AssistantChat/AssistantChatForm'
|
||||
export * from './AssistantChat/AssistantCommandsPopover'
|
||||
export * from './AuthenticatedDropdownMenu'
|
||||
export * from './CommandMenu'
|
||||
export * from './ComputeBadge'
|
||||
export * from './ConsentToast'
|
||||
export * from './consent'
|
||||
export * from './CountdownWidget'
|
||||
export * from './Dialogs/ConfirmDialog'
|
||||
export * from './Dialogs/ConfirmationModal'
|
||||
export * from './ExpandableVideo'
|
||||
export * from './GlassPanel'
|
||||
export * from './IconPanel'
|
||||
export * from './InnerSideMenu'
|
||||
export * from './LogsBarChart'
|
||||
export * from './MobileSheetNav'
|
||||
export * from './PrivacySettings'
|
||||
export * from './PromoToast'
|
||||
export * from './ThemeToggle'
|
||||
export * from './TweetCard'
|
||||
export * from './InnerSideMenu'
|
||||
export * from './ShimmeringLoader'
|
||||
export * from './Dialogs/ConfirmDialog'
|
||||
export * from './Dialogs/ConfirmationModal'
|
||||
export * from './AssistantChat/AssistantChatForm'
|
||||
export * from './AssistantChat/AssistantCommandsPopover'
|
||||
export * from './PromoToast'
|
||||
export * from './admonition'
|
||||
export * from './ComputeBadge'
|
||||
export * from './TimestampInfo'
|
||||
export * from './FilterBar'
|
||||
export * from './Toc'
|
||||
export * from './LogsBarChart'
|
||||
export * from './ShimmeringLoader'
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"@hookform/resolvers": "^3.1.1",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@supabase/sql-to-rest": "^0.1.6",
|
||||
"@supabase/supabase-js": "catalog:",
|
||||
"class-variance-authority": "^0.6.0",
|
||||
"clsx": "^1.2.1",
|
||||
"cmdk": "^1.0.0",
|
||||
@@ -22,6 +23,7 @@
|
||||
"dayjs": "^1.11.13",
|
||||
"framer-motion": "^11.1.9",
|
||||
"github-slugger": "^2.0.0",
|
||||
"icons": "workspace:*",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "*",
|
||||
"mdast": "^3.0.0",
|
||||
|
||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@@ -2015,6 +2015,9 @@ importers:
|
||||
'@supabase/sql-to-rest':
|
||||
specifier: ^0.1.6
|
||||
version: 0.1.6(encoding@0.1.13)(supports-color@8.1.1)
|
||||
'@supabase/supabase-js':
|
||||
specifier: 'catalog:'
|
||||
version: 2.49.3
|
||||
class-variance-authority:
|
||||
specifier: ^0.6.0
|
||||
version: 0.6.1
|
||||
@@ -2039,6 +2042,9 @@ importers:
|
||||
github-slugger:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
icons:
|
||||
specifier: workspace:*
|
||||
version: link:../icons
|
||||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
|
||||
@@ -1,436 +0,0 @@
|
||||
export type Json =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| { [key: string]: Json | undefined }
|
||||
| Json[]
|
||||
|
||||
export interface Database {
|
||||
graphql_public: {
|
||||
Tables: {
|
||||
[_ in never]: never
|
||||
}
|
||||
Views: {
|
||||
[_ in never]: never
|
||||
}
|
||||
Functions: {
|
||||
graphql: {
|
||||
Args: {
|
||||
operationName?: string
|
||||
query?: string
|
||||
variables?: Json
|
||||
extensions?: Json
|
||||
}
|
||||
Returns: Json
|
||||
}
|
||||
}
|
||||
Enums: {
|
||||
[_ in never]: never
|
||||
}
|
||||
CompositeTypes: {
|
||||
[_ in never]: never
|
||||
}
|
||||
}
|
||||
public: {
|
||||
Tables: {
|
||||
page: {
|
||||
Row: {
|
||||
checksum: string | null
|
||||
id: number
|
||||
last_refresh: string | null
|
||||
meta: Json | null
|
||||
parent_page_id: number | null
|
||||
path: string
|
||||
source: string | null
|
||||
type: string | null
|
||||
version: string | null
|
||||
}
|
||||
Insert: {
|
||||
checksum?: string | null
|
||||
id?: number
|
||||
last_refresh?: string | null
|
||||
meta?: Json | null
|
||||
parent_page_id?: number | null
|
||||
path: string
|
||||
source?: string | null
|
||||
type?: string | null
|
||||
version?: string | null
|
||||
}
|
||||
Update: {
|
||||
checksum?: string | null
|
||||
id?: number
|
||||
last_refresh?: string | null
|
||||
meta?: Json | null
|
||||
parent_page_id?: number | null
|
||||
path?: string
|
||||
source?: string | null
|
||||
type?: string | null
|
||||
version?: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "page_parent_page_id_fkey"
|
||||
columns: ["parent_page_id"]
|
||||
referencedRelation: "page"
|
||||
referencedColumns: ["id"]
|
||||
}
|
||||
]
|
||||
}
|
||||
page_section: {
|
||||
Row: {
|
||||
content: string | null
|
||||
embedding: string | null
|
||||
fts_tokens: unknown | null
|
||||
heading: string | null
|
||||
id: number
|
||||
page_id: number
|
||||
slug: string | null
|
||||
token_count: number | null
|
||||
}
|
||||
Insert: {
|
||||
content?: string | null
|
||||
embedding?: string | null
|
||||
fts_tokens?: unknown | null
|
||||
heading?: string | null
|
||||
id?: number
|
||||
page_id: number
|
||||
slug?: string | null
|
||||
token_count?: number | null
|
||||
}
|
||||
Update: {
|
||||
content?: string | null
|
||||
embedding?: string | null
|
||||
fts_tokens?: unknown | null
|
||||
heading?: string | null
|
||||
id?: number
|
||||
page_id?: number
|
||||
slug?: string | null
|
||||
token_count?: number | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "page_section_page_id_fkey"
|
||||
columns: ["page_id"]
|
||||
referencedRelation: "page"
|
||||
referencedColumns: ["id"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Views: {
|
||||
[_ in never]: never
|
||||
}
|
||||
Functions: {
|
||||
docs_search_embeddings: {
|
||||
Args: {
|
||||
embedding: string
|
||||
match_threshold: number
|
||||
}
|
||||
Returns: {
|
||||
id: number
|
||||
path: string
|
||||
type: string
|
||||
title: string
|
||||
subtitle: string
|
||||
description: string
|
||||
headings: string[]
|
||||
slugs: string[]
|
||||
}[]
|
||||
}
|
||||
docs_search_fts: {
|
||||
Args: {
|
||||
query: string
|
||||
}
|
||||
Returns: {
|
||||
id: number
|
||||
path: string
|
||||
type: string
|
||||
title: string
|
||||
subtitle: string
|
||||
description: string
|
||||
headings: string[]
|
||||
slugs: string[]
|
||||
}[]
|
||||
}
|
||||
get_page_parents: {
|
||||
Args: {
|
||||
page_id: number
|
||||
}
|
||||
Returns: {
|
||||
id: number
|
||||
parent_page_id: number
|
||||
path: string
|
||||
meta: Json
|
||||
}[]
|
||||
}
|
||||
hnswhandler: {
|
||||
Args: {
|
||||
"": unknown
|
||||
}
|
||||
Returns: unknown
|
||||
}
|
||||
ivfflathandler: {
|
||||
Args: {
|
||||
"": unknown
|
||||
}
|
||||
Returns: unknown
|
||||
}
|
||||
match_page_sections: {
|
||||
Args: {
|
||||
embedding: string
|
||||
match_threshold: number
|
||||
match_count: number
|
||||
min_content_length: number
|
||||
}
|
||||
Returns: {
|
||||
id: number
|
||||
page_id: number
|
||||
slug: string
|
||||
heading: string
|
||||
content: string
|
||||
similarity: number
|
||||
}[]
|
||||
}
|
||||
match_page_sections_v2: {
|
||||
Args: {
|
||||
embedding: string
|
||||
match_threshold: number
|
||||
min_content_length: number
|
||||
}
|
||||
Returns: {
|
||||
content: string | null
|
||||
embedding: string | null
|
||||
fts_tokens: unknown | null
|
||||
heading: string | null
|
||||
id: number
|
||||
page_id: number
|
||||
slug: string | null
|
||||
token_count: number | null
|
||||
}[]
|
||||
}
|
||||
vector_avg: {
|
||||
Args: {
|
||||
"": number[]
|
||||
}
|
||||
Returns: string
|
||||
}
|
||||
vector_dims: {
|
||||
Args: {
|
||||
"": string
|
||||
}
|
||||
Returns: number
|
||||
}
|
||||
vector_norm: {
|
||||
Args: {
|
||||
"": string
|
||||
}
|
||||
Returns: number
|
||||
}
|
||||
vector_out: {
|
||||
Args: {
|
||||
"": string
|
||||
}
|
||||
Returns: unknown
|
||||
}
|
||||
vector_send: {
|
||||
Args: {
|
||||
"": string
|
||||
}
|
||||
Returns: string
|
||||
}
|
||||
vector_typmod_in: {
|
||||
Args: {
|
||||
"": unknown[]
|
||||
}
|
||||
Returns: number
|
||||
}
|
||||
}
|
||||
Enums: {
|
||||
[_ in never]: never
|
||||
}
|
||||
CompositeTypes: {
|
||||
[_ in never]: never
|
||||
}
|
||||
}
|
||||
storage: {
|
||||
Tables: {
|
||||
buckets: {
|
||||
Row: {
|
||||
allowed_mime_types: string[] | null
|
||||
avif_autodetection: boolean | null
|
||||
created_at: string | null
|
||||
file_size_limit: number | null
|
||||
id: string
|
||||
name: string
|
||||
owner: string | null
|
||||
public: boolean | null
|
||||
updated_at: string | null
|
||||
}
|
||||
Insert: {
|
||||
allowed_mime_types?: string[] | null
|
||||
avif_autodetection?: boolean | null
|
||||
created_at?: string | null
|
||||
file_size_limit?: number | null
|
||||
id: string
|
||||
name: string
|
||||
owner?: string | null
|
||||
public?: boolean | null
|
||||
updated_at?: string | null
|
||||
}
|
||||
Update: {
|
||||
allowed_mime_types?: string[] | null
|
||||
avif_autodetection?: boolean | null
|
||||
created_at?: string | null
|
||||
file_size_limit?: number | null
|
||||
id?: string
|
||||
name?: string
|
||||
owner?: string | null
|
||||
public?: boolean | null
|
||||
updated_at?: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "buckets_owner_fkey"
|
||||
columns: ["owner"]
|
||||
referencedRelation: "users"
|
||||
referencedColumns: ["id"]
|
||||
}
|
||||
]
|
||||
}
|
||||
migrations: {
|
||||
Row: {
|
||||
executed_at: string | null
|
||||
hash: string
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
Insert: {
|
||||
executed_at?: string | null
|
||||
hash: string
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
Update: {
|
||||
executed_at?: string | null
|
||||
hash?: string
|
||||
id?: number
|
||||
name?: string
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
objects: {
|
||||
Row: {
|
||||
bucket_id: string | null
|
||||
created_at: string | null
|
||||
id: string
|
||||
last_accessed_at: string | null
|
||||
metadata: Json | null
|
||||
name: string | null
|
||||
owner: string | null
|
||||
path_tokens: string[] | null
|
||||
updated_at: string | null
|
||||
version: string | null
|
||||
}
|
||||
Insert: {
|
||||
bucket_id?: string | null
|
||||
created_at?: string | null
|
||||
id?: string
|
||||
last_accessed_at?: string | null
|
||||
metadata?: Json | null
|
||||
name?: string | null
|
||||
owner?: string | null
|
||||
path_tokens?: string[] | null
|
||||
updated_at?: string | null
|
||||
version?: string | null
|
||||
}
|
||||
Update: {
|
||||
bucket_id?: string | null
|
||||
created_at?: string | null
|
||||
id?: string
|
||||
last_accessed_at?: string | null
|
||||
metadata?: Json | null
|
||||
name?: string | null
|
||||
owner?: string | null
|
||||
path_tokens?: string[] | null
|
||||
updated_at?: string | null
|
||||
version?: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "objects_bucketId_fkey"
|
||||
columns: ["bucket_id"]
|
||||
referencedRelation: "buckets"
|
||||
referencedColumns: ["id"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Views: {
|
||||
[_ in never]: never
|
||||
}
|
||||
Functions: {
|
||||
can_insert_object: {
|
||||
Args: {
|
||||
bucketid: string
|
||||
name: string
|
||||
owner: string
|
||||
metadata: Json
|
||||
}
|
||||
Returns: undefined
|
||||
}
|
||||
extension: {
|
||||
Args: {
|
||||
name: string
|
||||
}
|
||||
Returns: string
|
||||
}
|
||||
filename: {
|
||||
Args: {
|
||||
name: string
|
||||
}
|
||||
Returns: string
|
||||
}
|
||||
foldername: {
|
||||
Args: {
|
||||
name: string
|
||||
}
|
||||
Returns: unknown
|
||||
}
|
||||
get_size_by_bucket: {
|
||||
Args: Record<PropertyKey, never>
|
||||
Returns: {
|
||||
size: number
|
||||
bucket_id: string
|
||||
}[]
|
||||
}
|
||||
search: {
|
||||
Args: {
|
||||
prefix: string
|
||||
bucketname: string
|
||||
limits?: number
|
||||
levels?: number
|
||||
offsets?: number
|
||||
search?: string
|
||||
sortcolumn?: string
|
||||
sortorder?: string
|
||||
}
|
||||
Returns: {
|
||||
name: string
|
||||
id: string
|
||||
updated_at: string
|
||||
created_at: string
|
||||
last_accessed_at: string
|
||||
metadata: Json
|
||||
}[]
|
||||
}
|
||||
}
|
||||
Enums: {
|
||||
[_ in never]: never
|
||||
}
|
||||
CompositeTypes: {
|
||||
[_ in never]: never
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user