diff --git a/src/renderer/components/dock/logs/list.tsx b/src/renderer/components/dock/logs/list.tsx index fba6bce048..2976a258fa 100644 --- a/src/renderer/components/dock/logs/list.tsx +++ b/src/renderer/components/dock/logs/list.tsx @@ -5,6 +5,7 @@ import "./list.scss"; +import type { ForwardedRef } from "react"; import React from "react"; import AnsiUp from "ansi_up"; import DOMPurify from "dompurify"; @@ -28,8 +29,12 @@ export interface LogListProps { const colorConverter = new AnsiUp(); +export interface LogListRef { + scrollToItem: (index: number, align: Align) => void; +} + @observer -export class LogList extends React.Component { +class NonForwardedLogList extends React.Component }> { @observable isJumpButtonVisible = false; @observable isLastLineVisible = true; @@ -37,7 +42,7 @@ export class LogList extends React.Component { private virtualListRef = React.createRef(); // A reference for VirtualList component private lineHeight = 18; // Height of a log line. Should correlate with styles in pod-log-list.scss - constructor(props: LogListProps) { + constructor(props: any) { super(props); makeObservable(this); autoBind(this); @@ -51,6 +56,27 @@ export class LogList extends React.Component { this.onUserScrolledUp(logs, prevLogs); }), ]); + this.bindInnerRef({ + scrollToItem: this.scrollToItem, + }); + } + + componentDidUpdate() { + this.bindInnerRef({ + scrollToItem: this.scrollToItem, + }); + } + + componentWillUnmount() { + this.bindInnerRef(null); + } + + private bindInnerRef(value: LogListRef | null) { + if (typeof this.props.innerRef === "function") { + this.props.innerRef(value); + } else if (this.props.innerRef && typeof this.props.innerRef === "object") { + this.props.innerRef.current = value; + } } onLogsInitialLoad(logs: string[], prevLogs: string[]) { @@ -246,3 +272,7 @@ export class LogList extends React.Component { ); } } + +export const LogList = React.forwardRef((props, ref) => ( + +)); diff --git a/src/renderer/components/dock/logs/view.tsx b/src/renderer/components/dock/logs/view.tsx index a624fad597..095fd73bb9 100644 --- a/src/renderer/components/dock/logs/view.tsx +++ b/src/renderer/components/dock/logs/view.tsx @@ -7,6 +7,7 @@ import React, { createRef, useEffect } from "react"; import { observer } from "mobx-react"; import { InfoPanel } from "../info-panel"; import { LogResourceSelector } from "./resource-selector"; +import type { LogListRef } from "./list"; import { LogList } from "./list"; import { LogSearch } from "./search"; import { LogControls } from "./controls"; @@ -30,7 +31,7 @@ interface Dependencies { } const NonInjectedLogsDockTab = observer(({ className, tab, model, subscribeStores }: Dependencies & LogsDockTabProps) => { - const logListElement = createRef(); + const logListElement = createRef(); const data = model.logTabData.get(); useEffect(() => { diff --git a/src/renderer/components/virtual-list/virtual-list.tsx b/src/renderer/components/virtual-list/virtual-list.tsx index 45b2bd0994..1045cc5d22 100644 --- a/src/renderer/components/virtual-list/virtual-list.tsx +++ b/src/renderer/components/virtual-list/virtual-list.tsx @@ -7,7 +7,7 @@ // API docs: https://react-window.now.sh import "./virtual-list.scss"; -import type { ForwardedRef, PropsWithoutRef, RefObject } from "react"; +import type { ForwardedRef } from "react"; import React, { createRef, forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react"; import { observer } from "mobx-react"; import type { Align, ListChildComponentProps, ListOnScrollProps } from "react-window"; @@ -28,7 +28,7 @@ export interface VirtualListProps { selectedItemId?: string; getRow?: (uid: T extends string ? number : string) => React.ReactElement | undefined | null; onScroll?: (props: ListOnScrollProps) => void; - outerRef?: React.Ref; + outerRef?: React.Ref; /** * If specified then AutoSizer will not be used and instead a fixed height @@ -53,7 +53,8 @@ function VirtualListInner({ onScroll = noop, outerRef, fixedHeight, -}: VirtualListProps, ref: ForwardedRef) { + forwardedRef, +}: VirtualListProps & { forwardedRef?: ForwardedRef }) { const [overscanCount, setOverscanCount] = useState(initialOffset); const listRef = createRef(); const prevItems = useRef(items); @@ -75,7 +76,7 @@ function VirtualListInner({ }), [selectedItemId, [items]]); const getItemSize = (index: number) => rowHeights[index]; - useImperativeHandle(ref, () => ({ + useImperativeHandle(forwardedRef, () => ({ scrollToItem: (index, align) => listRef.current?.scrollToItem(index, align), })); @@ -130,13 +131,9 @@ function VirtualListInner({ ); } -const ForwardedVirtualList = forwardRef(VirtualListInner); - -export function VirtualList( - props: PropsWithoutRef> & { ref?: RefObject }, -) { - return ; -} +export const VirtualList = forwardRef>((props, ref) => ( + +)) as (props: VirtualListProps & { ref?: ForwardedRef }) => JSX.Element; interface RowData { items: T[];