-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: date filter experiment #10462
feat: date filter experiment #10462
Conversation
Minor flyby feedback: This PR popped up in my email with the With conventional commits, the things in the bracket is the scope, a.k.a what part of the project you're touching, so This also sounds like a full blown feature, hence |
Ah, sorry, let me remove that, I wasn't sure how to flag it as an experiment. It's a fix, but more of a UX fix, not a bug fix. The PR seems huge because there's code duplication, because of the feature flag, but the actual changes are not really that big. |
I think your linter ran through everything which is why there's so many files changed 😮 , you can run black on just a single file at a time |
77f3568
to
9718822
Compare
ah, my bad, I removed anything that wasn't part of the original commits |
Checked out locally and I get some weird layout going on @kappa90 are you getting this locally as well? Maybe something weird on a merge from master? |
@kappa90 I think this might be the culprit - https://github.com/PostHog/posthog/pull/10462/files#diff-c908934c4df2c03e9cb3f37eef8e2b4c921b0a0bd82c1c088b04c2d595a5f4bfR1 Should be |
Ah shoot, fixing it, I refactored some files and class names yesterday to include "rolling" and that css class got out. Thanks! |
@@ -15,8 +15,8 @@ export interface LemonInputProps | |||
value?: string | number | |||
defaultValue?: string | |||
placeholder?: string | |||
onChange?: (newValue: string) => void | |||
onPressEnter?: (newValue: string) => void | |||
onChange?: (newValue: string | number) => void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if this has any wider impacts. Running yarn typescript:check
definitely throws some issues up.
Would be awesome if we can infer the type using a generic for value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reverted it, and it shows other problems, I think the LemonInput component needs to be refactored. I tried a couple things but couldn't figure it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Browser textfields only support strings. Even with type="number"
, you need to access a special variable input.valueAsNumber
to get the numeric value, complicating everything. If we add another component for number inputs, it's best to encapsulate this in a LemonInputNumeric
component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made this to solve the issue: #10533
} | ||
} | ||
|
||
.date-options-selector-popup { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a massive fan of this but I know why it's here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any idea how could I apply a class to that popup otherwise?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick flyby before I dig in deeper: I see a lot of different types of dropdowns on the page.
How closely is the new dropdown following the design in figma? I don't have a link nearby to check now, but I think we are converging on the new lemony look everywhere.
This would look out of place with the other chart dropdowns, but even then the hover color is different now. Something to check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few more comments
propsChanged: (props) => { | ||
// when props change, automatically reset the Select key to reflect the change | ||
const { dateFrom, dateTo, defaultValue, dateOptions, isDateFormatted } = props | ||
if (dateFrom && dayjs(dateFrom).isValid() && dayjs(dateTo).isValid()) { | ||
actions.setCurrentKey(`${dateFrom} - ${dateTo}`) | ||
} else { | ||
const currKey = dateFilterToText(dateFrom, dateTo, defaultValue, dateOptions, false) | ||
actions.setCurrentKey( | ||
isDateFormatted && !(currKey in dateOptions) | ||
? dateFilterToText(dateFrom, dateTo, defaultValue, dateOptions, true) | ||
: currKey | ||
) | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest one additional layer of safety here: generate the currentKey
, save it as a variable, and only set
it if it's not the same as the current currentKey
. It's possible to get into loops when responding to events of all types, and it's safer to code defensively, minimising changes. Even if not now, always code with the assumption that you never know what other code will live with your code in the future. E.g. someone could add a bunch of rapidly changing props that trigger this event and the actions, without needing to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks for pointing that out!
data-attr="date-filter" | ||
bordered={bordered} | ||
id="daterange_selector" | ||
value={currentKey} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was confused when I saw the currentKey
prop. Knowing it's the value
of the field cleared everything up. So could we rename it value
? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed this to value
useEffect(() => { | ||
window.addEventListener('mousedown', onClickOutside) | ||
return () => { | ||
window.removeEventListener('mousedown', onClickOutside) | ||
} | ||
}, [isOpen]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a useOutsideClickHandler
helper. Could this be used instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also feel like this onClickOutside handling is also slightly out of scope of this component, and could just be handled by <Popup>
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made it so that Popup
can now handle additional refs passed as props, so that it can manage nested popups, and removed all the click handling logic that was outside of it!
This is a massive improvement to the date picking workflow, @kappa90. I know there are still some implementation details being worked out, but generally based on the demo gif you shared this looks really well done. There are two topics I'd like to point out (also pointed out by you and @mariusandra):
It's hard to know user intent. That issue assumes the user is wanting to select another fixed range. It's equally feasible that the user wants to select a rolling range. Given that it's two clicks to get back to the calendar picker, I'm not sure this should block shipping this change. If we were to show the calendar by default, and the user wanted a rolling range, they'd still have to click back to get to the menu that allows them to select a relative range. It's the same amount of effort either way and starting from the same menu does make it obvious how to get back to the calendar. This one might need more discussion before settling on a fix. Marius pointed out:
This is happening all over the product even with features that we just shipped. I've been trying to call out opportunities to make these more consistent as we get new lemon components. I agree that it's a good and valuable change to make. I do think it should be distinct from this issue only because I'd like to see this change ship sooner than later. I've been working on longer term consistency changes for the insight results container at https://www.figma.com/file/gQBj9YnNgD8YW4nBwCVLZf/PostHog-App?node-id=11224%3A50863. Maybe we can schedule that for a follow up project? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
7c7a718
to
109c513
Compare
95b97fe
to
69e1c5c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost :)
frontend/src/lib/components/DateFilter/RollingDateRangeFilter.tsx
Outdated
Show resolved
Hide resolved
frontend/src/lib/components/DateFilter/DateFilterExperiment.scss
Outdated
Show resolved
Hide resolved
We rescoped this experiment to only change the interface. In the next experiment we will change the default |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hit the button!
@@ -195,7 +195,8 @@ function DateFilterExperiment({ | |||
dateOptions = dateMappingExperiment, | |||
isDateFormatted = true, | |||
}: RawDateFilterProps): JSX.Element { | |||
const logicProps = { dateFrom, dateTo, onChange, defaultValue, dateOptions, isDateFormatted } | |||
const key = useRef(uuid()).current |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice trick! If we'd migrate to React 18, we could use the new useId
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes me question why we need Kea here but in any case it works 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using kea logic with components is a blurry subject, especially in the case of small components that share no state with the outside world. This could have been in pure React, and I wouldn't have minded.
However I do think it's beneficial to keep a strong line between code operating at the application data level (in kea) vs code at the view level (stateless interactive components, react templates around application data). I also know that everything expands in scope, and I've seen too many times how data in that useState
call eventually wants to interact with data from elsewhere in the app, requiring a rewrite of the component into logic land. Hence I suggest to just save future you the trouble and write a logic directly.
Since you're considering work that might never happen, it's hard to draw a line. What if we wrote everything with useState
, and want to go fancy and show a heatmap of events on the calendar, like google flights does for the price? Rewrite to a logic? Parallel system of network calls to load the data in React hooks? 🤷
Frontend trends come and go, and if we remain consistent in our approach and technologies, we'll build a more maintainable app in the long run.
Should this have a highlight tag + some prewritten release notes? |
Problem
Related: https://github.com/PostHog/product-internal/pull/305
Experiment could close: #9727, #9453, #9027, #8059, #7625
Does not fix (up for discussion if still relevant): #9664
Following the conversion in issue #9727, and the other mentioned issues, the entire date picker flow has been improved.
All changes are behind a feature flag, in order to be able to test them as an experiment.
Changes
Behind feature flag:
{number} {period}
.days
,weeks
,months
,quarter
Last 3 days
is removed as it becomes the default for the rolling date range pickerGrouped by
interval is automatically selected. In particular:hour
day
month
Not behind a feature flag (fix):
date_from
filter, to indicate what is the date window, which, if not selected from the UI, is initially set from backend. Not exposing this parameter can lead to buggy states in the UI, which doesn't know information about the insight date range.How did you test this code?
Cypress tests for the new rolling range picker, and the automatic interval selection.
GIF/Images
New flow: