Skip to content
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: Add initial Core Web Vitals UI behind FF #27336

Merged

Conversation

rafaeelaudibert
Copy link
Member

@rafaeelaudibert rafaeelaudibert commented Jan 7, 2025

First PR on the Core Web Vitals project!

Changes

This is a simple PR creating the page and route for our upcoming Core Web Vitals UI
There're some slight changes to some components so that our <Filters /> component has the proper space to render on Mobile

This is hidden behind a FF for now because there isn't anything to see, but it should go behind a Beta FF soon!

image
image

https://www.loom.com/share/2ac44609fe894f9182ea76a7e0d7a20b?sid=cab54855-c9b6-40f8-bba8-579c676f89d3

Does this work well for both Cloud and self-hosted?

Yes sir

How did you test this code?

Manual testing, looked around the app comparing with prod to guarantee changes to Filters had no regressions around the app

@rafaeelaudibert rafaeelaudibert force-pushed the add-web-vitals-secondary-page-to-web-analytics branch from a65cd6b to b32deb8 Compare January 7, 2025 21:29
@rafaeelaudibert rafaeelaudibert changed the title Add initial Core Web Vitals UI behind FF feat: Add initial Core Web Vitals UI behind FF Jan 7, 2025
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this to a .ts file but git wasn't smart enough to notice that, see below

@@ -688,8 +708,31 @@ export const webAnalyticsLogic = kea<webAnalyticsLogicType>([
}
}

const pathCleaningSettingsUrl = urls.settings('project-product-analytics', 'path-cleaning')
const customChannelTypesUrl = urls.settings('environment-web-analytics', 'channel-type')
// TODO: Use actual web vitals tab, this is just a placeholder
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not happening on this PR, this will be a thing on the next PR

Comment on lines 1861 to 1862
'/web': (pathParams, queryParams) => setFilters(actions, values, pathParams, queryParams),
'/web/:productTab': (pathParams, queryParams) => setFilters(actions, values, pathParams, queryParams),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't get this to work with a single string. I tried all sorts of regexes, but I don't think kea is that powerful. @mariusandra if you're keen to help here :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you're trying to achieve, and Kea is as powerful as the user 😅. urlToAction takes a function that returns an object, so feel free to add whatever rows into the object that you need to.

    urlToAction(({ actions, values }) => {
        const obj = {}
        const handler = (path, search, hash) => {...}
        for (...) { obj[`/web/${product.name}`] => handler }
        return obj
    })

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, of course, it's a function, I can just create the keys programatically, thanks

