Skip to content

Commit

Permalink
fix: console module tree: rip out disclosure button to fix all the st…
Browse files Browse the repository at this point in the history
…ate consistency bugs (#2811)

Part 1 of #2760
  • Loading branch information
deniseli authored Sep 25, 2024
1 parent 4b74557 commit fb5c766
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 37 deletions.
2 changes: 1 addition & 1 deletion frontend/console/e2e/module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ftlTest('shows verbs for deployment', async ({ page }) => {
const modulesNavItem = page.getByRole('link', { name: 'Modules' })
await modulesNavItem.click()

const moduleEchoRow = page.getByRole('button', { name: 'echo' })
const moduleEchoRow = page.locator('div.cursor-pointer').getByText('echo')
const moduleEcho = moduleEchoRow.locator('svg').nth(1)
await moduleEcho.click()

Expand Down
2 changes: 1 addition & 1 deletion frontend/console/e2e/verb.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ftlTest.beforeEach(async ({ page }) => {
const modulesNavItem = page.getByRole('link', { name: 'Modules' })
await modulesNavItem.click()

const moduleEcho = page.getByRole('button', { name: 'echo' })
const moduleEcho = page.locator('div.cursor-pointer').getByText('echo').nth(0)
await moduleEcho.click()

const verbEcho = page.locator('div#decl-echo')
Expand Down
77 changes: 42 additions & 35 deletions frontend/console/src/features/modules/ModulesTree.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react'
import { ArrowRight01Icon, CircleArrowRight02Icon, CodeIcon, FileExportIcon, PackageIcon } from 'hugeicons-react'
import { useEffect, useMemo, useRef } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import type { Decl } from '../../protos/xyz/block/ftl/v1/schema/schema_pb'
import { classNames } from '../../utils'
Expand Down Expand Up @@ -60,7 +59,7 @@ const ModuleSection = ({ module, isExpanded, toggleExpansion }: { module: Module
const { moduleName, declName } = useParams()
const navigate = useNavigate()
const isSelected = useMemo(() => moduleName === module.name, [moduleName, module.name])
const moduleRef = useRef<HTMLButtonElement>(null)
const moduleRef = useRef<HTMLDivElement>(null)

// Scroll to the selected module on page load
useEffect(() => {
Expand All @@ -75,54 +74,62 @@ const ModuleSection = ({ module, isExpanded, toggleExpansion }: { module: Module

return (
<li key={module.name} id={`module-tree-module-${module.name}`} className='my-2'>
<Disclosure as='div' defaultOpen={isExpanded}>
<DisclosureButton
ref={moduleRef}
className={classNames(
isSelected ? 'bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 hover:dark:bg-gray-600' : 'hover:bg-gray-200 hover:dark:bg-gray-700',
'group flex w-full modules-center gap-x-2 space-y-1 text-left text-sm font-medium leading-6',
)}
onClick={() => toggleExpansion(module.name)}
>
<PackageIcon aria-hidden='true' className='size-4 my-1 ml-3 shrink-0' />
{module.name}
<CircleArrowRight02Icon
className='size-4 shrink-0 rounded-md hover:bg-gray-200 dark:hover:bg-gray-600'
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
navigate(`/modules/${module.name}`)
}}
/>
{module.decls.length === 0 || (
<ArrowRight01Icon aria-hidden='true' className='ml-auto mr-2 h-4 w-4 shrink-0 group-data-[open]:rotate-90 group-data-[open]:text-gray-500' />
)}
</DisclosureButton>
<DisclosurePanel as='ul'>
<div
ref={moduleRef}
className={classNames(
isSelected ? 'bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 hover:dark:bg-gray-600' : 'hover:bg-gray-200 hover:dark:bg-gray-700',
'group flex w-full modules-center gap-x-2 space-y-1 text-left text-sm font-medium cursor-pointer leading-6',
)}
onClick={() => toggleExpansion(module.name)}
>
<PackageIcon aria-hidden='true' className='size-4 my-1 ml-3 shrink-0' />
{module.name}
<CircleArrowRight02Icon
className='size-4 shrink-0 rounded-md hover:bg-gray-200 dark:hover:bg-gray-600'
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
navigate(`/modules/${module.name}`)
}}
/>
{module.decls.length === 0 || (
<ArrowRight01Icon aria-hidden='true' className='ml-auto mr-2 h-4 w-4 shrink-0 group-data-[open]:rotate-90 group-data-[open]:text-gray-500' />
)}
</div>
{isExpanded && (
<ul>
{module.decls.map((d, i) => (
<DeclNode key={i} decl={d} href={declUrl(module.name, d)} isSelected={isSelected && declName === d.value.value?.name} />
))}
</DisclosurePanel>
</Disclosure>
</ul>
)}
</li>
)
}

export const ModulesTree = ({ modules }: { modules: ModuleTreeItem[] }) => {
const { moduleName } = useParams()
const { moduleName, declName } = useParams()

const [expandedModules, setExpandedModules] = useState(listExpandedModulesFromLocalStorage())
useEffect(() => {
addModuleToLocalStorageIfMissing(moduleName)
}, [moduleName])
if (declName) {
addModuleToLocalStorageIfMissing(moduleName)
}
}, [moduleName, declName])

modules.sort((m1, m2) => Number(m1.isBuiltin) - Number(m2.isBuiltin))
function toggleFn(moduleName: string) {
toggleModuleExpansionInLocalStorage(moduleName)
setExpandedModules(listExpandedModulesFromLocalStorage())
return
}

const expandedModules = listExpandedModulesFromLocalStorage()
modules.sort((m1, m2) => Number(m1.isBuiltin) - Number(m2.isBuiltin))
return (
<div className={'flex grow flex-col h-full gap-y-5 overflow-y-auto bg-gray-100 dark:bg-gray-900'}>
<nav>
<ul>
{modules.map((m) => (
<ModuleSection key={m.name} module={m} isExpanded={expandedModules.includes(m.name)} toggleExpansion={toggleModuleExpansionInLocalStorage} />
<ModuleSection key={m.name} module={m} isExpanded={expandedModules.includes(m.name)} toggleExpansion={toggleFn} />
))}
</ul>
</nav>
Expand Down

0 comments on commit fb5c766

Please sign in to comment.