feat(ui): player controls redesign
This commit is contained in:
parent
35d258aa8c
commit
dbae4fe353
13 changed files with 258 additions and 434 deletions
|
|
@ -20,4 +20,4 @@
|
|||
pointer-events: none;
|
||||
height: 2px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,33 @@ import cn from 'classnames';
|
|||
import { Icon } from 'UI';
|
||||
import stl from './controlButton.module.css';
|
||||
|
||||
const ControlButton = ({ label, icon, disabled=false, onClick, count = 0, hasErrors=false, active=false }) => (
|
||||
const ControlButton = ({
|
||||
label,
|
||||
icon = '',
|
||||
disabled=false,
|
||||
onClick,
|
||||
count = 0,
|
||||
hasErrors=false,
|
||||
active=false,
|
||||
size = 20,
|
||||
noLabel,
|
||||
labelClassName,
|
||||
containerClassName,
|
||||
noIcon,
|
||||
}) => (
|
||||
<button
|
||||
className={ cn(stl.controlButton, { [stl.disabled]: disabled, [stl.active]: active }) }
|
||||
className={ cn(stl.controlButton, { [stl.disabled]: disabled, [stl.active]: active }, "relative", containerClassName) }
|
||||
onClick={ onClick }
|
||||
id={"control-button-" + label.toLowerCase()}
|
||||
disabled={disabled}
|
||||
>
|
||||
<div className="relative">
|
||||
{ count > 0 && <div className={ stl.countLabel }>{ count }</div>}
|
||||
{ hasErrors && <div className={ stl.errorSymbol } /> }
|
||||
<Icon name={ icon } size="20" color="gray-dark"/>
|
||||
</div>
|
||||
<span className={ stl.label }>{ label }</span>
|
||||
{!noIcon && <Icon name={ icon } size={size} color="gray-dark"/>}
|
||||
{!noLabel && <span className={ cn(stl.label, labelClassName) }>{ label }</span>}
|
||||
</button>
|
||||
);
|
||||
|
||||
ControlButton.displayName = 'ControlButton';
|
||||
|
||||
export default ControlButton;
|
||||
export default ControlButton;
|
||||
|
|
|
|||
|
|
@ -50,15 +50,15 @@ function getStorageIconName(type) {
|
|||
function getStorageName(type) {
|
||||
switch(type) {
|
||||
case STORAGE_TYPES.REDUX:
|
||||
return "Redux";
|
||||
return "REDUX";
|
||||
case STORAGE_TYPES.MOBX:
|
||||
return "MobX";
|
||||
return "MOBX";
|
||||
case STORAGE_TYPES.VUEX:
|
||||
return "Vuex";
|
||||
return "VUEX";
|
||||
case STORAGE_TYPES.NGRX:
|
||||
return "NgRx";
|
||||
return "NGRX";
|
||||
case STORAGE_TYPES.NONE:
|
||||
return "State";
|
||||
return "STATE";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -204,25 +204,32 @@ export default class Controls extends React.Component {
|
|||
let label;
|
||||
let icon;
|
||||
if (completed) {
|
||||
label = 'Replay';
|
||||
icon = 'redo';
|
||||
} else if (playing) {
|
||||
label = 'Pause';
|
||||
icon = 'pause';
|
||||
icon = 'play-fill-new';
|
||||
} else {
|
||||
label = 'Play';
|
||||
icon = 'play';
|
||||
icon = 'pause-fill';
|
||||
}
|
||||
|
||||
return (
|
||||
<ControlButton
|
||||
disabled={ disabled }
|
||||
onClick={ this.props.togglePlay }
|
||||
icon={ icon }
|
||||
label={ label }
|
||||
/>
|
||||
);
|
||||
<div
|
||||
onClick={this.props.togglePlay}
|
||||
className="mr-2 hover-main color-gray-medium cursor-pointer rounded hover:bg-gray-light-shade"
|
||||
>
|
||||
<Icon name={icon} size="36" color="inherit" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
controlIcon = (icon, size, action, isBackwards, additionalClasses) =>
|
||||
<div
|
||||
onClick={ action }
|
||||
className={cn("py-1 px-2 color-gray-medium hover-main cursor-pointer", additionalClasses)}
|
||||
style={{ transform: isBackwards ? 'rotate(180deg)' : '' }}
|
||||
>
|
||||
<Icon name={icon} size={size} color="inherit" />
|
||||
</div>
|
||||
|
||||
render() {
|
||||
const {
|
||||
bottomBlock,
|
||||
|
|
@ -267,21 +274,42 @@ export default class Controls extends React.Component {
|
|||
<div className={ styles.buttons } data-is-live={ live }>
|
||||
<div>
|
||||
{ !live && (
|
||||
<div className={ styles.buttonsLeft }>
|
||||
<div className="flex items-center">
|
||||
{ this.renderPlayBtn() }
|
||||
<ControlButton
|
||||
onClick={ this.backTenSeconds }
|
||||
disabled={ disabled }
|
||||
label="Back"
|
||||
icon="replay-10"
|
||||
/>
|
||||
{/* <ControlButton
|
||||
disabled={ disabled }
|
||||
onClick={ this.props.toggleSkipToIssue }
|
||||
active={ skipToIssue }
|
||||
label="Skip to Issue"
|
||||
icon={skipToIssue ? 'skip-forward-fill' : 'skip-forward'}
|
||||
/> */}
|
||||
{ !live && (
|
||||
<div className="flex items-center font-semibold">
|
||||
<ReduxTime isCustom name="time" />
|
||||
<span className="px-1">/</span>
|
||||
<ReduxTime isCustom name="endTime" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="rounded ml-4 bg-active-blue border border-active-blue-border flex items-stretch">
|
||||
{this.controlIcon("skip-forward-fill", 18, this.backTenSeconds, true, 'hover:bg-active-blue-border')}
|
||||
<div className='p-1 border-l border-r bg-active-blue-border border-active-blue-border'>10s</div>
|
||||
{this.controlIcon("skip-forward-fill", 18, this.forthTenSeconds, false, 'hover:bg-active-blue-border')}
|
||||
</div>
|
||||
|
||||
{!live &&
|
||||
<div className='flex items-center mx-4'>
|
||||
<button
|
||||
className={ styles.speedButton }
|
||||
onClick={ this.props.toggleSpeed }
|
||||
data-disabled={ disabled }
|
||||
>
|
||||
<div>{ speed + 'x' }</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={ cn(styles.skipIntervalButton, { [styles.withCheckIcon]: skip }) }
|
||||
onClick={ this.props.toggleSkip }
|
||||
data-disabled={ disabled }
|
||||
>
|
||||
<span className={ styles.checkIcon } />
|
||||
{ 'Skip Inactivity' }
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -294,50 +322,59 @@ export default class Controls extends React.Component {
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div className={ styles.butonsRight }>
|
||||
{!live &&
|
||||
<React.Fragment>
|
||||
<button
|
||||
className={ styles.speedButton }
|
||||
onClick={ this.props.toggleSpeed }
|
||||
data-disabled={ disabled }
|
||||
>
|
||||
<div>{ speed + 'x' }</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={ cn(styles.skipIntervalButton, { [styles.withCheckIcon]: skip }) }
|
||||
onClick={ this.props.toggleSkip }
|
||||
data-disabled={ disabled }
|
||||
>
|
||||
<span className={ styles.checkIcon } />
|
||||
{ 'Skip Inactivity' }
|
||||
</button>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
{ !live && <div className={ styles.divider } /> }
|
||||
|
||||
<div className="flex items-center h-full">
|
||||
{ !live && <div className={cn(styles.divider, 'h-full')} /> }
|
||||
{!live && (
|
||||
<ControlButton
|
||||
disabled={ disabled && !inspectorMode }
|
||||
active={ bottomBlock === INSPECTOR }
|
||||
onClick={ toggleInspectorMode }
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
label="INSPECT"
|
||||
/>
|
||||
)}
|
||||
<ControlButton
|
||||
disabled={ disabled }
|
||||
onClick={ () => toggleBottomBlock(CONSOLE) }
|
||||
active={ bottomBlock === CONSOLE }
|
||||
label="CONSOLE"
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
count={ logCount }
|
||||
hasErrors={ logRedCount > 0 }
|
||||
/>
|
||||
{ !live &&
|
||||
<ControlButton
|
||||
disabled={ disabled }
|
||||
onClick={ () => toggleBottomBlock(NETWORK) }
|
||||
active={ bottomBlock === NETWORK }
|
||||
label="Network"
|
||||
// count={ redResourceCount }
|
||||
label="NETWORK"
|
||||
hasErrors={ resourceRedCount > 0 }
|
||||
icon="wifi"
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
/>
|
||||
}
|
||||
{ showFetch &&
|
||||
{!live &&
|
||||
<ControlButton
|
||||
disabled={ disabled }
|
||||
onClick={ () => toggleBottomBlock(PERFORMANCE) }
|
||||
active={ bottomBlock === PERFORMANCE }
|
||||
label="PERFORMANCE"
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
/>
|
||||
}
|
||||
{showFetch &&
|
||||
<ControlButton
|
||||
disabled={disabled}
|
||||
onClick={ ()=> toggleBottomBlock(FETCH) }
|
||||
active={ bottomBlock === FETCH }
|
||||
hasErrors={ fetchRedCount > 0 }
|
||||
count={ fetchCount }
|
||||
label="Fetch"
|
||||
icon="fetch"
|
||||
label="FETCH"
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
/>
|
||||
}
|
||||
{ !live && showGraphql &&
|
||||
|
|
@ -346,8 +383,9 @@ export default class Controls extends React.Component {
|
|||
onClick={ ()=> toggleBottomBlock(GRAPHQL) }
|
||||
active={ bottomBlock === GRAPHQL }
|
||||
count={ graphqlCount }
|
||||
label="GraphQL"
|
||||
icon="vendors/graphql"
|
||||
label="GRAPHQL"
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
/>
|
||||
}
|
||||
{ !live && showStorage &&
|
||||
|
|
@ -357,18 +395,8 @@ export default class Controls extends React.Component {
|
|||
active={ bottomBlock === STORAGE }
|
||||
count={ storageCount }
|
||||
label={ getStorageName(storageType) }
|
||||
icon={ getStorageIconName(storageType) }
|
||||
/>
|
||||
}
|
||||
{
|
||||
<ControlButton
|
||||
disabled={ disabled }
|
||||
onClick={ () => toggleBottomBlock(CONSOLE) }
|
||||
active={ bottomBlock === CONSOLE }
|
||||
label="Console"
|
||||
icon="console"
|
||||
count={ logCount }
|
||||
hasErrors={ logRedCount > 0 }
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
/>
|
||||
}
|
||||
{ showExceptions &&
|
||||
|
|
@ -376,8 +404,9 @@ export default class Controls extends React.Component {
|
|||
disabled={ disabled }
|
||||
onClick={ () => toggleBottomBlock(EXCEPTIONS) }
|
||||
active={ bottomBlock === EXCEPTIONS }
|
||||
label="Exceptions"
|
||||
icon="console/error"
|
||||
label="EXCEPTIONS"
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
count={ exceptionsCount }
|
||||
hasErrors={ exceptionsCount > 0 }
|
||||
/>
|
||||
|
|
@ -387,8 +416,9 @@ export default class Controls extends React.Component {
|
|||
disabled={ disabled }
|
||||
onClick={ () => toggleBottomBlock(STACKEVENTS) }
|
||||
active={ bottomBlock === STACKEVENTS }
|
||||
label="Events"
|
||||
icon="puzzle-piece"
|
||||
label="EVENTS"
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
count={ stackCount }
|
||||
hasErrors={ stackRedCount > 0 }
|
||||
/>
|
||||
|
|
@ -399,51 +429,15 @@ export default class Controls extends React.Component {
|
|||
onClick={ () => toggleBottomBlock(PROFILER) }
|
||||
active={ bottomBlock === PROFILER }
|
||||
count={ profilesCount }
|
||||
label="Profiler"
|
||||
icon="code"
|
||||
label="PROFILER"
|
||||
noIcon
|
||||
labelClassName="text-base font-semibold"
|
||||
/>
|
||||
}
|
||||
{
|
||||
!live &&
|
||||
<ControlButton
|
||||
disabled={ disabled }
|
||||
onClick={ () => toggleBottomBlock(PERFORMANCE) }
|
||||
active={ bottomBlock === PERFORMANCE }
|
||||
label="Performance"
|
||||
icon="tachometer-slow"
|
||||
/>
|
||||
}
|
||||
{/* { !live && showLongtasks &&
|
||||
<ControlButton
|
||||
disabled={ disabled }
|
||||
onClick={ () => toggleBottomBlock(LONGTASKS) }
|
||||
active={ bottomBlock === LONGTASKS }
|
||||
label="Long Tasks"
|
||||
icon="business-time"
|
||||
/>
|
||||
} */}
|
||||
|
||||
{ !live && <div className={cn(styles.divider, 'h-full')} /> }
|
||||
{ !live &&
|
||||
<React.Fragment>
|
||||
<ControlButton
|
||||
disabled={ fullscreenDisabled }
|
||||
onClick={ this.props.fullscreenOn }
|
||||
label="Full Screen"
|
||||
icon="fullscreen"
|
||||
/>
|
||||
</React.Fragment>
|
||||
this.controlIcon("arrows-angle-extend", 18, this.props.fullscreenOn, false, "rounded hover:bg-gray-light-shade")
|
||||
}
|
||||
|
||||
|
||||
{!live && (
|
||||
<ControlButton
|
||||
disabled={ disabled && !inspectorMode }
|
||||
active={ bottomBlock === INSPECTOR }
|
||||
onClick={ toggleInspectorMode }
|
||||
icon={ inspectorMode ? 'close' : 'inspect' }
|
||||
label="Inspect"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import { Duration } from 'luxon';
|
|||
import { connectPlayer } from 'Player';
|
||||
import styles from './time.module.css';
|
||||
|
||||
const Time = ({ time }) => (
|
||||
<div className={ styles.time }>
|
||||
const Time = ({ time, isCustom }) => (
|
||||
<div className={ !isCustom && styles.time }>
|
||||
{ Duration.fromMillis(time).toFormat('m:ss') }
|
||||
</div>
|
||||
)
|
||||
|
|
@ -19,4 +19,4 @@ const ReduxTime = connectPlayer((state, { name }) => ({
|
|||
ReduxTime.displayName = "ReduxTime";
|
||||
|
||||
export default Time;
|
||||
export { ReduxTime };
|
||||
export { ReduxTime };
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import cn from 'classnames';
|
||||
import { connectPlayer } from 'Player';
|
||||
import { TimelinePointer } from 'UI';
|
||||
import { Popup, TimelinePointer, Icon } from 'UI';
|
||||
import TimeTracker from './TimeTracker';
|
||||
import { ReduxTime } from './Time';
|
||||
import stl from './timeline.module.css';
|
||||
|
|
@ -11,20 +11,21 @@ import { setTimelinePointer } from 'Duck/sessions';
|
|||
import DraggableCircle from './DraggableCircle';
|
||||
import CustomDragLayer from './CustomDragLayer';
|
||||
import { debounce } from 'App/utils';
|
||||
import { Tooltip } from 'react-tippy';
|
||||
|
||||
const getPointerIcon = (type) => {
|
||||
// exception,
|
||||
// exception,
|
||||
switch(type) {
|
||||
case 'fetch':
|
||||
return 'funnel/file-earmark-minus-fill';
|
||||
case 'exception':
|
||||
return 'funnel/exclamation-circle';
|
||||
return 'funnel/exclamation-circle-fill';
|
||||
case 'log':
|
||||
return 'funnel/exclamation-circle';
|
||||
return 'funnel/exclamation-circle-fill';
|
||||
case 'stack':
|
||||
return 'funnel/patch-exclamation-fill';
|
||||
case 'resource':
|
||||
return 'funnel/file-medical-alt';
|
||||
return 'funnel/file-earmark-minus-fill';
|
||||
|
||||
case 'dead_click':
|
||||
return 'funnel/dizzy';
|
||||
|
|
@ -47,10 +48,10 @@ const getPointerIcon = (type) => {
|
|||
case 'crash':
|
||||
return 'funnel/file-exclamation';
|
||||
case 'js_exception':
|
||||
return 'funnel/exclamation-circle';
|
||||
return 'funnel/exclamation-circle-fill';
|
||||
}
|
||||
|
||||
return 'info';
|
||||
return 'info';
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -72,7 +73,7 @@ let deboucneJump = () => null;
|
|||
fetchList: state.fetchList,
|
||||
}))
|
||||
@connect(state => ({
|
||||
issues: state.getIn([ 'sessions', 'current', 'issues' ]),
|
||||
issues: state.getIn([ 'sessions', 'current', 'issues' ]),
|
||||
clickRageTime: state.getIn([ 'sessions', 'current', 'clickRage' ]) &&
|
||||
state.getIn([ 'sessions', 'current', 'clickRageTime' ]),
|
||||
returningLocationTime: state.getIn([ 'sessions', 'current', 'returningLocation' ]) &&
|
||||
|
|
@ -143,10 +144,10 @@ export default class Timeline extends React.PureComponent {
|
|||
const scale = 100 / endTime;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ cn("flex items-center") }
|
||||
<div
|
||||
className={ cn("flex items-center absolute w-full") }
|
||||
style={{ top: '-5px', zIndex: 100}}
|
||||
>
|
||||
{ !live && <ReduxTime name="time" /> }
|
||||
<div
|
||||
className={ stl.progress }
|
||||
onClick={ disabled ? null : this.seekProgress }
|
||||
|
|
@ -176,219 +177,98 @@ export default class Timeline extends React.PureComponent {
|
|||
}
|
||||
{
|
||||
issues.map(iss => (
|
||||
<div
|
||||
style={ {
|
||||
<div
|
||||
style={ {
|
||||
left: `${ iss.time * scale }%`,
|
||||
top: '-30px'
|
||||
//width: `${ 2000 * scale }%`
|
||||
} }
|
||||
top: '0px',
|
||||
zIndex: 11, width: 16, height: 16
|
||||
} }
|
||||
key={iss.key}
|
||||
className={ stl.clickRage }
|
||||
onClick={ this.createEventClickHandler(iss) }
|
||||
>
|
||||
<TimelinePointer
|
||||
icon={iss.icon}
|
||||
content={
|
||||
<Tooltip
|
||||
delay={0}
|
||||
position="top"
|
||||
html={
|
||||
<div className={ stl.popup }>
|
||||
<b>{ iss.name }</b>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Icon className="rounded-full p-px bg-white" name={iss.icon} size="16" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{ events.filter(e => e.type === TYPES.CLICKRAGE).map(e => (
|
||||
<div
|
||||
style={ {
|
||||
<div
|
||||
style={ {
|
||||
left: `${ e.time * scale }%`,
|
||||
top: '-30px'
|
||||
//width: `${ 2000 * scale }%`
|
||||
} }
|
||||
top: '0px',
|
||||
zIndex: 11, width: 16, height: 16
|
||||
} }
|
||||
key={e.key}
|
||||
className={ stl.clickRage }
|
||||
onClick={ this.createEventClickHandler(e) }
|
||||
>
|
||||
<TimelinePointer
|
||||
icon={getPointerIcon('click_rage')}
|
||||
content={
|
||||
<Tooltip
|
||||
delay={0}
|
||||
position="top"
|
||||
html={
|
||||
<div className={ stl.popup }>
|
||||
<b>{ "Click Rage" }</b>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Icon className="rounded-full p-px bg-white" name={getPointerIcon('click_rage')} size="16" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
// <Popup
|
||||
// pinned
|
||||
// offset="-19"
|
||||
// trigger={
|
||||
// <div
|
||||
// style={ {
|
||||
// left: `${ e.time * scale }%`,
|
||||
// //width: `${ 2000 * scale }%`
|
||||
// } }
|
||||
// className={ stl.clickRage }
|
||||
// />
|
||||
// }
|
||||
// content={
|
||||
// <div className={ stl.popup }>
|
||||
// <b>{ "Click Rage" }</b>
|
||||
// </div>
|
||||
// }
|
||||
// />
|
||||
))}
|
||||
{ typeof clickRageTime === 'number' &&
|
||||
<div
|
||||
style={ {
|
||||
{typeof clickRageTime === 'number' &&
|
||||
<div
|
||||
style={{
|
||||
left: `${ clickRageTime * scale }%`,
|
||||
top: '-30px'
|
||||
//width: `${ 2000 * scale }%`
|
||||
} }
|
||||
className={ stl.clickRage }
|
||||
top: '-0px',
|
||||
zIndex: 11, width: 16, height: 16
|
||||
}}
|
||||
className={stl.clickRage}
|
||||
>
|
||||
<TimelinePointer
|
||||
icon={getPointerIcon('click_rage')}
|
||||
content={
|
||||
<Tooltip
|
||||
delay={0}
|
||||
position="top"
|
||||
html={
|
||||
<div className={ stl.popup }>
|
||||
<b>{ "Click Rage" }</b>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Icon className="rounded-full p-px bg-white" name={getPointerIcon('click_rage')} size="16" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
// <Popup
|
||||
// pinned
|
||||
// offset="-19"
|
||||
// trigger={
|
||||
// <div
|
||||
// style={ {
|
||||
// left: `${ clickRageTime * scale }%`,
|
||||
// //width: `${ 2000 * scale }%`
|
||||
// } }
|
||||
// className={ stl.clickRage }
|
||||
// />
|
||||
// }
|
||||
// content={
|
||||
// <div className={ stl.popup }>
|
||||
// <b>{ "Click Rage" }</b>
|
||||
// </div>
|
||||
// }
|
||||
// />
|
||||
}
|
||||
{ /* typeof returningLocationTime === 'number' &&
|
||||
<Popup
|
||||
pinned
|
||||
offset="-19"
|
||||
trigger={
|
||||
<div
|
||||
style={ {
|
||||
left: `${ returningLocationTime * scale }%`,
|
||||
//width: `${ 2000 * scale }%`
|
||||
} }
|
||||
className={ stl.returningLocation }
|
||||
onClick={ this.createEventClickHandler(returningLocationTime) }
|
||||
/>
|
||||
}
|
||||
content={
|
||||
<div className={ stl.popup }>
|
||||
<b>{ "Returning Location" }</b>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
*/ }
|
||||
{ exceptionsList
|
||||
.map(e => (
|
||||
<div
|
||||
key={ e.key }
|
||||
className={ cn(stl.markup, stl.error) }
|
||||
style={ { left: `${ e.time * scale }%`, top: '-30px' } }
|
||||
style={ { left: `${ e.time * scale }%`, top: '0px', zIndex: 10, width: 16, height: 16 } }
|
||||
onClick={ this.createEventClickHandler(e) }
|
||||
>
|
||||
<TimelinePointer
|
||||
icon={getPointerIcon('exception')}
|
||||
content={
|
||||
<Tooltip
|
||||
delay={0}
|
||||
position="top"
|
||||
html={
|
||||
<div className={ stl.popup } >
|
||||
<b>{ "Exception" }</b>
|
||||
<br/>
|
||||
<span>{ e.message }</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Icon className="rounded-full p-px bg-white" name={getPointerIcon('exception')} size="16" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
// <Popup
|
||||
// key={ e.key }
|
||||
// offset="-19"
|
||||
// pinned
|
||||
// className="error"
|
||||
// trigger={
|
||||
// <div
|
||||
// key={ e.key }
|
||||
// className={ cn(stl.markup, stl.error) }
|
||||
// style={ { left: `${ e.time * scale }%` } }
|
||||
// onClick={ this.createEventClickHandler(e.time) }
|
||||
// />
|
||||
// }
|
||||
// content={
|
||||
// <div className={ stl.popup } >
|
||||
// <b>{ "Exception:" }</b>
|
||||
// <br/>
|
||||
// <span>{ e.message }</span>
|
||||
// </div>
|
||||
// }
|
||||
// />
|
||||
))
|
||||
}
|
||||
{ logList
|
||||
.map(l => l.isRed() && (
|
||||
<div
|
||||
key={ l.key }
|
||||
className={ cn(stl.markup, {
|
||||
[ stl.error ]: l.isRed(),
|
||||
//[ stl.warning ]: l.isYellow(),
|
||||
//[ stl.info ]: !l.isYellow() && !l.isRed(),
|
||||
}) }
|
||||
style={ { left: `${ l.time * scale }%`, top: '-30px' } }
|
||||
onClick={ this.createEventClickHandler(l) }
|
||||
>
|
||||
<TimelinePointer
|
||||
icon={getPointerIcon('log')}
|
||||
content={
|
||||
<div className={ stl.popup } >
|
||||
<b>{ "Console" }</b>
|
||||
<br/>
|
||||
<span>{ l.value }</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
// <Popup
|
||||
// //on="click"
|
||||
// key={ l.key }
|
||||
// offset="-19"
|
||||
// pinned
|
||||
// className={ cn({
|
||||
// "info": !l.isYellow() && !l.isRed(),
|
||||
// "warn": l.isYellow(),
|
||||
// "error": l.isRed(),
|
||||
// })}
|
||||
// trigger={
|
||||
// <div
|
||||
// key={ l.key }
|
||||
// className={ cn(stl.markup, {
|
||||
// [ stl.error ]: l.isRed(),
|
||||
// //[ stl.warning ]: l.isYellow(),
|
||||
// //[ stl.info ]: !l.isYellow() && !l.isRed(),
|
||||
// }) }
|
||||
// style={ { left: `${ l.time * scale }%` } }
|
||||
// onClick={ this.createEventClickHandler(l.time) }
|
||||
// />
|
||||
// }
|
||||
// content={
|
||||
// <div className={ stl.popup } >
|
||||
// <b>{ "Console:" }</b>
|
||||
// <br/>
|
||||
// <span>{ l.value }</span>
|
||||
// </div>
|
||||
// }
|
||||
// />
|
||||
))
|
||||
}
|
||||
{ resourceList
|
||||
|
|
@ -396,49 +276,27 @@ export default class Timeline extends React.PureComponent {
|
|||
.map(r => (
|
||||
<div
|
||||
key={ r.key }
|
||||
className={ cn(stl.markup, {
|
||||
className={ cn(stl.markup, {
|
||||
[ stl.error ]: r.isRed(),
|
||||
[ stl.warning ]: r.isYellow(),
|
||||
}) }
|
||||
style={ { left: `${ r.time * scale }%`, top: '-30px' } }
|
||||
style={ { left: `${ r.time * scale }%`, top: '0px', zIndex: 10, width: 16, height: 16 } }
|
||||
onClick={ this.createEventClickHandler(r) }
|
||||
>
|
||||
<TimelinePointer
|
||||
icon={getPointerIcon('resource')}
|
||||
content={
|
||||
<Tooltip
|
||||
delay={0}
|
||||
position="top"
|
||||
html={
|
||||
<div className={ stl.popup }>
|
||||
<b>{ r.success ? "Slow resource: " : "Missing resource:" }</b>
|
||||
<br/>
|
||||
{ r.name }
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Icon className="rounded-full p-px bg-white" name={getPointerIcon('resource')} size="16" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
// <Popup
|
||||
// key={ r.key }
|
||||
// offset="-19"
|
||||
// pinned
|
||||
// trigger={
|
||||
// <div
|
||||
// key={ r.key }
|
||||
// className={ cn(stl.markup, {
|
||||
// [ stl.error ]: r.isRed(),
|
||||
// [ stl.warning ]: r.isYellow(),
|
||||
// }) }
|
||||
// style={ { left: `${ r.time * scale }%` } }
|
||||
// onClick={ this.createEventClickHandler(r.time) }
|
||||
// >
|
||||
|
||||
// </div>
|
||||
// }
|
||||
// content={
|
||||
// <div className={ stl.popup }>
|
||||
// <b>{ r.success ? "Slow resource: " : "Missing resource:" }</b>
|
||||
// <br/>
|
||||
// { r.name }
|
||||
// </div>
|
||||
// }
|
||||
// />
|
||||
))
|
||||
}
|
||||
{ fetchList
|
||||
|
|
@ -447,39 +305,20 @@ export default class Timeline extends React.PureComponent {
|
|||
<div
|
||||
key={ e.key }
|
||||
className={ cn(stl.markup, stl.error) }
|
||||
style={ { left: `${ e.time * scale }%`, top: '-30px' } }
|
||||
style={ { left: `${ e.time * scale }%`, top: '-5px' } }
|
||||
onClick={ this.createEventClickHandler(e) }
|
||||
>
|
||||
<TimelinePointer
|
||||
icon={getPointerIcon('fetch')}
|
||||
content={
|
||||
content={
|
||||
<div className={ stl.popup }>
|
||||
<b>{ "Failed Fetch" }</b>
|
||||
<br/>
|
||||
{ e.name }
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
// <Popup
|
||||
// offset="-19"
|
||||
// pinned
|
||||
// trigger={
|
||||
// <div
|
||||
// key={ e.key }
|
||||
// className={ cn(stl.markup, stl.error) }
|
||||
// style={ { left: `${ e.time * scale }%` } }
|
||||
// onClick={ this.createEventClickHandler(e.time) }
|
||||
// />
|
||||
// }
|
||||
// content={
|
||||
// <div className={ stl.popup }>
|
||||
// <b>{ "Failed Fetch:" }</b>
|
||||
// <br/>
|
||||
// { e.name }
|
||||
// </div>
|
||||
// }
|
||||
// />
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{ stackList
|
||||
|
|
@ -488,43 +327,23 @@ export default class Timeline extends React.PureComponent {
|
|||
<div
|
||||
key={ e.key }
|
||||
className={ cn(stl.markup, stl.error) }
|
||||
style={ { left: `${ e.time * scale }%`, top: '-30px' } }
|
||||
style={ { left: `${ e.time * scale }%`, top: '-5px' } }
|
||||
onClick={ this.createEventClickHandler(e) }
|
||||
>
|
||||
<TimelinePointer
|
||||
icon={getPointerIcon('stack')}
|
||||
content={
|
||||
content={
|
||||
<div className={ stl.popup }>
|
||||
<b> { "Stack Event" }</b>
|
||||
<br/>
|
||||
{ e.name }
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
// <Popup
|
||||
// offset="-19"
|
||||
// pinned
|
||||
// trigger={
|
||||
// <div
|
||||
// key={ e.key }
|
||||
// className={ cn(stl.markup, stl.error) }
|
||||
// style={ { left: `${ e.time * scale }%` } }
|
||||
// onClick={ this.createEventClickHandler(e.time) }
|
||||
// />
|
||||
// }
|
||||
// content={
|
||||
// <div className={ stl.popup }>
|
||||
// <b> { "Stack Event:" }</b>
|
||||
// <br/>
|
||||
// { e.name }
|
||||
// </div>
|
||||
// }
|
||||
// />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
{ !live && <ReduxTime name="endTime" /> }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,15 +19,15 @@
|
|||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background-color: red;
|
||||
top: 12px;
|
||||
left: 23px;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
& .countLabel {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
left: 12px;
|
||||
right: -6px;
|
||||
background-color: $gray-dark;
|
||||
color: white;
|
||||
font-size: 9px;
|
||||
|
|
@ -52,4 +52,4 @@
|
|||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,17 +7,15 @@
|
|||
}
|
||||
|
||||
.controls {
|
||||
/* margin-top: 10px; */
|
||||
border-top: solid thin $gray-light;
|
||||
padding-top: 36px;
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 7px;
|
||||
align-items: center;
|
||||
height: 65px;
|
||||
padding: 0 30px;
|
||||
&[data-is-live=true] {
|
||||
padding: 0;
|
||||
|
|
@ -115,4 +113,4 @@
|
|||
animation: fade 1s infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,8 @@
|
|||
.playedTimeline {
|
||||
display: block;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
background-color: $teal;
|
||||
background-color: $active-blue-border;
|
||||
pointer-events: none;
|
||||
height: 2px;
|
||||
height: 10px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
.positionTracker {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
outline: solid 1px $teal;
|
||||
outline: solid 1px $teal-dark;
|
||||
outline-style: inset;
|
||||
margin-left: -7px;
|
||||
border-radius: 50%;
|
||||
background-color: $active-blue;
|
||||
background-color: $main;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 98;
|
||||
top: 0;
|
||||
top: 3px;
|
||||
transition: all 0.2s ease-out;
|
||||
&:hover,
|
||||
&:focus {
|
||||
transition: all 0.1s ease-in;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
top: -2px;
|
||||
top: 1px;
|
||||
left: -2px;
|
||||
}
|
||||
|
||||
|
|
@ -24,8 +24,7 @@
|
|||
|
||||
.progress {
|
||||
height: 10px;
|
||||
border-radius: 1px;
|
||||
background: transparent;
|
||||
padding: 8px 0;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
|
@ -36,22 +35,20 @@
|
|||
|
||||
.skipInterval {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
top: 3px;
|
||||
height: 10px;
|
||||
bottom: 0;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
background-color: $gray-light;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
||||
.event {
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border: solid 1px white;
|
||||
margin-left: -4px;
|
||||
border-radius: 50%;
|
||||
background: rgba(136, 136, 136, 0.8);
|
||||
width: 2px;
|
||||
height: 10px;
|
||||
background: $main;
|
||||
pointer-events: none;
|
||||
/* top: 0; */
|
||||
/* bottom: 0; */
|
||||
|
|
@ -74,7 +71,6 @@
|
|||
position: absolute;
|
||||
width: 2px;
|
||||
height: 8px;
|
||||
border-radius: 2px;
|
||||
margin-left: -15px;
|
||||
&:hover {
|
||||
z-index: 9999;
|
||||
|
|
@ -112,13 +108,13 @@
|
|||
}
|
||||
|
||||
.timeline {
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background-color: $gray-light;
|
||||
height: 10px;
|
||||
border-top: 1px solid $gray-light;
|
||||
border-bottom: 1px solid $gray-light;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
|
@ -127,7 +123,6 @@
|
|||
position: absolute;
|
||||
width: 2px;
|
||||
height: 8px;
|
||||
border-radius: 2px;
|
||||
margin-left: -1px;
|
||||
/* background: $red; */
|
||||
}
|
||||
|
|
@ -146,7 +141,6 @@
|
|||
margin-left: -9px;
|
||||
background-color: $gray-lightest;
|
||||
padding: 2px;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0px 0px 0px 1px rgba(0,0,0,0.1);
|
||||
|
||||
& .tooltipArrow {
|
||||
|
|
@ -169,4 +163,4 @@
|
|||
box-shadow: 0px 0px 0px 1px rgba(0,0,0,0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,12 +119,12 @@ export default class PlayerBlockHeader extends React.PureComponent {
|
|||
<div className={cn("ml-auto flex items-center h-full", { 'hidden' : closedLive })}>
|
||||
{ live && !isAssist && (
|
||||
<>
|
||||
<div className={stl.liveSwitchButton}>
|
||||
<div className={cn(stl.liveSwitchButton, 'pr-4')}>
|
||||
<Link to={withSiteId(liveSessionRoute(sessionId), siteId)}>
|
||||
This Session is Now Continuing Live
|
||||
</Link>
|
||||
</div>
|
||||
<div className={ stl.divider } />
|
||||
{_metaList.length > 0 && <div className={ stl.divider } />}
|
||||
</>
|
||||
)}
|
||||
|
||||
|
|
|
|||
3
frontend/app/svg/icons/arrows-angle-extend.svg
Normal file
3
frontend/app/svg/icons/arrows-angle-extend.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg viewBox="0 0 27 27" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.80392 17.1429C9.64551 16.9846 9.43069 16.8956 9.2067 16.8956C8.98271 16.8956 8.76789 16.9846 8.60948 17.1429L1.68946 24.0629V19.3865C1.68946 19.1625 1.60046 18.9476 1.44204 18.7892C1.28363 18.6308 1.06876 18.5418 0.844729 18.5418C0.620693 18.5418 0.405833 18.6308 0.247415 18.7892C0.088998 18.9476 0 19.1625 0 19.3865V26.1021C0 26.3262 0.088998 26.541 0.247415 26.6994C0.405833 26.8579 0.620693 26.9469 0.844729 26.9469H7.56032C7.78436 26.9469 7.99922 26.8579 8.15764 26.6994C8.31605 26.541 8.40505 26.3262 8.40505 26.1021C8.40505 25.8781 8.31605 25.6632 8.15764 25.5048C7.99922 25.3464 7.78436 25.2574 7.56032 25.2574H2.8839L9.80392 18.3374C9.96229 18.179 10.0512 17.9641 10.0512 17.7402C10.0512 17.5162 9.96229 17.3013 9.80392 17.1429ZM17.1429 9.80392C17.3013 9.96229 17.5162 10.0512 17.7402 10.0512C17.9641 10.0512 18.179 9.96229 18.3374 9.80392L25.2574 2.8839V7.56032C25.2574 7.78436 25.3464 7.99922 25.5048 8.15764C25.6632 8.31605 25.8781 8.40505 26.1021 8.40505C26.3262 8.40505 26.541 8.31605 26.6994 8.15764C26.8579 7.99922 26.9469 7.78436 26.9469 7.56032V0.844729C26.9469 0.620693 26.8579 0.405833 26.6994 0.247415C26.541 0.088998 26.3262 0 26.1021 0H19.3865C19.1625 3.3384e-09 18.9476 0.088998 18.7892 0.247415C18.6308 0.405833 18.5418 0.620693 18.5418 0.844729C18.5418 1.06876 18.6308 1.28363 18.7892 1.44204C18.9476 1.60046 19.1625 1.68946 19.3865 1.68946H24.0629L17.1429 8.60948C16.9846 8.76789 16.8956 8.98271 16.8956 9.2067C16.8956 9.43069 16.9846 9.64551 17.1429 9.80392Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
3
frontend/app/svg/icons/pause-fill.svg
Normal file
3
frontend/app/svg/icons/pause-fill.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<path d="M5.5 3.5A1.5 1.5 0 0 1 7 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5zm5 0A1.5 1.5 0 0 1 12 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 222 B |
3
frontend/app/svg/icons/play-fill-new.svg
Normal file
3
frontend/app/svg/icons/play-fill-new.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<path d="m11.596 8.697-6.363 3.692c-.54.313-1.233-.066-1.233-.697V4.308c0-.63.692-1.01 1.233-.696l6.363 3.692a.802.802 0 0 1 0 1.393z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 207 B |
Loading…
Add table
Reference in a new issue