Merge remote-tracking branch 'origin/redux-toolkit-move' into rtm-temp

This commit is contained in:
Shekar Siri 2024-09-20 11:25:33 +05:30
commit 70293cd8de
11 changed files with 84 additions and 190 deletions

View file

@ -1,8 +1,7 @@
import React, { useMemo, useContext, useState, useRef } from 'react'; import React, { useMemo, useContext, useState, useRef } from 'react';
import { connect } from 'react-redux'; import { useStore } from 'App/mstore';
import TimeTracker from 'Components/Session_/Player/Controls/TimeTracker'; import TimeTracker from 'Components/Session_/Player/Controls/TimeTracker';
import stl from 'Components/Session_/Player/Controls/timeline.module.css'; import stl from 'Components/Session_/Player/Controls/timeline.module.css';
import { setTimelinePointer, setTimelineHoverTime } from 'Duck/sessions';
import DraggableCircle from 'Components/Session_/Player/Controls/components/DraggableCircle'; import DraggableCircle from 'Components/Session_/Player/Controls/components/DraggableCircle';
import CustomDragLayer, { OnDragCallback } from 'Components/Session_/Player/Controls/components/CustomDragLayer'; import CustomDragLayer, { OnDragCallback } from 'Components/Session_/Player/Controls/components/CustomDragLayer';
import { debounce } from 'App/utils'; import { debounce } from 'App/utils';
@ -11,13 +10,11 @@ import { PlayerContext, ILivePlayerContext } from 'App/components/Session/player
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { Duration } from 'luxon'; import { Duration } from 'luxon';
interface IProps { function Timeline() {
setTimelineHoverTime: (t: number) => void const { sessionStore } = useStore();
startedAt: number const startedAt = sessionStore.current.startedAt ?? 0;
tooltipVisible: boolean const tooltipVisible = sessionStore.timeLineTooltip.isVisible;
} const setTimelineHoverTime = sessionStore.setTimelineTooltip;
function Timeline(props: IProps) {
// @ts-ignore // @ts-ignore
const { player, store } = useContext<ILivePlayerContext>(PlayerContext) const { player, store } = useContext<ILivePlayerContext>(PlayerContext)
const [wasPlaying, setWasPlaying] = useState(false) const [wasPlaying, setWasPlaying] = useState(false)
@ -35,7 +32,7 @@ function Timeline(props: IProps) {
const scale = 100 / endTime; const scale = 100 / endTime;
const debouncedJump = useMemo(() => debounce(player.jump, 500), []) const debouncedJump = useMemo(() => debounce(player.jump, 500), [])
const debouncedTooltipChange = useMemo(() => debounce(props.setTimelineHoverTime, 50), []) const debouncedTooltipChange = useMemo(() => debounce(setTimelineHoverTime, 50), [])
const onDragEnd = () => { const onDragEnd = () => {
if (!liveTimeTravel) return; if (!liveTimeTravel) return;
@ -59,7 +56,7 @@ function Timeline(props: IProps) {
}; };
const getLiveTime = (e: React.MouseEvent) => { const getLiveTime = (e: React.MouseEvent) => {
const duration = new Date().getTime() - props.startedAt; const duration = new Date().getTime() - startedAt;
// @ts-ignore type mismatch from react? // @ts-ignore type mismatch from react?
const p = e.nativeEvent.offsetX / e.target.offsetWidth; const p = e.nativeEvent.offsetX / e.target.offsetWidth;
const time = Math.max(Math.round(p * duration), 0); const time = Math.max(Math.round(p * duration), 0);
@ -69,7 +66,7 @@ function Timeline(props: IProps) {
const showTimeTooltip = (e: React.MouseEvent<HTMLDivElement>) => { const showTimeTooltip = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.target !== progressRef.current && e.target !== timelineRef.current) { if (e.target !== progressRef.current && e.target !== timelineRef.current) {
return props.tooltipVisible && hideTimeTooltip(); return tooltipVisible && hideTimeTooltip();
} }
const [time, duration] = getLiveTime(e); const [time, duration] = getLiveTime(e);
@ -136,7 +133,7 @@ function Timeline(props: IProps) {
onMouseEnter={showTimeTooltip} onMouseEnter={showTimeTooltip}
onMouseLeave={hideTimeTooltip} onMouseLeave={hideTimeTooltip}
> >
<TooltipContainer live /> <TooltipContainer />
<DraggableCircle <DraggableCircle
left={time * scale} left={time * scale}
onDrop={onDragEnd} onDrop={onDragEnd}
@ -156,10 +153,4 @@ function Timeline(props: IProps) {
) )
} }
export default connect( export default observer(Timeline)
(state: any) => ({
startedAt: state.getIn(['sessions', 'current']).startedAt || 0,
tooltipVisible: state.getIn(['sessions', 'timeLineTooltip', 'isVisible']),
}),
{ setTimelinePointer, setTimelineHoverTime }
)(observer(Timeline))

View file

@ -1,9 +1,8 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { sessions as sessionsRoute, liveSession as liveSessionRoute, withSiteId } from 'App/routes'; import { sessions as sessionsRoute, withSiteId } from 'App/routes';
import { BackLink, Link } from 'UI'; import { BackLink } from 'UI';
import { toggleFavorite, setSessionPath } from 'Duck/sessions';
import cn from 'classnames'; import cn from 'classnames';
import SessionMetaList from 'Shared/SessionItem/SessionMetaList'; import SessionMetaList from 'Shared/SessionItem/SessionMetaList';
import UserCard from '../ReplayPlayer/EventsBlock/UserCard'; import UserCard from '../ReplayPlayer/EventsBlock/UserCard';
@ -23,10 +22,10 @@ function PlayerBlockHeader(props: any) {
const playerState = store?.get?.() || { width: 0, height: 0, showEvents: false }; const playerState = store?.get?.() || { width: 0, height: 0, showEvents: false };
const { width = 0, height = 0, showEvents = false } = playerState; const { width = 0, height = 0, showEvents = false } = playerState;
const { customFieldStore, projectsStore } = useStore(); const { customFieldStore, projectsStore, sessionStore } = useStore();
const session = sessionStore.current;
const siteId = projectsStore.siteId!; const siteId = projectsStore.siteId!;
const { const {
session,
fullscreen, fullscreen,
metaList, metaList,
setActiveTab, setActiveTab,
@ -100,18 +99,12 @@ function PlayerBlockHeader(props: any) {
const PlayerHeaderCont = connect( const PlayerHeaderCont = connect(
(state: any) => { (state: any) => {
const session = state.getIn(['sessions', 'current']);
return { return {
session,
sessionPath: state.getIn(['sessions', 'sessionPath']),
funnelRef: state.getIn(['funnels', 'navRef']), funnelRef: state.getIn(['funnels', 'navRef']),
metaList: state.getIn(['customFields', 'list']).map((i: any) => i.key), metaList: state.getIn(['customFields', 'list']).map((i: any) => i.key),
}; };
}, },
{ {
toggleFavorite,
setSessionPath,
} }
)(observer(PlayerBlockHeader)); )(observer(PlayerBlockHeader));

View file

@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux';
import { findDOMNode } from 'react-dom'; import { findDOMNode } from 'react-dom';
import cn from 'classnames'; import cn from 'classnames';
import { EscapeButton } from 'UI'; import { EscapeButton } from 'UI';
@ -18,7 +17,6 @@ import { MobileExceptions } from 'Components/Session_/Exceptions/Exceptions';
import MobileControls from './MobileControls'; import MobileControls from './MobileControls';
import Overlay from './MobileOverlay' import Overlay from './MobileOverlay'
import stl from 'Components/Session_/Player/player.module.css'; import stl from 'Components/Session_/Player/player.module.css';
import { updateLastPlayedSession } from 'Duck/sessions';
import { MobileOverviewPanel } from 'Components/Session_/OverviewPanel'; import { MobileOverviewPanel } from 'Components/Session_/OverviewPanel';
import MobileConsolePanel from 'Shared/DevTools/ConsolePanel/MobileConsolePanel'; import MobileConsolePanel from 'Shared/DevTools/ConsolePanel/MobileConsolePanel';
import { MobilePlayerContext } from 'App/components/Session/playerContext'; import { MobilePlayerContext } from 'App/components/Session/playerContext';
@ -32,32 +30,28 @@ import { useStore } from 'App/mstore';
interface IProps { interface IProps {
fullView: boolean; fullView: boolean;
isMultiview?: boolean; isMultiview?: boolean;
nextId: string;
sessionId: string;
activeTab: string; activeTab: string;
updateLastPlayedSession: (id: string) => void
videoURL: string[];
setActiveTab: (tab: string) => void; setActiveTab: (tab: string) => void;
userDevice: string; bottomBlock: any;
screenWidth: number; fullscreen?: boolean;
screenHeight: number;
platform: string;
} }
function Player(props: IProps) { function Player(props: IProps) {
const defaultHeight = getDefaultPanelHeight() const defaultHeight = getDefaultPanelHeight()
const [panelHeight, setPanelHeight] = React.useState(defaultHeight); const [panelHeight, setPanelHeight] = React.useState(defaultHeight);
const { const {
nextId,
activeTab, activeTab,
fullView, fullView,
videoURL,
userDevice,
screenWidth,
screenHeight,
platform,
} = props; } = props;
const { uiPlayerStore } = useStore(); const { uiPlayerStore, sessionStore } = useStore();
const nextId = sessionStore.nextId;
const sessionId = sessionStore.current.sessionId;
const userDevice = sessionStore.current.userDevice;
const videoURL = sessionStore.current.videoURL;
const platform = sessionStore.current.platform;
const screenWidth = sessionStore.current.screenWidth!;
const screenHeight = sessionStore.current.screenHeight!;
const updateLastPlayedSession = sessionStore.updateLastPlayedSession;
const fullscreenOff = uiPlayerStore.fullscreenOff; const fullscreenOff = uiPlayerStore.fullscreenOff;
const fullscreen = uiPlayerStore.fullscreen; const fullscreen = uiPlayerStore.fullscreen;
const bottomBlock = uiPlayerStore.bottomBlock; const bottomBlock = uiPlayerStore.bottomBlock;
@ -68,7 +62,7 @@ function Player(props: IProps) {
const [isAttached, setAttached] = React.useState(false); const [isAttached, setAttached] = React.useState(false);
React.useEffect(() => { React.useEffect(() => {
props.updateLastPlayedSession(props.sessionId); updateLastPlayedSession(sessionId);
const parentElement = findDOMNode(screenWrapper.current) as HTMLDivElement | null; //TODO: good architecture const parentElement = findDOMNode(screenWrapper.current) as HTMLDivElement | null; //TODO: good architecture
if (parentElement && !isAttached) { if (parentElement && !isAttached) {
playerContext.player.attach(parentElement); playerContext.player.attach(parentElement);
@ -166,17 +160,4 @@ function Player(props: IProps) {
); );
} }
export default connect( export default observer(Player);
(state: any) => ({
nextId: state.getIn(['sessions', 'nextId']),
sessionId: state.getIn(['sessions', 'current']).sessionId,
userDevice: state.getIn(['sessions', 'current']).userDevice,
videoURL: state.getIn(['sessions', 'current']).videoURL,
platform: state.getIn(['sessions', 'current']).platform,
screenWidth: state.getIn(['sessions', 'current']).screenWidth,
screenHeight: state.getIn(['sessions', 'current']).screenHeight,
}),
{
updateLastPlayedSession,
}
)(observer(Player));

View file

@ -8,7 +8,6 @@ import {
withSiteId, withSiteId,
} from 'App/routes'; } from 'App/routes';
import { BackLink, Link } from 'UI'; import { BackLink, Link } from 'UI';
import { toggleFavorite, setSessionPath } from 'Duck/sessions';
import cn from 'classnames'; import cn from 'classnames';
import SessionMetaList from 'Shared/SessionItem/SessionMetaList'; import SessionMetaList from 'Shared/SessionItem/SessionMetaList';
import UserCard from './EventsBlock/UserCard'; import UserCard from './EventsBlock/UserCard';
@ -20,24 +19,23 @@ import { IFRAME } from 'App/constants/storageKeys';
const SESSIONS_ROUTE = sessionsRoute(); const SESSIONS_ROUTE = sessionsRoute();
// TODO props
function PlayerBlockHeader(props: any) { function PlayerBlockHeader(props: any) {
const [hideBack, setHideBack] = React.useState(false); const [hideBack, setHideBack] = React.useState(false);
const { player, store } = React.useContext(PlayerContext); const { player, store } = React.useContext(PlayerContext);
const { uxtestingStore, customFieldStore, projectsStore } = useStore() const { uxtestingStore, customFieldStore, projectsStore, sessionStore } = useStore()
const session = sessionStore.current;
const sessionPath = sessionStore.sessionPath;
const siteId = projectsStore.siteId!; const siteId = projectsStore.siteId!;
const playerState = store?.get?.() || { width: 0, height: 0, showEvents: false } const playerState = store?.get?.() || { width: 0, height: 0, showEvents: false }
const { width = 0, height = 0, showEvents = false } = playerState const { width = 0, height = 0, showEvents = false } = playerState
const { const {
session,
fullscreen, fullscreen,
metaList, metaList,
closedLive = false, closedLive = false,
setActiveTab, setActiveTab,
activeTab, activeTab,
history, history,
sessionPath,
} = props; } = props;
React.useEffect(() => { React.useEffect(() => {
@ -130,19 +128,12 @@ function PlayerBlockHeader(props: any) {
const PlayerHeaderCont = connect( const PlayerHeaderCont = connect(
(state: any) => { (state: any) => {
const session = state.getIn(['sessions', 'current']);
return { return {
session,
sessionPath: state.getIn(['sessions', 'sessionPath']),
funnelRef: state.getIn(['funnels', 'navRef']), funnelRef: state.getIn(['funnels', 'navRef']),
metaList: state.getIn(['customFields', 'list']).map((i: any) => i.key), metaList: state.getIn(['customFields', 'list']).map((i: any) => i.key),
}; };
}, },
{
toggleFavorite,
setSessionPath,
}
)(observer(PlayerBlockHeader)); )(observer(PlayerBlockHeader));
export default withRouter(PlayerHeaderCont); export default withRouter(PlayerHeaderCont);

View file

@ -10,7 +10,6 @@ import { VList, VListHandle } from 'virtua';
import { PlayerContext } from 'App/components/Session/playerContext'; import { PlayerContext } from 'App/components/Session/playerContext';
import { RootStore } from 'App/duck'; import { RootStore } from 'App/duck';
import { useStore } from 'App/mstore'; import { useStore } from 'App/mstore';
import { filterOutNote, setEventFilter } from 'Duck/sessions';
import { Icon } from 'UI'; import { Icon } from 'UI';
import EventGroupWrapper from './EventGroupWrapper'; import EventGroupWrapper from './EventGroupWrapper';
@ -18,19 +17,19 @@ import EventSearch from './EventSearch/EventSearch';
import styles from './eventsBlock.module.css'; import styles from './eventsBlock.module.css';
interface IProps { interface IProps {
setEventFilter: (filter: { query: string }) => void;
filteredEvents: InjectedEvent[];
setActiveTab: (tab?: string) => void; setActiveTab: (tab?: string) => void;
query: string;
events: Session['events'];
notesWithEvents: Session['notesWithEvents'];
filterOutNote: (id: string) => void;
eventsIndex: number[];
uxtVideo: string;
} }
function EventsBlock(props: IProps) { function EventsBlock(props: IProps) {
const { notesStore, uxtestingStore, uiPlayerStore } = useStore(); const { notesStore, uxtestingStore, uiPlayerStore, sessionStore } = useStore();
const session = sessionStore.current;
const notesWithEvents = session.notesWithEvents;
const uxtVideo = session.uxtVideo;
const filteredEvents = sessionStore.filteredEvents;
const query = sessionStore.eventsQuery;
const eventsIndex = sessionStore.eventsIndex;
const setEventFilter = sessionStore.setEventQuery;
const filterOutNote = sessionStore.filterOutNote;
const [mouseOver, setMouseOver] = React.useState(false); const [mouseOver, setMouseOver] = React.useState(false);
const scroller = React.useRef<VListHandle>(null); const scroller = React.useRef<VListHandle>(null);
const zoomEnabled = uiPlayerStore.timelineZoom.enabled; const zoomEnabled = uiPlayerStore.timelineZoom.enabled;
@ -47,12 +46,7 @@ function EventsBlock(props: IProps) {
} = store.get(); } = store.get();
const { const {
filteredEvents,
eventsIndex,
filterOutNote,
query,
setActiveTab, setActiveTab,
notesWithEvents = [],
} = props; } = props;
const notes = notesStore.sessionNotes; const notes = notesStore.sessionNotes;
@ -129,7 +123,7 @@ function EventsBlock(props: IProps) {
const write = ({ const write = ({
target: { value }, target: { value },
}: React.ChangeEvent<HTMLInputElement>) => { }: React.ChangeEvent<HTMLInputElement>) => {
props.setEventFilter({ query: value }); setEventFilter({ query: value });
setTimeout(() => { setTimeout(() => {
if (!scroller.current) return; if (!scroller.current) return;
@ -139,7 +133,7 @@ function EventsBlock(props: IProps) {
}; };
const clearSearch = () => { const clearSearch = () => {
props.setEventFilter({ query: '' }); setEventFilter({ query: '' });
setTimeout(() => { setTimeout(() => {
if (!scroller.current) return; if (!scroller.current) return;
@ -163,7 +157,7 @@ function EventsBlock(props: IProps) {
const onEventClick = (_: React.MouseEvent, event: { time: number }) => { const onEventClick = (_: React.MouseEvent, event: { time: number }) => {
player.jump(event.time); player.jump(event.time);
props.setEventFilter({ query: '' }); setEventFilter({ query: '' });
}; };
const onMouseOver = () => setMouseOver(true); const onMouseOver = () => setMouseOver(true);
const onMouseLeave = () => setMouseOver(false); const onMouseLeave = () => setMouseOver(false);
@ -213,7 +207,7 @@ function EventsBlock(props: IProps) {
muted muted
autoPlay autoPlay
controls controls
src={props.uxtVideo} src={uxtVideo}
width={240} width={240}
/> />
<div <div
@ -265,18 +259,4 @@ function EventsBlock(props: IProps) {
); );
} }
export default connect( export default observer(EventsBlock);
(state: RootStore) => ({
session: state.getIn(['sessions', 'current']),
notesWithEvents: state.getIn(['sessions', 'current']).notesWithEvents,
events: state.getIn(['sessions', 'current']).events,
uxtVideo: state.getIn(['sessions', 'current']).uxtVideo,
filteredEvents: state.getIn(['sessions', 'filteredEvents']),
query: state.getIn(['sessions', 'eventsQuery']),
eventsIndex: state.getIn(['sessions', 'eventsIndex']),
}),
{
setEventFilter,
filterOutNote,
}
)(observer(EventsBlock));

View file

@ -1,8 +1,6 @@
import DraggableMarkers from 'Components/Session_/Player/Controls/components/ZoomDragLayer'; import DraggableMarkers from 'Components/Session_/Player/Controls/components/ZoomDragLayer';
import React, { useEffect, useMemo, useContext, useState, useRef } from 'react'; import React, { useEffect, useMemo, useContext, useState, useRef } from 'react';
import { connect } from 'react-redux';
import stl from './timeline.module.css'; import stl from './timeline.module.css';
import { setTimelinePointer, setTimelineHoverTime } from 'Duck/sessions';
import CustomDragLayer, { OnDragCallback } from './components/CustomDragLayer'; import CustomDragLayer, { OnDragCallback } from './components/CustomDragLayer';
import { debounce } from 'App/utils'; import { debounce } from 'App/utils';
import TooltipContainer from './components/TooltipContainer'; import TooltipContainer from './components/TooltipContainer';
@ -10,18 +8,12 @@ import { PlayerContext } from 'App/components/Session/playerContext';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { useStore } from 'App/mstore'; import { useStore } from 'App/mstore';
import { DateTime, Duration } from 'luxon'; import { DateTime, Duration } from 'luxon';
import Issue from 'Types/session/issue';
import { WebEventsList, MobEventsList } from './EventsList'; import { WebEventsList, MobEventsList } from './EventsList';
import NotesList from './NotesList'; import NotesList from './NotesList';
import SkipIntervalsList from './SkipIntervalsList'; import SkipIntervalsList from './SkipIntervalsList';
import TimelineTracker from 'Components/Session_/Player/Controls/TimelineTracker'; import TimelineTracker from 'Components/Session_/Player/Controls/TimelineTracker';
interface IProps { interface IProps {
issues: Issue[];
setTimelineHoverTime: (t: number) => void;
startedAt: number;
tooltipVisible: boolean;
timezone?: string;
isMobile?: boolean; isMobile?: boolean;
} }
@ -29,10 +21,14 @@ function Timeline(props: IProps) {
const { player, store } = useContext(PlayerContext); const { player, store } = useContext(PlayerContext);
const [wasPlaying, setWasPlaying] = useState(false); const [wasPlaying, setWasPlaying] = useState(false);
const [maxWidth, setMaxWidth] = useState(0); const [maxWidth, setMaxWidth] = useState(0);
const { settingsStore, uiPlayerStore } = useStore(); const { settingsStore, uiPlayerStore, sessionStore } = useStore();
const startedAt = sessionStore.current.startedAt ?? 0;
const tooltipVisible = sessionStore.timeLineTooltip.isVisible;
const setTimelineHoverTime = sessionStore.setTimelineTooltip;
const timezone = sessionStore.current.timezone;
const issues = sessionStore.current.issues;
const timelineZoomEnabled = uiPlayerStore.timelineZoom.enabled; const timelineZoomEnabled = uiPlayerStore.timelineZoom.enabled;
const { playing, skipToIssue, ready, endTime, devtoolsLoading, domLoading } = store.get(); const { playing, skipToIssue, ready, endTime, devtoolsLoading, domLoading } = store.get();
const { issues, timezone } = props;
const progressRef = useRef<HTMLDivElement>(null); const progressRef = useRef<HTMLDivElement>(null);
const timelineRef = useRef<HTMLDivElement>(null); const timelineRef = useRef<HTMLDivElement>(null);
@ -51,7 +47,7 @@ function Timeline(props: IProps) {
}, []); }, []);
const debouncedJump = useMemo(() => debounce(player.jump, 500), []); const debouncedJump = useMemo(() => debounce(player.jump, 500), []);
const debouncedTooltipChange = useMemo(() => debounce(props.setTimelineHoverTime, 50), []); const debouncedTooltipChange = useMemo(() => debounce(setTimelineHoverTime, 50), []);
const onDragEnd = () => { const onDragEnd = () => {
if (wasPlaying) { if (wasPlaying) {
@ -78,17 +74,17 @@ function Timeline(props: IProps) {
// @ts-ignore black magic // @ts-ignore black magic
!progressRef.current.contains(e.target) !progressRef.current.contains(e.target)
) { ) {
return props.tooltipVisible && hideTimeTooltip(); return tooltipVisible && hideTimeTooltip();
} }
const time = getTime(e); const time = getTime(e);
if (!time) return; if (!time) return;
const tz = settingsStore.sessionSettings.timezone.value; const tz = settingsStore.sessionSettings.timezone.value;
const timeStr = DateTime.fromMillis(props.startedAt + time) const timeStr = DateTime.fromMillis(startedAt + time)
.setZone(tz) .setZone(tz)
.toFormat(`hh:mm:ss a`); .toFormat(`hh:mm:ss a`);
const userTimeStr = timezone const userTimeStr = timezone
? DateTime.fromMillis(props.startedAt + time) ? DateTime.fromMillis(startedAt + time)
.setZone(timezone) .setZone(timezone)
.toFormat(`hh:mm:ss a`) .toFormat(`hh:mm:ss a`)
: undefined; : undefined;
@ -177,12 +173,4 @@ function Timeline(props: IProps) {
); );
} }
export default connect( export default observer(Timeline);
(state: any) => ({
issues: state.getIn(['sessions', 'current']).issues || [],
startedAt: state.getIn(['sessions', 'current']).startedAt || 0,
timezone: state.getIn(['sessions', 'current']).timezone,
tooltipVisible: state.getIn(['sessions', 'timeLineTooltip', 'isVisible']),
}),
{ setTimelinePointer, setTimelineHoverTime }
)(observer(Timeline));

View file

@ -12,16 +12,13 @@ import {
iTag, iTag,
tagProps, tagProps,
} from 'App/services/NotesService'; } from 'App/services/NotesService';
import { addNote, updateNote } from 'Duck/sessions';
import { Button, Checkbox, Icon } from 'UI'; import { Button, Checkbox, Icon } from 'UI';
import Select from 'Shared/Select'; import Select from 'Shared/Select';
interface Props { interface Props {
time: number; time: number;
addNote: (note: Note) => void;
updateNote: (note: Note) => void; updateNote: (note: Note) => void;
sessionId: string;
isEdit?: boolean; isEdit?: boolean;
editNote?: WriteNote; editNote?: WriteNote;
hideModal: () => void; hideModal: () => void;
@ -29,13 +26,13 @@ interface Props {
function CreateNote({ function CreateNote({
time, time,
sessionId,
isEdit, isEdit,
editNote, editNote,
updateNote,
hideModal, hideModal,
}: Props) { }: Props) {
const { notesStore, integrationsStore } = useStore(); const { notesStore, integrationsStore, sessionStore } = useStore();
const sessionId = sessionStore.current.sessionId;
const updateNote = sessionStore.updateNote;
const slackChannels = integrationsStore.slack.list; const slackChannels = integrationsStore.slack.list;
const fetchSlack = integrationsStore.slack.fetchIntegrations; const fetchSlack = integrationsStore.slack.fetchIntegrations;
const teamsChannels = integrationsStore.msteams.list; const teamsChannels = integrationsStore.msteams.list;
@ -323,10 +320,4 @@ function CreateNote({
); );
} }
export default connect( export default observer(CreateNote);
(state: any) => {
const sessionId = state.getIn(['sessions', 'current']).sessionId;
return { sessionId };
},
{ addNote, updateNote,}
)(observer(CreateNote));

View file

@ -1,6 +1,5 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setAutoplayValues } from 'Duck/sessions';
import { withSiteId, session as sessionRoute } from 'App/routes'; import { withSiteId, session as sessionRoute } from 'App/routes';
import AutoplayToggle from 'Shared/AutoplayToggle/AutoplayToggle'; import AutoplayToggle from 'Shared/AutoplayToggle/AutoplayToggle';
import { withRouter, RouteComponentProps } from 'react-router-dom'; import { withRouter, RouteComponentProps } from 'react-router-dom';
@ -12,24 +11,21 @@ import { useStore } from 'App/mstore';
const PER_PAGE = 10; const PER_PAGE = 10;
interface Props extends RouteComponentProps { interface Props extends RouteComponentProps {
previousId: string;
nextId: string;
defaultList: any; defaultList: any;
currentPage: number; currentPage: number;
total: number;
setAutoplayValues: () => void;
latestRequestTime: any; latestRequestTime: any;
sessionIds: any; sessionIds: any;
} }
function QueueControls(props: Props) { function QueueControls(props: Props) {
const { projectsStore } = useStore(); const { projectsStore, sessionStore, searchStore } = useStore();
const previousId = sessionStore.previousId;
const nextId = sessionStore.nextId;
const total = sessionStore.total;
const sessionIds = sessionStore.sessionIds ?? [];
const setAutoplayValues = sessionStore.setAutoplayValues;
const { const {
previousId,
nextId,
currentPage, currentPage,
total,
sessionIds,
latestRequestTime, latestRequestTime,
match: { match: {
// @ts-ignore // @ts-ignore
@ -37,19 +33,15 @@ function QueueControls(props: Props) {
} }
} = props; } = props;
const { searchStore } = useStore();
const disabled = sessionIds.length === 0;
useEffect(() => { useEffect(() => {
if (latestRequestTime) { if (latestRequestTime) {
props.setAutoplayValues(); setAutoplayValues();
const totalPages = Math.ceil(total / PER_PAGE); const totalPages = Math.ceil(total / PER_PAGE);
const index = sessionIds.indexOf(sessionId); const index = sessionIds.indexOf(sessionId);
// check for the last page and load the next // check for the last page and load the next
if (currentPage !== totalPages && index === sessionIds.length - 1) { if (currentPage !== totalPages && index === sessionIds.length - 1) {
searchStore.fetchAutoplaySessions(currentPage + 1).then(props.setAutoplayValues); searchStore.fetchAutoplaySessions(currentPage + 1).then(setAutoplayValues);
} }
} }
}, []); }, []);
@ -107,12 +99,7 @@ function QueueControls(props: Props) {
export default connect( export default connect(
(state: any) => ({ (state: any) => ({
previousId: state.getIn(['sessions', 'previousId']),
nextId: state.getIn(['sessions', 'nextId']),
currentPage: state.getIn(['search', 'currentPage']) || 1, currentPage: state.getIn(['search', 'currentPage']) || 1,
total: state.getIn(['sessions', 'total']) || 0,
sessionIds: state.getIn(['sessions', 'sessionIds']) || [],
latestRequestTime: state.getIn(['search', 'latestRequestTime']) latestRequestTime: state.getIn(['search', 'latestRequestTime'])
}), }),
{ setAutoplayValues }
)(withRouter(QueueControls)); )(withRouter(QueueControls));

View file

@ -3,20 +3,21 @@ import { BookmarkCheck, Bookmark as BookmarkIcn, Vault } from 'lucide-react';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { useStore } from 'App/mstore';
import { toggleFavorite } from 'Duck/sessions'; import { observer } from 'mobx-react-lite';
interface Props { interface Props {
toggleFavorite: (sessionId: string) => Promise<void>;
favorite: boolean;
sessionId: any; sessionId: any;
isEnterprise: boolean; isEnterprise: boolean;
noMargin?: boolean;
} }
function Bookmark(props: Props) { function Bookmark(props: Props) {
const { sessionId, favorite, isEnterprise, noMargin } = props; const { sessionStore } = useStore();
const favorite = sessionStore.current.favorite;
const onToggleFavorite = sessionStore.toggleFavorite;
const { sessionId, isEnterprise } = props;
const [isFavorite, setIsFavorite] = useState(favorite); const [isFavorite, setIsFavorite] = useState(favorite);
const ADDED_MESSAGE = isEnterprise const ADDED_MESSAGE = isEnterprise
? 'Session added to vault' ? 'Session added to vault'
: 'Session added to your bookmarks'; : 'Session added to your bookmarks';
@ -33,7 +34,7 @@ function Bookmark(props: Props) {
}, [favorite]); }, [favorite]);
const toggleFavorite = async () => { const toggleFavorite = async () => {
props.toggleFavorite(sessionId).then(() => { onToggleFavorite(sessionId).then(() => {
toast.success(isFavorite ? REMOVED_MESSAGE : ADDED_MESSAGE); toast.success(isFavorite ? REMOVED_MESSAGE : ADDED_MESSAGE);
setIsFavorite(!isFavorite); setIsFavorite(!isFavorite);
}); });
@ -65,8 +66,6 @@ function Bookmark(props: Props) {
export default connect( export default connect(
(state: any) => ({ (state: any) => ({
isEnterprise: state.getIn(['user', 'account', 'edition']) === 'ee', isEnterprise: state.getIn(['user', 'account', 'edition']) === 'ee',
favorite: state.getIn(['sessions', 'current']).favorite, }),
}), )(observer(Bookmark));
{ toggleFavorite }
)(Bookmark);

View file

@ -70,7 +70,7 @@ export default class SessionStore {
visitedEvents: Location[] = []; visitedEvents: Location[] = [];
insights: any[] = []; insights: any[] = [];
host = ''; host = '';
sessionPath = {}; sessionPath: Record<string, any> = {};
lastPlayedSessionId: string = ''; lastPlayedSessionId: string = '';
timeLineTooltip = { timeLineTooltip = {
time: 0, time: 0,
@ -421,16 +421,6 @@ export default class SessionStore {
}); });
} }
// Add Note
addNote(note: Note) {
this.current.notesWithEvents.push(note);
this.current.notesWithEvents.sort((a, b) => {
const aTs = a.time || a.timestamp;
const bTs = b.time || b.timestamp;
return aTs - bTs;
});
}
// Update Note // Update Note
updateNote(note: Note) { updateNote(note: Note) {
const noteIndex = this.current.notesWithEvents.findIndex((item) => { const noteIndex = this.current.notesWithEvents.findIndex((item) => {
@ -450,7 +440,6 @@ export default class SessionStore {
this.sessionPath = path; this.sessionPath = path;
} }
// Update Last Played Session
updateLastPlayedSession(sessionId: string) { updateLastPlayedSession(sessionId: string) {
const sIndex = this.list.findIndex((s) => s.sessionId === sessionId); const sIndex = this.list.findIndex((s) => s.sessionId === sessionId);
if (sIndex !== -1) { if (sIndex !== -1) {

View file

@ -174,6 +174,7 @@ export default class Session {
duration: Duration; duration: Duration;
durationMs: ISession['durationMs']; durationMs: ISession['durationMs'];
events: ISession['events']; events: ISession['events'];
uxtVideo?: any;
stackEvents: ISession['stackEvents']; stackEvents: ISession['stackEvents'];
metadata: ISession['metadata']; metadata: ISession['metadata'];
favorite: ISession['favorite']; favorite: ISession['favorite'];
@ -228,6 +229,9 @@ export default class Session {
fileKey: ISession['fileKey']; fileKey: ISession['fileKey'];
durationSeconds: number; durationSeconds: number;
liveOnly: boolean; liveOnly: boolean;
videoURL: string[]
screenWidth?: number
screenHeight?: number
constructor(plainSession?: ISession) { constructor(plainSession?: ISession) {
const sessionData = plainSession || (emptyValues as unknown as ISession); const sessionData = plainSession || (emptyValues as unknown as ISession);