diff --git a/frontend/app/components/Session_/EventsBlock/EventsBlock.js b/frontend/app/components/Session_/EventsBlock/EventsBlock.js index acace84ed..8e82ecdd6 100644 --- a/frontend/app/components/Session_/EventsBlock/EventsBlock.js +++ b/frontend/app/components/Session_/EventsBlock/EventsBlock.js @@ -11,20 +11,20 @@ import EventGroupWrapper from './EventGroupWrapper'; import styles from './eventsBlock.module.css'; import EventSearch from './EventSearch/EventSearch'; -@connect(state => ({ +@connect(state => ({ session: state.getIn([ 'sessions', 'current' ]), filteredEvents: state.getIn([ 'sessions', 'filteredEvents' ]), eventsIndex: state.getIn([ 'sessions', 'eventsIndex' ]), selectedEvents: state.getIn([ 'events', 'selected' ]), targetDefinerDisplayed: state.getIn([ 'components', 'targetDefiner', 'isDisplayed' ]), - testsAvaliable: false, + testsAvaliable: false, }), { showTargetDefiner, setSelected, setEventFilter }) export default class EventsBlock extends React.PureComponent { - state = { + state = { editingEvent: null, mouseOver: false, query: '' @@ -36,14 +36,14 @@ export default class EventsBlock extends React.PureComponent { defaultHeight: 300 }); - write = ({ target: { value, name } }) => { + write = ({ target: { value, name } }) => { const { filter } = this.state; this.setState({ query: value }) - this.props.setEventFilter({ query: value, filter }) - - setTimeout(() => { + this.props.setEventFilter({ query: value, filter }) + + setTimeout(() => { if (!this.scroller.current) return; - + this.scroller.current.scrollToRow(0); }, 100) } @@ -55,11 +55,11 @@ export default class EventsBlock extends React.PureComponent { this.scroller.current.forceUpdateGrid(); - setTimeout(() => { + setTimeout(() => { if (!this.scroller.current) return; - + this.scroller.current.scrollToRow(0); - }, 100) + }, 100) } onSetEventFilter = (e, { name, value }) => { @@ -84,7 +84,7 @@ export default class EventsBlock extends React.PureComponent { if (!this.state.mouseOver) { this.scroller.current.scrollToRow(this.props.currentTimeEventIndex); } - } + } } onCheckboxClick(e, event) { @@ -124,7 +124,7 @@ export default class EventsBlock extends React.PureComponent { onMouseLeave = () => this.setState({ mouseOver: false }) renderGroup = ({ index, key, style, parent }) => { - const { + const { session: { events }, selectedEvents, currentTimeEventIndex, @@ -142,16 +142,16 @@ export default class EventsBlock extends React.PureComponent { const isCurrent = index === currentTimeEventIndex; const isEditing = this.state.editingEvent === event; return ( - {({measure, registerChild}) => (
- - -
+
{ `User Events (${ events.size })` }
} /> -
+
-
{({ height }) => ( - )} diff --git a/frontend/app/components/Session_/EventsBlock/UserCard/UserCard.js b/frontend/app/components/Session_/EventsBlock/UserCard/UserCard.js index c2b138044..ba987cdba 100644 --- a/frontend/app/components/Session_/EventsBlock/UserCard/UserCard.js +++ b/frontend/app/components/Session_/EventsBlock/UserCard/UserCard.js @@ -1,55 +1,113 @@ import React, { useState } from 'react' +import { connect } from 'react-redux' import { List } from 'immutable' -import { Avatar, TextEllipsis, SlideModal } from 'UI' +import { countries } from 'App/constants'; +import { browserIcon, osIcon, deviceTypeIcon } from 'App/iconNames'; +import { formatTimeOrDate, formatDateTimeDefault } from 'App/date'; +import { Avatar, TextEllipsis, SlideModal, Popup, CountryFlag, Icon } from 'UI' import cn from 'classnames' -import Metadata from '../Metadata' import { withRequest } from 'HOCs' -import SessionList from '../Metadata/SessionList' +import SessionInfoItem from '../../SessionInfoItem' -function UserCard({ className, userNumericHash, userDisplayName, similarSessions, userId, userAnonymousId, request, loading, revId }) { +function UserCard({ + className, + request, + session, + width, + height, + }) { const [showUserSessions, setShowUserSessions] = useState(false) - const hasUserDetails = !!userId || !!userAnonymousId; + const { + userBrowser, + userDevice, + userCountry, + userBrowserVersion, + userOs, + userOsVersion, + startedAt, + userId, + userAnonymousId, + userNumericHash, + userDisplayName, + userDeviceType, + revId, + } = session; + const hasUserDetails = !!userId || !!userAnonymousId; const showSimilarSessions = () => { setShowUserSessions(true); request({ key: !userId ? 'USERANONYMOUSID' : 'USERID', value: userId || userAnonymousId }); } + const getDimension = (width, height) => { + return width && height ? ( +
+ { width || 'x' } { height || 'x' } +
+ ) : Resolution N/A; + } + + const avatarbgSize = '38px' return ( -
-
- +
+
+
{ userDisplayName } + +
+ {formatDateTimeDefault(startedAt)} + · + {userBrowser}, {userDevice} + · + {countries[userCountry]} + · + More} + + content={( +
+ } label={countries[userCountry]} value={ formatTimeOrDate(startedAt) } /> + + + +
+ )} + position="bottom center" + hoverable + disabled={false} + on="hover" + /> +
{revId && ( -
+
Rev ID: {revId}
)} -
- -
- User Sessions
} isDisplayed={ showUserSessions } content={ showUserSessions && } onClose={ () => showUserSessions ? setShowUserSessions(false) : null } - /> + /> */}
) } +const component = React.memo(connect(state => ({ session: state.getIn([ 'sessions', 'current' ]) }))(UserCard)) + export default withRequest({ initialData: List(), endpoint: '/metadata/session_search', dataWrapper: data => Object.values(data), dataName: 'similarSessions', -})(UserCard) +})(component) diff --git a/frontend/app/components/Session_/PlayerBlockHeader.js b/frontend/app/components/Session_/PlayerBlockHeader.js index 1f493deac..eb656d50a 100644 --- a/frontend/app/components/Session_/PlayerBlockHeader.js +++ b/frontend/app/components/Session_/PlayerBlockHeader.js @@ -1,28 +1,25 @@ import React from 'react'; import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; -import { browserIcon, osIcon, deviceTypeIcon } from 'App/iconNames'; -import { formatTimeOrDate } from 'App/date'; import { sessions as sessionsRoute, assist as assistRoute, liveSession as liveSessionRoute, withSiteId } from 'App/routes'; -import { Button, Icon, CountryFlag, IconButton, BackLink, Popup, Link } from 'UI'; +import { Button, Icon, BackLink, Link } from 'UI'; import { toggleFavorite, setSessionPath } from 'Duck/sessions'; import cn from 'classnames'; import { connectPlayer } from 'Player'; -// import HeaderInfo from './HeaderInfo'; import SharePopup from '../shared/SharePopup/SharePopup'; -import { countries } from 'App/constants'; import SessionMetaList from 'Shared/SessionItem/SessionMetaList'; import Bookmark from 'Shared/Bookmark' +import UserCard from './EventsBlock/UserCard'; import stl from './playerBlockHeader.module.css'; import Issues from './Issues/Issues'; import Autoplay from './Autoplay'; import AssistActions from '../Assist/components/AssistActions'; import AssistTabs from '../Assist/components/AssistTabs'; -import SessionInfoItem from './SessionInfoItem' const SESSIONS_ROUTE = sessionsRoute(); const ASSIST_ROUTE = assistRoute(); + @connectPlayer(state => ({ width: state.width, height: state.height, @@ -75,23 +72,7 @@ export default class PlayerBlockHeader extends React.PureComponent { const { width, height, - session: { - sessionId, - userCountry, - userId, - userNumericHash, - favorite, - startedAt, - userBrowser, - userOs, - userOsVersion, - userDevice, - userBrowserVersion, - userDeviceType, - live, - metadata, - }, - loading, + session, disabled, jiraConfig, fullscreen, @@ -102,17 +83,31 @@ export default class PlayerBlockHeader extends React.PureComponent { } = this.props; // const _live = isAssist; - const _metaList = Object.keys(metadata).filter(i => metaList.includes(i)).map(key => { + const { + sessionId, + userId, + userNumericHash, + favorite, + live, + metadata, + } = session; + let _metaList = Object.keys(metadata).filter(i => metaList.includes(i)).map(key => { const value = metadata[key]; return { label: key, value }; }); + console.log(session.toJS()) return (
+ -
+ { isAssist && }
@@ -126,31 +121,9 @@ export default class PlayerBlockHeader extends React.PureComponent {
)} - - { isAssist && ( - <> - -
- - )} - - - } label={countries[userCountry]} value={ formatTimeOrDate(startedAt) } /> - - - -
- )} - // trigger="click" - hideOnClick={true} - > - - + + +
{ isAssist && } { !isAssist && ( @@ -184,4 +157,3 @@ export default class PlayerBlockHeader extends React.PureComponent { ); } } - diff --git a/frontend/app/components/shared/SessionItem/SessionMetaList/SessionMetaList.tsx b/frontend/app/components/shared/SessionItem/SessionMetaList/SessionMetaList.tsx index 850343110..b843134c5 100644 --- a/frontend/app/components/shared/SessionItem/SessionMetaList/SessionMetaList.tsx +++ b/frontend/app/components/shared/SessionItem/SessionMetaList/SessionMetaList.tsx @@ -13,7 +13,7 @@ interface Props { export default function SessionMetaList(props: Props) { const { className = '', metaList, maxLength = 4 } = props return ( -
+
{metaList.slice(0, maxLength).map(({ label, value }, index) => ( ))} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 966e3cbbe..b79753ca1 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -119,23 +119,32 @@ module.exports = { 'border-gray': '0 0 0 1px #999', }, keyframes: { - 'fade-in': { - '0%': { - opacity: '0', - // transform: 'translateY(-10px)' - }, - '100%': { - opacity: '1', - // transform: 'translateY(0)' - }, - } - }, - animation: { - 'fade-in': 'fade-in 0.2s ease-out' - } + 'fade-in': { + '0%': { + opacity: '0', + // transform: 'translateY(-10px)' + }, + '100%': { + opacity: '1', + // transform: 'translateY(0)' + }, + } + }, + animation: { + 'fade-in': 'fade-in 0.2s ease-out' + }, + colors: { + 'disabled-text': 'rgba(0,0,0, 0.38)', + }, + boxShadow: { + 'border-blue': `0 0 0 1px ${colors['active-blue-border']}`, + 'border-main': `0 0 0 1px ${colors['main']}`, + 'border-gray': '0 0 0 1px #999', + } }, - }, - variants: { + }, + content: [], + variants: { visibility: ['responsive', 'hover', 'focus', 'group-hover'] }, plugins: [],