Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const ActivityLogDetails: React.FC<{ actionId: string | null }> = ({ acti
const [taskLogs, setTaskLogs] = useState<TaskLogs>({});
const [loadingLogs, setLoadingLogs] = useState<{ [taskId: string]: boolean }>({});
const [elapsedTimes, setElapsedTimes] = useState<{ [taskId: string]: string }>({});
const [followScroll, setFollowScroll] = useState<{ [taskId: string]: boolean }>({});
const logStreams = useRef<{ [taskId: string]: EventSourcePolyfill | null }>({});
const { data: actionDetails, isLoading } = useProviderActionStatus(actionId);

Expand Down Expand Up @@ -184,16 +185,29 @@ export const ActivityLogDetails: React.FC<{ actionId: string | null }> = ({ acti

try {
const sanitizedLogs = logs.trim();
const shouldFollow = followScroll[taskId] !== false; // Default to true, but allow user to disable

return (
<div className="mt-4" style={{ height: 200 }}>
<ScrollFollow
startFollowing={true}
startFollowing={shouldFollow}
render={({ follow, onScroll }) => (
<LazyLog
text={sanitizedLogs}
follow={follow}
onScroll={onScroll}
onScroll={({ scrollTop, scrollHeight, clientHeight }) => {
// Check if user has scrolled to the bottom
const isAtBottom = scrollTop + clientHeight >= scrollHeight - 10; // 10px threshold

// Update follow state based on scroll position
setFollowScroll(prev => ({
...prev,
[taskId]: isAtBottom
}));

// Call the original onScroll handler
onScroll({ scrollTop, scrollHeight, clientHeight });
}}
Comment on lines +198 to +210
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Optimize scroll handler performance and verify ScrollFollow behavior.

The onScroll handler updates state on every scroll event, which fires continuously during scrolling and may cause performance issues.

Additionally, verify that the ScrollFollow component respects the startFollowing prop on re-renders. If it only uses startFollowing during initial mount and maintains internal state thereafter, updating followScroll state may not affect the auto-follow behavior as intended.

Performance optimization: Consider throttling or debouncing the state updates:

onScroll={({ scrollTop, scrollHeight, clientHeight }) => {
  const isAtBottom = scrollTop + clientHeight >= scrollHeight - 10;
  
  // Only update state if the value actually changes
  setFollowScroll(prev => {
    if (prev[taskId] !== isAtBottom) {
      return { ...prev, [taskId]: isAtBottom };
    }
    return prev;
  });

  onScroll({ scrollTop, scrollHeight, clientHeight });
}}

Verification: Please test that toggling auto-follow works correctly by:

  1. Scrolling up in an active log stream (should disable auto-follow)
  2. Scrolling back to bottom (should re-enable auto-follow)
  3. Verifying new logs appear automatically when at bottom


---

🏁 Script executed:

```shell
#!/bin/bash
# Find and examine ActivityLogDetails.tsx
fd --type f "ActivityLogDetails.tsx" --exec cat {} \;

Length of output: 11611


🏁 Script executed:

#!/bin/bash
# Find ScrollFollow component
fd --type f -e "ts" -e "tsx" -e "js" -e "jsx" | xargs rg -l "ScrollFollow" -g '!node_modules' | head -20

Length of output: 66


🏁 Script executed:

#!/bin/bash
# Search for ScrollFollow component definition
rg -nP --type=ts --type=tsx "(?:export\s+)?(const|function|class)\s+ScrollFollow\b" -A 15

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check for throttle/debounce imports or usage in the ActivityLogDetails file
rg -nP "(throttle|debounce)" apps/provider-console/src/components/shared/ActivityLogDetails.tsx

Length of output: 0



---

🌐 Web query:

```web
@melloware/react-logviewer ScrollFollow startFollowing prop behavior

💡 Result:

Short answer: startFollowing is the initial boolean that determines whether ScrollFollow begins in "follow" mode (i.e., child LazyLog receives follow=true). It only sets the initial state — user scrolling will turn follow off, and to re-enable following you must call the startFollowing helper returned by the render/child function (the prop itself is not a runtime restart callback). [1][2]

Sources:

  • @melloware/react-logviewer ScrollFollow docs (usage, startFollowing prop example). [1]
  • react-lazylog ScrollFollow docs (explains startFollowing is initial value and exposes startFollowing/stopFollowing functions from the child render). [2]

Address both performance and architectural issues with ScrollFollow integration.

The performance concern is valid: the onScroll handler updates state on every scroll event without checking if the value changes, causing unnecessary re-renders.

More critically, the current approach is architecturally problematic. According to the library documentation, startFollowing is an initial prop only—it doesn't control follow behavior on subsequent renders. The code recreates the entire ScrollFollow component on each render attempt to work around this, which is inefficient. The proper approach is to use the startFollowing() and stopFollowing() functions from the render prop to control follow state dynamically.

Required fixes:

  1. Performance: Only update state when the value actually changes:
onScroll={({ scrollTop, scrollHeight, clientHeight }) => {
  const isAtBottom = scrollTop + clientHeight >= scrollHeight - 10;
  
  setFollowScroll(prev => {
    if (prev[taskId] !== isAtBottom) {
      return { ...prev, [taskId]: isAtBottom };
    }
    return prev;
  });

  onScroll({ scrollTop, scrollHeight, clientHeight });
}}
  1. Architecture: Refactor to use the startFollowing and stopFollowing callback functions instead of relying on prop changes:
render={({ follow, onScroll, startFollowing, stopFollowing }) => (
  <LazyLog
    text={sanitizedLogs}
    follow={follow}
    onScroll={({ scrollTop, scrollHeight, clientHeight }) => {
      const isAtBottom = scrollTop + clientHeight >= scrollHeight - 10;
      if (isAtBottom) {
        startFollowing();
      } else {
        stopFollowing();
      }
      onScroll({ scrollTop, scrollHeight, clientHeight });
    }}
    // ... rest of props
  />
)}
🤖 Prompt for AI Agents
In apps/provider-console/src/components/shared/ActivityLogDetails.tsx around
lines 198-210, the current onScroll handler updates follow state on every scroll
and relies on re-rendering via the startFollowing prop; change it to (1) only
call setFollowScroll when the computed isAtBottom value actually differs from
the existing state for taskId to avoid needless re-renders, and (2) refactor the
ScrollFollow render prop to use the provided startFollowing and stopFollowing
functions to control follow behavior dynamically (call startFollowing when at
bottom, stopFollowing when not) while still invoking the original onScroll({
scrollTop, scrollHeight, clientHeight }) after handling follow state.

highlight={[]}
extraLines={1}
ansi
Expand All @@ -206,7 +220,6 @@ export const ActivityLogDetails: React.FC<{ actionId: string | null }> = ({ acti
backgroundColor: "var(--log-background, #1e1e1e)",
color: "var(--log-text, #ffffff)"
}}
key={`${taskId}-${sanitizedLogs.length}`}
/>
)}
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/net/src/generated/netConfigData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const netConfigData = {
mainnet: {
version: "v0.38.1",
version: "v1.0.0",
faucetUrl: null,
apiUrls: [
"https://rest-akash.ecostake.com",
Expand Down