From 565d739569ca6707ff7fc75f776dce1791ba1049 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Sun, 10 Mar 2019 10:13:20 -0700 Subject: [PATCH] Added commit time filter --- src/devtools/views/Profiler/FilterModal.css | 31 ++++++++ src/devtools/views/Profiler/FilterModal.js | 75 +++++++++++++++++++ src/devtools/views/Profiler/Profiler.css | 1 + src/devtools/views/Profiler/Profiler.js | 33 ++++---- .../views/Settings/SettingsContext.js | 1 + src/devtools/views/hooks.js | 33 +++++++- src/devtools/views/root.css | 2 + 7 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 src/devtools/views/Profiler/FilterModal.css create mode 100644 src/devtools/views/Profiler/FilterModal.js diff --git a/src/devtools/views/Profiler/FilterModal.css b/src/devtools/views/Profiler/FilterModal.css new file mode 100644 index 0000000000..4403bb4064 --- /dev/null +++ b/src/devtools/views/Profiler/FilterModal.css @@ -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; +} diff --git a/src/devtools/views/Profiler/FilterModal.js b/src/devtools/views/Profiler/FilterModal.js new file mode 100644 index 0000000000..34a25e52a7 --- /dev/null +++ b/src/devtools/views/Profiler/FilterModal.js @@ -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( + 'minCommitDurationFilterEnabled', + false + ); + const [value, setValue] = useLocalStorage( + '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(null); + const modalRef = useRef(null); + + useModalDismissSignal(modalRef, dismissModal); + + useEffect(() => { + if (inputRef.current !== null) { + inputRef.current.focus(); + } + }, [inputRef]); + + return ( +
+
+ {' '} + {' '} + (ms) +
+
+ ); +} diff --git a/src/devtools/views/Profiler/Profiler.css b/src/devtools/views/Profiler/Profiler.css index e72ed4eb76..107a092f99 100644 --- a/src/devtools/views/Profiler/Profiler.css +++ b/src/devtools/views/Profiler/Profiler.css @@ -10,6 +10,7 @@ } .Content { + position: relative; flex: 1 1 auto; display: flex; flex-direction: row; diff --git a/src/devtools/views/Profiler/Profiler.js b/src/devtools/views/Profiler/Profiler.js index fff247ba7a..388d6c9d3d 100644 --- a/src/devtools/views/Profiler/Profiler.js +++ b/src/devtools/views/Profiler/Profiler.js @@ -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} />
-
-
{view}
+
+ {view} + {isFilterModalShowing && ( + + )} +
); } @@ -77,13 +86,11 @@ const NoProfilingData = () => ( ); -const RecortdingInProgress = () => { - return ( -
-
Profiling is in progress...
-
- Click the record button to stop recording. -
+const RecortdingInProgress = () => ( +
+
Profiling is in progress...
+
+ Click the record button to stop recording.
- ); -}; +
+); diff --git a/src/devtools/views/Settings/SettingsContext.js b/src/devtools/views/Settings/SettingsContext.js index 32e13338c1..2c5b16b1b0 100644 --- a/src/devtools/views/Settings/SettingsContext.js +++ b/src/devtools/views/Settings/SettingsContext.js @@ -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'); diff --git a/src/devtools/views/hooks.js b/src/devtools/views/hooks.js index c3900add8e..0218aef2e6 100644 --- a/src/devtools/views/hooks.js +++ b/src/devtools/views/hooks.js @@ -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( @@ -52,3 +52,34 @@ export function useLocalStorage( return [storedValue, setValue]; } + +export function useModalDismissSignal( + modalRef: React$Ref, + 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]); +} diff --git a/src/devtools/views/root.css b/src/devtools/views/root.css index 40b093d10c..5c01902c1f 100644 --- a/src/devtools/views/root.css +++ b/src/devtools/views/root.css @@ -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;