-
Notifications
You must be signed in to change notification settings - Fork 18
fix(studio): DD embedding template fix #661
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
6b40556
fix(studio): DD embedding template fix
steramae-nvidia bf34aa3
fix type
steramae-nvidia 3fb0d91
fix icon for DD
steramae-nvidia 8c03841
fix test model names
steramae-nvidia 04570fd
fix test
steramae-nvidia e458c41
fix(studio): address CodeRabbit review on DD embedding PR
steramae-nvidia a179f3d
fix tests
steramae-nvidia File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
web/packages/common/src/hooks/useStickToBottom/index.test.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { useStickToBottom } from '@nemo/common/src/hooks/useStickToBottom'; | ||
| import { render, screen } from '@testing-library/react'; | ||
| import userEvent from '@testing-library/user-event'; | ||
| import { FC } from 'react'; | ||
|
|
||
| // jsdom has no layout: scrollHeight/clientHeight report 0 and scrollTop is a no-op. | ||
| // Fake the geometry and back scrollTop with a real stored value so assignments stick. | ||
| const SCROLL_HEIGHT = 1000; | ||
| const CLIENT_HEIGHT = 100; | ||
| const MAX_SCROLL_TOP = SCROLL_HEIGHT - CLIENT_HEIGHT; | ||
|
|
||
| const mockGeometry = (element: HTMLElement) => { | ||
| let scrollTop = 0; | ||
| Object.defineProperty(element, 'scrollHeight', { configurable: true, value: SCROLL_HEIGHT }); | ||
| Object.defineProperty(element, 'clientHeight', { configurable: true, value: CLIENT_HEIGHT }); | ||
| Object.defineProperty(element, 'scrollTop', { | ||
| configurable: true, | ||
| get: () => scrollTop, | ||
| set: (value: number) => { | ||
| scrollTop = value; | ||
| }, | ||
| }); | ||
| }; | ||
|
|
||
| const Harness: FC<{ enabled?: boolean; attached?: boolean }> = ({ enabled, attached = true }) => { | ||
| const { ref, scrollToBottom } = useStickToBottom<HTMLDivElement>({ enabled }); | ||
| return ( | ||
| <> | ||
| <button onClick={scrollToBottom}>scroll</button> | ||
| {attached && <div ref={ref} data-testid="scroll" />} | ||
| </> | ||
| ); | ||
| }; | ||
|
|
||
| it('scrollToBottom() jumps the container to the bottom', async () => { | ||
| const user = userEvent.setup(); | ||
| render(<Harness enabled />); | ||
| const scroll = screen.getByTestId('scroll'); | ||
| mockGeometry(scroll); | ||
| expect(scroll.scrollTop).toBe(0); | ||
|
|
||
| await user.click(screen.getByRole('button', { name: 'scroll' })); | ||
|
|
||
| expect(scroll.scrollTop).toBe(MAX_SCROLL_TOP); | ||
| }); | ||
|
|
||
| it('scrollToBottom() does not throw before the element is attached', async () => { | ||
| const user = userEvent.setup(); | ||
| render(<Harness enabled attached={false} />); | ||
|
|
||
| await expect(user.click(screen.getByRole('button', { name: 'scroll' }))).resolves.not.toThrow(); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { RefObject, useCallback, useEffect, useRef } from 'react'; | ||
|
|
||
| interface UseStickToBottomOptions { | ||
| /** When false, the scroll listener and observer are detached (e.g. while loading). */ | ||
| enabled?: boolean; | ||
| /** Distance (px) from the bottom that still counts as "at the bottom". */ | ||
| threshold?: number; | ||
| /** | ||
| * Changing this re-attaches the observers and re-arms auto-scroll — use it when the | ||
| * scroll container's content is swapped out (e.g. toggling "show all" vs "tail"). | ||
| */ | ||
| resetKey?: unknown; | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| interface UseStickToBottom<T extends HTMLElement> { | ||
| /** Attach to the scrollable element (or the element whose content grows). */ | ||
| ref: RefObject<T | null>; | ||
| /** Jump to the bottom now and re-arm auto-scroll so future growth stays pinned. */ | ||
| scrollToBottom: () => void; | ||
| } | ||
|
|
||
| /** | ||
| * Keeps a scroll container pinned to the bottom as content streams in, but only while | ||
| * the user is already at the bottom. If the user scrolls up, auto-scroll pauses until | ||
| * they scroll back down (within `threshold`). | ||
| * | ||
| * Growth is detected with a MutationObserver so it also catches async content (e.g. a | ||
| * CodeSnippet that re-renders highlighted text after the value prop changes). | ||
| */ | ||
| export function useStickToBottom<T extends HTMLElement = HTMLElement>({ | ||
| enabled = true, | ||
| threshold = 50, | ||
| resetKey, | ||
| }: UseStickToBottomOptions = {}): UseStickToBottom<T> { | ||
| const ref = useRef<T>(null); | ||
| const shouldAutoScrollRef = useRef(true); | ||
|
|
||
| const scrollToBottom = useCallback(() => { | ||
| shouldAutoScrollRef.current = true; | ||
| const element = ref.current; | ||
| if (element) { | ||
| element.scrollTop = element.scrollHeight - element.clientHeight; | ||
| } | ||
| }, []); | ||
|
|
||
| // Pin to the bottom whenever content changes and the user is at the bottom. | ||
| useEffect(() => { | ||
| if (!enabled) return; | ||
| const element = ref.current; | ||
| if (!element) return; | ||
|
|
||
| shouldAutoScrollRef.current = true; | ||
| element.scrollTop = element.scrollHeight - element.clientHeight; | ||
|
|
||
| const observer = new MutationObserver(() => { | ||
| if (shouldAutoScrollRef.current) { | ||
| element.scrollTop = element.scrollHeight - element.clientHeight; | ||
| } | ||
| }); | ||
|
|
||
| observer.observe(element, { childList: true, subtree: true, characterData: true }); | ||
|
|
||
| return () => observer.disconnect(); | ||
| }, [enabled, resetKey]); | ||
|
|
||
| // Track whether the user is at the bottom so we can pause/resume auto-scroll. | ||
| useEffect(() => { | ||
| if (!enabled) return; | ||
| const element = ref.current; | ||
| if (!element) return; | ||
|
|
||
| const handleScroll = () => { | ||
| const distanceFromBottom = element.scrollHeight - element.clientHeight - element.scrollTop; | ||
| shouldAutoScrollRef.current = Math.abs(distanceFromBottom) < threshold; | ||
| }; | ||
|
|
||
| element.addEventListener('scroll', handleScroll); | ||
|
|
||
| return () => element.removeEventListener('scroll', handleScroll); | ||
| }, [enabled, threshold, resetKey]); | ||
|
|
||
| return { ref, scrollToBottom }; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.