Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/wiki/progress.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Progress
updated: 2026-08-08
updated: 2026-08-10
type: ledger
---

Expand All @@ -10,6 +10,7 @@ Stage ledger. One row per stage; keep entries short. Verifier = exact fresh comm

| Stage | Status | Verifier | Review | Next |
|---|---|---|---|---|
| Preserve Index DTF section in cmd-k navigation | human-review-required (base ebcd6febe) | RED: proposal/rebalance both landed overview; GREEN 2/2 · gate typecheck/lint/880 unit · live Ctrl+K proposal→governance + rebalance→auctions | independent Intent + Engineering Risk PASS, no findings; shared route-selection behavior requires Engineer review | merge only after Engineer review; wiki-lint blocked by pre-existing stale design-system page |
| vote modal: address-length title overflowed the dialog | done (base 6854a370b) | lint · typecheck · test:run · e2e helper units · smoke 58 · new `vote-modal-long-title` spec desktop+mobile green · RED-verified (reverted the index-dtf modal fix → checkbox right edge 943 vs dialog 849.9) | product/correctness: self — copy + layout only, no tx path touched | — |
| Fix DTF settings confirm button | human-review-required (base 6854a370b) | RED: rounded seeded distribution blocked mandate confirm; GREEN: unit 878 incl. mapper 27/27 · focused E2E 5/5 · typecheck · lint | Dark HOLD on untested mapping → 27 exhaustive mapper tests → Dark PASS; Light PASS; CodeRabbit 2 Minor → resolved (test IDs + editable confirmed state) | PR #1084 open; Engineer review required before merge; wiki-lint blocked by pre-existing stale design-system page |
| vlRSR self-appreciating vaults: drawer shares/redeem + rate line · governance card · portfolio · earn rate-corrected + APY | human-review-required (base d0427a7cf; SDK local-linked) | gate green: typecheck+lint+847 unit · 72 helper · smoke 58 · drawer spec 2/2 · live BSC visual light+dark incl. earn TVL 261.5M RSR = totalAssets | Dark + Light on both diffs; all blockers fixed; details in git | PR #1072 open on SDK 0.5.1 (published, pinned exact; direct sdk dep dropped). Companions: dtf-interface#29, reserve-api#236 (deploy w/ daos CDN purge). **Engineer review**: withdraw→redeem for ALL vaults, governance card, api token.price×rate. [plan](../plans/vlrsr-self-appreciating-vaults.md) |
Expand Down
113 changes: 74 additions & 39 deletions src/components/command-menu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import useIndexDTFList from '@/hooks/useIndexDTFList'
import useTokenList from '@/hooks/useTokenList'
import { getFolioRoute, getTokenRoute } from '@/utils'
import { CHAIN_TAGS } from '@/utils/constants'
import { CHAIN_TAGS, ROUTES } from '@/utils/constants'
import { msg } from '@lingui/core/macro'
import { Trans, useLingui } from '@lingui/react/macro'
import type { MessageDescriptor } from '@lingui/core'
import { atom, useAtom } from 'jotai'
import { Search } from 'lucide-react'
import { useEffect, useMemo, useRef } from 'react'
import Skeleton from 'react-loading-skeleton'
import { Link, useNavigate } from 'react-router-dom'
import { Link, useLocation, useNavigate } from 'react-router-dom'
import ChainLogo from '../icons/ChainLogo'
import TokenLogo from '../token-logo'
import {
Expand Down Expand Up @@ -67,7 +67,28 @@
index: msg`Index DTFs`,
yield: msg`Yield DTFs`,
}
const SECTIONS = ['index', 'yield']
const SECTIONS = ['index', 'yield'] as const
type DTFType = (typeof SECTIONS)[number]

const DTF_ROUTES: Record<DTFType, Set<string>> = {
index: new Set([
ROUTES.OVERVIEW,
ROUTES.MANAGE,
ROUTES.FACTSHEET,
ROUTES.ISSUANCE,
ROUTES.AUCTIONS,
ROUTES.SETTINGS,
ROUTES.GOVERNANCE,
]),
yield: new Set([
ROUTES.OVERVIEW,
ROUTES.ISSUANCE,
ROUTES.STAKING,
ROUTES.AUCTIONS,
ROUTES.SETTINGS,
ROUTES.GOVERNANCE,
]),
}

export const searchMenuOpenAtom = atom(false)

Expand All @@ -82,12 +103,13 @@
const [open, setOpen] = useAtom(searchMenuOpenAtom)
const listRef = useRef<HTMLDivElement | null>(null)
const navigate = useNavigate()
const { pathname } = useLocation()

useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
e.preventDefault()
setOpen((open) => !open)

Check warning on line 112 in src/components/command-menu/index.tsx

View workflow job for this annotation

GitHub Actions / check

react-hooks(exhaustive-deps)

