Added commit time filter

This commit is contained in:
Brian Vaughn
2019-03-10 10:13:20 -07:00
parent 2d68007288
commit 565d739569
7 changed files with 162 additions and 14 deletions
@@ -0,0 +1,31 @@
.Background {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--color-modal-background);
}
.Modal {
position: absolute;
top: 5px;
right: 5px;
display: inline-block;
background-color: var(--color-background);
padding: 1rem;
border: 1px solid var(--color-border);
border-radius: 0.25rem;
}
.Input {
width: 40px;
background: none;
border: 1px solid transparent;
color: var(--color-attribute-editable-value);
border-radius: 0.125rem;
font-family: var(--font-family-monospace);
font-size: var(--font-size-monospace-normal);
}
.Input:focus {
background-color: var(--color-button-background-focus);
outline: none;
}
@@ -0,0 +1,75 @@
// @flow
import React, { useCallback, useEffect, useRef } from 'react';
import { useLocalStorage, useModalDismissSignal } from '../hooks';
import styles from './FilterModal.css';
type Props = {|
dismissModal: Function,
|};
export default function FilterModal({ dismissModal }: Props) {
const [isEnabled, setIsEnabled] = useLocalStorage<boolean>(
'minCommitDurationFilterEnabled',
false
);
const [value, setValue] = useLocalStorage<number>(
'minCommitDurationFilter',
0
);
const handleNumberChange = useCallback(
({ currentTarget }) => {
const newValue = parseInt(currentTarget.value, 10);
setValue(Number.isNaN(newValue) || newValue <= 0 ? 0 : newValue);
},
[setValue]
);
const handleEnabledChange = useCallback(
({ currentTarget }) => {
setIsEnabled(currentTarget.checked);
if (currentTarget.checked) {
if (inputRef.current !== null) {
inputRef.current.focus();
}
}
},
[setIsEnabled]
);
const inputRef = useRef<HTMLInputElement | null>(null);
const modalRef = useRef<HTMLDivElement | null>(null);
useModalDismissSignal(modalRef, dismissModal);
useEffect(() => {
if (inputRef.current !== null) {
inputRef.current.focus();
}
}, [inputRef]);
return (
<div className={styles.Background}>
<div className={styles.Modal} ref={modalRef}>
<label>
<input
checked={isEnabled}
onChange={handleEnabledChange}
type="checkbox"
/>{' '}
Hide commits below
</label>{' '}
<input
className={styles.Input}
onChange={handleNumberChange}
ref={inputRef}
type="number"
value={value}
/>{' '}
(ms)
</div>
</div>
);
}
+1
View File
@@ -10,6 +10,7 @@
}
.Content {
position: relative;
flex: 1 1 auto;
display: flex;
flex-direction: row;
+20 -13
View File
@@ -1,10 +1,11 @@
// @flow
import React, { useContext, useState } from 'react';
import React, { useCallback, useContext, useState } from 'react';
import { ProfilerContext, ProfilerContextController } from './ProfilerContext';
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
import TabBar from '../TabBar';
import FilterModal from './FilterModal';
import RecordToggle from './RecordToggle';
import styles from './Profiler.css';
@@ -22,6 +23,10 @@ export default function ProfilerOuter(_: Props) {
function ProfilerInner(_: Props) {
const { hasProfilingData, isProfiling } = useContext(ProfilerContext);
const [tab, setTab] = useState('flame-chart');
const [isFilterModalShowing, setIsFilterModalShowing] = useState(false);
const showFilterModal = useCallback(() => setIsFilterModalShowing(true));
const dismissFilterModal = useCallback(() => setIsFilterModalShowing(false));
let view = null;
if (isProfiling) {
@@ -52,12 +57,16 @@ function ProfilerInner(_: Props) {
tabs={tabs}
/>
<div className={styles.Spacer} />
<Button disabled title="Filter commits by duration">
{/* TODO (profiling) Wire up filter button */}
<Button onClick={showFilterModal} title="Filter commits by duration">
<ButtonIcon type="filter" />
</Button>
</div>
<div className={styles.Content}>{view}</div>
<div className={styles.Content}>
{view}
{isFilterModalShowing && (
<FilterModal dismissModal={dismissFilterModal} />
)}
</div>
</div>
);
}
@@ -77,13 +86,11 @@ const NoProfilingData = () => (
</div>
);
const RecortdingInProgress = () => {
return (
<div className={styles.Column}>
<div className={styles.Header}>Profiling is in progress...</div>
<div className={styles.Row}>
Click the record button <RecordToggle /> to stop recording.
</div>
const RecortdingInProgress = () => (
<div className={styles.Column}>
<div className={styles.Header}>Profiling is in progress...</div>
<div className={styles.Row}>
Click the record button <RecordToggle /> to stop recording.
</div>
);
};
</div>
);
@@ -141,6 +141,7 @@ function updateThemeVariables(theme: Theme): void {
updateStyleHelper(theme, 'color-dimmest');
updateStyleHelper(theme, 'color-jsx-arrow-brackets');
updateStyleHelper(theme, 'color-jsx-arrow-brackets-inverted');
updateStyleHelper(theme, 'color-modal-background');
updateStyleHelper(theme, 'color-record-active');
updateStyleHelper(theme, 'color-record-hover');
updateStyleHelper(theme, 'color-record-inactive');
+32 -1
View File
@@ -1,6 +1,6 @@
// @flow
import { useCallback, useLayoutEffect, useState } from 'react';
import { useCallback, useEffect, useLayoutEffect, useState } from 'react';
// Forked from https://usehooks.com/useLocalStorage/
export function useLocalStorage<T>(
@@ -52,3 +52,34 @@ export function useLocalStorage<T>(
return [storedValue, setValue];
}
export function useModalDismissSignal(
modalRef: React$Ref<any>,
dismissCallback: Function
): void {
useEffect(() => {
const handleKeyDown = ({ key }: any) => {
if (key === 'Escape') {
dismissCallback();
}
};
const handleMouseOrTouch = ({ target }: any) => {
// $FlowFixMe
if (modalRef.current !== null && !modalRef.current.contains(target)) {
dismissCallback();
}
};
const body = ((document.body: any): HTMLBodyElement);
body.addEventListener('keydown', handleKeyDown);
body.addEventListener('mousedown', handleMouseOrTouch);
body.addEventListener('touchstart', handleMouseOrTouch);
return () => {
body.removeEventListener('keydown', handleKeyDown);
body.removeEventListener('mousedown', handleMouseOrTouch);
body.removeEventListener('touchstart', handleMouseOrTouch);
};
}, [modalRef, dismissCallback]);
}
+2
View File
@@ -23,6 +23,7 @@
--light-color-dimmest: #eff0f1;
--light-color-jsx-arrow-brackets: #333333;
--light-color-jsx-arrow-brackets-inverted: rgba(255, 255, 255, 0.7);
--light-color-modal-background: rgba(255, 255, 255, 0.25);
--light-color-record-active: #fc3a4b;
--light-color-record-hover: #000000;
--light-color-record-inactive: #cfd1d5;
@@ -52,6 +53,7 @@
--dark-color-dimmest: #4f5766;
--dark-color-jsx-arrow-brackets: #777d88;
--dark-color-jsx-arrow-brackets-inverted: rgba(255, 255, 255, 0.7);
--dark-color-modal-background: rgba(0, 0, 0, 0.25);
--dark-color-record-active: #fc3a4b;
--dark-color-record-hover: #ffffff;
--dark-color-record-inactive: #777d88;