diff --git a/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx index 039670377..99e141068 100644 --- a/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx +++ b/frontend/app/components/shared/DevTools/ConsolePanel/ConsolePanel.tsx @@ -5,7 +5,6 @@ import { Tabs, Input, Icon, NoContent } from 'UI'; import cn from 'classnames'; import ConsoleRow from '../ConsoleRow'; import useLatestRef from 'App/hooks/useLatestRef' -import { getRE } from 'App/utils'; import { PlayerContext } from 'App/components/Session/playerContext'; import { observer } from 'mobx-react-lite'; import { List, CellMeasurer, CellMeasurerCache, AutoSizer } from 'react-virtualized'; @@ -159,7 +158,7 @@ function ConsolePanel() { return ( diff --git a/frontend/app/components/shared/DevTools/ProfilerPanel/ProfilerPanel.tsx b/frontend/app/components/shared/DevTools/ProfilerPanel/ProfilerPanel.tsx index e95f5ada6..f5709093b 100644 --- a/frontend/app/components/shared/DevTools/ProfilerPanel/ProfilerPanel.tsx +++ b/frontend/app/components/shared/DevTools/ProfilerPanel/ProfilerPanel.tsx @@ -1,13 +1,14 @@ import React, { useState } from 'react'; -import { TextEllipsis, Input } from 'UI'; -import { getRE } from 'App/utils'; -import { PlayerContext } from 'App/components/Session/playerContext'; import { observer } from 'mobx-react-lite'; +import { TextEllipsis, Input } from 'UI'; +import { PlayerContext } from 'App/components/Session/playerContext'; +import useInputState from 'App/hooks/useInputState' import TimeTable from '../TimeTable'; import BottomBlock from '../BottomBlock'; import { useModal } from 'App/components/Modal'; import ProfilerModal from '../ProfilerModal'; +import { useRegExListFilterMemo } from '../useListFilter' const renderDuration = (p: any) => `${p.duration}ms`; const renderName = (p: any) => ; @@ -15,19 +16,12 @@ const renderName = (p: any) => ; function ProfilerPanel() { const { store } = React.useContext(PlayerContext) - const profiles = store.get().profilesList + const profiles = store.get().profilesList as any[] // TODO lest internal types const { showModal } = useModal(); - const [filter, setFilter] = useState(''); - const filtered: any = React.useMemo(() => { - const filterRE = getRE(filter, 'i'); - let list = profiles; + const [ filter, onFilterChange ] = useInputState() + const filtered = useRegExListFilterMemo(profiles, pr => pr.name, filter) - list = list.filter(({ name }: any) => (!!filter ? filterRE.test(name) : true)); - return list; - }, [filter]); - - const onFilterChange = ({ target: { value } }: any) => setFilter(value); const onRowClick = (profile: any) => { showModal(, { right: true }); }; diff --git a/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx b/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx index d1f3e9d16..42bff41ca 100644 --- a/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx +++ b/frontend/app/components/shared/DevTools/StackEventPanel/StackEventPanel.tsx @@ -1,95 +1,61 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; -import { hideHint } from 'Duck/components/player'; +import { observer } from 'mobx-react-lite'; import { Tooltip, Tabs, Input, NoContent, Icon, Toggler } from 'UI'; -import { getRE } from 'App/utils'; import { List, CellMeasurer, CellMeasurerCache, AutoSizer } from 'react-virtualized'; - +import { PlayerContext } from 'App/components/Session/playerContext'; import BottomBlock from '../BottomBlock'; -import { connectPlayer, jump } from 'Player'; import { useModal } from 'App/components/Modal'; import { useStore } from 'App/mstore'; -import { useObserver } from 'mobx-react-lite'; -import { DATADOG, SENTRY, STACKDRIVER, typeList } from 'Types/session/stackEvent'; -import { connect } from 'react-redux'; +import { typeList } from 'Types/session/stackEvent'; import StackEventRow from 'Shared/DevTools/StackEventRow'; -import StackEventModal from '../StackEventModal'; -let timeOut: any = null; -const TIMEOUT_DURATION = 5000; +import StackEventModal from '../StackEventModal'; +import useAutoscroll from '../useAutoscroll'; +import { useRegExListFilterMemo, useTabListFilterMemo } from '../useListFilter' + const INDEX_KEY = 'stackEvent'; const ALL = 'ALL'; -const TABS = [ALL, ...typeList].map((tab) => ({ text: tab, key: tab })); +const TAB_KEYS = [ ALL, ...typeList] as const +const TABS = TAB_KEYS.map((tab) => ({ text: tab, key: tab })) + +function StackEventPanel() { + const { player, store } = React.useContext(PlayerContext) + const jump = (t: number) => player.jump(t) + const { stackList: list, stackListNow: listNow } = store.get() -interface Props { - list: any; - hideHint: any; - time: any; -} -function StackEventPanel(props: Props) { - const { list, time } = props; - const additionalHeight = 0; const { sessionStore: { devTools }, } = useStore(); const { showModal } = useModal(); - const [isDetailsModalActive, setIsDetailsModalActive] = useState(false); - const [filteredList, setFilteredList] = useState([]); - const filter = useObserver(() => devTools[INDEX_KEY].filter); - const activeTab = useObserver(() => devTools[INDEX_KEY].activeTab); - const activeIndex = useObserver(() => devTools[INDEX_KEY].index); - const [pauseSync, setPauseSync] = useState(activeIndex > 0); - const synRef: any = useRef({}); - synRef.current = { - pauseSync, + const [isDetailsModalActive, setIsDetailsModalActive] = useState(false) // TODO:embed that into useModal + const filter = devTools[INDEX_KEY].filter + const activeTab = devTools[INDEX_KEY].activeTab) + const activeIndex = devTools[INDEX_KEY].index + + let filteredList = useRegExListFilterMemo(list, it => it.name, filter) + filteredList = useTabListFilterMemo(filteredList, it => it.source, ALL, activeTab) + + const onTabClick = (activeTab: typeof TAB_KEYS[number]) => devTools.update(INDEX_KEY, { activeTab }) + const onFilterChange = ({ target: { value } }: any) => devTools.update(INDEX_KEY, { filter: value }) + + const tabs = useMemo(() => + TABS.filter(({ key }) => key === ALL || list.some(({ source }) => key === source)), + [ list.length ], + ) + + const { + timeoutStartAutoscroll, + stopAutoscroll, + } = useAutoscroll( activeIndex, - }; - const _list = React.useRef(); - - const onTabClick = (activeTab: any) => devTools.update(INDEX_KEY, { activeTab }); - const onFilterChange = ({ target: { value } }: any) => { - devTools.update(INDEX_KEY, { filter: value }); - }; - - const getCurrentIndex = () => { - return filteredList.filter((item: any) => item.time <= time).length - 1; - }; - - const removePause = () => { - clearTimeout(timeOut); - setIsDetailsModalActive(false); - timeOut = setTimeout(() => { - devTools.update(INDEX_KEY, { index: getCurrentIndex() }); - setPauseSync(false); - }, TIMEOUT_DURATION); - }; - - useEffect(() => { - const currentIndex = getCurrentIndex(); - if (currentIndex !== activeIndex && !pauseSync) { - devTools.update(INDEX_KEY, { index: currentIndex }); - } - }, [time]); - + listNow.length, + index => devTools.update(INDEX_KEY, { index }) + ) + const onMouseEnter = stopAutoscroll const onMouseLeave = () => { - if (isDetailsModalActive) return; - removePause(); - }; - - React.useMemo(() => { - const filterRE = getRE(filter, 'i'); - let list = props.list; - - list = list.filter( - ({ name, source }: any) => - (!!filter ? filterRE.test(name) : true) && (activeTab === ALL || activeTab === source) - ); - - setFilteredList(list); - }, [filter, activeTab]); - - const tabs = useMemo(() => { - return TABS.filter(({ key }) => key === ALL || list.some(({ source }: any) => key === source)); - }, []); + if (isDetailsModalActive) { return } + timeoutStartAutoscroll() + } const cache = new CellMeasurerCache({ fixedWidth: true, @@ -97,11 +63,29 @@ function StackEventPanel(props: Props) { }); const showDetails = (item: any) => { - setIsDetailsModalActive(true); - showModal(, { right: true, onClose: removePause }); - devTools.update(INDEX_KEY, { index: filteredList.indexOf(item) }); - setPauseSync(true); - }; + setIsDetailsModalActive(true) + showModal( + , + { + right: true, + onClose: () => { + setIsDetailsModalActive(false) + timeoutStartAutoscroll() + } + } + ) + devTools.update(INDEX_KEY, { index: filteredList.indexOf(item) }) + stopAutoscroll() + } + + const _list = React.useRef() + useEffect(() => { + if (_list.current) { + // @ts-ignore + _list.current.scrollToRow(activeIndex) + } + }, [ activeIndex ]) + const _rowRenderer = ({ index, key, parent, style }: any) => { const item = filteredList[index]; @@ -116,7 +100,7 @@ function StackEventPanel(props: Props) { key={item.key} event={item} onJump={() => { - setPauseSync(true); + stopAutoscroll() devTools.update(INDEX_KEY, { index: filteredList.indexOf(item) }); jump(item.time); }} @@ -125,19 +109,12 @@ function StackEventPanel(props: Props) { )} ); - }; - - useEffect(() => { - if (_list.current) { - // @ts-ignore - _list.current.scrollToRow(activeIndex); - } - }, [activeIndex]); + } return ( setPauseSync(true)} + style={{ height: '300px' }} + onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} > @@ -187,16 +164,4 @@ function StackEventPanel(props: Props) { ); } -export default connect( - (state: any) => ({ - hintIsHidden: - state.getIn(['components', 'player', 'hiddenHints', 'stack']) || - !state.getIn(['site', 'list']).some((s: any) => s.stackIntegrations), - }), - { hideHint } -)( - connectPlayer((state: any) => ({ - list: state.stackList, - time: state.time, - }))(StackEventPanel) -); +export default observer(StackEventPanel)