React Hook useEffect has a missing dependency: 'setOpen'
}
}
document.addEventListener('keydown', down)
Expand Down Expand Up @@ -130,43 +152,39 @@
</CommandEmpty>
{SECTIONS.map((section) => (
<CommandGroup key={section} heading={t(SECTION_TITLES[section])}>
{dtfs[section].map((dtf) => (
<Link
key={dtf.address}
to={
section === 'index'
? getFolioRoute(dtf.address, dtf.chain)
: getTokenRoute(dtf.address, dtf.chain)
}
onClick={() => setOpen(false)}
>
<CommandItem
keywords={dtf.keywords}
value={`${dtf.name} ${dtf.symbol}`}
className="gap-3 cursor-pointer"
onSelect={() => {
navigate(
section === 'index'
? getFolioRoute(dtf.address, dtf.chain)
: getTokenRoute(dtf.address, dtf.chain)
)
setOpen(false)
}}
{dtfs[section].map((dtf) => {
const destination = getDTFRoute(pathname, section, dtf)

return (
<Link
key={dtf.address}
to={destination}
onClick={() => setOpen(false)}
>
<div className="relative">
<TokenLogo src={dtf.icon} size="xl" />
<ChainLogo
chain={dtf.chain}
className="absolute -bottom-1 -right-1 w-4 h-2"
/>
</div>
<div className="break-words max-w-[420px]">
<h4 className="font-semibold ">{dtf.name}</h4>
<span className="text-legend">${dtf.symbol}</span>
</div>
</CommandItem>
</Link>
))}
<CommandItem
keywords={dtf.keywords}
value={`${dtf.name} ${dtf.symbol}`}
className="gap-3 cursor-pointer"
onSelect={() => {
navigate(destination)
setOpen(false)
}}
>
<div className="relative">
<TokenLogo src={dtf.icon} size="xl" />
<ChainLogo
chain={dtf.chain}
className="absolute -bottom-1 -right-1 w-4 h-2"
/>
</div>
<div className="break-words max-w-[420px]">
<h4 className="font-semibold ">{dtf.name}</h4>
<span className="text-legend">${dtf.symbol}</span>
</div>
</CommandItem>
</Link>
)
})}
</CommandGroup>
))}
</CommandList>
Expand All @@ -177,3 +195,20 @@
}

export default CommandMenu

const getDTFRoute = (pathname: string, type: DTFType, dtf: DTF) => {
const segments = pathname.split('/').filter(Boolean)
const dtfRootIndex = segments.findIndex(
(segment) => segment === 'index-dtf' || segment === 'token'
)
const currentRoute =
dtfRootIndex === -1 ? undefined : segments[dtfRootIndex + 2]
const route =
currentRoute && DTF_ROUTES[type].has(currentRoute)
? currentRoute
: ROUTES.OVERVIEW

return type === 'index'
? getFolioRoute(dtf.address, dtf.chain, route)
: getTokenRoute(dtf.address, dtf.chain, route)
}
68 changes: 68 additions & 0 deletions src/components/command-menu/tests/navigation.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { render, screen } from '@/test-utils'
import userEvent from '@testing-library/user-event'
import { MemoryRouter, useLocation } from 'react-router-dom'
import { describe, expect, it, vi } from 'vitest'
import CommandMenu from '..'

window.HTMLElement.prototype.scrollIntoView = vi.fn()

vi.mock('@/components/icons/ChainLogo', () => ({
default: () => <span data-testid="chain-logo" />,
}))

vi.mock('@/components/token-logo', () => ({
default: () => <span data-testid="token-logo" />,
}))

vi.mock('@/hooks/useIndexDTFList', () => ({
default: () => ({
data: [
{
address: '0xTarget',
brand: { icon: '' },
chainId: 8453,
name: 'Target DTF',
symbol: 'TARGET',
},
],
}),
}))

vi.mock('@/hooks/useTokenList', () => ({
default: () => ({ list: [] }),
}))

const CurrentPath = () => {
const { pathname } = useLocation()
return <output data-testid="current-path">{pathname}</output>
}

describe('CommandMenu DTF navigation', () => {
it.each([
[
'/ethereum/index-dtf/0xcurrent/governance/proposal/42',
'/base/index-dtf/0xtarget/governance',
],
[
'/ethereum/index-dtf/0xcurrent/auctions/rebalance/7',
'/base/index-dtf/0xtarget/auctions',
],
])(
'keeps the top-level DTF section when switching from %s',
async (currentPath, expectedPath) => {
const user = userEvent.setup()

render(
<MemoryRouter initialEntries={[currentPath]}>
<CommandMenu />
<CurrentPath />
</MemoryRouter>
)

await user.click(screen.getByRole('button', { name: 'Search' }))
await user.click(await screen.findByText('Target DTF'))

expect(screen.getByTestId('current-path')).toHaveTextContent(expectedPath)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
)
})
Loading