react/packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.js

180 lines
5.2 KiB
JavaScript
Raw Normal View History

2019-03-11 10:16:34 +08:00
// @flow
2019-08-14 08:58:03 +08:00
import React, {Fragment, useCallback, useContext, useMemo} from 'react';
2019-03-11 10:16:34 +08:00
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
2019-08-14 08:58:03 +08:00
import {ProfilerContext} from './ProfilerContext';
import SnapshotCommitList from './SnapshotCommitList';
2019-08-14 08:58:03 +08:00
import {maxBarWidth} from './constants';
import {StoreContext} from '../context';
2019-03-11 10:16:34 +08:00
import styles from './SnapshotSelector.css';
export type Props = {||};
export default function SnapshotSelector(_: Props) {
2019-03-14 08:00:44 +08:00
const {
isCommitFilterEnabled,
minCommitDuration,
2019-03-14 08:00:44 +08:00
rootID,
selectedCommitIndex,
selectCommitIndex,
} = useContext(ProfilerContext);
2019-08-14 08:58:03 +08:00
const {profilerStore} = useContext(StoreContext);
const {commitData} = profilerStore.getDataForRoot(((rootID: any): number));
const commitDurations: Array<number> = [];
const commitTimes: Array<number> = [];
commitData.forEach(commitDatum => {
commitDurations.push(commitDatum.duration);
commitTimes.push(commitDatum.timestamp);
});
const filteredCommitIndices = useMemo(
() =>
commitData.reduce((reduced, commitDatum, index) => {
if (
!isCommitFilterEnabled ||
commitDatum.duration >= minCommitDuration
) {
reduced.push(index);
}
return reduced;
}, []),
2019-08-14 08:58:03 +08:00
[commitData, isCommitFilterEnabled, minCommitDuration],
);
2019-03-16 11:05:52 +08:00
const numFilteredCommits = filteredCommitIndices.length;
// Map the (unfiltered) selected commit index to an index within the filtered data.
2019-08-14 08:58:03 +08:00
const selectedFilteredCommitIndex = useMemo(
() => {
if (selectedCommitIndex !== null) {
for (let i = 0; i < filteredCommitIndices.length; i++) {
if (filteredCommitIndices[i] === selectedCommitIndex) {
return i;
}
}
}
2019-08-14 08:58:03 +08:00
return null;
},
[filteredCommitIndices, selectedCommitIndex],
);
// TODO (profiling) This should be managed by the context controller (reducer).
// It doesn't currently know about the filtered commits though (since it doesn't suspend).
// Maybe this component should pass filteredCommitIndices up?
if (selectedFilteredCommitIndex === null) {
2019-03-16 11:05:52 +08:00
if (numFilteredCommits > 0) {
selectCommitIndex(0);
} else {
selectCommitIndex(null);
}
2019-03-16 11:05:52 +08:00
} else if (selectedFilteredCommitIndex >= numFilteredCommits) {
selectCommitIndex(numFilteredCommits === 0 ? null : numFilteredCommits - 1);
}
2019-03-16 11:05:52 +08:00
let label = null;
if (numFilteredCommits > 0) {
label =
`${selectedFilteredCommitIndex + 1}`.padStart(
`${numFilteredCommits}`.length,
2019-08-14 08:58:03 +08:00
'0',
2019-03-16 11:05:52 +08:00
) +
' / ' +
numFilteredCommits;
}
2019-08-14 08:58:03 +08:00
const viewNextCommit = useCallback(
() => {
const nextCommitIndex = Math.min(
((selectedFilteredCommitIndex: any): number) + 1,
filteredCommitIndices.length - 1,
);
selectCommitIndex(filteredCommitIndices[nextCommitIndex]);
},
[selectedFilteredCommitIndex, filteredCommitIndices, selectCommitIndex],
);
const viewPrevCommit = useCallback(
() => {
const nextCommitIndex = Math.max(
((selectedFilteredCommitIndex: any): number) - 1,
0,
);
selectCommitIndex(filteredCommitIndices[nextCommitIndex]);
},
[selectedFilteredCommitIndex, filteredCommitIndices, selectCommitIndex],
);
const handleKeyDown = useCallback(
event => {
switch (event.key) {
case 'ArrowLeft':
viewPrevCommit();
event.stopPropagation();
break;
case 'ArrowRight':
viewNextCommit();
event.stopPropagation();
break;
default:
break;
}
},
2019-08-14 08:58:03 +08:00
[viewNextCommit, viewPrevCommit],
);
if (commitData.length === 0) {
return null;
}
return (
<Fragment>
2019-03-16 11:05:52 +08:00
<span className={styles.IndexLabel}>{label}</span>
<Button
className={styles.Button}
2019-03-16 11:05:52 +08:00
disabled={selectedFilteredCommitIndex === 0 || numFilteredCommits === 0}
onClick={viewPrevCommit}
2019-08-14 08:58:03 +08:00
title="Select previous commit">
<ButtonIcon type="previous" />
</Button>
<div
className={styles.Commits}
onKeyDown={handleKeyDown}
style={{
2019-03-16 11:05:52 +08:00
flex: numFilteredCommits > 0 ? '1 1 auto' : '0 0 auto',
maxWidth:
numFilteredCommits > 0
? numFilteredCommits * maxBarWidth
: undefined,
}}
2019-08-14 08:58:03 +08:00
tabIndex={0}>
2019-03-16 11:05:52 +08:00
{numFilteredCommits > 0 && (
<SnapshotCommitList
commitDurations={commitDurations}
commitTimes={commitTimes}
filteredCommitIndices={filteredCommitIndices}
selectedCommitIndex={selectedCommitIndex}
selectedFilteredCommitIndex={selectedFilteredCommitIndex}
selectCommitIndex={selectCommitIndex}
/>
)}
2019-03-16 11:05:52 +08:00
{numFilteredCommits === 0 && (
<div className={styles.NoCommits}>No commits</div>
)}
2019-03-11 10:16:34 +08:00
</div>
<Button
className={styles.Button}
disabled={
selectedFilteredCommitIndex === null ||
2019-03-16 11:05:52 +08:00
selectedFilteredCommitIndex >= numFilteredCommits - 1
}
onClick={viewNextCommit}
2019-08-14 08:58:03 +08:00
title="Select next commit">
<ButtonIcon type="next" />
</Button>
</Fragment>
2019-03-11 10:16:34 +08:00
);
}