Skip to content

Commit

Permalink
feat: watch next and sort different (#25701)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Michael Matloka <[email protected]>
  • Loading branch information
3 people authored Oct 22, 2024
1 parent 8fcd33b commit c3b0cb2
Show file tree
Hide file tree
Showing 41 changed files with 674 additions and 425 deletions.

Large diffs are not rendered by default.

Binary file modified frontend/__snapshots__/components-playlist--default--dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/components-playlist--default--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/components-playlist--with-footer--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions frontend/src/lib/components/CompactList/CompactList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { themeLogic } from '~/layout/navigation-3000/themeLogic'
import { EmptyMessage, EmptyMessageProps } from '../EmptyMessage/EmptyMessage'

interface CompactListProps {
title: string
title: string | JSX.Element
viewAllURL?: string
loading: boolean
items: any[]
Expand All @@ -34,7 +34,7 @@ export function CompactList({
style={theme?.boxStyle}
>
<div className="CompactList__header">
<h3 className="px-2 truncate" title={title}>
<h3 className="px-2 truncate" title={typeof title === 'string' ? title : undefined}>
{title}
</h3>
{viewAllURL && <LemonButton to={viewAllURL}>View all</LemonButton>}
Expand Down
80 changes: 46 additions & 34 deletions frontend/src/lib/components/Playlist/Playlist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export type PlaylistProps<T> = {
onChangeSections?: (activeKeys: string[]) => void
'data-attr'?: string
activeItemId?: string
controls?: JSX.Element | null
}

const CounterBadge = ({ children }: { children: React.ReactNode }): JSX.Element => (
Expand All @@ -70,6 +71,7 @@ export function Playlist<
onSelect,
onChangeSections,
'data-attr': dataAttr,
controls,
}: PlaylistProps<T>): JSX.Element {
const [controlledActiveItemId, setControlledActiveItemId] = useState<T['id'] | null>(
selectInitialItem && sections[0].items[0] ? sections[0].items[0].id : null
Expand Down Expand Up @@ -115,6 +117,7 @@ export function Playlist<
setActiveItemId={onChangeActiveItem}
onChangeSections={onChangeSections}
emptyState={listEmptyState}
controls={controls}
/>
)}
<Resizer
Expand Down Expand Up @@ -154,6 +157,7 @@ function List<
onScrollListEdge,
loading,
emptyState,
controls,
}: {
title: PlaylistProps<T>['title']
notebooksHref: PlaylistProps<T>['notebooksHref']
Expand All @@ -166,6 +170,7 @@ function List<
onScrollListEdge: PlaylistProps<T>['onScrollListEdge']
loading: PlaylistProps<T>['loading']
emptyState: PlaylistProps<T>['listEmptyState']
controls?: JSX.Element | null
}): JSX.Element {
const [activeHeaderActionKey, setActiveHeaderActionKey] = useState<string | null>(null)
const lastScrollPositionRef = useRef(0)
Expand Down Expand Up @@ -203,42 +208,49 @@ function List<
return (
<div className="flex flex-col w-full bg-bg-light overflow-hidden border-r h-full">
<DraggableToNotebook href={notebooksHref}>
<div className="shrink-0 relative flex justify-between items-center p-1 gap-1 whitespace-nowrap border-b">
<LemonButton size="small" icon={<IconCollapse className="rotate-90" />} onClick={onClickCollapse} />
<span className="py-1 flex flex-1 gap-2">
{title ? (
<span className="font-bold uppercase text-xs my-1 tracking-wide flex gap-1 items-center">
{title}
</span>
) : null}
<Tooltip
placement="bottom"
title={
<>
Showing {itemsCount} results.
<br />
Scrolling to the bottom or the top of the list will load older or newer results
respectively.
</>
}
>
<span>
<CounterBadge>{Math.min(999, itemsCount)}+</CounterBadge>
</span>
</Tooltip>
</span>
{headerActions.map(({ key, icon, tooltip, children }) => (
<div className="flex flex-col gap-1">
<div className="shrink-0 relative flex justify-between items-center p-1 gap-1 whitespace-nowrap border-b">
<LemonButton
key={key}
icon={icon}
tooltip={tooltip}
size="small"
active={activeHeaderActionKey === key}
onClick={() => setActiveHeaderActionKey(activeHeaderActionKey === key ? null : key)}
>
{children}
</LemonButton>
))}
icon={<IconCollapse className="rotate-90" />}
onClick={onClickCollapse}
/>
<span className="py-1 flex flex-1 gap-2">
{title ? (
<span className="font-bold uppercase text-xs my-1 tracking-wide flex gap-1 items-center">
{title}
</span>
) : null}
<Tooltip
placement="bottom"
title={
<>
Showing {itemsCount} results.
<br />
Scrolling to the bottom or the top of the list will load older or newer results
respectively.
</>
}
>
<span>
<CounterBadge>{Math.min(999, itemsCount)}+</CounterBadge>
</span>
</Tooltip>
</span>
{headerActions.map(({ key, icon, tooltip, children }) => (
<LemonButton
key={key}
icon={icon}
tooltip={tooltip}
size="small"
active={activeHeaderActionKey === key}
onClick={() => setActiveHeaderActionKey(activeHeaderActionKey === key ? null : key)}
>
{children}
</LemonButton>
))}
</div>
{controls ? <div className="w-full border-b">{controls}</div> : null}
<LemonTableLoader loading={loading} />
</div>
</DraggableToNotebook>
Expand Down
1 change: 0 additions & 1 deletion frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ export const FEATURE_FLAGS = {
INSIGHT_VARIABLES: 'insight_variables', // owner: @Gilbert09 #team-data-warehouse
WEB_EXPERIMENTS: 'web-experiments', // owner: @team-feature-success
BIGQUERY_DWH: 'bigquery-dwh', // owner: @Gilbert09 #team-data-warehouse
REPLAY_DEFAULT_SORT_ORDER_EXPERIMENT: 'replay-order-by-experiment', // owner: #team-replay
ENVIRONMENTS: 'environments', // owner: @Twixes #team-product-analytics
BILLING_PAYMENT_ENTRY_IN_APP: 'billing-payment-entry-in-app', // owner: @zach
LEGACY_ACTION_WEBHOOKS: 'legacy-action-webhooks', // owner: @mariusandra #team-cdp
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -10260,6 +10260,10 @@
{
"const": "mouse_activity_count",
"type": "string"
},
{
"const": "activity_score",
"type": "string"
}
]
},
Expand Down Expand Up @@ -10833,6 +10837,10 @@
"active_seconds": {
"type": "number"
},
"activity_score": {
"description": "calculated on the backend so that we can sort by it, definition may change over time",
"type": "number"
},
"click_count": {
"type": "number"
},
Expand Down
1 change: 1 addition & 0 deletions frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ export interface RecordingsQuery extends DataNode<RecordingsQueryResponse> {
| 'click_count'
| 'keypress_count'
| 'mouse_activity_count'
| 'activity_score'
limit?: integer
offset?: integer
user_modified_filters?: Record<string, any>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/scenes/project-homepage/ProjectHomepage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { Dashboard } from 'scenes/dashboard/Dashboard'
import { dashboardLogic, DashboardLogicProps } from 'scenes/dashboard/dashboardLogic'
import { projectHomepageLogic } from 'scenes/project-homepage/projectHomepageLogic'
import { WatchNextPanel } from 'scenes/project-homepage/WatchNextPanel'
import { Scene, SceneExport } from 'scenes/sceneTypes'
import { inviteLogic } from 'scenes/settings/organization/inviteLogic'
import { urls } from 'scenes/urls'
Expand All @@ -24,7 +25,6 @@ import { DashboardPlacement } from '~/types'

import { RecentInsights } from './RecentInsights'
import { RecentPersons } from './RecentPersons'
import { RecentRecordings } from './RecentRecordings'

export const scene: SceneExport = {
component: ProjectHomepage,
Expand Down Expand Up @@ -70,7 +70,7 @@ export function ProjectHomepage(): JSX.Element {
<div className="ProjectHomepage__lists">
<RecentInsights />
<RecentPersons />
<RecentRecordings />
<WatchNextPanel />
</div>
{dashboardLogicProps ? (
<HomeDashboard dashboardLogicProps={dashboardLogicProps} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import './ProjectHomepage.scss'

import { IconInfo } from '@posthog/icons'
import { useActions, useValues } from 'kea'
import { CompactList } from 'lib/components/CompactList/CompactList'
import { dayjs } from 'lib/dayjs'
import { IconPlayCircle } from 'lib/lemon-ui/icons'
import { ProfilePicture } from 'lib/lemon-ui/ProfilePicture'
import { Tooltip } from 'lib/lemon-ui/Tooltip'
import { humanFriendlyDuration } from 'lib/utils'
import { eventUsageLogic } from 'lib/utils/eventUsageLogic'
import { asDisplay } from 'scenes/persons/person-utils'
import { sessionPlayerModalLogic } from 'scenes/session-recordings/player/modal/sessionPlayerModalLogic'
import { sessionRecordingsPlaylistLogic } from 'scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic'
import {
DEFAULT_RECORDING_FILTERS,
sessionRecordingsPlaylistLogic,
} from 'scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic'
import { teamLogic } from 'scenes/teamLogic'
import { urls } from 'scenes/urls'

Expand All @@ -28,7 +32,7 @@ export function RecordingRow({ recording }: RecordingRowProps): JSX.Element {
return (
<ProjectHomePageCompactListItem
title={asDisplay(recording.person)}
subtitle={`Recorded ${dayjs(recording.start_time).fromNow()}`}
subtitle={`Activity score: ${parseFloat((recording.activity_score ?? 0).toFixed(2))}`}
prefix={<ProfilePicture name={asDisplay(recording.person)} />}
suffix={
<div className="flex items-center justify-end text-text-3000">
Expand All @@ -47,15 +51,28 @@ export function RecordingRow({ recording }: RecordingRowProps): JSX.Element {
)
}

export function RecentRecordings(): JSX.Element {
export function WatchNextPanel(): JSX.Element {
const { currentTeam } = useValues(teamLogic)
const sessionRecordingsListLogicInstance = sessionRecordingsPlaylistLogic({ logicKey: 'projectHomepage' })
const sessionRecordingsListLogicInstance = sessionRecordingsPlaylistLogic({
logicKey: 'projectHomepage',
filters: {
...DEFAULT_RECORDING_FILTERS,
order: 'activity_score',
},
})
const { sessionRecordings, sessionRecordingsResponseLoading } = useValues(sessionRecordingsListLogicInstance)

return (
<>
<CompactList
title="Recent recordings"
title={
<Tooltip title="A selection of the most interesting recordings. We use multiple signals to calculate an activity score.">
<div className="flex items-center gap-1.5">
<span>Watch next</span>
<IconInfo className="text-lg" />
</div>
</Tooltip>
}
viewAllURL={urls.replay()}
loading={sessionRecordingsResponseLoading}
emptyMessage={
Expand All @@ -68,7 +85,7 @@ export function RecentRecordings(): JSX.Element {
}
: {
title: 'Recordings are not enabled for this project',
description: 'Once recordings are enabled, new recordings will display here.',
description: 'Once recordings are enabled, recordings will display here.',
buttonText: 'Enable recordings',
buttonTo: urls.settings('project-replay'),
}
Expand Down
38 changes: 0 additions & 38 deletions frontend/src/scenes/session-recordings/filters/OrderingFilters.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { LemonSelect } from '@posthog/lemon-ui'
import clsx from 'clsx'
import { useActions, useMountedLogic, useValues } from 'kea'
import { DateFilter } from 'lib/components/DateFilter/DateFilter'
Expand All @@ -14,7 +13,6 @@ import { cohortsModel } from '~/models/cohortsModel'
import { AndOrFilterSelect } from '~/queries/nodes/InsightViz/PropertyGroupFilters/AndOrFilterSelect'
import { RecordingUniversalFilters } from '~/types'

import { sessionRecordingsPlaylistLogic } from '../playlist/sessionRecordingsPlaylistLogic'
import { DurationFilter } from './DurationFilter'

export const RecordingsUniversalFilters = ({
Expand All @@ -29,9 +27,6 @@ export const RecordingsUniversalFilters = ({
useMountedLogic(cohortsModel)
useMountedLogic(actionsModel)

const { orderBy } = useValues(sessionRecordingsPlaylistLogic)
const { setOrderBy } = useActions(sessionRecordingsPlaylistLogic)

const durationFilter = filters.duration[0]

return (
Expand Down Expand Up @@ -92,56 +87,6 @@ export const RecordingsUniversalFilters = ({
durationTypeFilter={durationFilter.key}
pageKey="session-recordings"
/>
<span className="font-medium">sorted by</span>
<LemonSelect
options={[
{
value: 'start_time',
label: 'Latest',
},
{
label: 'Longest',
options: [
{
value: 'duration',
label: 'Total duration',
},
{
value: 'active_seconds',
label: 'Active duration',
},
{
value: 'inactive_seconds',
label: 'Inactive duration',
},
],
},
{
label: 'Most active',
options: [
{
value: 'click_count',
label: 'Clicks',
},
{
value: 'keypress_count',
label: 'Key presses',
},
{
value: 'mouse_activity_count',
label: 'Mouse activity',
},
],
},
{
value: 'console_error_count',
label: 'Most errors',
},
]}
size="small"
value={orderBy}
onChange={setOrderBy}
/>
</div>
<div>
<TestAccountFilter
Expand Down
Loading

0 comments on commit c3b0cb2

Please sign in to comment.