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

chore: separate aifilter into subcomponents and make it nicer #28735

Merged
merged 28 commits into from
Feb 17, 2025

Conversation

veryayskiy
Copy link
Contributor

  • Separate the AI filter component into subcomponents
  • Use taxonomy.py instead of hard coded values
  • Move the component into a button instead of collapses element
  • Add validation of filters before applying

Before:
Screenshot 2025-02-14 at 17 40 28

After:
Screenshot 2025-02-14 at 17 40 53

@veryayskiy
Copy link
Contributor Author

Some of the files I guess changed because of the "ruff check --fix"

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

PR Summary

This PR refactors the AI filter component in the session recordings interface, improving its organization and user experience while adding validation for filters.

  • Moved AI filter from a collapse element to a button-based interface in /frontend/src/scenes/session-recordings/components/AiFilter/AiFilter.tsx
  • Added validation in sessionRecordingsPlaylistLogic.ts to ensure filters meet type requirements before being applied
  • Created new AiFilterIntro component with FilmCameraHog icon and consent popover for better UX
  • Replaced hardcoded property definitions with dynamic taxonomy data from posthog.taxonomy.taxonomy in ai_filter_prompts.py
  • Added preference rules for property type selection (event > session > person) when handling ambiguous cases

14 file(s) reviewed, 8 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines +258 to +259
{' '}
{typeof content === 'function' ? content({ activeItem }) : content}
Copy link
Contributor

Choose a reason for hiding this comment

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

syntax: unnecessary whitespace character before content rendering

Suggested change
{' '}
{typeof content === 'function' ? content({ activeItem }) : content}
{typeof content === 'function' ? content({ activeItem }) : content}

>
<DraggableToNotebook href={notebooksHref}>{filterActions}</DraggableToNotebook>

<div className="flex flex-col relative w-full bg-bg-light overflow-hidden h-full Playlist__list">
Copy link
Contributor

Choose a reason for hiding this comment

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

style: duplicate class name 'Playlist__list' applied to nested div, may cause styling conflicts

return (
<>
<div className="flex">
<AIConsentPopoverWrapper placement="right-end" middleware={[offset(-12)]} showArrow>
Copy link
Contributor

Choose a reason for hiding this comment

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

style: offset(-12) seems like a magic number. Consider defining this as a constant with a descriptive name to explain its purpose.

@@ -264,8 +264,7 @@ def get_decide(request: HttpRequest):
request,
generate_exception_response(
"decide",
f"Team with ID {team.id} cannot access the /decide endpoint."
f"Please contact us at [email protected]",
f"Team with ID {team.id} cannot access the /decide endpoint.Please contact us at [email protected]",
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Missing space after period in error message which may affect readability

Comment on lines +124 to +134
if ('duration' in filters) {
if (!Array.isArray(filters.duration)) {
return false
}
if (
filters.duration.length > 0 &&
(!filters.duration[0]?.type || !filters.duration[0]?.key || !filters.duration[0]?.operator)
) {
return false
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Duration validation could be more robust - currently only checks first element's properties but array could contain invalid elements after index 0

Comment on lines +136 to +144
if ('filter_group' in filters) {
const group = filters.filter_group
if (!group || typeof group !== 'object') {
return false
}
if (!('type' in group) || !('values' in group) || !Array.isArray(group.values)) {
return false
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: filter_group validation should also check that 'type' is a valid FilterLogicalOperator value

Comment on lines +471 to +474
if (!isValidRecordingFilters(filters)) {
console.error('Invalid filters provided:', filters)
return state
}
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Consider throwing an error or showing a user-facing notification instead of just logging to console when invalid filters are provided

Comment on lines +314 to +315
Full list of available properties and their definitions:
{json.dumps(CORE_FILTER_DEFINITIONS_BY_GROUP, indent=2)}
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Using f-strings with json.dumps() could potentially cause issues if the JSON contains curly braces. Consider using a different string formatting approach or escaping the braces

Copy link
Member

Choose a reason for hiding this comment

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

we should probably prompt "when there is a choice prefer event properties over session properties and session properties over person properties"

event properties are faster and generally better match people's expected results better

Copy link
Contributor

github-actions bot commented Feb 14, 2025

Size Change: 0 B

Total Size: 1.21 MB

ℹ️ View Unchanged
Filename Size
frontend/dist/toolbar.js 1.21 MB

compressed-size-action

@posthog-bot
Copy link
Contributor

📸 UI snapshots have been updated

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

Triggered by this commit.

👉 Review this PR's diff of snapshots.

Copy link
Member

Choose a reason for hiding this comment

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

is the pop up here expected?

Copy link
Member

@pauldambra pauldambra left a comment

Choose a reason for hiding this comment

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

quick pass

Copy link
Member

Choose a reason for hiding this comment

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

same popping in here

@@ -83,6 +88,8 @@ export function Playlist({
750: 'medium',
})

const [isExpanded, setIsExpanded] = useState(false)
Copy link
Member

Choose a reason for hiding this comment

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

really this should be on a kea logic but I'll pretend not to notice 😉

className={clsx('Playlist h-full min-h-96 w-full min-w-96 lg:min-w-[560px] order-first xl:order-none', {
'Playlist--wide': size !== 'small',
'Playlist--embedded': embedded,
className={clsx('flex flex-col w-full gap-2 h-full', {
Copy link
Member

Choose a reason for hiding this comment

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

are we sure we're not using the wide and embedded classes?
they might be necessary when shared or full screen?

ref={playlistRef}
data-attr={dataAttr}
className={clsx('Playlist w-full min-w-60 min-h-96', {
'Playlist--wide': size !== 'small',
Copy link
Member

Choose a reason for hiding this comment

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

ah, they're down here 🤣

* @param filters - The filters to check.
* @returns True if the filters are valid, false otherwise.
*/
export function isValidRecordingFilters(filters: Partial<RecordingUniversalFilters>): boolean {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export function isValidRecordingFilters(filters: Partial<RecordingUniversalFilters>): boolean {
export function isValidRecordingFilters(filters: Partial<RecordingUniversalFilters>): x is Partial<RecordingUniversalFilters> {

can do this so TS can do type narrowing

Comment on lines +314 to +315
Full list of available properties and their definitions:
{json.dumps(CORE_FILTER_DEFINITIONS_BY_GROUP, indent=2)}
Copy link
Member

Choose a reason for hiding this comment

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

we should probably prompt "when there is a choice prefer event properties over session properties and session properties over person properties"

event properties are faster and generally better match people's expected results better

@veryayskiy veryayskiy merged commit 53f5d58 into master Feb 17, 2025
104 checks passed
@veryayskiy veryayskiy deleted the chore/sr/chat-with-recordings branch February 17, 2025 13:28
HamedMP pushed a commit that referenced this pull request Feb 19, 2025
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Peter Kirkham <[email protected]>
Co-authored-by: Paul D'Ambra <[email protected]>
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