From da632304a16f7a8874e35ea532d84b90a0615ca2 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Thu, 31 Oct 2024 10:36:02 +0100 Subject: [PATCH] ui: remove search field, show filters picker by default for assist --- frontend/app/components/Assist/AssistView.tsx | 1 - .../shared/Filters/FilterList/FilterList.tsx | 407 +++++++++--------- .../LiveSessionSearch/LiveSessionSearch.tsx | 52 +-- .../shared/SessionItem/MetaItem/MetaItem.tsx | 6 +- .../shared/SessionItem/SessionItem.tsx | 150 ++++--- 5 files changed, 304 insertions(+), 312 deletions(-) diff --git a/frontend/app/components/Assist/AssistView.tsx b/frontend/app/components/Assist/AssistView.tsx index 5a345380a..56fc3108a 100644 --- a/frontend/app/components/Assist/AssistView.tsx +++ b/frontend/app/components/Assist/AssistView.tsx @@ -6,7 +6,6 @@ import AssistSearchField from './AssistSearchField'; function AssistView() { return (
-
diff --git a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx index 0a0ff0572..29a3f2bac 100644 --- a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx +++ b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx @@ -1,223 +1,240 @@ -import {Space} from 'antd'; -import {List} from 'immutable'; -import {GripHorizontal} from 'lucide-react'; -import {observer} from 'mobx-react-lite'; -import React, {useEffect} from 'react'; +import { Space } from 'antd'; +import { List } from 'immutable'; +import { GripHorizontal } from 'lucide-react'; +import { observer } from 'mobx-react-lite'; +import React, { useEffect } from 'react'; +import { Button, Card } from 'antd'; +import { Icon } from 'UI'; import FilterItem from '../FilterItem'; -import EventsOrder from "Shared/Filters/FilterList/EventsOrder"; +import EventsOrder from 'Shared/Filters/FilterList/EventsOrder'; +import FilterSelection from '../FilterSelection/FilterSelection'; interface Props { - filter?: any; // event/filter - onUpdateFilter: (filterIndex: any, filter: any) => void; - onFilterMove?: (filters: any) => void; - onRemoveFilter: (filterIndex: any) => void; - onChangeEventsOrder: (e: any, {name, value}: any) => void; - hideEventsOrder?: boolean; - observeChanges?: () => void; - saveRequestPayloads?: boolean; - supportsEmpty?: boolean; - readonly?: boolean; - excludeFilterKeys?: Array; - isConditional?: boolean; - actions?: React.ReactNode[]; + filter?: any; // event/filter + onUpdateFilter: (filterIndex: any, filter: any) => void; + onFilterMove?: (filters: any) => void; + onRemoveFilter: (filterIndex: any) => void; + onChangeEventsOrder: (e: any, { name, value }: any) => void; + hideEventsOrder?: boolean; + observeChanges?: () => void; + saveRequestPayloads?: boolean; + supportsEmpty?: boolean; + readonly?: boolean; + excludeFilterKeys?: Array; + isConditional?: boolean; + actions?: React.ReactNode[]; + onlyFilters?: boolean; + onAddFilter: (filter: any) => void; } function FilterList(props: Props) { - const { - observeChanges = () => { - }, - filter, - hideEventsOrder = false, - saveRequestPayloads, - supportsEmpty = true, - excludeFilterKeys = [], - isConditional, - actions = [] - } = props; + const { + observeChanges = () => {}, + filter, + hideEventsOrder = false, + saveRequestPayloads, + supportsEmpty = true, + excludeFilterKeys = [], + isConditional, + actions = [], + onAddFilter, + onlyFilters, + } = props; - const filters = filter.filters; - const hasEvents = filters.filter((i: any) => i.isEvent).length > 0; - const hasFilters = filters.filter((i: any) => !i.isEvent).length > 0; + const filters = filter.filters; + const hasEvents = filters.filter((i: any) => i.isEvent).length > 0; + const hasFilters = filters.filter((i: any) => !i.isEvent).length > 0; - let rowIndex = 0; - const cannotDeleteFilter = hasEvents && !supportsEmpty; + let rowIndex = 0; + const cannotDeleteFilter = hasEvents && !supportsEmpty; - useEffect(observeChanges, [filters]); + useEffect(observeChanges, [filters]); - const onRemoveFilter = (filterIndex: any) => { - props.onRemoveFilter(filterIndex); - }; + const onRemoveFilter = (filterIndex: any) => { + props.onRemoveFilter(filterIndex); + }; - const [hoveredItem, setHoveredItem] = React.useState>({ - i: null, - position: null, - }); - const [draggedInd, setDraggedItem] = React.useState(null); + const [hoveredItem, setHoveredItem] = React.useState>({ + i: null, + position: null, + }); + const [draggedInd, setDraggedItem] = React.useState(null); - const handleDragOverEv = (event: Record, i: number) => { - event.preventDefault(); - const target = event.currentTarget.getBoundingClientRect(); - const hoverMiddleY = (target.bottom - target.top) / 2; - const hoverClientY = event.clientY - target.top; + const handleDragOverEv = (event: Record, i: number) => { + event.preventDefault(); + const target = event.currentTarget.getBoundingClientRect(); + const hoverMiddleY = (target.bottom - target.top) / 2; + const hoverClientY = event.clientY - target.top; - const position = hoverClientY < hoverMiddleY ? 'top' : 'bottom'; - setHoveredItem({position, i}); - }; + const position = hoverClientY < hoverMiddleY ? 'top' : 'bottom'; + setHoveredItem({ position, i }); + }; - const calculateNewPosition = React.useCallback( - (draggedInd: number, hoveredIndex: number, hoveredPosition: string) => { - if (hoveredPosition === 'bottom') { - hoveredIndex++; - } - return draggedInd < hoveredIndex ? hoveredIndex - 1 : hoveredIndex; - }, - [] - ); + const calculateNewPosition = React.useCallback( + (draggedInd: number, hoveredIndex: number, hoveredPosition: string) => { + if (hoveredPosition === 'bottom') { + hoveredIndex++; + } + return draggedInd < hoveredIndex ? hoveredIndex - 1 : hoveredIndex; + }, + [] + ); - const handleDragStart = React.useCallback(( - ev: Record, - index: number, - elId: string - ) => { - ev.dataTransfer.setData("text/plain", index.toString()); - setDraggedItem(index); - const el = document.getElementById(elId); - if (el) { - ev.dataTransfer.setDragImage(el, 0, 0); - } - }, []) + const handleDragStart = React.useCallback( + (ev: Record, index: number, elId: string) => { + ev.dataTransfer.setData('text/plain', index.toString()); + setDraggedItem(index); + const el = document.getElementById(elId); + if (el) { + ev.dataTransfer.setDragImage(el, 0, 0); + } + }, + [] + ); - const handleDrop = React.useCallback( - (event: Record) => { - event.preventDefault(); - if (draggedInd === null) return; - const newItems = filters.toArray(); - const newPosition = calculateNewPosition( - draggedInd, - hoveredItem.i, - hoveredItem.position - ); + const handleDrop = React.useCallback( + (event: Record) => { + event.preventDefault(); + if (draggedInd === null) return; + const newItems = filters.toArray(); + const newPosition = calculateNewPosition( + draggedInd, + hoveredItem.i, + hoveredItem.position + ); - const reorderedItem = newItems.splice(draggedInd, 1)[0]; - newItems.splice(newPosition, 0, reorderedItem); + const reorderedItem = newItems.splice(draggedInd, 1)[0]; + newItems.splice(newPosition, 0, reorderedItem); - props.onFilterMove?.(List(newItems)); - setHoveredItem({i: null, position: null}); - setDraggedItem(null); - }, - [draggedInd, hoveredItem, filters, props.onFilterMove] - ); + props.onFilterMove?.(List(newItems)); + setHoveredItem({ i: null, position: null }); + setDraggedItem(null); + }, + [draggedInd, hoveredItem, filters, props.onFilterMove] + ); - const eventsNum = filters.filter((i: any) => i.isEvent).size - return ( -
- {hasEvents && ( - <> -
-
- {filter.eventsHeader || 'EVENTS'} -
+ const eventsNum = filters.filter((i: any) => i.isEvent).size; + return ( +
+ {onlyFilters ? null : ( +
+
+ {filter.eventsHeader || 'Events'} +
- - {!hideEventsOrder && } - {actions && actions.map((action, index) => ( -
{action}
- ))} -
+ + {!hideEventsOrder && ( + + )} + {actions && + actions.map((action, index) =>
{action}
)} +
+
+
+ {filters.map((filter: any, filterIndex: number) => + filter.isEvent ? ( +
handleDragOverEv(e, filterIndex)} + onDrop={(e) => handleDrop(e)} + key={`${filter.key}-${filterIndex}`} + > + {!!props.onFilterMove && eventsNum > 1 ? ( +
+ handleDragStart( + e, + filterIndex, + `${filter.key}-${filterIndex}` + ) + } + > +
-
- {filters.map((filter: any, filterIndex: number) => - filter.isEvent ? ( -
handleDragOverEv(e, filterIndex)} - onDrop={(e) => handleDrop(e)} - key={`${filter.key}-${filterIndex}`} - > - {!!props.onFilterMove && eventsNum > 1 ? ( -
- handleDragStart( - e, - filterIndex, - `${filter.key}-${filterIndex}` - ) - } - > - -
- ) : null} - - props.onUpdateFilter(filterIndex, filter) - } - onRemoveFilter={() => onRemoveFilter(filterIndex)} - saveRequestPayloads={saveRequestPayloads} - disableDelete={cannotDeleteFilter} - excludeFilterKeys={excludeFilterKeys} - readonly={props.readonly} - isConditional={isConditional} - /> -
- ) : null - )} -
-
- + ) : null} + + props.onUpdateFilter(filterIndex, filter) + } + onRemoveFilter={() => onRemoveFilter(filterIndex)} + saveRequestPayloads={saveRequestPayloads} + disableDelete={cannotDeleteFilter} + excludeFilterKeys={excludeFilterKeys} + readonly={props.readonly} + isConditional={isConditional} + /> +
+ ) : null )} +
+
+ )} - {hasFilters && ( - <> - {hasEvents &&
} -
FILTERS
- {filters.map((filter: any, filterIndex: any) => - !filter.isEvent ? ( -
- props.onUpdateFilter(filterIndex, filter)} - onRemoveFilter={() => onRemoveFilter(filterIndex)} - excludeFilterKeys={excludeFilterKeys} - isConditional={isConditional} - /> -
- ) : null - )} - - )} + +
+
Filters
+ + +
- ); + {filters.map((filter: any, filterIndex: any) => + !filter.isEvent ? ( +
+ props.onUpdateFilter(filterIndex, filter)} + onRemoveFilter={() => onRemoveFilter(filterIndex)} + excludeFilterKeys={excludeFilterKeys} + isConditional={isConditional} + /> +
+ ) : null + )} +
+
+ ); } export default observer(FilterList); diff --git a/frontend/app/components/shared/LiveSessionSearch/LiveSessionSearch.tsx b/frontend/app/components/shared/LiveSessionSearch/LiveSessionSearch.tsx index 82303564c..9c291dbf0 100644 --- a/frontend/app/components/shared/LiveSessionSearch/LiveSessionSearch.tsx +++ b/frontend/app/components/shared/LiveSessionSearch/LiveSessionSearch.tsx @@ -9,8 +9,8 @@ function LiveSessionSearch() { const { projectsStore, searchStoreLive, sessionStore } = useStore(); const saveRequestPayloads = projectsStore.active?.saveRequestPayloads; const appliedFilter = searchStoreLive.instance; - const hasEvents = appliedFilter.filters.filter(i => i.isEvent).length > 0; - const hasFilters = appliedFilter.filters.filter(i => !i.isEvent).length > 0; + const hasEvents = appliedFilter.filters.filter((i) => i.isEvent).length > 0; + const hasFilters = appliedFilter.filters.filter((i) => !i.isEvent).length > 0; useEffect(() => { void searchStoreLive.fetchSessions(); @@ -31,7 +31,7 @@ function LiveSessionSearch() { }); searchStoreLive.edit({ - filters: newFilters + filters: newFilters, }); void searchStoreLive.fetchSessions(); @@ -39,45 +39,23 @@ function LiveSessionSearch() { const onChangeEventsOrder = (e: any, { name, value }: any) => { searchStoreLive.edit({ - eventsOrder: value + eventsOrder: value, }); void searchStoreLive.fetchSessions(); }; - return (hasEvents || hasFilters) ? ( -
-
- -
- -
-
- - {/* */} - - -
-
-
-
-
- ) : <>; + return ( + + ); } export default observer(LiveSessionSearch); diff --git a/frontend/app/components/shared/SessionItem/MetaItem/MetaItem.tsx b/frontend/app/components/shared/SessionItem/MetaItem/MetaItem.tsx index 5b88d1896..42eae0244 100644 --- a/frontend/app/components/shared/SessionItem/MetaItem/MetaItem.tsx +++ b/frontend/app/components/shared/SessionItem/MetaItem/MetaItem.tsx @@ -10,11 +10,11 @@ interface Props { export default function MetaItem(props: Props) { const { className = '', label, value } = props return ( -
- +
+ - +
diff --git a/frontend/app/components/shared/SessionItem/SessionItem.tsx b/frontend/app/components/shared/SessionItem/SessionItem.tsx index a87bfc3c4..ea5b54882 100644 --- a/frontend/app/components/shared/SessionItem/SessionItem.tsx +++ b/frontend/app/components/shared/SessionItem/SessionItem.tsx @@ -13,14 +13,7 @@ import { sessions as sessionsRoute, } from 'App/routes'; import { capitalize } from 'App/utils'; -import { - Avatar, - CountryFlag, - Icon, - Label, - TextEllipsis, - Tooltip, -} from 'UI'; +import { Avatar, CountryFlag, Icon, Label, TextEllipsis, Tooltip } from 'UI'; import Counter from './Counter'; import ErrorBars from './ErrorBars'; @@ -83,7 +76,7 @@ const PREFETCH_STATE = { none: 0, loading: 1, fetched: 2, -} +}; function SessionItem(props: RouteComponentProps & Props) { const { settingsStore, sessionStore } = useStore(); @@ -130,32 +123,32 @@ function SessionItem(props: RouteComponentProps & Props) { const location = props.location; const queryParams = Object.fromEntries(new URLSearchParams(location.search)); - const isMobile = platform !== 'web' + const isMobile = platform !== 'web'; const formattedDuration = durationFormatted(duration); const hasUserId = userId || userAnonymousId; const isSessions = isRoute(SESSIONS_ROUTE, location.pathname); const isAssist = (!ignoreAssist && - (isRoute(ASSIST_ROUTE, location.pathname) || - isRoute(ASSIST_LIVE_SESSION, location.pathname) || - location.pathname.includes('multiview'))) || + (isRoute(ASSIST_ROUTE, location.pathname) || + isRoute(ASSIST_LIVE_SESSION, location.pathname) || + location.pathname.includes('multiview'))) || props.live; const isLastPlayed = lastPlayedSessionId === sessionId; - const _metaList = Object.keys(metadata) - .map((key) => { - const value = metadata[key]; - return { label: key, value }; - }); + const _metaList = Object.keys(metadata).map((key) => { + const value = metadata[key]; + return { label: key, value }; + }); const handleHover = async () => { if ( - prefetchState !== PREFETCH_STATE.none - || props.live - || isAssist - || isMobile - ) return; + prefetchState !== PREFETCH_STATE.none || + props.live || + isAssist || + isMobile + ) + return; setPrefetched(PREFETCH_STATE.loading); try { @@ -167,10 +160,10 @@ function SessionItem(props: RouteComponentProps & Props) { }; const populateData = () => { if ( - props.live - || isAssist - || prefetchState === PREFETCH_STATE.none - || isMobile + props.live || + isAssist || + prefetchState === PREFETCH_STATE.none || + isMobile ) { return; } @@ -193,38 +186,46 @@ function SessionItem(props: RouteComponentProps & Props) {
{!compact && (
-
- -
-
-
- !disableUser && !hasUserFilter && hasUserId - ? onUserClick(userId, userAnonymousId) - : null - } - > - +
+
+
+
+ !disableUser && !hasUserFilter && hasUserId + ? onUserClick(userId, userAnonymousId) + : null + } + > + +
+
+ {_metaList.length > 0 && ( + + )}
)}
@@ -281,8 +282,8 @@ function SessionItem(props: RouteComponentProps & Props) { {eventsCount} {eventsCount === 0 || eventsCount > 1 - ? 'Events' - : 'Event'} + ? 'Events' + : 'Event'}
@@ -292,8 +293,8 @@ function SessionItem(props: RouteComponentProps & Props) { {live || props.live ? ( ) : ( - formattedDuration - )} + formattedDuration + )}
@@ -394,22 +395,19 @@ function SessionItem(props: RouteComponentProps & Props) {
) : ( - - )} + + )}
- {_metaList.length > 0 && ( - - )}
);