Comment on lines 1987 to 1989
if (device_tab && device_tab !== values._deviceTab) {
actions.setDeviceTab(device_tab)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love so much if our style allowed this to be inlined, it's just so clean. One can only wonder ⭐

Suggested change
if (device_tab && device_tab !== values._deviceTab) {
actions.setDeviceTab(device_tab)
}
if (device_tab && device_tab !== values._deviceTab) actions.setDeviceTab(device_tab)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And there are others who'll consider the straightforwardness of the non-inline version as clean and elegant.

We don't support inline ifs to avoid bugs, which happen much easier this ways. While you or I might not make any, considering how this company is growing and how many people work on the codebase, we need some structure to maintain sanity :).

Copy link
Member Author

@rafaeelaudibert rafaeelaudibert Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't support inline ifs to avoid bugs, which happen much easier this ways.

Yeah, I can get behind, hence why I won't propose changing this, I can withstand spending 2 seconds adding curly braces if we can avoid the odd bug.

}),
selectors(({ actions, values }) => ({
breadcrumbs: [
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not sure how breadcrumbs work. Who's accessing these? This is like magic to me

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whatever is your active scene, and what is that scene's logic and component, is recorded in sceneLogic (each scene exports its data with export const scene: SceneExport = ...). If the scene's logic contains a breadcrumbs selector, we use it to show breadcrumbs via breadcrumbsLogic

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the scene's logic contains a breadcrumbs selector

Ah ok, that's the confusing bit for me. So we're dynamically accessing the logic exported on SceneExport and then conditionally checking if they have a breadcrumbs selector? Sounds like typescript hell, but that makes sense. And then, if there's no selector, we simply use the SceneExport title as the crumb, right?

@posthog-bot
Copy link
Contributor

📸 UI snapshots have been updated

4 snapshot changes in total. 0 added, 4 modified, 0 deleted:

Triggered by this commit.

👉 Review this PR's diff of snapshots.

Copy link
Contributor

github-actions bot commented Jan 7, 2025

Size Change: +87 B (+0.01%)

Total Size: 1.11 MB

ℹ️ View Unchanged
Filename Size Change
frontend/dist/toolbar.js 1.11 MB +87 B (+0.01%)

compressed-size-action

@posthog-bot
Copy link
Contributor

📸 UI snapshots have been updated

1 snapshot changes in total. 0 added, 1 modified, 0 deleted:

  • chromium: 0 added, 1 modified, 0 deleted (diff for shard 2)
  • webkit: 0 added, 0 modified, 0 deleted

Triggered by this commit.

👉 Review this PR's diff of snapshots.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could possibly also use this: https://keajs.org/docs/plugins/window-values/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but then I need to import TAILWIND_BREAKPOINTS into every logic that wants to know the screen size and reimplement the exact same logic. Using this hook should be much simpler.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reimplement the exact same logic? Not unless you make one common tailwindBreakpointLogic and use that :D

}),
selectors(({ actions, values }) => ({
breadcrumbs: [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whatever is your active scene, and what is that scene's logic and component, is recorded in sceneLogic (each scene exports its data with export const scene: SceneExport = ...). If the scene's logic contains a breadcrumbs selector, we use it to show breadcrumbs via breadcrumbsLogic

Comment on lines 1861 to 1862
'/web': (pathParams, queryParams) => setFilters(actions, values, pathParams, queryParams),
'/web/:productTab': (pathParams, queryParams) => setFilters(actions, values, pathParams, queryParams),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you're trying to achieve, and Kea is as powerful as the user 😅. urlToAction takes a function that returns an object, so feel free to add whatever rows into the object that you need to.

    urlToAction(({ actions, values }) => {
        const obj = {}
        const handler = (path, search, hash) => {...}
        for (...) { obj[`/web/${product.name}`] => handler }
        return obj
    })

Copy link
Member

@robbie-c robbie-c left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, LGTM.

Long term we might want to separate these into difference scenes/logics, I don't know how much code we'll be sharing between the two views but even if it's a lot, that might be easier than having one scene for both.

Keen to see the product itself :)

@rafaeelaudibert
Copy link
Member Author

Long term we might want to separate these into difference scenes/logics, I don't know how much code we'll be sharing between the two views but even if it's a lot, that might be easier than having one scene for both.

@robbie-c Yeah, fully agreed. I reused it because I thought it was easier right now - while I don't understand kea fully. I thought we'd share a lot of code, but we'll probably only share the header, but that's easy to solve, I can just extract that to a separate component.

@robbie-c
Copy link
Member

robbie-c commented Jan 8, 2025

I don't think you need to worry about this too much right now though, let's focus on getting something in front of our users, even if it means creating some tech debt which we can clean up later

rafaeelaudibert and others added 12 commits January 8, 2025 11:51
This will allow us to more easily check whether we're on a small screen or not. Without this, we'd need to keep implementing our own breakpoint checking by using `TAILWIND_BREAKPOINTS`
This is a simple commit creating the page and route for our upcoming Core Web Vitals UI

There's some slight changes to some components so that our `<Filters />` component has the proper space to render
We changed how our filters work in the previous commit because we wanted a nicer layout for Web Analytics, but it added a couple of regressions in some other parts of the app, let's fix them :)
Even though these aren't used in the app, we need them to be exported if we want the typegen to work
This more closely explains what's this function purpose, and it also allows us to heavily simplify our types
@rafaeelaudibert rafaeelaudibert force-pushed the add-web-vitals-secondary-page-to-web-analytics branch from 901bf09 to c0910c3 Compare January 8, 2025 14:51
@rafaeelaudibert rafaeelaudibert enabled auto-merge (squash) January 8, 2025 14:51
@rafaeelaudibert rafaeelaudibert merged commit adc845f into master Jan 8, 2025
99 checks passed
@rafaeelaudibert rafaeelaudibert deleted the add-web-vitals-secondary-page-to-web-analytics branch January 8, 2025 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants