diff --git a/frontend/app/components/Dashboard/components/AddCardSelectionModal.tsx b/frontend/app/components/Dashboard/components/AddCardSelectionModal.tsx index 037bf8cae..4cbf7627d 100644 --- a/frontend/app/components/Dashboard/components/AddCardSelectionModal.tsx +++ b/frontend/app/components/Dashboard/components/AddCardSelectionModal.tsx @@ -2,6 +2,7 @@ import React from 'react'; import {Card, Col, Modal, Row, Typography} from "antd"; import {Grid2x2CheckIcon, Plus} from "lucide-react"; import NewDashboardModal from "Components/Dashboard/components/DashboardList/NewDashModal"; +import {useStore} from "App/mstore"; interface Props { open: boolean; @@ -9,6 +10,7 @@ interface Props { } function AddCardSelectionModal(props: Props) { + const {metricStore} = useStore(); const [open, setOpen] = React.useState(false); const [isLibrary, setIsLibrary] = React.useState(false); @@ -18,6 +20,9 @@ function AddCardSelectionModal(props: Props) { } const onClick = (isLibrary: boolean) => { + if (!isLibrary) { + metricStore.init(); + } setIsLibrary(isLibrary); setOpen(true); } diff --git a/frontend/app/components/Dashboard/components/CreateDashboardButton.tsx b/frontend/app/components/Dashboard/components/CreateDashboardButton.tsx index 639c63903..d5731517d 100644 --- a/frontend/app/components/Dashboard/components/CreateDashboardButton.tsx +++ b/frontend/app/components/Dashboard/components/CreateDashboardButton.tsx @@ -8,7 +8,7 @@ interface Props { } function CreateDashboardButton({disabled = false}: Props) { - const [showModal, setShowModal] = React.useState(true); + const [showModal, setShowModal] = React.useState(false); return <> -// ) : ''} -// -// -// ); - interface CategorySelectorProps { setSelected?: React.Dispatch>; selected?: string; diff --git a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx index aa21ecea8..e87a4dd54 100644 --- a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx @@ -105,6 +105,7 @@ function FilterSeries(props: Props) { } const onChangeEventsOrder = (_: any, {name, value}: any) => { + console.log(name, value) series.filter.updateKey(name, value); observeChanges(); }; @@ -115,7 +116,7 @@ function FilterSeries(props: Props) { }; return ( -
+
{canExclude && } {!hideHeader && ( @@ -129,7 +130,7 @@ function FilterSeries(props: Props) { )} {expandable && !expanded && ( - + setExpanded(!expanded)}/>
-
+
diff --git a/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx b/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx index fde2b4f4e..3050acb94 100644 --- a/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx +++ b/frontend/app/components/Dashboard/components/WidgetForm/WidgetFormNew.tsx @@ -2,15 +2,27 @@ import React from 'react'; import {Card, Space, Typography, Button} from "antd"; import {useStore} from "App/mstore"; import {eventKeys} from "Types/filter/newFilter"; -import {CLICKMAP, FUNNEL, INSIGHTS, RETENTION, TABLE, USER_PATH} from "App/constants/card"; +import { + CLICKMAP, + ERRORS, + FUNNEL, + INSIGHTS, + PERFORMANCE, + RESOURCE_MONITORING, + RETENTION, + TABLE, + USER_PATH, WEB_VITALS +} from "App/constants/card"; import FilterSeries from "Components/Dashboard/components/FilterSeries/FilterSeries"; import {metricOf} from "App/constants/filterOptions"; import {AudioWaveform, ChevronDown, ChevronUp, PlusIcon} from "lucide-react"; import {observer} from "mobx-react-lite"; import AddStepButton from "Components/Dashboard/components/FilterSeries/AddStepButton"; +import {Icon} from "UI"; +import FilterItem from "Shared/Filters/FilterItem"; +import {FilterKey} from "Types/filter/filterType"; function WidgetFormNew() { - // const [expanded, setExpanded] = React.useState(true); const {metricStore, dashboardStore, aiFiltersStore} = useStore(); const metric: any = metricStore.instance; @@ -20,9 +32,11 @@ function WidgetFormNew() { const isPathAnalysis = metric.metricType === USER_PATH; const excludeFilterKeys = isClickMap || isPathAnalysis ? eventKeys : []; const hasFilters = filtersLength > 0 || eventsLength > 0; + const isPredefined = [ERRORS, PERFORMANCE, RESOURCE_MONITORING, WEB_VITALS].includes(metric.metricType); - return ( + return isPredefined ? : ( <> + { ); }) + + +const PathAnalysisFilter = observer(({metric}: any) => ( +
+ {metric.startType === 'start' ? 'Start Point' : 'End Point'} + metric.updateStartPoint(val)} + onRemoveFilter={() => { + }} + /> +
+)); + +const AdditionalFilters = observer(() => { + const {metricStore, dashboardStore, aiFiltersStore} = useStore(); + const metric: any = metricStore.instance; + + return ( + <> + {metric.metricType === USER_PATH && } + + ) +}); + + +const PredefinedMessage = () => ( +
+ +
Filtering and drill-downs will be supported soon for this card type.
+
+); diff --git a/frontend/app/components/shared/Filters/FilterList/EventsOrder.tsx b/frontend/app/components/shared/Filters/FilterList/EventsOrder.tsx new file mode 100644 index 000000000..6f7f8a0b6 --- /dev/null +++ b/frontend/app/components/shared/Filters/FilterList/EventsOrder.tsx @@ -0,0 +1,55 @@ +import {observer} from "mobx-react-lite"; +import {Tooltip} from "UI"; +import {Segmented} from "antd"; +import React from "react"; + +const EventsOrder = observer((props: { + onChange: (e: any, v: any) => void, + filter: any, +}) => { + const {filter, onChange} = props; + const eventsOrderSupport = filter.eventsOrderSupport; + const options = [ + { + name: 'eventsOrder', + label: 'THEN', + value: 'then', + disabled: eventsOrderSupport && !eventsOrderSupport.includes('then'), + }, + { + name: 'eventsOrder', + label: 'AND', + value: 'and', + disabled: eventsOrderSupport && !eventsOrderSupport.includes('and'), + }, + { + name: 'eventsOrder', + label: 'OR', + value: 'or', + disabled: eventsOrderSupport && !eventsOrderSupport.includes('or'), + }, + ]; + + return
+
+ +
Events Order
+
+
+ + onChange(null, options.find((i) => i.value === v))} + value={filter.eventsOrder} + options={options} + /> +
; +}); + +export default EventsOrder; diff --git a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx index efd8dbd5a..c02d49d00 100644 --- a/frontend/app/components/shared/Filters/FilterList/FilterList.tsx +++ b/frontend/app/components/shared/Filters/FilterList/FilterList.tsx @@ -1,12 +1,11 @@ -import {Segmented} from 'antd'; +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 {Tooltip} from 'UI'; - import FilterItem from '../FilterItem'; +import EventsOrder from "Shared/Filters/FilterList/EventsOrder"; interface Props { filter?: any; // event/filter @@ -38,7 +37,6 @@ function FilterList(props: Props) { } = props; const filters = List(filter.filters); - const eventsOrderSupport = filter.eventsOrderSupport; const hasEvents = filters.filter((i: any) => i.isEvent).size > 0; const hasFilters = filters.filter((i: any) => !i.isEvent).size > 0; @@ -111,25 +109,6 @@ function FilterList(props: Props) { [draggedInd, hoveredItem, filters, props.onFilterMove] ); - const eventOrderItems = [ - { - label: 'THEN', - value: 'then', - disabled: eventsOrderSupport && !eventsOrderSupport.includes('then'), - - }, - { - label: 'AND', - value: 'and', - disabled: eventsOrderSupport && !eventsOrderSupport.includes('and'), - }, - { - label: 'OR', - value: 'or', - disabled: eventsOrderSupport && !eventsOrderSupport.includes('or'), - }, - ]; - const eventsNum = filters.filter((i: any) => i.isEvent).size return (
@@ -137,37 +116,16 @@ function FilterList(props: Props) { <>
- {filter.eventsHeader} + {filter.eventsHeader || 'EVENTS'}
- {!hideEventsOrder && ( -
-
- -
Events Order
-
-
- - props.onChangeEventsOrder( - null, - eventOrderItems.find((i) => i.value === v) - ) - } - value={filter.eventsOrder} - options={eventOrderItems} - /> - {actions && actions.map((action, index) => ( -
{action}
- ))} -
- )} + + {!hideEventsOrder && } + {actions && actions.map((action, index) => ( +
{action}
+ ))} +
{filters.map((filter: any, filterIndex: number) => @@ -263,50 +221,3 @@ function FilterList(props: Props) { } export default observer(FilterList); - - -function EventsOrder(props: { - onChange: (e: any, v: any) => void, - filter: any, - eventsOrderSupport: any -}) { - const {filter, eventsOrderSupport, onChange} = props; - const options = [ - { - label: 'THEN', - value: 'then', - disabled: eventsOrderSupport && !eventsOrderSupport.includes('then'), - }, - { - label: 'AND', - value: 'and', - disabled: eventsOrderSupport && !eventsOrderSupport.includes('and'), - }, - { - label: 'OR', - value: 'or', - disabled: eventsOrderSupport && !eventsOrderSupport.includes('or'), - }, - ]; - - return
-
- -
Events Order
-
-
- - onChange(null, options.find((i) => i.value === v))} - value={filter.eventsOrder} - options={options} - /> -
; -} diff --git a/frontend/app/mstore/types/filter.ts b/frontend/app/mstore/types/filter.ts index 8b77e4f5f..a1a4009fb 100644 --- a/frontend/app/mstore/types/filter.ts +++ b/frontend/app/mstore/types/filter.ts @@ -1,9 +1,13 @@ -import { makeAutoObservable, runInAction, observable, action } from "mobx" +import {makeAutoObservable, runInAction, observable, action} from "mobx" import FilterItem from "./filterItem" -import { filtersMap, conditionalFiltersMap } from 'Types/filter/newFilter'; +import {filtersMap, conditionalFiltersMap} from 'Types/filter/newFilter'; +import {FilterKey} from "Types/filter/filterType"; export default class Filter { - public static get ID_KEY():string { return "filterId" } + public static get ID_KEY(): string { + return "filterId" + } + filterId: string = '' name: string = '' filters: FilterItem[] = [] @@ -70,7 +74,7 @@ export default class Filter { fromJson(json: any) { this.name = json.name this.filters = json.filters.map((i: Record) => - new FilterItem(undefined, this.isConditional, this.isMobile).fromJson(i) + new FilterItem(undefined, this.isConditional, this.isMobile).fromJson(i) ); this.eventsOrder = json.eventsOrder return this @@ -79,7 +83,7 @@ export default class Filter { fromData(data) { this.name = data.name this.filters = data.filters.map((i: Record) => - new FilterItem(undefined, this.isConditional, this.isMobile).fromData(i) + new FilterItem(undefined, this.isConditional, this.isMobile).fromData(i) ) this.eventsOrder = data.eventsOrder return this @@ -121,4 +125,10 @@ export default class Filter { removeExcludeFilter(index: number) { this.excludes.splice(index, 1) } + + addFunnelDefaultFilters() { + this.filters = [] + this.addFilter({...filtersMap[FilterKey.CLICK], value: [''], operator: 'onAny'}) + this.addFilter({...filtersMap[FilterKey.CLICK], value: [''], operator: 'onAny'}) + } } diff --git a/frontend/app/mstore/types/widget.ts b/frontend/app/mstore/types/widget.ts index e33d8b61e..90606c99f 100644 --- a/frontend/app/mstore/types/widget.ts +++ b/frontend/app/mstore/types/widget.ts @@ -265,6 +265,16 @@ export default class Widget { }); } + resetDefaults() { + if (this.metricType === FUNNEL) { + this.series = []; + this.series.push(new FilterSeries()); + this.series[0].filter.addFunnelDefaultFilters(); + this.series[0].filter.eventsOrder = 'then'; + this.series[0].filter.eventsOrderSupport = ['then']; + } + } + exists() { return this.metricId !== undefined; } diff --git a/frontend/app/styles/general.css b/frontend/app/styles/general.css index 0828358d9..5332c0533 100644 --- a/frontend/app/styles/general.css +++ b/frontend/app/styles/general.css @@ -10,6 +10,18 @@ background-color: var(--bg-teal); } +:root{ + --bg-teal: #394dfe; +} + +.ant-btn{ + border-radius: .5rem; +} + +.ant-btn-primary{ + background-color: var(--bg-teal); +} + .ml-15 { margin-left: 15px; } .ph-10 { padding-left: 10px; padding-right: 10px; }