From f033cbd12f677d233c0b5d0b7d4d42f09943f867 Mon Sep 17 00:00:00 2001 From: Delirium Date: Thu, 25 Apr 2024 15:28:12 +0200 Subject: [PATCH] fix ui: fixes for segment comp + ui mockup (#2137) * fix ui: fixes for segment comp * feat ui: some ai testing mockup --- frontend/app/api_client.ts | 8 +- .../Integrations/IntegrationFilters.tsx | 45 +++---- .../Client/Integrations/Integrations.tsx | 3 +- .../MetricViewHeader/MetricViewHeader.tsx | 41 +++--- .../components/WidgetForm/WidgetForm.tsx | 17 +++ .../Player/MobilePlayer/PlayerContent.tsx | 4 +- .../Player/ReplayPlayer/PlayerContent.tsx | 5 - frontend/app/components/Session/WebPlayer.tsx | 5 +- .../Session_/OverviewPanel/OverviewPanel.tsx | 121 ++++++++++++------ .../shared/Filters/FilterList/FilterList.tsx | 1 + frontend/app/initialize.tsx | 1 + frontend/app/mstore/aiFiltersStore.ts | 5 + frontend/app/services/AiService.ts | 9 ++ 13 files changed, 174 insertions(+), 91 deletions(-) diff --git a/frontend/app/api_client.ts b/frontend/app/api_client.ts index ed739c8f8..73c5d554d 100644 --- a/frontend/app/api_client.ts +++ b/frontend/app/api_client.ts @@ -160,7 +160,13 @@ export default class APIClient { edp = `${edp}/${this.siteId}`; } - if (path.includes('login') || path.includes('refresh') || path.includes('logout')) { + if ( + ( + path.includes('login') + || path.includes('refresh') + || path.includes('logout') + ) && window.env.NODE_ENV !== 'development' + ) { init.credentials = 'include'; } else { delete init.credentials; diff --git a/frontend/app/components/Client/Integrations/IntegrationFilters.tsx b/frontend/app/components/Client/Integrations/IntegrationFilters.tsx index 5e8d8f7b3..898d38587 100644 --- a/frontend/app/components/Client/Integrations/IntegrationFilters.tsx +++ b/frontend/app/components/Client/Integrations/IntegrationFilters.tsx @@ -1,6 +1,9 @@ -import React from 'react'; -import { Icon } from 'UI'; +import { Segmented } from 'antd'; import cn from 'classnames'; +import React from 'react'; + +import { Icon } from 'UI'; + interface Props { onChange: any; @@ -10,31 +13,29 @@ interface Props { const allItem = { key: 'all', title: 'All' }; -function FilterButton(props: { activeItem: string, item: any, onClick: () => any }) { - return
- {props.item.icon && } - {props.item.title} -
; -} - function IntegrationFilters(props: Props) { + const segmentItems = [allItem, ...props.filters].map((item: any) => ({ + key: item.key, + value: item.key, + label: ( +
+ {item.icon ? : null} +
{item.title}
+
+ ), + })) + + const onChange = (val) => { + props.onChange(val) + } return (
- props.onChange(allItem.key)} + - {props.filters.map((item: any) => ( - props.onChange(item.key)} /> - ))}
); } diff --git a/frontend/app/components/Client/Integrations/Integrations.tsx b/frontend/app/components/Client/Integrations/Integrations.tsx index d847e9c0e..9ed478fc4 100644 --- a/frontend/app/components/Client/Integrations/Integrations.tsx +++ b/frontend/app/components/Client/Integrations/Integrations.tsx @@ -98,8 +98,9 @@ function Integrations(props: Props) { const filters = integrations.map((cat: any) => ({ key: cat.key, title: cat.title, + label: cat.title, icon: cat.icon - })); + })) const allIntegrations = filteredIntegrations.flatMap(cat => cat.integrations); diff --git a/frontend/app/components/Dashboard/components/MetricViewHeader/MetricViewHeader.tsx b/frontend/app/components/Dashboard/components/MetricViewHeader/MetricViewHeader.tsx index 89fc066be..e32350288 100644 --- a/frontend/app/components/Dashboard/components/MetricViewHeader/MetricViewHeader.tsx +++ b/frontend/app/components/Dashboard/components/MetricViewHeader/MetricViewHeader.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { PageTitle, Button, Link, Toggler } from 'UI'; +import { PageTitle, Button, Toggler, Icon } from "UI"; +import { Segmented } from 'antd'; import MetricsSearch from '../MetricsSearch'; import Select from 'Shared/Select'; import { useStore } from 'App/mstore'; @@ -102,25 +103,33 @@ function DashboardDropdown({ onChange, plain = false }: { plain?: boolean; onCha ); } -function ListViewToggler({}) { +function ListViewToggler() { const { metricStore } = useStore(); const listView = useObserver(() => metricStore.listView); return (
- - + + +
List
+
, + value: 'list' + }, + { + label:
+ +
Grid
+
, + value: 'grid' + } + ]} + onChange={(val) => { + metricStore.updateKey('listView', val === 'list') + }} + value={listView ? 'list' : 'grid'} + /> ); } diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx index 35ebd62af..b4aed6460 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetForm.tsx @@ -42,6 +42,7 @@ function WidgetForm(props: Props) { } } = props; const [aiQuery, setAiQuery] = useState('') + const [aiAskChart, setAiAskChart] = useState('') const { metricStore, dashboardStore, aiFiltersStore } = useStore(); const isSaving = metricStore.isSaving; const metric: any = metricStore.instance; @@ -139,11 +140,20 @@ function WidgetForm(props: Props) { }) }; + const fetchChartData = () => { + void aiFiltersStore.getCardData(aiAskChart, metric.toJson()) + } + const handleKeyDown = (event: any) => { if (event.key === 'Enter') { fetchResults(); } }; + const handleChartKeyDown = (event: any) => { + if (event.key === 'Enter') { + fetchChartData(); + } + }; const testingKey = localStorage.getItem('__mauricio_testing_access') === 'true'; return ( @@ -260,6 +270,13 @@ function WidgetForm(props: Props) { className="w-full mb-2" onKeyDown={handleKeyDown} /> : null} + {testingKey ? setAiAskChart(e.target.value)} + className="w-full mb-2" + onKeyDown={handleChartKeyDown} + /> : null} {aiFiltersStore.isLoading ? (
diff --git a/frontend/app/components/Session/Player/MobilePlayer/PlayerContent.tsx b/frontend/app/components/Session/Player/MobilePlayer/PlayerContent.tsx index 04144fdc9..a9e41fd9e 100644 --- a/frontend/app/components/Session/Player/MobilePlayer/PlayerContent.tsx +++ b/frontend/app/components/Session/Player/MobilePlayer/PlayerContent.tsx @@ -9,8 +9,8 @@ import Session from 'Types/session' import PlayerBlock from './PlayerBlock'; const TABS = { - EVENTS: 'User Events', - HEATMAPS: 'Click Map', + EVENTS: 'Activity', + HEATMAPS: 'Click map', }; interface IProps { diff --git a/frontend/app/components/Session/Player/ReplayPlayer/PlayerContent.tsx b/frontend/app/components/Session/Player/ReplayPlayer/PlayerContent.tsx index ae8da605c..e27d2eaef 100644 --- a/frontend/app/components/Session/Player/ReplayPlayer/PlayerContent.tsx +++ b/frontend/app/components/Session/Player/ReplayPlayer/PlayerContent.tsx @@ -8,11 +8,6 @@ import { PlayerContext } from 'Components/Session/playerContext'; import Session from 'Types/session' import PlayerBlock from './PlayerBlock'; -const TABS = { - EVENTS: 'User Events', - HEATMAPS: 'Click Map', -}; - interface IProps { fullscreen: boolean; activeTab: string; diff --git a/frontend/app/components/Session/WebPlayer.tsx b/frontend/app/components/Session/WebPlayer.tsx index fd1e250d9..e41ecba33 100644 --- a/frontend/app/components/Session/WebPlayer.tsx +++ b/frontend/app/components/Session/WebPlayer.tsx @@ -25,9 +25,10 @@ import { IPlayerContext, PlayerContext, defaultContextValue } from './playerCont const TABS = { EVENTS: 'Activity', - CLICKMAP: 'Click Map', + CLICKMAP: 'Click map', INSPECTOR: 'Tag' }; + const UXTTABS = { EVENTS: TABS.EVENTS }; @@ -141,7 +142,7 @@ function WebPlayer(props: any) { }, [cssLoading, ready]) React.useEffect(() => { - if (activeTab === 'Click Map') { + if (activeTab === 'Click map') { contextValue.player?.pause(); } }, [activeTab]); diff --git a/frontend/app/components/Session_/OverviewPanel/OverviewPanel.tsx b/frontend/app/components/Session_/OverviewPanel/OverviewPanel.tsx index edafb2b73..42aa27542 100644 --- a/frontend/app/components/Session_/OverviewPanel/OverviewPanel.tsx +++ b/frontend/app/components/Session_/OverviewPanel/OverviewPanel.tsx @@ -1,24 +1,29 @@ +import { Segmented } from 'antd'; import cn from 'classnames'; import { observer } from 'mobx-react-lite'; import React, { useEffect } from 'react'; import { connect } from 'react-redux'; -import { Segmented } from 'antd' -import { MobilePlayerContext, PlayerContext } from 'App/components/Session/playerContext'; +import { + MobilePlayerContext, + PlayerContext, +} from 'App/components/Session/playerContext'; import { useStore } from 'App/mstore'; import SummaryBlock from 'Components/Session/Player/ReplayPlayer/SummaryBlock'; import { SummaryButton } from 'Components/Session_/Player/Controls/Controls'; -import { toggleBottomBlock, setZoomTab } from 'Duck/components/player'; +import TimelineZoomButton from 'Components/Session_/Player/Controls/components/TimelineZoomButton'; +import { setZoomTab, toggleBottomBlock } from 'Duck/components/player'; import { Icon, NoContent } from 'UI'; import BottomBlock from '../BottomBlock'; import EventRow from './components/EventRow'; -import FeatureSelection, { HELP_MESSAGE } from './components/FeatureSelection/FeatureSelection'; +import FeatureSelection, { + HELP_MESSAGE, +} from './components/FeatureSelection/FeatureSelection'; import OverviewPanelContainer from './components/OverviewPanelContainer'; import TimelinePointer from './components/TimelinePointer'; import TimelineScale from './components/TimelineScale'; import VerticalPointerLine from './components/VerticalPointerLine'; -import TimelineZoomButton from 'Components/Session_/Player/Controls/components/TimelineZoomButton'; function MobileOverviewPanelCont({ issuesList, @@ -27,7 +32,7 @@ function MobileOverviewPanelCont({ zoomStartTs, zoomEndTs, setZoomTab, - zoomTab + zoomTab, }: { issuesList: Record[]; sessionId: string; @@ -35,7 +40,7 @@ function MobileOverviewPanelCont({ zoomStartTs: number; zoomEndTs: number; setZoomTab: (tab: string) => void; - zoomTab: 'overview' | 'journey' | 'issues' | 'errors' + zoomTab: 'overview' | 'journey' | 'issues' | 'errors'; }) { const { aiSummaryStore } = useStore(); const { store, player } = React.useContext(MobilePlayerContext); @@ -60,7 +65,9 @@ function MobileOverviewPanelCont({ const fetchPresented = fetchList.length > 0; const checkInZoomRange = (list: any[]) => { - return list.filter((i) => (zoomEnabled ? i.time >= zoomStartTs && i.time <= zoomEndTs : true)); + return list.filter((i) => + zoomEnabled ? i.time >= zoomStartTs && i.time <= zoomEndTs : true + ); }; const resources = { @@ -87,7 +94,13 @@ function MobileOverviewPanelCont({ ) { setDataLoaded(true); } - }, [issuesList, exceptionsList, eventsList, performanceChartData, frustrationsList]); + }, [ + issuesList, + exceptionsList, + eventsList, + performanceChartData, + frustrationsList, + ]); React.useEffect(() => { player.scale(); @@ -106,7 +119,9 @@ function MobileOverviewPanelCont({ performanceList={performanceList} sessionId={sessionId} showSummary={isSaas} - toggleSummary={() => aiSummaryStore.setToggleSummary(!aiSummaryStore.toggleSummary)} + toggleSummary={() => + aiSummaryStore.setToggleSummary(!aiSummaryStore.toggleSummary) + } summaryChecked={aiSummaryStore.toggleSummary} setZoomTab={setZoomTab} zoomTab={zoomTab} @@ -127,7 +142,7 @@ function WebOverviewPanelCont({ zoomStartTs: number; zoomEndTs: number; setZoomTab: (tab: string) => void; - zoomTab: 'overview' | 'journey' | 'issues' | 'errors' + zoomTab: 'overview' | 'journey' | 'issues' | 'errors'; }) { const { aiSummaryStore } = useStore(); const { store } = React.useContext(PlayerContext); @@ -146,7 +161,8 @@ function WebOverviewPanelCont({ const resourceListUnmap = tabStates[currentTab]?.resourceList || []; const fetchList = tabStates[currentTab]?.fetchList || []; const graphqlList = tabStates[currentTab]?.graphqlList || []; - const performanceChartData = tabStates[currentTab]?.performanceChartData || []; + const performanceChartData = + tabStates[currentTab]?.performanceChartData || []; const fetchPresented = fetchList.length > 0; const resourceList = resourceListUnmap @@ -158,7 +174,9 @@ function WebOverviewPanelCont({ .filter((i: any) => i.type === 'fetch'); const checkInZoomRange = (list: any[]) => { - return list.filter((i) => (zoomEnabled ? i.time >= zoomStartTs && i.time <= zoomEndTs : true)); + return list.filter((i) => + zoomEnabled ? i.time >= zoomStartTs && i.time <= zoomEndTs : true + ); }; const resources: any = React.useMemo(() => { @@ -181,7 +199,9 @@ function WebOverviewPanelCont({ fetchPresented={fetchPresented} setSelectedFeatures={setSelectedFeatures} showSummary={isSaas} - toggleSummary={() => aiSummaryStore.setToggleSummary(!aiSummaryStore.toggleSummary)} + toggleSummary={() => + aiSummaryStore.setToggleSummary(!aiSummaryStore.toggleSummary) + } summaryChecked={aiSummaryStore.toggleSummary} sessionId={sessionId} setZoomTab={setZoomTab} @@ -213,35 +233,44 @@ function PanelComponent({ X-Ray {showSummary ? ( <> - - setZoomTab(val)} - options={[ - { - label: 'Overview', - value: 'overview', - }, - { - label: 'User Journey', - value: 'journey', - }, - { - label: 'Issues', - value: 'issues', - }, - { - label: 'Suggestions', - value: 'errors', - } - ]} + + {summaryChecked ? ( + setZoomTab(val)} + options={[ + { + label: 'Overview', + value: 'overview', + }, + { + label: 'User journey', + value: 'journey', + }, + { + label: 'Issues', + value: 'issues', + }, + { + label: 'Suggestions', + value: 'errors', + }, + ]} + /> + ) : null} ) : null}
- +
@@ -266,7 +295,9 @@ function PanelComponent({ {selectedFeatures.map((feature: any, index: number) => (
{isMobile && feature === 'PERFORMANCE' ? ( -
+
props.onChangeEventsOrder( null, diff --git a/frontend/app/initialize.tsx b/frontend/app/initialize.tsx index 2de4c4e08..b5e11e28b 100644 --- a/frontend/app/initialize.tsx +++ b/frontend/app/initialize.tsx @@ -25,6 +25,7 @@ const customTheme: ThemeConfig = { }, Segmented: { itemSelectedBg: '#FFFFFF', + itemSelectedColor: colors['main'], }, Menu: { colorPrimary: colors.teal, diff --git a/frontend/app/mstore/aiFiltersStore.ts b/frontend/app/mstore/aiFiltersStore.ts index cfd5e69fe..bd3833129 100644 --- a/frontend/app/mstore/aiFiltersStore.ts +++ b/frontend/app/mstore/aiFiltersStore.ts @@ -25,6 +25,11 @@ export default class AiFiltersStore { this.filtersSetKey += 1; }; + getCardData = async (query: string, chartData: Record) => { + const r = await aiService.getCardData(query, chartData); + console.log(r) + } + getCardFilters = async (query: string, chartType: string): Promise => { this.isLoading = true; try { diff --git a/frontend/app/services/AiService.ts b/frontend/app/services/AiService.ts index 85feef677..3b0bc1862 100644 --- a/frontend/app/services/AiService.ts +++ b/frontend/app/services/AiService.ts @@ -40,4 +40,13 @@ export default class AiService extends BaseService { const { data } = await r.json(); return data; } + + async getCardData(query: string, chartData: Record): Promise> { + const r = await this.client.post('/intelligent/search-plus', { + ...chartData, + question: query, + }); + const { data } = await r.json(); + return data; + } }