From e76f0d806695d2df1f16e9527a021e97d650fced Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Wed, 18 Dec 2024 19:18:00 +0800 Subject: [PATCH] moar --- .../interfaces/App/AppBannerWrapper.tsx | 21 +- .../Functions/TerminalInstructions.tsx | 2 +- .../interfaces/Linter/LintPageTabs.tsx | 24 +- .../Storage/storage-bucket-list.tsx | 431 ++++++++++++++++++ .../interfaces/app-default-navigation.tsx | 403 +++++++++------- .../interfaces/sidebar-open-top-banner.tsx | 62 ++- .../layouts/AdvisorsLayout/AdvisorsLayout.tsx | 4 +- .../AdvisorsLayout/AdvisorsLayout.utils.tsx | 28 ++ .../layouts/AppLayout/IncidentBanner.tsx | 6 +- .../layouts/AppLayout/NoticeBanner.tsx | 5 +- .../AppLayout/OrganizationDropdown.tsx | 7 +- .../layouts/AppLayout/ProjectDropdown.tsx | 1 + .../AuthLayout/ProjectPageNavigation.tsx | 5 + .../components/layouts/DefaultLayout.tsx | 28 +- .../FunctionsLayout/FunctionsLayout.utils.tsx | 51 +++ .../components/layouts/OrganizationLayout.tsx | 43 +- .../layouts/ProjectLayout/ProjectLayout.tsx | 8 +- .../layouts/RealtimeLayout/RealtimeLayout.tsx | 2 +- .../layouts/StorageLayout/StorageLayout.tsx | 6 +- .../ui/ProductMenu/ProductMenu.types.ts | 1 + apps/studio/lib/constants/index.ts | 1 + apps/studio/pages/_app.tsx | 22 +- .../project/[ref]/advisors/performance.tsx | 14 +- .../[ref]/advisors/query-performance.tsx | 12 +- .../pages/project/[ref]/advisors/security.tsx | 14 +- .../pages/project/[ref]/functions/index.tsx | 10 +- .../project/[ref]/realtime/inspector.tsx | 8 +- .../project/[ref]/storage/buckets/index.tsx | 35 +- .../ui/src/components/shadcn/ui/sidebar.tsx | 7 +- 29 files changed, 970 insertions(+), 291 deletions(-) create mode 100644 apps/studio/components/interfaces/Storage/storage-bucket-list.tsx create mode 100644 apps/studio/components/layouts/AdvisorsLayout/AdvisorsLayout.utils.tsx create mode 100644 apps/studio/components/layouts/FunctionsLayout/FunctionsLayout.utils.tsx diff --git a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx index 7a19a898f9a..edbc66a683a 100644 --- a/apps/studio/components/interfaces/App/AppBannerWrapper.tsx +++ b/apps/studio/components/interfaces/App/AppBannerWrapper.tsx @@ -27,10 +27,23 @@ const AppBannerWrapper = ({ children }: PropsWithChildren<{}>) => { }, [resolvedTheme, monaco]) return ( -
-
- {ongoingIncident && } - {showNoticeBanner && } +
+
+ { + // ongoingIncident + true && ( + // + + ) + } + {/* { + //showNoticeBanner + // + true && ( + // + + ) + } */} {profile !== undefined && }
{children} diff --git a/apps/studio/components/interfaces/Functions/TerminalInstructions.tsx b/apps/studio/components/interfaces/Functions/TerminalInstructions.tsx index 6c49a15927b..e7ce6e3e843 100644 --- a/apps/studio/components/interfaces/Functions/TerminalInstructions.tsx +++ b/apps/studio/components/interfaces/Functions/TerminalInstructions.tsx @@ -45,7 +45,7 @@ const TerminalInstructions = forwardRef< // get the .co or .net TLD from the restUrl const restUrl = `https://${endpoint}` - const restUrlTld = restUrl ? new URL(restUrl).hostname.split('.').pop() : 'co' + const restUrlTld = restUrl ? new URL(restUrl).hostname?.split('.').pop() : 'co' const commands: Commands[] = [ { diff --git a/apps/studio/components/interfaces/Linter/LintPageTabs.tsx b/apps/studio/components/interfaces/Linter/LintPageTabs.tsx index 7eca6b04290..89f8e8b687c 100644 --- a/apps/studio/components/interfaces/Linter/LintPageTabs.tsx +++ b/apps/studio/components/interfaces/Linter/LintPageTabs.tsx @@ -71,6 +71,7 @@ const LintPageTabs = ({ return ( { setCurrentTab(value as LINTER_LEVELS) setSelectedLint(null) @@ -78,15 +79,14 @@ const LintPageTabs = ({ router.push({ ...router, query: { ...rest, preset: value, id: null } }) }} > - + {LINT_TABS.map((tab) => ( - {tab.id === currentTab && ( + {/* {tab.id === currentTab && (
- )} + )} */}
{tab.label} - - - - - {tab.description} -
+ + + + + {tab.description} + ))} diff --git a/apps/studio/components/interfaces/Storage/storage-bucket-list.tsx b/apps/studio/components/interfaces/Storage/storage-bucket-list.tsx new file mode 100644 index 00000000000..ad2ea370a61 --- /dev/null +++ b/apps/studio/components/interfaces/Storage/storage-bucket-list.tsx @@ -0,0 +1,431 @@ +import AwesomeDebouncePromise from 'awesome-debounce-promise' +import { Archive, ArrowDown, ArrowUp, Loader2, RefreshCw, Search, X } from 'lucide-react' +import { UIEvent, useEffect, useMemo, useRef, useState } from 'react' +import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid' +import { useParams } from 'common' +import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' +import AlertError from 'components/ui/AlertError' +import APIDocsButton from 'components/ui/APIDocsButton' +import { FilterPopover } from 'components/ui/FilterPopover' +import { FormHeader } from 'components/ui/Forms/FormHeader' +import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' +import { LOCAL_STORAGE_KEYS } from 'lib/constants' +import { + Button, + cn, + DropdownMenu, + DropdownMenuContent, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, + LoadingLine, + ResizablePanel, + ResizablePanelGroup, + Select_Shadcn_, + SelectContent_Shadcn_, + SelectGroup_Shadcn_, + SelectItem_Shadcn_, + SelectTrigger_Shadcn_, + SelectValue_Shadcn_, +} from 'ui' +import { Input } from 'ui-patterns/DataInputs/Input' +import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' +import { useBucketsQuery } from 'data/storage/buckets-query' +import type { StorageBucket } from 'components/interfaces/Storage/Storage.types' +import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' +import { PermissionAction } from '@supabase/shared-types/out/constants' +import CreateBucketModal from './CreateBucketModal' +import { formatBytes } from 'lib/helpers' +import Link from 'next/link' + +type Filter = 'all' | 'public' | 'private' +export type BucketsTableColumn = { + id: string + name: string + minWidth?: number + width?: number + resizable?: boolean +} +export type ColumnConfiguration = { id: string; width?: number } +export const BUCKETS_TABLE_COLUMNS: BucketsTableColumn[] = [ + { id: 'name', name: 'Name', width: 280 }, + { id: 'public', name: 'Public', width: 100 }, + { id: 'created_at', name: 'Created at', width: 260 }, + { id: 'file_count', name: 'Files', width: 100 }, + { id: 'size', name: 'Size', width: 100 }, + { id: 'owner', name: 'Owner', width: 200 }, +] + +// [Joshen] Just naming it as V2 as its a rewrite of the old one, to make it easier for reviews +// Can change it to remove V2 thereafter +export const StorageBucketList = () => { + const { ref } = useParams() + const { project } = useProjectContext() + const gridRef = useRef(null) + const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() + const canCreateBuckets = useCheckPermissions(PermissionAction.STORAGE_WRITE, '*') + + const [columns, setColumns] = useState[]>([]) + const [search, setSearch] = useState('') + const [filter, setFilter] = useState('all') + const [filterKeywords, setFilterKeywords] = useState('') + const [selectedColumns, setSelectedColumns] = useState([]) + const [selectedRow, setSelectedRow] = useState() + const [sortByValue, setSortByValue] = useState('created_at:desc') + const [columnConfiguration, setColumnConfiguration] = useLocalStorageQuery( + LOCAL_STORAGE_KEYS.STORAGE_BUCKETS_COLUMN_CONFIG(ref ?? ''), + null as ColumnConfiguration[] | null + ) + const [showCreateBucketModal, setShowCreateBucketModal] = useState(false) + + const [sortColumn, sortOrder] = sortByValue.split(':') + + const { data, error, isLoading, isError, isSuccess, isRefetching, refetch } = useBucketsQuery({ + projectRef: ref, + }) + + const buckets = data ?? [] + const sortedBuckets = + sortColumn === 'name' + ? buckets.sort( + (a, b) => + (sortOrder === 'asc' ? 1 : -1) * + a.name.toLowerCase().trim().localeCompare(b.name.toLowerCase().trim()) + ) + : buckets.sort( + (a, b) => + (sortOrder === 'asc' ? 1 : -1) * + (new Date(b.created_at) > new Date(a.created_at) ? -1 : 1) + ) + + const filteredBuckets = + filterKeywords.length > 1 + ? sortedBuckets.filter((bucket) => + bucket.name.toLowerCase().includes(filterKeywords.toLowerCase().trim()) + ) + : sortedBuckets + + const handleScroll = (event: UIEvent) => { + // if (isLoading || !isAtBottom(event)) return + // refetch() + } + + const clearSearch = () => { + setSearch('') + setFilterKeywords('') + } + + const swapColumns = (data: any[], sourceIdx: number, targetIdx: number) => { + const updatedColumns = data.slice() + const [removed] = updatedColumns.splice(sourceIdx, 1) + updatedColumns.splice(targetIdx, 0, removed) + return updatedColumns + } + + // [Joshen] Left off here - it's tricky trying to do both column toggling and re-ordering + const saveColumnConfiguration = AwesomeDebouncePromise( + (event: 'resize' | 'reorder' | 'toggle', value) => { + if (event === 'toggle') { + const columnConfig = value.columns.map((col: any) => ({ + id: col.key, + width: col.width, + })) + setColumnConfiguration(columnConfig) + } else if (event === 'resize') { + const columnConfig = columns.map((col, idx) => ({ + id: col.key, + width: idx === value.idx ? value.width : col.width, + })) + setColumnConfiguration(columnConfig) + } else if (event === 'reorder') { + const columnConfig = value.columns.map((col: any) => ({ + id: col.key, + width: col.width, + })) + setColumnConfiguration(columnConfig) + } + }, + 500 + ) + + useEffect(() => { + if (!isRefetching) { + const columns = formatBucketColumns({ + config: columnConfiguration ?? [], + buckets: buckets ?? [], + visibleColumns: selectedColumns, + setSortByValue, + sortByValue, + ref, + }) + setColumns(columns) + if (columns.length < BUCKETS_TABLE_COLUMNS.length) { + setSelectedColumns(columns.map((col) => col.key)) + } + } + }, [isSuccess, isRefetching, buckets, columnConfiguration, selectedColumns, sortByValue]) + + return ( +
+
+
+ } + placeholder="Search bucket name" + value={search} + onChange={(e) => setSearch(e.target.value)} + onKeyDown={(e) => { + if (e.code === 'Enter') { + setSearch(search.trim()) + setFilterKeywords(search.trim().toLocaleLowerCase()) + } + }} + actions={[ + search && ( + + + + + + Sort by name + + Ascending + Descending + + + + Sort by created at + + Ascending + + Descending + + + + + + +
+ +
+ {isNewAPIDocsEnabled && } + + +
+
+ + + + +
+ { + const isSelected = idx === selectedRow + return [ + `${isSelected ? 'bg-surface-300 dark:bg-surface-300' : 'bg-200'} cursor-pointer`, + '[&>.rdg-cell]:border-box [&>.rdg-cell]:outline-none [&>.rdg-cell]:shadow-none', + '[&>.rdg-cell:first-child>div]:ml-4', + ].join(' ') + }} + renderers={{ + noRowsFallback: isLoading ? ( +
+ +
+ ) : isError ? ( +
+ +
+ ) : ( +
+ +
+

+ {filter !== 'all' || filterKeywords.length > 0 + ? 'No buckets found' + : 'No buckets in your project'} +

+

+ {filter !== 'all' || filterKeywords.length > 0 + ? 'There are currently no buckets based on the filters applied' + : 'There are currently no buckets in your project'} +

+
+
+ ), + }} + /> +
+
+
+ +
+ {isLoading || isRefetching + ? 'Loading buckets...' + : `Total: ${filteredBuckets.length} buckets`} + {(isLoading || isRefetching) && ( + + Loading... + + )} +
+ + setShowCreateBucketModal(false)} + /> +
+ ) +} + +const formatBucketColumns = ({ + config, + buckets, + visibleColumns, + setSortByValue, + sortByValue, + ref, +}: { + config: ColumnConfiguration[] + buckets: StorageBucket[] + visibleColumns: string[] + setSortByValue: (value: string) => void + sortByValue: string + ref +}) => { + const columnOrder = config.map((c) => c.id) ?? BUCKETS_TABLE_COLUMNS.map((c) => c.id) + + let gridColumns = BUCKETS_TABLE_COLUMNS.map((col) => { + const savedConfig = config.find((c) => c.id === col.id) + + return { + key: col.id, + name: col.name, + resizable: col.resizable ?? true, + sortable: ['name', 'created_at'].includes(col.id), + draggable: true, + width: savedConfig?.width ?? col.width, + minWidth: col.minWidth ?? 120, + headerCellClass: 'z-50 outline-none !shadow-none', + onSort: () => { + if (col.id === 'name' || col.id === 'created_at') { + const order = sortByValue === `${col.id}:asc` ? 'desc' : 'asc' + setSortByValue(`${col.id}:${order}`) + } + }, + renderHeaderCell: () => { + const icon = sortByValue.includes(col.id) ? ( + sortByValue.includes('asc') ? ( + + ) : ( + + ) + ) : null + + return ( +
+ {col.name} + {icon &&
{icon}
} +
+ ) + }, + renderCell: ({ row }) => { + switch (col.id) { + case 'name': + return ( + + {row.name} + + ) + case 'public': + return row.public ? 'Public' : 'Private' + case 'created_at': + return new Date(row.created_at).toLocaleString() + case 'file_count': + return row.file_count ?? 0 + case 'size': + return formatBytes(row.size ?? 0) + case 'owner': + return row.owner ?? '-' + default: + return row[col.id] + } + }, + } + }) + + if (columnOrder.length > 0) { + gridColumns = gridColumns + .filter((col) => columnOrder.includes(col.key)) + .sort((a: any, b: any) => columnOrder.indexOf(a.key) - columnOrder.indexOf(b.key)) + } + + return visibleColumns.length === 0 + ? gridColumns + : gridColumns.filter((col) => visibleColumns.includes(col.key)) +} diff --git a/apps/studio/components/interfaces/app-default-navigation.tsx b/apps/studio/components/interfaces/app-default-navigation.tsx index b053ec3cf94..353a4306563 100644 --- a/apps/studio/components/interfaces/app-default-navigation.tsx +++ b/apps/studio/components/interfaces/app-default-navigation.tsx @@ -21,6 +21,7 @@ import { useRouter } from 'next/router' import { useMemo, useState } from 'react' import { Button, + cn, Collapsible_Shadcn_, CollapsibleContent_Shadcn_, CollapsibleTrigger_Shadcn_, @@ -28,6 +29,8 @@ import { Sidebar, SidebarContent, SidebarFooter, + SidebarGroup, + SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, @@ -39,7 +42,15 @@ import { } from 'ui' import { AppDefaultNavigationUsageBanner } from './app-default-navigation-usage-banner' import { useSelectedProject } from 'hooks/misc/useSelectedProject' -import { Blocks, Boxes, ChevronDown, ChevronRight, CornerLeftUp, SidebarClose } from 'lucide-react' +import { + Blocks, + Boxes, + ChevronDown, + ChevronLeft, + ChevronRight, + CornerLeftUp, + SidebarClose, +} from 'lucide-react' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import Connect from './Connect/Connect' import { useFlag } from 'hooks/ui/useFlag' @@ -49,6 +60,8 @@ import { UserDropdown } from './user-dropdown' export const ICON_SIZE = 18 export const ICON_STROKE_WIDTH = 1.5 +const SidebarMotion = motion(Sidebar) + export function AppDefaultNavigation() { // Function logic goes here const router = useRouter() @@ -68,23 +81,35 @@ export function AppDefaultNavigation() { return ( <> - - -
- {!isProjects && } - - {isProjects && ( - -
+ + + {open && ( + +
+ {!isProjects && } + + {isProjects && open && ( + + {/*
-
- +
*/} + + + )} +
+ {/* */} + + {ref && open && ( + + + + {selectedProject && isBranchingEnabled && ( + <> + + + )} + + )} + +
+ + )} + + + {isProjects ? ( + + + + ) : ( + + )} - - {/* */} + +
+ + + + {ref && ( - - - {selectedProject && isBranchingEnabled && ( - <> - - - )} + {!isBranchingEnabled && } + + )} + {connectDialogUpdate && ref && ( + +
+ +
)}
-
-
- - - {isProjects ? ( - - - - ) : ( - - - - )} - - - - - - {ref && ( - - {!isBranchingEnabled && } - - )} - {connectDialogUpdate && ref && ( - -
- -
-
- )} -
- -
-
+ + + + ) } @@ -205,23 +243,24 @@ function NavLink({ route, active }: { route: any; active?: boolean }) { // console.log('route', route) - if (!route.items) { - return ( - - - - {route.icon} - {route.label} - - - - ) - } + // if (!route.items) { + return ( + + + + {route.icon} + {route.label} + + + + ) + // } return ( @@ -271,6 +310,7 @@ function ProjectLinks() { const router = useRouter() const { ref } = useParams() const { project } = useProjectContext() + const { open } = useSidebar() const activeRoute = router.pathname.split('/')[3] @@ -300,45 +340,57 @@ function ProjectLinks() { return ( - , - link: `/project/${ref}`, - linkElement: , - }} - /> - {toolRoutes.map((route, i) => ( - - ))} - - - products - - {productRoutes.map((route, i) => ( - - ))} - - - develop - - {otherRoutes.map((route, i) => ( - - ))} - {settingsRoutes.map((route, i) => ( - - ))} + + , + link: `/project/${ref}`, + linkElement: , + }} + /> + {toolRoutes.map((route, i) => ( + + ))} + + {/* */} + + + products + + {productRoutes.map((route, i) => ( + + ))} + + {/* */} + + + develop + + {otherRoutes.map((route, i) => ( + + ))} + + + {settingsRoutes.map((route, i) => ( + + ))} + ) } const OrganizationLinks = () => { const router = useRouter() - const activeRoute = router.pathname.split('/')[3] const { slug } = useParams() + const { open } = useSidebar() + + const activeRoute = router.pathname.split('/')[3] const navMenuItems = [ { @@ -404,24 +456,25 @@ const OrganizationLinks = () => { }, ] - // const filteredNavMenuItems = navMenuItems.filter((item) => !item.hidden) - - // console.log(activeRoute) - return ( -
    - {navMenuItems.map((item) => ( - - ))} -
+ + + {navMenuItems.map((item, i) => ( + + + + ))} + + ) } diff --git a/apps/studio/components/interfaces/sidebar-open-top-banner.tsx b/apps/studio/components/interfaces/sidebar-open-top-banner.tsx index 2ec45614e33..c294952083c 100644 --- a/apps/studio/components/interfaces/sidebar-open-top-banner.tsx +++ b/apps/studio/components/interfaces/sidebar-open-top-banner.tsx @@ -1,14 +1,24 @@ import { AnimatePresence, motion } from 'framer-motion' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { useSelectedProject } from 'hooks/misc/useSelectedProject' -import { Box, Boxes } from 'lucide-react' +import { Box, Boxes, CornerLeftUp } from 'lucide-react' import { useSidebar } from 'ui' import { SidebarOpenButton } from './sidebar-open-button' +import { useRouter } from 'next/router' +import OrganizationDropdown from 'components/layouts/AppLayout/OrganizationDropdown' +import ProjectDropdown from 'components/layouts/AppLayout/ProjectDropdown' +import { FeedbackDropdown } from 'components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown' +import NotificationsPopoverV2 from 'components/layouts/ProjectLayout/LayoutHeader/NotificationsPopoverV2/NotificationsPopover' +import HelpPopover from 'components/layouts/ProjectLayout/LayoutHeader/HelpPopover' +import { UserDropdown } from './user-dropdown' +import { IS_PLATFORM } from 'lib/constants' export function SidebarOpenTopBanner() { const { state, setOpen, open } = useSidebar() + const router = useRouter() const project = useSelectedProject() const org = useSelectedOrganization() + return ( {state === 'collapsed' && ( @@ -26,18 +36,50 @@ export function SidebarOpenTopBanner() { height: 0, transition: { duration: 0.05 }, }} - className="relative items-center flex w-full h-5 mt-0.5 gap-5 px-0.5" + style={{ + paddingLeft: open ? '16px' : '8px', + paddingRight: open ? '16px' : '8px', + }} + className="relative items-center flex w-full gap-5 pt-[6px] pb-[1px]" > -
- + {/* */} + + {project && ( + router.push(`/org/${org?.slug}`)} + className="group/org-back-button text-foreground-lighter flex items-center gap-1 hover:text-foreground text-xs cursor-pointer" + initial={{ opacity: 0, x: -20, width: 0 }} + animate={{ opacity: 1, x: 0, width: 'auto' }} + exit={{ opacity: 0, x: 20, width: 0 }} + transition={{ duration: 0.2 }} + > + + Organization + + )} + +
+ + {/* + {org?.name} */} +
+ {project && (
- - {org?.name} -
-
- - {project?.name} +
+ )} +
+ {IS_PLATFORM && ( + <> + + + + + )}
)} diff --git a/apps/studio/components/layouts/AdvisorsLayout/AdvisorsLayout.tsx b/apps/studio/components/layouts/AdvisorsLayout/AdvisorsLayout.tsx index 70724989d05..4c6bbf820c8 100644 --- a/apps/studio/components/layouts/AdvisorsLayout/AdvisorsLayout.tsx +++ b/apps/studio/components/layouts/AdvisorsLayout/AdvisorsLayout.tsx @@ -6,6 +6,7 @@ import { useSelectedProject } from 'hooks/misc/useSelectedProject' import { withAuth } from 'hooks/misc/withAuth' import ProjectLayout from '../ProjectLayout/ProjectLayout' import { generateAdvisorsMenu } from './AdvisorsMenu.utils' +import { ProjectPageNavigation } from '../AuthLayout/ProjectPageNavigation' export interface AdvisorsLayoutProps { title?: string @@ -21,8 +22,9 @@ const AdvisorsLayout = ({ children }: PropsWithChildren) => } + // productMenu={} > + {children} {children} ) diff --git a/apps/studio/components/layouts/AdvisorsLayout/AdvisorsLayout.utils.tsx b/apps/studio/components/layouts/AdvisorsLayout/AdvisorsLayout.utils.tsx new file mode 100644 index 00000000000..ed78453d6b3 --- /dev/null +++ b/apps/studio/components/layouts/AdvisorsLayout/AdvisorsLayout.utils.tsx @@ -0,0 +1,28 @@ +import type { ProductMenuGroupItem } from 'components/ui/ProductMenu/ProductMenu.types' + +export const generateAdvisorsPageItemsMenu = ( + ref: string, + flags?: { + pgNetExtensionExists: boolean + pitrEnabled: boolean + columnLevelPrivileges: boolean + } +): ProductMenuGroupItem[] => { + return [ + { + name: 'Security', + key: 'security', + url: `/project/${ref}/advisors/security`, + }, + { + name: 'Performance', + key: 'performance', + url: `/project/${ref}/advisors/performance`, + }, + { + name: 'Query', + key: 'query', + url: `/project/${ref}/advisors/query-performance`, + }, + ] +} diff --git a/apps/studio/components/layouts/AppLayout/IncidentBanner.tsx b/apps/studio/components/layouts/AppLayout/IncidentBanner.tsx index d2fd5030540..b5ff7738287 100644 --- a/apps/studio/components/layouts/AppLayout/IncidentBanner.tsx +++ b/apps/studio/components/layouts/AppLayout/IncidentBanner.tsx @@ -4,11 +4,11 @@ import Link from 'next/link' const IncidentBanner = () => { return ( -
-

+

+

We are currently investigating a technical issue, follow status.supabase.com for updates

- +
) diff --git a/apps/studio/components/layouts/AppLayout/NoticeBanner.tsx b/apps/studio/components/layouts/AppLayout/NoticeBanner.tsx index 462350ab40c..faf0380755b 100644 --- a/apps/studio/components/layouts/AppLayout/NoticeBanner.tsx +++ b/apps/studio/components/layouts/AppLayout/NoticeBanner.tsx @@ -43,10 +43,7 @@ export const NoticeBanner = () => { } return ( -
+

Action required: Set up a custom SMTP provider, further restrictions will be imposed for the default email provider diff --git a/apps/studio/components/layouts/AppLayout/OrganizationDropdown.tsx b/apps/studio/components/layouts/AppLayout/OrganizationDropdown.tsx index 75636426743..481fa144163 100644 --- a/apps/studio/components/layouts/AppLayout/OrganizationDropdown.tsx +++ b/apps/studio/components/layouts/AppLayout/OrganizationDropdown.tsx @@ -46,7 +46,12 @@ const OrganizationDropdown = () => {

- - - - )} - - {children} + {selectedOrganization && selectedOrganization?.managed_by !== 'supabase' && ( + + + + + This organization is managed by {PARTNER_TO_NAME[selectedOrganization.managed_by]}. + + + + + )} +
{children}
+
) } diff --git a/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx b/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx index 4c0a7250683..069968f4271 100644 --- a/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx +++ b/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx @@ -178,14 +178,10 @@ const ProjectLayout = forwardRef} */}
- + {showProductMenu && productMenu && ( } + // productMenu={} > {children} diff --git a/apps/studio/components/layouts/StorageLayout/StorageLayout.tsx b/apps/studio/components/layouts/StorageLayout/StorageLayout.tsx index d76ee09d61e..cfdbb300ae8 100644 --- a/apps/studio/components/layouts/StorageLayout/StorageLayout.tsx +++ b/apps/studio/components/layouts/StorageLayout/StorageLayout.tsx @@ -48,7 +48,11 @@ const StorageLayout = ({ title, children }: StorageLayoutProps) => { } return ( - }> + } + > {children} ) diff --git a/apps/studio/components/ui/ProductMenu/ProductMenu.types.ts b/apps/studio/components/ui/ProductMenu/ProductMenu.types.ts index 2f8ee64eca3..79c583d0b13 100644 --- a/apps/studio/components/ui/ProductMenu/ProductMenu.types.ts +++ b/apps/studio/components/ui/ProductMenu/ProductMenu.types.ts @@ -23,4 +23,5 @@ export interface ProductMenuGroupItem { childId?: string childIcon?: ReactNode + childItems?: ProductMenuGroupItem[] } diff --git a/apps/studio/lib/constants/index.ts b/apps/studio/lib/constants/index.ts index 58994aa7f05..1f59242bb11 100644 --- a/apps/studio/lib/constants/index.ts +++ b/apps/studio/lib/constants/index.ts @@ -76,6 +76,7 @@ export const LOCAL_STORAGE_KEYS = { AUTH_SMTP_CHANGES_WARNING: 'auth-smtp-changes-warning-dismissed', AUTH_USERS_COLUMNS_CONFIGURATION: (ref: string) => `supabase-auth-users-columns-${ref}`, + STORAGE_BUCKETS_COLUMN_CONFIG: (ref: string) => `supabase-storage-buckets-columns-${ref}`, } export const OPT_IN_TAGS = { diff --git a/apps/studio/pages/_app.tsx b/apps/studio/pages/_app.tsx index 900cc483375..d40898ef2ae 100644 --- a/apps/studio/pages/_app.tsx +++ b/apps/studio/pages/_app.tsx @@ -147,19 +147,15 @@ function CustomApp({ Component, pageProps }: AppPropsWithLayout) { enableSystem disableTransitionOnChange > - - - - - {getLayout()} - - - - - - - - + + + {getLayout()} + + + + + + diff --git a/apps/studio/pages/project/[ref]/advisors/performance.tsx b/apps/studio/pages/project/[ref]/advisors/performance.tsx index 06a5a0ebd35..1b1e877377d 100644 --- a/apps/studio/pages/project/[ref]/advisors/performance.tsx +++ b/apps/studio/pages/project/[ref]/advisors/performance.tsx @@ -13,6 +13,8 @@ import { Lint, useProjectLintsQuery } from 'data/lint/lint-query' import { useSelectedProject } from 'hooks/misc/useSelectedProject' import type { NextPageWithLayout } from 'types' import { LoadingLine } from 'ui' +import AppLayout from 'components/layouts/AppLayout/AppLayout' +import DefaultLayout from 'components/layouts/DefaultLayout' const ProjectLints: NextPageWithLayout = () => { const project = useSelectedProject() @@ -65,11 +67,11 @@ const ProjectLints: NextPageWithLayout = () => { return (
- + /> */} { ) } -ProjectLints.getLayout = (page) => {page} +ProjectLints.getLayout = (page) => ( + + + {page} + + +) export default ProjectLints diff --git a/apps/studio/pages/project/[ref]/advisors/query-performance.tsx b/apps/studio/pages/project/[ref]/advisors/query-performance.tsx index 6ec244ce9b1..378b27c69c9 100644 --- a/apps/studio/pages/project/[ref]/advisors/query-performance.tsx +++ b/apps/studio/pages/project/[ref]/advisors/query-performance.tsx @@ -14,6 +14,8 @@ import AdvisorsLayout from 'components/layouts/AdvisorsLayout/AdvisorsLayout' import DatabaseSelector from 'components/ui/DatabaseSelector' import { FormHeader } from 'components/ui/Forms/FormHeader' import type { NextPageWithLayout } from 'types' +import AppLayout from 'components/layouts/AppLayout/AppLayout' +import DefaultLayout from 'components/layouts/DefaultLayout' const PRESET_MAP = { [QUERY_PERFORMANCE_REPORT_TYPES.MOST_TIME_CONSUMING]: 'mostTimeConsuming', @@ -46,19 +48,23 @@ const QueryPerformanceReport: NextPageWithLayout = () => { return (
- } - /> + /> */}
) } QueryPerformanceReport.getLayout = (page) => ( - {page} + + + {page} + + ) export default QueryPerformanceReport diff --git a/apps/studio/pages/project/[ref]/advisors/security.tsx b/apps/studio/pages/project/[ref]/advisors/security.tsx index edeb7c593bb..bb705e8bd45 100644 --- a/apps/studio/pages/project/[ref]/advisors/security.tsx +++ b/apps/studio/pages/project/[ref]/advisors/security.tsx @@ -13,6 +13,8 @@ import { Lint, useProjectLintsQuery } from 'data/lint/lint-query' import { useSelectedProject } from 'hooks/misc/useSelectedProject' import type { NextPageWithLayout } from 'types' import { LoadingLine } from 'ui' +import DefaultLayout from 'components/layouts/DefaultLayout' +import AppLayout from 'components/layouts/AppLayout/AppLayout' const ProjectLints: NextPageWithLayout = () => { const project = useSelectedProject() @@ -72,11 +74,11 @@ const ProjectLints: NextPageWithLayout = () => { return (
- + /> */} { ) } -ProjectLints.getLayout = (page) => {page} +ProjectLints.getLayout = (page) => ( + + + {page} + + +) export default ProjectLints diff --git a/apps/studio/pages/project/[ref]/functions/index.tsx b/apps/studio/pages/project/[ref]/functions/index.tsx index 9a819b83a6f..94ef245292d 100644 --- a/apps/studio/pages/project/[ref]/functions/index.tsx +++ b/apps/studio/pages/project/[ref]/functions/index.tsx @@ -23,6 +23,8 @@ import AlertError from 'components/ui/AlertError' import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' import { useEdgeFunctionsQuery } from 'data/edge-functions/edge-functions-query' import type { NextPageWithLayout } from 'types' +import AppLayout from 'components/layouts/AppLayout/AppLayout' +import DefaultLayout from 'components/layouts/DefaultLayout' const PageLayout: NextPageWithLayout = () => { const { ref } = useParams() @@ -96,6 +98,12 @@ const PageLayout: NextPageWithLayout = () => { ) } -PageLayout.getLayout = (page) => {page} +PageLayout.getLayout = (page) => ( + + + {page} + + +) export default PageLayout diff --git a/apps/studio/pages/project/[ref]/realtime/inspector.tsx b/apps/studio/pages/project/[ref]/realtime/inspector.tsx index b180cf75bac..1bcc38d8f2a 100644 --- a/apps/studio/pages/project/[ref]/realtime/inspector.tsx +++ b/apps/studio/pages/project/[ref]/realtime/inspector.tsx @@ -5,6 +5,8 @@ import { RealtimeInspector } from 'components/interfaces/Realtime/Inspector' import RealtimeLayout from 'components/layouts/RealtimeLayout/RealtimeLayout' import NoPermission from 'components/ui/NoPermission' import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' +import AppLayout from 'components/layouts/AppLayout/AppLayout' +import DefaultLayout from 'components/layouts/DefaultLayout' export const InspectorPage: NextPageWithLayout = () => { const canReadAPIKeys = useCheckPermissions(PermissionAction.READ, 'service_api_keys') @@ -17,7 +19,11 @@ export const InspectorPage: NextPageWithLayout = () => { } InspectorPage.getLayout = (page) => ( - {page} + + + {page} + + ) export default InspectorPage diff --git a/apps/studio/pages/project/[ref]/storage/buckets/index.tsx b/apps/studio/pages/project/[ref]/storage/buckets/index.tsx index a37e5e6a639..68e0899d86b 100644 --- a/apps/studio/pages/project/[ref]/storage/buckets/index.tsx +++ b/apps/studio/pages/project/[ref]/storage/buckets/index.tsx @@ -1,4 +1,5 @@ import { useParams } from 'common' +import { StorageBucketList } from 'components/interfaces/Storage/storage-bucket-list' import AppLayout from 'components/layouts/AppLayout/AppLayout' import DefaultLayout from 'components/layouts/DefaultLayout' @@ -21,22 +22,24 @@ const PageLayout: NextPageWithLayout = () => { if (isError) - return ( -
- -

- Create buckets to store and serve any type of digital content. -

-

- Make your buckets private or public depending on your security preference. -

-
-
- ) + // return ( + //
+ // + //

+ // Create buckets to store and serve any type of digital content. + //

+ //

+ // Make your buckets private or public depending on your security preference. + //

+ //
+ //
+ // ) + + return } PageLayout.getLayout = (page) => ( diff --git a/packages/ui/src/components/shadcn/ui/sidebar.tsx b/packages/ui/src/components/shadcn/ui/sidebar.tsx index 492c4025f2e..309626ef1b7 100644 --- a/packages/ui/src/components/shadcn/ui/sidebar.tsx +++ b/packages/ui/src/components/shadcn/ui/sidebar.tsx @@ -205,7 +205,7 @@ const Sidebar = React.forwardRef< return (