Skip to content

Conversation

@kunal-595
Copy link
Contributor

Adds a logs button in the footer that opens a full-screen overlay to view jmwalletd logs. Follows the same pattern as the orderbook overlay

Copilot AI review requested due to automatic review settings January 22, 2026 19:33
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a log viewer overlay feature that allows users to view jmwalletd logs from the application's footer. The implementation follows the established orderbook overlay pattern for consistency.

Changes:

  • Added a "Logs" button to the footer that opens a full-screen overlay
  • Created a new LogsOverlay component that displays logs in a dialog
  • Created a LogsContent component that handles fetching, displaying, and managing log file content
  • Added translation key for the new logs button

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/i18n/locales/en/translation.json Added "logs" translation key to footer section
src/components/layout/Layout.tsx Added state management for logs overlay and integrated LogsOverlay component
src/components/layout/AppFooter.tsx Added logs button with ScrollTextIcon and onClick handler
src/components/LogsOverlay.tsx New component implementing full-screen dialog for log viewing
src/components/LogsContent.tsx New component implementing log fetching, display, refresh, and download functionality

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +183 to +190
if (enabled && !isInitialized) {
const abortCtrl = new AbortController()
refresh(abortCtrl.signal).finally(() => {
if (abortCtrl.signal.aborted) return
setIsInitialized(true)
})
}

Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is executing side effects (calling refresh and setting state) during the render phase. This violates React's rules and can cause issues such as multiple fetch calls, memory leaks if the component unmounts before the promise resolves, and inconsistent behavior. This should be moved to a useEffect hook. For reference, see the OrderbookContent component which uses React Query's enabled prop to handle conditional fetching properly.

Suggested change
if (enabled && !isInitialized) {
const abortCtrl = new AbortController()
refresh(abortCtrl.signal).finally(() => {
if (abortCtrl.signal.aborted) return
setIsInitialized(true)
})
}
useEffect(() => {
if (!enabled || isInitialized) {
return
}
const abortCtrl = new AbortController()
refresh(abortCtrl.signal).finally(() => {
if (!abortCtrl.signal.aborted) {
setIsInitialized(true)
}
})
return () => {
abortCtrl.abort()
}
}, [enabled, isInitialized, refresh])

Copilot uses AI. Check for mistakes.
disabled={isScrolledToLogBottom}
size="icon"
onClick={scrollToLogBottom}
title={/* TODO: i18n */ 'Scroll to bottom'}
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hardcoded string should be internationalized. Add a translation key such as 'logs.scroll_to_bottom' to the translation file and use t('logs.scroll_to_bottom') instead of the hardcoded English text.

Suggested change
title={/* TODO: i18n */ 'Scroll to bottom'}
title={t('logs.scroll_to_bottom')}

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +63
const handleRefresh = useCallback(async () => {
if (isLoadingRefresh) return

setIsLoadingRefresh(true)
const abortCtrl = new AbortController()

try {
await refresh(abortCtrl.signal).then(() => delayedPromise(210))
} finally {
setIsLoadingRefresh(false)
}
}, [isLoadingRefresh, refresh])
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AbortController created in handleRefresh is never aborted if the component unmounts while a refresh is in progress. This could lead to state updates on an unmounted component. Consider adding cleanup logic to abort the request when the component unmounts, or move this logic into a useEffect with proper cleanup.

Copilot uses AI. Check for mistakes.
@theborakompanioni theborakompanioni added the v2 Related to the redesigned v2 release label Jan 23, 2026
@theborakompanioni theborakompanioni merged commit 324a067 into joinmarket-webui:v2 Jan 23, 2026
3 checks passed
@theborakompanioni
Copy link
Collaborator

Nice. I'll move logs related components to their own dir, remove duplicate code and add a storybook story for the logs content. Thanks @kunal-595 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Related to the redesigned v2 release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants