Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3a0e533
paired hookStates names with hookStates
liuedar Nov 6, 2021
e6cac0d
added hover functionality over nodes
Nov 6, 2021
1809cd2
Added Jest tests for hooks compatibility
liuedar Nov 9, 2021
11ebdea
removed greying out feature for hover in jump bar on snapshots after …
liuedar Nov 10, 2021
96fc411
Improved visibility of hovers in Web Metrics tab
liuedar Nov 10, 2021
332ed15
Merge pull request #1 from oslabs-beta/hooks
KristinaWallen Nov 10, 2021
b8bf0b4
ui/ux improvements
Nov 10, 2021
7639f60
Merge branch 'dev46' into History-Hover
robmaeda Nov 10, 2021
6ece0ba
Merge pull request #2 from oslabs-beta/History-Hover
liuedar Nov 10, 2021
76603ef
history hover display fixed
Nov 11, 2021
6e9190f
timejumping for specific hooks app
Nov 13, 2021
0453165
Time Jumping fully functional w/ Hooks
liuedar Nov 14, 2021
f70cea8
separated getComponentByIndex for Class vs Hooks
liuedar Nov 15, 2021
2f1c8b5
Merge pull request #3 from oslabs-beta/edar-branch
liuedar Nov 15, 2021
1e60866
fixed visibility of time-button hover across all tabs
liuedar Nov 16, 2021
384a157
Merge pull request #5 from oslabs-beta/edar-branch
liuedar Nov 16, 2021
3a5db80
Cleaned up console logs used for debugging
Nov 19, 2021
0561231
Merge pull request #6 from oslabs-beta/cleaning
KristinaWallen Nov 19, 2021
60dcb94
Added psuedocoding to improve future developer experience
Nov 19, 2021
2dba4d3
Merge pull request #7 from oslabs-beta/pseudocoding
robmaeda Nov 19, 2021
0449bb1
updates to readme
Nov 23, 2021
15ad3bd
Merge pull request #9 from oslabs-beta/readme
liuedar Nov 23, 2021
7783a64
Merge pull request #10 from oslabs-beta/dev46
robmaeda Nov 23, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@
<a href="#how-to-use">How To Use</a> • <a href="#features">Features</a> • <a href="https://reactime.io">Website</a> • <a href="#read-more">Read More</a>
</p>

Currently, Reactime supports React apps using stateful components and Hooks, including frameworks like Gatsby and Next.js, with beta support for Recoil and Context API.
Currently, Reactime supports React apps using stateful components and Hooks, with beta support for Recoil and Context API and frameworks like Gatsby and Next.js.

<b>Reactime version 9.0</b> allows you to run A/B testing on your application by storing a "series" of state data snapshots. At any stage in the dev cycle, devs could run Reactime again and select any past series to do an A/B test with the current series of snapshots. With Save Series, developers have access to view trends in their App's component render times during development by comparing the previous series of snapshots.
<b>Reactime version 11.0</b> implements full compatibility with React Hooks. Additionally, hover functionality was added to all of the nodes that populate in the history tab, allowing developers to more easily view the state at that snapshot.

Reactime 9.0 fixes previous version bugs and incorporates improved user experience for saved snapshot series.
Reactime 11.0 fixes existing bugs while also improving the user experience for information tooltips.

After installing Reactime, you can test its functionalities with your React application in development mode.

Expand Down Expand Up @@ -152,6 +152,8 @@ After cloning this repository, developers can simply run `npm run docs` at the r
- [React Fiber and Reactime](https://medium.com/@aquinojardim/react-fiber-reactime-4-0-f200f02e7fa8)
- [Meet Reactime - a time-traveling State Debugger for React](https://medium.com/@yujinkay/meet-reactime-a-time-traveling-state-debugger-for-react-24f0fce96802)
- [Deep in Weeds with Reactime, Concurrent React_fiberRoot, and Browser History Caching](https://itnext.io/deep-in-the-weeds-with-reactime-concurrent-react-fiberroot-and-browser-history-caching-7ce9d7300abb)
- [Time-Traveling Through React State with Reactime 9.0](https://rxlina.medium.com/time-traveling-through-react-state-with-reactime-9-0-371dbdc99319)
- [What time is it? Reactime!](https://medium.com/@liuedar/what-time-is-it-reactime-fd7267b9eb89)

## <b>Authors</b>
- **Harry Fox** - [@StackOverFlowWhereArtThou](https://github.com/StackOverFlowWhereArtThou)
Expand Down Expand Up @@ -201,6 +203,11 @@ After cloning this repository, developers can simply run `npm run docs` at the r
- **Andy Tsou** - [@andytsou19](https://github.com/andytsou19)
- **Feiyi Wu** - [@FreyaWu](https://github.com/FreyaWu)
- **Viet Nguyen** - [@vnguyen95](https://github.com/vnguyen95)
- **Alex Gomez** - [@alexgomez9](https://github.com/alexgomez9)
- **Edar Liu** - [@liuedar](https://github.com/liuedar)
- **Kristina Wallen** - [@kristinawallen](https://github.com/kristinawallen)
- **Quan Le** - [@blachfog](https://github.com/Blachfog)
- **Robert Maeda** - [@robmaeda](https://github.com/robmaeda)

## <b>License </b>

Expand Down
5 changes: 3 additions & 2 deletions src/app/components/Action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import React from 'react';
import ReactHover, { Trigger, Hover } from 'react-hover';
import { changeView, changeSlider } from '../actions/actions';
import snapshots from './snapshots';

/**
* @template ActionProps Props for the action component
Expand Down Expand Up @@ -148,8 +149,8 @@ const Action = (props: ActionProps): JSX.Element => {
</div>
</Trigger>
<Hover type="hover">
<div style={{ padding: '0.5rem 1rem' }} id="hover-box">
<p>{logChangedState(index)}</p>
<div style={{ zIndex: 1, position: 'relative', padding: '0.5rem 1rem' }} id="hover-box">
<p>{(logChangedState(index))}</p>
</div>
</Hover>
</ReactHover>
Expand Down
4 changes: 3 additions & 1 deletion src/app/components/ComponentMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ export default function ComponentMap({

<svg ref={containerRef} width={totalWidth} height={totalHeight}>
<LinearGradient id="links-gradient" from="#fd9b93" to="#fe6e9e" />
<rect width={totalWidth} height={totalHeight} rx={14} fill="#242529" />
<rect onClick={() => {
setTooltip(false);
hideTooltip();}} width={totalWidth} height={totalHeight} rx={14} fill="#242529" />
<Group top={margin.top} left={margin.left}>
<Tree
root={hierarchy(startNode || data, d => (d.isExpanded ? null : d.children))}
Expand Down
101 changes: 98 additions & 3 deletions src/app/components/History.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
/* eslint-disable react-hooks/exhaustive-deps */
// @ts-nocheck
import React, { Component, useEffect, useState } from 'react';
// ReactHover does not refer to individual nodes within the history tab but rather can only wrap the entire SVG div
import ReactHover, { Trigger, Hover } from 'react-hover';
// used in action.tsx to format the return data of findDiff into a react component, not needed since the return of findDiff in History.tsx is simple a divs html
import ReactHtmlParser from 'react-html-parser';
// formatting findDiff return data to show the changes with green and red background colors, aligns with actions.tsx
import { diff, formatters } from 'jsondiffpatch';
import * as d3 from 'd3';
// legend key taken out before ReactimeX(v 10.0)
import LegendKey from './legend';
import { changeView, changeSlider } from '../actions/actions';

//unused function definition, didnt break reactime when commented out
const filterHooks = (data: any[]) => {
if (data[0].children && data[0].state === 'stateless') {
return filterHooks(data[0].children);
Expand All @@ -26,6 +34,8 @@ function History(props: Record<string, unknown>) {
hierarchy,
dispatch,
currLocation,
//snapshots array passed down from state route, needed for findDiff function
snapshots,
} = props;

const svgRef = React.useRef(null);
Expand Down Expand Up @@ -102,9 +112,25 @@ function History(props: Record<string, unknown>) {
dispatch(changeView(d.data.index));
dispatch(changeSlider(d.data.index));
})
//added to display state change information to node tree
.on('mouseover', d => {
// created popup div and appended it to display div(returned in this function)
// D3 doesn't utilize z-index for priority, rather decides on placement by order of rendering
// needed to define the return div with a className to have a target to append to with the correct level of priority
const div = d3.select('.display').append('div')
.attr('class', 'tooltip')
.style('opacity', 1)
.style('left', (d3.event.pageX) + 'px')
.style('top', (d3.event.pageY) + 'px')
d3.selectAll('.tooltip').html(findDiff(d.data.index));
})
.on('mouseout', d => {
// when appending divs on mouseover the appended dives would not disappear when using D3's 'transition' on mouseover/mouseout
// solution: remove all tooltop divs on mouseout
d3.selectAll('.tooltip').remove();
})
.attr('transform', d => `translate(${d.x},${d.y})`);


node.append('circle')
.attr('fill', d => {
if (d.data.index === currLocation.index) {
Expand All @@ -124,17 +150,86 @@ function History(props: Record<string, unknown>) {
return svg.node();
};

// findDiff function uses same logic as ActionContainer.tsx
function findDiff(index) {
const statelessCleanning = (obj: {
name?: string;
componentData?: object;
state?: string | any;
stateSnaphot?: object;
children?: any[];
}) => {
const newObj = { ...obj };
if (newObj.name === 'nameless') {
delete newObj.name;
}
if (newObj.componentData) {
delete newObj.componentData;
}
if (newObj.state === 'stateless') {
delete newObj.state;
}
if (newObj.stateSnaphot) {
newObj.stateSnaphot = statelessCleanning(obj.stateSnaphot);
}
if (newObj.children) {
newObj.children = [];
if (obj.children.length > 0) {
obj.children.forEach(
(element: { state?: object | string; children?: [] }) => {
if (
element.state !== 'stateless'
|| element.children.length > 0
) {
const clean = statelessCleanning(element);
newObj.children.push(clean);
}
},
);
}
}
return newObj;
};

const previousDisplay = statelessCleanning(snapshots[index - 1]);
const delta = diff(previousDisplay, snapshots[index]);
const changedState = findStateChangeObj(delta);
// figured out the formatting for hover, applying diff.csss
const html = formatters.html.format(changedState[0]);
// uneeded, not returning a react component in SVG div
// const output = ReactHtmlParser(html);
return html;
}

function findStateChangeObj(delta, changedState = []) {
if (!delta.children && !delta.state) {
return changedState;
}
if (delta.state && delta.state[0] !== 'stateless') {
changedState.push(delta.state);
}
if (!delta.children) {
return changedState;
}
Object.keys(delta.children).forEach(child => {
// if (isNaN(child) === false) {
changedState.push(...findStateChangeObj(delta.children[child]));
// }
});
return changedState;
}

// below we are rendering the LegendKey component and passing hierarchy as props
// then rendering each node in History tab to render using D3, which will share area with LegendKey
return (
<>
<div className="display">
{/* <LegendKey hierarchy={hierarchy} /> */}
<svg
ref={svgRef}
width={totalWidth}
height={totalHeight}
/>
</>
</div>
);
}

Expand Down
2 changes: 2 additions & 0 deletions src/app/components/StateRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ const StateRoute = (props: StateRouteProps) => {
sliderIndex={sliderIndex}
viewIndex={viewIndex}
currLocation={currLocation}
// added snapshots 11/4 Rob
snapshots={snapshots}
/>
)}
</ParentSize>
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/WebMetrics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const radialGraph = props => {
</div>
</Trigger>
<Hover type="hover">
<div style={{ padding: '0.5rem 1rem' }} id="hover-box">
<div style={{ zIndex: 1, position: 'relative', padding: '0.5rem 1rem' }} id="hover-box">
<p>
<strong>{props.name}</strong>
</p>
Expand Down
2 changes: 1 addition & 1 deletion src/app/containers/ActionContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ function ActionContainer(props) {
let actionsArr = [];
const hierarchyArr: any[] = [];


function findDiff(index) {
const statelessCleanning = (obj: {
name?: string;
Expand Down Expand Up @@ -154,7 +155,6 @@ function ActionContainer(props) {
}
// Sort by index.
hierarchyArr.sort((a, b) => a.index - b.index);

actionsArr = hierarchyArr.map(
(
snapshot: {
Expand Down
1 change: 0 additions & 1 deletion src/app/containers/MainContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const mixpanel = require('mixpanel').init('12fa2800ccbf44a5c36c37bc9776e4c0', {
debug: false,
protocol: 'https',
});

function MainContainer(): any {
const [store, dispatch] = useStoreContext();
const { tabs, currentTab, port: currentPort } = store;
Expand Down
2 changes: 2 additions & 0 deletions src/app/containers/StateContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const StateContainer = (props: StateContainerProps): JSX.Element => {
viewIndex,
webMetrics,
currLocation,
// added snapshots, Rob 11/4
snapshots,
} = props;

return (
Expand Down
15 changes: 10 additions & 5 deletions src/app/reducers/mainReducer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { produce, original } from 'immer';
import { debuglog } from 'util';

import * as types from '../constants/actionTypes.ts';

Expand All @@ -11,25 +12,27 @@ export default (state, action) => produce(state, draft => {
// eslint-disable-next-line max-len
// function that finds the index in the hierarchy and extracts the name of the equivalent index to add to the post message
// eslint-disable-next-line consistent-return

// (action.payload, hierarchy)
const findName = (index, obj) => {
// eslint-disable-next-line eqeqeq
if (obj && obj.index == index) {
return obj.name;
}

const objChildArray = [];
if (obj) {
// eslint-disable-next-line no-restricted-syntax
for (const objChild of obj.children) {
objChildArray.push(findName(index, objChild));
}
}
// eslint-disable-next-line no-restricted-syntax
for (const objChildName of objChildArray) {
if (objChildName) {
return objChildName;
}
}
};

switch (action.type) {
// Save case will store the series user wants to save to the chrome local storage
case types.SAVE: {
Expand Down Expand Up @@ -76,11 +79,12 @@ export default (state, action) => produce(state, draft => {
}

case types.MOVE_BACKWARD: {
if (snapshots.length > 0 && sliderIndex > 0) {
if (sliderIndex > 0) {
const newIndex = sliderIndex - 1;
// eslint-disable-next-line max-len
// finds the name by the newIndex parsing through the hierarchy to send to background.js the current name in the jump action
const nameFromIndex = findName(newIndex, hierarchy);

port.postMessage({
action: 'jumpToSnap',
payload: snapshots[newIndex],
Expand All @@ -105,9 +109,9 @@ export default (state, action) => produce(state, draft => {

port.postMessage({
action: 'jumpToSnap',
payload: snapshots[newIndex],
index: newIndex,
name: nameFromIndex,
payload: snapshots[newIndex],
tabId: currentTab,
});

Expand Down Expand Up @@ -146,7 +150,8 @@ export default (state, action) => produce(state, draft => {
// eslint-disable-next-line max-len
// finds the name by the action.payload parsing through the hierarchy to send to background.js the current name in the jump action
const nameFromIndex = findName(action.payload, hierarchy);

// nameFromIndex is a number based on which jump button is pushed

port.postMessage({
action: 'jumpToSnap',
payload: snapshots[action.payload],
Expand Down
2 changes: 1 addition & 1 deletion src/app/store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ import React, { useContext } from 'react';

export const StoreContext = React.createContext();

export const useStoreContext:any = () => useContext(StoreContext);
export const useStoreContext:any = () => useContext(StoreContext);
21 changes: 11 additions & 10 deletions src/app/styles/components/d3graph.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,18 @@ body {

div.tooltip {
position: absolute;
text-align: center;
display: inline;
max-width: 250px;
overflow-wrap: break-word;
padding: 6px;
color: #2b2f39;
/* text-align: center; */
/* display: inline; */
max-width: 150px;
/* overflow-wrap: break-word; */
padding: 0.5rem 1rem;
/* padding: 6px; */
color: white;
font-size: 12px;
font-family: 'Overpass Mono', monospace;
background: #679dca;
border-radius: 8px;
pointer-events: none;
font-family: 'Roboto', sans-serif;
background: #51565e;
border-radius: 5px;
/* pointer-events: none; */
}

.d3-tip {
Expand Down
2 changes: 1 addition & 1 deletion src/app/styles/components/diff.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ ul.jsondiffpatch-delta {
}
.jsondiffpatch-unchanged,
.jsondiffpatch-movedestination {
color: gray;
color: white;
}
.jsondiffpatch-unchanged,
.jsondiffpatch-movedestination > .jsondiffpatch-value {
Expand Down
1 change: 1 addition & 0 deletions src/app/styles/layout/_stateContainer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
max-width: 150px;
background-color: #51565e;
border-radius: 5px;
color: white;
}

.bargraph-position {
Expand Down
3 changes: 2 additions & 1 deletion src/app/styles/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,5 @@
}
.props p{
line-height:1;
}
}

Loading