Chore/update sql side panel (#30050)

* init

* Update inner-side-menu.mdx

* chore: update SQL sidebar to use ui pattern components

* mor

* Update

* Update index.tsx

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
Jonathan Summers-MuirandJoshen Lim authored and GitHub committed 2024-11-13 14:03:48 +08:00
1 parent aad6c48d03
commit 297fc76bfd
4 files changed
+164 -153

No files matched your search

@@ -36,11 +36,10 @@ export const SQLEditorMenu = ({ onViewOngoingQueries }: SQLEditorMenuProps) => {
const router = useRouter()
const { profile } = useProfile()
const project = useSelectedProject()
const { ref, id: activeId } = useParams()
const { ref } = useParams()
const snapV2 = useSqlEditorV2StateSnapshot()
const [searchText, setSearchText] = useState('')
const [selectedQueries, setSelectedQueries] = useState<string[]>([])
const canCreateSQLSnippet = useCheckPermissions(PermissionAction.CREATE, 'user_content', {
resource: { type: 'sql', owner_id: profile?.id },
@@ -80,78 +79,76 @@ export const SQLEditorMenu = ({ onViewOngoingQueries }: SQLEditorMenuProps) => {
}
return (
<>
<div className="h-full flex flex-col justify-between">
<div className="mt-4 mb-2 flex flex-col gap-y-4">
<div className="mx-4 flex items-center justify-between gap-x-2">
<InnerSideBarFilters className="w-full p-0 gap-0">
<InnerSideBarFilterSearchInput
name="search-queries"
placeholder="Search queries..."
aria-labelledby="Search queries"
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
<div className="h-full flex flex-col justify-between">
<div className="mt-4 mb-2 flex flex-col gap-y-4">
<div className="mx-4 flex items-center justify-between gap-x-2">
<InnerSideBarFilters className="w-full p-0 gap-0">
<InnerSideBarFilterSearchInput
name="search-queries"
placeholder="Search queries..."
aria-labelledby="Search queries"
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
>
<InnerSideBarFilterSortDropdown
value={snapV2.order}
onValueChange={(value: any) => snapV2.setOrder(value)}
>
<InnerSideBarFilterSortDropdown
value={snapV2.order}
onValueChange={(value: any) => snapV2.setOrder(value)}
>
<InnerSideBarFilterSortDropdownItem key="name" value="name">
Alphabetical
</InnerSideBarFilterSortDropdownItem>
<InnerSideBarFilterSortDropdownItem key="inserted_at" value="inserted_at">
Created At
</InnerSideBarFilterSortDropdownItem>
</InnerSideBarFilterSortDropdown>
</InnerSideBarFilterSearchInput>
</InnerSideBarFilters>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
type="default"
icon={<Plus className="text-foreground" />}
className="w-[26px]"
/>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" side="bottom" className="w-48">
<DropdownMenuItem className="gap-x-2" onClick={() => handleNewQuery()}>
<FilePlus size={14} />
Create a new snippet
</DropdownMenuItem>
<DropdownMenuItem className="gap-x-2" onClick={() => createNewFolder()}>
<FolderPlus size={14} />
Create a new folder
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="px-2">
<InnerSideMenuItem
title="Templates"
isActive={router.asPath === `/project/${ref}/sql/templates`}
href={`/project/${ref}/sql/templates`}
>
Templates
</InnerSideMenuItem>
<InnerSideMenuItem
title="Quickstarts"
isActive={router.asPath === `/project/${ref}/sql/quickstarts`}
href={`/project/${ref}/sql/quickstarts`}
>
Quickstarts
</InnerSideMenuItem>
</div>
<SQLEditorNavV2 searchText={searchText} />
<InnerSideBarFilterSortDropdownItem key="name" value="name">
Alphabetical
</InnerSideBarFilterSortDropdownItem>
<InnerSideBarFilterSortDropdownItem key="inserted_at" value="inserted_at">
Created At
</InnerSideBarFilterSortDropdownItem>
</InnerSideBarFilterSortDropdown>
</InnerSideBarFilterSearchInput>
</InnerSideBarFilters>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
type="default"
icon={<Plus className="text-foreground" />}
className="w-[26px]"
/>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" side="bottom" className="w-48">
<DropdownMenuItem className="gap-x-2" onClick={() => handleNewQuery()}>
<FilePlus size={14} />
Create a new snippet
</DropdownMenuItem>
<DropdownMenuItem className="gap-x-2" onClick={() => createNewFolder()}>
<FolderPlus size={14} />
Create a new folder
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="p-4 border-t sticky bottom-0 bg-studio">
<Button block type="default" onClick={onViewOngoingQueries}>
View running queries
</Button>
<div className="px-2">
<InnerSideMenuItem
title="Templates"
isActive={router.asPath === `/project/${ref}/sql/templates`}
href={`/project/${ref}/sql/templates`}
>
Templates
</InnerSideMenuItem>
<InnerSideMenuItem
title="Quickstarts"
isActive={router.asPath === `/project/${ref}/sql/quickstarts`}
href={`/project/${ref}/sql/quickstarts`}
>
Quickstarts
</InnerSideMenuItem>
</div>
<SQLEditorNavV2 searchText={searchText} />
</div>
</>
<div className="p-4 border-t sticky bottom-0 bg-studio">
<Button block type="default" onClick={onViewOngoingQueries}>
View running queries
</Button>
</div>
</div>
)
}
@@ -1,4 +1,4 @@
import { ChevronRight, Eye, EyeOffIcon, Heart, Unlock } from 'lucide-react'
import { Eye, EyeOffIcon, Heart, Unlock } from 'lucide-react'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'
@@ -31,18 +31,15 @@ import {
useSnippets,
useSqlEditorV2StateSnapshot,
} from 'state/sql-editor-v2'
import { Separator, Skeleton, TreeView } from 'ui'
import {
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
Alert_Shadcn_,
CollapsibleContent_Shadcn_,
CollapsibleTrigger_Shadcn_,
Collapsible_Shadcn_,
Separator,
TreeView,
} from 'ui'
InnerSideBarEmptyPanel,
InnerSideMenuCollapsible,
InnerSideMenuCollapsibleContent,
InnerSideMenuCollapsibleTrigger,
InnerSideMenuSeparator,
} from 'ui-patterns'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
import { ROOT_NODE, formatFolderResponseForTreeView } from './SQLEditorNav.utils'
import { SQLEditorTreeViewItem } from './SQLEditorTreeViewItem'
@@ -75,11 +72,6 @@ export const SQLEditorNav = ({ searchText: _searchText }: SQLEditorNavProps) =>
const [selectedSnippetToDownload, setSelectedSnippetToDownload] = useState<Snippet>()
const [selectedFolderToDelete, setSelectedFolderToDelete] = useState<SnippetFolder>()
const COLLAPSIBLE_TRIGGER_CLASS_NAMES =
'flex items-center gap-x-2 px-4 [&[data-state=open]>svg]:!rotate-90'
const COLLAPSIBLE_ICON_CLASS_NAMES = 'text-foreground-light transition-transform duration-200'
const COLLASIBLE_HEADER_CLASS_NAMES = 'text-foreground-light font-mono text-sm uppercase'
// =======================================================
// [Joshen] Set up favorites, shared, and private snippets
// =======================================================
@@ -341,27 +333,24 @@ export const SQLEditorNav = ({ searchText: _searchText }: SQLEditorNavProps) =>
return (
<>
<Separator />
<InnerSideMenuSeparator />
{((numProjectSnippets === 0 && searchText.length === 0) || numProjectSnippets > 0) && (
<>
<Collapsible_Shadcn_ open={showSharedSnippets} onOpenChange={setShowSharedSnippets}>
<CollapsibleTrigger_Shadcn_ className={COLLAPSIBLE_TRIGGER_CLASS_NAMES}>
<ChevronRight size={16} className={COLLAPSIBLE_ICON_CLASS_NAMES} />
<span className={COLLASIBLE_HEADER_CLASS_NAMES}>
Shared{numProjectSnippets > 0 && ` (${numProjectSnippets})`}
</span>
</CollapsibleTrigger_Shadcn_>
<CollapsibleContent_Shadcn_ className="pt-2">
<InnerSideMenuCollapsible
open={showSharedSnippets}
onOpenChange={setShowSharedSnippets}
className="px-0"
>
<InnerSideMenuCollapsibleTrigger
title={`Shared ${numProjectSnippets > 0 ? ` (${numProjectSnippets})` : ''}`}
/>
<InnerSideMenuCollapsibleContent className="group-data-[state=open]:pt-2">
{numProjectSnippets === 0 ? (
<div className="mx-4">
<Alert_Shadcn_ className="p-3">
<AlertTitle_Shadcn_ className="text-xs">No shared queries</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_ className="text-xs ">
Share queries with your team by right-clicking on the query.
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
</div>
<InnerSideBarEmptyPanel
className="mx-2"
title="No shared queries"
description="Share queries with your team by right-clicking on the query."
/>
) : (
<TreeView
data={projectSnippetsTreeState}
@@ -391,33 +380,35 @@ export const SQLEditorNav = ({ searchText: _searchText }: SQLEditorNavProps) =>
)}
/>
)}
</CollapsibleContent_Shadcn_>
</Collapsible_Shadcn_>
<Separator />
</InnerSideMenuCollapsibleContent>
</InnerSideMenuCollapsible>
<InnerSideMenuSeparator />
</>
)}
{((numFavoriteSnippets === 0 && searchText.length === 0) || numFavoriteSnippets > 0) && (
<>
<Collapsible_Shadcn_ open={showFavouriteSnippets} onOpenChange={setShowFavouriteSnippets}>
<CollapsibleTrigger_Shadcn_ className={COLLAPSIBLE_TRIGGER_CLASS_NAMES}>
<ChevronRight size={16} className={COLLAPSIBLE_ICON_CLASS_NAMES} />
<span className={COLLASIBLE_HEADER_CLASS_NAMES}>
Favorites{numFavoriteSnippets > 0 && ` (${numFavoriteSnippets})`}
</span>
</CollapsibleTrigger_Shadcn_>
<CollapsibleContent_Shadcn_ className="pt-2">
<InnerSideMenuCollapsible
className="px-0"
open={showFavouriteSnippets}
onOpenChange={setShowFavouriteSnippets}
>
<InnerSideMenuCollapsibleTrigger
title={`Favorites ${numFavoriteSnippets > 0 ? ` (${numFavoriteSnippets})` : ''}`}
/>
<InnerSideMenuCollapsibleContent className="group-data-[state=open]:pt-2">
{numFavoriteSnippets === 0 ? (
<div className="mx-4">
<Alert_Shadcn_ className="p-3">
<AlertTitle_Shadcn_ className="text-xs">No favorite queries</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_ className="text-xs ">
<InnerSideBarEmptyPanel
title="No favorite queries"
className="mx-2"
description={
<>
Save a query to favorites for easy accessbility by clicking the{' '}
<Heart size={12} className="inline-block relative align-center -top-[1px]" />{' '}
icon.
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
</div>
</>
}
/>
) : (
<TreeView
data={favoritesTreeState}
@@ -448,34 +439,51 @@ export const SQLEditorNav = ({ searchText: _searchText }: SQLEditorNavProps) =>
)}
/>
)}
</CollapsibleContent_Shadcn_>
</Collapsible_Shadcn_>
<Separator />
</InnerSideMenuCollapsibleContent>
</InnerSideMenuCollapsible>
<InnerSideMenuSeparator />
</>
)}
<Collapsible_Shadcn_ open={showPrivateSnippets} onOpenChange={setShowPrivateSnippets}>
<CollapsibleTrigger_Shadcn_ className={COLLAPSIBLE_TRIGGER_CLASS_NAMES}>
<ChevronRight size={16} className={COLLAPSIBLE_ICON_CLASS_NAMES} />
<span className={COLLASIBLE_HEADER_CLASS_NAMES}>
PRIVATE
{numPrivateSnippets > 0 && ` (${numPrivateSnippets})`}
</span>
</CollapsibleTrigger_Shadcn_>
<CollapsibleContent_Shadcn_ className="pt-2">
<InnerSideMenuCollapsible
open={showPrivateSnippets}
onOpenChange={setShowPrivateSnippets}
className="px-0"
>
<InnerSideMenuCollapsibleTrigger
title={`PRIVATE
${numPrivateSnippets > 0 ? ` (${numPrivateSnippets})` : ''}`}
/>
<InnerSideMenuCollapsibleContent className="group-data-[state=open]:pt-2">
{!snapV2.loaded[projectRef as string] ? (
<div className="px-4">
<GenericSkeletonLoader />
</div>
<>
<div className="flex flex-row h-6 px-3 items-center gap-3">
<Skeleton className="h-4 w-5" />
<Skeleton className="w-40 h-4" />
</div>
<div className="flex flex-row h-6 px-3 items-center gap-3">
<Skeleton className="h-4 w-5" />
<Skeleton className="w-32 h-4" />
</div>
<div className="flex flex-row h-6 px-3 items-center gap-3 opacity-75">
<Skeleton className="h-4 w-5" />
<Skeleton className="w-20 h-4" />
</div>
<div className="flex flex-row h-6 px-3 items-center gap-3 opacity-50">
<Skeleton className="h-4 w-5" />
<Skeleton className="w-40 h-4" />
</div>
<div className="flex flex-row h-6 px-3 items-center gap-3 opacity-25">
<Skeleton className="h-4 w-5" />
<Skeleton className="w-20 h-4" />
</div>
</>
) : folders.length === 0 && numPrivateSnippets === 0 ? (
<div className="mx-4">
<Alert_Shadcn_ className="p-3">
<AlertTitle_Shadcn_ className="text-xs">No queries created yet</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_ className="text-xs">
Queries will be automatically saved once you start writing in the editor.
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
</div>
<InnerSideBarEmptyPanel
className="mx-3 px-4"
title="No queries created yet"
description="Queries will be automatically saved once you start writing in the editor"
/>
) : (
<TreeView
multiSelect
@@ -544,8 +552,8 @@ export const SQLEditorNav = ({ searchText: _searchText }: SQLEditorNavProps) =>
)}
/>
)}
</CollapsibleContent_Shadcn_>
</Collapsible_Shadcn_>
</InnerSideMenuCollapsibleContent>
</InnerSideMenuCollapsible>
<Separator />
+3
View File
@@ -420,6 +420,9 @@ const uiConfig = ui({
require('@tailwindcss/typography'),
require('tailwindcss-animate'),
plugin(motionSafeTransition),
function ({ addVariant }) {
addVariant('not-disabled', '&:not(:disabled)')
},
],
})
+9 -6
View File
@@ -39,7 +39,13 @@ const InnerSideMenuCollapsible = forwardRef<
ElementRef<typeof Collapsible_Shadcn_>,
React.ComponentPropsWithoutRef<typeof Collapsible_Shadcn_>
>(({ ...props }, ref) => {
return <Collapsible_Shadcn_ ref={ref} {...props} className={cn('w-full px-2', props.className)} />
return (
<Collapsible_Shadcn_
ref={ref}
{...props}
className={cn('w-full px-2 group', props.className)}
/>
)
})
const InnerSideMenuCollapsibleTrigger = forwardRef<
@@ -73,10 +79,7 @@ const InnerSideMenuCollapsibleContent = forwardRef<
<CollapsibleContent_Shadcn_
ref={ref}
{...props}
className={cn(
'w-full flex flex-col gap-0 transition-all data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down',
props.className
)}
className={cn('w-full flex flex-col gap-0', props.className)}
/>
)
})
@@ -220,7 +223,7 @@ const InnerSideBarEmptyPanel = forwardRef<
HTMLDivElement,
React.ComponentPropsWithoutRef<'div'> & {
title: string
description?: string
description?: string | React.ReactNode
illustration?: React.ReactNode
actions?: React.ReactNode
}